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 18:55:58 +01:00
committed by GitHub
parent 5d41bcfbf9
commit ec41393b31
4 changed files with 119 additions and 41 deletions
+42
View File
@@ -138,6 +138,12 @@ The `SS13` package contains various helper functions that use code specific to t
### SS13.state
A reference to the state datum (`/datum/lua_state`) handling this Lua state.
### SS13.get_runner_ckey()
The ckey of the user who ran the lua script in the current context. Can be unreliable if accessed after sleeping.
### SS13.get_runner_client()
Returns the client of the user who ran the lua script in the current context. Can be unreliable if accessed after sleeping.
### SS13.global_proc
A wrapper for the magic string used to tell `WrapAdminProcCall` to call a global proc.
For instance, `/datum/callback` must be instantiated with `SS13.global_proc` as its first argument to specify that it will be invoking a global proc.
@@ -224,6 +230,42 @@ SS13.set_timeout(5, function()
end)
```
### SS13.start_loop(time, amount, func)
Creates a timer which will execute `func` after `time` **seconds**. `func` should not expect to be passed any arguments, as it will not be passed any. Works exactly the same as `SS13.set_timeout` except it will loop the timer `amount` times. If `amount` is set to -1, it will loop indefinitely. Returns a number value, which represents the timer's id. Can be stopped with `SS13.end_loop`
Returns a number, the timer id, which is needed to stop indefinite timers.
The following example will output a message to chat every 5 seconds, repeating 10 times:
```lua
SS13.start_loop(5, 10, function()
dm.global_proc("to_chat", dm.world, "Hello World!")
end)
```
The following example will output a message to chat every 5 seconds, until `SS13.end_loop(timerid)` is called:
```lua
local timerid = SS13.start_loop(5, -1, function()
dm.global_proc("to_chat", dm.world, "Hello World!")
end)
```
### SS13.end_loop(id)
Prematurely ends a loop that hasn't ended yet, created with `SS13.start_loop`. Silently fails if there is no started loop with the specified id.
The following example will output a message to chat every 5 seconds and delete it after it has repeated 20 times:
```lua
local repeated_amount = 0
-- timerid won't be in the looping function's scope if declared before the function is declared.
local timerid
timerid = SS13.start_loop(5, -1, function()
dm.global_proc("to_chat", dm.world, "Hello World!")
repeated_amount += 1
if repeated_amount >= 20 then
SS13.end_loop(timerid)
end
end)
```
### SS13.stop_all_loops()
Stops all current running loops that haven't ended yet.
Useful in case you accidentally left a indefinite loop running without storing the id anywhere.
### SS13.stop_tracking(datum)
Stops tracking a datum that was created via `SS13.new` so that it can be garbage collected and deleted without having to qdel. Should be used for things like callbacks and other such datums where the reference to the variable is no longer needed.
@@ -126,6 +126,7 @@
return TRUE
if("runCode")
var/code = params["code"]
current_state.ckey_last_runner = usr.ckey
var/result = current_state.load_script(code)
var/index_with_result = current_state.log_result(result)
message_admins("[key_name(usr)] executed [length(code)] bytes of lua code. [ADMIN_LUAVIEW_CHUNK(current_state, index_with_result)]")
@@ -21,6 +21,9 @@ GLOBAL_PROTECT(lua_usr)
/// A list in which to store datums and lists instantiated in lua, ensuring that they don't get garbage collected
var/list/references = list()
/// Ckey of the last user who ran a script on this lua state.
var/ckey_last_runner = ""
/datum/lua_state/vv_edit_var(var_name, var_value)
. = ..()
if(var_name == NAMEOF(src, internal_id))