diff --git a/baystation12.dme b/baystation12.dme index a9e966322aa..e1f2323fd9a 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -214,6 +214,7 @@ #include "code\datums\server_greeting.dm" #include "code\datums\statistic.dm" #include "code\datums\supplypacks.dm" +#include "code\datums\weakref.dm" #include "code\datums\diseases\appendicitis.dm" #include "code\datums\diseases\beesease.dm" #include "code\datums\diseases\brainrot.dm" diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm index 90cdae5a88e..3df56854d04 100644 --- a/code/__defines/misc.dm +++ b/code/__defines/misc.dm @@ -336,6 +336,14 @@ Will print: "/mob/living/carbon/human/death" (you can optionally embed it in a s // as text so you don't necessarily fuck with an object's ability to be garbage collected. #define SOFTREF(A) "\ref[A]" +// A slightly stronger version of the above that does type validation for you. +#if DM_VERSION >= 511 +// This only works on 511 because it relies on 511's `var/something = foo = bar` syntax. +#define WEAKREF(D) (istype(D, /datum) && !D:gcDestroyed ? (D:weakref ? D:weakref : (D:weakref = new(D))) : null) +#else +#define WEAKREF(D) _weakref(D) +#endif + #define ADD_VERB_IN(the_atom,time,verb) addtimer(CALLBACK(the_atom, /atom/.proc/add_verb, verb), time, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_NO_HASH_WAIT) #define ADD_VERB_IN_IF(the_atom,time,verb,callback) addtimer(CALLBACK(the_atom, /atom/.proc/add_verb, verb, callback), time, TIMER_UNIQUE | TIMER_OVERRIDE | TIMER_NO_HASH_WAIT) diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index b43970d500a..ee9f93ee9df 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -227,6 +227,7 @@ var/datum/controller/subsystem/garbage_collector/SSgarbage // This should be overridden to remove all references pointing to the object being destroyed. // Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE. /datum/proc/Destroy(force=FALSE) + weakref = null destroyed_event.raise_event(src) SSnanoui.close_uis(src) tag = null diff --git a/code/datums/weakref.dm b/code/datums/weakref.dm new file mode 100644 index 00000000000..5562ae25b5c --- /dev/null +++ b/code/datums/weakref.dm @@ -0,0 +1,31 @@ +/datum + var/datum/weakref/weakref + +/datum/weakref + var/ref + + +#if DM_VERSION < 511 +// Don't use this directly, use the WEAKREF macro. +/proc/_weakref(datum/D) + if(!istype(D) || QDELETED(D)) + return + if(!D.weakref) + D.weakref = new(D) + return D.weakref +#endif + +/datum/weakref/New(datum/D) + ref = SOFTREF(D) + +/datum/weakref/Destroy(force = 0) + crash_with("Some fuck is trying to [force ? "force-" : ""]delete a weakref!") + if (!force) + return QDEL_HINT_LETMELIVE // feck off + + return ..() + +/datum/weakref/proc/resolve() + var/datum/D = locate(ref) + if (!QDELETED(D) && D.weakref == src) + . = D