diff --git a/resources/[essential]/es_extended/__resource.lua b/resources/[essential]/es_extended/__resource.lua new file mode 100644 index 00000000..4157559d --- /dev/null +++ b/resources/[essential]/es_extended/__resource.lua @@ -0,0 +1,44 @@ +resource_manifest_version '44febabe-d386-4d18-afbe-5e627f4af937' + +description 'ES Extended' + +server_scripts { + '@async/async.lua', + '@mysql-async/lib/MySQL.lua', + 'config.lua', + 'server/common.lua', + 'server/classes/player.lua', + 'server/functions.lua', + 'server/main.lua', + 'server/commands.lua' +} + +client_scripts { + 'config.lua', + 'client/functions.lua', + 'client/main.lua' +} + +ui_page { + 'html/ui.html' +} + +files { + + 'html/ui.html', + + 'html/css/app.css', + + 'html/js/mustache.min.js', + 'html/js/app.js', + + 'html/fonts/pdown.ttf', + 'html/fonts/bankgothic.ttf', + + 'html/img/cursor.png', + 'html/img/keys/enter.png', + 'html/img/keys/return.png', + + 'html/img/accounts/bank.png', + 'html/img/accounts/black_money.png' +} \ No newline at end of file diff --git a/resources/[essential]/es_extended/client/functions.lua b/resources/[essential]/es_extended/client/functions.lua new file mode 100644 index 00000000..8e52a0b2 --- /dev/null +++ b/resources/[essential]/es_extended/client/functions.lua @@ -0,0 +1,781 @@ +local charset = {} + +for i = 48, 57 do table.insert(charset, string.char(i)) end +for i = 65, 90 do table.insert(charset, string.char(i)) end +for i = 97, 122 do table.insert(charset, string.char(i)) end + +ESX = {} +ESX.CurrentRequestId = 0 +ESX.ServerCallbacks = {} +ESX.TimeoutCallbacks = {} +ESX.UI = {} +ESX.UI.HUD = {} +ESX.UI.HUD.RegisteredElements = {} +ESX.UI.Menu = {} +ESX.UI.Menu.RegisteredTypes = {} +ESX.UI.Menu.Opened = {} +ESX.Game = {} + +ESX.GetRandomString = function(length) + + math.randomseed(GetGameTimer()) + + if length > 0 then + return ESX.GetRandomString(length - 1) .. charset[math.random(1, #charset)] + else + return '' + end + +end + +ESX.SetTimeout = function(msec, cb) + table.insert(ESX.TimeoutCallbacks, { + time = GetGameTimer() + msec, + cb = cb + }) +end + +ESX.ShowNotification = function(msg) + SetNotificationTextEntry('STRING') + AddTextComponentString(msg) + DrawNotification(0,1) +end + +ESX.TriggerServerCallback = function(name, cb, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + + ESX.ServerCallbacks[ESX.CurrentRequestId] = cb + + TriggerServerEvent('esx:triggerServerCallback', name, ESX.CurrentRequestId, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + + if ESX.CurrentRequestId < 65535 then + ESX.CurrentRequestId = ESX.CurrentRequestId + 1 + else + ESX.CurrentRequestId = 0 + end + +end + +ESX.UI.HUD.SetDisplay = function(opacity) + + SendNUIMessage({ + action = 'setHUDDisplay', + opacity = opacity + }) + +end + +ESX.UI.HUD.RegisterElement = function(name, index, priority, html, data) + + local found = false + + for i=1, #ESX.UI.HUD.RegisteredElements, 1 do + if ESX.UI.HUD.RegisteredElements[i] == name then + found = true + break + end + end + + if found then + return + end + + table.insert(ESX.UI.HUD.RegisteredElements, name) + + SendNUIMessage({ + action = 'insertHUDElement', + name = name, + index = index, + priority = priority, + html = html, + data = data, + }) + + ESX.UI.HUD.UpdateElement(name, data) + +end + +ESX.UI.HUD.RemoveElement = function(name) + + for i=1, #ESX.UI.HUD.RegisteredElements, 1 do + if ESX.UI.HUD.RegisteredElements[i] == name then + table.remove(ESX.UI.HUD.RegisteredElements, i) + break + end + end + + SendNUIMessage({ + action = 'deleteHUDElement', + name = name + }) + +end + +ESX.UI.HUD.UpdateElement = function(name, data) + + SendNUIMessage({ + action = 'updateHUDElement', + name = name, + data = data, + }) + +end + +ESX.UI.Menu.RegisterType = function(type, open, close) + + ESX.UI.Menu.RegisteredTypes[type] = { + open = open, + close = close, + } + +end + +ESX.UI.Menu.Open = function(type, namespace, name, data, submit, cancel, change) + + local menu = {} + + menu.type = type + menu.namespace = namespace + menu.name = name + menu.data = data + menu.submit = submit + menu.cancel = cancel + menu.change = change + + menu.close = function() + + ESX.UI.Menu.RegisteredTypes[type].close(namespace, name) + + for i=1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i].type == type and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + ESX.UI.Menu.Opened[i] = nil + end + end + + end + + menu.update = function(query, newData) + + for i=1, #menu.data.elements, 1 do + + local match = true + + for k,v in pairs(query) do + if menu.data.elements[i][k] ~= v then + match = false + end + end + + if match then + for k,v in pairs(newData) do + menu.data.elements[i][k] = v + end + end + + ESX.UI.Menu.RegisteredTypes[type].open(namespace, name, menu.data) + + end + + end + + menu.setElement = function(i, key, val) + menu.data.elements[i][key] = val + end + + table.insert(ESX.UI.Menu.Opened, menu) + + ESX.UI.Menu.RegisteredTypes[type].open(namespace, name, data) + +end + +ESX.UI.Menu.Close = function(type, namespace, name) + + for i=1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i].type == type and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + ESX.UI.Menu.Opened[i].close() + ESX.UI.Menu.Opened[i] = nil + end + end + +end + +ESX.UI.Menu.CloseAll = function() + + for i=1, #ESX.UI.Menu.Opened, 1 do + ESX.UI.Menu.Opened[i].close() + ESX.UI.Menu.Opened[i] = nil + end + +end + +ESX.UI.Menu.GetOpened = function(type, namespace, name) + + for i=1, #ESX.UI.Menu.Opened, 1 do + if ESX.UI.Menu.Opened[i].type == type and ESX.UI.Menu.Opened[i].namespace == namespace and ESX.UI.Menu.Opened[i].name == name then + return ESX.UI.Menu.Opened[i] + end + end + +end + +ESX.UI.Menu.IsOpen = function(type, namespace, name) + return ESX.UI.Menu.GetOpened(type, namespace, name) ~= nil +end + +ESX.UI.ShowInventoryItemNotification = function(add, item, count) + SendNUIMessage({ + action = 'inventoryNotification', + add = add, + item = item, + count = count + }) +end + +ESX.GetWeaponList = function() + return Config.Weapons +end + +ESX.GetWeaponLabel = function(name) + + name = string.upper(name) + local weapons = ESX.GetWeaponList() + + for i=1, #weapons, 1 do + if weapons[i].name == name then + return weapons[i].label + end + end + +end + +ESX.Game.GetPlayers = function() + + local maxPlayers = Config.MaxPlayers + local players = {} + + for i=0, maxPlayers, 1 do + + local ped = GetPlayerPed(i) + + if DoesEntityExist(ped) then + table.insert(players, i) + end + end + + return players + +end + +ESX.Game.SpawnVehicle = function(modelName, coords, heading, cb) + + local playerPed = GetPlayerPed(-1) + local model = (type(modelName) == 'number' and modelName or GetHashKey(modelName)) + + Citizen.CreateThread(function() + + RequestModel(model) + + while not HasModelLoaded(model) do + Citizen.Wait(0) + end + + local vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, heading, true, false) + + SetNetworkIdCanMigrate(id, true) + SetEntityAsMissionEntity(vehicle, true, true) + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + SetModelAsNoLongerNeeded(model) + + RequestCollisionAtCoord(coords.x, coords.y, coords.z) + + while not HasCollisionLoadedAroundEntity(vehicle) do + RequestCollisionAtCoord(coords.x, coords.x, coords.x) + Citizen.Wait(0) + end + + local id = NetworkGetNetworkIdFromEntity(vehicle) + + if cb ~= nil then + cb(vehicle) + end + + end) + +end + +ESX.Game.SpawnLocalVehicle = function(modelName, coords, heading, cb) + + local playerPed = GetPlayerPed(-1) + local model = (type(modelName) == 'number' and modelName or GetHashKey(modelName)) + + Citizen.CreateThread(function() + + RequestModel(model) + + while not HasModelLoaded(model) do + Citizen.Wait(0) + end + + local vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, heading, false, false) + local id = NetworkGetNetworkIdFromEntity(vehicle) + + SetNetworkIdCanMigrate(id, true) + SetEntityAsMissionEntity(vehicle, true, true) + SetVehicleHasBeenOwnedByPlayer(vehicle, true) + SetModelAsNoLongerNeeded(model) + + RequestCollisionAtCoord(coords.x, coords.y, coords.z) + + while not HasCollisionLoadedAroundEntity(vehicle) do + RequestCollisionAtCoord(coords.x, coords.x, coords.x) + Citizen.Wait(0) + end + + if cb ~= nil then + cb(vehicle) + end + + end) + +end + +ESX.Game.GetClosestPlayer = function() + + local players = ESX.Game.GetPlayers() + local closestDistance = -1 + local closestPlayer = -1 + local playerPed = GetPlayerPed(-1) + local playerCoords = GetEntityCoords(playerPed) + + for i=1, #players, 1 do + + local target = GetPlayerPed(players[i]) + + -- if target ~= playerPed then + + local targetCoords = GetEntityCoords(target) + local distance = GetDistanceBetweenCoords(targetCoords.x, targetCoords.y, targetCoords.z, playerCoords.x, playerCoords.y, playerCoords.z, true) + + if closestDistance == -1 or closestDistance > distance then + closestPlayer = players[i] + closestDistance = distance + end + + -- end + + end + + return closestPlayer, closestDistance +end + +ESX.Game.GetPlayersInArea = function(coords, area) + + local players = ESX.Game.GetPlayers() + local playersInArea = {} + + for i=1, #players, 1 do + + local target = GetPlayerPed(players[i]) + local targetCoords = GetEntityCoords(target) + local distance = GetDistanceBetweenCoords(targetCoords.x, targetCoords.y, targetCoords.z, coords.x, coords.y, coords.z, true) + + if distance <= area then + table.insert(playersInArea, players[i]) + end + + end + + return playersInArea +end + +ESX.Game.GetVehicleProperties = function(vehicle) + + local colour1, colour2 = GetVehicleColours(vehicle) + local pearlescentColor, wheelColor = GetVehicleExtraColours(vehicle) + + return { + + model = GetEntityModel(vehicle), + + plate = GetVehicleNumberPlateText(vehicle), + plateIndex = GetVehicleNumberPlateTextIndex(vehicle), + + health = GetEntityHealth(vehicle), + dirtLevel = GetVehicleDirtLevel(vehicle), + + color1 = colour1, + color2 = colour2, + pearlescentColor = pearlescentColor, + wheelColor = wheelColor, + + wheels = GetVehicleWheelType(vehicle), + windowTint = GetVehicleWindowTint(vehicle), + + neonColor = table.pack(GetVehicleNeonLightsColour(vehicle)), + + modSpoilers = GetVehicleMod(vehicle, 0), + modFrontBumper = GetVehicleMod(vehicle, 1), + modRearBumper = GetVehicleMod(vehicle, 2), + modSideSkirt = GetVehicleMod(vehicle, 3), + modExhaust = GetVehicleMod(vehicle, 4), + modFrame = GetVehicleMod(vehicle, 5), + modGrille = GetVehicleMod(vehicle, 6), + modHood = GetVehicleMod(vehicle, 7), + modFender = GetVehicleMod(vehicle, 8), + modRightFender = GetVehicleMod(vehicle, 9), + modRoof = GetVehicleMod(vehicle, 10), + + modEngine = GetVehicleMod(vehicle, 11), + modBrakes = GetVehicleMod(vehicle, 12), + modTransmission = GetVehicleMod(vehicle, 13), + modHorns = GetVehicleMod(vehicle, 14), + modSuspension = GetVehicleMod(vehicle, 15), + modArmor = GetVehicleMod(vehicle, 16), + + modTurbo = IsToggleModOn(vehicle, 18), + modXenon = IsToggleModOn(vehicle, 22), + + modFrontWheels = GetVehicleMod(vehicle, 23), + modBackWheels = GetVehicleMod(vehicle, 24) + } + +end + +ESX.Game.SetVehicleProperties = function(vehicle, props) + + SetVehicleModKit(vehicle, 0) + + if props.plate ~= nil then + SetVehicleNumberPlateText(vehicle, props.plate) + end + + if props.plateIndex ~= nil then + SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex) + end + + if props.health ~= nil then + SetEntityHealth(vehicle, props.health) + end + + if props.dirtLevel ~= nil then + SetVehicleDirtLevel(vehicle, props.dirtLevel) + end + + if props.color1 ~= nil and props.color2 ~= nil then + SetVehicleColours(vehicle, props.color1, props.color2) + end + + if props.pearlescentColor ~= nil and props.wheelColor ~= nil then + SetVehicleExtraColours(vehicle, props.pearlescentColor, props.wheelColor) + end + + if props.wheels ~= nil then + SetVehicleWheelType(vehicle, props.wheels) + end + + if props.windowTint ~= nil then + SetVehicleWindowTint(vehicle, props.windowTint) + end + + if props.neonColor ~= nil then + SetVehicleNeonLightsColour(vehicle, props.neonColor[1], props.neonColor[2], props.neonColor[3]) + end + + if props.modSpoilers ~= nil then + SetVehicleMod(vehicle, 0, props.modSpoilers, false) + end + + if props.modFrontBumper ~= nil then + SetVehicleMod(vehicle, 1, props.modFrontBumper, false) + end + + if props.modRearBumper ~= nil then + SetVehicleMod(vehicle, 2, props.modRearBumper, false) + end + + if props.modSideSkirt ~= nil then + SetVehicleMod(vehicle, 3, props.modSideSkirt, false) + end + + if props.modExhaust ~= nil then + SetVehicleMod(vehicle, 4, props.modExhaust, false) + end + + if props.modFrame ~= nil then + SetVehicleMod(vehicle, 5, props.modFrame, false) + end + + if props.modGrille ~= nil then + SetVehicleMod(vehicle, 6, props.modGrille, false) + end + + if props.modHood ~= nil then + SetVehicleMod(vehicle, 7, props.modHood, false) + end + + if props.modFender ~= nil then + SetVehicleMod(vehicle, 8, props.modFender, false) + end + + if props.modRightFender ~= nil then + SetVehicleMod(vehicle, 9, props.modRightFender, false) + end + + if props.modRoof ~= nil then + SetVehicleMod(vehicle, 10, props.modRoof, false) + end + + if props.modEngine ~= nil then + SetVehicleMod(vehicle, 11, props.modEngine, false) + end + + if props.modBrakes ~= nil then + SetVehicleMod(vehicle, 12, props.modBrakes, false) + end + + if props.modTransmission ~= nil then + SetVehicleMod(vehicle, 13, props.modTransmission, false) + end + + if props.modHorns ~= nil then + SetVehicleMod(vehicle, 14, props.modHorns, false) + end + + if props.modSuspension ~= nil then + SetVehicleMod(vehicle, 15, props.modSuspension, false) + end + + if props.modArmor ~= nil then + SetVehicleMod(vehicle, 16, props.modArmor, false) + end + + if props.modTurbo ~= nil then + ToggleVehicleMod(vehicle, 18, props.modTurbo) + end + + if props.modXenon ~= nil then + ToggleVehicleMod(vehicle, 22, props.modXenon) + end + + if props.modFrontWheels ~= nil then + SetVehicleMod(vehicle, 23, props.modFrontWheels, false) + end + + if props.modBackWheels ~= nil then + SetVehicleMod(vehicle, 24, props.modBackWheels, false) + end + +end + +ESX.ShowInventory = function() + + ESX.TriggerServerCallback('esx:getPlayerData', function(data) + + local playerPed = GetPlayerPed(-1) + local elements = {} + + table.insert(elements, { + label = '[Cash] $' .. data.money, + count = data.money, + type = 'item_money', + value = 'money', + usable = false + }) + + for i=1, #data.accounts, 1 do + table.insert(elements, { + label = '[' .. data.accounts[i].label .. '] $' .. data.accounts[i].money, + count = data.accounts[i].money, + type = 'item_account', + value = data.accounts[i].name, + usable = false + }) + end + + for i=1, #data.inventory, 1 do + + if data.inventory[i].count > 0 then + table.insert(elements, { + label = data.inventory[i].label .. ' x' .. data.inventory[i].count, + count = data.inventory[i].count, + type = 'item_standard', + value = data.inventory[i].name, + usable = data.inventory[i].usable + }) + end + + end + + for i=1, #Config.Weapons, 1 do + + local weaponHash = GetHashKey(Config.Weapons[i].name) + + if HasPedGotWeapon(playerPed, weaponHash, false) and Config.Weapons[i].name ~= 'WEAPON_UNARMED' then + + local ammo = GetAmmoInPedWeapon(playerPed, weaponHash) + + table.insert(elements, { + label = Config.Weapons[i].label .. ' x1 [' .. ammo .. ']', + count = 1, + type = 'item_weapon', + value = Config.Weapons[i].name, + usable = false + }) + + end + end + + ESX.UI.Menu.CloseAll() + + ESX.UI.Menu.Open( + 'default', GetCurrentResourceName(), 'inventory', + { + title = 'Inventaire', + align = 'bottom-right', + elements = elements, + }, + function(data, menu) + + menu.close() + + local elements = {} + + if data.current.usable then + table.insert(elements, {label = 'Utiliser', action = 'use', type = data.current.type, value = data.current.value}) + end + + table.insert(elements, {label = 'Donner', action = 'give', type = data.current.type, value = data.current.value}) + table.insert(elements, {label = 'Jeter', action = 'remove', type = data.current.type, value = data.current.value}) + table.insert(elements, {label = 'Retour', action = 'return'}) + + ESX.UI.Menu.Open( + 'default', GetCurrentResourceName(), 'inventory_item', + { + title = 'Inventaire', + align = 'bottom-right', + elements = elements, + }, + function(data, menu) + + local item = data.current.value + local type = data.current.type + + if data.current.action == 'give' then + + if type == 'item_weapon' then + TriggerServerEvent('esx:giveInventoryItem', GetPlayerServerId(closestPlayer), type, item, 1) + else + + ESX.UI.Menu.Open( + 'dialog', GetCurrentResourceName(), 'inventory_item_count_give', + { + title = 'Quantité' + }, + function(data2, menu) + + local quantity = tonumber(data2.value) + local closestPlayer, closestDistance = ESX.Game.GetClosestPlayer() + + if closestPlayer == -1 or closestDistance > 3.0 then + ESX.ShowNotification('Aucun joueur à proximité') + else + TriggerServerEvent('esx:giveInventoryItem', GetPlayerServerId(closestPlayer), type, item, quantity) + end + + menu.close() + end, + function(data2, menu) + menu.close() + end + ) + + end + + elseif data.current.action == 'remove' then + + if type == 'item_weapon' then + TriggerServerEvent('esx:removeInventoryItem', type, item, 1) + else + + ESX.UI.Menu.Open( + 'dialog', GetCurrentResourceName(), 'inventory_item_count_remove', + { + title = 'Quantité' + }, + function(data2, menu) + + local quantity = tonumber(data2.value) + + if quantity == nil then + ESX.ShowNotification('Montant invalide') + else + + menu.close() + + TriggerServerEvent('esx:removeInventoryItem', type, item, quantity) + + end + + end, + function(data2, menu) + menu.close() + end + ) + + end + + elseif data.current.action == 'return' then + ESX.UI.Menu.CloseAll() + ESX.ShowInventory() + end + + end, + function(data, menu) + ESX.UI.Menu.CloseAll() + ESX.ShowInventory() + end + ) + + end, + function(data, menu) + menu.close() + end + ) + + end) + +end + +AddEventHandler('esx:getSharedObject', function(cb) + cb(ESX) +end) + +RegisterNetEvent('esx:serverCallback') +AddEventHandler('esx:serverCallback', function(requestId, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + ESX.ServerCallbacks[requestId](a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + ESX.ServerCallbacks[requestId] = nil +end) + +RegisterNetEvent('esx:showNotification') +AddEventHandler('esx:showNotification', function(msg) + ESX.ShowNotification(msg) +end) + +-- SetTimeout +Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + local currTime = GetGameTimer() + + for i=1, #ESX.TimeoutCallbacks, 1 do + + if currTime >= ESX.TimeoutCallbacks[i].time then + ESX.TimeoutCallbacks[i].cb() + ESX.TimeoutCallbacks[i] = nil + end + + end + + end +end) \ No newline at end of file diff --git a/resources/[essential]/es_extended/client/main.lua b/resources/[essential]/es_extended/client/main.lua new file mode 100644 index 00000000..a2e1adb1 --- /dev/null +++ b/resources/[essential]/es_extended/client/main.lua @@ -0,0 +1,372 @@ +local Keys = { + ["ESC"] = 322, ["F1"] = 288, ["F2"] = 289, ["F3"] = 170, ["F5"] = 166, ["F6"] = 167, ["F7"] = 168, ["F8"] = 169, ["F9"] = 56, ["F10"] = 57, + ["~"] = 243, ["1"] = 157, ["2"] = 158, ["3"] = 160, ["4"] = 164, ["5"] = 165, ["6"] = 159, ["7"] = 161, ["8"] = 162, ["9"] = 163, ["-"] = 84, ["="] = 83, ["BACKSPACE"] = 177, + ["TAB"] = 37, ["Q"] = 44, ["W"] = 32, ["E"] = 38, ["R"] = 45, ["T"] = 245, ["Y"] = 246, ["U"] = 303, ["P"] = 199, ["["] = 39, ["]"] = 40, ["ENTER"] = 18, + ["CAPS"] = 137, ["A"] = 34, ["S"] = 8, ["D"] = 9, ["F"] = 23, ["G"] = 47, ["H"] = 74, ["K"] = 311, ["L"] = 182, + ["LEFTSHIFT"] = 21, ["Z"] = 20, ["X"] = 73, ["C"] = 26, ["V"] = 0, ["B"] = 29, ["N"] = 249, ["M"] = 244, [","] = 82, ["."] = 81, + ["LEFTCTRL"] = 36, ["LEFTALT"] = 19, ["SPACE"] = 22, ["RIGHTCTRL"] = 70, + ["HOME"] = 213, ["PAGEUP"] = 10, ["PAGEDOWN"] = 11, ["DELETE"] = 178, + ["LEFT"] = 174, ["RIGHT"] = 175, ["TOP"] = 27, ["DOWN"] = 173, + ["NENTER"] = 201, ["N4"] = 108, ["N5"] = 60, ["N6"] = 107, ["N+"] = 96, ["N-"] = 97, ["N7"] = 117, ["N8"] = 61, ["N9"] = 118 +} + +local GUI = {} +GUI.Time = 0 +local PlayerLoaded = false +local LoadoutLoaded = false +local IsPaused = false +local LastLoadout = {} + +RegisterNetEvent('esx:playerLoaded') +AddEventHandler('esx:playerLoaded', function(xPlayer) + + PlayerLoaded = true + + for i=1, #xPlayer.accounts, 1 do + + local accountTpl = '
 {{money}}
' + + ESX.UI.HUD.RegisterElement('account_' .. xPlayer.accounts[i].name, i-1, 0, accountTpl, { + money = 0 + }) + + ESX.UI.HUD.UpdateElement('account_' .. xPlayer.accounts[i].name, { + money = xPlayer.accounts[i].money + }) + + end + + local jobTpl = '
{{job_label}} - {{grade_label}}
' + + if xPlayer.job.grade_label == '' then + jobTpl = '
{{job_label}}
' + end + + ESX.UI.HUD.RegisterElement('job', #xPlayer.accounts, 0, jobTpl, { + job_label = '', + grade_label = '' + }) + + ESX.UI.HUD.UpdateElement('job', { + job_label = xPlayer.job.label, + grade_label = xPlayer.job.grade_label + }) + +end) + +AddEventHandler('playerSpawned', function() + + Citizen.CreateThread(function() + + while not PlayerLoaded do + Citizen.Wait(0) + end + + ESX.TriggerServerCallback('esx:getPlayerData', function(data) + + local playerPed = GetPlayerPed(-1) + + -- Restore position + if data.lastPosition ~= nil then + SetEntityCoords(playerPed, data.lastPosition.x, data.lastPosition.y, data.lastPosition.z) + end + + -- Restore loadout + for i=1, #data.loadout, 1 do + local weaponHash = GetHashKey(data.loadout[i].name) + GiveWeaponToPed(playerPed, weaponHash, data.loadout[i].ammo, false, false) + end + + LoadoutLoaded = true + + end) + + end) + +end) + +AddEventHandler('skinchanger:LoadDefaultModel', function() + LoadoutLoaded = false +end) + +AddEventHandler('skinchanger:modelLoaded', function() + + -- Restore loadout + ESX.TriggerServerCallback('esx:getPlayerData', function(data) + + local playerPed = GetPlayerPed(-1) + + for i=1, #data.loadout, 1 do + local weaponHash = GetHashKey(data.loadout[i].name) + GiveWeaponToPed(playerPed, weaponHash, data.loadout[i].ammo, false, false) + end + + LoadoutLoaded = true + + end) + +end) + +RegisterNetEvent('esx:setAccountMoney') +AddEventHandler('esx:setAccountMoney', function(account) + ESX.UI.HUD.UpdateElement('account_' .. account.name, { + money = account.money + }) +end) + +RegisterNetEvent('esx:addInventoryItem') +AddEventHandler('esx:addInventoryItem', function(item, count) + + ESX.UI.ShowInventoryItemNotification(true, item, count) + + if ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then + ESX.ShowInventory() + end + +end) + +RegisterNetEvent('esx:removeInventoryItem') +AddEventHandler('esx:removeInventoryItem', function(item, count) + + ESX.UI.ShowInventoryItemNotification(false, item, count) + + if ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') then + ESX.ShowInventory() + end + +end) + +RegisterNetEvent('esx:addWeapon') +AddEventHandler('esx:addWeapon', function(weaponName, ammo) + local playerPed = GetPlayerPed(-1) + local weaponHash = GetHashKey(weaponName) + + GiveWeaponToPed(playerPed, weaponHash, ammo, false, false) +end) + +RegisterNetEvent('esx:removeWeapon') +AddEventHandler('esx:removeWeapon', function(weaponName) + local playerPed = GetPlayerPed(-1) + local weaponHash = GetHashKey(weaponName) + + RemoveWeaponFromPed(playerPed, weaponHash) +end) + +-- Commands +RegisterNetEvent('esx:teleport') +AddEventHandler('esx:teleport', function(pos) + + pos.x = pos.x + 0.0 + pos.y = pos.y + 0.0 + pos.z = pos.z + 0.0 + + RequestCollisionAtCoord(pos.x, pos.y, pos.z) + + while not HasCollisionLoadedAroundEntity(GetPlayerPed(-1)) do + RequestCollisionAtCoord(pos.x, pos.y, pos.z) + Citizen.Wait(0) + end + + SetEntityCoords(GetPlayerPed(-1), pos.x, pos.y, pos.z) + +end) + +RegisterNetEvent('esx:setJob') +AddEventHandler('esx:setJob', function(job) + ESX.UI.HUD.UpdateElement('job', { + job_label = job.label, + grade_label = job.grade_label + }) +end) + +RegisterNetEvent('esx:loadIPL') +AddEventHandler('esx:loadIPL', function(name) + + Citizen.CreateThread(function() + LoadMpDlcMaps() + EnableMpDlcMaps(true) + RequestIpl(name) + end) + +end) + +RegisterNetEvent('esx:unloadIPL') +AddEventHandler('esx:unloadIPL', function(name) + + Citizen.CreateThread(function() + RemoveIpl(name) + end) + +end) + +RegisterNetEvent('esx:playAnim') +AddEventHandler('esx:playAnim', function(dict, anim) + + Citizen.CreateThread(function() + + local pid = PlayerPedId() + + RequestAnimDict(dict) + + while not HasAnimDictLoaded(dict) do + Wait(0) + end + + TaskPlayAnim(pid, dict, anim, 1.0, -1.0, 20000, 0, 1, true, true, true) + + end) + +end) + +RegisterNetEvent('esx:playEmote') +AddEventHandler('esx:playEmote', function(emote) + + Citizen.CreateThread(function() + + local playerPed = GetPlayerPed(-1) + + TaskStartScenarioInPlace(playerPed, emote, 0, false); + Wait(20000) + ClearPedTasks(playerPed) + + end) + +end) + +RegisterNetEvent('esx:spawnVehicle') +AddEventHandler('esx:spawnVehicle', function(model) + + local playerPed = GetPlayerPed(-1) + local coords = GetEntityCoords(playerPed) + + ESX.Game.SpawnVehicle(model, coords, 90.0, function(vehicle) + TaskWarpPedIntoVehicle(playerPed, vehicle, -1) + end) + +end) + +-- Pause menu disable HUD display +Citizen.CreateThread(function() + while true do + Citizen.Wait(1) + if IsPauseMenuActive() and not IsPaused then + IsPaused = true + TriggerEvent('es:setMoneyDisplay', 0.0) + ESX.UI.HUD.SetDisplay(0.0) + elseif not IsPauseMenuActive() and IsPaused then + IsPaused = false + TriggerEvent('es:setMoneyDisplay', 1.0) + ESX.UI.HUD.SetDisplay(1.0) + end + end +end) + +-- Save loadout +Citizen.CreateThread(function() + + while true do + + Wait(0) + + local playerPed = GetPlayerPed(-1) + local loadout = {} + local loadoutChanged = false + + if IsPedDeadOrDying(playerPed) then + LoadoutLoaded = false + end + + for i=1, #Config.Weapons, 1 do + + local weaponHash = GetHashKey(Config.Weapons[i].name) + + if HasPedGotWeapon(playerPed, weaponHash, false) and Config.Weapons[i].name ~= 'WEAPON_UNARMED' then + + local ammo = GetAmmoInPedWeapon(playerPed, weaponHash) + + if LastLoadout[Config.Weapons[i].name] == nil or LastLoadout[Config.Weapons[i].name] ~= ammo then + loadoutChanged = true + end + + LastLoadout[Config.Weapons[i].name] = ammo + + table.insert(loadout, { + name = Config.Weapons[i].name, + ammo = ammo, + label = Config.Weapons[i].label + }) + + else + + if LastLoadout[Config.Weapons[i].name] ~= nil then + loadoutChanged = true + end + + LastLoadout[Config.Weapons[i].name] = nil + + end + + end + + if loadoutChanged and LoadoutLoaded then + TriggerServerEvent('esx:updateLoadout', loadout) + end + + end +end) + +-- Menu interactions +Citizen.CreateThread(function() + while true do + + Wait(0) + + if IsControlPressed(0, Keys["F2"]) and not ESX.UI.Menu.IsOpen('default', 'es_extended', 'inventory') and (GetGameTimer() - GUI.Time) > 150 then + ESX.ShowInventory() + GUI.Time = GetGameTimer() + end + + end +end) + +-- Dot above head +if Config.ShowDotAbovePlayer then + + Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + local players = ESX.Game.GetPlayers() + + for i = 1, #players, 1 do + if players[i] ~= PlayerId() then + local ped = GetPlayerPed(players[i]) + local headId = Citizen.InvokeNative(0xBFEFE3321A3F5015, ped, ('·'), false, false, '', false) + end + end + + end + end) + +end + +-- Disable wanted level +if Config.DisableWantedLevel then + + Citizen.CreateThread(function() + while true do + + Citizen.Wait(0) + + local playerId = PlayerId() + + if GetPlayerWantedLevel(playerId) ~= 0 then + SetPlayerWantedLevel(playerId, 0, false) + SetPlayerWantedLevelNow(playerId, false) + end + + end + end) + +end \ No newline at end of file diff --git a/resources/[essential]/es_extended/config.lua b/resources/[essential]/es_extended/config.lua new file mode 100644 index 00000000..22f1c7c9 --- /dev/null +++ b/resources/[essential]/es_extended/config.lua @@ -0,0 +1,89 @@ +Config = {} +Config.MaxPlayers = 32 +Config.Accounts = {'bank', 'black_money'} +Config.AccountLabels = {bank = 'Banque', black_money = 'Argent Sale'} +Config.PaycheckInterval = 7 * 60000 +Config.ShowDotAbovePlayer = false +Config.DisableWantedLevel = true +Config.RemoveInventoryItemDelay = 5 * 60000 + +Config.Weapons = { + + {name = 'WEAPON_KNIFE', label = 'Couteau'}, + {name = 'WEAPON_NIGHTSTICK', label = 'Matraque'}, + {name = 'WEAPON_HAMMER', label = 'Marteau'}, + {name = 'WEAPON_BAT', label = 'Bat'}, + {name = 'WEAPON_GOLFCLUB', label = 'Club de golfe'}, + {name = 'WEAPON_CROWBAR', label = 'Pied de biche'}, + {name = 'WEAPON_PISTOL', label = 'Pistolet'}, + {name = 'WEAPON_COMBATPISTOL', label = 'Pistolet de combat'}, + {name = 'WEAPON_APPISTOL', label = 'Pistolet automatique'}, + {name = 'WEAPON_PISTOL50', label = 'Pistolet calibre 50'}, + {name = 'WEAPON_MICROSMG', label = 'Micro SMG'}, + {name = 'WEAPON_SMG', label = 'SMG'}, + {name = 'WEAPON_ASSAULTSMG', label = 'SMG d\'assaut'}, + {name = 'WEAPON_ASSAULTRIFLE', label = 'Fusil d\'assaut'}, + {name = 'WEAPON_CARBINERIFLE', label = 'Carabine d\'assaut'}, + {name = 'WEAPON_ADVANCEDRIFLE', label = 'Fusil avancé'}, + {name = 'WEAPON_MG', label = 'Mitrailleuse'}, + {name = 'WEAPON_COMBATMG', label = 'Mitrailleuse de combat'}, + {name = 'WEAPON_PUMPSHOTGUN', label = 'Fusil à pompe'}, + {name = 'WEAPON_SAWNOFFSHOTGUN', label = 'Carabine à canon scié'}, + {name = 'WEAPON_ASSAULTSHOTGUN', label = 'Carabine d\'assaut'}, + {name = 'WEAPON_BULLPUPSHOTGUN', label = 'Carabine Bullpup'}, + {name = 'WEAPON_STUNGUN', label = 'Tazer'}, + {name = 'WEAPON_SNIPERRIFLE', label = 'Fusil de sniper'}, + {name = 'WEAPON_HEAVYSNIPER', label = 'Fusil de sniper lourd'}, + {name = 'WEAPON_REMOTESNIPER', label = 'Fusil de sniper à distance'}, + {name = 'WEAPON_GRENADELAUNCHER', label = 'Lance-grenade'}, + {name = 'WEAPON_RPG', label = 'Lance-rocket'}, + {name = 'WEAPON_STINGER', label = 'Lance-Missile Stinger'}, + {name = 'WEAPON_MINIGUN', label = 'Minigun'}, + {name = 'WEAPON_GRENADE', label = 'Grenade'}, + {name = 'WEAPON_STICKYBOMB', label = 'Bombe collante'}, + {name = 'WEAPON_SMOKEGRENADE', label = 'Grenade fumigène'}, + {name = 'WEAPON_BZGAS', 'Grenade à gaz BZ'}, + {name = 'WEAPON_MOLOTOV', 'Cocktail molotov'}, + {name = 'WEAPON_FIREEXTINGUISHER', 'Extincteur'}, + {name = 'WEAPON_PETROLCAN', 'Jerrican d\'essence'}, + {name = 'WEAPON_DIGISCANNER', 'Digiscanner'}, + {name = 'WEAPON_BALL', 'Balle'}, + {name = 'WEAPON_SNSPISTOL', label = 'Pistolet SNS'}, + {name = 'WEAPON_BOTTLE', label = 'Bouteille'}, + {name = 'WEAPON_GUSENBERG', label = 'Balayeuse Gusenberg'}, + {name = 'WEAPON_SPECIALCARBINE', label = 'Carabine spéciale'}, + {name = 'WEAPON_HEAVYPISTOL', label = 'Pistolet lourd'}, + {name = 'WEAPON_BULLPUPRIFLE', label = 'Fusil Bullpup'}, + {name = 'WEAPON_DAGGER', label = 'Poignard'}, + {name = 'WEAPON_VINTAGEPISTOL', label = 'Pistolet vintage'}, + {name = 'WEAPON_FIREWORK', label = 'Feu d\'artifice'}, + {name = 'WEAPON_MUSKET', label = 'Mousquet'}, + {name = 'WEAPON_HEAVYSHOTGUN', label = 'Fusil à pompe lourd'}, + {name = 'WEAPON_MARKSMANRIFLE', label = 'Fusil Marksman'}, + {name = 'WEAPON_HOMINGLAUNCHER', label = 'Lance tête-chercheuse'}, + {name = 'WEAPON_PROXMINE', label = 'Mine de proximité'}, + {name = 'WEAPON_SNOWBALL', label = 'Boule de neige'}, + {name = 'WEAPON_FLAREGUN', label = 'Lance fusée de détresse'}, + {name = 'WEAPON_GARBAGEBAG', label = 'Sac poubelle'}, + {name = 'WEAPON_HANDCUFFS', label = 'Menottes'}, + {name = 'WEAPON_COMBATPDW', label = 'Arme de défense personnelle'}, + {name = 'WEAPON_MARKSMANPISTOL', label = 'Pistolet Marksman'}, + {name = 'WEAPON_KNUCKLE', label = 'Poing américain'}, + {name = 'WEAPON_HATCHET', label = 'Hachette'}, + {name = 'WEAPON_RAILGUN', label = 'Canon éléctrique'}, + {name = 'WEAPON_MACHETE', label = 'Machetta'}, + {name = 'WEAPON_MACHINEPISTOL', label = 'Pistolet mitrailleur'}, + {name = 'WEAPON_SWITCHBLADE', label = 'Couteau à cran d\'arrêt'}, + {name = 'WEAPON_REVOLVER', label = 'Revolver'}, + {name = 'WEAPON_DBSHOTGUN', label = 'Fusil à pompe double canon'}, + {name = 'WEAPON_COMPACTRIFLE', label = 'Fusil compact'}, + {name = 'WEAPON_AUTOSHOTGUN', label = 'Fusil à pompe automatique'}, + {name = 'WEAPON_BATTLEAXE', label = 'Hache de combat'}, + {name = 'WEAPON_COMPACTLAUNCHER', label = 'Lanceur compact'}, + {name = 'WEAPON_MINISMG', label = 'Mini SMG'}, + {name = 'WEAPON_PIPEBOMB', label = 'Bombe tuyau'}, + {name = 'WEAPON_POOLCUE', label = 'Queue de billard'}, + {name = 'WEAPON_WRENCH', label = 'Clé'}, + {name = 'GADGET_NIGHTVISION', label = 'Vision nocturne'}, + {name = 'GADGET_PARACHUTE', label = 'Parachute'}, +} \ No newline at end of file diff --git a/resources/[essential]/es_extended/html/css/app.css b/resources/[essential]/es_extended/html/css/app.css new file mode 100644 index 00000000..2f72814b --- /dev/null +++ b/resources/[essential]/es_extended/html/css/app.css @@ -0,0 +1,101 @@ +@font-face { + font-family: 'Pricedown'; + src: url('../fonts/pdown.ttf') /* TTF file for CSS3 browsers */ +} + +@font-face { + font-family: 'bankgothic'; + src: url('../fonts/bankgothic.ttf') /* TTF file for CSS3 browsers */ +} + +html { + overflow: hidden; +} + +#cursor { + position: absolute; + z-index: 999999; + display: none; +} + +#hud { + position : absolute; + font-family: 'Pricedown'; + font-size : 35px; + color : white; + padding : 4px; + text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; + + text-align: right; + top : 80; + right : 40; +} + +#inventory_notifications { + font-family: bankgothic; + position : absolute; + right : 40; + bottom : 40; + font-size : 2em; + font-weight: bold; + color : #FFF; + text-shadow: + -1px -1px 0 #000, + 1px -1px 0 #000, + -1px 1px 0 #000, + 1px 1px 0 #000; +} + +.menu { + font-family: 'Open Sans', sans-serif; + min-width : 400px; + min-height: : 250px; + color : #fff; + position : absolute; + left : 40; + top : 0; +} + +.menu .head { + font-family: 'Open Sans', sans-serif; + font-size: 28px; + padding: 10px; + background: #1A1A1A; + border-bottom: 3px solid #BC1635; + border-radius: 10px 10px 0 0; + -webkit-border-radius: 10px 10px 0 0; + -moz-border-radius: 10px 10px 0 0; + -o-border-radius: 10px 10px 0 0; + box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -webkit-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -moz-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + -o-box-shadow: inset 0px 1px 0 rgba(255, 255, 255, 0.28); + box-shadow: 1px 1px 10px 4px rgba(0, 0, 0, 0.4); +} +.menu .head span { + font-family: 'Pricedown'; + font-size: 28px; + padding-left: 15px; + padding-top: 6px; +} + +.menu .menu-items .menu-item { + font-family : 'Open Sans', sans-serif; + font-size : 14px; + height : 40px; + display : block; + background-color: #f1f1f1; + box-shadow : inset 1px 0px 0px 1px #b8b8b8; + height : 32px; + line-height : 32px; + color : #3A3A3A; + text-align : center; +} + +.menu .menu-items .menu-item.selected { + background-color: #ccc; +} diff --git a/resources/[essential]/es_extended/html/fonts/bankgothic.ttf b/resources/[essential]/es_extended/html/fonts/bankgothic.ttf new file mode 100644 index 00000000..f3d8049b Binary files /dev/null and b/resources/[essential]/es_extended/html/fonts/bankgothic.ttf differ diff --git a/resources/[essential]/es_extended/html/fonts/pdown.ttf b/resources/[essential]/es_extended/html/fonts/pdown.ttf new file mode 100644 index 00000000..69c76cf3 Binary files /dev/null and b/resources/[essential]/es_extended/html/fonts/pdown.ttf differ diff --git a/resources/[essential]/es_extended/html/img/accounts/bank.png b/resources/[essential]/es_extended/html/img/accounts/bank.png new file mode 100644 index 00000000..eb36dc8e Binary files /dev/null and b/resources/[essential]/es_extended/html/img/accounts/bank.png differ diff --git a/resources/[essential]/es_extended/html/img/accounts/black_money.png b/resources/[essential]/es_extended/html/img/accounts/black_money.png new file mode 100644 index 00000000..a42f6aa5 Binary files /dev/null and b/resources/[essential]/es_extended/html/img/accounts/black_money.png differ diff --git a/resources/[essential]/es_extended/html/img/cursor.png b/resources/[essential]/es_extended/html/img/cursor.png new file mode 100644 index 00000000..39536f95 Binary files /dev/null and b/resources/[essential]/es_extended/html/img/cursor.png differ diff --git a/resources/[essential]/es_extended/html/img/keys/enter.png b/resources/[essential]/es_extended/html/img/keys/enter.png new file mode 100644 index 00000000..3eb9a1f6 Binary files /dev/null and b/resources/[essential]/es_extended/html/img/keys/enter.png differ diff --git a/resources/[essential]/es_extended/html/img/keys/return.png b/resources/[essential]/es_extended/html/img/keys/return.png new file mode 100644 index 00000000..a3ca125a Binary files /dev/null and b/resources/[essential]/es_extended/html/img/keys/return.png differ diff --git a/resources/[essential]/es_extended/html/js/app.js b/resources/[essential]/es_extended/html/js/app.js new file mode 100644 index 00000000..6da6d52b --- /dev/null +++ b/resources/[essential]/es_extended/html/js/app.js @@ -0,0 +1,114 @@ +(() => { + + ESX = {}; + ESX.HUDElements = []; + + ESX.setHUDDisplay = function(opacity){ + $('#hud').css('opacity', opacity); + } + + ESX.insertHUDElement = function(name, index, priority, html, data){ + + ESX.HUDElements.push({ + name : name, + index : index, + priority : priority, + html : html, + data : data + }) + + ESX.HUDElements.sort((a,b) => { + return a.index - b.index || b.priority - a.priority; + }) + + } + + ESX.updateHUDElement = function(name, data){ + + for(let i=0; i' + notif + ''); + + $('#inventory_notifications').append(elem); + + $(elem).delay(3000).fadeOut(1000, function(){ + elem.remove(); + }) + } + + window.onData = (data) => { + + switch(data.action){ + + case 'setHUDDisplay' : { + ESX.setHUDDisplay(data.opacity); + break; + } + + case 'insertHUDElement' : { + ESX.insertHUDElement(data.name, data.index, data.priority, data.html, data.data); + break; + } + + case 'updateHUDElement' : { + ESX.updateHUDElement(data.name, data.data); + break; + } + + case 'deleteHUDElement' : { + ESX.deleteHUDElement(data.name); + break; + } + + case 'inventoryNotification' : { + ESX.inventoryNotification(data.add, data.item, data.count) + } + + } + + } + + window.onload = function(e){ + window.addEventListener('message', (event) => { + onData(event.data) + }); + } + +})() \ No newline at end of file diff --git a/resources/[essential]/es_extended/html/js/mustache.min.js b/resources/[essential]/es_extended/html/js/mustache.min.js new file mode 100644 index 00000000..520cfcb9 --- /dev/null +++ b/resources/[essential]/es_extended/html/js/mustache.min.js @@ -0,0 +1 @@ +(function defineMustache(global,factory){if(typeof exports==="object"&&exports&&typeof exports.nodeName!=="string"){factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],factory)}else{global.Mustache={};factory(global.Mustache)}})(this,function mustacheFactory(mustache){var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function eos(){return this.tail===""};Scanner.prototype.scan=function scan(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function scanUntil(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function push(view){return new Context(view,this)};Context.prototype.lookup=function lookup(name){var cache=this.cache;var value;if(cache.hasOwnProperty(name)){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index")value=this.renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this.unescapedValue(token,context);else if(symbol==="name")value=this.escapedValue(token,context);else if(symbol==="text")value=this.rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype.renderSection=function renderSection(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;j + + + + + +
+
+ + + + + + + + \ No newline at end of file diff --git a/resources/[essential]/es_extended/server/classes/player.lua b/resources/[essential]/es_extended/server/classes/player.lua new file mode 100644 index 00000000..954dcf63 --- /dev/null +++ b/resources/[essential]/es_extended/server/classes/player.lua @@ -0,0 +1,382 @@ +function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, lastPosition) + + local self = {} + + self.player = player + self.accounts = accounts + self.inventory = inventory + self.job = job + self.loadout = loadout + self.name = name + self.lastPosition = lastPosition + + self.source = self.player.get('source') + self.identifier = self.player.get('identifier') + + self.setMoney = function(m) + self.player.setMoney(m) + end + + self.getMoney = function() + return self.player.get('money') + end + + self.setBankBalance = function(m) + self.player.setBankBalance(m) + end + + self.getBank = function() + return self.player.get('bank') + end + + self.getCoords = function() + return self.player.get('coords') + end + + self.setCoords = function(x, y, z) + self.player.coords = {x = x, y = y, z = z} + end + + self.kick = function(r) + self.player.kick(r) + end + + self.addMoney = function(m) + self.player.addMoney(m) + end + + self.removeMoney = function(m) + self.player.removeMoney(m) + end + + self.addBank = function(m) + self.player.addBank(m) + end + + self.removeBank = function(m) + self.player.removeBank(m) + end + + self.displayMoney = function(m) + self.player.displayMoney(m) + end + + self.displayBank = function(m) + self.player.displayBank(m) + end + + self.setSessionVar = function(key, value) + self.player.setSessionVar(key, value) + end + + self.getSessionVar = function(k) + return self.player.getSessionVar(k) + end + + self.getPermissions = function() + return self.player.getPermissions() + end + + self.setPermissions = function(p) + self.player.setPermissions(p) + end + + self.getIdentifier = function() + return self.player.getIdentifier() + end + + self.getGroup = function() + return self.player.getGroup() + end + + self.set = function(k, v) + self.player.set(k, v) + end + + self.get = function(k) + return self.player.get(k) + end + + self.getPlayer = function() + return self.player + end + + self.getAccounts = function() + + local accounts = {} + + for i=1, #Config.Accounts, 1 do + + if Config.Accounts[i] == 'bank' then + + table.insert(accounts, { + name = 'bank', + money = self.get('bank'), + label = Config.AccountLabels['bank'] + }) + + else + + for j=1, #self.accounts, 1 do + if self.accounts[j].name == Config.Accounts[i] then + table.insert(accounts, self.accounts[j]) + end + end + + end + end + + return accounts + + end + + self.getAccount = function(a) + + if a == 'bank' then + + return { + name = 'bank', + money = self.get('bank'), + label = Config.AccountLabels['bank'] + } + + end + + for i=1, #self.accounts, 1 do + if self.accounts[i].name == a then + return self.accounts[i] + end + end + end + + self.getInventory = function() + return self.inventory + end + + self.getJob = function() + return self.job + end + + self.getLoadout = function() + return self.loadout + end + + self.getName = function() + return self.name + end + + self.getLastPosition = function() + return self.lastPosition + end + + self.getMissingAccounts = function(cb) + + MySQL.Async.fetchAll( + 'SELECT * FROM `user_accounts` WHERE `identifier` = @identifier', + { + ['@identifier'] = self.getIdentifier() + }, + function(result) + + local missingAccounts = {}; + + for i=1, #Config.Accounts, 1 do + + if Config.Accounts[i] ~= 'bank' then + + local found = false + + for j=1, #result, 1 do + if Config.Accounts[i] == result[j].name then + found = true + end + end + + if not found then + table.insert(missingAccounts, Config.Accounts[i]) + end + + end + + end + + cb(missingAccounts) + + end + ) + + end + + self.createAccounts = function(missingAccounts, cb) + + for i=1, #missingAccounts, 1 do + MySQL.Async.execute( + 'INSERT INTO `user_accounts` (identifier, name) VALUES (@identifier, @name)', + { + ['@identifier'] = self.getIdentifier(), + ['@name'] = missingAccounts[i] + }, + function(rowsChanged) + if cb ~= nil then + cb() + end + end + ) + end + + end + + self.setAccountMoney = function(a, m) + + local account = self.getAccount(a) + local prevMoney = account.money + local newMoney = m + + account.money = newMoney + + if a == 'bank' then + self.set('bank', newMoney) + end + + TriggerClientEvent('esx:setAccountMoney', self.source, account) + end + + self.addAccountMoney = function(a, m) + + local account = self.getAccount(a) + local newMoney = account.money + m + + account.money = newMoney + + if a == 'bank' then + self.set('bank', newMoney) + end + + TriggerClientEvent('esx:setAccountMoney', self.source, account) + end + + self.removeAccountMoney = function(a, m) + local account = self.getAccount(a) + local newMoney = account.money - m + + account.money = newMoney + + if a == 'bank' then + self.set('bank', newMoney) + end + + TriggerClientEvent('esx:setAccountMoney', self.source, account) + end + + self.getInventoryItem = function(name) + + for i=1, #self.inventory, 1 do + if self.inventory[i].name == name then + return self.inventory[i] + end + end + + end + + self.addInventoryItem = function(name, count) + + local item = self.getInventoryItem(name) + local newCount = item.count + count + item.count = newCount + + TriggerEvent("esx:onAddInventoryItem", self.source, item, count) + TriggerClientEvent("esx:addInventoryItem", self.source, item, count) + + end + + self.removeInventoryItem = function(name, count) + + local item = self.getInventoryItem(name) + local newCount = item.count - count + item.count = newCount + + TriggerEvent("esx:onRemoveInventoryItem", self.source, item, count) + TriggerClientEvent("esx:removeInventoryItem", self.source, item, count) + + end + + self.setJob = function(name, grade) + + MySQL.Async.fetchAll( + 'SELECT * FROM `jobs` WHERE `name` = @name', + { + ['@name'] = name + }, + function(result) + + self.job['id'] = result[1].id + self.job['name'] = result[1].name + self.job['label'] = result[1].label + + MySQL.Async.fetchAll( + 'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade', + { + ['@job_name'] = name, + ['@grade'] = grade + }, + function(result) + + self.job['grade'] = grade + self.job['grade_name'] = result[1].name + self.job['grade_label'] = result[1].label + self.job['grade_salary'] = result[1].salary + + self.job['skin_male'] = nil + self.job['skin_female'] = nil + + if result[1].skin_male ~= nil then + self.job['skin_male'] = json.decode(result[1].skin_male) + end + + if result[1].skin_female ~= nil then + self.job['skin_female'] = json.decode(result[1].skin_female) + end + + TriggerClientEvent("esx:setJob", self.source, self.job) + + end + ) + + end + ) + + end + + self.addWeapon = function(weaponName, ammo) + + local weaponLabel = weaponName + + for i=1, #Config.Weapons, 1 do + if Config.Weapons[i].name == weaponName then + weaponLabel = Config.Weapons[i].label + break + end + end + + TriggerClientEvent('esx:addWeapon', self.source, weaponName, ammo) + TriggerClientEvent("esx:addInventoryItem", self.source, {label = weaponLabel}, 1) + end + + self.removeWeapon = function(weaponName) + + local weaponLabel = weaponName + + for i=1, #Config.Weapons, 1 do + if Config.Weapons[i].name == weaponName then + weaponLabel = Config.Weapons[i].label + break + end + end + + TriggerClientEvent('esx:removeWeapon', self.source, weaponName) + TriggerClientEvent("esx:removeInventoryItem", self.source, {label = weaponLabel}, 1) + end + + return self + +end \ No newline at end of file diff --git a/resources/[essential]/es_extended/server/commands.lua b/resources/[essential]/es_extended/server/commands.lua new file mode 100644 index 00000000..2d4ccc12 --- /dev/null +++ b/resources/[essential]/es_extended/server/commands.lua @@ -0,0 +1,48 @@ +TriggerEvent('es:addGroupCommand', 'tp', 'admin', function(source, args, user) + + TriggerClientEvent("esx:teleport", source, { + x = tonumber(args[2]), + y = tonumber(args[3]), + z = tonumber(args[4]) + }) + +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end) + +TriggerEvent('es:addGroupCommand', 'setjob', 'jobmaster', function(source, args, user) + local xPlayer = ESX.GetPlayerFromId(args[2]) + xPlayer.setJob(args[3], tonumber(args[4])) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Assigner job => setjob [id] [job] [grade_id]'}) + +TriggerEvent('es:addGroupCommand', 'loadipl', 'admin', function(source, args, user) + TriggerClientEvent('esx:loadIPL', -1, args[2]) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Charger ipl'}) + +TriggerEvent('es:addGroupCommand', 'unloadipl', 'admin', function(source, args, user) + TriggerClientEvent('esx:unloadIPL', -1, args[2]) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Décharger ipl'}) + +TriggerEvent('es:addGroupCommand', 'playanim', 'admin', function(source, args, user) + TriggerClientEvent('esx:playAnim', -1, args[2], args[3]) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Jouer animation'}) + +TriggerEvent('es:addGroupCommand', 'playemote', 'admin', function(source, args, user) + TriggerClientEvent('esx:playEmote', -1, args[2]) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Jouer emote'}) + +TriggerEvent('es:addGroupCommand', 'car', 'admin', function(source, args, user) + TriggerClientEvent('esx:spawnVehicle', source, args[2]) +end, function(source, args, user) + TriggerClientEvent('chatMessage', source, "SYSTEM", {255, 0, 0}, "Insufficient Permissions.") +end, {help = 'Spawn un véhicule'}) \ No newline at end of file diff --git a/resources/[essential]/es_extended/server/common.lua b/resources/[essential]/es_extended/server/common.lua new file mode 100644 index 00000000..915707f8 --- /dev/null +++ b/resources/[essential]/es_extended/server/common.lua @@ -0,0 +1,28 @@ +ESX = {} +ESX.Players = {} +ESX.UsableItemsCallbacks = {} +ESX.Items = {} +ESX.ServerCallbacks = {} + +AddEventHandler('esx:getSharedObject', function(cb) + cb(ESX) +end) + +AddEventHandler('onMySQLReady', function () + + MySQL.Async.fetchAll( + 'SELECT * FROM items', + {}, + function(result) + + for i=1, #result, 1 do + ESX.Items[result[i].name] = { + label = result[i].label, + limit = result[i].limit + } + end + + end + ) + +end) \ No newline at end of file diff --git a/resources/[essential]/es_extended/server/functions.lua b/resources/[essential]/es_extended/server/functions.lua new file mode 100644 index 00000000..44b01413 --- /dev/null +++ b/resources/[essential]/es_extended/server/functions.lua @@ -0,0 +1,176 @@ +local charset = {} + +for i = 48, 57 do table.insert(charset, string.char(i)) end +for i = 65, 90 do table.insert(charset, string.char(i)) end +for i = 97, 122 do table.insert(charset, string.char(i)) end + +ESX.GetRandomString = function(length) + + math.randomseed(os.time()) + + if length > 0 then + return ESX.GetRandomString(length - 1) .. charset[math.random(1, #charset)] + else + return '' + end + +end + +ESX.RegisterServerCallback = function(name, cb) + ESX.ServerCallbacks[name] = cb +end + +ESX.TriggerServerCallback = function(name, requestId, source, cb, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + ESX.ServerCallbacks[name](source, cb, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) +end + +ESX.SavePlayer = function(xPlayer, cb) + + local asyncTasks = {} + xPlayer.lastPosition = xPlayer.get('coords') + + -- User accounts + for i=1, #xPlayer.accounts, 1 do + + table.insert(asyncTasks, function(cb) + + MySQL.Async.execute( + 'UPDATE user_accounts SET `money` = @money WHERE identifier = @identifier AND name = @name', + { + ['@money'] = xPlayer.accounts[i].money, + ['@identifier'] = xPlayer.identifier, + ['@name'] = xPlayer.accounts[i].name + }, + function(rowsChanged) + cb() + end + ) + + end) + + end + + -- Inventory items + for i=1, #xPlayer.inventory, 1 do + + table.insert(asyncTasks, function(cb) + + MySQL.Async.execute( + 'UPDATE user_inventory SET `count` = @count WHERE identifier = @identifier AND item = @item', + { + ['@count'] = xPlayer.inventory[i].count, + ['@identifier'] = xPlayer.identifier, + ['@item'] = xPlayer.inventory[i].name + }, + function(rowsChanged) + cb() + end + ) + + end) + + end + + -- Job, loadout and position + table.insert(asyncTasks, function(cb) + + MySQL.Async.execute( + 'UPDATE users SET `job` = @job, `job_grade` = @job_grade, `loadout` = @loadout, `position` = @position WHERE identifier = @identifier', + { + ['@job'] = xPlayer.job.name, + ['@job_grade'] = xPlayer.job.grade, + ['@loadout'] = json.encode(xPlayer.loadout), + ['@position'] = json.encode(xPlayer.lastPosition), + ['@identifier'] = xPlayer.identifier + }, + function(rowsChanged) + cb() + end + ) + + end) + + Async.parallel(asyncTasks, function(results) + + RconPrint('[SAVED] ' .. xPlayer.name .. "\n") + + if cb ~= nil then + cb() + end + + end) + +end + +ESX.SavePlayers = function(cb) + + local asyncTasks = {} + local players = ESX.GetPlayers() + + for k,v in pairs(players) do + table.insert(asyncTasks, function(cb) + ESX.SavePlayer(v, cb) + end) + end + + Async.parallelLimit(asyncTasks, 15, function(results) + + RconPrint('[SAVED] All players' .. "\n") + + if cb ~= nil then + cb() + end + + end) + +end + +ESX.StartDBSync = function() + + function saveData() + ESX.SavePlayers() + SetTimeout(60000, saveData) + end + + SetTimeout(60000, saveData) + +end + +ESX.GetPlayers = function() + return ESX.Players +end + +ESX.GetPlayerFromId = function(source) + return ESX.Players[tonumber(source)] +end + +ESX.GetPlayerFromIdentifier = function(identifier) + + for k,v in pairs(ESX.Players) do + if v.identifier == identifier then + return v + end + end + +end + +ESX.RegisterUsableItem = function(item, cb) + ESX.UsableItemsCallbacks[item] = cb +end + +ESX.UseItem = function(source, item) + ESX.UsableItemsCallbacks[item](source) +end + +RegisterServerEvent('esx:clientLog') +AddEventHandler('esx:clientLog', function(msg) + RconPrint(msg) +end) + +RegisterServerEvent('esx:triggerServerCallback') +AddEventHandler('esx:triggerServerCallback', function(name, requestId, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + local _source = source + ESX.TriggerServerCallback(name, requestID, _source, function(a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + TriggerClientEvent('esx:serverCallback', _source, requestId, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) + end, a, b, c, d, e, f, g ,h ,i ,j ,k, l, m, n, o, p, q, r, s, t, u ,v ,w, x ,y ,z) +end) diff --git a/resources/[essential]/es_extended/server/main.lua b/resources/[essential]/es_extended/server/main.lua new file mode 100644 index 00000000..251d70c8 --- /dev/null +++ b/resources/[essential]/es_extended/server/main.lua @@ -0,0 +1,524 @@ +AddEventHandler('es:playerLoaded', function(source, _player) + + local _source = source + local tasks = {} + + local userData = { + accounts = {}, + inventory = {}, + job = {}, + loadout = {}, + playerName = GetPlayerName(_source), + lastPosition = nil + } + + TriggerEvent('es:getPlayerFromId', _source, function(player) + + -- Update user name in DB + table.insert(tasks, function(cb) + + MySQL.Async.execute( + 'UPDATE `users` SET `name` = @name WHERE `identifier` = @identifier', + { + ['@identifier'] = player.getIdentifier(), + ['@name'] = userData.playerName + }, + function(rowsChanged) + cb() + end + ) + + end) + + -- Get accounts + table.insert(tasks, function(cb) + + MySQL.Async.fetchAll( + 'SELECT * FROM `user_accounts` WHERE `identifier` = @identifier', + { + ['@identifier'] = player.getIdentifier() + }, + function(accounts) + + for i=1, #Config.Accounts, 1 do + for j=1, #accounts, 1 do + if accounts[j].name == Config.Accounts[i] then + table.insert(userData.accounts, { + name = accounts[j].name, + money = accounts[j].money, + label = Config.AccountLabels[accounts[j].name] + }) + end + end + + end + + cb() + end + ) + + end) + + -- Get Inventory + table.insert(tasks, function(cb) + + MySQL.Async.fetchAll( + 'SELECT * FROM `user_inventory` WHERE `identifier` = @identifier', + { + ['@identifier'] = player.getIdentifier() + }, + function(inventory) + + for i=1, #inventory, 1 do + table.insert(userData.inventory, { + name = inventory[i].item, + count = inventory[i].count, + label = ESX.Items[inventory[i].item].label, + limit = ESX.Items[inventory[i].item].limit, + usable = ESX.UsableItemsCallbacks[inventory[i].item] ~= nil + }) + end + + for k,v in pairs(ESX.Items) do + + local found = false + + for j=1, #userData.inventory, 1 do + if userData.inventory[j].name == k then + found = true + break + end + end + + if not found then + + table.insert(userData.inventory, { + name = k, + count = 0, + label = ESX.Items[k].label, + limit = ESX.Items[k].limit, + usable = ESX.UsableItemsCallbacks[k] ~= nil + }) + + MySQL.Async.execute( + 'INSERT INTO user_inventory (identifier, item, count) VALUES (@identifier, @item, @count)', + { + ['@identifier'] = player.getIdentifier(), + ['@item'] = k, + ['@count'] = 0 + } + ) + + end + + end + + table.sort(userData.inventory, function(a,b) + return a.label < b.label + end) + + cb() + end + ) + + end) + + -- Get job and loadout + table.insert(tasks, function(cb) + + local tasks2 = {} + + -- Get job name, grade and last position + table.insert(tasks2, function(cb2) + + MySQL.Async.fetchAll( + 'SELECT * FROM `users` WHERE `identifier` = @identifier', + { + ['@identifier'] = player.getIdentifier() + }, + function(result) + + userData.job['name'] = result[1].job + userData.job['grade'] = result[1].job_grade + + if result[1].loadout ~= nil then + userData.loadout = json.decode(result[1].loadout) + end + + if result[1].position ~= nil then + userData.lastPosition = json.decode(result[1].position) + end + + cb2() + + end + ) + + end) + + -- Get job label + table.insert(tasks2, function(cb2) + + MySQL.Async.fetchAll( + 'SELECT * FROM `jobs` WHERE `name` = @name', + { + ['@name'] = userData.job.name + }, + function(result) + + userData.job['label'] = result[1].label + + cb2() + + end + ) + + end) + + -- Get job grade data + table.insert(tasks2, function(cb2) + + MySQL.Async.fetchAll( + 'SELECT * FROM `job_grades` WHERE `job_name` = @job_name AND `grade` = @grade', + { + ['@job_name'] = userData.job.name, + ['@grade'] = userData.job.grade + }, + function(result) + + userData.job['grade_name'] = result[1].name + userData.job['grade_label'] = result[1].label + userData.job['grade_salary'] = result[1].salary + + userData.job['skin_male'] = {} + userData.job['skin_female'] = {} + + if result[1].skin_male ~= nil then + userData.job['skin_male'] = json.decode(result[1].skin_male) + end + + if result[1].skin_female ~= nil then + userData.job['skin_female'] = json.decode(result[1].skin_female) + end + + cb2() + + end + ) + + end) + + Async.series(tasks2, cb) + + end) + + -- Run Tasks + Async.parallel(tasks, function(results) + + local xPlayer = CreateExtendedPlayer(player, userData.accounts, userData.inventory, userData.job, userData.loadout, userData.playerName, userData.lastPosition) + + xPlayer.getMissingAccounts(function(missingAccounts) + + if #missingAccounts > 0 then + + for i=1, #missingAccounts, 1 do + table.insert(xPlayer.accounts, { + name = missingAccounts[i], + money = 0, + label = Config.AccountLabels[missingAccounts[i]] + }) + end + + xPlayer.createAccounts(missingAccounts) + end + + ESX.Players[_source] = xPlayer + + TriggerEvent('esx:playerLoaded', _source) + + TriggerClientEvent('esx:playerLoaded', _source, { + accounts = xPlayer.getAccounts(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + lastPosition = xPlayer.getLastPosition(), + money = xPlayer.player.get('money') + }) + + xPlayer.player.displayMoney(xPlayer.get('money')) + + end) + + end) + + end) + +end) + +AddEventHandler('playerDropped', function() + + local _source = source + local xPlayer = ESX.GetPlayerFromId(_source) + + if xPlayer ~= nil then + + TriggerEvent('esx:playerDropped', _source) + + ESX.SavePlayer(xPlayer, function() + ESX.Players[_source] = nil + end) + + end + +end) + +RegisterServerEvent('esx:updateLoadout') +AddEventHandler('esx:updateLoadout', function(loadout) + local xPlayer = ESX.GetPlayerFromId(source) + xPlayer.loadout = loadout +end) + +RegisterServerEvent('esx:giveInventoryItem') +AddEventHandler('esx:giveInventoryItem', function(target, type, itemName, itemCount) + + local _source = source + + local sourceXPlayer = ESX.GetPlayerFromId(_source) + local targetXPlayer = ESX.GetPlayerFromId(target) + + if type == 'item_standard' then + + local sourceItem = sourceXPlayer.getInventoryItem(itemName) + local targetItem = targetXPlayer.getInventoryItem(itemName) + + if itemCount > 0 and sourceItem.count >= itemCount then + + if targetItem.limit ~= -1 and (targetItem.count + sourceItem.count) > targetItem.limit then + TriggerClientEvent('esx:showNotification', target, 'Action impossible, depassement de la limite d\'inventaire pour ~b~' .. targetXPlayer.name) + else + sourceXPlayer.removeInventoryItem(itemName, itemCount) + targetXPlayer.addInventoryItem (itemName, itemCount) + + TriggerClientEvent('esx:showNotification', _source, 'Vous avez donné ~g~x' .. itemCount .. ' ' .. ESX.Items[itemName].label .. '~s~ à ~b~' .. targetXPlayer.name) + TriggerClientEvent('esx:showNotification', target, 'Vous avez reçu ~g~x' .. itemCount .. ' ' .. ESX.Items[itemName].label .. '~s~ par ~b~' .. sourceXPlayer.name) + end + + else + TriggerClientEvent('esx:showNotification', target, 'Action impossible, ~r~quantité invalide') + end + + elseif type == 'item_money' then + + if itemCount > 0 and sourceXPlayer.player.get('money') >= itemCount then + + sourceXPlayer.removeMoney(itemCount) + targetXPlayer.addMoney(itemCount) + + TriggerClientEvent('esx:showNotification', _source, 'Vous avez donné ~g~$' .. itemCount .. '~s~ à ~b~' .. targetXPlayer.name) + TriggerClientEvent('esx:showNotification', target, 'Vous avez reçu ~g~$' .. itemCount .. '~s~ par ~b~' .. sourceXPlayer.name) + + else + TriggerClientEvent('esx:showNotification', target, 'Action impossible, ~r~montant invalide') + end + + elseif type == 'item_account' then + + if itemCount > 0 and sourceXPlayer.getAccount(itemName).money >= itemCount then + + sourceXPlayer.removeAccountMoney(itemName, itemCount) + targetXPlayer.addAccountMoney(itemName, itemCount) + + TriggerClientEvent('esx:showNotification', _source, 'Vous avez donné [' .. Config.AccountLabels[itemName] .. '] ~g~$' .. itemCount .. '~s~ à ~b~' .. targetXPlayer.name) + TriggerClientEvent('esx:showNotification', target, 'Vous avez reçu [' .. Config.AccountLabels[itemName] .. '] ~g~$' .. itemCount .. '~s~ par ~b~' .. sourceXPlayer.name) + + else + TriggerClientEvent('esx:showNotification', target, 'Action impossible, ~r~montant invalide') + end + + elseif type == 'item_weapon' then + + sourceXPlayer.removeWeapon(itemName) + targetXPlayer.addWeapon(itemName, itemCount) + + local weaponLabel = itemName + + for i=1, #Config.Weapons, 1 do + if Config.Weapons[i].name == itemName then + weaponLabel = Config.Weapons[i].label + break + end + end + + TriggerClientEvent('esx:showNotification', _source, 'Vous avez donné x1 ' .. ' ~g~' .. weaponLabel .. '~s~ à ~b~' .. targetXPlayer.name) + TriggerClientEvent('esx:showNotification', target, 'Vous avez reçu x1 ' .. ' ~g~' .. weaponLabel .. '~s~ par ~b~' .. sourceXPlayer.name) + end + +end) + +RegisterServerEvent('esx:removeInventoryItem') +AddEventHandler('esx:removeInventoryItem', function(type, itemName, itemCount) + + local _source = source + + if type == 'item_standard' then + + if itemCount == nil or itemCount <= 0 then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~quantité invalide') + else + + local xPlayer = ESX.GetPlayerFromId(source) + local foundItem = nil + + for i=1, #xPlayer.inventory, 1 do + if xPlayer.inventory[i].name == itemName then + foundItem = xPlayer.inventory[i] + end + end + + if itemCount > foundItem.count then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~quantité invalide') + else + + TriggerClientEvent('esx:showNotification', _source, '~r~Suppression~s~ dans 5 minutes') + + SetTimeout(Config.RemoveInventoryItemDelay, function() + + local remainingCount = xPlayer.getInventoryItem(itemName).count + local total = itemCount + + if remainingCount < itemCount then + total = remainingCount + end + + if total > 0 then + xPlayer.removeInventoryItem(itemName, total) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez ~r~jeté~s~ ' .. foundItem.label .. ' x' .. total) + end + + end) + + end + + end + + elseif type == 'item_money' then + + if itemCount == nil or itemCount <= 0 then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~montant invalide') + else + + local xPlayer = ESX.GetPlayerFromId(source) + + if itemCount > xPlayer.player.get('money') then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~montant invalide') + else + + TriggerClientEvent('esx:showNotification', _source, '~r~Suppression~s~ dans 5 minutes') + + SetTimeout(Config.RemoveInventoryItemDelay, function() + + local remainingCount = xPlayer.player.get('money') + local total = itemCount + + if remainingCount < itemCount then + total = remainingCount + end + + if total > 0 then + xPlayer.removeMoney(total) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez ~r~jeté~s~ [Cash] $' .. total) + end + + end) + + end + + end + + elseif type == 'item_account' then + + if itemCount == nil or itemCount <= 0 then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~montant invalide') + else + + local xPlayer = ESX.GetPlayerFromId(source) + + if itemCount > xPlayer.getAccount(itemName).money then + TriggerClientEvent('esx:showNotification', _source, 'Action impossible, ~r~montant invalide') + else + + TriggerClientEvent('esx:showNotification', _source, '~r~Suppression~s~ dans 5 minutes') + + SetTimeout(Config.RemoveInventoryItemDelay, function() + + local remainingCount = xPlayer.getAccount(itemName).money + local total = itemCount + + if remainingCount < itemCount then + total = remainingCount + end + + if total > 0 then + xPlayer.removeAccountMoney(itemName, total) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez ~r~jeté~s~ [Cash] $' .. total) + end + + end) + + end + + end + + elseif type == 'item_weapon' then + + local weaponLabel = itemName + + for i=1, #Config.Weapons, 1 do + if Config.Weapons[i].name == itemName then + weaponLabel = Config.Weapons[i].label + break + end + end + + SetTimeout(Config.RemoveInventoryItemDelay, function() + xPlayer.removeWeapon(itemName) + TriggerClientEvent('esx:showNotification', _source, 'Vous avez ~r~jeté~s~ x1 ' .. ' ~g~' .. weaponLabel) + end) + + end + +end) + +ESX.RegisterServerCallback('esx:getPlayerData', function(source, cb) + + local xPlayer = ESX.GetPlayerFromId(source) + + cb({ + accounts = xPlayer.getAccounts(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + lastPosition = xPlayer.getLastPosition(), + money = xPlayer.player.get('money') + }) + +end) + +ESX.RegisterServerCallback('esx:getOtherPlayerData', function(source, cb, target) + + local xPlayer = ESX.GetPlayerFromId(target) + + cb({ + accounts = xPlayer.getAccounts(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + lastPosition = xPlayer.getLastPosition(), + money = xPlayer.player.get('money') + }) + +end) + +TriggerEvent("es:addGroup", "jobmaster", "user", function(group) end) + +ESX.StartDBSync() diff --git a/resources/[esx]/[ui]/esx_menu_default b/resources/[esx]/[ui]/esx_menu_default new file mode 160000 index 00000000..9954bec8 --- /dev/null +++ b/resources/[esx]/[ui]/esx_menu_default @@ -0,0 +1 @@ +Subproject commit 9954bec81228b19479730969a76fb75afa2b3b0c diff --git a/resources/[esx]/[ui]/esx_menu_dialog b/resources/[esx]/[ui]/esx_menu_dialog new file mode 160000 index 00000000..73f0d5dd --- /dev/null +++ b/resources/[esx]/[ui]/esx_menu_dialog @@ -0,0 +1 @@ +Subproject commit 73f0d5dd0ee5318e03b9bb5003573ef2e88df66a diff --git a/resources/[esx]/[ui]/esx_menu_list b/resources/[esx]/[ui]/esx_menu_list new file mode 160000 index 00000000..5bd0f9e9 --- /dev/null +++ b/resources/[esx]/[ui]/esx_menu_list @@ -0,0 +1 @@ +Subproject commit 5bd0f9e9a5986d74ebc0465b712db6648d7a92bd diff --git a/resources/async b/resources/async new file mode 160000 index 00000000..089dbcc1 --- /dev/null +++ b/resources/async @@ -0,0 +1 @@ +Subproject commit 089dbcc1a5b3baa2eaca09b8f43d6c14d83cdaaf