mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-10 09:42:29 +00:00
Moves lua off of the timer subsystem and onto its own internal scheduler. (#82131)
## About The Pull Request Lua uses the timer subsystem, which can end up holding the entire timer subsystem if lua is creating a lot of timers. The solution to this is to use an internal scheduler instead so that the load gets placed onto the lua subsystem. ## Why It's Good For The Game Performance improvement when using lua scripts. ## Changelog 🆑 refactor: Auxlua no longer uses the timer subsystem to get stuff done, lua scripts shouldn't slow down timers anymore. /🆑 --------- Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
This commit is contained in:
@@ -16,6 +16,7 @@ SUBSYSTEM_DEF(lua)
|
|||||||
var/list/resumes = list()
|
var/list/resumes = list()
|
||||||
|
|
||||||
var/list/current_run = list()
|
var/list/current_run = list()
|
||||||
|
var/list/current_states_run = list()
|
||||||
|
|
||||||
/// Protects return values from getting GCed before getting converted to lua values
|
/// Protects return values from getting GCed before getting converted to lua values
|
||||||
/// Gets cleared every tick.
|
/// Gets cleared every tick.
|
||||||
@@ -97,6 +98,7 @@ SUBSYSTEM_DEF(lua)
|
|||||||
// then resumes every yielded task in the order their resumes were queued
|
// then resumes every yielded task in the order their resumes were queued
|
||||||
if(!resumed)
|
if(!resumed)
|
||||||
current_run = list("sleeps" = sleeps.Copy(), "resumes" = resumes.Copy())
|
current_run = list("sleeps" = sleeps.Copy(), "resumes" = resumes.Copy())
|
||||||
|
current_states_run = states.Copy()
|
||||||
sleeps.Cut()
|
sleeps.Cut()
|
||||||
resumes.Cut()
|
resumes.Cut()
|
||||||
|
|
||||||
@@ -136,6 +138,13 @@ SUBSYSTEM_DEF(lua)
|
|||||||
if(MC_TICK_CHECK)
|
if(MC_TICK_CHECK)
|
||||||
break
|
break
|
||||||
|
|
||||||
|
while(length(current_states_run))
|
||||||
|
var/datum/lua_state/state = current_states_run[current_states_run.len]
|
||||||
|
current_states_run.len--
|
||||||
|
state.process(wait)
|
||||||
|
if(MC_TICK_CHECK)
|
||||||
|
break
|
||||||
|
|
||||||
// Update every lua editor TGUI open for each state that had a task awakened or resumed
|
// Update every lua editor TGUI open for each state that had a task awakened or resumed
|
||||||
for(var/datum/lua_state/state in affected_states)
|
for(var/datum/lua_state/state in affected_states)
|
||||||
INVOKE_ASYNC(state, TYPE_PROC_REF(/datum/lua_state, update_editors))
|
INVOKE_ASYNC(state, TYPE_PROC_REF(/datum/lua_state, update_editors))
|
||||||
|
|||||||
@@ -24,6 +24,12 @@ GLOBAL_PROTECT(lua_usr)
|
|||||||
/// Ckey of the last user who ran a script on this lua state.
|
/// Ckey of the last user who ran a script on this lua state.
|
||||||
var/ckey_last_runner = ""
|
var/ckey_last_runner = ""
|
||||||
|
|
||||||
|
/// Whether the timer.lua script has been included into this lua context state.
|
||||||
|
var/timer_enabled = FALSE
|
||||||
|
|
||||||
|
/// Callbacks that need to be ran on next tick
|
||||||
|
var/list/functions_to_execute = list()
|
||||||
|
|
||||||
/datum/lua_state/vv_edit_var(var_name, var_value)
|
/datum/lua_state/vv_edit_var(var_name, var_value)
|
||||||
. = ..()
|
. = ..()
|
||||||
if(var_name == NAMEOF(src, internal_id))
|
if(var_name == NAMEOF(src, internal_id))
|
||||||
@@ -89,6 +95,13 @@ GLOBAL_PROTECT(lua_usr)
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
/datum/lua_state/process(seconds_per_tick)
|
||||||
|
if(timer_enabled)
|
||||||
|
call_function("__Timer_timer_process", seconds_per_tick)
|
||||||
|
for(var/function as anything in functions_to_execute)
|
||||||
|
call_function(list("__Timer_callbacks", function))
|
||||||
|
functions_to_execute.Cut()
|
||||||
|
|
||||||
/datum/lua_state/proc/call_function(function, ...)
|
/datum/lua_state/proc/call_function(function, ...)
|
||||||
var/call_args = length(args) > 1 ? args.Copy(2) : list()
|
var/call_args = length(args) > 1 ? args.Copy(2) : list()
|
||||||
if(islist(function))
|
if(islist(function))
|
||||||
|
|||||||
253
lua/SS13.lua
253
lua/SS13.lua
@@ -1,249 +1,10 @@
|
|||||||
local SS13 = {}
|
local SS13 = require("SS13_base")
|
||||||
|
local timer = require("timer")
|
||||||
|
|
||||||
__SS13_signal_handlers = __SS13_signal_handlers or {}
|
SS13.wait = timer.wait
|
||||||
__SS13_timeouts = __SS13_timeouts or {}
|
SS13.set_timeout = timer.set_timeout
|
||||||
__SS13_timeouts_id_mapping = __SS13_timeouts_id_mapping or {}
|
SS13.start_loop = timer.start_loop
|
||||||
|
SS13.end_loop = timer.end_loop
|
||||||
SS13.SSlua = dm.global_vars.vars.SSlua
|
SS13.stop_all_loops = timer.stop_all_loops
|
||||||
|
|
||||||
SS13.global_proc = "some_magic_bullshit"
|
|
||||||
|
|
||||||
for _, state in SS13.SSlua.vars.states do
|
|
||||||
if state.vars.internal_id == dm.state_id then
|
|
||||||
SS13.state = state
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.get_runner_ckey()
|
|
||||||
return SS13.state:get_var("ckey_last_runner")
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.get_runner_client()
|
|
||||||
return dm.global_vars:get_var("GLOB"):get_var("directory"):get(SS13.get_runner_ckey())
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.istype(thing, type)
|
|
||||||
return dm.global_proc("_istype", thing, dm.global_proc("_text2path", type)) == 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.new(type, ...)
|
|
||||||
local datum = SS13.new_untracked(type, table.unpack({...}))
|
|
||||||
if datum then
|
|
||||||
local references = SS13.state.vars.references
|
|
||||||
references:add(datum)
|
|
||||||
SS13.state:call_proc("clear_on_delete", datum)
|
|
||||||
return datum
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.type(string_type)
|
|
||||||
return dm.global_proc("_text2path", string_type)
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.qdel(datum)
|
|
||||||
if SS13.is_valid(datum) then
|
|
||||||
dm.global_proc("qdel", datum)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.new_untracked(type, ...)
|
|
||||||
return dm.global_proc("_new", type, { ... })
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.is_valid(datum)
|
|
||||||
if datum and not datum:is_null() and not datum:get_var("gc_destroyed") then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.await(thing_to_call, proc_to_call, ...)
|
|
||||||
if not SS13.istype(thing_to_call, "/datum") then
|
|
||||||
thing_to_call = SS13.global_proc
|
|
||||||
end
|
|
||||||
if thing_to_call == SS13.global_proc then
|
|
||||||
proc_to_call = "/proc/" .. proc_to_call
|
|
||||||
end
|
|
||||||
local promise = SS13.new("/datum/auxtools_promise", thing_to_call, proc_to_call, ...)
|
|
||||||
local promise_vars = promise.vars
|
|
||||||
while promise_vars.status == 0 do
|
|
||||||
sleep()
|
|
||||||
end
|
|
||||||
local return_value, runtime_message = promise_vars.return_value, promise_vars.runtime_message
|
|
||||||
SS13.stop_tracking(promise)
|
|
||||||
return return_value, runtime_message
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.wait(time)
|
|
||||||
local callback = SS13.new("/datum/callback", SS13.SSlua, "queue_resume", SS13.state, __next_yield_index)
|
|
||||||
local timedevent = dm.global_proc("_addtimer", callback, time * 10, 8, nil, debug.info(1, "sl"))
|
|
||||||
coroutine.yield()
|
|
||||||
dm.global_proc("deltimer", timedevent)
|
|
||||||
SS13.stop_tracking(callback)
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.register_signal(datum, signal, func, make_easy_clear_function)
|
|
||||||
if not SS13.istype(datum, "/datum") then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not __SS13_signal_handlers[datum] then
|
|
||||||
__SS13_signal_handlers[datum] = {}
|
|
||||||
end
|
|
||||||
if signal == "_cleanup" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not __SS13_signal_handlers[datum][signal] then
|
|
||||||
__SS13_signal_handlers[datum][signal] = {}
|
|
||||||
end
|
|
||||||
local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first")
|
|
||||||
callback:call_proc("RegisterSignal", datum, signal, "Invoke")
|
|
||||||
local path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), signal, dm.global_proc("WEAKREF", callback), "func" }
|
|
||||||
callback.vars.arguments = { path }
|
|
||||||
if not __SS13_signal_handlers[datum]["_cleanup"] then
|
|
||||||
local cleanup_path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), "_cleanup", "func" }
|
|
||||||
local cleanup_callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first", cleanup_path)
|
|
||||||
cleanup_callback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke")
|
|
||||||
__SS13_signal_handlers[datum]["_cleanup"] = {
|
|
||||||
func = function(datum)
|
|
||||||
SS13.signal_handler_cleanup(datum)
|
|
||||||
SS13.stop_tracking(cleanup_callback)
|
|
||||||
end,
|
|
||||||
callback = cleanup_callback,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
if signal == "parent_qdeleting" then --We want to make sure that the cleanup function is the very last signal handler called.
|
|
||||||
local comp_lookup = datum.vars._listen_lookup
|
|
||||||
if comp_lookup then
|
|
||||||
local lookup_for_signal = comp_lookup.entries.parent_qdeleting
|
|
||||||
if lookup_for_signal and not SS13.istype(lookup_for_signal, "/datum") then
|
|
||||||
local cleanup_callback_index =
|
|
||||||
dm.global_proc("_list_find", lookup_for_signal, __SS13_signal_handlers[datum]["_cleanup"].callback)
|
|
||||||
if cleanup_callback_index ~= 0 and cleanup_callback_index ~= #comp_lookup then
|
|
||||||
dm.global_proc("_list_swap", lookup_for_signal, cleanup_callback_index, #lookup_for_signal)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
__SS13_signal_handlers[datum][signal][callback] = { func = func, callback = callback }
|
|
||||||
if make_easy_clear_function then
|
|
||||||
local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback)
|
|
||||||
SS13[clear_function_name] = function()
|
|
||||||
if callback then
|
|
||||||
SS13.unregister_signal(datum, signal, callback)
|
|
||||||
end
|
|
||||||
SS13[clear_function_name] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return callback
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.stop_tracking(datum)
|
|
||||||
SS13.state:call_proc("let_soft_delete", datum)
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.unregister_signal(datum, signal, callback)
|
|
||||||
local function clear_handler(handler_info)
|
|
||||||
if not handler_info then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not handler_info.callback then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local handler_callback = handler_info.callback
|
|
||||||
handler_callback:call_proc("UnregisterSignal", datum, signal)
|
|
||||||
SS13.stop_tracking(handler_callback)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function clear_easy_clear_function(callback_to_clear)
|
|
||||||
local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback_to_clear)
|
|
||||||
SS13[clear_function_name] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
if not __SS13_signal_handlers[datum] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if signal == "_cleanup" then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not __SS13_signal_handlers[datum][signal] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if not callback then
|
|
||||||
for handler_key, handler_info in __SS13_signal_handlers[datum][signal] do
|
|
||||||
clear_easy_clear_function(handler_key)
|
|
||||||
clear_handler(handler_info)
|
|
||||||
end
|
|
||||||
__SS13_signal_handlers[datum][signal] = nil
|
|
||||||
else
|
|
||||||
if not SS13.istype(callback, "/datum/callback") then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
clear_easy_clear_function(callback)
|
|
||||||
clear_handler(__SS13_signal_handlers[datum][signal][callback])
|
|
||||||
__SS13_signal_handlers[datum][signal][callback] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.signal_handler_cleanup(datum)
|
|
||||||
if not __SS13_signal_handlers[datum] then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
for signal, _ in __SS13_signal_handlers[datum] do
|
|
||||||
SS13.unregister_signal(datum, signal)
|
|
||||||
end
|
|
||||||
|
|
||||||
__SS13_signal_handlers[datum] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.set_timeout(time, func)
|
|
||||||
SS13.start_loop(time, 1, func)
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.start_loop(time, amount, func)
|
|
||||||
if not amount or amount == 0 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local callback = SS13.new("/datum/callback", SS13.state, "call_function")
|
|
||||||
local timedevent = dm.global_proc("_addtimer", callback, time * 10, 40, nil, debug.info(1, "sl"))
|
|
||||||
local doneAmount = 0
|
|
||||||
__SS13_timeouts[callback] = function()
|
|
||||||
doneAmount += 1
|
|
||||||
if amount ~= -1 and doneAmount >= amount then
|
|
||||||
SS13.end_loop(timedevent)
|
|
||||||
end
|
|
||||||
func()
|
|
||||||
end
|
|
||||||
local loop_data = {
|
|
||||||
callback = callback,
|
|
||||||
loop_amount = amount,
|
|
||||||
}
|
|
||||||
__SS13_timeouts_id_mapping[timedevent] = loop_data
|
|
||||||
local path = { "__SS13_timeouts", dm.global_proc("WEAKREF", callback) }
|
|
||||||
callback.vars.arguments = { path }
|
|
||||||
return timedevent
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.end_loop(id)
|
|
||||||
local data = __SS13_timeouts_id_mapping[id]
|
|
||||||
if data then
|
|
||||||
__SS13_timeouts_id_mapping[id] = nil
|
|
||||||
__SS13_timeouts[data.callback] = nil
|
|
||||||
SS13.stop_tracking(data.callback)
|
|
||||||
dm.global_proc("deltimer", id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SS13.stop_all_loops()
|
|
||||||
for id, data in __SS13_timeouts_id_mapping do
|
|
||||||
if data.amount ~= 1 then
|
|
||||||
SS13.end_loop(id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return SS13
|
return SS13
|
||||||
|
|||||||
193
lua/SS13_base.lua
Normal file
193
lua/SS13_base.lua
Normal file
@@ -0,0 +1,193 @@
|
|||||||
|
local SS13 = {}
|
||||||
|
|
||||||
|
__SS13_signal_handlers = __SS13_signal_handlers or {}
|
||||||
|
|
||||||
|
SS13.SSlua = dm.global_vars.vars.SSlua
|
||||||
|
|
||||||
|
SS13.global_proc = "some_magic_bullshit"
|
||||||
|
|
||||||
|
for _, state in SS13.SSlua.vars.states do
|
||||||
|
if state.vars.internal_id == dm.state_id then
|
||||||
|
SS13.state = state
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.get_runner_ckey()
|
||||||
|
return SS13.state:get_var("ckey_last_runner")
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.get_runner_client()
|
||||||
|
return dm.global_vars:get_var("GLOB"):get_var("directory"):get(SS13.get_runner_ckey())
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.istype(thing, type)
|
||||||
|
return dm.global_proc("_istype", thing, dm.global_proc("_text2path", type)) == 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.new(type, ...)
|
||||||
|
local datum = SS13.new_untracked(type, table.unpack({...}))
|
||||||
|
if datum then
|
||||||
|
local references = SS13.state.vars.references
|
||||||
|
references:add(datum)
|
||||||
|
SS13.state:call_proc("clear_on_delete", datum)
|
||||||
|
return datum
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.type(string_type)
|
||||||
|
return dm.global_proc("_text2path", string_type)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.qdel(datum)
|
||||||
|
if SS13.is_valid(datum) then
|
||||||
|
dm.global_proc("qdel", datum)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.new_untracked(type, ...)
|
||||||
|
return dm.global_proc("_new", type, { ... })
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.is_valid(datum)
|
||||||
|
if datum and not datum:is_null() and not datum:get_var("gc_destroyed") then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.await(thing_to_call, proc_to_call, ...)
|
||||||
|
if not SS13.istype(thing_to_call, "/datum") then
|
||||||
|
thing_to_call = SS13.global_proc
|
||||||
|
end
|
||||||
|
if thing_to_call == SS13.global_proc then
|
||||||
|
proc_to_call = "/proc/" .. proc_to_call
|
||||||
|
end
|
||||||
|
local promise = SS13.new("/datum/auxtools_promise", thing_to_call, proc_to_call, ...)
|
||||||
|
local promise_vars = promise.vars
|
||||||
|
while promise_vars.status == 0 do
|
||||||
|
sleep()
|
||||||
|
end
|
||||||
|
local return_value, runtime_message = promise_vars.return_value, promise_vars.runtime_message
|
||||||
|
SS13.stop_tracking(promise)
|
||||||
|
return return_value, runtime_message
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.register_signal(datum, signal, func, make_easy_clear_function)
|
||||||
|
if not SS13.istype(datum, "/datum") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not __SS13_signal_handlers[datum] then
|
||||||
|
__SS13_signal_handlers[datum] = {}
|
||||||
|
end
|
||||||
|
if signal == "_cleanup" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not __SS13_signal_handlers[datum][signal] then
|
||||||
|
__SS13_signal_handlers[datum][signal] = {}
|
||||||
|
end
|
||||||
|
local callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first")
|
||||||
|
callback:call_proc("RegisterSignal", datum, signal, "Invoke")
|
||||||
|
local path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), signal, dm.global_proc("WEAKREF", callback), "func" }
|
||||||
|
callback.vars.arguments = { path }
|
||||||
|
if not __SS13_signal_handlers[datum]["_cleanup"] then
|
||||||
|
local cleanup_path = { "__SS13_signal_handlers", dm.global_proc("WEAKREF", datum), "_cleanup", "func" }
|
||||||
|
local cleanup_callback = SS13.new("/datum/callback", SS13.state, "call_function_return_first", cleanup_path)
|
||||||
|
cleanup_callback:call_proc("RegisterSignal", datum, "parent_qdeleting", "Invoke")
|
||||||
|
__SS13_signal_handlers[datum]["_cleanup"] = {
|
||||||
|
func = function(datum)
|
||||||
|
SS13.signal_handler_cleanup(datum)
|
||||||
|
SS13.stop_tracking(cleanup_callback)
|
||||||
|
end,
|
||||||
|
callback = cleanup_callback,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
if signal == "parent_qdeleting" then --We want to make sure that the cleanup function is the very last signal handler called.
|
||||||
|
local comp_lookup = datum.vars._listen_lookup
|
||||||
|
if comp_lookup then
|
||||||
|
local lookup_for_signal = comp_lookup.entries.parent_qdeleting
|
||||||
|
if lookup_for_signal and not SS13.istype(lookup_for_signal, "/datum") then
|
||||||
|
local cleanup_callback_index =
|
||||||
|
dm.global_proc("_list_find", lookup_for_signal, __SS13_signal_handlers[datum]["_cleanup"].callback)
|
||||||
|
if cleanup_callback_index ~= 0 and cleanup_callback_index ~= #comp_lookup then
|
||||||
|
dm.global_proc("_list_swap", lookup_for_signal, cleanup_callback_index, #lookup_for_signal)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
__SS13_signal_handlers[datum][signal][callback] = { func = func, callback = callback }
|
||||||
|
if make_easy_clear_function then
|
||||||
|
local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback)
|
||||||
|
SS13[clear_function_name] = function()
|
||||||
|
if callback then
|
||||||
|
SS13.unregister_signal(datum, signal, callback)
|
||||||
|
end
|
||||||
|
SS13[clear_function_name] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return callback
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.stop_tracking(datum)
|
||||||
|
SS13.state:call_proc("let_soft_delete", datum)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.unregister_signal(datum, signal, callback)
|
||||||
|
local function clear_handler(handler_info)
|
||||||
|
if not handler_info then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not handler_info.callback then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local handler_callback = handler_info.callback
|
||||||
|
handler_callback:call_proc("UnregisterSignal", datum, signal)
|
||||||
|
SS13.stop_tracking(handler_callback)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function clear_easy_clear_function(callback_to_clear)
|
||||||
|
local clear_function_name = "clear_signal_" .. tostring(datum) .. "_" .. signal .. "_" .. tostring(callback_to_clear)
|
||||||
|
SS13[clear_function_name] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
if not __SS13_signal_handlers[datum] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if signal == "_cleanup" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not __SS13_signal_handlers[datum][signal] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not callback then
|
||||||
|
for handler_key, handler_info in __SS13_signal_handlers[datum][signal] do
|
||||||
|
clear_easy_clear_function(handler_key)
|
||||||
|
clear_handler(handler_info)
|
||||||
|
end
|
||||||
|
__SS13_signal_handlers[datum][signal] = nil
|
||||||
|
else
|
||||||
|
if not SS13.istype(callback, "/datum/callback") then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
clear_easy_clear_function(callback)
|
||||||
|
clear_handler(__SS13_signal_handlers[datum][signal][callback])
|
||||||
|
__SS13_signal_handlers[datum][signal][callback] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SS13.signal_handler_cleanup(datum)
|
||||||
|
if not __SS13_signal_handlers[datum] then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
for signal, _ in __SS13_signal_handlers[datum] do
|
||||||
|
SS13.unregister_signal(datum, signal)
|
||||||
|
end
|
||||||
|
|
||||||
|
__SS13_signal_handlers[datum] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return SS13
|
||||||
106
lua/timer.lua
Normal file
106
lua/timer.lua
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
local SS13 = require("SS13_base")
|
||||||
|
local Timer = {}
|
||||||
|
|
||||||
|
__Timer_timers = __Timer_timers or {}
|
||||||
|
__Timer_callbacks = __Timer_callbacks or {}
|
||||||
|
|
||||||
|
function __add_internal_timer(func, time, loop)
|
||||||
|
local timer = {
|
||||||
|
loop = loop,
|
||||||
|
executeTime = time + dm.world:get_var("time")
|
||||||
|
}
|
||||||
|
__Timer_callbacks[tostring(func)] = function()
|
||||||
|
timer.executing = false
|
||||||
|
if loop and timer.terminate ~= true then
|
||||||
|
timer.executeTime = dm.world:get_var("time") + time
|
||||||
|
else
|
||||||
|
__stop_internal_timer(tostring(func))
|
||||||
|
end
|
||||||
|
func()
|
||||||
|
end
|
||||||
|
__Timer_timers[tostring(func)] = timer
|
||||||
|
return tostring(func)
|
||||||
|
end
|
||||||
|
|
||||||
|
function __stop_internal_timer(func)
|
||||||
|
local timer = __Timer_timers[func]
|
||||||
|
if timer and not timer.executing then
|
||||||
|
__Timer_timers[func] = nil
|
||||||
|
__Timer_callbacks[func] = nil
|
||||||
|
else
|
||||||
|
timer.terminate = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
__Timer_timer_processing = __Timer_timer_processing or false
|
||||||
|
SS13.state:set_var("timer_enabled", 1)
|
||||||
|
__Timer_timer_process = function(seconds_per_tick)
|
||||||
|
if __Timer_timer_processing then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
__Timer_timer_processing = true
|
||||||
|
local time = dm.world:get_var("time")
|
||||||
|
for func, timeData in __Timer_timers do
|
||||||
|
if timeData.executing == true then
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
if over_exec_usage(0.85) then
|
||||||
|
sleep()
|
||||||
|
end
|
||||||
|
if time >= timeData.executeTime then
|
||||||
|
SS13.state:get_var("functions_to_execute"):add(func)
|
||||||
|
timeData.executing = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
__Timer_timer_processing = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function Timer.wait(time)
|
||||||
|
local next_yield_index = __next_yield_index
|
||||||
|
__add_internal_timer(function()
|
||||||
|
SS13.SSlua:call_proc("queue_resume", SS13.state, next_yield_index)
|
||||||
|
end, time * 10, false)
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Timer.set_timeout(time, func)
|
||||||
|
Timer.start_loop(time, 1, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Timer.start_loop(time, amount, func)
|
||||||
|
if not amount or amount == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if amount == -1 then
|
||||||
|
return __add_internal_timer(func, time * 10, true)
|
||||||
|
end
|
||||||
|
if amount == 1 then
|
||||||
|
return __add_internal_timer(func, time * 10, false)
|
||||||
|
end
|
||||||
|
local callback = SS13.new("/datum/callback", SS13.state, "call_function")
|
||||||
|
local timedevent = dm.global_proc("_addtimer", callback, time * 10, 40, nil, debug.info(1, "sl"))
|
||||||
|
local doneAmount = 0
|
||||||
|
local newFunc = function()
|
||||||
|
func()
|
||||||
|
doneAmount += 1
|
||||||
|
if doneAmount >= amount then
|
||||||
|
Timer.end_loop(timedevent)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
__add_internal_timer(newFunc, time * 10, true)
|
||||||
|
return newFunc
|
||||||
|
end
|
||||||
|
|
||||||
|
function Timer.end_loop(id)
|
||||||
|
__stop_internal_timer(id)
|
||||||
|
end
|
||||||
|
|
||||||
|
function Timer.stop_all_loops()
|
||||||
|
for id, data in __Timer_timers do
|
||||||
|
if data.loop then
|
||||||
|
Timer.end_loop(id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return Timer
|
||||||
Reference in New Issue
Block a user