Un serveur FiveM lent a presque toujours la même cause : quelques ressources mal écrites qui travaillent pour rien. Ce guide vous montre comment les trouver, puis comment les corriger, avec des exemples de code avant et après.
Les deux types de lenteur
| Symptôme | Où ça se passe | Outil |
|---|---|---|
| Les joueurs ont peu d'images par seconde, le jeu saccade | Client : scripts qui tournent sur chaque PC | resmon 1 dans la console F8 |
| Désynchronisations, véhicules qui se téléportent, actions en retard | Serveur : scripts lents ou machine saturée | profiler dans la Live Console, onglet Infrastructure du panel |
| Chargement très long à la connexion | Streaming : cartes, véhicules, vêtements trop lourds | Taille du dossier stream des ressources |
Mesurer côté client avec resmon
En jeu, ouvrez la console avec F8 et tapez :
resmon 1Un tableau affiche, pour chaque ressource, le temps processeur utilisé à chaque image (en millisecondes) et la mémoire.
| Temps par image | Interprétation |
|---|---|
| 0,00 à 0,05 ms | Excellent |
| 0,05 à 0,20 ms | Correct |
| 0,20 à 0,50 ms | À surveiller |
| Plus de 0,50 ms en continu | À corriger en priorité |
À 60 images par seconde, le jeu dispose d'environ 16 ms par image pour tout faire. Dix ressources à 0,5 ms en mangent déjà 5.
Mesurer côté serveur avec le profiler
Dans la Live Console de txAdmin :
profiler record 500
profiler viewLa première commande enregistre 500 images serveur, la seconde ouvre un lien vers un rapport détaillé qui montre le temps passé dans chaque ressource. Cherchez les ressources qui reviennent en haut du classement.
Sur EsoterHost, l'onglet Métriques du panel montre le processeur et la RAM de votre serveur sur 24 heures. Si le processeur reste près de 100 % de la formule, passez à la formule supérieure ou allégez vos scripts.
Correction n°1 : les boucles qui tournent à chaque image
C'est la cause la plus fréquente. Avant :
CreateThread(function()
while true do
Wait(0)
for _, magasin in ipairs(Config.Magasins) do
local distance = #(GetEntityCoords(PlayerPedId()) - magasin.coords)
if distance < 10.0 then
DrawMarker(29, magasin.coords.x, magasin.coords.y, magasin.coords.z, 0, 0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 0, 200, 0, 150, false, true, 2, false, nil, nil, false)
end
end
end
end)Ce code calcule la distance à tous les magasins, à chaque image, même quand le joueur est à l'autre bout de la carte. Après :
local proche = nil
-- 1) Une boucle lente cherche le magasin le plus proche, deux fois par seconde
CreateThread(function()
while true do
local coords = GetEntityCoords(PlayerPedId())
local trouve = nil
for _, magasin in ipairs(Config.Magasins) do
if #(coords - magasin.coords) < 15.0 then trouve = magasin break end
end
proche = trouve
Wait(500)
end
end)
-- 2) Une boucle rapide ne dessine que si un magasin est proche
CreateThread(function()
while true do
if proche then
local c = proche.coords
DrawMarker(29, c.x, c.y, c.z, 0, 0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 0, 200, 0, 150, false, true, 2, false, nil, nil, false)
Wait(0)
else
Wait(500)
end
end
end)Résultat typique : de 0,30 ms à 0,01 ms quand aucun magasin n'est proche.
La fonction lib.points.new d'ox_lib gère les distances pour vous et n'appelle votre code qu'à proximité. Une seule boucle optimisée sert alors toutes vos ressources.
for _, magasin in ipairs(Config.Magasins) do
lib.points.new({
coords = magasin.coords,
distance = 15,
nearby = function(self)
DrawMarker(29, self.coords.x, self.coords.y, self.coords.z, 0, 0, 0, 0, 0, 0, 1.0, 1.0, 1.0, 0, 200, 0, 150, false, true, 2, false, nil, nil, false)
end,
})
endCorrection n°2 : appeler les natives moins souvent
Chaque appel de native a un coût. Gardez en mémoire ce qui ne change pas à chaque image.
CreateThread(function()
while true do
Wait(0)
if IsPedInAnyVehicle(PlayerPedId(), false) then
local vehicule = GetVehiclePedIsIn(PlayerPedId(), false)
local vitesse = GetEntitySpeed(vehicule) * 3.6
-- affichage de la vitesse…
end
end
end)local vehicule = 0
-- Le véhicule change rarement : on le relit deux fois par seconde
CreateThread(function()
while true do
vehicule = GetVehiclePedIsIn(PlayerPedId(), false)
Wait(500)
end
end)
CreateThread(function()
while true do
if vehicule ~= 0 then
local vitesse = GetEntitySpeed(vehicule) * 3.6
-- affichage de la vitesse…
Wait(0)
else
Wait(500)
end
end
end)Correction n°3 : les événements plutôt que les boucles
Beaucoup de scripts vérifient en boucle un état qui ne change que rarement. FiveM envoie des événements à la place :
| Au lieu de vérifier en boucle… | Écoutez |
|---|---|
| Le joueur est-il mort ? | gameEventTriggered avec CEventNetworkEntityDamage |
| Le joueur est-il entré dans un véhicule ? | baseevents:enteredVehicle (ressource baseevents) |
| Le métier a-t-il changé ? | esx:setJob ou QBCore:Client:OnJobUpdate |
| Une valeur partagée a-t-elle changé ? | AddStateBagChangeHandler |
AddEventHandler('gameEventTriggered', function(nom, args)
if nom ~= 'CEventNetworkEntityDamage' then return end
local victime, mortelle = args[1], args[6] == 1
if victime == PlayerPedId() and mortelle then
TriggerServerEvent('mon-script:mort')
end
end)Correction n°4 : la base de données
- Une requête par joueur et par seconde, c'est beaucoup. Gardez les données en mémoire côté serveur et enregistrez-les à intervalles (toutes les 5 minutes) ou à la déconnexion.
- Ajoutez des index sur les colonnes que vous cherchez souvent.
- Utilisez la version
.awaitd'oxmysql dans un thread, jamais des boucles d'attente maison.
-- Accélère les recherches de véhicules par propriétaire (ESX)
CREATE INDEX idx_owned_vehicles_owner ON owned_vehicles (owner);Pour repérer les requêtes lentes, oxmysql peut les journaliser :
set mysql_slow_query_warning 150Toute requête de plus de 150 ms s'affiche alors dans la Live Console avec la ressource qui l'a lancée.
Correction n°5 : le streaming
Les cartes, véhicules et vêtements ajoutés sont téléchargés par chaque joueur à la connexion.
- Compressez les textures (
.ytd) : une texture de 4096 × 4096 pixels est rarement utile, 1024 × 1024 suffit souvent. L'outil OpenIV permet de les redimensionner. - Regroupez les véhicules dans une seule ressource plutôt que cinquante.
- Supprimez ce qui ne sert plus : chaque ressource démarrée est téléchargée, même inutilisée.
- Au-delà de 16 Mo, une texture de véhicule déclenche un avertissement « oversized asset » et peut faire disparaître des objets en jeu.
Réglages du server.cfg utiles
# OneSync : indispensable, à garder activé
set onesync on
# Réduit la population de PNJ et de véhicules côté serveur (OneSync)
set onesync_population true
# Avertit des requêtes SQL lentes (oxmysql)
set mysql_slow_query_warning 150Pour réduire le trafic de PNJ côté client, une petite ressource suffit :
CreateThread(function()
while true do
SetVehicleDensityMultiplierThisFrame(0.4)
SetPedDensityMultiplierThisFrame(0.5)
SetRandomVehicleDensityMultiplierThisFrame(0.4)
SetParkedVehicleDensityMultiplierThisFrame(0.4)
SetScenarioPedDensityMultiplierThisFrame(0.5, 0.5)
Wait(0)
end
end)Ces natives « ThisFrame » doivent être appelées à chaque image : c'est l'un des rares cas où Wait(0) est justifié. Elles coûtent très peu.
Liste de contrôle
resmon 1en jeu : notez les ressources au-dessus de 0,2 ms.profiler record 500dans la Live Console : notez les ressources serveur les plus coûteuses.- Cherchez dans leur code les boucles
Wait(0)permanentes et les natives appelées à chaque image. - Remplacez par des boucles à deux vitesses,
lib.pointsou des événements. - Activez
mysql_slow_query_warninget ajoutez des index. - Allégez le streaming.
- Si la machine reste saturée, passez à la formule supérieure depuis l'onglet Abonnement du panel.
EsoterHost n'est ni approuvé, ni sponsorisé, ni affilié à Rockstar Games ou à Cfx.re. FiveM et Grand Theft Auto V sont des marques de leurs propriétaires.
