diff --git a/code/__DEFINES/qdel.dm b/code/__DEFINES/qdel.dm index 9e4917802c8..3042ff6d302 100644 --- a/code/__DEFINES/qdel.dm +++ b/code/__DEFINES/qdel.dm @@ -4,4 +4,6 @@ #define QDEL_HINT_LETMELIVE 1 //qdel should let the object live after calling destory. #define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it. #define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste. -#define QDEL_HINT_PUTINPOOL 5 //qdel will put this object in the atom pool. \ No newline at end of file +#define QDEL_HINT_PUTINPOOL 5 //qdel will put this object in the atom pool. +#define QDEL_HINT_FINDREFERENCE 6 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm. + //if TESTING is enabled, qdel will call this object's find_references() verb. \ No newline at end of file diff --git a/code/_compile_options.dm b/code/_compile_options.dm index a2bf32f53c7..31ef57a65ff 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -1,10 +1,11 @@ #define DEBUG +#define TESTING #define IS_MODE_COMPILED(MODE) (ispath(text2path("/datum/game_mode/"+(MODE)))) #define BACKGROUND_ENABLED 0 // The default value for all uses of set background. Set background can cause gradual lag and is recommended you only turn this on if necessary. - //Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam +//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam #define MAX_MESSAGE_LEN 1024 #define MAX_PAPER_MESSAGE_LEN 3072 #define MAX_BOOK_MESSAGE_LEN 9216 diff --git a/code/modules/garbage collection/garbage_collector.dm b/code/modules/garbage collection/garbage_collector.dm index 4ae68bf9952..836138c0220 100644 --- a/code/modules/garbage collection/garbage_collector.dm +++ b/code/modules/garbage collection/garbage_collector.dm @@ -136,6 +136,11 @@ var/global/datum/controller/process/garbage_collector/garbageCollector garbageCollector.dels_count++ if (QDEL_HINT_PUTINPOOL) //qdel will put this object in the pool. PlaceInPool(D,0) + if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion. + #ifdef TESTING + D.find_references(remove_from_queue = FALSE) + #endif + garbageCollector.addTrash(D) else // world << "WARNING GC DID NOT GET A RETURN VALUE FOR [D], [D.type]!" garbageCollector.addTrash(D) @@ -176,3 +181,72 @@ var/global/datum/controller/process/garbage_collector/garbageCollector /proc/gcwarning(msg) log_to_dd("## GC WARNING: [msg]") + +#ifdef TESTING +/client/var/running_find_references +/datum/var/running_find_references + +/datum/verb/find_references(remove_from_queue = TRUE as num) + set category = "Debug" + set name = "Find References" + set background = 1 + set src in world + + running_find_references = type + if(usr && usr.client) + if(usr.client.running_find_references) + testing("CANCELLED search for references to a [usr.client.running_find_references].") + usr.client.running_find_references = null + running_find_references = null + return + + if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No") + running_find_references = null + return + // Remove this object from the list of things to be auto-deleted. + if(remove_from_queue && garbageCollector && ("\ref[src]" in garbageCollector.queue)) + garbageCollector.queue -= "\ref[src]" + if(usr && usr.client) + usr.client.running_find_references = type + + testing("Beginning search for references to a [type].") + var/list/things = list() + for(var/client/thing) + things |= thing + for(var/datum/thing) + things |= thing + testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)") + for(var/datum/thing in things) + if(usr && usr.client && !usr.client.running_find_references) return + for(var/varname in thing.vars) + var/variable = thing.vars[varname] + if(variable == src) + testing("Found [src.type] \ref[src] in [thing.type]'s [varname] var.") + else if(islist(variable)) + if(src in variable) + testing("Found [src.type] \ref[src] in [thing.type]'s [varname] list var.") + testing("Completed search for references to a [type].") + if(usr && usr.client) + usr.client.running_find_references = null + running_find_references = null + +/client/verb/purge_all_destroyed_objects() + set category = "Debug" + if(garbageCollector) + while(garbageCollector.queue.len) + var/datum/o = locate(garbageCollector.queue[1]) + if(istype(o) && o.gcDestroyed) + del(o) + garbageCollector.dels_count++ + garbageCollector.queue.Cut(1, 2) + +/datum/verb/qdel_then_find_references() + set category = "Debug" + set name = "qdel() then Find References" + set background = 1 + set src in world + + qdel(src) + if(!running_find_references) + find_references(remove_from_queue = FALSE) +#endif