diff --git a/byond-extools.dll b/byond-extools.dll
index 8eb4497fef0..0588171ca5c 100644
Binary files a/byond-extools.dll and b/byond-extools.dll differ
diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm
index 956106c7ec1..430d5dd230f 100644
--- a/code/__DEFINES/vv.dm
+++ b/code/__DEFINES/vv.dm
@@ -75,6 +75,7 @@
#define VV_HK_MARK "mark"
#define VV_HK_ADDCOMPONENT "addcomponent"
#define VV_HK_MODIFY_TRAITS "modtraits"
+#define VV_HK_VIEW_REFERENCES "viewreferences"
// /atom
#define VV_HK_MODIFY_TRANSFORM "atom_transform"
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index da359fe4947..01ec8b22244 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -16,10 +16,12 @@
//#define FIND_REF_NO_CHECK_TICK //Sets world.loop_checks to false and prevents find references from sleeping
-
//#define VISUALIZE_ACTIVE_TURFS //Highlights atmos active turfs in green
#endif
+//#define REFERENCE_TRACKING //Enables extools-powered reference tracking system, letting you see what is
+ //referencing objects that refuse to hard delete
+
//#define UNIT_TESTS //Enables unit tests via TEST_RUN_PARAMETER
#ifndef PRELOAD_RSC //set to:
diff --git a/code/datums/datumvars.dm b/code/datums/datumvars.dm
index 4b887f3eb43..4477573106c 100644
--- a/code/datums/datumvars.dm
+++ b/code/datums/datumvars.dm
@@ -31,6 +31,7 @@
VV_DROPDOWN_OPTION(VV_HK_EXPOSE, "Show VV To Player")
VV_DROPDOWN_OPTION(VV_HK_ADDCOMPONENT, "Add Component/Element")
VV_DROPDOWN_OPTION(VV_HK_MODIFY_TRAITS, "Modify Traits")
+ VV_DROPDOWN_OPTION(VV_HK_VIEW_REFERENCES, "View References")
//This proc is only called if everything topic-wise is verified. The only verifications that should happen here is things like permission checks!
//href_list is a reference, modifying it in these procs WILL change the rest of the proc in topic.dm of admin/view_variables!
diff --git a/code/game/world.dm b/code/game/world.dm
index 7b212040412..af835bbc92c 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -23,6 +23,9 @@ GLOBAL_VAR(restart_counter)
if (fexists(extools))
call(extools, "maptick_initialize")()
enable_debugger()
+#ifdef REFERENCE_TRACKING
+ enable_reference_tracking()
+#endif
//Early profile for auto-profiler - will be stopped on profiler init if necessary.
#if DM_BUILD >= 1506
diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm
index a285fa1e941..0f5c96a444f 100644
--- a/code/modules/admin/admin_verbs.dm
+++ b/code/modules/admin/admin_verbs.dm
@@ -170,6 +170,7 @@ GLOBAL_PROTECT(admin_verbs_debug)
/client/proc/test_cardpack_distribution,
/client/proc/print_cards,
/datum/admins/proc/create_or_modify_area,
+ /client/proc/view_refs
)
GLOBAL_LIST_INIT(admin_verbs_possess, list(/proc/possess, /proc/release))
GLOBAL_PROTECT(admin_verbs_possess)
diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm
new file mode 100644
index 00000000000..e35afa901a9
--- /dev/null
+++ b/code/modules/admin/view_variables/reference_tracking.dm
@@ -0,0 +1,45 @@
+/world/proc/enable_reference_tracking()
+ var/extools = world.GetConfig("env", "EXTOOLS_DLL") || (world.system_type == MS_WINDOWS ? "./byond-extools.dll" : "./libbyond-extools.so")
+ if (fexists(extools))
+ call(extools, "ref_tracking_initialize")()
+
+/proc/get_back_references(datum/D)
+ CRASH("/proc/get_back_references not hooked by extools, reference tracking will not function!")
+
+/proc/get_forward_references(datum/D)
+ CRASH("/proc/get_forward_references not hooked by extools, reference tracking will not function!")
+
+/proc/clear_references(datum/D)
+ return
+
+/client/proc/view_refs(atom/D) //it actually supports datums as well but byond no likey
+ set category = "Debug"
+ set name = "View References"
+
+ if(!check_rights(R_DEBUG))
+ return
+
+ var/list/backrefs = get_back_references(D)
+ if(isnull(backrefs))
+ usr << browse("Reference tracking not enabled", "window=ref_view")
+ return
+ var/list/frontrefs = get_forward_references(D)
+ var/list/dat = list()
+ dat += "
References of \ref[D] - [D]
\[Refresh\]
"
+ dat += "Back references - these things hold references to this object.
"
+ dat += ""
+ dat += "| Ref | Type | Variable Name | Follow | "
+ for(var/ref in backrefs)
+ var/datum/R = ref
+ dat += "
|---|
| [REF(R)] | [R.type] | [backrefs[R]] | \[Follow\] |
"
+ dat += "
"
+ dat += "Forward references - this object is referencing those things.
"
+ dat += ""
+ dat += "| Variable name | Ref | Type | Follow | "
+ for(var/ref in frontrefs)
+ var/datum/R = frontrefs[ref]
+ dat += "
|---|
| [ref] | [REF(R)] | [R.type] | \[Follow\] |
"
+ dat += "
"
+ dat = dat.Join()
+
+ usr << browse(dat, "window=ref_view") //Done this way rather than tgui to facilitate porting to other codebases or even byond games
diff --git a/code/modules/admin/view_variables/topic_basic.dm b/code/modules/admin/view_variables/topic_basic.dm
index 0e27f46f832..6e3f2bd1a01 100644
--- a/code/modules/admin/view_variables/topic_basic.dm
+++ b/code/modules/admin/view_variables/topic_basic.dm
@@ -77,3 +77,5 @@
message_admins("[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(src)].")
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)
+ if(href_list[VV_HK_VIEW_REFERENCES])
+ usr.client.view_refs(target)
diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm
index 472ee5271d4..62d9ff62fb9 100644
--- a/code/modules/admin/view_variables/view_variables.dm
+++ b/code/modules/admin/view_variables/view_variables.dm
@@ -59,6 +59,7 @@
"Set len" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SET_LENGTH),
"Shuffle" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_LIST_SHUFFLE),
"Show VV To Player" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_EXPOSE),
+ "View References" = VV_HREF_TARGETREF_INTERNAL(refid, VV_HK_VIEW_REFERENCES),
"---"
)
for(var/i in 1 to length(dropdownoptions))
diff --git a/tgstation.dme b/tgstation.dme
index e2cec0e435c..ef9ba7e40fa 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1355,6 +1355,7 @@
#include "code\modules\admin\view_variables\mark_datum.dm"
#include "code\modules\admin\view_variables\mass_edit_variables.dm"
#include "code\modules\admin\view_variables\modify_variables.dm"
+#include "code\modules\admin\view_variables\reference_tracking.dm"
#include "code\modules\admin\view_variables\topic.dm"
#include "code\modules\admin\view_variables\topic_basic.dm"
#include "code\modules\admin\view_variables\topic_list.dm"