Gestión de entidades en FiveM: controla peatones, vehículos y objetos
Domina la gestión de entidades en FiveM. Crea, asigna y elimina peatones, vehículos y objetos para mantener tu servidor estable y rápido.
Agency Scripts
Fundador y desarrollador principal en Agency Scripts
Entender las entidades en FiveM
En FiveM, una entidad es cualquier objeto que existe en el mundo del juego: vehículos, peds, objetos, objetos recogibles e incluso el personaje del jugador. Cada entidad tiene un identificador (un ID entero) que se usa para interactuar con ella mediante funciones nativas. La gestión de entidades es una de las habilidades más fundamentales para desarrollar en FiveM, porque casi todos los scripts interactúan con entidades de alguna forma. Una gestión deficiente de las entidades provoca fugas de memoria, objetos fantasma que permanecen tras reiniciar un recurso, desincronización entre jugadores y, en última instancia, inestabilidad del servidor. Esta guía cubre los patrones correctos para crear, registrar y eliminar entidades.
Generar objetos y props
La función nativa principal para generar props es CreateObject (o CreateObjectNoOffset). Antes de generar cualquier objeto, debes solicitar el modelo y esperar a que se cargue. Si no solicitas el modelo primero, la entidad será invisible o no aparecerá. Libera siempre el modelo después de crear el objeto para liberar memoria.
-- 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)
Generar vehículos
La generación de vehículos sigue un patrón similar, pero usa CreateVehicle y requiere tener en cuenta otros aspectos, como la propiedad de red, el nivel de combustible y el texto de la matrícula. Genera siempre los vehículos en el servidor cuando sea posible o usa callbacks del servidor para validar las solicitudes de creación de vehículos de los 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
Seguimiento y limpieza de entidades
El aspecto más importante de la gestión de entidades es registrar todas las entidades que crea tu script y eliminarlas cuando el recurso se detenga. Sin una limpieza adecuada, las entidades permanecen en el mundo del juego como huérfanas y consumen memoria y recursos de renderizado. Usa una tabla de seguimiento para guardar todos los identificadores de entidades y registra un controlador de onResourceStop que las elimine.
-- 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)
Propiedad de las entidades de red
En el entorno de red de FiveM, cada entidad tiene un propietario: el cliente responsable de simular su física y posición. La propiedad de red determina qué cliente de jugador controla el movimiento y las colisiones de la entidad. Entender y gestionar la propiedad de red es esencial para sincronizar el comportamiento de las entidades, especialmente en scripts que necesitan controlar NPC o vehículos de forma remota.
-- 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
Generar y gestionar peds
Las entidades ped (peatón) se usan para NPC, vendedores, personajes que dan misiones y personajes ambientales. Requieren un tratamiento especial, porque su IA puede hacer que se alejen, reaccionen al entorno o ataquen a los jugadores si no se configuran correctamente. Para los NPC estáticos, congélalos y desactiva siempre su IA.
-- 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'
)
Consejos de rendimiento para gestionar entidades
- Limita las entidades activas. Cada entidad consume memoria y ciclos de renderizado. Usa sistemas de streaming para cargar entidades cuando el jugador esté cerca y descargarlas cuando se aleje de la zona.
- Usa pools de objetos. Para entidades que aparecen y desaparecen con frecuencia, como casquillos de bala o efectos de partículas, reutiliza los identificadores de entidad en lugar de crear y eliminar entidades nuevas constantemente.
- Prefiere las entidades del lado del cliente. Si una entidad solo debe ser visible para un jugador, como un objeto de interfaz o de vista previa, créala sin conexión de red para reducir la carga del servidor.
- Llama siempre a SetModelAsNoLongerNeeded. Los modelos cargados permanecen en la memoria hasta que se liberan explícitamente. Olvidar esta llamada es una de las causas más comunes de fugas de memoria en scripts de FiveM.
- Comprueba DoesEntityExist antes de realizar operaciones. El motor del juego, otros scripts o la desincronización pueden eliminar entidades. Comprueba siempre que una entidad siga existiendo antes de intentar modificarla.
- Usa state bags de entidades para los metadatos. En lugar de mantener tablas de búsqueda independientes para los datos de las entidades, usa
Entity(entity).statepara guardar propiedades personalizadas directamente en la entidad.