Adds reference tracking (#51467)

About The Pull Request

Adds extools-powered reference tracking. Includes a couple procs that retrieve the back and forward references of a datum - Back references let you see what is referencing your object and potentially preventing it from garbage collecting, and forward ones show you what your object in turn references. Also made a cool GUI to inspect and follow these references.

The tracking adds some overhead to all variable sets and list operations. Init time is increased by ~15%. I haven't actually benched it so it might impact the actual game less.
Why It's Good For The Game

no lagging caused by hard dels scanning the entire planet (once coders fix them)
This commit is contained in:
MCHSL
2020-06-25 11:26:59 +12:00
committed by GitHub
parent ea39b87c4c
commit 331365b422
10 changed files with 58 additions and 1 deletions
+1
View File
@@ -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)
@@ -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 += "<h1>References of \ref[D] - [D]</h1><br><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(D)]'>\[Refresh\]</a><hr>"
dat += "<h3>Back references - these things hold references to this object.</h3>"
dat += "<table>"
dat += "<tr><th>Ref</th><th>Type</th><th>Variable Name</th><th>Follow</th>"
for(var/ref in backrefs)
var/datum/R = ref
dat += "<tr><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(R)]'>[REF(R)]</td><td>[R.type]</td><td>[backrefs[R]]</td><td><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(R)]'>\[Follow\]</a></td></tr>"
dat += "</table><hr>"
dat += "<h3>Forward references - this object is referencing those things.</h3>"
dat += "<table>"
dat += "<tr><th>Variable name</th><th>Ref</th><th>Type</th><th>Follow</th>"
for(var/ref in frontrefs)
var/datum/R = frontrefs[ref]
dat += "<tr><td>[ref]</td><td><a href='?_src_=vars;[HrefToken()];Vars=[REF(R)]'>[REF(R)]</a></td><td>[R.type]</td><td><a href='?_src_=vars;[HrefToken()];[VV_HK_VIEW_REFERENCES]=TRUE;[VV_HK_TARGET]=[REF(R)]'>\[Follow\]</a></td></tr>"
dat += "</table><hr>"
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
@@ -77,3 +77,5 @@
message_admins("<span class='notice'>[key_name_admin(usr)] has added [result] [datumname] to [key_name_admin(src)].</span>")
if(href_list[VV_HK_CALLPROC])
usr.client.callproc_datum(target)
if(href_list[VV_HK_VIEW_REFERENCES])
usr.client.view_refs(target)
@@ -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))