Added Networked Markers Added Anim module Added framework default file for things that are native to game related to player Started on a batch network event trigger to allow for single event call for multiple events Updated params notation for ids Removed prints from client_entity + actions + ext
137 lines
6.8 KiB
Lua
137 lines
6.8 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
|
|
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]
|
|
if actionFunc then
|
|
-- print(string.format("[ClientEntityActions] Starting action '%s' for entity %s", nextAction.name, entityId))
|
|
ClientEntityActions.IsActionRunning [entityId] = true
|
|
-- Call the registered function
|
|
ClientEntityActions.ActionQueue[entityId] = actionFunc(entityData, table.unpack(nextAction.args))
|
|
if not ClientEntityActions.ActionQueue[entityId] then
|
|
-- If the action function doesn't return a queue, set it to nil
|
|
ClientEntityActions.IsActionRunning[entityId] = false
|
|
ClientEntityActions.ProcessNextAction(entityId) -- Try next action if this one failed immediately
|
|
end
|
|
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.ActionQueue[entityId] = 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")
|
|
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
|