bunch of misc fixes (#17031)

* bunch of misc fixes

* .

* more refs also new ref tracking from chomp

* oups

* eh
This commit is contained in:
Kashargul
2025-02-05 13:53:53 -05:00
committed by GitHub
parent 59a6e06ab5
commit af85f098cd
14 changed files with 243 additions and 15 deletions
+4 -4
View File
@@ -71,28 +71,28 @@
return 1
/obj/machinery/atmospherics/pipe/return_air()
if(!parent)
if(!QDELETED(src) || !parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.air
/obj/machinery/atmospherics/pipe/build_network()
if(!parent)
if(!QDELETED(src) || !parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.return_network()
/obj/machinery/atmospherics/pipe/network_expand(datum/pipe_network/new_network, obj/machinery/atmospherics/pipe/reference)
if(!parent)
if(!QDELETED(src) || !parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
return parent.network_expand(new_network, reference)
/obj/machinery/atmospherics/pipe/return_network(obj/machinery/atmospherics/reference)
if(!parent)
if(!QDELETED(src) || !parent)
parent = new /datum/pipeline()
parent.build_pipeline(src)
+5
View File
@@ -39,6 +39,11 @@
///Used for doing dry runs of the reference finder, to test for feature completeness
//#define REFERENCE_TRACKING_DEBUG
#ifdef FIND_REF_NO_CHECK_TICK
/world
loop_checks = FALSE
#endif
///Run a lookup on things hard deleting by default.
//#define GC_FAILURE_HARD_LOOKUP
#ifdef GC_FAILURE_HARD_LOOKUP
-2
View File
@@ -221,8 +221,6 @@
/proc/get_mobs_in_radio_ranges(var/list/obj/item/radio/radios)
set background = 1
. = list()
// Returns a list of mobs who can hear any of the radios given in @radios
var/list/speaker_coverage = list()
+2 -2
View File
@@ -105,7 +105,7 @@ SUBSYSTEM_DEF(machines)
while(current_run.len)
var/datum/pipe_network/PN = current_run[current_run.len]
current_run.len--
if(!PN)
if(!PN || QDELETED(PN))
networks.Remove(PN)
DISABLE_BITFIELD(PN?.datum_flags, DF_ISPROCESSING)
else
@@ -122,7 +122,7 @@ SUBSYSTEM_DEF(machines)
while(current_run.len)
var/obj/machinery/M = current_run[current_run.len]
current_run.len--
if(!M || (M.process(wait) == PROCESS_KILL))
if(!istype(M) || QDELETED(M) || (M.process(wait) == PROCESS_KILL))
processing_machines.Remove(M)
DISABLE_BITFIELD(M?.datum_flags, DF_ISPROCESSING)
if(MC_TICK_CHECK)
+2 -1
View File
@@ -139,7 +139,8 @@ SUBSYSTEM_DEF(plants)
return
/datum/controller/subsystem/plants/proc/add_plant(var/obj/effect/plant/plant)
processing |= plant
if(!QDELETED(plant))
processing |= plant
/datum/controller/subsystem/plants/proc/remove_plant(var/obj/effect/plant/plant)
processing -= plant
+212
View File
@@ -0,0 +1,212 @@
// Drop in replacement for reference tracking
#ifdef REFERENCE_TRACKING
#define REFSEARCH_RECURSE_LIMIT 64
/datum
var/references_to_clear
/datum/proc/find_references(references_to_clear = INFINITY)
if(usr?.client)
if(tgui_alert(usr,"Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", list("Yes", "No")) != "Yes")
return
src.references_to_clear = references_to_clear
//this keeps the garbage collector from failing to collect objects being searched for in here
SSgarbage.can_fire = FALSE
_search_references()
//restart the garbage collector
SSgarbage.can_fire = TRUE
SSgarbage.next_fire = world.time + world.tick_lag
//SSgarbage.update_nextfire(reset_time = TRUE)
/datum/proc/_search_references()
log_reftracker("Beginning search for references to a [type], looking for [references_to_clear] refs.")
var/starting_time = world.time
//Time to search the whole game for our ref
DoSearchVar(GLOB, "GLOB", starting_time) //globals
log_reftracker("Finished searching globals")
if(src.references_to_clear == 0)
return
//Yes we do actually need to do this. The searcher refuses to read weird lists
//And global.vars is a really weird list
var/global_vars = list()
for(var/key in global.vars)
global_vars[key] = global.vars[key]
DoSearchVar(global_vars, "Native Global", starting_time)
log_reftracker("Finished searching native globals")
if(src.references_to_clear == 0)
return
for(var/datum/thing in world) //atoms (don't beleive its lies)
DoSearchVar(thing, "World -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching atoms")
if(src.references_to_clear == 0)
return
for(var/datum/thing) //datums
DoSearchVar(thing, "Datums -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching datums")
if(src.references_to_clear == 0)
return
//Warning, attempting to search clients like this will cause crashes if done on live. Watch yourself
#ifndef REFERENCE_DOING_IT_LIVE
for(var/client/thing) //clients
DoSearchVar(thing, "Clients -> [thing.type]", starting_time)
if(src.references_to_clear == 0)
break
log_reftracker("Finished searching clients")
if(src.references_to_clear == 0)
return
#endif
log_reftracker("Completed search for references to a [type].")
/datum/proc/DoSearchVar(potential_container, container_name, search_time, recursion_count, is_special_list)
if(recursion_count >= REFSEARCH_RECURSE_LIMIT)
log_reftracker("Recursion limit reached. [container_name]")
return
if(references_to_clear == 0)
return
//Check each time you go down a layer. This makes it a bit slow, but it won't effect the rest of the game at all
#ifndef FIND_REF_NO_CHECK_TICK
CHECK_TICK
#endif
if(isdatum(potential_container))
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
var/is_atom = FALSE
var/is_area = FALSE
if(isatom(datum_container))
is_atom = TRUE
if(isarea(datum_container))
is_area = TRUE
for(var/varname in vars_list)
var/variable = vars_list[varname]
if(islist(variable))
//Fun fact, vis_locs don't count for references
if(varname == "vars" || (is_atom && (varname == "vis_locs" || varname == "overlays" || varname == "underlays" || varname == "filters" || varname == "verbs" || (is_area && varname == "contents"))))
continue
// We do this after the varname check to avoid area contents (reading it incures a world loop's worth of cost)
if(!length(variable))
continue
DoSearchVar(variable,\
"[container_name] [datum_container.ref_search_details()] -> [varname] (list)",\
search_time,\
recursion_count + 1,\
/*is_special_list = */ is_atom && (varname == "contents" || varname == "vis_contents" || varname == "locs"))
else if(variable == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[varname] = TRUE
continue //End early, don't want these logging
else
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
#else
log_reftracker("Found [type] [text_ref(src)] in [datum_container.type]'s [datum_container.ref_search_details()] [varname] var. [container_name]")
#endif
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
continue
else if(islist(potential_container))
var/list/potential_cache = potential_container
for(var/element_in_list in potential_cache)
//Check normal sublists
if(islist(element_in_list))
if(length(element_in_list))
DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", search_time, recursion_count + 1)
//Check normal entrys
else if(element_in_list == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[potential_cache] = TRUE
continue
else
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
#else
log_reftracker("Found [type] [text_ref(src)] in list [container_name].")
#endif
// This is dumb as hell I'm sorry
// I don't want the garbage subsystem to count as a ref for the purposes of this number
// If we find all other refs before it I want to early exit, and if we don't I want to keep searching past it
var/ignore_ref = FALSE
var/list/queues = SSgarbage.queues
for(var/list/queue in queues)
if(potential_cache in queue)
ignore_ref = TRUE
break
if(ignore_ref)
log_reftracker("[container_name] does not count as a ref for our count")
else
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
if(!isnum(element_in_list) && !is_special_list)
// This exists to catch an error that throws when we access a special list
// is_special_list is a hint, it can be wrong
try
var/assoc_val = potential_cache[element_in_list]
//Check assoc sublists
if(islist(assoc_val))
if(length(assoc_val))
DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", search_time, recursion_count + 1)
//Check assoc entry
else if(assoc_val == src)
#ifdef REFERENCE_TRACKING_DEBUG
if(SSgarbage.should_save_refs)
if(!found_refs)
found_refs = list()
found_refs[potential_cache] = TRUE
continue
else
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
#else
log_reftracker("Found [type] [text_ref(src)] in list [container_name]\[[element_in_list]\]")
#endif
references_to_clear -= 1
if(references_to_clear == 0)
log_reftracker("All references to [type] [text_ref(src)] found, exiting.")
return
catch
// So if it goes wrong we kill it
is_special_list = TRUE
log_reftracker("Curiosity: [container_name] lead to an error when acessing [element_in_list], what is it?")
#undef REFSEARCH_RECURSE_LIMIT
#endif
// Kept outside the ifdef so overrides are easy to implement
/// Return info about us for reference searching purposes
/// Will be logged as a representation of this datum if it's a part of a search chain
/datum/proc/ref_search_details()
return text_ref(src)
/datum/callback/ref_search_details()
return "[text_ref(src)] (obj: [object] proc: [delegate] args: [json_encode(arguments)] user: [user?.resolve() || "null"])"
+11
View File
@@ -43,6 +43,7 @@
render_target = ref(src)
em_block = new(src, render_target)
add_overlay(list(em_block), TRUE)
RegisterSignal(em_block, COMSIG_PARENT_QDELETING, PROC_REF(emblocker_gc))
if(opacity)
AddElement(/datum/element/light_blocking)
if(icon_scale_x != DEFAULT_ICON_SCALE_X || icon_scale_y != DEFAULT_ICON_SCALE_Y || icon_rotation != DEFAULT_ICON_ROTATION)
@@ -56,6 +57,10 @@
AddComponent(/datum/component/overlay_lighting, is_directional = TRUE, starts_on = light_on)
/atom/movable/Destroy()
if(em_block)
cut_overlay(em_block)
UnregisterSignal(em_block, COMSIG_PARENT_QDELETING)
QDEL_NULL(em_block)
. = ..()
for(var/atom/movable/AM in contents)
qdel(AM)
@@ -640,3 +645,9 @@
/atom/movable/proc/get_cell()
return
/atom/movable/proc/emblocker_gc(var/datum/source)
UnregisterSignal(source, COMSIG_PARENT_QDELETING)
cut_overlay(source)
if(em_block == source)
em_block = null
@@ -14,7 +14,7 @@
var/max_mob_buckle_size = MOB_LARGE
/obj/structure/bed/chair/wheelchair/Initialize(var/newloc, var/new_material, var/new_padding_material)
..()
. = ..()
update_icon()
/obj/structure/bed/chair/wheelchair/motor
+1 -1
View File
@@ -189,7 +189,7 @@
/datum/ai_holder/proc/walk_to_target()
ai_log("walk_to_target() : Entering.", AI_LOG_DEBUG)
// Make sure we can still chase/attack them.
if(!target || !can_attack(target))
if(QDELETED(target) || !can_attack(target))
ai_log("walk_to_target() : Lost target.", AI_LOG_INFO)
lose_target()
return
@@ -205,7 +205,6 @@
density = FALSE
/obj/effect/plant/proc/calc_dir()
set background = 1
var/turf/T = get_turf(src)
if(!istype(T)) return
@@ -2,7 +2,6 @@
/mob/living/carbon/alien/Life()
set invisibility = 0
set background = 1
if (transforming) return
if(!loc) return
@@ -1,6 +1,5 @@
/mob/living/silicon/robot/Life()
set invisibility = 0
set background = 1
if (transforming)
return
+4
View File
@@ -42,3 +42,7 @@
entopic_users -= my_mob
if(my_mob.client)
my_mob.client.images -= entopic_images
/mob/Destroy()
. = ..()
entopic_users -= src
+1 -1
View File
@@ -128,7 +128,7 @@
var/style = pick(styles)
icon_state = style
item_state = style
..()
. = ..()
/obj/item/cracker/shrinking
name = "shrinking bluespace cracker"