Files
Bubberstation/code/datums/movement_detector.dm
SkyratBot e65a48e91f [MIRROR] Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking (#430)
* Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking (#52761)

Adds SIGNAL_HANDLER, a macro that sets SHOULD_NOT_SLEEP(TRUE). This should ideally be required on all new signal callbacks.

Adds BLOCKING_SIGNAL_HANDLER, a macro that does nothing except symbolize "this is an older signal that didn't necessitate a code rewrite". It should not be allowed for new work.

This comes from discussion around #52735, which yields by calling input, and (though it sets the return type beforehand) will not properly return the flag to prevent attack from slapping.

To fix 60% of the yielding cases, WrapAdminProcCall no longer waits for another admin's proc call to finish. I'm not an admin, so I don't know how many behinds this has saved, but if this is problematic for admins I can just make it so that it lets you do it anyway. I'm not sure what the point of this babysitting was anyway.

Requested by @optimumtact.
Changelog

cl
admin: Calling a proc while another admin is calling one will no longer wait for the first to finish. You will simply just have to call it again.
/cl

* Adds SIGNAL_HANDLER and SIGNAL_HANDLER_DOES_SLEEP to prevent signal callbacks from blocking

Co-authored-by: Jared-Fogle <35135081+Jared-Fogle@users.noreply.github.com>
2020-08-19 20:17:28 -04:00

56 lines
1.6 KiB
Plaintext

/// A datum to handle the busywork of registering signals to handle in depth tracking of a movable
/datum/movement_detector
var/atom/movable/tracked
var/datum/callback/listener
/datum/movement_detector/New(atom/movable/target, datum/callback/listener)
if(target)
track(target, listener)
/datum/movement_detector/Destroy()
untrack()
tracked = null
listener = null
return ..()
/// Sets up tracking of the given movable atom
/datum/movement_detector/proc/track(atom/movable/target, datum/callback/listener)
untrack()
tracked = target
src.listener = listener
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react)
target = target.loc
/// Stops tracking
/datum/movement_detector/proc/untrack()
if(!tracked)
return
var/atom/movable/target = tracked
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
/**
* Reacts to any movement that would cause a change in coordinates of the tracked movable atom
* This works by detecting movement of either the tracked object, or anything it is inside, recursively
*/
/datum/movement_detector/proc/move_react(atom/movable/mover, atom/oldloc, direction)
SIGNAL_HANDLER
var/turf/newturf = get_turf(tracked)
if(oldloc && !isturf(oldloc))
var/atom/target = oldloc
while(ismovable(target))
UnregisterSignal(target, COMSIG_MOVABLE_MOVED)
target = target.loc
if(tracked.loc != newturf)
var/atom/target = mover.loc
while(ismovable(target))
RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/move_react, TRUE)
target = target.loc
listener.Invoke(tracked, mover, oldloc, direction)