Added lazy events (#27091)

* Added lazy events

* remember to compile before changing your code

* Converted on_z_transition and on_post_z_transition to lazy events

* add todo

* fix oops

* fix another oops

* and anotha one

* Moved unit tests to the proper place
This commit is contained in:
DamianX
2020-07-15 22:15:44 +02:00
committed by GitHub
parent 15694ba6e0
commit 1e007a1a3e
12 changed files with 158 additions and 50 deletions

View File

@@ -500,7 +500,7 @@ var/list/variables_not_to_be_copied = list(
"type","loc","locs","vars","parent","parent_type","verbs","ckey","key",
"group","on_login","on_ban","on_unban","on_pipenet_tick","on_item_added",
"on_item_removed","on_moved","on_destroyed","on_density_change",
"on_z_transition","on_use","on_emote","on_life","on_resist","post_z_transition",
"on_use","on_emote","on_life","on_resist",
"on_spellcast","on_uattack","on_ruattack","on_logout","on_damaged",
"on_irradiate","on_death","on_clickon","on_attackhand","on_attackby",
"on_explode","on_projectile","in_chamber","power_supply","contents",

View File

@@ -51,3 +51,92 @@
args["event"] = src
if(call(objRef,procName)(args, holder)) //An intercept value so whatever code section knows we mean business
. = 1
#define EVENT_HANDLER_OBJREF_INDEX 1
#define EVENT_HANDLER_PROCNAME_INDEX 2
/proc/CallAsync(datum/source, proctype, list/arguments)
set waitfor = FALSE
return call(source, proctype)(arglist(arguments))
// Declare children of this type path to use as identifiers for the events.
/lazy_event
// TODO: Document here the arguments that need to be passed to the procs invoked by each event
/lazy_event/on_z_transition
/lazy_event/on_post_z_transition
/datum
/// Associative list of type path -> list(),
/// where the type path is a descendant of /event_type.
/// The inner list is itself an associative list of string -> list(),
/// where string is the \ref of an object + the proc to be called.
/// The list associated with the string above contains the hard-ref
/// to an object and the proc to be called.
var/list/list/registered_events
/**
* Calls all registered event handlers with the specified parameters, if any.
* Arguments:
* * lazy_event/event_type Required. The typepath of the event to invoke.
* * list/arguments Optional. List of parameters to be passed to the event handlers.
*/
/datum/proc/lazy_invoke_event(lazy_event/event_type, list/arguments)
SHOULD_NOT_OVERRIDE(TRUE)
if(!length(registered_events))
// No event at all is registered for this datum.
return
var/list/event_handlers = registered_events[event_type]
if(!length(event_handlers))
// This datum does not have any handler registered for this event_type.
return
. = NONE
for(var/key in event_handlers)
var/list/handler = event_handlers[key]
var/objRef = handler[EVENT_HANDLER_OBJREF_INDEX]
var/procName = handler[EVENT_HANDLER_PROCNAME_INDEX]
. |= CallAsync(objRef, procName, arguments)
/**
* Registers a proc to be called on an object whenever the specified event_type
* is invoked on this datum.
* Arguments:
* * lazy_event/event_type Required. The typepath of the event to register.
* * datum/target Required. The object that the proc will be called on.
* * procname Required. The proc to be called.
*/
/datum/proc/lazy_register_event(lazy_event/event_type, datum/target, procname)
SHOULD_NOT_OVERRIDE(TRUE)
if(!registered_events)
registered_events = list()
if(!registered_events[event_type])
registered_events[event_type] = list()
var/key = "[ref(target)]:[procname]"
registered_events[event_type][key] = list(
EVENT_HANDLER_OBJREF_INDEX = target,
EVENT_HANDLER_PROCNAME_INDEX = procname
)
/**
* Unregisters a proc so that it is no longer called when the specified
* event is invoked.
* Arguments:
* * lazy_event/event_type Required. The typepath of the event to unregister.
* * datum/target Required. The object that's been previously registered.
* * procname Required. The proc of the object.
*/
/datum/proc/lazy_unregister_event(lazy_event/event_type, datum/target, procname)
SHOULD_NOT_OVERRIDE(TRUE)
if(!registered_events)
return
if(!registered_events[event_type])
return
var/key = "[ref(target)]:[procname]"
registered_events[event_type] -= key
if(!registered_events[event_type].len)
registered_events -= event_type
if(!registered_events.len)
registered_events = null
#undef EVENT_HANDLER_OBJREF_INDEX
#undef EVENT_HANDLER_PROCNAME_INDEX

View File

@@ -50,10 +50,11 @@
second.equip_to_slot(cuffs, slot_handcuffed)
first.equip_to_slot(cuffs, slot_handcuffed)
first.z_transition_bringalong_key = first.on_z_transition.Add(first, "z_transition_bringalong")
second.z_transition_bringalong_key = second.on_z_transition.Add(second, "z_transition_bringalong")
first.post_z_transition_bringalong_key = first.post_z_transition.Add(first, "post_z_transition_bringalong")
second.post_z_transition_bringalong_key = second.post_z_transition.Add(second, "post_z_transition_bringalong")
first.lazy_register_event(/lazy_event/on_z_transition, first, /mob/living/carbon/proc/z_transition_bringalong)
second.lazy_register_event(/lazy_event/on_z_transition, second, /mob/living/carbon/proc/z_transition_bringalong)
first.lazy_register_event(/lazy_event/on_post_z_transition, first, /mob/living/carbon/proc/post_z_transition_bringalong)
second.lazy_register_event(/lazy_event/on_post_z_transition, second, /mob/living/carbon/proc/post_z_transition_bringalong)
second.mutual_handcuffed_to_event_key = second.on_moved.Add(first, "on_mutual_cuffed_move")
first.mutual_handcuffed_to_event_key = first.on_moved.Add(second, "on_mutual_cuffed_move")
@@ -77,11 +78,11 @@
C.on_moved.Remove(C.mutual_handcuffed_to_event_key)
handcuffed_to.on_moved.Remove(handcuffed_to.mutual_handcuffed_to_event_key)
C.on_z_transition.Remove(C.z_transition_bringalong_key)
handcuffed_to.on_z_transition.Remove(handcuffed_to.z_transition_bringalong_key)
C.lazy_unregister_event(/lazy_event/on_z_transition, C, /mob/living/carbon/proc/z_transition_bringalong)
handcuffed_to.lazy_unregister_event(/lazy_event/on_z_transition, handcuffed_to, /mob/living/carbon/proc/z_transition_bringalong)
C.post_z_transition.Remove(C.post_z_transition_bringalong_key)
handcuffed_to.post_z_transition.Remove(handcuffed_to.post_z_transition_bringalong_key)
C.lazy_unregister_event(/lazy_event/on_post_z_transition, C, /mob/living/carbon/proc/post_z_transition_bringalong)
handcuffed_to.lazy_unregister_event(/lazy_event/on_post_z_transition, handcuffed_to, /mob/living/carbon/proc/post_z_transition_bringalong)
//reset the mob's vars
handcuffed_to.mutual_handcuffed_to = null
@@ -113,10 +114,8 @@
/mob/living/carbon/proc/z_transition_bringalong(var/mob/user, var/from_z, var/to_z)
if (mutual_handcuffed_to)
// Remove the ability to bring his buddy, since his buddy already brought him here
mutual_handcuffed_to.on_z_transition.Remove(mutual_handcuffed_to.z_transition_bringalong_key)
mutual_handcuffed_to.z_transition_bringalong_key = null
mutual_handcuffed_to.post_z_transition.Remove(mutual_handcuffed_to.post_z_transition_bringalong_key)
mutual_handcuffed_to.post_z_transition_bringalong_key = null
mutual_handcuffed_to.lazy_unregister_event(/lazy_event/on_z_transition, mutual_handcuffed_to, /mob/living/carbon/proc/z_transition_bringalong)
mutual_handcuffed_to.lazy_unregister_event(/lazy_event/on_post_z_transition, mutual_handcuffed_to, /mob/living/carbon/proc/post_z_transition_bringalong)
mutual_handcuffed_to.on_moved.Remove(mutual_handcuffed_to.mutual_handcuffed_to_event_key)
mutual_handcuffed_to_event_key = null
@@ -124,6 +123,6 @@
if (mutual_handcuffed_to)
// Re-adds the events on the fly once the transition is done.
mutual_handcuffed_to.forceMove(get_turf(src))
mutual_handcuffed_to.z_transition_bringalong_key = mutual_handcuffed_to.on_z_transition.Add(mutual_handcuffed_to, "z_transition_bringalong")
mutual_handcuffed_to.post_z_transition_bringalong_key = mutual_handcuffed_to.post_z_transition.Add(mutual_handcuffed_to, "post_z_transition_bringalong")
mutual_handcuffed_to.lazy_register_event(/lazy_event/on_z_transition, mutual_handcuffed_to, /mob/living/carbon/proc/z_transition_bringalong)
mutual_handcuffed_to.lazy_register_event(/lazy_event/on_post_z_transition, mutual_handcuffed_to, /mob/living/carbon/proc/post_z_transition_bringalong)
mutual_handcuffed_to_event_key = mutual_handcuffed_to.on_moved.Add(src, "on_mutual_cuffed_move")

View File

@@ -137,9 +137,9 @@
P.reflected = TRUE//you can now get hit by the projectile you just fired. Careful with portals!
if(curturf.z != destturf.z)
INVOKE_EVENT(teleatom.on_z_transition, list("user" = teleatom, "from_z" = curturf.z, "to_z" = destturf.z))
teleatom.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = teleatom, "from_z" = curturf.z, "to_z" = destturf.z))
for(var/atom/movable/AA in recursive_type_check(teleatom))
INVOKE_EVENT(AA.on_z_transition, list("user" = AA, "from_z" = curturf.z, "to_z" = destturf.z))
AA.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = AA, "from_z" = curturf.z, "to_z" = destturf.z))
if(force_teleport)
teleatom.forceMove(destturf,TRUE)

View File

@@ -333,7 +333,7 @@
destination_port = null
return 0
for(var/atom/movable/AA in linked_area)
INVOKE_EVENT(AA.on_z_transition, list("user" = AA, "to_z" = D.z, "from_z" = linked_port.z))
AA.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = AA, "to_z" = D.z, "from_z" = linked_port.z))
if(transit_port && get_transit_delay())
if(broadcast)

View File

@@ -45,10 +45,6 @@
var/throwpass = 0
var/level = 2
// Change of z-level.
var/event/on_z_transition
var/event/post_z_transition
// When this object moves. (args: loc)
var/event/on_moved
// When the object is qdel'd
@@ -75,8 +71,6 @@
on_destroyed = new("owner"=src)
on_moved = new("owner"=src)
on_z_transition = new("owner"=src)
post_z_transition = new("owner"=src)
/atom/movable/Destroy()
var/turf/T = loc
@@ -87,14 +81,6 @@
qdel(materials)
materials = null
if(on_z_transition)
on_z_transition.holder = null
qdel(on_z_transition)
on_z_transition = null
if(post_z_transition)
post_z_transition.holder = null
qdel(post_z_transition)
post_z_transition = null
if(on_moved)
on_moved.holder = null
on_moved = null
@@ -456,7 +442,7 @@
INVOKE_EVENT(on_moved,list("loc"=loc))
var/turf/T = get_turf(destination)
if(old_loc && T && old_loc.z != T.z)
INVOKE_EVENT(on_z_transition, list("user" = src, "from_z" = old_loc.z, "to_z" = T.z))
lazy_invoke_event(/lazy_event/on_z_transition, list("user" = src, "from_z" = old_loc.z, "to_z" = T.z))
return 1
/atom/movable/proc/update_client_hook(atom/destination)

View File

@@ -200,7 +200,6 @@
var/charges = 0
var/soulbound
var/mindbound
var/z_bound
var/mob/bound_soul
var/datum/mind/bound_mind
@@ -225,8 +224,7 @@
/obj/item/phylactery/Destroy()
if(bound_soul.on_death)
bound_soul.on_death.Remove(soulbound)
bound_soul.on_z_transition.Remove(z_bound)
z_bound = null
bound_soul.lazy_unregister_event(/lazy_event/on_z_transition, src, .proc/z_block)
soulbound = null
if(bound_soul)
to_chat(bound_soul, "<span class = 'warning'><b>You feel your form begin to unwind!</b></span>")
@@ -291,18 +289,17 @@
update_icon()
/obj/item/phylactery/proc/unbind()
if(bound_soul)
bound_soul.lazy_unregister_event(/lazy_event/on_z_transition, src, .proc/z_block)
if(bound_soul.on_death)
bound_soul.on_death.Remove(soulbound)
if(bound_soul.on_z_transition)
bound_soul.on_z_transition.Remove(z_bound)
z_bound = null
soulbound = null
bound_soul = null
update_icon()
/obj/item/phylactery/proc/bind(var/mob/to_bind)
soulbound = to_bind.on_death.Add(src, "revive_soul")
z_bound = to_bind.on_z_transition.Add(src, "z_block")
to_bind.lazy_register_event(/lazy_event/on_z_transition, src, .proc/z_block)
bound_soul = to_bind
/obj/item/phylactery/proc/unbind_mind()

View File

@@ -90,14 +90,14 @@
if(!success)
tempL.Remove(attempt)
else
INVOKE_EVENT(user.on_z_transition, list("user" = user, "to_z" = user.z, "from_z" = prev_z))
user.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = user, "to_z" = user.z, "from_z" = prev_z))
break
if(!success)
user.forceMove(pick(L))
INVOKE_EVENT(user.on_z_transition, list("user" = user, "to_z" = user.z, "from_z" = prev_z))
user.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = user, "to_z" = user.z, "from_z" = prev_z))
smoke.start()
src.uses -= 1
log_game("[key_name(user)] teleported to [thearea.name] using a scroll.")
log_game("[key_name(user)] teleported to [thearea.name] using a scroll.")

View File

@@ -239,9 +239,9 @@
if(!move_to_z)
return
INVOKE_EVENT(A.on_z_transition, list("user" = A, "from_z" = A.z, "to_z" = move_to_z))
A.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = A, "from_z" = A.z, "to_z" = move_to_z))
for(var/atom/movable/AA in contents_brought)
INVOKE_EVENT(AA.on_z_transition, list("user" = AA, "from_z" = AA.z, "to_z" = move_to_z))
AA.lazy_invoke_event(/lazy_event/on_z_transition, list("user" = AA, "from_z" = AA.z, "to_z" = move_to_z))
A.z = move_to_z
if(src.x <= TRANSITIONEDGE)
@@ -271,9 +271,9 @@
var/obj/item/projectile/P = A
P.reset()//fixing linear projectile movement
INVOKE_EVENT(A.post_z_transition, list("user" = A, "from_z" = A.z, "to_z" = move_to_z))
A.lazy_invoke_event(/lazy_event/on_post_z_transition, list("user" = A, "from_z" = A.z, "to_z" = move_to_z))
for(var/atom/movable/AA in contents_brought)
INVOKE_EVENT(AA.post_z_transition, list("user" = AA, "from_z" = AA.z, "to_z" = move_to_z))
AA.lazy_invoke_event(/lazy_event/on_post_z_transition, list("user" = AA, "from_z" = AA.z, "to_z" = move_to_z))
if(A && A.opacity)
has_opaque_atom = TRUE // Make sure to do this before reconsider_lights(), incase we're on instant updates. Guaranteed to be on in this case.

View File

@@ -10,8 +10,6 @@
var/mob/living/carbon/mutual_handcuffed_to = null
var/mutual_handcuffed_to_event_key = null
var/z_transition_bringalong_key = null
var/post_z_transition_bringalong_key = null
var/obj/item/handcuffed = null //Whether or not the mob is handcuffed.
var/obj/item/weapon/handcuffs/mutual_handcuffs = null // whether or not cuffed to somebody else
var/mutual_handcuff_forcemove_time = 0 //last teleport time when user moves ontop of another
@@ -37,4 +35,4 @@
. = ..()
/mob/living/carbon/proc/hasmouth()
return hasmouth
return hasmouth

View File

@@ -7,4 +7,5 @@
#include "slipping.dm"
#include "names.dm"
#include "turretid.dm"
#include "lazy_events.dm"
#endif

View File

@@ -0,0 +1,38 @@
/lazy_event/demo_event
/datum/unit_test
var/did_something = FALSE
/datum/unit_test/lazy_event_does_stuff/start()
var/datum/demo_datum = new
demo_datum.lazy_register_event(/lazy_event/demo_event, src, .proc/do_something)
demo_datum.lazy_invoke_event(/lazy_event/demo_event)
if(!did_something)
fail("lazy event did nothing")
/datum/unit_test/lazy_event_does_stuff/proc/do_something()
did_something = TRUE
/datum/unit_test/lazy_event_cleanup/start()
var/datum/demo_datum = new
if(!isnull(demo_datum.registered_events))
fail("registered_events is not null by default")
demo_datum.lazy_register_event(/lazy_event/demo_event, src, .proc/do_nothing)
assert_eq(demo_datum.registered_events.len, 1)
assert_eq(demo_datum.registered_events[/lazy_event/demo_event].len, 1)
demo_datum.lazy_unregister_event(/lazy_event/demo_event, src, .proc/do_nothing)
if(!isnull(demo_datum.registered_events))
fail("registered_events is not null after removing the last handler")
/datum/unit_test/lazy_event_cleanup/proc/do_nothing()
/datum/unit_test/lazy_event_arguments/start()
var/datum/demo_datum = new
demo_datum.lazy_register_event(/lazy_event/demo_event, src, .proc/do_stuff_with_args)
demo_datum.lazy_invoke_event(/lazy_event/demo_event, list("abc", 123))
demo_datum.lazy_unregister_event(/lazy_event/demo_event, src, .proc/do_stuff_with_args)
demo_datum.lazy_register_event(/lazy_event/demo_event, src, .proc/do_something_with_named_args)
demo_datum.lazy_invoke_event(/lazy_event/demo_event, list("second_parameter"=1))
/datum/unit_test/lazy_event_arguments/proc/do_stuff_with_args(string, number)
assert_eq(string, "abc")
assert_eq(number, 123)
/datum/unit_test/lazy_event_arguments/proc/do_something_with_named_args(first_parameter, second_parameter)
assert_eq(first_parameter, null)
assert_eq(second_parameter, 1)