Parent : [[INDEX-FIVEM-BACKEND]]
FiveM - Itération ESX.GetPlayers() sans cache : charge serveur inutile
Problème
Itération sur TOUS les joueurs pour compter les policiers à chaque callback, sans cache. Sur un serveur à 100+ joueurs, cette opération est exécutée des centaines de fois par minute.
-- rm_trainheist/server.lua (PROBLEMATIQUE)
ESX.RegisterServerCallback('trainheist:checkPoliceCount', function(source, cb)
local policeCount = 0
local players = ESX.GetPlayers()
for i = 1, #players do
local player = ESX.GetPlayerFromId(players[i])
for k, v in pairs(Config.dispatchJobs) do
if player.job.name == v then
policeCount = policeCount + 1
end
end
end
cb(policeCount >= Config.requiredPoliceCount)
end)
Conséquences
- O(n*m) à chaque callback : n joueurs × m jobs dispatch
- Pas de cache : le compte est recalculé même si aucun joueur n'a changé de job depuis 10 secondes
- Charge serveur : impact sur les tick rates, latence augmentée
Solution
Correct
-- Cache avec invalidation
local policeCountCache = 0
local lastCacheUpdate = 0
local CACHE_TTL = 5000 -- 5 secondes
function GetPoliceCount()
local now = GetGameTimer()
if now - lastCacheUpdate < CACHE_TTL then
return policeCountCache
end
local count = 0
for _, playerId in ipairs(ESX.GetPlayers()) do
local xPlayer = ESX.GetPlayerFromId(playerId)
if xPlayer and Config.dispatchJobs[xPlayer.job.name] then
count = count + 1
end
end
policeCountCache = count
lastCacheUpdate = now
return count
end
-- Invalidation sur changement de job
RegisterNetEvent('esx:setJob')
AddEventHandler('esx:setJob', function(job)
lastCacheUpdate = 0 -- Force recalcul au prochain appel
end)
-- Usage dans le callback
ESX.RegisterServerCallback('trainheist:checkPoliceCount', function(source, cb)
cb(GetPoliceCount() >= Config.requiredPoliceCount)
end)
Alternative : Event-driven
-- Mise à jour proactive plutôt que reactive
local onlinePolice = {}
AddEventHandler('esx:setJob', function(source, job, lastJob)
if Config.dispatchJobs[job.name] then
onlinePolice[source] = true
else
onlinePolice[source] = nil
end
end)
AddEventHandler('playerDropped', function()
onlinePolice[source] = nil
end)
function GetPoliceCount()
local count = 0
for _ in pairs(onlinePolice) do
count = count + 1
end
return count
end
Incorrect
-- Double boucle dans le event handler (encore pire)
RegisterNetEvent('robbery:attempt')
AddEventHandler('robbery:attempt', function(storeId)
local cops = 0
for _, id in ipairs(ESX.GetPlayers()) do
local p = ESX.GetPlayerFromId(id)
for _, job in ipairs({'police', 'sheriff', 'fbi'}) do
if p.job.name == job then cops = cops + 1 end
end
end
if cops < 3 then return end
-- ... même logique dans 10 events différents
end)
Détection
Rechercher :
ESX.GetPlayers\(\)\n.*for.*#.*players
for.*ESX.GetPlayers.*do.*job
Références
- loffe_robbery/server.lua L38-45
- rm_trainheist/server.lua L24-32