mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-30 11:32:20 +00:00
* Ref Tracking: Revengance (#57728) * Ref Tracking: Revengance Fixes reference tracking ignoring self references due to a poorly thought out tick checking system. Fixes reference tracking ignoring the contents of assoc lists Makes the reference tracking printouts actually describe what list the ref is in, rather then just saying "list" Adds REFERENCE_TRACKING_DEBUG, a define which toggles tracking info for the ref tracking procs, which allows for oversight on how the proc is working Allows for direct calls of qdel_and_find_ref_if_fail(), makes it use ref rather then REF(), fixing it breaking for mobs. (Ditto for the qdel hint which does the same thing) Moves REAGENTS_TESTING out of the reftracking define block Makes unit tests define REFERENCE_TRACKING, REFERENCE_TRACKING_DEBUG, and FIND_REF_NO_CHECK_TICK Adds a unit test that sanity checks the reference finder proc * Ref Tracking: Revengance Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
148 lines
4.6 KiB
Plaintext
148 lines
4.6 KiB
Plaintext
#ifdef REFERENCE_TRACKING
|
|
|
|
/datum/verb/find_refs()
|
|
set category = "Debug"
|
|
set name = "Find References"
|
|
set src in world
|
|
|
|
find_references(FALSE)
|
|
|
|
|
|
/datum/proc/find_references(skip_alert)
|
|
running_find_references = type
|
|
if(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
|
|
//restart the garbage collector
|
|
SSgarbage.can_fire = TRUE
|
|
SSgarbage.next_fire = world.time + world.tick_lag
|
|
return
|
|
|
|
if(!skip_alert && alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") != "Yes")
|
|
running_find_references = null
|
|
return
|
|
|
|
//this keeps the garbage collector from failing to collect objects being searched for in here
|
|
SSgarbage.can_fire = FALSE
|
|
|
|
if(usr?.client)
|
|
usr.client.running_find_references = type
|
|
|
|
testing("Beginning search for references to a [type].")
|
|
|
|
var/starting_time = world.time
|
|
|
|
DoSearchVar(GLOB, "GLOB") //globals
|
|
for(var/datum/thing in world) //atoms (don't beleive its lies)
|
|
DoSearchVar(thing, "World -> [thing.type]", search_time = starting_time)
|
|
|
|
for(var/datum/thing) //datums
|
|
DoSearchVar(thing, "Datums -> [thing.type]", search_time = starting_time)
|
|
|
|
for(var/client/thing) //clients
|
|
DoSearchVar(thing, "Clients -> [thing.type]", search_time = starting_time)
|
|
|
|
testing("Completed search for references to a [type].")
|
|
if(usr?.client)
|
|
usr.client.running_find_references = null
|
|
running_find_references = null
|
|
|
|
//restart the garbage collector
|
|
SSgarbage.can_fire = TRUE
|
|
SSgarbage.next_fire = world.time + world.tick_lag
|
|
|
|
|
|
/datum/verb/qdel_then_find_references()
|
|
set category = "Debug"
|
|
set name = "qdel() then Find References"
|
|
set src in world
|
|
|
|
qdel(src, TRUE) //force a qdel
|
|
if(!running_find_references)
|
|
find_references(TRUE)
|
|
|
|
|
|
/datum/verb/qdel_then_if_fail_find_references()
|
|
set category = "Debug"
|
|
set name = "qdel() then Find References if GC failure"
|
|
set src in world
|
|
|
|
qdel_and_find_ref_if_fail(src, TRUE)
|
|
|
|
|
|
/datum/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64, search_time = world.time)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
if(!found_refs)
|
|
found_refs = list()
|
|
#endif
|
|
|
|
if(usr?.client && !usr.client.running_find_references)
|
|
return
|
|
|
|
if(!recursive_limit)
|
|
testing("Recursion limit reached. [container_name]")
|
|
return
|
|
|
|
if(istype(potential_container, /datum))
|
|
var/datum/datum_container = potential_container
|
|
if(datum_container.last_find_references == search_time)
|
|
return
|
|
|
|
datum_container.last_find_references = search_time
|
|
var/list/vars_list = datum_container.vars
|
|
|
|
for(var/varname in vars_list)
|
|
if (varname == "vars" || varname == "vis_locs") //Fun fact, vis_locs don't count for references
|
|
continue
|
|
var/variable = vars_list[varname]
|
|
|
|
if(variable == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
found_refs[varname] = TRUE
|
|
#endif
|
|
testing("Found [type] \ref[src] in [datum_container.type]'s \ref[datum_container] [varname] var. [container_name]")
|
|
|
|
else if(islist(variable))
|
|
DoSearchVar(variable, "[container_name] \ref[datum_container] -> [varname] (list)", recursive_limit - 1, search_time)
|
|
|
|
else if(islist(potential_container))
|
|
var/normal = IS_NORMAL_LIST(potential_container)
|
|
for(var/element_in_list in potential_container)
|
|
//Check normal entrys
|
|
if(element_in_list == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
found_refs[potential_container] = TRUE
|
|
#endif
|
|
testing("Found [type] \ref[src] in list [container_name].")
|
|
|
|
//Check assoc entrys
|
|
else if(element_in_list && !isnum(element_in_list) && normal && potential_container[element_in_list] == src)
|
|
#ifdef REFERENCE_TRACKING_DEBUG
|
|
found_refs[potential_container] = TRUE
|
|
#endif
|
|
testing("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]")
|
|
|
|
//Check normal sublists
|
|
else if(islist(element_in_list))
|
|
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", recursive_limit - 1, search_time)
|
|
|
|
//Check assoc sublists
|
|
else if(element_in_list && !isnum(element_in_list) && normal && islist(potential_container[element_in_list]))
|
|
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [potential_container[element_in_list]] (list)", recursive_limit - 1, search_time)
|
|
|
|
#ifndef FIND_REF_NO_CHECK_TICK
|
|
CHECK_TICK
|
|
#endif
|
|
|
|
|
|
/proc/qdel_and_find_ref_if_fail(datum/thing_to_del, force = FALSE)
|
|
thing_to_del.qdel_and_find_ref_if_fail(force)
|
|
|
|
/datum/proc/qdel_and_find_ref_if_fail(force = FALSE)
|
|
SSgarbage.reference_find_on_fail["\ref[src]"] = TRUE
|
|
qdel(src, force)
|
|
|
|
#endif
|