Files
community_bridge/lib/entities/client/client_entity_actions.lua
T
gononono64 c23df31199 Server and client entity update
syncing non networked entities to all players in range
allow for firing functions when entering or exiting the range of the entity
2025-04-28 22:51:54 -05:00

136 lines
6.7 KiB
Lua

ClientEntityActions = {}
ClientEntityActions.ActionThreads = {} -- Store running action threads { [entityId] = thread }
ClientEntityActions.ActionQueue = {} -- Stores pending actions { [entityId] = {{name="ActionName", args={...}}, ...} }
ClientEntityActions.IsActionRunning = {} -- Tracks if an action is currently running { [entityId] = boolean }
ClientEntityActions.RegisteredActions = {} -- New: Registry for action implementations { [actionName] = function(entityData, ...) }
-- Forward declaration
--- Processes the next action in the queue for a given entity.
-- @param entityId string|number The ID of the entity.
function ClientEntityActions.ProcessNextAction(entityId)
if ClientEntityActions.IsActionRunning [entityId] then return end -- Already running something
print(string.format("[ClientEntityActions] Processing next action for entity %s", entityId))
local queue = ClientEntityActions.ActionQueue[entityId]
if not queue or #queue == 0 then return end -- Queue is empty
local nextAction = table.remove(queue, 1) -- Dequeue (FIFO)
local entityData = ClientEntity.Get(entityId) -- Assumes ClientEntity is accessible
-- Check if entity is still valid and spawned before starting next action
if not entityData or not entityData.spawned or not DoesEntityExist(entityData.spawned) then
-- Entity despawned while idle, clear queue and do nothing
ClientEntityActions.ActionQueue[entityId] = nil
return
end
-- Look up the action in the registry
local actionFunc = ClientEntityActions.RegisteredActions [nextAction.name]
print(string.format("[ClientEntityActions] Action '%s' dequeued for entity %s", nextAction.name, entityId))
if actionFunc then
-- print(string.format("[ClientEntityActions] Starting action '%s' for entity %s", nextAction.name, entityId))
ClientEntityActions.IsActionRunning [entityId] = true
-- Call the registered function
actionFunc(entityData, table.unpack(nextAction.args))
else
print(string.format("[ClientEntityActions] Unknown action '%s' dequeued for entity %s", nextAction.name, entityId))
-- Skip unknown action and try the next one immediately
ClientEntityActions.ProcessNextAction(entityId)
end
end
--- Registers a custom action implementation.
-- The action function should handle its own logic, including threading if needed,
-- and MUST call ClientEntityActions.ProcessNextAction(entityData.id) when it completes or fails,
-- after setting ClientEntityActions.IsActionRunning [entityData.id] = false.
-- @param actionName string The name used to trigger this action.
-- @param actionFunc function The function to execute. Signature: function(entityData, ...)
function ClientEntityActions.RegisterAction(actionName, actionFunc)
if ClientEntityActions.RegisteredActions [actionName] then
print(string.format("[ClientEntityActions] WARNING: Overwriting registered action '%s'", actionName))
end
assert(type(actionName) == "string", "actionName must be a string")
assert(type(actionFunc) == "function", "actionFunc must be a function")
print(string.format("[ClientEntityActions] Registered action: %s", actionName))
ClientEntityActions.RegisteredActions [actionName] = actionFunc
-- print(string.format("[ClientEntityActions] Registered action: %s", actionName))
end
--- Queues an action for an entity. Starts processing if idle.
-- @param entityData table The entity data.
-- @param actionName string The name of the action.
-- @param ... any Arguments for the action.
function ClientEntityActions.QueueAction(entityData, actionName, ...)
local entityId = entityData.id
if not ClientEntityActions.ActionQueue[entityId] then
ClientEntityActions.ActionQueue[entityId] = {}
end
local actionArgs = {...}
table.insert(ClientEntityActions.ActionQueue[entityId], { name = actionName, args = actionArgs })
-- print(string.format("[ClientEntityActions] Queued action '%s' for entity %s. Queue size: %d", actionName, entityId, #ClientEntityActions.ActionQueue[entityId]))
-- If the entity isn't currently doing anything, start processing immediately
if not ClientEntityActions.IsActionRunning [entityId] then
ClientEntityActions.ProcessNextAction(entityId)
end
end
--- Stops the current action and clears the queue for a specific entity.
-- @param entityId string|number The ID of the entity.
function ClientEntityActions.StopAction(entityId)
-- print(string.format("[ClientEntityActions] Stopping all actions for entity %s", entityId))
ClientEntityActions.ActionQueue[entityId] = nil -- Clear the queue
ClientEntityActions.IsActionRunning [entityId] = false -- Mark as not running (this will stop loops in threads)
-- Stop current task/thread if applicable
if ClientEntityActions.ActionThreads[entityId] then
-- Lua threads stop themselves based on ClientEntityActions.IsActionRunning flag
ClientEntityActions.ActionThreads[entityId] = nil
end
-- Specific task clearing for peds
local entityData = ClientEntity.Get(entityId)
if entityData and entityData.spawned and DoesEntityExist(entityData.spawned) then
if IsEntityAPed(entityData.spawned) then
ClearPedTasksImmediately(entityData.spawned) -- Use Immediately for forceful stop
end
-- Other entity types might need different stop logic
end
end
--- Skips the current action and starts the next one in the queue, if any.
-- @param entityId string|number The ID of the entity.
function ClientEntityActions.SkipAction(entityId)
if not ClientEntityActions.IsActionRunning [entityId] then
-- print(string.format("[ClientEntityActions] SkipAction called for %s, but no action running.", entityId))
return -- Nothing to skip
end
-- print(string.format("[ClientEntityActions] Skipping current action for entity %s", entityId))
ClientEntityActions.IsActionRunning [entityId] = false -- Mark as not running (this will stop loops in threads)
-- Stop current task/thread if applicable
if ClientEntityActions.ActionThreads[entityId] then
ClientEntityActions.ActionThreads[entityId] = nil
end
local entityData = ClientEntity.Get(entityId)
if entityData and entityData.spawned and DoesEntityExist(entityData.spawned) then
if IsEntityAPed(entityData.spawned) then
ClearPedTasksImmediately(entityData.spawned)
end
end
-- Immediately try to process the next action
ClientEntityActions.ProcessNextAction(entityId)
end
-- Add server-callable functions for Stop and Skip
function ClientEntityActions.Stop(entityData)
ClientEntityActions.StopAction(entityData.id)
end
function ClientEntityActions.Skip(entityData)
ClientEntityActions.SkipAction(entityData.id)
end
return ClientEntityActions