Tutoriel 2026-05-05

Gestion des entités dans FiveM

TDYSKY

TDYSKY

Fondateur et développeur principal chez Agency Scripts

Comprendre les entités dans FiveM

Dans FiveM, une entité est n'importe quel objet qui existe dans le monde du jeu : véhicules, véhicules, accessoires, camionnettes et même le personnage du joueur. Chaque entité possède un handle (un identifiant entier) que tu utilises pour interagir avec elle via des fonctions natives. La gestion des entités est l'une des compétences les plus fondamentales du développement FiveM, car presque tous les scripts interagissent avec les entités d'une manière ou d'une autre. Une mauvaise gestion des entités entraîne des fuites de mémoire, des objets fantômes qui persistent après le redémarrage d'une ressource, une désynchronisation entre les joueurs et, finalement, une instabilité du serveur. Ce guide couvre les modèles corrects pour la création, le suivi et le nettoyage des entités.

Génération d'objets et d'accessoires

Le principal indigène pour les accessoires de frai est CreateObject (ou CreateObjectNoOffset). Avant de générer un objet, tu dois demander le modèle et attendre qu'il se charge. Ne pas demander le modèle au préalable entraînera une entité invisible ou manquante. Libérez toujours le modèle après avoir créé l'objet pour libérer de la mémoire.

-- client/entity_spawner.lua
local function SpawnProp(modelName, coords, rotation, isNetwork)
    local model = joaat(modelName)

    -- Request the model and wait for it to load
    RequestModel(model)
    local timeout = 0
    while not HasModelLoaded(model) do
        Wait(10)
        timeout = timeout + 10
        if timeout > 5000 then
            print(('[ERROR] Model %s failed to load after 5s'):format(modelName))
            return nil
        end
    end

    local obj = CreateObject(model, coords.x, coords.y, coords.z, isNetwork, true, false)

    if rotation then
        SetEntityRotation(obj, rotation.x, rotation.y, rotation.z, 2, true)
    end

    -- Freeze the object so it does not fall through the ground
    FreezeEntityPosition(obj, true)

    -- Release the model from memory
    SetModelAsNoLongerNeeded(model)

    return obj
end

-- Usage
local chair = SpawnProp('prop_chair_01a', vector3(200.0, -800.0, 31.0), nil, false)

Véhicules engendrés

L'apparition des véhicules suit un schéma similaire mais utilise CreateVehicle et comporte des considérations supplémentaires concernant la propriété du réseau, les niveaux de carburant et le texte de la plaque. Générez toujours des véhicules côté serveur lorsque cela est possible, ou utilisez des rappels côté serveur pour valider les demandes de création de véhicules des clients.

-- client/vehicle_spawner.lua
local function SpawnVehicle(modelName, coords, heading)
    local model = joaat(modelName)

    RequestModel(model)
    while not HasModelLoaded(model) do
        Wait(10)
    end

    local vehicle = CreateVehicle(model, coords.x, coords.y, coords.z, heading, true, false)

    -- Basic vehicle setup
    SetVehicleOnGroundProperly(vehicle)
    SetEntityAsMissionEntity(vehicle, true, true)
    SetVehicleHasBeenOwnedByPlayer(vehicle, true)
    SetVehicleNeedsToBeHotwired(vehicle, false)
    SetVehRadioStation(vehicle, 'OFF')

    -- Set fuel if using a fuel system
    Entity(vehicle).state:set('fuel', 100.0, true)

    SetModelAsNoLongerNeeded(model)

    return vehicle
end

Suivi et nettoyage des entités

L'aspect le plus critique de la gestion des entités consiste à suivre chaque entité créée par ton script et à les nettoyer lorsque la ressource s'arrête. Sans un nettoyage approprié, les entités persistent dans le monde du jeu comme des orphelines qui gaspillent de la mémoire et restituent des ressources. Utilisez une table de suivi pour stocker tous les descripteurs d'entité et enregistrer un onResourceStop gestionnaire qui les supprime.

-- client/entity_manager.lua
local ManagedEntities = {}

function RegisterEntity(entity, category)
    if not DoesEntityExist(entity) then return end

    ManagedEntities[entity] = {
        category = category or 'default',
        created = GetGameTimer(),
        model = GetEntityModel(entity),
    }
end

function UnregisterEntity(entity)
    if ManagedEntities[entity] then
        if DoesEntityExist(entity) then
            SetEntityAsMissionEntity(entity, false, true)
            DeleteEntity(entity)
        end
        ManagedEntities[entity] = nil
    end
end

function CleanupCategory(category)
    for entity, data in pairs(ManagedEntities) do
        if data.category == category then
            UnregisterEntity(entity)
        end
    end
end

function CleanupAllEntities()
    for entity, _ in pairs(ManagedEntities) do
        UnregisterEntity(entity)
    end
    ManagedEntities = {}
end

-- Critical: Clean up when resource stops
AddEventHandler('onResourceStop', function(resourceName)
    if GetCurrentResourceName() ~= resourceName then return end
    CleanupAllEntities()
end)

Propriété de l'entité réseau

Dans l'environnement réseau du FiveM, chaque entité a un propriétaire, le client responsable de la simulation de sa physique et de sa position. La propriété du réseau détermine quel client du joueur contrôle le mouvement et la collision de l'entité. Comprendre et gérer la propriété du réseau est essentiel pour le comportement synchronisé des entités, en particulier pour les scripts qui doivent contrôler les PNJ ou les véhicules à distance.

-- server/ownership.lua
-- Request control of a networked entity
local function RequestEntityOwnership(src, netId)
    local entity = NetworkGetEntityFromNetworkId(netId)
    if not DoesEntityExist(entity) then return false end

    -- Set the requesting player as the owner
    SetEntityRoutingBucket(entity, GetPlayerRoutingBucket(src))

    return true
end

-- client/ownership.lua
-- Request network control of an entity
local function TakeEntityControl(entity, timeout)
    timeout = timeout or 2000
    local start = GetGameTimer()

    NetworkRequestControlOfEntity(entity)

    while not NetworkHasControlOfEntity(entity) do
        Wait(100)
        NetworkRequestControlOfEntity(entity)
        if GetGameTimer() - start > timeout then
            return false
        end
    end

    return true
end

-- Usage: Move an entity you need control of
local function MoveEntity(entity, targetCoords)
    if TakeEntityControl(entity) then
        SetEntityCoords(entity, targetCoords.x, targetCoords.y, targetCoords.z, false, false, false, false)
        return true
    end

    print('[WARN] Could not get control of entity')
    return false
end

Apparition et gestion des Peds

Les entités Ped (piéton) sont utilisées pour les PNJ, les vendeurs de magasins, les donneurs de quêtes et les personnages ambiants. Ils nécessitent un traitement spécial car ils disposent d'une IA qui peut les faire s'éloigner, réagir à l'environnement ou attaquer les joueurs s'ils ne sont pas correctement configurés. Gèlez et désactivez toujours l’IA pour les PNJ statiques.

-- client/ped_spawner.lua
local function SpawnStaticPed(modelName, coords, heading, scenario)
    local model = joaat(modelName)

    RequestModel(model)
    while not HasModelLoaded(model) do
        Wait(10)
    end

    local ped = CreatePed(0, model, coords.x, coords.y, coords.z - 1.0, heading, false, true)

    -- Make the ped static and non-interactive with ambient AI
    SetEntityAsMissionEntity(ped, true, true)
    SetBlockingOfNonTemporaryEvents(ped, true)
    SetPedFleeAttributes(ped, 0, false)
    SetPedCombatAttributes(ped, 17, true)
    SetPedDiesWhenInjured(ped, false)
    SetEntityInvincible(ped, true)
    FreezeEntityPosition(ped, true)

    -- Play a scenario animation if specified
    if scenario then
        TaskStartScenarioInPlace(ped, scenario, 0, true)
    end

    SetModelAsNoLongerNeeded(model)
    RegisterEntity(ped, 'npc')

    return ped
end

-- Spawn a shop vendor
local vendor = SpawnStaticPed(
    's_m_y_ammucity_01',
    vector3(22.0, -1105.0, 29.8),
    160.0,
    'WORLD_HUMAN_STAND_IMPATIENT'
)

Conseils de performances pour la gestion des entités

  • Limiter les entités actives. Chaque entité consomme de la mémoire et des cycles de rendu. Utilisez des systèmes de streaming pour charger des entités lorsque le joueur est à proximité et les décharger lorsqu'il quitte la zone.
  • Utilisez des pools d'objets. Pour les entités fréquemment générées et supprimées, comme les douilles de balle ou les effets de particules, réutilisez les poignées d'entité au lieu d'en créer et d'en supprimer constamment de nouvelles.
  • Préférez les entités côté client. Si une entité ne doit être visible que par un seul joueur (comme un accessoire d'interface utilisateur ou un objet d'aperçu), créez-la comme non en réseau pour réduire la charge du serveur.
  • Appelez toujours SetModelAsNoLongerNeeded. Les modèles chargés restent en mémoire jusqu'à ce qu'ils soient explicitement publiés. L'oubli de cet appel est l'une des causes les plus courantes de fuites de mémoire dans les scripts FiveM.
  • Vérifiez DoesEntityExist avant les opérations. Les entités peuvent être supprimées par le moteur de jeu, d'autres scripts ou par désynchronisation. Vérifiez toujours qu'une entité existe toujours avant d'essayer de la modifier.
  • Utilisez des sacs d'état d'entité pour les métadonnées. Au lieu de conserver des tables de recherche distinctes pour les données d'entité, utilisez Entity(entity).state pour stocker les propriétés personnalisées directement sur l'entité.

Partager cet article

Prêt à améliorer votre serveur ?

Découvrez nos scripts FiveM premium dans la boutique Agency Scripts ou rejoignez notre communauté Discord pour le support et les mises à jour.