Files
community_bridge/lib/entities/client/client_entity.lua
T

248 lines
9.4 KiB
Lua
Raw Normal View History

2025-04-23 14:10:19 -05:00
Utility = Utility or Require("lib/utility/client/utility.lua")
Ids = Ids or Require("lib/utility/shared/ids.lua")
Point = Point or Require("lib/points/client/points.lua")
2025-04-28 22:51:54 -05:00
ClientEntityActions = ClientEntityActions or Require("lib/entities/client/client_entity_actions_ext.lua") -- Added
2025-04-23 14:10:19 -05:00
local Entities = {} -- Stores entity data received from server
ClientEntity = {} -- Renamed from BaseEntity
local function SpawnEntity(entityData)
entityData = entityData and entityData.args
if entityData.spawned and DoesEntityExist(entityData.spawned) then return end -- Already spawned
-- for k, v in pairs(entityData.args) do
-- print(string.format("SpawnEntity %s: %s", k, v))
-- end
2025-07-25 02:51:14 -05:00
local loaded, model = Utility.LoadModel(entityData.model)
2025-07-24 05:03:07 -05:00
if not loaded then
2025-04-23 14:10:19 -05:00
print(string.format("[ClientEntity] Failed to load model %s for entity %s", entityData.model, entityData.id))
return
end
local entity = nil
local coords = entityData.coords
2025-07-24 05:03:07 -05:00
local rotation = entityData.rotation or vector3(0.0, 0.0, entityData.heading or 0.0) -- Default rotation if not provided
2025-04-23 14:10:19 -05:00
if entityData.entityType == 'object' then
entity = CreateObject(model, coords.x, coords.y, coords.z, false, false, false)
SetEntityRotation(entity, rotation.x, rotation.y, rotation.z, 2, true)
elseif entityData.entityType == 'ped' then
entity = CreatePed(4, model, coords.x, coords.y, coords.z, type(rotation) == 'number' and rotation or rotation.z, false, false)
elseif entityData.entityType == 'vehicle' then
entity = CreateVehicle(model, coords.x, coords.y, coords.z, type(rotation) == 'number' and rotation or rotation.z, false, false)
else
print(string.format("[ClientEntity] Unknown entity type '%s' for entity %s", entityData.entityType, entityData.id))
end
2025-06-02 22:19:42 -05:00
if entity and model then
2025-04-23 14:10:19 -05:00
entityData.spawned = entity
SetModelAsNoLongerNeeded(model)
2025-06-02 22:19:42 -05:00
SetEntityAsMissionEntity(entity, true, true)
FreezeEntityPosition(entity, true)
2025-04-23 14:10:19 -05:00
else
SetModelAsNoLongerNeeded(model)
end
2025-06-02 22:19:42 -05:00
if entityData.OnSpawn then
entityData.OnSpawn(entityData)
end
2025-04-23 14:10:19 -05:00
end
2025-07-28 00:58:02 -05:00
local function RemoveEntity(entityData, skip)
2025-05-11 00:47:33 -05:00
entityData = entityData and entityData.args or entityData
if not entityData then return end
ClientEntityActions.StopAction(entityData.id)
2025-04-23 14:10:19 -05:00
if entityData.spawned and DoesEntityExist(entityData.spawned) then
local entityHandle = entityData.spawned
2025-05-11 00:47:33 -05:00
entityData.spawned = nil
SetEntityAsMissionEntity(entityHandle, false, false)
2025-04-23 14:10:19 -05:00
DeleteEntity(entityHandle)
end
2025-07-28 00:58:02 -05:00
if not skip and entityData.OnRemove then
2025-04-23 14:10:19 -05:00
entityData.OnRemove(entityData)
end
end
--- Registers an entity received from the server and sets up proximity spawning.
-- @param entityData table Data received from the server via 'community_bridge:client:CreateEntity'
2025-06-30 15:18:01 -05:00
function ClientEntity.Create(entityData)
entityData.id = entityData.id or Ids.CreateUniqueId(Entities)
if Entities[entityData.id] then return Entities[entityData.id] end -- Already registered
2025-04-23 14:10:19 -05:00
Entities[entityData.id] = entityData
2025-06-30 15:18:01 -05:00
return Point.Register(entityData.id, entityData.coords, entityData.spawnDistance or 50.0, entityData, SpawnEntity, RemoveEntity, function() end)
2025-04-23 14:10:19 -05:00
end
2025-06-30 15:18:01 -05:00
--Depricated use ClientEntity.Create instead
--- Registers an entity and spawns it in the world if not already spawned.
ClientEntity.Register = ClientEntity.Create
function ClientEntity.CreateBulk(entities)
2025-06-22 17:40:41 -05:00
local registeredEntities = {}
for _, entityData in pairs(entities) do
2025-06-30 15:18:01 -05:00
local entity = ClientEntity.Create(entityData)
registeredEntities[entity.id] = entity
2025-06-22 17:40:41 -05:00
end
return registeredEntities
end
2025-06-30 15:18:01 -05:00
-- Depricated use ClientEntity.CreateBulk instead
ClientEntity.RegisterBulk = ClientEntity.CreateBulk
2025-04-23 14:10:19 -05:00
--- Unregisters an entity and removes it from the world if spawned.
-- @param id string|number The ID of the entity to unregister.
2025-06-30 15:18:01 -05:00
function ClientEntity.Destroy(id)
2025-04-23 14:10:19 -05:00
local entityData = Entities[id]
if not entityData then return end
2025-06-02 22:19:42 -05:00
Point.Remove(id)
RemoveEntity(entityData)
2025-04-23 14:10:19 -05:00
Entities[id] = nil
end
2025-06-30 15:18:01 -05:00
ClientEntity.Unregister = ClientEntity.Destroy
2025-04-23 14:10:19 -05:00
--- Updates the data for a registered entity.
-- @param id string|number The ID of the entity to update.
-- @param data table The data fields to update.
function ClientEntity.Update(id, data)
local entityData = Entities[id]
2025-05-09 19:06:50 -05:00
-- print(string.format("[ClientEntity] Updating entity %s", id))
2025-04-23 14:10:19 -05:00
if not entityData then return end
local needsPointUpdate = false
for key, value in pairs(data) do
if key == 'coords' and #(entityData.coords - value) > 0.1 then
needsPointUpdate = true
end
if key == 'spawnDistance' and entityData.spawnDistance ~= value then
needsPointUpdate = true
end
entityData[key] = value
end
-- If entity is currently spawned, apply updates
if entityData.spawned and DoesEntityExist(entityData.spawned) then
if data.coords then
SetEntityCoords(entityData.spawned, entityData.coords.x, entityData.coords.y, entityData.coords.z, false, false, false, true)
end
if data.rotation then
if entityData.entityType == 'object' then
SetEntityRotation(entityData.spawned, entityData.rotation.x, entityData.rotation.y, entityData.rotation.z, 2, true)
else -- Ped/Vehicle heading
SetEntityHeading(entityData.spawned, type(entityData.rotation) == 'number' and entityData.rotation or entityData.rotation.z)
end
end
if data.freeze ~= nil then
FreezeEntityPosition(entityData.spawned, data.freeze)
end
-- Add other updatable properties as needed
end
-- Update Point registration if coords or distance changed
if needsPointUpdate then
Point.Remove(id)
Point.Register(
entityData.id,
entityData.coords,
entityData.spawnDistance or 50.0,
SpawnEntity,
RemoveEntity,
nil,
entityData
)
end
if entityData.OnUpdate and type(entityData.OnUpdate) == 'function' then
entityData.OnUpdate(entityData, data)
end
end
function ClientEntity.Get(id)
return Entities[id]
end
function ClientEntity.GetAll()
return Entities
end
2025-05-04 11:11:29 -05:00
function ClientEntity.RegisterAction(name, func)
ClientEntityActions.RegisterAction(name, func)
end
2025-06-30 15:18:01 -05:00
function ClientEntity.OnCreate(_type, func)
ClientEntity.OnCreates = ClientEntity.OnCreates or {}
if not ClientEntity.OnCreates[_type] then
ClientEntity.OnCreates[_type] = {}
end
table.insert(ClientEntity.OnCreates[_type], func)
end
2025-04-23 14:10:19 -05:00
-- Network Event Handlers
RegisterNetEvent("community_bridge:client:CreateEntity", function(entityData)
2025-06-30 15:18:01 -05:00
ClientEntity.Create(entityData)
2025-04-23 14:10:19 -05:00
end)
2025-06-22 17:40:41 -05:00
RegisterNetEvent("community_bridge:client:CreateEntities", function(entities)
2025-06-30 15:18:01 -05:00
ClientEntity.CreateBulk(entities)
2025-06-22 17:40:41 -05:00
end)
2025-04-23 14:10:19 -05:00
RegisterNetEvent("community_bridge:client:DeleteEntity", function(id)
ClientEntity.Unregister(id)
end)
RegisterNetEvent("community_bridge:client:UpdateEntity", function(id, data)
ClientEntity.Update(id, data)
end)
-- New handler for entity actions
RegisterNetEvent("community_bridge:client:TriggerEntityAction", function(entityId, actionName, ...)
local entityData = Entities[entityId]
2025-04-28 22:51:54 -05:00
-- Check if entity exists locally (it doesn't need to be spawned to queue actions)
if entityData then
if actionName == "Stop" then
ClientEntityActions.StopAction(entityId)
elseif actionName == "Skip" then
ClientEntityActions.SkipAction(entityId)
2025-04-23 14:10:19 -05:00
else
2025-04-28 22:51:54 -05:00
print(string.format("[ClientEntity] Triggering action '%s' for entity %s", actionName, entityId))
local currentAction = ClientEntityActions.ActionQueue[entityId] and ClientEntityActions.ActionQueue[entityId][1]
ClientEntityActions.QueueAction(entityData, actionName, ...)
2025-04-23 14:10:19 -05:00
end
-- else
2025-04-28 22:51:54 -05:00
-- Optional: Log if action received but entity doesn't exist locally at all
-- print(string.format("[ClientEntity] Received action '%s' for non-existent entity %s.", actionName, entityId))
2025-04-23 14:10:19 -05:00
end
end)
2025-05-04 11:11:29 -05:00
RegisterNetEvent("community_bridge:client:TriggerEntityActions", function(entityId, actions, endPosition)
local entityData = Entities[entityId]
if entityData then
2025-06-02 22:19:42 -05:00
for _, actionData in pairs(actions) do
2025-05-04 11:11:29 -05:00
local actionName = actionData.name
local actionParams = actionData.params
if actionName == "Stop" then
ClientEntityActions.StopAction(entityId)
elseif actionName == "Skip" then
ClientEntityActions.SkipAction(entityId)
else
local currentAction = ClientEntityActions.ActionQueue[entityId] and ClientEntityActions.ActionQueue[entityId][1]
ClientEntityActions.QueueAction(entityData, actionName, table.unpack(actionParams))
end
end
else
print(string.format("[ClientEntity] Received actions for non-existent entity %s.", entityId))
end
end)
2025-04-23 14:10:19 -05:00
-- Resource Stop Cleanup
AddEventHandler('onResourceStop', function(resourceName)
if resourceName == GetCurrentResourceName() then
for id, entityData in pairs(Entities) do
Point.Remove(id) -- Clean up point registration
2025-07-28 00:58:02 -05:00
RemoveEntity(entityData, true) -- Clean up spawned game entity
2025-04-23 14:10:19 -05:00
end
Entities = {} -- Clear local cache
end
end)
return ClientEntity