Tutorial 2026-05-05

Gestão de Entidades e Spawn de Objetos em FiveM

TDYSKY

TDYSKY

Fundador & Lead Developer na Agency Scripts

Compreendendo as entidades no FiveM

No FiveM, uma entidade é qualquer objeto que existe no mundo do jogo: veículos, pedestres, adereços, pickups e até mesmo o personagem do jogador. Cada entidade possui um identificador (um ID inteiro) que você usa para interagir com ela por meio de funções nativas. O gerenciamento de entidades é uma das habilidades mais fundamentais no desenvolvimento FiveM porque quase todos os scripts interagem com as entidades de alguma forma. O mau gerenciamento de entidades leva a vazamentos de memória, objetos fantasmas que persistem após a reinicialização de um recurso, dessincronização entre jogadores e, por fim, instabilidade do servidor. Este guia aborda os padrões corretos para criar, rastrear e limpar entidades.

Gerando objetos e acessórios

O principal nativo para adereços de spawn é CreateObject (ou CreateObjectNoOffset). Antes de gerar qualquer objeto, você deve solicitar o modelo e aguardar seu carregamento. Deixar de solicitar o modelo primeiro resultará em uma entidade invisível ou ausente. Sempre libere o modelo após criar o objeto para liberar memória.

-- 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)

Desova de Veículos

A geração de veículos segue um padrão semelhante, mas usa CreateVehicle e tem considerações adicionais sobre propriedade da rede, níveis de combustível e texto da placa. Sempre gere veículos no lado do servidor quando possível ou use retornos de chamada do lado do servidor para validar solicitações de criação de veículos dos clientes.

-- 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

Rastreamento e limpeza de entidades

O aspecto mais crítico do gerenciamento de entidades é rastrear cada entidade que seu script cria e limpá-las quando o recurso é interrompido. Sem a limpeza adequada, as entidades persistem no mundo do jogo como órfãs que desperdiçam memória e renderizam recursos. Use uma tabela de rastreamento para armazenar todos os identificadores de entidade e registrar um manipulador onResourceStop que os remove.

-- 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)

Propriedade da entidade de rede

No ambiente de rede do FiveM, cada entidade possui um proprietário, o cliente responsável por simular sua física e posição. A propriedade da rede determina qual cliente do jogador controla o movimento e a colisão da entidade. Compreender e gerenciar a propriedade da rede é essencial para o comportamento sincronizado da entidade, especialmente para scripts que precisam controlar NPCs ou veículos remotamente.

-- 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

Gerando e Gerenciando Peds

Entidades Ped (pedestres) são usadas para NPCs, vendedores de lojas, entregadores de missões e personagens ambientais. Eles exigem tratamento especial porque possuem IA que pode fazer com que eles se desviem, reajam ao ambiente ou ataquem jogadores se não forem configurados corretamente. Sempre congele e desative a IA para NPCs estáticos.

-- 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'
)

Dicas de desempenho para gerenciamento de entidades

  • Limitar entidades ativas. Cada entidade consome memória e ciclos de renderização. Use sistemas de streaming para carregar entidades quando o jogador estiver por perto e descarregá-las quando ele sair da área.
  • Use pools de objetos. Para entidades geradas e desaparecidas com frequência, como invólucros de balas ou efeitos de partículas, reutilize identificadores de entidade em vez de criar e excluir novos constantemente.
  • Prefira entidades do lado do cliente. Se uma entidade só precisa ser visível para um jogador (como um suporte de interface de usuário ou um objeto de visualização), crie-a como sem rede para reduzir a carga do servidor.
  • Sempre chame SetModelAsNoLongerNeeded. Os modelos carregados permanecem na memória até serem liberados explicitamente. Esquecer esta chamada é uma das causas mais comuns de vazamentos de memória em scripts FiveM.
  • Verifique DoesEntityExist antes das operações. As entidades podem ser excluídas pelo mecanismo de jogo, outros scripts ou dessincronização. Sempre verifique se uma entidade ainda existe antes de tentar modificá-la.
  • Use pacotes de estado de entidade para metadados. Em vez de manter tabelas de pesquisa separadas para dados de entidade, use Entity(entity).state para armazenar propriedades personalizadas diretamente na entidade.

Partilhar este artigo

Pronto para melhorar o teu servidor?

Explora os nossos scripts FiveM premium na loja Agency Scripts ou junta-te à nossa comunidade no Discord para suporte e atualizações.