lwcomponents_for_VoxeLibre/lwcomponents/long_process.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