-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathtask.lua
168 lines (146 loc) · 3.79 KB
/
task.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
local resume,status=coroutine.resume,coroutine.status
local assert,rawset=assert,rawset
local rem=table.remove
local timer=ZENITHA.timer.getTime
local TASK={}
-- Locks
---@type Map<number>
local locks=setmetatable({},{
__index=function(self,k) rawset(self,k,-1e99) return -1e99 end,
__newindex=function(self,k) rawset(self,k,-1e99) end,
})
---Attempt to set a labeled lock
---
---Can only succeed if the same-name lock is not set or has expired
---
---### Example
---```
----- Making 'name' sound cannot be played in next 0.26 seconds
---if TASK.lock('sound_name',0.26) then playSound('name') end
---```
---@param name any
---@param time? number
---@return boolean
function TASK.lock(name,time)
if timer()>=locks[name] then
locks[name]=timer()+(time or 1e99)
return true
else
return false
end
end
---Same as `TASK.lock`, but lock will be forced set even if the lock is not expired
---@param name any
---@param time? number
---@return boolean succeed
function TASK.forceLock(name,time)
local res=timer()>=locks[name]
locks[name]=timer()+(time or 1e99)
return res
end
---Invalidate a lock
---@param name any
function TASK.unlock(name)
locks[name]=-1e99
end
---Get the time remaining of a lock, false if not locked or expired
---@param name any
---@return number | false
function TASK.getLock(name)
local v=locks[name]-timer()
return v>0 and v
end
---Remove the locks which are already expired
function TASK.freshLock()
for k,v in next,locks do
if timer()>v then locks[k]=nil end
end
end
---Invalidate all locks
function TASK.clearLock()
for k in next,locks do
locks[k]=nil
end
end
local tasks={}
---Update all tasks (called by Zenitha)
---@param dt number
function TASK._update(dt)
for i=#tasks,1,-1 do
local T=tasks[i]
if status(T.thread)=='dead' then
rem(tasks,i)
else
assert(resume(T.thread,dt))
end
end
end
---Wrap a function into coroutine then Zenitha will resume it automatically for each main loop cycle.
---Immediately resume when `TASK.new()`, then trigger by time with `dt` passed to it through `coroutine.yield` inside
---@generic T
---@param code async fun(...:T)
---@param ... T First-call arguments when called
function TASK.new(code,...)
local thread=coroutine.create(code)
assert(resume(thread,...))
if status(thread)~='dead' then
tasks[#tasks+1]={
thread=thread,
code=code,
args={...},
}
end
end
---Get the number of tasks
---@return number
function TASK.getCount()
return #tasks
end
---Remove task(s) by specified code(the function which created the task)
---@param code function
function TASK.removeTask_code(code)
for i=#tasks,1,-1 do
if tasks[i].code==code then
rem(tasks,i)
end
end
end
---Iterate through tasks, remove them if the given function returns true
---@param func function
---@param ... any Arguments passed to the given function
function TASK.removeTask_iterate(func,...)
for i=#tasks,1,-1 do
if func(tasks[i],...) then
rem(tasks,i)
end
end
end
---Remove all tasks
function TASK.clear()
for k in next,locks do
tasks[k]=nil
end
end
local yield=coroutine.yield
---Yield for some times
---@param count number
function TASK.yieldN(count)
for _=1,count do yield() end
end
---Yield for some seconds
---@param time number
function TASK.yieldT(time)
local t=timer()
while timer()-t<time do yield() end
end
local getLock=TASK.getLock
---Yield until a lock expired
---@param name string
function TASK.yieldL(name)
while getLock(name) do yield() end
end
---Yield until the scene swapping animation finished
function TASK.yieldUntilNextScene()
while SCN.swapping do yield() end
end
return TASK