mirror of
https://github.com/esx-framework/esx_core.git
synced 2026-09-04 16:23:21 +00:00
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()
This commit is contained in:
+38
-51
@@ -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)
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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` (
|
||||
|
||||
+35
-47
@@ -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
|
||||
|
||||
@@ -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
|
||||
end
|
||||
|
||||
+198
-207
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user