syncing non networked entities to all players in range allow for firing functions when entering or exiting the range of the entity
136 lines
6.7 KiB
Lua
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
|