I have 200 people on the server active, and a lot of thread hooks, doing a server-side Profiler, all that generates these thread hooks is this function:
ESX.GetPlayers ()
Is there any other way to do this?
I have 200 people on the server active, and a lot of thread hooks, doing a server-side Profiler, all that generates these thread hooks is this function:
ESX.GetPlayers ()
Is there any other way to do this?
ESX.GetPlayers() returns a list of player ids that have a character loaded.
Resources that use this function then loop through the IDs and use ESX.GetPlayerFromId(id), then perform a whatever task they want with that without any sort of wait. Sometimes this is an async query - so you send 200 database queries almost all at once, or some events (which are in themselves async).
You can alleviate some of the stress by changing how the xPlayer data is retrieved.
Add the following function to ESX/server/functions.lua
ESX.GetExtendedPlayers = function()
return ESX.Players
end
Example of a typical xPlayer loop
local xPlayers = ESX.GetPlayers()
for _,playerId in ipairs(xPlayers) do
local xPlayer = ESX.GetPlayerFromId(playerId)
MySQL.Async.fetchAll('SELECT status FROM users WHERE identifier = @identifier', {
['@identifier'] = xPlayer.identifier
}, function(result)
local data = {}
if result[1].status then
data = json.decode(result[1].status)
end
xPlayer.set('status', data)
TriggerClientEvent('esx_status:load', playerId, data)
end)
end
Replacement
local xPlayers = ESX.GetExtendedPlayers()
for k,v in pairs(xPlayers) do
MySQL.Async.fetchAll('SELECT status FROM users WHERE identifier = @identifier', {
['@identifier'] = v.identifier
}, function(result)
local data = {}
if result[1].status then
data = json.decode(result[1].status)
end
v.set('status', data)
TriggerClientEvent('esx_status:load', k, data)
end)
end
If you are using any resources for blips (for EMS, police, etc) check how they are performing this task as well. By default ambulancejob and policejob send a server event when a cop loads in, which tells all clients to check if they are ems/police and send a server callback.
The callback, which is triggered by (for example) 6 cops then runs 6 async xPlayer loops to get the ids of all active cops and report back to the client.
Lastly, if you are using gcphone then you need to replace the following function
function getSourceFromIdentifier(identifier, cb)
local xPlayers = ESX.GetPlayers()
for i=1, #xPlayers, 1 do
local xPlayer = ESX.GetPlayerFromId(xPlayers[i])
if(xPlayer.identifier ~= nil and xPlayer.identifier == identifier) or (xPlayer.identifier == identifier) then
cb(xPlayer.source)
return
end
end
cb(nil)
end
Replace with
function getSourceFromIdentifier(identifier, cb)
local xPlayer = ESX.GetPlayerFromIdentifier(identifier)
if xPlayer then cb(xPlayer.source) else cb(nil) end
end
You are a genius, now I am not clear in this part how I should replace?
local xAll = ESX.GetExtendedPlayers()
for i=1, #xAll, 1 do
local xTarget = ESX.GetPlayerFromId(xAll[i])
if havePermission(xTarget) then -- you can exclude some ranks to NOT reciveing reports
if xPlayer.source ~= xTarget.source then
TriggerClientEvent('chatMessage', xTarget.source, _U('report', GetPlayerName(xPlayer.source), xPlayer.source, message))
end
end
end
or here
local xPlayers = ESX.GetPlayers()
for i=1, #xPlayers, 1 do
local xPlayer = ESX.GetPlayerFromId(xPlayers[i])
local status = xPlayer.get('status')
whenList = whenList .. string.format('when identifier = \'%s\' then \'%s\' ', xPlayer.identifier, json.encode(status))
if firstItem == false then
whereList = whereList .. ', '
end
whereList = whereList .. string.format('\'%s\'', xPlayer.identifier)
firstItem = false
playerCount = playerCount + 1
end
With the table being returned, the key (or index) is equal to the players id (or source), while the value is their xPlayer data.
So k
is the same as v.source / v.playerId
- up to you how you want to reference it.
You do not need to use ESX.GetPlayerFromId()
at all, it is what causes a bulk of the lag (calling functions from other resources has a lot of overhead).
local xPlayers = ESX.GetExtendedPlayers()
for k,v in pairs(xPlayers) do
if havePermission(v) and xPlayer.source ~= k then
TriggerClientEvent('chatMessage', k, _U('report', GetPlayerName(xPlayer.source), xPlayer.source, message))
end
end
In the second example you’re trying to update esx_status, so you can reference my updated version
I’d appreciate feedback on how all of this performs too, since it’s getting pushed into an update for ESX Legacy.
Here’s an example of performance when triggering esx_society:getOnlinePlayers
with 200 active players.
Keep in mind this is being triggered by a single client - the default blips in esx_policejob trigger the callback for every cop online.
I’ve fixed up esx_society to use the new looping function.
Full comparison of performance differences when modifying esx_society.
The top two just swap out the function.
The bottom two modify the callback event to stop it from performing the same task 10 times in quick succession.
Now the only thing that causes me thread snags is the gcphone in this function:
RegisterServerEvent('gcPhone:sendMessage')
AddEventHandler('gcPhone:sendMessage', function(phoneNumber, message)
local _source = source
local sourcePlayer = tonumber(_source)
xPlayer = ESX.GetPlayerFromId(_source)
identifier = xPlayer.identifier
addMessage(sourcePlayer, identifier, phoneNumber, message)
end)
Using the snippet I included in the first reply?
function getSourceFromIdentifier(identifier, cb)
local xPlayers = ESX.GetExtendedPlayers()
for k,v in pairs(xPlayers) do
--if k then cb(k) else cb(nil) end
if(v.identifier ~= nil and v.identifier == identifier) or (v.identifier == identifier) then
cb(k)
return
end
end
end
function getSourceFromIdentifier(identifier, cb)
local xPlayer = ESX.GetPlayerFromIdentifier(identifier)
if xPlayer then cb(xPlayer.source) else cb(nil) end
end
There’s no need to loop through xPlayers to get a source from an identifier.
Shouldn’t it be ESX.GetPlayerFromIdentifier(identifier)
instead of ESX.GetPlayerFromId(identifier)
? since if you are getting xPlayer from Id why do you even need xPlayer xD.
typo
This does not work for me, the SMS do not arrive, I quit the gcphone and everyone arrives, but it is like the SMS are not updated. That’s why I did it as I happened to you.
The original code I sent had a mistake in it, as RealMasBagus pointed out. I edited the previous messages containing the function.
not found, no refresh de sms
The only way that works for me is the following:
function getSourceFromIdentifier(identifier, cb)
local xPlayers = ESX.GetExtendedPlayers()
for k,v in pairs(xPlayers) do
--if k then cb(k) else cb(nil) end
if(v.identifier ~= nil and v.identifier == identifier) or (v.identifier == identifier) then
cb(k)
return
end
end
end
But all the high thread hooks are given to me by the gcphone, when they send sms.
It is the following line:
RegisterServerEvent('gcPhone:sendMessage')
AddEventHandler('gcPhone:sendMessage', function(phoneNumber, message, gpsData)
local _source = source
local sourcePlayer = tonumber(_source)
xPlayer = ESX.GetPlayerFromId(_source)
identifier = xPlayer.identifier
addMessage(sourcePlayer, identifier, phoneNumber, message, gpsData)
end)
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.