summaryrefslogtreecommitdiff
path: root/Data/BuiltIn/Libraries/coil/coil.lua
diff options
context:
space:
mode:
authorchai <chaifix@163.com>2021-11-15 16:46:12 +0800
committerchai <chaifix@163.com>2021-11-15 16:46:12 +0800
commite47a1e5544d00c26aa08ae41287a525617e494b8 (patch)
treecde0574240413c6546310efd50414aa6d4f66403 /Data/BuiltIn/Libraries/coil/coil.lua
parent2853639a612860ab5a5710471ad66c33d63c9b41 (diff)
*misc
Diffstat (limited to 'Data/BuiltIn/Libraries/coil/coil.lua')
-rw-r--r--Data/BuiltIn/Libraries/coil/coil.lua165
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