mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-16 12:43:09 +00:00
When trying to run getFlatIcon using lua scripting, I discovered that it was so expensive that, for certain atoms like complex humans, there is no way it will complete within the lua execution limit. While Mothblocks would suggest just raising the execution limit, the idea leaves a bad taste in my mouth due to the possibility of a script causing extreme lag by consistently overrunning the BYOND tick. I instead elected to make /datum/auxtools_promise sleep once before invoking its assigned proc, thus immediately returning execution to lua, even if the proc being awaited wouldn't sleep. This allows for awaiting extremely expensive non-sleeping procs (like the aforementioned getFlatIcon)
51 lines
1.6 KiB
Plaintext
51 lines
1.6 KiB
Plaintext
#define PROMISE_PENDING 0
|
|
#define PROMISE_RESOLVED 1
|
|
#define PROMISE_REJECTED 2
|
|
|
|
/**
|
|
* Auxtools hooks act as "set waitfor = 0" procs. This means that whenever
|
|
* a proc directly called from auxtools sleeps, the hook returns with whatever
|
|
* the called proc had as its return value at the moment it slept. This may not
|
|
* be desired behavior, so this datum exists to wrap these procs.
|
|
*
|
|
* Some procs that don't sleep could take longer than the execution limit would
|
|
* allow for. We can wrap these in a promise as well.
|
|
*/
|
|
/datum/auxtools_promise
|
|
var/datum/callback/callback
|
|
var/return_value
|
|
var/runtime_message
|
|
var/status = PROMISE_PENDING
|
|
|
|
/datum/auxtools_promise/New(...)
|
|
callback = CALLBACK(arglist(args))
|
|
perform()
|
|
|
|
/datum/auxtools_promise/proc/perform()
|
|
set waitfor = 0
|
|
sleep() //In case we have to call a super-expensive non-sleeping proc (like getFlatIcon)
|
|
try
|
|
return_value = callback.Invoke()
|
|
status = PROMISE_RESOLVED
|
|
catch(var/exception/e)
|
|
runtime_message = e.name
|
|
status = PROMISE_REJECTED
|
|
|
|
#undef PROMISE_PENDING
|
|
#undef PROMISE_RESOLVED
|
|
#undef PROMISE_REJECTED
|
|
|
|
/**
|
|
* When a datum is created from lua, it gets held in `SSlua.gc_guard`, and later,
|
|
* in the calling state datum's `var/list/references`, just in case it would be garbage
|
|
* collected due to there not being any references that BYOND recognizes. To avoid harddels,
|
|
* we register this proc as a signal handler any time a DM function called from lua returns
|
|
* a datum.
|
|
*/
|
|
/datum/proc/lua_reference_cleanup()
|
|
SIGNAL_HANDLER
|
|
if(SSlua.gc_guard == src)
|
|
SSlua.gc_guard = null
|
|
for(var/datum/lua_state/state in SSlua.states)
|
|
state.references -= src
|