diff --git a/builtin/game/misc.lua b/builtin/game/misc.lua index efd0f8dc7..bacadf18f 100644 --- a/builtin/game/misc.lua +++ b/builtin/game/misc.lua @@ -4,74 +4,48 @@ -- Misc. API functions -- -local timers = {} -local mintime -local function update_timers(delay) - mintime = false - local sub = 0 - for index = 1, #timers do - index = index - sub - local timer = timers[index] - timer.time = timer.time - delay - if timer.time <= 0 then - core.set_last_run_mod(timer.mod_origin) - timer.func(unpack(timer.args or {})) - table.remove(timers, index) - sub = sub + 1 - elseif mintime then - mintime = math.min(mintime, timer.time) - else - mintime = timer.time +local jobs = {} +local time = 0.0 +local last = 0.0 + +core.register_globalstep(function(dtime) + local new = core.get_us_time() / 1000000 + if new > last then + time = time + (new - last) + else + -- Overflow, we may lose a little bit of time here but + -- only 1 tick max, potentially running timers slightly + -- too early. + time = time + new + end + last = new + + if #jobs < 1 then + return + end + + -- Iterate backwards so that we miss any new timers added by + -- a timer callback, and so that we don't skip the next timer + -- in the list if we remove one. + for i = #jobs, 1, -1 do + local job = jobs[i] + if time >= job.expire then + core.set_last_run_mod(job.mod_origin) + job.func(unpack(job.arg)) + table.remove(jobs, i) end end -end - -local timers_to_add -local function add_timers() - for _, timer in ipairs(timers_to_add) do - table.insert(timers, timer) - end - timers_to_add = false -end - -local delay = 0 -core.register_globalstep(function(dtime) - if not mintime then - -- abort if no timers are running - return - end - if timers_to_add then - add_timers() - end - delay = delay + dtime - if delay < mintime then - return - end - update_timers(delay) - delay = 0 end) -function core.after(time, func, ...) +function core.after(after, func, ...) assert(tonumber(time) and type(func) == "function", "Invalid core.after invocation") - if not mintime then - mintime = time - timers_to_add = {{ - time = time+delay, - func = func, - args = {...}, - mod_origin = core.get_last_run_mod(), - }} - return - end - mintime = math.min(mintime, time) - timers_to_add = timers_to_add or {} - timers_to_add[#timers_to_add+1] = { - time = time+delay, - func = func, - args = {...}, - mod_origin = core.get_last_run_mod(), - } + table.insert(jobs, { + func = func, + expire = time + after, + arg = {...}, + mod_origin = core.get_last_run_mod() + }) end function core.check_player_privs(player_or_name, ...) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 7255852e0..b6bc957c1 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2242,7 +2242,7 @@ These functions return the leftover itemstack. ### Timing * `minetest.after(time, func, ...)` - * Call the function `func` after `time` seconds + * Call the function `func` after `time` seconds, may be fractional * Optional: Variable number of arguments that are passed to `func` ### Server