diff --git a/[core]/es_extended/client/functions.lua b/[core]/es_extended/client/functions.lua index 074d6f19..f56e53fe 100644 --- a/[core]/es_extended/client/functions.lua +++ b/[core]/es_extended/client/functions.lua @@ -720,7 +720,9 @@ function ESX.Game.GetVehicleProperties(vehicle) modXenon = IsToggleModOn(vehicle, 22), modFrontWheels = GetVehicleMod(vehicle, 23), + modCustomFrontWheels = GetVehicleModVariation(vehicle, 23), modBackWheels = GetVehicleMod(vehicle, 24), + modCustomBackWheels = GetVehicleModVariation(vehicle, 24), modPlateHolder = GetVehicleMod(vehicle, 25), modVanityPlate = GetVehicleMod(vehicle, 26), @@ -906,10 +908,16 @@ function ESX.Game.SetVehicleProperties(vehicle, props) end if props.modFrontWheels ~= nil then SetVehicleMod(vehicle, 23, props.modFrontWheels, false) + end + if props.modCustomFrontWheels ~= nil then + SetVehicleMod(vehicle, 23, props.modCustomFrontWheels, false) end if props.modBackWheels ~= nil then SetVehicleMod(vehicle, 24, props.modBackWheels, false) end + if props.modCustomBackWheels ~= nil then + SetVehicleMod(vehicle, 24, props.modCustomBackWheels, false) + end if props.modPlateHolder ~= nil then SetVehicleMod(vehicle, 25, props.modPlateHolder, false) end diff --git a/[core]/es_extended/locale.lua b/[core]/es_extended/locale.lua index 18120067..37c7e091 100644 --- a/[core]/es_extended/locale.lua +++ b/[core]/es_extended/locale.lua @@ -2,8 +2,7 @@ Locales = {} function Translate(str, ...) -- Translate string if not str then - local currentResourceName = GetCurrentResourceName() - print(("[^1ERROR^7] Resource ^5%s^7 You did not specify a parameter for the Translate function or the value is nil!"):format(currentResourceName)) + print(("[^1ERROR^7] Resource ^5%s^7 You did not specify a parameter for the Translate function or the value is nil!"):format(GetInvokingResource() or GetCurrentResourceName())) return 'Given translate function parameter is nil!' end if Locales[Config.Locale] then diff --git a/[core]/es_extended/server/classes/player.lua b/[core]/es_extended/server/classes/player.lua index 9249c984..6d9b2b48 100644 --- a/[core]/es_extended/server/classes/player.lua +++ b/[core]/es_extended/server/classes/player.lua @@ -47,31 +47,18 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, SetEntityHeading(Ped, vector.w) end - function self.updateCoords() - SetTimeout(1000,function() - local Ped = GetPlayerPed(self.source) - if DoesEntityExist(Ped) then - local coords = GetEntityCoords(Ped) - local distance = #(coords - vector3(self.coords.x, self.coords.y, self.coords.z)) - if distance > 1.5 then - local heading = GetEntityHeading(Ped) - self.coords = { - x = coords.x, - y = coords.y, - z = coords.z, - heading = heading or 0.0 - } - end - end - self.updateCoords() - end) - end - function self.getCoords(vector) + local ped = GetPlayerPed(self.source) + local coords = GetEntityCoords(ped) + if vector then - return vector3(self.coords.x, self.coords.y, self.coords.z) + return coords else - return self.coords + return { + x = coords.x, + y = coords.y, + z = coords.z, + } end end @@ -572,57 +559,59 @@ function CreateExtendedPlayer(playerId, identifier, group, accounts, inventory, end end - function self.showNotification(msg) - self.triggerEvent('esx:showNotification', msg) + function self.showNotification(msg, type, length) + self.triggerEvent('esx:showNotification', msg, type, length) + end + + function self.showAdvancedNotification(sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) + self.triggerEvent('esx:showAdvancedNotification', sender, subject, msg, textureDict, iconType, flash, saveToBrief, hudColorIndex) end function self.showHelpNotification(msg, thisFrame, beep, duration) self.triggerEvent('esx:showHelpNotification', msg, thisFrame, beep, duration) end - function self.getMeta(index, subIndex) - if index then + function self.getMeta(index, subIndex) + if not (index) then return self.metadata end - if type(index) ~= "string" then - return print("[^1ERROR^7] xPlayer.getMeta ^5index^7 should be ^5string^7!") - end + if type(index) ~= "string" then + return print("[^1ERROR^7] xPlayer.getMeta ^5index^7 should be ^5string^7!") + end - if self.metadata[index] then + local metadata = self.metadata[index] + if (metadata == nil) then + return Config.EnableDebug and print(("[^1ERROR^7] xPlayer.getMeta ^5%s^7 not exist!"):format(index)) or nil + end - if subIndex and type(self.metadata[index]) == "table" then - local _type = type(subIndex) + if (subIndex and type(metadata) == "table") then + local _type = type(subIndex) - if _type == "string" then - if self.metadata[index][subIndex] then - return self.metadata[index][subIndex] - end - return - end + if (_type == "string") then + local value = metadata[subIndex] + return value + end - if _type == "table" then - local returnValues = {} - for i = 1, #subIndex do - if self.metadata[index][subIndex[i]] then - returnValues[subIndex[i]] = self.metadata[index][subIndex[i]] - else - print(("[^1ERROR^7] xPlayer.getMeta ^5%s^7 not esxist on ^5%s^7!"):format(subIndex[i], index)) - end - end + if (_type == "table") then + local returnValues = {} - return returnValues - end + for i = 1, #subIndex do + local key = subIndex[i] + if (type(key) == "string") then + returnValues[key] = self.getMeta(index, key) + else + print(("[^1ERROR^7] xPlayer.getMeta subIndex should be ^5string^7 or ^5table^7! that contains ^5string^7, received ^5%s^7!, skipping..."):format(type(key))) + end + end - end + return returnValues + end - return self.metadata[index] - else - return print(("[^1ERROR^7] xPlayer.getMeta ^5%s^7 not exist!"):format(index)) - end + return print(("[^1ERROR^7] xPlayer.getMeta subIndex should be ^5string^7 or ^5table^7!, received ^5%s^7!"):format(_type)) + end - end + return metadata + end - return self.metadata - end function self.setMeta(index, value, subValue) if not index then diff --git a/[core]/es_extended/server/functions.lua b/[core]/es_extended/server/functions.lua index 31b0c1a9..6ef5bbff 100644 --- a/[core]/es_extended/server/functions.lua +++ b/[core]/es_extended/server/functions.lua @@ -221,18 +221,36 @@ end ESX.GetPlayers = GetPlayers +local function checkTable(key, val, player, xPlayers) + for valIndex = 1, #val do + local value = val[valIndex] + if not xPlayers[value] then + xPlayers[value] = {} + end + + if (key == 'job' and player.job.name == value) or player[key] == value then + xPlayers[value][#xPlayers[value] + 1] = player + end + end +end + function ESX.GetExtendedPlayers(key, val) - local xPlayers = {} - for k, v in pairs(ESX.Players) do - if key then - if (key == 'job' and v.job.name == val) or v[key] == val then - xPlayers[#xPlayers + 1] = v - end - else - xPlayers[#xPlayers + 1] = v - end - end - return xPlayers + if not key then return ESX.Players end + + local xPlayers = {} + if type(val) == "table" then + for _, v in pairs(ESX.Players) do + checkTable(key, val, v, xPlayers) + end + else + for _, v in pairs(ESX.Players) do + if (key == 'job' and v.job.name == val) or v[key] == val then + xPlayers[#xPlayers + 1] = v + end + end + end + + return xPlayers end function ESX.GetPlayerFromId(source) @@ -321,6 +339,37 @@ function ESX.DiscordLogFields(name, title, color, fields) }) end +--- Create Job at Runtime +--- @param name string +--- @param label string +--- @param grades table +function ESX.CreateJob(name, label, grades) + if not name then + return print('[^3WARNING^7] missing argument `name(string)` while creating a job') + end + + if not label then + return print('[^3WARNING^7] missing argument `label(string)` while creating a job') + end + + if not grades or not next(grades) then + return print('[^3WARNING^7] missing argument `grades(table)` while creating a job!') + end + + local parameters = {} + local job = {name = name, label = label, grades = {}} + + for k,v in pairs(grades) do + job.grades[tostring(v.grade)] = {job_name = name, grade = v.grade, name = v.name, label = v.label, salary = v.salary, skin_male = {}, skin_female = {}} + parameters[#parameters + 1] = { name, v.grade, v.name, v.label, v.salary} + end + + MySQL.insert('INSERT IGNORE INTO jobs (name, label) VALUES (?, ?)', {name, label}) + MySQL.prepare('INSERT INTO job_grades (job_name, grade, name, label, salary) VALUES (?, ?, ?, ?, ?)', parameters) + + ESX.Jobs[name] = job +end + function ESX.RefreshJobs() local Jobs = {} local jobs = MySQL.query.await('SELECT * FROM jobs') diff --git a/[core]/es_extended/server/main.lua b/[core]/es_extended/server/main.lua index 87958fed..32abd891 100644 --- a/[core]/es_extended/server/main.lua +++ b/[core]/es_extended/server/main.lua @@ -121,221 +121,249 @@ if not Config.Multichar then end function loadESXPlayer(identifier, playerId, isNew) - local userData = {accounts = {}, inventory = {}, job = {}, loadout = {}, playerName = GetPlayerName(playerId), weight = 0, metadata = {}} - local result = MySQL.prepare.await(loadPlayer, {identifier}) - local job, grade, jobObject, gradeObject = result.job, tostring(result.job_grade) - local foundAccounts, foundItems = {}, {} + local userData = { + accounts = {}, + inventory = {}, + job = {}, + loadout = {}, + playerName = GetPlayerName(playerId), + weight = 0, + metadata = {} + } + local result = MySQL.prepare.await(loadPlayer, { identifier }) + local job, grade, jobObject, gradeObject = result.job, tostring(result.job_grade) + local foundAccounts, foundItems = {}, {} - -- Accounts - if result.accounts and result.accounts ~= '' then - local accounts = json.decode(result.accounts) + -- Accounts + if result.accounts and result.accounts ~= '' then + local accounts = json.decode(result.accounts) - for account, money in pairs(accounts) do - foundAccounts[account] = money - end - end + for account, money in pairs(accounts) do + foundAccounts[account] = money + end + end - for account, data in pairs(Config.Accounts) do - if data.round == nil then - data.round = true - end - local index = #userData.accounts + 1 - userData.accounts[index] = { - name = account, - money = foundAccounts[account] or Config.StartingAccountMoney[account] or 0, - label = data.label, - round = data.round, - index = index - } - end + for account, data in pairs(Config.Accounts) do + if data.round == nil then + data.round = true + end + local index = #userData.accounts + 1 + userData.accounts[index] = { + name = account, + money = foundAccounts[account] or Config.StartingAccountMoney[account] or 0, + label = data.label, + round = data.round, + index = index + } + end - -- Job - if ESX.DoesJobExist(job, grade) then - jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] - else - print(('[^3WARNING^7] Ignoring invalid job for ^5%s^7 [job: ^5%s^7, grade: ^5%s^7]'):format(identifier, job, grade)) - job, grade = 'unemployed', '0' - jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] - end + -- Job + if ESX.DoesJobExist(job, grade) then + jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + else + print(('[^3WARNING^7] Ignoring invalid job for ^5%s^7 [job: ^5%s^7, grade: ^5%s^7]'):format(identifier, job, grade)) + job, grade = 'unemployed', '0' + jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + end - userData.job.id = jobObject.id - userData.job.name = jobObject.name - userData.job.label = jobObject.label + userData.job.id = jobObject.id + userData.job.name = jobObject.name + userData.job.label = jobObject.label - userData.job.grade = tonumber(grade) - userData.job.grade_name = gradeObject.name - userData.job.grade_label = gradeObject.label - userData.job.grade_salary = gradeObject.salary + userData.job.grade = tonumber(grade) + userData.job.grade_name = gradeObject.name + userData.job.grade_label = gradeObject.label + userData.job.grade_salary = gradeObject.salary - userData.job.skin_male = {} - userData.job.skin_female = {} + userData.job.skin_male = {} + userData.job.skin_female = {} - if gradeObject.skin_male then - userData.job.skin_male = json.decode(gradeObject.skin_male) - end - if gradeObject.skin_female then - userData.job.skin_female = json.decode(gradeObject.skin_female) - end + if gradeObject.skin_male then + userData.job.skin_male = json.decode(gradeObject.skin_male) + end + if gradeObject.skin_female then + userData.job.skin_female = json.decode(gradeObject.skin_female) + end - -- Inventory - if not Config.OxInventory then - if result.inventory and result.inventory ~= '' then - local inventory = json.decode(result.inventory) + -- Inventory + if not Config.OxInventory then + if result.inventory and result.inventory ~= '' then + local inventory = json.decode(result.inventory) - for name, count in pairs(inventory) do - local item = ESX.Items[name] + for name, count in pairs(inventory) do + local item = ESX.Items[name] - if item then - foundItems[name] = count - else - print(('[^3WARNING^7] Ignoring invalid item ^5"%s"^7 for ^5"%s^7"'):format(name, identifier)) - end - end - end + if item then + foundItems[name] = count + else + print(('[^3WARNING^7] Ignoring invalid item ^5"%s"^7 for ^5"%s^7"'):format(name, identifier)) + end + end + end - for name, item in pairs(ESX.Items) do - local count = foundItems[name] or 0 - if count > 0 then - userData.weight = userData.weight + (item.weight * count) - end + for name, item in pairs(ESX.Items) do + local count = foundItems[name] or 0 + if count > 0 then + userData.weight = userData.weight + (item.weight * count) + end - table.insert(userData.inventory, - {name = name, count = count, label = item.label, weight = item.weight, usable = Core.UsableItemsCallbacks[name] ~= nil, rare = item.rare, - canRemove = item.canRemove}) - end + table.insert(userData.inventory, + { + name = name, + count = count, + label = item.label, + weight = item.weight, + usable = Core.UsableItemsCallbacks[name] ~= nil, + rare = item.rare, + canRemove = item.canRemove + }) + end - table.sort(userData.inventory, function(a, b) - return a.label < b.label - end) - else - if result.inventory and result.inventory ~= '' then - userData.inventory = json.decode(result.inventory) - else - userData.inventory = {} - end - end + table.sort(userData.inventory, function(a, b) + return a.label < b.label + end) + else + if result.inventory and result.inventory ~= '' then + userData.inventory = json.decode(result.inventory) + else + userData.inventory = {} + end + end - -- Group - if result.group then - if result.group == "superadmin" then - userData.group = "admin" - print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7") - else - userData.group = result.group - end - else - userData.group = 'user' - end + -- Group + if result.group then + if result.group == "superadmin" then + userData.group = "admin" + print("[^3WARNING^7] ^5Superadmin^7 detected, setting group to ^5admin^7") + else + userData.group = result.group + end + else + userData.group = 'user' + end - -- Loadout - if not Config.OxInventory then - if result.loadout and result.loadout ~= '' then - local loadout = json.decode(result.loadout) + -- Loadout + if not Config.OxInventory then + if result.loadout and result.loadout ~= '' then + local loadout = json.decode(result.loadout) - for name, weapon in pairs(loadout) do - local label = ESX.GetWeaponLabel(name) + for name, weapon in pairs(loadout) do + local label = ESX.GetWeaponLabel(name) - if label then - if not weapon.components then - weapon.components = {} - end - if not weapon.tintIndex then - weapon.tintIndex = 0 - end + if label then + if not weapon.components then + weapon.components = {} + end + if not weapon.tintIndex then + weapon.tintIndex = 0 + end - table.insert(userData.loadout, - {name = name, ammo = weapon.ammo, label = label, components = weapon.components, tintIndex = weapon.tintIndex}) - end - end - end - end + table.insert(userData.loadout, + { + name = name, + ammo = weapon.ammo, + label = label, + components = weapon.components, + tintIndex = weapon.tintIndex + }) + end + end + end + end - -- Position - userData.coords = json.decode(result.position) or Config.DefaultSpawns[math.random(#Config.DefaultSpawns)] + -- Position + userData.coords = json.decode(result.position) or Config.DefaultSpawns[math.random(#Config.DefaultSpawns)] - -- Skin - if result.skin and result.skin ~= '' then - userData.skin = json.decode(result.skin) - else - if userData.sex == 'f' then - userData.skin = {sex = 1} - else - userData.skin = {sex = 0} - end - end + -- Skin + if result.skin and result.skin ~= '' then + userData.skin = json.decode(result.skin) + else + if userData.sex == 'f' then + userData.skin = { sex = 1 } + else + userData.skin = { sex = 0 } + end + end - -- Identity - if result.firstname and result.firstname ~= '' then - userData.firstname = result.firstname - userData.lastname = result.lastname - userData.playerName = userData.firstname .. ' ' .. userData.lastname - if result.dateofbirth then - userData.dateofbirth = result.dateofbirth - end - if result.sex then - userData.sex = result.sex - end - if result.height then - userData.height = result.height - end - end + -- Identity + if result.firstname and result.firstname ~= '' then + userData.firstname = result.firstname + userData.lastname = result.lastname + userData.playerName = userData.firstname .. ' ' .. userData.lastname + if result.dateofbirth then + userData.dateofbirth = result.dateofbirth + end + if result.sex then + userData.sex = result.sex + end + if result.height then + userData.height = result.height + end + end - if result.metadata and result.metadata ~= '' then - local metadata = json.decode(result.metadata) - userData.metadata = metadata - end + if result.metadata and result.metadata ~= '' then + local metadata = json.decode(result.metadata) + userData.metadata = metadata + end - local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, - userData.loadout, userData.playerName, userData.coords, userData.metadata) - ESX.Players[playerId] = xPlayer - Core.playersByIdentifier[identifier] = xPlayer + local xPlayer = CreateExtendedPlayer(playerId, identifier, userData.group, userData.accounts, userData.inventory, userData.weight, userData.job, userData.loadout, userData.playerName, userData.coords, userData.metadata) + ESX.Players[playerId] = xPlayer + Core.playersByIdentifier[identifier] = xPlayer - if userData.firstname then - xPlayer.set('firstName', userData.firstname) - xPlayer.set('lastName', userData.lastname) - if userData.dateofbirth then - xPlayer.set('dateofbirth', userData.dateofbirth) - end - if userData.sex then - xPlayer.set('sex', userData.sex) - end - if userData.height then - xPlayer.set('height', userData.height) - end - end + if userData.firstname then + xPlayer.set('firstName', userData.firstname) + xPlayer.set('lastName', userData.lastname) + if userData.dateofbirth then + xPlayer.set('dateofbirth', userData.dateofbirth) + end + if userData.sex then + xPlayer.set('sex', userData.sex) + end + if userData.height then + xPlayer.set('height', userData.height) + end + end - TriggerEvent('esx:playerLoaded', playerId, xPlayer, isNew) + TriggerEvent('esx:playerLoaded', playerId, xPlayer, isNew) - xPlayer.triggerEvent('esx:playerLoaded', - { - accounts = xPlayer.getAccounts(), - coords = xPlayer.getCoords(), - identifier = xPlayer.getIdentifier(), - inventory = xPlayer.getInventory(), - job = xPlayer.getJob(), - loadout = xPlayer.getLoadout(), - maxWeight = xPlayer.getMaxWeight(), - money = xPlayer.getMoney(), - sex = xPlayer.get("sex") or "m", - firstName = xPlayer.get("firstName") or "John", - lastName = xPlayer.get("lastName") or "Doe", - dateofbirth = xPlayer.get("dateofbirth") or "01/01/2000", - height = xPlayer.get("height") or 120, - dead = false, - metadata = xPlayer.getMeta() - }, isNew, - userData.skin) + xPlayer.triggerEvent('esx:playerLoaded', + { + accounts = xPlayer.getAccounts(), + coords = userData.coords, + identifier = xPlayer.getIdentifier(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + maxWeight = xPlayer.getMaxWeight(), + money = xPlayer.getMoney(), + sex = xPlayer.get("sex") or "m", + firstName = xPlayer.get("firstName") or "John", + lastName = xPlayer.get("lastName") or "Doe", + dateofbirth = xPlayer.get("dateofbirth") or "01/01/2000", + height = xPlayer.get("height") or 120, + dead = false, + metadata = xPlayer.getMeta() + }, isNew, + userData.skin) - if not Config.OxInventory then - xPlayer.triggerEvent('esx:createMissingPickups', Core.Pickups) - else - exports.ox_inventory:setPlayerInventory(xPlayer, userData.inventory) - end - xPlayer.updateCoords() - xPlayer.triggerEvent('esx:registerSuggestions', Core.RegisteredCommands) - print(('[^2INFO^0] Player ^5"%s"^0 has connected to the server. ID: ^5%s^7'):format(xPlayer.getName(), playerId)) + if not Config.OxInventory then + xPlayer.triggerEvent('esx:createMissingPickups', Core.Pickups) + else + exports.ox_inventory:setPlayerInventory(xPlayer, userData.inventory) + + if isNew then + for account, money in pairs(Config.StartingAccountMoney) do + if account == 'money' or account == 'black_money' then + exports.ox_inventory:AddItem(playerId, account, money) + end + end + end + end + xPlayer.triggerEvent('esx:registerSuggestions', Core.RegisteredCommands) + print(('[^2INFO^0] Player ^5"%s"^0 has connected to the server. ID: ^5%s^7'):format(xPlayer.getName(), playerId)) end + AddEventHandler('chatMessage', function(playerId, author, message) local xPlayer = ESX.GetPlayerFromId(playerId) if message:sub(1, 1) == '/' and playerId > 0 then @@ -628,6 +656,22 @@ ESX.RegisterServerCallback('esx:getPlayerNames', function(source, cb, players) cb(players) end) +ESX.RegisterServerCallback("esx:spawnVehicle", function(source,cb,vehData) + local ped = GetPlayerPed(source) + ESX.OneSync.SpawnVehicle(vehData.model or `ADDER`, vehData.coords or GetEntityCoords(ped), vehData.coords.w or 0.0, vehData.props or {}, function(id) + if vehData.warp then + local vehicle = NetworkGetEntityFromNetworkId(id) + local timeout = 0 + while GetVehiclePedIsIn(ped) ~= vehicle and timeout <= 15 do + Wait(0) + TaskWarpPedIntoVehicle(ped, vehicle, -1) + timeout += 1 + end + end + cb(id) + end) +end) + AddEventHandler('txAdmin:events:scheduledRestart', function(eventData) if eventData.secondsRemaining == 60 then CreateThread(function() diff --git a/[core]/esx_menu_default/client/main.lua b/[core]/esx_menu_default/client/main.lua index 463a1cd9..62b5f6a7 100644 --- a/[core]/esx_menu_default/client/main.lua +++ b/[core]/esx_menu_default/client/main.lua @@ -14,8 +14,10 @@ end local function closeMenu(namespace, name) CurrentNameSpace = namespace - if OpenedMenus < 1 then return end - OpenedMenus = OpenedMenus - 1 + OpenedMenus -= 1 + if OpenedMenus < 0 then + OpenedMenus = 0 + end SendNUIMessage({ action = 'closeMenu', namespace = namespace, diff --git a/[core]/esx_multicharacter/client/main.lua b/[core]/esx_multicharacter/client/main.lua index 901acbc3..4e5c5915 100644 --- a/[core]/esx_multicharacter/client/main.lua +++ b/[core]/esx_multicharacter/client/main.lua @@ -1,5 +1,8 @@ local mp_m_freemode_01 = `mp_m_freemode_01` local mp_f_freemode_01 = `mp_f_freemode_01` + +local SpawnCoords = Config.Spawn[math.random(#Config.Spawn)] + if ESX.GetConfig().Multichar then CreateThread(function() @@ -9,7 +12,7 @@ if ESX.GetConfig().Multichar then if NetworkIsPlayerActive(PlayerId()) then exports.spawnmanager:setAutoSpawn(false) DoScreenFadeOut(0) - while not GetResourceState('esx_context') == 'started' do + while GetResourceState('esx_context') ~= 'started' do Wait(100) end TriggerEvent("esx_multicharacter:SetupCharacters") @@ -28,14 +31,14 @@ if ESX.GetConfig().Multichar then spawned = false cam = CreateCam("DEFAULT_SCRIPTED_CAMERA", true) local playerPed = PlayerPedId() - SetEntityCoords(playerPed, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z, true, false, false, false) - SetEntityHeading(playerPed, Config.Spawn.w) + SetEntityCoords(playerPed, SpawnCoords.x, SpawnCoords.y, SpawnCoords.z, true, false, false, false) + SetEntityHeading(playerPed, SpawnCoords.w) local offset = GetOffsetFromEntityInWorldCoords(playerPed, 0, 1.7, 0.4) DoScreenFadeOut(0) SetCamActive(cam, true) RenderScriptCams(true, false, 1, true, true) SetCamCoord(cam, offset.x, offset.y, offset.z) - PointCamAtCoord(cam, Config.Spawn.x, Config.Spawn.y, Config.Spawn.z + 1.3) + PointCamAtCoord(cam, SpawnCoords.x, SpawnCoords.y, SpawnCoords.z + 1.3) StartLoop() ShutdownLoadingScreen() ShutdownLoadingScreenNui() @@ -98,10 +101,10 @@ if ESX.GetConfig().Multichar then SetupCharacter = function(index) if not spawned then exports.spawnmanager:spawnPlayer({ - x = Config.Spawn.x, - y = Config.Spawn.y, - z = Config.Spawn.z, - heading = Config.Spawn.w, + x = SpawnCoords.x, + y = SpawnCoords.y, + z = SpawnCoords.z, + heading = SpawnCoords.w, model = Characters[index].model or mp_m_freemode_01, skipFade = true }, function() @@ -147,7 +150,7 @@ if ESX.GetConfig().Multichar then {title = TranslateCap('return'), unselectable = false, icon = "fa-solid fa-arrow-left", description = TranslateCap('char_delete_no_description'), action = "return"} } - ESX.OpenContext("left", elements, function(element, Action) + ESX.OpenContext("left", elements, function(_, Action) if Action.action == "delete" then ESX.CloseContext() TriggerServerEvent('esx_multicharacter:DeleteCharacter', Action.value) @@ -167,7 +170,7 @@ if ESX.GetConfig().Multichar then elements[3] = {title = TranslateCap('char_disabled'), value = SelectedCharacter.value, icon ="fa-solid fa-xmark", description = TranslateCap('char_disabled_description'),} end if Config.CanDelete then elements[4] = {title = TranslateCap('char_delete'),icon ="fa-solid fa-xmark",description = TranslateCap('char_delete_description'), action = 'delete', value = SelectedCharacter.value} end - ESX.OpenContext("left", elements, function(element, Action) + ESX.OpenContext("left", elements, function(_, Action) if Action.action == "play" then SendNUIMessage({ action = "closeui" @@ -201,7 +204,7 @@ if ESX.GetConfig().Multichar then elements[#elements+1] = {title = TranslateCap('create_char'), icon = "fa-solid fa-plus", value = (#elements+1), new = true} end - ESX.OpenContext("left", elements, function(menu, SelectedCharacter) + ESX.OpenContext("left", elements, function(_, SelectedCharacter) if SelectedCharacter.new then ESX.CloseContext() local GetSlot = function() @@ -242,10 +245,10 @@ if ESX.GetConfig().Multichar then action = "closeui" }) exports.spawnmanager:spawnPlayer({ - x = Config.Spawn.x, - y = Config.Spawn.y, - z = Config.Spawn.z, - heading = Config.Spawn.w, + x = SpawnCoords.x, + y = SpawnCoords.y, + z = SpawnCoords.z, + heading = SpawnCoords.w, model = mp_m_freemode_01, skipFade = true }, function() @@ -318,7 +321,7 @@ if ESX.GetConfig().Multichar then end) if Config.Relog then - RegisterCommand('relog', function(source, args, rawCommand) + RegisterCommand('relog', function() if canRelog then canRelog = false TriggerServerEvent('esx_multicharacter:relog') diff --git a/[core]/esx_multicharacter/config.lua b/[core]/esx_multicharacter/config.lua index 9a2cb18f..f8256d38 100644 --- a/[core]/esx_multicharacter/config.lua +++ b/[core]/esx_multicharacter/config.lua @@ -16,7 +16,9 @@ if IsDuplicityVersion() then else -- Sets the location for the character selection scene -- To set the spawn location for new characters, modify the default value in the users SQL table - Config.Spawn = vector4(-284.2856, 562.4627, 172.9182, 19.9895) + Config.Spawn = { + {x = -284.2856, y = 562.4627, z = 172.9182, heading = 19.9895}, + } -------------------- -- Do not use unless you are prepared to adjust your resources to correctly reset data diff --git a/[core]/esx_multicharacter/server/commands.lua b/[core]/esx_multicharacter/server/commands.lua index 67fb5b04..3ba94d0c 100644 --- a/[core]/esx_multicharacter/server/commands.lua +++ b/[core]/esx_multicharacter/server/commands.lua @@ -24,7 +24,7 @@ end, true, {help = TranslateCap('command_remslots'), validate = true, arguments {name = 'identifier', help = TranslateCap('command_identifier'), type = 'string'} }}) -ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args, showError) +ESX.RegisterCommand('enablechar', 'admin', function(xPlayer, args) local selectedCharacter = 'char'..args.charslot..':'..args.identifier; @@ -43,7 +43,7 @@ end, true, {help = TranslateCap('command_enablechar'), validate = true, argument {name = 'charslot', help = TranslateCap('command_charslot'), type = 'number'} }}) -ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args, showError) +ESX.RegisterCommand('disablechar', 'admin', function(xPlayer, args) local selectedCharacter = 'char'..args.charslot..':'..args.identifier; @@ -62,6 +62,6 @@ end, true, {help = TranslateCap('command_disablechar'), validate = true, argumen {name = 'charslot', help = TranslateCap('command_charslot'), type = 'number'} }}) -RegisterCommand('forcelog', function(source, args, rawCommand) +RegisterCommand('forcelog', function(source) TriggerEvent('esx:playerLogout', source) end, true) diff --git a/[core]/esx_multicharacter/server/main.lua b/[core]/esx_multicharacter/server/main.lua index e07debe4..e09b48de 100644 --- a/[core]/esx_multicharacter/server/main.lua +++ b/[core]/esx_multicharacter/server/main.lua @@ -96,7 +96,7 @@ end TriggerClientEvent('esx_multicharacter:SetupUI', source, characters, slots) end - AddEventHandler('playerConnecting', function(playerName, setKickReason, deferrals) + AddEventHandler('playerConnecting', function(_, _, deferrals) deferrals.defer() local identifier = GetIdentifier(source) if oneSyncState == "off" or oneSyncState == "legacy" then @@ -214,6 +214,14 @@ end if isNew then awaitingRegistration[source] = charid else + if not ESX.GetConfig().EnableDebug then + local identifier = PREFIX..charid .. ':' .. GetIdentifier(source) + if ESX.GetPlayerFromIdentifier(identifier) then + DropPlayer(source, 'Your identifier '..identifier..' is already on the server!') + return + end + end + TriggerEvent('esx:onPlayerJoined', source, PREFIX..charid) ESX.Players[GetIdentifier(source)] = true end @@ -226,7 +234,7 @@ end ESX.Players[GetIdentifier(source)] = true end) - AddEventHandler('playerDropped', function(reason) + AddEventHandler('playerDropped', function() awaitingRegistration[source] = nil ESX.Players[GetIdentifier(source)] = nil end) diff --git a/[core]/esx_skin/client/main.lua b/[core]/esx_skin/client/main.lua index 367e27a6..de5b919f 100644 --- a/[core]/esx_skin/client/main.lua +++ b/[core]/esx_skin/client/main.lua @@ -1,8 +1,8 @@ local lastSkin, cam, isCameraActive -local firstSpawn, zoomOffset, camOffset, heading, skinLoaded = true, 0.0, 0.0, 90.0, false +local firstSpawn, zoomOffset, camOffset, heading = true, 0.0, 0.0, 90.0, false RegisterNetEvent('esx:playerLoaded') -AddEventHandler('esx:playerLoaded', function(xPlayer, isNew, skin) +AddEventHandler('esx:playerLoaded', function(_, _, skin) TriggerServerEvent('esx_skin:setWeight', skin) end) @@ -117,7 +117,7 @@ function OpenMenu(submitCb, cancelCb, restrict) menu.refresh() end - end, function(data, menu) + end, function() DeleteSkinCam() end) end) @@ -248,7 +248,6 @@ end AddEventHandler('esx_skin:resetFirstSpawn', function() firstSpawn = true - skinLoaded = false ESX.PlayerLoaded = false end) @@ -259,15 +258,13 @@ AddEventHandler('esx_skin:playerRegistered', function() end if firstSpawn then - ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin, jobSkin) + ESX.TriggerServerCallback('esx_skin:getPlayerSkin', function(skin) if skin == nil then TriggerEvent('skinchanger:loadSkin', {sex = 0}, OpenSaveableMenu) Wait(100) - skinLoaded = true else TriggerEvent('skinchanger:loadSkin', skin) Wait(100) - skinLoaded = true end end) @@ -277,7 +274,7 @@ AddEventHandler('esx_skin:playerRegistered', function() end) RegisterNetEvent('esx:playerLoaded') -AddEventHandler('esx:playerLoaded', function(xPlayer) +AddEventHandler('esx:playerLoaded', function() ESX.PlayerLoaded = true end) diff --git a/[core]/esx_skin/server/main.lua b/[core]/esx_skin/server/main.lua index 73f47cd0..29d3da28 100644 --- a/[core]/esx_skin/server/main.lua +++ b/[core]/esx_skin/server/main.lua @@ -71,10 +71,10 @@ ESX.RegisterServerCallback('esx_skin:getPlayerSkin', function(source, cb) end) end) -ESX.RegisterCommand('skin', 'admin', function(xPlayer, args, showError) +ESX.RegisterCommand('skin', 'admin', function(xPlayer) xPlayer.triggerEvent('esx_skin:openSaveableMenu') end, false, {help = TranslateCap('skin')}) -ESX.RegisterCommand('skinsave', 'admin', function(xPlayer, args, showError) +ESX.RegisterCommand('skinsave', 'admin', function(xPlayer) xPlayer.triggerEvent('esx_skin:requestSaveSkin') end, false, {help = TranslateCap('saveskin')}) diff --git a/readme.md b/readme.md index 6db69c2e..8731c473 100644 --- a/readme.md +++ b/readme.md @@ -2,7 +2,7 @@

Discord - Website - Documentation

Want more resources? You can browse the ESX Community Github or Cfx.re Releases board for more! -

ESX is the leading framework, trusted By thousands of commmunitys for the highest quality roleplay servers on FiveM

+

ESX is the leading framework, trusted by thousands of communities for the highest quality roleplay servers on FiveM