---@alias ActionResult {} ---@type table<string, ActionResult> -- selene: allow(unscoped_variables) ActionResult = { Succeeded = {}, Failed = {}, NeedsMoreTime = {}, } -- selene: allow(unscoped_variables) actionQueue = { ---@type ({ action: Action, expireTimeMs: number })[] queue = {}, } ---@alias Action fun(deltaSeconds: number): ActionResult --- Added actions will be called on every runWaiting() update. --- They will continue to be executed until they return Succeeded or Failed instead of NeedsMoreTime. --- --- Replaces any existing action with the given name. --- If the initial call of action() doesn't return NeedsMoreTime, this function will not bother adding it to the queue. ---@param name string ---@param maxTimeMs number ---@param action Action function actionQueue:upsert(name, maxTimeMs, action) if action(0) ~= ActionResult.NeedsMoreTime then return end self.queue[name] = { action = action, expireTimeMs = maxTimeMs + playdate.getCurrentTimeMilliseconds(), } end --- Must be called on every playdate.update() to check for (and run) any waiting tasks. --- Actions that return NeedsMoreTime will not be removed from the queue unless they have expired. function actionQueue:runWaiting(deltaSeconds) local currentTimeMs = playdate.getCurrentTimeMilliseconds() for name, actionObject in pairs(self.queue) do local result = actionObject.action(deltaSeconds) if result ~= ActionResult.NeedsMoreTime or currentTimeMs > actionObject.expireTimeMs then self.queue[name] = nil end end end