Expands the SS13.lua module by adding loop helpers and functions to get the script runner. (#79081)

## About The Pull Request
`SS13.get_runner_client()` and `SS13.get_runner_ckey` will return the
client and the ckey respectively of the user who ran the lua script. Can
be unreliable after the first sleep or yield.
The SS13 module can now be made local as the tables that need to be
accessed globally have been moved to their own global variables.
Added `SS13.start_loop(time, amount, func)`, `SS13.end_loop(id)`,
`SS13.stop_all_loops()` that allow lua scripts to more easily make
loops. Removed the `timer` parameter from these functions, which
specified the timer subsystem to use.
Documentation on all new added functions have been added in the
lua/README.md

## Why It's Good For The Game
Getting the client who ran the script and the ckey that ran the script
is useful for self contained scripts that are looking for an entrypoint
(e.g. location to spawn some item/mob/structure). `dm.usr` is a special
variable used for other purposes and can be unreliable when used this
way even if there haven't been any sleeps or yields yet, so having a
dedicated variable and function to handle it makes things easier.

Being able to make the SS13 module local allows for more self-contained
scripts. Although this isn't super helpful because `require` will still
load the same object for all lua scripts loaded on the same state.

Basic looping helpers allow for lua scripts to more easily create loops
without needing to recursively do a `set_timeout` or to do a
`while(true) do SS13.wait(1) end` loop.

## Changelog
🆑
admin: Added SS13.get_runner_ckey() and SS13.get_runner_client() which
stores the ckey and returns the client of the user who ran the lua
script. Can be unreliable if accessed after sleeping.
admin: Added timer loop helpers to the SS13.lua module, check the docs
admin: The SS13.lua module can now be made local without causing any
errors.
/🆑

---------

Co-authored-by: Watermelon914 <3052169-Watermelon914@users.noreply.gitlab.com>
This commit is contained in:
Watermelon914
2023-10-20 13:55:58 -04:00
committed by GitHub
co-authored by Watermelon914
parent 5d41bcfbf9
commit ec41393b31
4 changed files with 119 additions and 41 deletions
+73 -41
View File
@@ -1,5 +1,9 @@
local SS13 = {}
__SS13_signal_handlers = __SS13_signal_handlers or {}
__SS13_timeouts = __SS13_timeouts or {}
__SS13_timeouts_id_mapping = __SS13_timeouts_id_mapping or {}
SS13.SSlua = dm.global_vars.vars.SSlua
SS13.global_proc = "some_magic_bullshit"
@@ -11,6 +15,14 @@ for _, state in SS13.SSlua.vars.states do
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
@@ -65,39 +77,36 @@ function SS13.await(thing_to_call, proc_to_call, ...)
return return_value, runtime_message
end
function SS13.wait(time, timer)
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, timer, debug.info(1, "sl"))
local timedevent = dm.global_proc("_addtimer", callback, time * 10, 8, nil, debug.info(1, "sl"))
coroutine.yield()
dm.global_proc("deltimer", timedevent, timer)
dm.global_proc("deltimer", timedevent)
SS13.stop_tracking(callback)
end
function SS13.register_signal(datum, signal, func, make_easy_clear_function)
if not SS13.signal_handlers then
SS13.signal_handlers = {}
end
if not SS13.istype(datum, "/datum") then
return
end
if not SS13.signal_handlers[datum] then
SS13.signal_handlers[datum] = {}
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] = {}
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" }
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" }
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"] = {
__SS13_signal_handlers[datum]["_cleanup"] = {
func = function(datum)
SS13.signal_handler_cleanup(datum)
SS13.stop_tracking(cleanup_callback)
@@ -111,14 +120,14 @@ function SS13.register_signal(datum, signal, func, make_easy_clear_function)
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)
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 }
__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()
@@ -148,70 +157,93 @@ function SS13.unregister_signal(datum, signal, callback)
SS13.stop_tracking(handler_callback)
end
if not SS13.signal_handlers then
return
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
if not __SS13_signal_handlers[datum] then
return
end
if signal == "_cleanup" then
return
end
if not SS13.signal_handlers[datum][signal] then
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
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
__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
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 then
return
end
if not SS13.signal_handlers[datum] then
if not __SS13_signal_handlers[datum] then
return
end
for signal, _ in SS13.signal_handlers[datum] do
for signal, _ in __SS13_signal_handlers[datum] do
SS13.unregister_signal(datum, signal)
end
SS13.signal_handlers[datum] = nil
__SS13_signal_handlers[datum] = nil
end
function SS13.set_timeout(time, func, timer)
if not SS13.timeouts then
SS13.timeouts = {}
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, 8, timer, debug.info(1, "sl"))
SS13.timeouts[callback] = function()
SS13.timeouts[callback] = nil
dm.global_proc("deltimer", timedevent, timer)
SS13.stop_tracking(callback)
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 path = { "SS13", "timeouts", dm.global_proc("WEAKREF", callback) }
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