150 lines
3.3 KiB
Lua
Raw Normal View History

-- abort if the function already exists
if minetest.delay_function then
minetest.log("error", "[function_delayer] minetest.delay_function already exists.")
return
end
local clock = minetest.get_us_time
local load_time_start = clock()
local maxdelay = 1 * 1000000
local skipstep = 5
local lastmod_effect = 2
local tasks = {}
-- used for the table.sort function
local previous_modname
local function sort_times(a, b)
a, b = tasks[a], tasks[b]
local a_first = b.time - a.time
if a.mod_origin ~= b.mod_origin then
if a.mod_origin == previous_modname then
a_first = a_first - lastmod_effect
elseif b.mod_origin == previous_modname then
a_first = a_first + lastmod_effect
end
end
a_first = a_first > 0
previous_modname = a_first and a.mod_origin or b.mod_origin
return a_first
end
local needs_sort, toadd, supramod
local todo = {}
function minetest.delay_function(task, func, ...)
if type(task) == "number" then
task = {time = task}
end
if toadd then
task.time = task.time + toadd
end
local id = #tasks+1
todo[#todo+1] = id
task.mod_origin = supramod or minetest.get_last_run_mod()
if func then
task.func = func
task.params = {...}
end
tasks[id] = task
needs_sort = true
end
local stepnum = 0
local col_dtime = 0
minetest.register_globalstep(function(dtime)
local count = #todo
-- abort if nothing is todo
if count == 0 then
return
end
-- abort if it's not the skipstepths step
stepnum = (stepnum+1)%skipstep
col_dtime = col_dtime+dtime
if stepnum ~= 0 then
return
end
dtime = col_dtime
col_dtime = 0
-- get the start time
local ts = clock() - dtime * 1000000
if needs_sort then
-- execute the functions with lower delays earlier
table.sort(todo, sort_times)
needs_sort = false
end
-- execute expired functions
toadd = dtime
local n = 1
while true do
local id = todo[n]
if not id then
break
end
local task = tasks[id]
local time = task.time - dtime
if time < 0 then
local params = task.params or {}
params[#params+1] = time
local func = task.func
supramod = task.mod_origin
table.remove(todo, n)
tasks[id] = nil
func(unpack(params))
else
task.time = time
n = n+1
end
--print("expired")
end
toadd = nil
supramod = nil
-- execute functions until the time limit is reached
while todo[1]
and clock() - ts < maxdelay do
local task = tasks[todo[1]]
local params = task.params or {}
params[#params+1] = task.time
local func = task.func
supramod = task.mod_origin
tasks[todo[1]] = nil
table.remove(todo, 1)
func(unpack(params))
end
supramod = nil
end)
-- requested by raymoo
minetest.register_on_shutdown(function()
-- execute functions until nothing is left
while todo[1] do
local task = tasks[todo[1]]
tasks[todo[1]] = nil
table.remove(todo, 1)
if task.run_on_shutdown then
local params = task.params or {}
params[#params+1] = task.time -- time is wrong here
local func = task.func
supramod = task.mod_origin
func(unpack(params))
end
end
end)
local time = (clock()-load_time_start)/1000000
local msg = "[function_delayer] loaded after ca. "..time.." seconds"
if time > 0.01 then
print(msg)
else
minetest.log("info", msg)
end