diff options
author | chai <chaifix@163.com> | 2021-11-15 16:46:12 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-11-15 16:46:12 +0800 |
commit | e47a1e5544d00c26aa08ae41287a525617e494b8 (patch) | |
tree | cde0574240413c6546310efd50414aa6d4f66403 /Data/BuiltIn/Libraries/coil/coil.lua | |
parent | 2853639a612860ab5a5710471ad66c33d63c9b41 (diff) |
*misc
Diffstat (limited to 'Data/BuiltIn/Libraries/coil/coil.lua')
-rw-r--r-- | Data/BuiltIn/Libraries/coil/coil.lua | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/Data/BuiltIn/Libraries/coil/coil.lua b/Data/BuiltIn/Libraries/coil/coil.lua new file mode 100644 index 0000000..fbd20c9 --- /dev/null +++ b/Data/BuiltIn/Libraries/coil/coil.lua @@ -0,0 +1,165 @@ +-- +-- coil +-- +-- Copyright (c) 2014 rxi +-- +-- This library is free software; you can redistribute it and/or modify it +-- under the terms of the MIT license. See LICENSE for details. +-- + +local coil = { _version = "0.1.0" } +coil.__index = coil +coil.tasks = {} + + +local unpack = unpack or table.unpack + +local _assert = function(cond, msg, lvl) + if cond then return cond, msg, lvl end + error(msg, lvl + 1) +end + +local callback_mt = { + __call = function(t, ...) + t.args = {...} + t.ready = true + end} + + +local task = {} +task.__index = task + + +function task.new(fn, parent) + local self = setmetatable({}, task) + self.routine = coroutine.wrap(fn) + self.parent = parent + self.pausecount = 0 + return self +end + + +function task:pause() + self.pausecount = self.pausecount + 1 +end + + +function task:resume() + _assert(self.pausecount > 0, "unbalanced resume()", 2) + self.pausecount = self.pausecount - 1 +end + + +function task:stop() + coil.remove(self.parent, self) +end + + + +function coil:update(dt) + if #self == 0 then return end + coil.deltatime = dt + for i = #self, 1, -1 do + local task = self[i] + if task.wait then + -- Handle wait + if type(task.wait) == "number" then + -- Handle numerical wait + task.wait = task.wait - dt + if task.wait <= 0 then + task.waitrem = task.wait + task.wait = nil + end + elseif type(task.wait) == "table" then + -- Handle callback object + if task.wait.ready then + task.wait = nil + end + end + end + if not task.wait and task.pausecount == 0 then + -- Run task + coil.current = task + if not task.routine() then + coil.remove(self, i) + end + end + end + coil.current = nil +end + + +function coil:add(fn) + local t = task.new(fn, self) + table.insert(self, t) + return t +end + + +function coil:remove(t) + if type(t) == "number" then + self[t] = self[#self] + table.remove(self) + return + end + for i, task in ipairs(self) do + if task == t then + return coil.remove(self, i) + end + end +end + + +function coil.wait(x, y) + -- Discard first argument if its a coil group + x = getmetatable(x) == coil and y or x + local c = coil.current + _assert(c, "wait() called from outside a coroutine", 2) + if type(x) == "number" then + -- Handle numerical wait + c.wait = (c.waitrem or 0) + x + if c.wait <= 0 then + c.waitrem = c.wait + return + else + c.waitrem = nil + end + else + -- Handle next-frame / callback wait + _assert(x == nil or getmetatable(x) == callback_mt, + "wait() expected number, callback object or nothing as argument", + 2) + c.waitrem = nil + c.wait = x + end + coroutine.yield(true) + -- Return args if wait was a callback object + if type(x) == "table" then + return unpack(x.args) + end + -- Return delta time if wait had no args + if x == nil then + return coil.deltatime + end +end + + +function coil.callback() + return setmetatable({ ready = false }, callback_mt) +end + + +function coil.group() + return setmetatable({}, coil) +end + + + +local bound = { + update = function(...) return coil.update(coil.tasks, ...) end, + add = function(...) return coil.add(coil.tasks, ...) end, + remove = function(...) return coil.remove(coil.tasks, ...) end, +} +setmetatable(bound, coil) + +return bound |