-- selene: allow(unscoped_variables) actionQueue = { ---@type table queue = {}, } ---@alias Action fun(deltaSeconds: number) --selene: allow(incorrect_standard_library_use) local close = coroutine.close --- 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 id. --- If the initial call of action() doesn't return NeedsMoreTime, this function will not bother adding it to the queue. ---@param id any ---@param maxTimeMs number ---@param action Action function actionQueue:upsert(id, maxTimeMs, action) if self.queue[id] then close(self.queue[id].coroutine) end self.queue[id] = { coroutine = coroutine.create(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 id, actionObject in pairs(self.queue) do coroutine.resume(actionObject.coroutine, deltaSeconds) if currentTimeMs > actionObject.expireTimeMs then close(actionObject.coroutine) end if coroutine.status(actionObject.coroutine) == "dead" then self.queue[id] = nil end end end