From e1c1aa06b0b89e9dc283a55152c2579a8f9ee63c Mon Sep 17 00:00:00 2001
From: Penelope Haze <out.of.p.haze@proton.me>
Date: Sun, 5 Jan 2025 18:05:54 -0500
Subject: [PATCH] Enable reftracking in CI

---
 code/__defines/_compile_options.dm     | 13 +++++++++++++
 code/__defines/qdel.dm                 |  4 ++--
 code/controllers/subsystems/garbage.dm | 27 ++++++++++++++------------
 code/datums/datum.dm                   |  2 +-
 4 files changed, 31 insertions(+), 15 deletions(-)

diff --git a/code/__defines/_compile_options.dm b/code/__defines/_compile_options.dm
index d2f61e13dca..0c60ba0a5dd 100644
--- a/code/__defines/_compile_options.dm
+++ b/code/__defines/_compile_options.dm
@@ -1,3 +1,16 @@
 // 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.
 // 1 will enable set background. 0 will disable set background.
 #define BACKGROUND_ENABLED 0
+
+// If REFTRACK_IN_CI is defined, the reftracker will run in CI.
+#define REFTRACK_IN_CI
+#if defined(REFTRACK_IN_CI) && defined(UNIT_TEST) && !defined(SPACEMAN_DMM)
+#define REFTRACKING_ENABLED
+#define GC_FAILURE_HARD_LOOKUP
+#define FIND_REF_NO_CHECK_TICK
+#endif
+
+// parity with previous behavior where TESTING enabled reftracking
+#ifdef TESTING
+#define REFTRACKING_ENABLED
+#endif
\ No newline at end of file
diff --git a/code/__defines/qdel.dm b/code/__defines/qdel.dm
index 2c81f12ad7d..fa9cf0a8deb 100644
--- a/code/__defines/qdel.dm
+++ b/code/__defines/qdel.dm
@@ -5,8 +5,8 @@
 #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		3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference.
 #define QDEL_HINT_HARDDEL_NOW	4 //qdel should assume this object won't gc, and hard del it post haste.
-#define QDEL_HINT_FINDREFERENCE	5 //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.
+#define QDEL_HINT_FINDREFERENCE	5 //functionally identical to QDEL_HINT_QUEUE if REFTRACKING_ENABLED is not enabled in _compiler_options.dm.
+								  //if REFTRACKING_ENABLED is enabled, qdel will call this object's find_references() verb.
 #define QDEL_HINT_IFFAIL_FINDREFERENCE 6		//Above but only if gc fails.
 //defines for the gc_destroyed var
 
diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index c27fcb3238e..d44e5410646 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -37,7 +37,7 @@ SUBSYSTEM_DEF(garbage)
 	//Queue
 	var/list/queues
 
-	#ifdef TESTING
+	#ifdef REFTRACKING_ENABLED
 	var/list/reference_find_on_fail = list()
 	#endif
 
@@ -155,7 +155,7 @@ SUBSYSTEM_DEF(garbage)
 			++gcedlasttick
 			++totalgcs
 			pass_counts[level]++
-			#ifdef TESTING
+			#ifdef REFTRACKING_ENABLED
 			reference_find_on_fail -= ref(D) //It's deleted we don't care anymore.
 			#endif
 			if (MC_TICK_CHECK)
@@ -167,10 +167,11 @@ SUBSYSTEM_DEF(garbage)
 
 		switch (level)
 			if (GC_QUEUE_CHECK)
-				#ifdef TESTING
+				#ifdef REFTRACKING_ENABLED
 				// Decides how many refs to look for (potentially)
 				// Based off the remaining and the ones we can account for
 				var/remaining_refs = refcount(D) - REFS_WE_EXPECT
+				var/refID = ref(D)
 				if(reference_find_on_fail[refID])
 					D.find_references(remaining_refs)
 				#ifdef GC_FAILURE_HARD_LOOKUP
@@ -279,7 +280,7 @@ SUBSYSTEM_DEF(garbage)
 /datum/qdel_item/New(mytype)
 	name = "[mytype]"
 
-#ifdef TESTING
+#ifdef REFTRACKING_ENABLED
 /proc/qdel_and_find_ref_if_fail(datum/D, force = FALSE)
 	SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
 	qdel(D, force)
@@ -337,7 +338,7 @@ SUBSYSTEM_DEF(garbage)
 					return
 				// Returning LETMELIVE after being told to force destroy
 				// indicates the objects Destroy() does not respect force
-				#ifdef TESTING
+				#ifdef REFTRACKING_ENABLED
 				if(!I.no_respect_force)
 					PRINT_STACK_TRACE("WARNING: [D.type] has been force deleted, but is \
 						returning an immortal QDEL_HINT, indicating it does \
@@ -353,18 +354,19 @@ SUBSYSTEM_DEF(garbage)
 				SSgarbage.HardQueue(D)
 			if (QDEL_HINT_HARDDEL_NOW)	//qdel should assume this object won't gc, and hard del it post haste.
 				SSgarbage.HardDelete(D)
-			if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
+			if (QDEL_HINT_FINDREFERENCE)//qdel will, if REFTRACKING_ENABLED is enabled, display all references to this object, then queue the object for deletion.
 				SSgarbage.Queue(D)
-				#ifdef TESTING
-				D.find_references()
+				#ifdef REFTRACKING_ENABLED
+				var/remaining_refs = refcount(D) - REFS_WE_EXPECT
+				D.find_references(remaining_refs)
 				#endif
 			if (QDEL_HINT_IFFAIL_FINDREFERENCE)
 				SSgarbage.Queue(D)
-				#ifdef TESTING
+				#ifdef REFTRACKING_ENABLED
 				SSgarbage.reference_find_on_fail["\ref[D]"] = TRUE
 				#endif
 			else
-				#ifdef TESTING
+				#ifdef REFTRACKING_ENABLED
 				if(!I.no_hint)
 					PRINT_STACK_TRACE("WARNING: [D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
 				#endif
@@ -373,7 +375,7 @@ SUBSYSTEM_DEF(garbage)
 	else if(D.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
 		CRASH("[D.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic")
 
-#ifdef TESTING
+#ifdef REFTRACKING_ENABLED
 
 /datum/verb/find_refs()
 	set category = "Debug"
@@ -389,6 +391,7 @@ SUBSYSTEM_DEF(garbage)
 
 /datum/proc/find_references(references_to_clear = INFINITY)
 	running_find_references = type
+	src.references_to_clear = references_to_clear
 	if(usr && usr.client)
 		if(usr.client.running_find_references)
 			testing("CANCELLED search for references to a [usr.client.running_find_references].")
@@ -529,7 +532,7 @@ SUBSYSTEM_DEF(garbage)
 				var/ignore_ref = FALSE
 				var/list/queues = SSgarbage.queues
 				for(var/list/queue in queues)
-					if(potential_cache in queue)
+					if(X in queue)
 						ignore_ref = TRUE
 						break
 				if(ignore_ref)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index 61780203703..aa855c0b1e3 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -10,7 +10,7 @@
 	/// Used to avoid unnecessary refstring creation in Destroy().
 	var/tmp/has_state_machine = FALSE
 
-#ifdef TESTING
+#ifdef REFTRACKING_ENABLED
 	var/tmp/running_find_references
 	/// When was this datum last touched by a reftracker?
 	/// If this value doesn't match with the start of the search