196 lines
3.3 KiB
Lua
196 lines
3.3 KiB
Lua
local utils = ...
|
|
|
|
|
|
|
|
local RUN_INTERVAL = 0.1
|
|
|
|
|
|
|
|
local processes = { index = 0, current = 0 }
|
|
local after_job
|
|
|
|
|
|
|
|
local function run_processes ()
|
|
if #processes > 0 then
|
|
processes.index = (processes.index % #processes) + 1
|
|
|
|
local process = processes[processes.index]
|
|
|
|
processes.current = processes.index
|
|
process.timer = os.clock ()
|
|
process.resume ()
|
|
processes.current = 0
|
|
end
|
|
|
|
if #processes > 0 then
|
|
after_job = minetest.after (RUN_INTERVAL, run_processes)
|
|
else
|
|
processes.index = 0
|
|
processes.current = 0
|
|
after_job = nil
|
|
end
|
|
end
|
|
|
|
|
|
|
|
local long_process = { }
|
|
|
|
|
|
|
|
function long_process.remove (id)
|
|
if id then
|
|
for i = 1, #processes, 1 do
|
|
if processes[i].id == id then
|
|
local breaker = ((processes.current == id) and processes[i].breaker)
|
|
|
|
if processes.current == i then
|
|
processes.current = 0
|
|
elseif processes.current > i then
|
|
processes.current = processes.current - 1
|
|
end
|
|
|
|
if processes.index >= i then
|
|
processes.index = processes.index - 1
|
|
end
|
|
|
|
table.remove (processes, i)
|
|
|
|
if breaker then
|
|
breaker ()
|
|
end
|
|
|
|
return true
|
|
end
|
|
end
|
|
elseif processes[processes.current] then
|
|
local breaker = processes[processes.current].breaker
|
|
|
|
if processes.index >= processes.current then
|
|
processes.index = processes.index - 1
|
|
end
|
|
|
|
table.remove (processes, processes.current)
|
|
processes.current = 0
|
|
|
|
if breaker then
|
|
breaker ()
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
|
|
|
|
function long_process.breaker (id)
|
|
if id then
|
|
for i = 1, #processes, 1 do
|
|
if processes[i].id == id then
|
|
return processes[i].breaker
|
|
end
|
|
end
|
|
elseif processes[processes.current] then
|
|
return processes[processes.current].breaker
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
|
|
function long_process.timer (id)
|
|
if id then
|
|
for i = 1, #processes, 1 do
|
|
if processes[i].id == id then
|
|
return processes[i].timer
|
|
end
|
|
end
|
|
elseif processes[processes.current] then
|
|
return processes[processes.current].timer
|
|
end
|
|
|
|
return os.clock () + 3600
|
|
end
|
|
|
|
|
|
|
|
function long_process.expire (secs, id)
|
|
if id then
|
|
for i = 1, #processes, 1 do
|
|
if processes[i].id == id then
|
|
if (processes[i].timer + secs) <= os.clock () then
|
|
processes[i].breaker ()
|
|
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
elseif processes[processes.current] then
|
|
if (processes[processes.current].timer + secs) <= os.clock () then
|
|
processes[processes.current].breaker ()
|
|
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
|
|
|
|
function long_process.add (func, callback, ...)
|
|
local args = { ... }
|
|
local id = math.random (1000000)
|
|
local thread
|
|
|
|
|
|
local function thread_breaker ()
|
|
coroutine.yield (thread)
|
|
end
|
|
|
|
|
|
local function thread_func ()
|
|
return func (unpack (args))
|
|
end
|
|
|
|
|
|
local function thread_resume ()
|
|
local results = { coroutine.resume (thread) }
|
|
|
|
if coroutine.status (thread) == "dead" then
|
|
if callback then
|
|
callback (id, unpack (results))
|
|
end
|
|
|
|
long_process.remove (id)
|
|
end
|
|
end
|
|
|
|
thread = coroutine.create (thread_func)
|
|
|
|
if thread and coroutine.status (thread) == "suspended" then
|
|
processes[#processes + 1] =
|
|
{
|
|
id = id,
|
|
resume = thread_resume,
|
|
breaker = thread_breaker,
|
|
callback = callback,
|
|
timer = os.clock ()
|
|
}
|
|
|
|
if not after_job then
|
|
after_job = minetest.after (RUN_INTERVAL, run_processes)
|
|
end
|
|
|
|
return id
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
|
|
|
|
utils.long_process = long_process
|