From f89e05175626f47275b4301e6561295414210711 Mon Sep 17 00:00:00 2001 From: ElPumpo Date: Sun, 12 Jan 2020 22:13:30 +0100 Subject: [PATCH] BREAKING COMMIT - Player loading improvements (read description!) This commit implements a new way of saving and getting player coords. Player coords are synced with its assigned xPlayer, the syncing interval is defined in the configuration file. Also coords wont sync if the player is too close to their previous location. Existing servers must change their database to account for the new length of the position varchar, at 53 chars max. There's also a column default value specified in the sql file. New xPlayer functions: - .getCoords() - .setCoords() (x,y,z,heading (optional) table - .updateCoords() The last one is used for syncing coords from client (interval). The second one will teleport the player. First one is a renamed .getLastPosition() --- client/main.lua | 89 ++++----- config.lua | 3 +- es_extended.sql | 2 +- server/classes/player.lua | 82 ++++---- server/functions.lua | 7 +- server/main.lua | 405 +++++++++++++++++++------------------- 6 files changed, 277 insertions(+), 311 deletions(-) diff --git a/client/main.lua b/client/main.lua index 22292f4e..48285d2b 100644 --- a/client/main.lua +++ b/client/main.lua @@ -1,6 +1,4 @@ - -local isLoadoutLoaded, isPaused, isPlayerSpawned, isDead = false, false, false, false -local lastLoadout, pickups = {}, {} +local isLoadoutLoaded, isPaused, isDead, isFirstSpawn, pickups = false, false, false, true, {} RegisterNetEvent('esx:playerLoaded') AddEventHandler('esx:playerLoaded', function(xPlayer) @@ -47,33 +45,26 @@ end) AddEventHandler('playerSpawned', function() while not ESX.PlayerLoaded do - Citizen.Wait(1) + Citizen.Wait(10) end - local playerPed = PlayerPedId() + TriggerEvent('esx:restoreLoadout') - -- Restore position - if ESX.PlayerData.lastPosition then - SetEntityCoords(playerPed, ESX.PlayerData.lastPosition.x, ESX.PlayerData.lastPosition.y, ESX.PlayerData.lastPosition.z) + if isFirstSpawn then + ESX.Game.Teleport(PlayerPedId(), ESX.PlayerData.coords) + isFirstSpawn = false end - TriggerEvent('esx:restoreLoadout') -- restore loadout - - isLoadoutLoaded, isPlayerSpawned, isDead = true, true, false + isLoadoutLoaded, isDead = true, false if Config.EnablePvP then - SetCanAttackFriendly(playerPed, true, false) + SetCanAttackFriendly(PlayerPedId(), true, false) NetworkSetFriendlyFireOption(true) end end) -AddEventHandler('esx:onPlayerDeath', function() - isDead = true -end) - -AddEventHandler('skinchanger:loadDefaultModel', function() - isLoadoutLoaded = false -end) +AddEventHandler('esx:onPlayerDeath', function() isDead = true end) +AddEventHandler('skinchanger:loadDefaultModel', function() isLoadoutLoaded = false end) AddEventHandler('skinchanger:modelLoaded', function() while not ESX.PlayerLoaded do @@ -175,7 +166,6 @@ AddEventHandler('esx:addWeapon', function(weaponName, ammo) local weaponHash = GetHashKey(weaponName) GiveWeaponToPed(playerPed, weaponHash, ammo, false, false) - --AddAmmoToPed(playerPed, weaponHash, ammo) possibly not needed end) RegisterNetEvent('esx:addWeaponComponent') @@ -211,7 +201,6 @@ AddEventHandler('esx:removeWeapon', function(weaponName, ammo) end end) - RegisterNetEvent('esx:removeWeaponComponent') AddEventHandler('esx:removeWeaponComponent', function(weaponName, weaponComponent) local playerPed = PlayerPedId() @@ -221,21 +210,16 @@ AddEventHandler('esx:removeWeaponComponent', function(weaponName, weaponComponen RemoveWeaponComponentFromPed(playerPed, weaponHash, componentHash) 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 +AddEventHandler('esx:teleport', function(coords) + local playerPed = PlayerPedId() - RequestCollisionAtCoord(pos.x, pos.y, pos.z) + -- ensure decmial number + coords.x = coords.x + 0.0 + coords.y = coords.y + 0.0 + coords.z = coords.z + 0.0 - while not HasCollisionLoadedAroundEntity(PlayerPedId()) do - RequestCollisionAtCoord(pos.x, pos.y, pos.z) - Citizen.Wait(1) - end - - SetEntityCoords(PlayerPedId(), pos.x, pos.y, pos.z) + ESX.Game.Teleport(playerPed, coords) end) RegisterNetEvent('esx:setJob') @@ -384,7 +368,7 @@ AddEventHandler('esx:deleteVehicle', function(radius) end end) --- Pause menu disable HUD display +-- Pause menu disables HUD display if Config.EnableHud then Citizen.CreateThread(function() while true do @@ -405,12 +389,11 @@ end -- Save loadout Citizen.CreateThread(function() + local lastLoadout = {} + while true do Citizen.Wait(5000) - - local playerPed = PlayerPedId() - local loadout = {} - local loadoutChanged = false + local playerPed, loadout, loadoutChanged = PlayerPedId(), {}, false for k,v in ipairs(Config.Weapons) do local weaponName = v.name @@ -469,8 +452,8 @@ 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) @@ -528,22 +511,26 @@ Citizen.CreateThread(function() end end) --- Last position +-- Update current player coords Citizen.CreateThread(function() - while true do + local previousCoords = vector3(0, 0, 0) + + -- wait for player to restore coords + while not isLoadoutLoaded do Citizen.Wait(1000) + end + + while true do + Citizen.Wait(Config.CoordsSyncInterval) local playerPed = PlayerPedId() + local playerCoords = GetEntityCoords(playerPed) + local distance = #(playerCoords - previousCoords) - if ESX.PlayerLoaded and isPlayerSpawned then - local coords = GetEntityCoords(playerPed) - - if not IsEntityDead(playerPed) then - ESX.PlayerData.lastPosition = {x = coords.x, y = coords.y, z = coords.z} - end - end - - if IsEntityDead(playerPed) and isPlayerSpawned then - isPlayerSpawned = false + if distance > 10 then + previousCoords = playerCoords + local playerHeading = ESX.Math.Round(GetEntityHeading(playerPed), 1) + local formattedCoords = {x = ESX.Math.Round(playerCoords.x, 1), y = ESX.Math.Round(playerCoords.y, 1), z = ESX.Math.Round(playerCoords.z, 1), heading = playerHeading} + TriggerServerEvent('esx:updateCoords', formattedCoords) end end end) diff --git a/config.lua b/config.lua index a332cf44..5dfee80f 100644 --- a/config.lua +++ b/config.lua @@ -10,6 +10,7 @@ Config.EnableHud = true -- enable the default hud? Display current jo Config.EnablePvP = true -- enable pvp? Config.MaxWeight = 24 -- the max inventory weight without backpack -Config.PaycheckInterval = 7 * 60000 +Config.PaycheckInterval = 7 * 60000 -- how often to recieve pay checks in milliseconds +Config.CoordsSyncInterval = 2 * 60000 -- how often to sync coords with server in milliseconds Config.EnableDebug = false diff --git a/es_extended.sql b/es_extended.sql index 52534684..4cab101a 100644 --- a/es_extended.sql +++ b/es_extended.sql @@ -6,7 +6,7 @@ ALTER TABLE `users` ADD COLUMN `job` VARCHAR(50) NULL DEFAULT 'unemployed' AFTER `skin`, ADD COLUMN `job_grade` INT NULL DEFAULT 0 AFTER `job`, ADD COLUMN `loadout` LONGTEXT NULL AFTER `job_grade`, - ADD COLUMN `position` VARCHAR(36) NULL AFTER `loadout` + ADD COLUMN `position` VARCHAR(53) NULL DEFAULT '{"x":-269.4,"y":-955.3,"z":31.2,"heading":205.8}' AFTER `loadout` ; CREATE TABLE `items` ( diff --git a/server/classes/player.lua b/server/classes/player.lua index fe1cf5e0..851bb397 100644 --- a/server/classes/player.lua +++ b/server/classes/player.lua @@ -1,4 +1,4 @@ -function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, lastPosition) +function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, coords) local self = {} self.player = player @@ -7,8 +7,8 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.job = job self.loadout = loadout self.name = name - self.lastPosition = lastPosition self.maxWeight = Config.MaxWeight + self.coords = coords self.source = self.player.get('source') self.identifier = self.player.get('identifier') @@ -41,23 +41,25 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l return self.player.get('bank') end - self.getCoords = function(vectorType) - local coords = self.player.get('coords') - coords = {x = ESX.Math.Round(coords.x, 1), y = ESX.Math.Round(coords.y, 1), z = ESX.Math.Round(coords.z, 1)} + self.setCoords = function(coords) + self.updateCoords(coords) + self.triggerEvent('esx:teleport', coords) + end - if vectorType then - return vector3(coords.x, coords.y, coords.z) + self.updateCoords = function(coords) + self.coords = {x = ESX.Math.Round(coords.x, 1), y = ESX.Math.Round(coords.y, 1), z = ESX.Math.Round(coords.z, 1), heading = ESX.Math.Round(coords.heading, 1)} + end + + self.getCoords = function(vector) + if vector then + return vector3(self.coords.x, self.coords.y, self.coords.z) else - return coords + return self.coords end end - self.setCoords = function(x, y, z) - self.player.coords = {x = x, y = y, z = z} - end - self.kick = function(reason) - self.player.kick(reason) + DropPlayer(self.source, reason) end self.addMoney = function(money) @@ -194,20 +196,6 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.name = newName end - self.getLastPosition = function() - if self.lastPosition and self.lastPosition.x and self.lastPosition.y and self.lastPosition.z then - self.lastPosition.x = ESX.Math.Round(self.lastPosition.x, 1) - self.lastPosition.y = ESX.Math.Round(self.lastPosition.y, 1) - self.lastPosition.z = ESX.Math.Round(self.lastPosition.z, 1) - end - - return self.lastPosition - end - - self.setLastPosition = function(position) - self.lastPosition = position - end - self.getMissingAccounts = function(cb) MySQL.Async.fetchAll('SELECT name FROM user_accounts WHERE identifier = @identifier', { ['@identifier'] = self.getIdentifier() @@ -262,7 +250,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.set('bank', newMoney) end - TriggerClientEvent('esx:setAccountMoney', self.source, account) + self.triggerEvent('esx:setAccountMoney', account) end end end @@ -279,7 +267,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.set('bank', newMoney) end - TriggerClientEvent('esx:setAccountMoney', self.source, account) + self.triggerEvent('esx:setAccountMoney', account) end end end @@ -296,7 +284,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.set('bank', newMoney) end - TriggerClientEvent('esx:setAccountMoney', self.source, account) + self.triggerEvent('esx:setAccountMoney', account) end end end @@ -319,7 +307,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l item.count = newCount TriggerEvent('esx:onAddInventoryItem', self.source, item, count) - TriggerClientEvent('esx:addInventoryItem', self.source, item, count) + self.triggerEvent('esx:addInventoryItem', item, count) end end @@ -333,7 +321,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l item.count = newCount TriggerEvent('esx:onRemoveInventoryItem', self.source, item, count) - TriggerClientEvent('esx:removeInventoryItem', self.source, item, count) + self.triggerEvent('esx:removeInventoryItem', item, count) end end end @@ -347,10 +335,10 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l if oldCount > item.count then TriggerEvent('esx:onRemoveInventoryItem', self.source, item, oldCount - item.count) - TriggerClientEvent('esx:removeInventoryItem', self.source, item, oldCount - item.count) + self.triggerEvent('esx:removeInventoryItem', item, oldCount - item.count) else TriggerEvent('esx:onAddInventoryItem', self.source, item, item.count - oldCount) - TriggerClientEvent('esx:addInventoryItem', self.source, item, item.count - oldCount) + self.triggerEvent('esx:addInventoryItem', item, item.count - oldCount) end end end @@ -388,7 +376,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l self.setMaxWeight = function(newWeight) self.maxWeight = newWeight - TriggerClientEvent('esx:setMaxWeight', self.source, self.maxWeight) + self.triggerEvent('esx:setMaxWeight', self.maxWeight) end self.setJob = function(job, grade) @@ -419,7 +407,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l end TriggerEvent('esx:setJob', self.source, self.job, lastJob) - TriggerClientEvent('esx:setJob', self.source, self.job) + self.triggerEvent('esx:setJob', self.job) else print(('[es_extended] [^3WARNING^7] Ignoring invalid .setJob() usage for "%s"'):format(self.identifier)) end @@ -436,8 +424,8 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l components = {} }) - TriggerClientEvent('esx:addWeapon', self.source, weaponName, ammo) - TriggerClientEvent('esx:addInventoryItem', self.source, {label = weaponLabel}, 1) + self.triggerEvent('esx:addWeapon', weaponName, ammo) + self.triggerEvent('esx:addInventoryItem', {label = weaponLabel}, 1) end end @@ -447,7 +435,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l if weapon then if not self.hasWeaponComponent(weaponName, weaponComponent) then table.insert(self.loadout[loadoutNum].components, weaponComponent) - TriggerClientEvent('esx:addWeaponComponent', self.source, weaponName, weaponComponent) + self.triggerEvent('esx:addWeaponComponent', weaponName, weaponComponent) end end end @@ -457,7 +445,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l if weapon then weapon.ammo = weapon.ammo + ammoCount - TriggerClientEvent('esx:setWeaponAmmo', self.source, weaponName, weapon.ammo) + self.triggerEvent('esx:setWeaponAmmo', weaponName, weapon.ammo) end end @@ -469,7 +457,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l weaponLabel = v.label for k2,v2 in ipairs(v.components) do - TriggerClientEvent('esx:removeWeaponComponent', self.source, weaponName, v2) + self.triggerEvent('esx:removeWeaponComponent', weaponName, v2) end table.remove(self.loadout, k) @@ -478,8 +466,8 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l end if weaponLabel then - TriggerClientEvent('esx:removeWeapon', self.source, weaponName, ammo) - TriggerClientEvent('esx:removeInventoryItem', self.source, {label = weaponLabel}, 1) + self.triggerEvent('esx:removeWeapon', weaponName, ammo) + self.triggerEvent('esx:removeInventoryItem', {label = weaponLabel}, 1) end end @@ -494,7 +482,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l end end - TriggerClientEvent('esx:removeWeaponComponent', self.source, weaponName, weaponComponent) + self.triggerEvent('esx:removeWeaponComponent', weaponName, weaponComponent) end end @@ -503,7 +491,7 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l if weapon then weapon.ammo = weapon.ammo - ammoCount - TriggerClientEvent('esx:setWeaponAmmo', self.source, weaponName, weapon.ammo) + self.triggerEvent('esx:setWeaponAmmo', weaponName, weapon.ammo) end end @@ -544,11 +532,11 @@ function CreateExtendedPlayer(player, accounts, inventory, job, loadout, name, l end self.showNotification = function(msg) - TriggerClientEvent('esx:showNotification', self.source, msg) + self.triggerEvent('esx:showNotification', msg) end self.showHelpNotification = function(msg) - TriggerClientEvent('esx:showHelpNotification', self.source, msg) + self.triggerEvent('esx:showHelpNotification', msg) end return self diff --git a/server/functions.lua b/server/functions.lua index 5bd0008f..2a20eeea 100644 --- a/server/functions.lua +++ b/server/functions.lua @@ -38,7 +38,6 @@ end ESX.SavePlayer = function(xPlayer, cb) local asyncTasks = {} - xPlayer.setLastPosition(xPlayer.getCoords()) -- User accounts for k,v in ipairs(xPlayer.accounts) do @@ -80,7 +79,7 @@ ESX.SavePlayer = function(xPlayer, cb) ['@job'] = xPlayer.job.name, ['@job_grade'] = xPlayer.job.grade, ['@loadout'] = json.encode(xPlayer.getLoadout()), - ['@position'] = json.encode(xPlayer.getLastPosition()), + ['@position'] = json.encode(xPlayer.getCoords()), ['@identifier'] = xPlayer.identifier }, function(rowsChanged) cb() @@ -88,7 +87,7 @@ ESX.SavePlayer = function(xPlayer, cb) end) Async.parallel(asyncTasks, function(results) - print(('[es_extended] [^2INFO^7] Saved %s'):format(xPlayer.getName())) + print(('[es_extended] [^2INFO^7] Saved player "%s^7"'):format(xPlayer.getName())) if cb ~= nil then cb() @@ -190,4 +189,4 @@ ESX.DoesJobExist = function(job, grade) end return false -end \ No newline at end of file +end diff --git a/server/main.lua b/server/main.lua index b6e1806d..49fb94fe 100644 --- a/server/main.lua +++ b/server/main.lua @@ -1,233 +1,225 @@ -AddEventHandler('es:playerLoaded', function(source, _player) - local playerId = source - local tasks = {} +AddEventHandler('es:playerLoaded', function(playerId, player) + local tasks = {} local userData = { - accounts = {}, - inventory = {}, - job = {}, - loadout = {}, - playerName = GetPlayerName(playerId), - lastPosition = nil + accounts = {}, + inventory = {}, + job = {}, + loadout = {}, + playerName = GetPlayerName(playerId), + coords = nil } - TriggerEvent('es:getPlayerFromId', playerId, 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) + -- 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 name, money FROM user_accounts WHERE identifier = @identifier', { - ['@identifier'] = player.getIdentifier() - }, function(accounts) - local validAccounts = ESX.Table.Set(Config.Accounts) - for k,v in ipairs(accounts) do - if validAccounts[v.name] then - table.insert(userData.accounts, { - name = v.name, - money = v.money, - label = Config.AccountLabels[v.name] - }) - end + -- Get accounts + table.insert(tasks, function(cb) + MySQL.Async.fetchAll('SELECT name, money FROM user_accounts WHERE identifier = @identifier', { + ['@identifier'] = player.getIdentifier() + }, function(accounts) + local validAccounts = ESX.Table.Set(Config.Accounts) + for k,v in ipairs(accounts) do + if validAccounts[v.name] then + table.insert(userData.accounts, { + name = v.name, + money = v.money, + label = Config.AccountLabels[v.name] + }) end + end - cb() - end) + cb() end) + end) - -- Get inventory - table.insert(tasks, function(cb) + -- Get inventory + table.insert(tasks, function(cb) + MySQL.Async.fetchAll('SELECT item, count FROM user_inventory WHERE identifier = @identifier', { + ['@identifier'] = player.getIdentifier() + }, function(inventory) + local tasks2, foundItems = {}, {} - MySQL.Async.fetchAll('SELECT item, count FROM user_inventory WHERE identifier = @identifier', { - ['@identifier'] = player.getIdentifier() - }, function(inventory) - local tasks2, foundItems = {}, {} + for k,v in ipairs(inventory) do + local item = ESX.Items[v.item] - for k,v in ipairs(inventory) do - local item = ESX.Items[v.item] + if item then + foundItems[v.item] = true - if item then - foundItems[v.item] = true - - table.insert(userData.inventory, { - name = v.item, - count = v.count, - label = item.label, - weight = item.weight, - usable = ESX.UsableItemsCallbacks[v.item] ~= nil, - rare = item.rare, - canRemove = item.canRemove - }) - else - print(('[es_extended] [^3WARNING^7] Ignoring invalid item "%s" for "%s"'):format(v.item, player.getIdentifier())) - end + table.insert(userData.inventory, { + name = v.item, + count = v.count, + label = item.label, + weight = item.weight, + usable = ESX.UsableItemsCallbacks[v.item] ~= nil, + rare = item.rare, + canRemove = item.canRemove + }) + else + print(('[es_extended] [^3WARNING^7] Ignoring invalid item "%s" for "%s"'):format(v.item, player.getIdentifier())) end + end - for itemName,item in pairs(ESX.Items) do - if not foundItems[itemName] then - table.insert(userData.inventory, { - name = itemName, - count = 0, - label = item.label, - weight = item.weight, - usable = ESX.UsableItemsCallbacks[itemName] ~= nil, - rare = item.rare, - canRemove = item.canRemove - }) + for name,item in pairs(ESX.Items) do + if not foundItems[name] then + table.insert(userData.inventory, { + name = name, + count = 0, + label = item.label, + weight = item.weight, + usable = ESX.UsableItemsCallbacks[name] ~= nil, + rare = item.rare, + canRemove = item.canRemove + }) - local scope = function(item, identifier) - table.insert(tasks2, function(cb2) - MySQL.Async.execute('INSERT INTO user_inventory (identifier, item, count) VALUES (@identifier, @item, @count)', { - ['@identifier'] = identifier, - ['@item'] = item, - ['@count'] = 0 - }, function(rowsChanged) - cb2() - end) + local scope = function(item, identifier) + table.insert(tasks2, function(cb2) + MySQL.Async.execute('INSERT INTO user_inventory (identifier, item, count) VALUES (@identifier, @item, @count)', { + ['@identifier'] = identifier, + ['@item'] = item, + ['@count'] = 0 + }, function(rowsChanged) + cb2() end) - end + end) + end - scope(itemName, player.getIdentifier()) + scope(name, player.getIdentifier()) + end + end + + Async.parallelLimit(tasks2, 5, function(results) 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 coords + table.insert(tasks2, function(cb2) + + MySQL.Async.fetchAll('SELECT job, job_grade, loadout, position FROM users WHERE identifier = @identifier', { + ['@identifier'] = player.getIdentifier() + }, function(result) + local job, grade = result[1].job, tostring(result[1].job_grade) + + if ESX.DoesJobExist(job, grade) then + local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + + userData.job = {} + + 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.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 + else + print(('[es_extended] [^3WARNING^7] Ignoring invalid job for %s [job: %s, grade: %s]'):format(player.getIdentifier(), job, grade)) + + local job, grade = 'unemployed', '0' + local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] + + userData.job = {} + + 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.skin_male = {} + userData.job.skin_female = {} + end + + if result[1].loadout then + userData.loadout = json.decode(result[1].loadout) + + -- Compatibility with old loadouts prior to components update + for k,v in ipairs(userData.loadout) do + if v.components == nil then + v.components = {} + end end end - Async.parallelLimit(tasks2, 5, function(results) end) - - table.sort(userData.inventory, function(a,b) - return a.label < b.label - end) - - cb() + userData.coords = json.decode(result[1].position) + cb2() end) end) - -- Get job and loadout - table.insert(tasks, function(cb) + Async.series(tasks2, cb) - local tasks2 = {} + end) - -- Get job name, grade and last position - table.insert(tasks2, function(cb2) + -- Run Tasks + Async.parallel(tasks, function(results) + local xPlayer = CreateExtendedPlayer(player, userData.accounts, userData.inventory, userData.job, userData.loadout, userData.playerName, userData.coords) - MySQL.Async.fetchAll('SELECT job, job_grade, loadout, position FROM users WHERE identifier = @identifier', { - ['@identifier'] = player.getIdentifier() - }, function(result) - local job, grade = result[1].job, tostring(result[1].job_grade) - - if ESX.DoesJobExist(job, grade) then - local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] - - userData.job = {} - - 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.skin_male = {} - userData.job.skin_female = {} - - if gradeObject.skin_male ~= nil then - userData.job.skin_male = json.decode(gradeObject.skin_male) - end - - if gradeObject.skin_female ~= nil then - userData.job.skin_female = json.decode(gradeObject.skin_female) - end - else - print(('[es_extended] [^3WARNING^7] Ignoring invalid job for %s [job: %s, grade: %s]'):format(player.getIdentifier(), job, grade)) - - local job, grade = 'unemployed', '0' - local jobObject, gradeObject = ESX.Jobs[job], ESX.Jobs[job].grades[grade] - - userData.job = {} - - 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.skin_male = {} - userData.job.skin_female = {} - end - - if result[1].loadout ~= nil then - userData.loadout = json.decode(result[1].loadout) - - -- Compatibility with old loadouts prior to components update - for k,v in ipairs(userData.loadout) do - if v.components == nil then - v.components = {} - end - end - end - - if result[1].position ~= nil then - userData.lastPosition = json.decode(result[1].position) - 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) + 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 - ESX.Players[playerId] = xPlayer + xPlayer.createAccounts(missingAccounts) + end - TriggerEvent('esx:playerLoaded', playerId, xPlayer) + ESX.Players[playerId] = xPlayer - TriggerClientEvent('esx:playerLoaded', playerId, { - identifier = xPlayer.identifier, - accounts = xPlayer.getAccounts(), - inventory = xPlayer.getInventory(), - job = xPlayer.getJob(), - loadout = xPlayer.getLoadout(), - lastPosition = xPlayer.getLastPosition(), - money = xPlayer.getMoney(), - maxWeight = xPlayer.maxWeight - }) + TriggerEvent('esx:playerLoaded', playerId, xPlayer) - xPlayer.displayMoney(xPlayer.getMoney()) - TriggerClientEvent('esx:createMissingPickups', playerId, ESX.Pickups) - end) + xPlayer.triggerEvent('esx:playerLoaded', { + identifier = xPlayer.identifier, + accounts = xPlayer.getAccounts(), + coords = xPlayer.getCoords(), + inventory = xPlayer.getInventory(), + job = xPlayer.getJob(), + loadout = xPlayer.getLoadout(), + money = xPlayer.getMoney(), + maxWeight = xPlayer.maxWeight + }) + + xPlayer.displayMoney(xPlayer.getMoney()) + xPlayer.triggerEvent('esx:createMissingPickups', ESX.Pickups) end) - end) end) @@ -245,15 +237,16 @@ AddEventHandler('playerDropped', function(reason) end end) +RegisterNetEvent('esx:updateCoords') +AddEventHandler('esx:updateCoords', function(coords) local xPlayer = ESX.GetPlayerFromId(source) -RegisterServerEvent('esx:updateLastPosition') -AddEventHandler('esx:updateLastPosition', function(position) - local xPlayer = ESX.GetPlayerFromId(source) - xPlayer.setLastPosition(position) + if xPlayer then + xPlayer.updateCoords(coords) + end end) -RegisterServerEvent('esx:giveInventoryItem') +RegisterNetEvent('esx:giveInventoryItem') AddEventHandler('esx:giveInventoryItem', function(target, type, itemName, itemCount) local playerId = source local sourceXPlayer = ESX.GetPlayerFromId(playerId) @@ -306,7 +299,7 @@ AddEventHandler('esx:giveInventoryItem', function(target, type, itemName, itemCo sourceXPlayer.removeWeapon(itemName) targetXPlayer.addWeapon(itemName, itemCount) - + if itemCount > 0 then sourceXPlayer.showNotification(_U('gave_weapon_withammo', weaponLabel, itemCount, targetXPlayer.name)) targetXPlayer.showNotification(_U('received_weapon_withammo', weaponLabel, itemCount, sourceXPlayer.name)) @@ -339,7 +332,7 @@ AddEventHandler('esx:giveInventoryItem', function(target, type, itemName, itemCo end end) -RegisterServerEvent('esx:removeInventoryItem') +RegisterNetEvent('esx:removeInventoryItem') AddEventHandler('esx:removeInventoryItem', function(type, itemName, itemCount) local playerId = source local xPlayer = ESX.GetPlayerFromId(source) @@ -406,7 +399,7 @@ AddEventHandler('esx:removeInventoryItem', function(type, itemName, itemCount) end end) -RegisterServerEvent('esx:useItem') +RegisterNetEvent('esx:useItem') AddEventHandler('esx:useItem', function(itemName) local xPlayer = ESX.GetPlayerFromId(source) local count = xPlayer.getInventoryItem(itemName).count @@ -418,7 +411,7 @@ AddEventHandler('esx:useItem', function(itemName) end end) -RegisterServerEvent('esx:onPickup') +RegisterNetEvent('esx:onPickup') AddEventHandler('esx:onPickup', function(id) local pickup, xPlayer, success = ESX.Pickups[id], ESX.GetPlayerFromId(source) @@ -465,7 +458,6 @@ ESX.RegisterServerCallback('esx:getPlayerData', function(source, cb) inventory = xPlayer.getInventory(), job = xPlayer.getJob(), loadout = xPlayer.getLoadout(), - lastPosition = xPlayer.getLastPosition(), money = xPlayer.getMoney() }) end) @@ -479,7 +471,6 @@ ESX.RegisterServerCallback('esx:getOtherPlayerData', function(source, cb, target inventory = xPlayer.getInventory(), job = xPlayer.getJob(), loadout = xPlayer.getLoadout(), - lastPosition = xPlayer.getLastPosition(), money = xPlayer.getMoney() }) end)