From 76159e1f1a6bc1d3532ef1f401e390b78e7d4083 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 22:56:32 +0200 Subject: [PATCH 01/43] 56171 --- code/controllers/subsystem/garbage.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index d524bf29803..c005bc80d68 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -330,6 +330,11 @@ SUBSYSTEM_DEF(garbage) /// /// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. /proc/qdel(datum/D, force=FALSE) + if(isweakref(D)) + var/datum/weakref/weakref = D + D = weakref.resolve() + if(!D) + return if(!istype(D)) del(D) return From 73ab364994f7edc48f646547205fe91f1b95bc14 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 22:58:29 +0200 Subject: [PATCH 02/43] 70729 --- code/__HELPERS/icons.dm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 57404802845..bb03061fef9 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -988,7 +988,7 @@ ColorTone(rgb, tone) if(isicon(icon) && isfile(icon)) //icons compiled in from 'icons/path/to/dmi_file.dmi' at compile time are weird and arent really /icon objects, ///but they pass both isicon() and isfile() checks. theyre the easiest case since stringifying them gives us the path we want - var/icon_ref = "\ref[icon]" + var/icon_ref = text_ref(icon) var/locate_icon_string = "[locate(icon_ref)]" icon_path = locate_icon_string @@ -999,7 +999,7 @@ ColorTone(rgb, tone) // the rsc reference returned by fcopy_rsc() will be stringifiable to "icons/path/to/dmi_file.dmi" var/rsc_ref = fcopy_rsc(icon) - var/icon_ref = "\ref[rsc_ref]" + var/icon_ref = text_ref(rsc_ref) var/icon_path_string = "[locate(icon_ref)]" @@ -1009,7 +1009,7 @@ ColorTone(rgb, tone) var/rsc_ref = fcopy_rsc(icon) //if its the text path of an existing dmi file, the rsc reference returned by fcopy_rsc() will be stringifiable to a dmi path - var/rsc_ref_ref = "\ref[rsc_ref]" + var/rsc_ref_ref = text_ref(rsc_ref) var/rsc_ref_string = "[locate(rsc_ref_ref)]" icon_path = rsc_ref_string From a2288983d9bf9fcbc7b0aafa95a436370f6e627d Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 23:11:31 +0200 Subject: [PATCH 03/43] revert 56171 as it's already coded in --- code/controllers/subsystem/garbage.dm | 5 ----- 1 file changed, 5 deletions(-) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index c005bc80d68..d524bf29803 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -330,11 +330,6 @@ SUBSYSTEM_DEF(garbage) /// /// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. /proc/qdel(datum/D, force=FALSE) - if(isweakref(D)) - var/datum/weakref/weakref = D - D = weakref.resolve() - if(!D) - return if(!istype(D)) del(D) return From 9d45f544757435d11f548d8a4754ab4c531b0ff6 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 23:14:43 +0200 Subject: [PATCH 04/43] 79568 early returns and cleaning --- code/controllers/subsystem/garbage.dm | 126 +++++++++++++------------- 1 file changed, 64 insertions(+), 62 deletions(-) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index d524bf29803..05f8cca6526 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -325,75 +325,77 @@ SUBSYSTEM_DEF(garbage) /datum/qdel_item/New(mytype) name = "[mytype]" - /// Should be treated as a replacement for the 'del' keyword. /// /// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. -/proc/qdel(datum/D, force=FALSE) - if(!istype(D)) - del(D) +/proc/qdel(datum/to_delete, force = FALSE) + if(!istype(to_delete)) + del(to_delete) return - var/datum/qdel_item/I = SSgarbage.items[D.type] - if (!I) - I = SSgarbage.items[D.type] = new /datum/qdel_item(D.type) - I.qdels++ + var/datum/qdel_item/trash = SSgarbage.items[to_delete.type] + if(!trash) + trash = SSgarbage.items[to_delete.type] = new /datum/qdel_item(to_delete.type) + trash.qdels++ - if(isnull(D.gc_destroyed)) - if (SEND_SIGNAL(D, COMSIG_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted - return - D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED - var/start_time = world.time - var/start_tick = world.tick_usage - SEND_SIGNAL(D, COMSIG_QDELETING, force) // Let the (remaining) components know about the result of Destroy - var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up. - if(world.time != start_time) - I.slept_destroy++ - else - I.destroy_time += TICK_USAGE_TO_MS(start_tick) - if(!D) + if(!isnull(to_delete.gc_destroyed)) + if(to_delete.gc_destroyed == GC_CURRENTLY_BEING_QDELETED) + CRASH("[to_delete.type] destroy proc was called multiple times, likely due to a qdel loop in the Destroy logic") + return + + if(SEND_SIGNAL(to_delete, COMSIG_PREQDELETED, force)) // Give the components a chance to prevent their parent from being deleted + return + + to_delete.gc_destroyed = GC_CURRENTLY_BEING_QDELETED + var/start_time = world.time + var/start_tick = world.tick_usage + SEND_SIGNAL(to_delete, COMSIG_QDELETING, force) // Let the (remaining) components know about the result of Destroy + var/hint = to_delete.Destroy(force) // Let our friend know they're about to get fucked up. + if(world.time != start_time) + trash.slept_destroy++ + else + trash.destroy_time += TICK_USAGE_TO_MS(start_tick) + if(isnull(to_delete)) + return + switch(hint) + if(QDEL_HINT_QUEUE) //qdel should queue the object for deletion. + SSgarbage.Queue(to_delete) + if(QDEL_HINT_IWILLGC) + to_delete.gc_destroyed = world.time return - switch(hint) - if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion. - SSgarbage.Queue(D) - if (QDEL_HINT_IWILLGC) - D.gc_destroyed = world.time + if(QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. + if(!force) + to_delete.gc_destroyed = null //clear the gc variable (important!) return - if (QDEL_HINT_LETMELIVE) //qdel should let the object live after calling destory. - if(!force) - D.gc_destroyed = null //clear the gc variable (important!) - return - // Returning LETMELIVE after being told to force destroy - // indicates the objects Destroy() does not respect force - #ifdef TESTING - if(!I.no_respect_force) - testing("WARNING: [D.type] has been force deleted, but is \ - returning an immortal QDEL_HINT, indicating it does \ - not respect the force flag for qdel(). It has been \ - placed in the queue, further instances of this type \ - will also be queued.") - #endif - I.no_respect_force++ + // Returning LETMELIVE after being told to force destroy + // indicates the objects Destroy() does not respect force + #ifdef TESTING + if(!trash.no_respect_force) + testing("WARNING: [to_delete.type] has been force deleted, but is \ + returning an immortal QDEL_HINT, indicating it does \ + not respect the force flag for qdel(). It has been \ + placed in the queue, further instances of this type \ + will also be queued.") + #endif + trash.no_respect_force++ - SSgarbage.Queue(D) - if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete - SSgarbage.Queue(D, GC_QUEUE_HARDDELETE) - if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. - SSgarbage.HardDelete(D) - #ifdef REFERENCE_TRACKING - if (QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. - SSgarbage.Queue(D) - D.find_references() //This breaks ci. Consider it insurance against somehow pring reftracking on accident - if (QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. - SSgarbage.Queue(D) - SSgarbage.reference_find_on_fail[text_ref(D)] = TRUE + SSgarbage.Queue(to_delete) + if(QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete + SSgarbage.Queue(to_delete, GC_QUEUE_HARDDELETE) + if(QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste. + SSgarbage.HardDelete(to_delete) + #ifdef REFERENCE_TRACKING + if(QDEL_HINT_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled, display all references to this object, then queue the object for deletion. + SSgarbage.Queue(to_delete) + to_delete.find_references() //This breaks ci. Consider it insurance against somehow pring reftracking on accident + if(QDEL_HINT_IFFAIL_FINDREFERENCE) //qdel will, if REFERENCE_TRACKING is enabled and the object fails to collect, display all references to this object. + SSgarbage.Queue(to_delete) + SSgarbage.reference_find_on_fail[text_ref(to_delete)] = TRUE + #endif + else + #ifdef TESTING + if(!trash.no_hint) + testing("WARNING: [to_delete.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.") #endif - else - #ifdef TESTING - if(!I.no_hint) - testing("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 - I.no_hint++ - SSgarbage.Queue(D) - 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") + trash.no_hint++ + SSgarbage.Queue(to_delete) From 1359280de24a778c7074c0b59498dac942df6300 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 23:40:39 +0200 Subject: [PATCH 05/43] 79134 partly --- code/__DEFINES/rust_g.dm | 5 ----- code/controllers/subsystem/garbage.dm | 21 ++++++++------------- code/game/objects/objs.dm | 2 ++ code/modules/mob/mob.dm | 1 + code/modules/tgs/v3210/api.dm | 4 ---- 5 files changed, 11 insertions(+), 22 deletions(-) diff --git a/code/__DEFINES/rust_g.dm b/code/__DEFINES/rust_g.dm index 5789f44ffd7..0cd48223ec4 100644 --- a/code/__DEFINES/rust_g.dm +++ b/code/__DEFINES/rust_g.dm @@ -38,12 +38,7 @@ #define RUST_G (__rust_g || __detect_rust_g()) #endif -// Handle 515 call() -> call_ext() changes -#if DM_VERSION >= 515 #define RUSTG_CALL call_ext -#else -#define RUSTG_CALL call -#endif /// Gets the version of rust_g /proc/rustg_get_version() return RUSTG_CALL(RUST_G, "get_version")() diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 05f8cca6526..d2bfc391e82 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -161,7 +161,7 @@ SUBSYSTEM_DEF(garbage) lastlevel = level - //We do this rather then for(var/refID in queue) because that sort of for loop copies the whole list. + //We do this rather then for(var/list/ref_info in queue) because that sort of for loop copies the whole list. //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun. for (var/i in 1 to length(queue)) var/list/L = queue[i] @@ -175,20 +175,16 @@ SUBSYSTEM_DEF(garbage) if(queued_at_time > cut_off_time) break // Everything else is newer, skip them count++ - var/GCd_at_time = L[GC_QUEUE_ITEM_GCD_DESTROYED] - var/refID = L[GC_QUEUE_ITEM_REF] - var/datum/D - D = locate(refID) - - if (!D || D.gc_destroyed != GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake + var/datum/D = L[GC_QUEUE_ITEM_REF] + if(refcount(D) == 2) ++gcedlasttick ++totalgcs pass_counts[level]++ #ifdef REFERENCE_TRACKING reference_find_on_fail -= refID //It's deleted we don't care anymore. #endif - if (MC_TICK_CHECK) + if(MC_TICK_CHECK) return continue @@ -251,20 +247,19 @@ SUBSYSTEM_DEF(garbage) count = 0 /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) - if (isnull(D)) + if(isnull(D)) return - if (level > GC_QUEUE_COUNT) + if(level > GC_QUEUE_COUNT) HardDelete(D) return var/queue_time = world.time - var/refid = text_ref(D) - if (D.gc_destroyed <= 0) + if(D.gc_destroyed <= 0) D.gc_destroyed = queue_time var/list/queue = queues[level] - queue[++queue.len] = list(queue_time, refid, D.gc_destroyed) // not += for byond reasons + queue[++queue.len] = list(queue_time, D, D.gc_destroyed) // not += for byond reasons //this is mainly to separate things profile wise. /datum/controller/subsystem/garbage/proc/HardDelete(datum/D) diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index b8fa0441f96..92934f26e53 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -222,6 +222,8 @@ return /mob/proc/set_machine(obj/O) + if(QDELETED(src) || QDELETED(O)) + return if(machine) unset_machine() machine = O diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index d911392db80..6acedc649f3 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1,5 +1,6 @@ /mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. + unset_machine() GLOB.mob_list -= src GLOB.dead_mob_list -= src GLOB.offered_mob_list -= src diff --git a/code/modules/tgs/v3210/api.dm b/code/modules/tgs/v3210/api.dm index 666201a3225..aaf9671db7b 100644 --- a/code/modules/tgs/v3210/api.dm +++ b/code/modules/tgs/v3210/api.dm @@ -99,11 +99,7 @@ if(skip_compat_check && !fexists(SERVICE_INTERFACE_DLL)) TGS_ERROR_LOG("Service parameter present but no interface DLL detected. This is symptomatic of running a service less than version 3.1! Please upgrade.") return - #if DM_VERSION >= 515 call_ext(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval - #else - call(SERVICE_INTERFACE_DLL, SERVICE_INTERFACE_FUNCTION)(instance_name, command) //trust no retval - #endif return TRUE /datum/tgs_api/v3210/OnTopic(T) From 2cc8fe6d651b0bc8f17e6cb0baa61a05a1fc7db4 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Tue, 3 Dec 2024 23:44:02 +0200 Subject: [PATCH 06/43] 72797 --- code/modules/mob/mob.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 6acedc649f3..5ab1d372e7e 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1,5 +1,8 @@ - -/mob/Destroy()//This makes sure that mobs with clients/keys are not just deleted from the game. +/mob/Destroy() + if(client) + stack_trace("Mob with client has been deleted.") + else if(ckey) + stack_trace("Mob without client but with associated ckey has been deleted.") unset_machine() GLOB.mob_list -= src GLOB.dead_mob_list -= src From 341b158b6103a7c280ea52a5c09baae159ba42f2 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 00:18:47 +0200 Subject: [PATCH 07/43] 80443 --- code/controllers/subsystem/garbage.dm | 18 +- code/datums/datum.dm | 6 +- .../view_variables/reference_tracking.dm | 208 +++++++++++------- .../unit_tests/find_reference_sanity.dm | 44 ++-- 4 files changed, 166 insertions(+), 110 deletions(-) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index d2bfc391e82..0f463fae14e 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -161,6 +161,9 @@ SUBSYSTEM_DEF(garbage) lastlevel = level +// 1 from the hard reference in the queue, and 1 from the variable used before this +#define REFS_WE_EXPECT 2 + //We do this rather then for(var/list/ref_info in queue) because that sort of for loop copies the whole list. //Normally this isn't expensive, but the gc queue can grow to 40k items, and that gets costly/causes overrun. for (var/i in 1 to length(queue)) @@ -177,7 +180,7 @@ SUBSYSTEM_DEF(garbage) count++ var/datum/D = L[GC_QUEUE_ITEM_REF] - if(refcount(D) == 2) + if(refcount(D) == REFS_WE_EXPECT) ++gcedlasttick ++totalgcs pass_counts[level]++ @@ -198,12 +201,15 @@ SUBSYSTEM_DEF(garbage) switch (level) if (GC_QUEUE_CHECK) #ifdef REFERENCE_TRACKING + // 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 if(reference_find_on_fail[refID]) - INVOKE_ASYNC(D, TYPE_PROC_REF(/datum,find_references)) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references, remaining_refs)) ref_searching = TRUE #ifdef GC_FAILURE_HARD_LOOKUP else - INVOKE_ASYNC(D, TYPE_PROC_REF(/datum,find_references)) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references, remaining_refs)) ref_searching = TRUE #endif reference_find_on_fail -= refID @@ -227,7 +233,7 @@ SUBSYSTEM_DEF(garbage) return //ref searching intentionally cancels all further fires while running so things that hold references don't end up getting deleted, so we want to return here instead of continue #endif continue - if (GC_QUEUE_HARDDELETE) + if(GC_QUEUE_HARDDELETE) HardDelete(D) if (MC_TICK_CHECK) return @@ -242,10 +248,12 @@ SUBSYSTEM_DEF(garbage) if (MC_TICK_CHECK) return - if (count) + if(count) queue.Cut(1,count+1) count = 0 +#undef REFS_WE_EXPECT + /datum/controller/subsystem/garbage/proc/Queue(datum/D, level = GC_QUEUE_FILTER) if(isnull(D)) return diff --git a/code/datums/datum.dm b/code/datums/datum.dm index f7061192117..d257a149d01 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -67,8 +67,12 @@ #endif #ifdef REFERENCE_TRACKING - var/running_find_references + /// When was this datum last touched by a reftracker? + /// If this value doesn't match with the start of the search + /// We know this datum has never been seen before, and we should check it var/last_find_references = 0 + /// How many references we're trying to find when searching + var/references_to_clear = 0 #ifdef REFERENCE_TRACKING_DEBUG ///Stores info about where refs are found, used for sanity checks and testing var/list/found_refs diff --git a/code/modules/admin/view_variables/reference_tracking.dm b/code/modules/admin/view_variables/reference_tracking.dm index e4801e8722b..e351dffe2e2 100644 --- a/code/modules/admin/view_variables/reference_tracking.dm +++ b/code/modules/admin/view_variables/reference_tracking.dm @@ -1,34 +1,30 @@ #ifdef REFERENCE_TRACKING +#define REFSEARCH_RECURSE_LIMIT 64 -/datum/proc/find_references(skip_alert) - running_find_references = type +/datum/proc/find_references(references_to_clear = INFINITY) if(usr?.client) - if(usr.client.running_find_references) - log_reftracker("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 && 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") - running_find_references = null + 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 - if(usr?.client) - usr.client.running_find_references = type + _search_references() + //restart the garbage collector + SSgarbage.can_fire = TRUE + SSgarbage.update_nextfire(reset_time = TRUE) - log_reftracker("Beginning search for references to a [type].") +/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", search_time = starting_time) //globals + 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 @@ -36,44 +32,46 @@ for(var/key in global.vars) global_vars[key] = global.vars[key] - DoSearchVar(global_vars, "Native Global", search_time = starting_time) + 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]", search_time = starting_time) + 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]", search_time = starting_time) + 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]", search_time = starting_time) + 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].") - 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/proc/DoSearchVar(potential_container, container_name, recursive_limit = 64, search_time = world.time) - #ifdef REFERENCE_TRACKING_DEBUG - if(SSgarbage.should_save_refs && !found_refs) - found_refs = list() - #endif - - if(usr?.client && !usr.client.running_find_references) +/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(!recursive_limit) + if(references_to_clear == 0) log_reftracker("Recursion limit reached. [container_name]") return @@ -88,73 +86,117 @@ return datum_container.last_find_references = search_time - var/container_print = datum_container.ref_search_details() 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) - #ifndef FIND_REF_NO_CHECK_TICK - CHECK_TICK - #endif - if (varname == "vars" || varname == "vis_locs") //Fun fact, vis_locs don't count for references - continue var/variable = vars_list[varname] - if(variable == src) + 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 - log_reftracker("Found [type] \ref[src] in [datum_container.type]'s [container_print] [varname] var. [container_name]") + references_to_clear -= 1 + if(references_to_clear == 0) + log_reftracker("All references to [type] [text_ref(src)] found, exiting.") + return continue - if(islist(variable)) - DoSearchVar(variable, "[container_name] [container_print] -> [varname] (list)", recursive_limit - 1, search_time) - else if(islist(potential_container)) - var/normal = IS_NORMAL_LIST(potential_container) var/list/potential_cache = potential_container for(var/element_in_list in potential_cache) - #ifndef FIND_REF_NO_CHECK_TICK - CHECK_TICK - #endif + //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 - if(element_in_list == src) + 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 //End early, don't want these logging - #endif + continue + else + log_reftracker("Found [type] [text_ref(src)] in list [container_name].") + #else log_reftracker("Found [type] \ref[src] in list [container_name].") - continue - - var/assoc_val = null - if(!isnum(element_in_list) && normal) - assoc_val = potential_cache[element_in_list] - //Check assoc entrys - if(assoc_val == src) - #ifdef REFERENCE_TRACKING_DEBUG - if(SSgarbage.should_save_refs) - found_refs[potential_cache] = TRUE - continue //End early, don't want these logging #endif - log_reftracker("Found [type] \ref[src] in list [container_name]\[[element_in_list]\]") - continue - //We need to run both of these checks, since our object could be hiding in either of them - //Check normal sublists - if(islist(element_in_list)) - DoSearchVar(element_in_list, "[container_name] -> [element_in_list] (list)", recursive_limit - 1, search_time) - //Check assoc sublists - if(islist(assoc_val)) - DoSearchVar(potential_container[element_in_list], "[container_name]\[[element_in_list]\] -> [assoc_val] (list)", recursive_limit - 1, search_time) - -/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[text_ref(src)] = TRUE - qdel(src, force) - + // 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 diff --git a/code/modules/unit_tests/find_reference_sanity.dm b/code/modules/unit_tests/find_reference_sanity.dm index 3f2addd2315..a1637f7ea85 100644 --- a/code/modules/unit_tests/find_reference_sanity.dm +++ b/code/modules/unit_tests/find_reference_sanity.dm @@ -15,6 +15,8 @@ return ..() /atom/movable/ref_test + // Gotta make sure we do a full check + references_to_clear = INFINITY var/atom/movable/ref_test/self_ref /atom/movable/ref_test/Destroy(force) @@ -29,9 +31,9 @@ //Sanity check var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 3, "Should be: test references: 0 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(testbed, "Sanity Check", search_time = 1) //We increment search time to get around an optimization + victim.DoSearchVar(testbed, "Sanity Check") //We increment search time to get around an optimization - TEST_ASSERT(!victim.found_refs.len, "The ref-tracking tool found a ref where none existed") + TEST_ASSERT(!LAZYLEN(victim.found_refs), "The ref-tracking tool found a ref where none existed") SSgarbage.should_save_refs = FALSE /datum/unit_test/find_reference_baseline/Run() @@ -46,11 +48,11 @@ var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 6, "Should be: test references: 3 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(testbed, "First Run", search_time = 2) + victim.DoSearchVar(testbed, "First Run") - TEST_ASSERT(victim.found_refs["test"], "The ref-tracking tool failed to find a regular value") - TEST_ASSERT(victim.found_refs[testbed.test_list], "The ref-tracking tool failed to find a list entry") - TEST_ASSERT(victim.found_refs[testbed.test_assoc_list], "The ref-tracking tool failed to find an assoc list value") + TEST_ASSERT(LAZYACCESS(victim.found_refs, "test"), "The ref-tracking tool failed to find a regular value") + TEST_ASSERT(LAZYACCESS(victim.found_refs, testbed.test_list), "The ref-tracking tool failed to find a list entry") + TEST_ASSERT(LAZYACCESS(victim.found_refs, testbed.test_assoc_list), "The ref-tracking tool failed to find an assoc list value") SSgarbage.should_save_refs = FALSE /datum/unit_test/find_reference_exotic/Run() @@ -65,12 +67,12 @@ var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 6, "Should be: test references: 3 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(testbed, "Second Run", search_time = 3) + victim.DoSearchVar(testbed, "Second Run") //This is another sanity check - TEST_ASSERT(!victim.found_refs[testbed.overlays], "The ref-tracking tool found an overlays entry? That shouldn't be possible") - TEST_ASSERT(victim.found_refs[testbed.vis_contents], "The ref-tracking tool failed to find a vis_contents entry") - TEST_ASSERT(victim.found_refs[testbed.test_assoc_list], "The ref-tracking tool failed to find an assoc list key") + TEST_ASSERT(!LAZYACCESS(victim.found_refs, testbed.overlays), "The ref-tracking tool found an overlays entry? That shouldn't be possible") + TEST_ASSERT(LAZYACCESS(victim.found_refs, testbed.vis_contents), "The ref-tracking tool failed to find a vis_contents entry") + TEST_ASSERT(LAZYACCESS(victim.found_refs, testbed.test_assoc_list), "The ref-tracking tool failed to find an assoc list key") SSgarbage.should_save_refs = FALSE /datum/unit_test/find_reference_esoteric/Run() @@ -87,11 +89,11 @@ var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 6, "Should be: test references: 3 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(victim, "Third Run Self", search_time = 4) - victim.DoSearchVar(testbed, "Third Run Testbed", search_time = 4) - TEST_ASSERT(victim.found_refs["self_ref"], "The ref-tracking tool failed to find a self reference") - TEST_ASSERT(victim.found_refs[to_find], "The ref-tracking tool failed to find a nested list entry") - TEST_ASSERT(victim.found_refs[to_find_assoc], "The ref-tracking tool failed to find a nested assoc list entry") + victim.DoSearchVar(victim, "Third Run Self") + victim.DoSearchVar(testbed, "Third Run Testbed") + TEST_ASSERT(LAZYACCESS(victim.found_refs, "self_ref"), "The ref-tracking tool failed to find a self reference") + TEST_ASSERT(LAZYACCESS(victim.found_refs, to_find), "The ref-tracking tool failed to find a nested list entry") + TEST_ASSERT(LAZYACCESS(victim.found_refs, to_find_assoc), "The ref-tracking tool failed to find a nested assoc list entry") SSgarbage.should_save_refs = FALSE /datum/unit_test/find_reference_null_key_entry/Run() @@ -103,7 +105,7 @@ testbed.test_assoc_list = list(null = victim) var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 4, "Should be: test references: 1 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(testbed, "Fourth Run", search_time = 5) + victim.DoSearchVar(testbed, "Fourth Run") TEST_ASSERT(testbed.test_assoc_list, "The ref-tracking tool failed to find a null key'd assoc list entry") @@ -120,10 +122,10 @@ var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 5, "Should be: test references: 2 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(testbed, "Fifth Run", search_time = 6) + victim.DoSearchVar(testbed, "Fifth Run") - TEST_ASSERT(victim.found_refs[to_find_in_key], "The ref-tracking tool failed to find a nested assoc list key") - TEST_ASSERT(victim.found_refs[to_find_null_assoc_nested], "The ref-tracking tool failed to find a null key'd nested assoc list entry") + TEST_ASSERT(LAZYACCESS(victim.found_refs, to_find_in_key), "The ref-tracking tool failed to find a nested assoc list key") + TEST_ASSERT(LAZYACCESS(victim.found_refs, to_find_null_assoc_nested), "The ref-tracking tool failed to find a null key'd nested assoc list entry") SSgarbage.should_save_refs = FALSE /datum/unit_test/find_reference_static_investigation/Run() @@ -143,7 +145,7 @@ var/refcount = refcount(victim) TEST_ASSERT_EQUAL(refcount, 5, "Should be: test references: 2 + baseline references: 3 (victim var,loc,allocated list)") - victim.DoSearchVar(global_vars, "Sixth Run", search_time = 7) + victim.DoSearchVar(global_vars, "Sixth Run") - TEST_ASSERT(victim.found_refs[global_vars], "The ref-tracking tool failed to find a natively global variable") + TEST_ASSERT(LAZYACCESS(victim.found_refs, global_vars), "The ref-tracking tool failed to find a natively global variable") SSgarbage.should_save_refs = FALSE From 9ebed14a373c5aa03978bed8f6f2e8a54b243715 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 11:21:37 +0200 Subject: [PATCH 08/43] Update garbage.dm --- code/controllers/subsystem/garbage.dm | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index 0f463fae14e..40101f164a1 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -185,7 +185,7 @@ SUBSYSTEM_DEF(garbage) ++totalgcs pass_counts[level]++ #ifdef REFERENCE_TRACKING - reference_find_on_fail -= refID //It's deleted we don't care anymore. + reference_find_on_fail -= text_ref(D) //It's deleted we don't care anymore. #endif if(MC_TICK_CHECK) return @@ -204,15 +204,15 @@ SUBSYSTEM_DEF(garbage) // 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 - if(reference_find_on_fail[refID]) - INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references, remaining_refs)) + if(reference_find_on_fail[text_ref(D)]) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) ref_searching = TRUE #ifdef GC_FAILURE_HARD_LOOKUP else - INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references, remaining_refs)) + INVOKE_ASYNC(D, TYPE_PROC_REF(/datum, find_references), remaining_refs) ref_searching = TRUE #endif - reference_find_on_fail -= refID + reference_find_on_fail -= text_ref(D) #endif var/type = D.type var/datum/qdel_item/I = items[type] From 1424a16c6dae72a914b4e6839fb239f3919378c1 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 11:27:08 +0200 Subject: [PATCH 09/43] 59813 --- code/controllers/master.dm | 15 ++++++--------- code/controllers/subsystem.dm | 31 ++++++++++++++++++++++++++++--- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index 11dbcfe93a3..7e34885bc58 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -593,6 +593,10 @@ GLOBAL_REAL(Master, /datum/controller/master) continue if ((SS_flags & (SS_TICKER|SS_KEEP_TIMING)) == SS_KEEP_TIMING && SS.last_fire + (SS.wait * 0.75) > world.time) continue + if (SS.postponed_fires >= 1) + SS.postponed_fires-- + SS.update_nextfire() + continue SS.enqueue() . = 1 @@ -709,15 +713,8 @@ GLOBAL_REAL(Master, /datum/controller/master) queue_node.last_fire = world.time queue_node.times_fired++ - if (queue_node_flags & SS_TICKER) - queue_node.next_fire = world.time + (world.tick_lag * queue_node.wait) - else if (queue_node_flags & SS_POST_FIRE_TIMING) - queue_node.next_fire = world.time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun * 0.01)) - else if (queue_node_flags & SS_KEEP_TIMING) - queue_node.next_fire += queue_node.wait - else - queue_node.next_fire = queue_node.queued_time + queue_node.wait + (world.tick_lag * (queue_node.tick_overrun * 0.01)) - + queue_node.update_nextfire() + queue_node.queued_time = 0 //remove from queue diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 0a44e8d9930..41704e443d7 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -60,6 +60,8 @@ var/ticks = 1 ///number of times we have called fire() var/times_fired = 0 + /// How many fires have we been requested to postpone + var/postponed_fires = 0 ///time we entered the queue, (for timing and priority reasons) var/queued_time = 0 ///we keep a running total to make the math easier, if priority changes mid-fire that would break our running total, so we store it here @@ -111,6 +113,29 @@ Master.subsystems -= src return ..() +/** Update next_fire for the next run. + * reset_time (bool) - Ignore things that would normally alter the next fire, like tick_overrun, and last_fire. (also resets postpone) + */ +/datum/controller/subsystem/proc/update_nextfire(reset_time = FALSE) + var/queue_node_flags = flags + + if (reset_time) + postponed_fires = 0 + if (queue_node_flags & SS_TICKER) + next_fire = world.time + (world.tick_lag * wait) + else + next_fire = world.time + wait + return + + if (queue_node_flags & SS_TICKER) + next_fire = world.time + (world.tick_lag * wait) + else if (queue_node_flags & SS_POST_FIRE_TIMING) + next_fire = world.time + wait + (world.tick_lag * (tick_overrun/100)) + else if (queue_node_flags & SS_KEEP_TIMING) + next_fire += wait + else + next_fire = queued_time + wait + (world.tick_lag * (tick_overrun/100)) + ///Queue it to run. /// (we loop thru a linked list until we get to the end or find the right point) /// (this lets us sort our run order correctly without having to re-sort the entire already sorted list) @@ -226,8 +251,8 @@ //could be used to postpone a costly subsystem for (default one) var/cycles, cycles //for instance, during cpu intensive operations like explosions /datum/controller/subsystem/proc/postpone(cycles = 1) - if(next_fire - world.time < wait) - next_fire += (wait*cycles) + if(can_fire && cycles >= 1) + postponed_fires += cycles //usually called via datum/controller/subsystem/New() when replacing a subsystem (i.e. due to a recurring crash) //should attempt to salvage what it can from the old instance of subsystem @@ -238,7 +263,7 @@ if ("can_fire") //this is so the subsystem doesn't rapid fire to make up missed ticks causing more lag if (var_value) - next_fire = world.time + wait + update_nextfire(reset_time = TRUE) if ("queued_priority") //editing this breaks things. return 0 . = ..() From a5bff17eab4f1d8315ef90590b5ee6a432b9ad30 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 12:44:13 +0200 Subject: [PATCH 10/43] Update _attachable.dm --- code/modules/projectiles/attachables/_attachable.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index 09965c6f055..4563dad6567 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -155,6 +155,10 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. . = ..() AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound) +/obj/item/attachable/Destroy() + master_gun = null + return ..() + ///Called when the attachment is attached to something. If it is a gun it will update the guns stats. /obj/item/attachable/proc/on_attach(attaching_item, mob/user) From 8c346c55917d83e1df77d1231a0bc9d283967b89 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 16:33:34 +0200 Subject: [PATCH 11/43] Update dropship_equipment.dm --- code/game/objects/structures/dropship_equipment.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/structures/dropship_equipment.dm b/code/game/objects/structures/dropship_equipment.dm index 1be2e7a184f..8436a961c75 100644 --- a/code/game/objects/structures/dropship_equipment.dm +++ b/code/game/objects/structures/dropship_equipment.dm @@ -359,12 +359,12 @@ if(!deployed_turret) var/obj/new_gun = new sentry_type(src) deployed_turret = new_gun.loc - RegisterSignal(deployed_turret, COMSIG_OBJ_DECONSTRUCT, PROC_REF(clean_refs)) + RegisterSignal(deployed_turret, COMSIG_QDELETING, PROC_REF(clean_refs)) ///This cleans the deployed_turret ref when the sentry is destroyed. /obj/structure/dropship_equipment/shuttle/sentry_holder/proc/clean_refs(atom/source, disassembled) SIGNAL_HANDLER - UnregisterSignal(deployed_turret, COMSIG_OBJ_DECONSTRUCT) + UnregisterSignal(deployed_turret, COMSIG_QDELETING) deployed_turret = null dropship_equipment_flags &= ~IS_NOT_REMOVABLE From eac966658214bd0677ef40ac0b8a8772b41284eb Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 16:50:21 +0200 Subject: [PATCH 12/43] master_gun --- code/modules/projectiles/attachables/_attachable.dm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index 4563dad6567..82a5043334d 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -155,10 +155,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. . = ..() AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound) -/obj/item/attachable/Destroy() - master_gun = null - return ..() - +/obj/item/attachable ///Called when the attachment is attached to something. If it is a gun it will update the guns stats. /obj/item/attachable/proc/on_attach(attaching_item, mob/user) @@ -349,6 +346,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. activate(user) new_action.set_toggle(TRUE) update_icon() + RegisterSignal(master_gun, COMSIG_QDELETING, PROC_REF(clean_attachable_refs)) RegisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY, TYPE_PROC_REF(/obj/item/weapon/gun, drop_connected_mag)) ///This is called when an attachment gun (src) detaches from a gun. @@ -365,10 +363,16 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. master_gun.active_attachable = null master_gun.wield_delay -= wield_delay_mod UnregisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY) + UnregisterSignal(master_gun, COMSIG_QDELETING) master_gun = null attached_to:gunattachment = null update_icon() +/// Cleanup for deleting while attached to a gun. +/obj/item/weapon/gun/proc/clean_attachable_refs() + SIGNAL_HANDLER + master_gun = null + ///This activates the weapon for use. /obj/item/weapon/gun/proc/activate(mob/user) if(master_gun.active_attachable) From 0d9ee00a9e961204b845a2d2093877f04d9fe109 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 16:52:39 +0200 Subject: [PATCH 13/43] Update xeno_towers.dm --- code/modules/xenomorph/xeno_towers.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/xenomorph/xeno_towers.dm b/code/modules/xenomorph/xeno_towers.dm index cd1ec6c8f6d..b132ed1fc1a 100644 --- a/code/modules/xenomorph/xeno_towers.dm +++ b/code/modules/xenomorph/xeno_towers.dm @@ -70,7 +70,7 @@ SSminimaps.add_marker(src, MINIMAP_FLAG_XENO, image('icons/UI_icons/map_blips.dmi', null, "phero", ABOVE_FLOAT_LAYER)) // RU TGMC edit - map blips GLOB.hive_datums[hivenumber].pherotowers += src -//Pheromone towers start off with recovery. + //Pheromone towers start off with recovery. current_aura = SSaura.add_emitter(src, AURA_XENO_RECOVERY, aura_radius, aura_strength, -1, FACTION_XENO, hivenumber) playsound(src, "alien_drool", 25) update_icon() @@ -80,6 +80,7 @@ /obj/structure/xeno/pherotower/Destroy() GLOB.hive_datums[hivenumber].pherotowers -= src + QDEL_NULL(current_aura) return ..() // Clicking on the tower brings up a radial menu that allows you to select the type of pheromone that this tower will emit. From f8311d72b1188ecd62eb519f7efe6337f8d01eed Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 17:03:41 +0200 Subject: [PATCH 14/43] Update camera.dm --- code/game/objects/machinery/computer/camera.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/machinery/computer/camera.dm b/code/game/objects/machinery/computer/camera.dm index 2d02861febe..529cccdb6b8 100644 --- a/code/game/objects/machinery/computer/camera.dm +++ b/code/game/objects/machinery/computer/camera.dm @@ -51,9 +51,9 @@ cam_background.del_on_map_removal = FALSE /obj/machinery/computer/camera/Destroy() - qdel(cam_screen) + QDEL_NULL(cam_screen) QDEL_LIST(cam_plane_masters) - qdel(cam_background) + QDEL_NULL(cam_background) return ..() /obj/machinery/computer/camera/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock, idnum, override=FALSE) From 93fefd6a3b121884eda70e4d1e1b424a41e87063 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 17:14:53 +0200 Subject: [PATCH 15/43] Update _attachable.dm --- code/modules/projectiles/attachables/_attachable.dm | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index 82a5043334d..c2654955b2e 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -155,7 +155,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. . = ..() AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound) -/obj/item/attachable ///Called when the attachment is attached to something. If it is a gun it will update the guns stats. /obj/item/attachable/proc/on_attach(attaching_item, mob/user) @@ -362,8 +361,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. if(master_gun.active_attachable == src) master_gun.active_attachable = null master_gun.wield_delay -= wield_delay_mod - UnregisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY) - UnregisterSignal(master_gun, COMSIG_QDELETING) + UnregisterSignal(master_gun, list(COMSIG_ITEM_REMOVED_INVENTORY, COMSIG_QDELETING)) master_gun = null attached_to:gunattachment = null update_icon() From 269c15ee3926d808debca05079d4ba57fbe9050a Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 17:33:35 +0200 Subject: [PATCH 16/43] Update camera.dm --- code/game/objects/machinery/computer/camera.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/game/objects/machinery/computer/camera.dm b/code/game/objects/machinery/computer/camera.dm index 529cccdb6b8..fbe5a648436 100644 --- a/code/game/objects/machinery/computer/camera.dm +++ b/code/game/objects/machinery/computer/camera.dm @@ -1,3 +1,5 @@ +#define DEFAULT_MAP_SIZE 15 + /obj/machinery/computer/camera name = "security camera console" desc = "Used to access the various cameras on the station." @@ -15,7 +17,6 @@ // Stuff needed to render the map var/map_name - var/const/default_map_size = 15 var/atom/movable/screen/map_view/cam_screen /// All the plane masters that need to be applied. var/list/cam_plane_masters @@ -157,7 +158,7 @@ /obj/machinery/computer/camera/proc/show_camera_static() cam_screen.vis_contents.Cut() cam_background.icon_state = "scanline2" - cam_background.fill_rect(1, 1, default_map_size, default_map_size) + cam_background.fill_rect(1, 1, DEFAULT_MAP_SIZE, DEFAULT_MAP_SIZE) // Returns the list of cameras accessible from this computer /obj/machinery/computer/camera/proc/get_available_cameras() @@ -177,3 +178,5 @@ if(length(tempnetwork)) valid_cams["[C.c_tag]"] = C return valid_cams + +#undef DEFAULT_MAP_SIZE From 11025a71a1ab294f5c7f6de747ff6498edbc664a Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 17:37:30 +0200 Subject: [PATCH 17/43] Update attachments.dm --- code/modules/clothing/modular_armor/attachments.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/clothing/modular_armor/attachments.dm b/code/modules/clothing/modular_armor/attachments.dm index 2f1f9de34ef..9e9b8d697b7 100644 --- a/code/modules/clothing/modular_armor/attachments.dm +++ b/code/modules/clothing/modular_armor/attachments.dm @@ -67,6 +67,10 @@ AddComponent(/datum/component/attachment_handler, attachments_by_slot, attachments_allowed, starting_attachments = starting_attachments) update_icon() +/obj/item/armor_module/Destroy() + parent = null + return ..() + /// Called before a module is attached. /obj/item/armor_module/proc/can_attach(obj/item/attaching_to, mob/user) return TRUE From 1eb65395577be9abadc82e957179e02da072e3b2 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 17:38:41 +0200 Subject: [PATCH 18/43] Update _attachable.dm --- code/modules/projectiles/attachables/_attachable.dm | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index c2654955b2e..d2b7eaa3757 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -120,7 +120,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. ///only used by lace, denotes whether the lace is currently deployed var/lace_deployed = FALSE - ///what ability to give the user when attached to a weapon they are holding. var/attachment_action_type ///used for the codex to denote if a weapon has the ability to zoom in or not. @@ -155,6 +154,10 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. . = ..() AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound) +/obj/item/attachable/Destroy() + master_gun = null + return ..() + ///Called when the attachment is attached to something. If it is a gun it will update the guns stats. /obj/item/attachable/proc/on_attach(attaching_item, mob/user) @@ -345,7 +348,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. activate(user) new_action.set_toggle(TRUE) update_icon() - RegisterSignal(master_gun, COMSIG_QDELETING, PROC_REF(clean_attachable_refs)) RegisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY, TYPE_PROC_REF(/obj/item/weapon/gun, drop_connected_mag)) ///This is called when an attachment gun (src) detaches from a gun. @@ -361,16 +363,11 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. if(master_gun.active_attachable == src) master_gun.active_attachable = null master_gun.wield_delay -= wield_delay_mod - UnregisterSignal(master_gun, list(COMSIG_ITEM_REMOVED_INVENTORY, COMSIG_QDELETING)) + UnregisterSignal(master_gun, list(COMSIG_ITEM_REMOVED_INVENTORY)) master_gun = null attached_to:gunattachment = null update_icon() -/// Cleanup for deleting while attached to a gun. -/obj/item/weapon/gun/proc/clean_attachable_refs() - SIGNAL_HANDLER - master_gun = null - ///This activates the weapon for use. /obj/item/weapon/gun/proc/activate(mob/user) if(master_gun.active_attachable) From 4b2e9426f09635bf4b4c7f5f717098a76795a75f Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 18:17:26 +0200 Subject: [PATCH 19/43] Update dropship_equipment.dm --- code/game/objects/structures/dropship_equipment.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/objects/structures/dropship_equipment.dm b/code/game/objects/structures/dropship_equipment.dm index 8436a961c75..342a0d62a20 100644 --- a/code/game/objects/structures/dropship_equipment.dm +++ b/code/game/objects/structures/dropship_equipment.dm @@ -356,10 +356,10 @@ /obj/structure/dropship_equipment/shuttle/sentry_holder/Initialize(mapload) . = ..() + RegisterSignal(deployed_turret, COMSIG_QDELETING, PROC_REF(clean_refs)) if(!deployed_turret) var/obj/new_gun = new sentry_type(src) deployed_turret = new_gun.loc - RegisterSignal(deployed_turret, COMSIG_QDELETING, PROC_REF(clean_refs)) ///This cleans the deployed_turret ref when the sentry is destroyed. /obj/structure/dropship_equipment/shuttle/sentry_holder/proc/clean_refs(atom/source, disassembled) From f7dfcbb80f912361bcc045981b2f475f5e13cb09 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 19:19:15 +0200 Subject: [PATCH 20/43] Update dropship_equipment.dm --- code/game/objects/structures/dropship_equipment.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/game/objects/structures/dropship_equipment.dm b/code/game/objects/structures/dropship_equipment.dm index 342a0d62a20..eceb4cb2580 100644 --- a/code/game/objects/structures/dropship_equipment.dm +++ b/code/game/objects/structures/dropship_equipment.dm @@ -356,10 +356,14 @@ /obj/structure/dropship_equipment/shuttle/sentry_holder/Initialize(mapload) . = ..() - RegisterSignal(deployed_turret, COMSIG_QDELETING, PROC_REF(clean_refs)) if(!deployed_turret) var/obj/new_gun = new sentry_type(src) deployed_turret = new_gun.loc + RegisterSignal(deployed_turret, COMSIG_QDELETING, PROC_REF(clean_refs)) + +/obj/structure/dropship_equipment/shuttle/sentry_holder/Destroy() + deployed_turret = null + return ..() ///This cleans the deployed_turret ref when the sentry is destroyed. /obj/structure/dropship_equipment/shuttle/sentry_holder/proc/clean_refs(atom/source, disassembled) From 5ca14697ac18b98df6628519c34e0fe65dd650ed Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 19:21:27 +0200 Subject: [PATCH 21/43] hmm --- code/modules/projectiles/attachables/_attachable.dm | 4 ---- code/modules/projectiles/gun_system.dm | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index d2b7eaa3757..2152851545b 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -154,10 +154,6 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. . = ..() AddElement(/datum/element/attachment, slot, icon, PROC_REF(on_attach), PROC_REF(on_detach), PROC_REF(activate), PROC_REF(can_attach), pixel_shift_x, pixel_shift_y, flags_attach_features, attach_delay, detach_delay, attach_skill, attach_skill_upper_threshold, attach_sound) -/obj/item/attachable/Destroy() - master_gun = null - return ..() - ///Called when the attachment is attached to something. If it is a gun it will update the guns stats. /obj/item/attachable/proc/on_attach(attaching_item, mob/user) diff --git a/code/modules/projectiles/gun_system.dm b/code/modules/projectiles/gun_system.dm index 722749767d0..b8c56dfbebc 100644 --- a/code/modules/projectiles/gun_system.dm +++ b/code/modules/projectiles/gun_system.dm @@ -401,6 +401,7 @@ INVOKE_ASYNC(src, PROC_REF(fill_gun)) /obj/item/weapon/gun/Destroy() + master_gun = null active_attachable = null gunattachment = null QDEL_NULL(muzzle_flash) From 5ebfeeee8bcf7a07d57f82b0f03194b418117aec Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 19:25:50 +0200 Subject: [PATCH 22/43] Update _attachable.dm --- code/modules/projectiles/attachables/_attachable.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/projectiles/attachables/_attachable.dm b/code/modules/projectiles/attachables/_attachable.dm index 2152851545b..baa15e3eff4 100644 --- a/code/modules/projectiles/attachables/_attachable.dm +++ b/code/modules/projectiles/attachables/_attachable.dm @@ -359,7 +359,7 @@ inaccurate. Don't worry if force is ever negative, it won't runtime. if(master_gun.active_attachable == src) master_gun.active_attachable = null master_gun.wield_delay -= wield_delay_mod - UnregisterSignal(master_gun, list(COMSIG_ITEM_REMOVED_INVENTORY)) + UnregisterSignal(master_gun, COMSIG_ITEM_REMOVED_INVENTORY) master_gun = null attached_to:gunattachment = null update_icon() From 20b0ec80f3aecba6e7411df5da0a631109cb0368 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 20:00:31 +0200 Subject: [PATCH 23/43] Update bracers.dm --- code/modules/predator/yautja/bracers.dm | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/code/modules/predator/yautja/bracers.dm b/code/modules/predator/yautja/bracers.dm index 376e9b344c0..9d417c0f929 100644 --- a/code/modules/predator/yautja/bracers.dm +++ b/code/modules/predator/yautja/bracers.dm @@ -72,7 +72,16 @@ var/minimap_icon = "predator" COOLDOWN_DECLARE(bracer_recharge) -/obj/item/clothing/gloves/yautja/Destroy() +/obj/item/clothing/gloves/yautja/Destroy() // FUCKING SHITCODE + left_wristblades = null + right_wristblades = null + combistick = null + discs.Cut() + real_owner = null + owner = null + QDEL_NULL(caster) + QDEL_NULL(embedded_id) + QDEL_LIST(actions_to_add) STOP_PROCESSING(SSobj, src) if(linked_bracer) linked_bracer.linked_bracer = null @@ -1033,11 +1042,6 @@ left_wristblades = new(src) right_wristblades = new(src) -/obj/item/clothing/gloves/yautja/hunter/Destroy() - . = ..() - left_wristblades = null - right_wristblades = null - /obj/item/clothing/gloves/yautja/hunter/emp_act(severity) charge = max(charge - (severity * 500), 0) if(ishuman(loc)) @@ -1058,11 +1062,6 @@ if(embedded_id?.registered_name) embedded_id.set_user_data(user) -/obj/item/clothing/gloves/yautja/hunter/Destroy() - QDEL_NULL(caster) - QDEL_NULL(embedded_id) - return ..() - /obj/item/clothing/gloves/yautja/hunter/process() if(!ishuman(loc)) STOP_PROCESSING(SSobj, src) From 71a6c0f854cd6bcfcb5a02deda41706149d27b87 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 21:11:22 +0200 Subject: [PATCH 24/43] why do we use isdatum here? --- code/modules/vehicles/armored/armored_weapons.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm index 0ddf9a0a171..0ad42bb27e3 100644 --- a/code/modules/vehicles/armored/armored_weapons.dm +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -57,8 +57,7 @@ /obj/item/armored_weapon/Destroy() if(chassis) detach(get_turf(chassis)) - if(isdatum(ammo)) - QDEL_NULL(ammo) + QDEL_NULL(ammo) QDEL_LIST(ammo_magazine) return ..() From 59d6924390bf52099b4612e5f8012cebc78e82af Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 21:15:56 +0200 Subject: [PATCH 25/43] will this work? --- code/datums/interior/_interior.dm | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm index d9fb0e3cb38..7d9cf1c6990 100644 --- a/code/datums/interior/_interior.dm +++ b/code/datums/interior/_interior.dm @@ -17,13 +17,17 @@ var/area/this_area /datum/interior/New(atom/container, datum/callback/exit_callback) - ..() + . = ..() src.container = container src.exit_callback = exit_callback RegisterSignal(container, COMSIG_QDELETING, PROC_REF(handle_container_del)) RegisterSignal(container, COMSIG_ATOM_ENTERED, PROC_REF(on_container_enter)) INVOKE_NEXT_TICK(src, PROC_REF(init_map)) +/datum/interior/Destroy(force) + container = null + return ..() + ///actual inits the map, seperate proc because otherwise it fails linter due to "sleep in new" /datum/interior/proc/init_map() var/datum/map_template/map = new template From 72359e573c6b1d0578eaeda2c0329bceaef4c4f2 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 21:37:44 +0200 Subject: [PATCH 26/43] Revert "will this work?" This reverts commit 59d6924390bf52099b4612e5f8012cebc78e82af. --- code/datums/interior/_interior.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm index 7d9cf1c6990..d9fb0e3cb38 100644 --- a/code/datums/interior/_interior.dm +++ b/code/datums/interior/_interior.dm @@ -17,17 +17,13 @@ var/area/this_area /datum/interior/New(atom/container, datum/callback/exit_callback) - . = ..() + ..() src.container = container src.exit_callback = exit_callback RegisterSignal(container, COMSIG_QDELETING, PROC_REF(handle_container_del)) RegisterSignal(container, COMSIG_ATOM_ENTERED, PROC_REF(on_container_enter)) INVOKE_NEXT_TICK(src, PROC_REF(init_map)) -/datum/interior/Destroy(force) - container = null - return ..() - ///actual inits the map, seperate proc because otherwise it fails linter due to "sleep in new" /datum/interior/proc/init_map() var/datum/map_template/map = new template From 85b135ade6872c9a7582bd74e9b95c1619b94d77 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 21:37:45 +0200 Subject: [PATCH 27/43] Revert "why do we use isdatum here?" This reverts commit 71a6c0f854cd6bcfcb5a02deda41706149d27b87. --- code/modules/vehicles/armored/armored_weapons.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm index 0ad42bb27e3..0ddf9a0a171 100644 --- a/code/modules/vehicles/armored/armored_weapons.dm +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -57,7 +57,8 @@ /obj/item/armored_weapon/Destroy() if(chassis) detach(get_turf(chassis)) - QDEL_NULL(ammo) + if(isdatum(ammo)) + QDEL_NULL(ammo) QDEL_LIST(ammo_magazine) return ..() From f2a2676f982dba85a0048e9208a1bed355e88b87 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 22:50:27 +0200 Subject: [PATCH 28/43] missing destroys? --- code/modules/vehicles/armored/interiors/chairs.dm | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/code/modules/vehicles/armored/interiors/chairs.dm b/code/modules/vehicles/armored/interiors/chairs.dm index bc6fe655d4e..8ad6ccd5297 100644 --- a/code/modules/vehicles/armored/interiors/chairs.dm +++ b/code/modules/vehicles/armored/interiors/chairs.dm @@ -55,6 +55,10 @@ ///owner of this object, assigned during interior linkage var/obj/vehicle/sealed/armored/owner +/obj/structure/bed/chair/vehicle_gunner_seat/Destroy() + owner = null + return ..() + /obj/structure/bed/chair/vehicle_gunner_seat/link_interior(datum/interior/link) if(!istype(link, /datum/interior/armored)) CRASH("invalid interior [link.type] passed to [name]") @@ -92,6 +96,10 @@ ///owner of this object, assigned during interior linkage var/obj/vehicle/sealed/armored/owner +/obj/structure/bed/chair/driver_gunner_seat/Destroy() + owner = null + return ..() + /obj/structure/bed/chair/driver_gunner_seat/link_interior(datum/interior/link) if(!istype(link, /datum/interior/armored)) CRASH("invalid interior [link.type] passed to [name]") From dd12c4d541d923fcc94b19c3a02a54bb2947472e Mon Sep 17 00:00:00 2001 From: Helg2 Date: Wed, 4 Dec 2024 23:29:52 +0200 Subject: [PATCH 29/43] hmmmmmmmmmm --- code/modules/vehicles/armored/armored_weapons.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm index 0ddf9a0a171..20f03601876 100644 --- a/code/modules/vehicles/armored/armored_weapons.dm +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -60,6 +60,7 @@ if(isdatum(ammo)) QDEL_NULL(ammo) QDEL_LIST(ammo_magazine) + QDEL_LIST(accepted_ammo) return ..() ///called by the chassis: begins firing, yes this is stolen from mech but I made both so bite me From 1604e7446cae9f2b5e7b5b43ddae82b9d269900a Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 00:07:43 +0200 Subject: [PATCH 30/43] Update armored_weapons.dm --- code/modules/vehicles/armored/armored_weapons.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm index 20f03601876..d5e312d3147 100644 --- a/code/modules/vehicles/armored/armored_weapons.dm +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -60,7 +60,7 @@ if(isdatum(ammo)) QDEL_NULL(ammo) QDEL_LIST(ammo_magazine) - QDEL_LIST(accepted_ammo) + accepted_ammo.Cut() return ..() ///called by the chassis: begins firing, yes this is stolen from mech but I made both so bite me From c6a13d13820f40c9992660026b6cccef9183faf5 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 00:34:57 +0200 Subject: [PATCH 31/43] doubt it even does something --- code/modules/vehicles/armored/armored_weapons.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/vehicles/armored/armored_weapons.dm b/code/modules/vehicles/armored/armored_weapons.dm index d5e312d3147..0ddf9a0a171 100644 --- a/code/modules/vehicles/armored/armored_weapons.dm +++ b/code/modules/vehicles/armored/armored_weapons.dm @@ -60,7 +60,6 @@ if(isdatum(ammo)) QDEL_NULL(ammo) QDEL_LIST(ammo_magazine) - accepted_ammo.Cut() return ..() ///called by the chassis: begins firing, yes this is stolen from mech but I made both so bite me From e488eb7006cd7b358fcbef9d2f86cf0edc75db28 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 10:48:47 +0200 Subject: [PATCH 32/43] https://github.com/tgstation/tgstation/pull/79988 --- code/controllers/subsystem/atoms.dm | 2 +- code/modules/unit_tests/create_and_destroy.dm | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 6b0b114555b..f28b5d4870d 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -189,7 +189,7 @@ SUBSYSTEM_DEF(atoms) if(fails & BAD_INIT_NO_HINT) . += "- Didn't return an Initialize hint\n" if(fails & BAD_INIT_QDEL_BEFORE) - . += "- Qdel'd in New()\n" + . += "- Qdel'd before Initialize proc ran\n" if(fails & BAD_INIT_SLEPT) . += "- Slept during Initialize()\n" diff --git a/code/modules/unit_tests/create_and_destroy.dm b/code/modules/unit_tests/create_and_destroy.dm index a3dc08624f6..e34fc2f552b 100644 --- a/code/modules/unit_tests/create_and_destroy.dm +++ b/code/modules/unit_tests/create_and_destroy.dm @@ -155,7 +155,7 @@ GLOBAL_VAR_INIT(running_create_and_destroy, FALSE) if(fails & BAD_INIT_NO_HINT) Fail("[path] didn't return an Initialize hint") if(fails & BAD_INIT_QDEL_BEFORE) - Fail("[path] qdel'd in New()") + Fail("[path] qdel'd before we could call Initialize()") if(fails & BAD_INIT_SLEPT) Fail("[path] slept during Initialize()") From 60e3d0d84908bca2a22b7a4dd8b0819b4d55ec22 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 10:56:19 +0200 Subject: [PATCH 33/43] https://github.com/tgstation/tgstation/pull/76179 --- code/controllers/subsystem/atoms.dm | 60 +++++++++++++++++------------ code/modules/mapping/reader.dm | 8 ++-- 2 files changed, 39 insertions(+), 29 deletions(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index f28b5d4870d..3605b0e351e 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -3,14 +3,16 @@ #define BAD_INIT_SLEPT 4 #define BAD_INIT_NO_HINT 8 +#define SUBSYSTEM_INIT_SOURCE "subsystem init" SUBSYSTEM_DEF(atoms) name = "Atoms" init_order = INIT_ORDER_ATOMS flags = SS_NO_FIRE - var/old_initialized - /// A count of how many initalize changes we've made. We want to prevent old_initialize being overriden by some other value, breaking init code - var/initialized_changed = 0 + /// A stack of list(source, desired initialized state) + /// We read the source of init changes from the last entry, and assert that all changes will come with a reset + var/list/initialized_state = list() + var/base_initialized var/list/late_loaders = list() @@ -47,11 +49,11 @@ SUBSYSTEM_DEF(atoms) if(initialized == INITIALIZATION_INSSATOMS) return - set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD) + set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, SUBSYSTEM_INIT_SOURCE) // This may look a bit odd, but if the actual atom creation runtimes for some reason, we absolutely need to set initialized BACK CreateAtoms(atoms, atoms_to_return) - clear_tracked_initalize() + clear_tracked_initalize(SUBSYSTEM_INIT_SOURCE) if(length(late_loaders)) for(var/I in 1 to length(late_loaders)) @@ -152,31 +154,37 @@ SUBSYSTEM_DEF(atoms) return qdeleted || QDELING(A) -/datum/controller/subsystem/atoms/proc/map_loader_begin() - set_tracked_initalized(INITIALIZATION_INSSATOMS) - -/datum/controller/subsystem/atoms/proc/map_loader_stop() - clear_tracked_initalize() - -/// Use this to set initialized to prevent error states where old_initialized is overriden. It keeps happening and it's cheesing me off -/datum/controller/subsystem/atoms/proc/set_tracked_initalized(value) - if(!initialized_changed) - old_initialized = initialized - initialized = value - else - stack_trace("We started maploading while we were already maploading. You doing something odd?") - initialized_changed += 1 - -/datum/controller/subsystem/atoms/proc/clear_tracked_initalize() - initialized_changed -= 1 - if(!initialized_changed) - initialized = old_initialized +/datum/controller/subsystem/atoms/proc/map_loader_begin(source) + set_tracked_initalized(INITIALIZATION_INSSATOMS, source) + +/datum/controller/subsystem/atoms/proc/map_loader_stop(source) + clear_tracked_initalize(source) + +/// Use this to set initialized to prevent error states where the old initialized is overriden, and we end up losing all context +/// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentially +/datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source) + if(!length(initialized_state)) + base_initialized = initialized + initialized_state += list(list(source, state)) + initialized = state + +/datum/controller/subsystem/atoms/proc/clear_tracked_initalize(source) + for(var/i in length(initialized_state) to 1) + if(initialized_state[i][1] == source) + initialized_state.Cut(i, i+1) + break + + if(!length(initialized_state)) + initialized = base_initialized + base_initialized = INITIALIZATION_INNEW_REGULAR + return + initialized = initialized_state[length(initialized_state)][2] /datum/controller/subsystem/atoms/Recover() initialized = SSatoms.initialized if(initialized == INITIALIZATION_INNEW_MAPLOAD) InitializeAtoms() - old_initialized = SSatoms.old_initialized + initialized_state = SSatoms.initialized_state BadInitializeCalls = SSatoms.BadInitializeCalls /datum/controller/subsystem/atoms/proc/InitLog() @@ -205,3 +213,5 @@ SUBSYSTEM_DEF(atoms) var/initlog = InitLog() if(initlog) text2file(initlog, "[GLOB.log_directory]/initialize.log") + +#undef SUBSYSTEM_INIT_SOURCE diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 5c031adda34..81c22fc7a28 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -335,7 +335,7 @@ first_turf_index++ //turn off base new Initialization until the whole thing is loaded - SSatoms.map_loader_begin() + SSatoms.map_loader_begin(REF(src)) //instanciate the first /turf var/turf/T if(members[first_turf_index] != /turf/template_noop) @@ -354,7 +354,7 @@ for(index in 1 to first_turf_index-1) instance_atom(members[index], members_attributes[index], crds, no_changeturf, placeOnTop, delete) //Restore initialization to the previous value - SSatoms.map_loader_stop() + SSatoms.map_loader_stop(REF(src)) //////////////// //Helpers procs @@ -384,9 +384,9 @@ //custom CHECK_TICK here because we don't want things created while we're sleeping to not initialize if(TICK_CHECK) - SSatoms.map_loader_stop() + SSatoms.map_loader_stop(REF(src)) stoplag() - SSatoms.map_loader_begin() + SSatoms.map_loader_begin(REF(src)) /datum/parsed_map/proc/create_atom(path, crds) set waitfor = FALSE From 024b278ceadd1765ee71973f8b1f5b9a53371401 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 10:57:52 +0200 Subject: [PATCH 34/43] https://github.com/tgstation/tgstation/pull/76241 --- code/controllers/subsystem/atoms.dm | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 3605b0e351e..56a66a69c74 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -169,7 +169,9 @@ SUBSYSTEM_DEF(atoms) initialized = state /datum/controller/subsystem/atoms/proc/clear_tracked_initalize(source) - for(var/i in length(initialized_state) to 1) + if(!length(initialized_state)) + return + for(var/i in length(initialized_state) to 1 step -1) if(initialized_state[i][1] == source) initialized_state.Cut(i, i+1) break From c1a341fb041d49ccb3ce0b4d0b31ffcdf9f3c8fa Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 11:04:29 +0200 Subject: [PATCH 35/43] https://github.com/tgstation/tgstation/pull/81526 --- code/controllers/subsystem/atoms.dm | 36 +++++++++++++++++------ code/controllers/subsystem/icon_smooth.dm | 15 ++++++++++ code/controllers/subsystem/timer.dm | 3 -- 3 files changed, 42 insertions(+), 12 deletions(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 56a66a69c74..9de43346acf 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -3,7 +3,6 @@ #define BAD_INIT_SLEPT 4 #define BAD_INIT_NO_HINT 8 -#define SUBSYSTEM_INIT_SOURCE "subsystem init" SUBSYSTEM_DEF(atoms) name = "Atoms" init_order = INIT_ORDER_ATOMS @@ -49,11 +48,16 @@ SUBSYSTEM_DEF(atoms) if(initialized == INITIALIZATION_INSSATOMS) return - set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, SUBSYSTEM_INIT_SOURCE) + // Generate a unique mapload source for this run of InitializeAtoms + var/static/uid = 0 + uid = (uid + 1) % (SHORT_REAL_LIMIT - 1) + var/source = "subsystem init [uid]" + set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, source) // This may look a bit odd, but if the actual atom creation runtimes for some reason, we absolutely need to set initialized BACK - CreateAtoms(atoms, atoms_to_return) - clear_tracked_initalize(SUBSYSTEM_INIT_SOURCE) + CreateAtoms(atoms, atoms_to_return, source) + clear_tracked_initalize(source) + SSicon_smooth.free_deferred(source) if(length(late_loaders)) for(var/I in 1 to length(late_loaders)) @@ -80,7 +84,7 @@ SUBSYSTEM_DEF(atoms) #endif /// Actually creates the list of atoms. Exists soley so a runtime in the creation logic doesn't cause initalized to totally break -/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null) +/datum/controller/subsystem/atoms/proc/CreateAtoms(list/atoms, list/atoms_to_return = null, mapload_source = null) if (atoms_to_return) LAZYINITLIST(created_atoms) @@ -93,7 +97,12 @@ SUBSYSTEM_DEF(atoms) var/atom/A = atoms[I] if(A.flags_atom & INITIALIZED) continue - CHECK_TICK + // Unrolled CHECK_TICK setup to let us enable/disable mapload based off source + if(TICK_CHECK) + clear_tracked_initalize(mapload_source) + stoplag() + if(mapload_source) + set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source) PROFILE_INIT_ATOM_BEGIN() InitAtom(A, TRUE, mapload_arg) PROFILE_INIT_ATOM_END(A) @@ -106,7 +115,11 @@ SUBSYSTEM_DEF(atoms) InitAtom(A, FALSE, mapload_arg) PROFILE_INIT_ATOM_END(A) ++count - CHECK_TICK + if(TICK_CHECK) + clear_tracked_initalize(mapload_source) + stoplag() + if(mapload_source) + set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source) testing("Initialized [count] atoms") pass(count) @@ -160,6 +173,13 @@ SUBSYSTEM_DEF(atoms) /datum/controller/subsystem/atoms/proc/map_loader_stop(source) clear_tracked_initalize(source) +/// Returns the source currently modifying SSatom's init behavior +/datum/controller/subsystem/atoms/proc/get_initialized_source() + var/state_length = length(initialized_state) + if(!state_length) + return null + return initialized_state[state_length][1] + /// Use this to set initialized to prevent error states where the old initialized is overriden, and we end up losing all context /// Accepts a state and a source, the most recent state is used, sources exist to prevent overriding old values accidentially /datum/controller/subsystem/atoms/proc/set_tracked_initalized(state, source) @@ -215,5 +235,3 @@ SUBSYSTEM_DEF(atoms) var/initlog = InitLog() if(initlog) text2file(initlog, "[GLOB.log_directory]/initialize.log") - -#undef SUBSYSTEM_INIT_SOURCE diff --git a/code/controllers/subsystem/icon_smooth.dm b/code/controllers/subsystem/icon_smooth.dm index d4ddfeff7e0..0584d62c23c 100644 --- a/code/controllers/subsystem/icon_smooth.dm +++ b/code/controllers/subsystem/icon_smooth.dm @@ -9,6 +9,7 @@ SUBSYSTEM_DEF(icon_smooth) var/list/blueprint_queue = list() var/list/smooth_queue = list() var/list/deferred = list() + var/list/deferred_by_source = list() /datum/controller/subsystem/icon_smooth/Initialize() smooth_zlevel(1, TRUE) @@ -56,16 +57,30 @@ SUBSYSTEM_DEF(icon_smooth) else can_fire = FALSE +/// Releases a pool of delayed smooth attempts from a particular source +/datum/controller/subsystem/icon_smooth/proc/free_deferred(source_to_free) + smooth_queue += deferred_by_source[source_to_free] + deferred_by_source -= source_to_free + if(!can_fire) + can_fire = TRUE /datum/controller/subsystem/icon_smooth/proc/add_to_queue(atom/thing) if(thing.smoothing_flags & SMOOTH_QUEUED) return thing.smoothing_flags |= SMOOTH_QUEUED + // If we're currently locked into mapload BY something + // Then put us in a deferred list that we release when this mapload run is finished + if(initialized && length(SSatoms.initialized_state) && SSatoms.initialized == INITIALIZATION_INNEW_MAPLOAD) + var/source = SSatoms.get_initialized_source() + LAZYADD(deferred_by_source[source], thing) + return smooth_queue += thing if(!can_fire) can_fire = TRUE /datum/controller/subsystem/icon_smooth/proc/remove_from_queues(atom/thing) + // Lack of removal from deferred_by_source is safe because the lack of SMOOTH_QUEUED will just free it anyway + // Hopefully this'll never cause a harddel (dies) thing.smoothing_flags &= ~SMOOTH_QUEUED smooth_queue -= thing blueprint_queue -= thing diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index 35143d6f8cb..5f0b630fe25 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -4,8 +4,6 @@ #define BUCKET_POS(timer) (((round((timer.timeToRun - timer.timer_subsystem.head_offset) / world.tick_lag)+1) % BUCKET_LEN)||BUCKET_LEN) /// Gets the maximum time at which timers will be invoked from buckets, used for deferring to secondary queue #define TIMER_MAX(timer_ss) (timer_ss.head_offset + TICKS2DS(BUCKET_LEN + timer_ss.practical_offset - 1)) -/// Max float with integer precision -#define TIMER_ID_MAX (2**24) /** * # Timer Subsystem @@ -656,4 +654,3 @@ SUBSYSTEM_DEF(timer) #undef BUCKET_LEN #undef BUCKET_POS #undef TIMER_MAX -#undef TIMER_ID_MAX From 9e99b3ad9189e61d2881d9e8ce59a0c6b273f2e7 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 11:10:28 +0200 Subject: [PATCH 36/43] https://github.com/tgstation/tgstation/pull/69742 --- code/controllers/subsystem/atoms.dm | 46 ++++++++++++++++++----------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 9de43346acf..2aaa287224b 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -88,12 +88,18 @@ SUBSYSTEM_DEF(atoms) if (atoms_to_return) LAZYINITLIST(created_atoms) + #ifdef TESTING var/count + #endif + var/list/mapload_arg = list(TRUE) if(atoms) + #ifdef TESTING count = length(atoms) - for(var/I in 1 to count) + #endif + + for(var/I in 1 to length(atoms)) var/atom/A = atoms[I] if(A.flags_atom & INITIALIZED) continue @@ -107,14 +113,18 @@ SUBSYSTEM_DEF(atoms) InitAtom(A, TRUE, mapload_arg) PROFILE_INIT_ATOM_END(A) else + #ifdef TESTING count = 0 - for(var/atom/A in world) + #endif + for(var/atom/A as anything in world) if(A.flags_atom & INITIALIZED) continue PROFILE_INIT_ATOM_BEGIN() InitAtom(A, FALSE, mapload_arg) PROFILE_INIT_ATOM_END(A) + #ifdef TESTING ++count + #endif if(TICK_CHECK) clear_tracked_initalize(mapload_source) stoplag() @@ -122,7 +132,6 @@ SUBSYSTEM_DEF(atoms) set_tracked_initalized(INITIALIZATION_INNEW_MAPLOAD, mapload_source) testing("Initialized [count] atoms") - pass(count) /// Init this specific atom /datum/controller/subsystem/atoms/proc/InitAtom(atom/A, from_template = FALSE, list/arguments) @@ -131,30 +140,33 @@ SUBSYSTEM_DEF(atoms) BadInitializeCalls[the_type] |= BAD_INIT_QDEL_BEFORE return TRUE + // This is handled and battle tested by dreamchecker. Limit to UNIT_TESTS just in case that ever fails. + #ifdef UNIT_TESTS var/start_tick = world.time + #endif var/result = A.Initialize(arglist(arguments)) + #ifdef UNIT_TESTS if(start_tick != world.time) BadInitializeCalls[the_type] |= BAD_INIT_SLEPT + #endif var/qdeleted = FALSE - if(result != INITIALIZE_HINT_NORMAL) - switch(result) - if(INITIALIZE_HINT_LATELOAD) - if(arguments[1]) //mapload - late_loaders += A - else - A.LateInitialize() - if(INITIALIZE_HINT_QDEL) - qdel(A) - qdeleted = TRUE - if(INITIALIZE_HINT_QDEL_FORCE) - qdel(A, force = TRUE) - qdeleted = TRUE + switch(result) + if (INITIALIZE_HINT_NORMAL) + // pass + if(INITIALIZE_HINT_LATELOAD) + if(arguments[1]) //mapload + late_loaders += A else - BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT + A.LateInitialize() + if(INITIALIZE_HINT_QDEL) + qdel(A) + qdeleted = TRUE + else + BadInitializeCalls[the_type] |= BAD_INIT_NO_HINT if(!A) //possible harddel qdeleted = TRUE From 3bb3c9467ff4bb0ccd8c933fa299ede40511c141 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 11:16:25 +0200 Subject: [PATCH 37/43] Update atoms.dm --- code/controllers/subsystem/atoms.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm index 2aaa287224b..5e2b97bb5a1 100644 --- a/code/controllers/subsystem/atoms.dm +++ b/code/controllers/subsystem/atoms.dm @@ -155,8 +155,8 @@ SUBSYSTEM_DEF(atoms) var/qdeleted = FALSE switch(result) - if (INITIALIZE_HINT_NORMAL) - // pass + if(INITIALIZE_HINT_NORMAL) + EMPTY_BLOCK_GUARD // pass if(INITIALIZE_HINT_LATELOAD) if(arguments[1]) //mapload late_loaders += A From ef08eaf0fea04ef1ffe1f0c687c77f4ea0043436 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 12:11:51 +0200 Subject: [PATCH 38/43] will this even work --- .../lighting/lighting_static/static_lighting_source.dm | 2 ++ code/modules/vehicles/armored/__armored.dm | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/modules/lighting/lighting_static/static_lighting_source.dm b/code/modules/lighting/lighting_static/static_lighting_source.dm index 9d11a7c7773..bb85ac72d34 100644 --- a/code/modules/lighting/lighting_static/static_lighting_source.dm +++ b/code/modules/lighting/lighting_static/static_lighting_source.dm @@ -69,6 +69,8 @@ LAZYREMOVE(top_atom.static_light_sources, src) SSlighting.static_sources_queue -= src + top_atom = null + source_atom = null return ..() // Yes this doesn't align correctly on anything other than 4 width tabs. diff --git a/code/modules/vehicles/armored/__armored.dm b/code/modules/vehicles/armored/__armored.dm index eea9bddae48..774ff9bacad 100644 --- a/code/modules/vehicles/armored/__armored.dm +++ b/code/modules/vehicles/armored/__armored.dm @@ -114,7 +114,7 @@ icon_state += "_desert" if(minimap_icon_state) SSminimaps.add_marker(src, minimap_flags, image('icons/UI_icons/map_blips_large.dmi', null, minimap_icon_state)) - GLOB.tank_list += src + LAZYADD(GLOB.tank_list, src) /obj/vehicle/sealed/armored/Destroy() if(primary_weapon) @@ -132,7 +132,7 @@ if(isdatum(interior)) QDEL_NULL(interior) underlay = null - GLOB.tank_list -= src + LAZYREMOVE(GLOB.tank_list, src) return ..() /obj/vehicle/sealed/armored/generate_actions() From b8ba713abeff129c54e70e03127c83209b70a9af Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 13:08:50 +0200 Subject: [PATCH 39/43] Revert "will this even work" This reverts commit ef08eaf0fea04ef1ffe1f0c687c77f4ea0043436. --- .../lighting/lighting_static/static_lighting_source.dm | 2 -- code/modules/vehicles/armored/__armored.dm | 4 ++-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/code/modules/lighting/lighting_static/static_lighting_source.dm b/code/modules/lighting/lighting_static/static_lighting_source.dm index bb85ac72d34..9d11a7c7773 100644 --- a/code/modules/lighting/lighting_static/static_lighting_source.dm +++ b/code/modules/lighting/lighting_static/static_lighting_source.dm @@ -69,8 +69,6 @@ LAZYREMOVE(top_atom.static_light_sources, src) SSlighting.static_sources_queue -= src - top_atom = null - source_atom = null return ..() // Yes this doesn't align correctly on anything other than 4 width tabs. diff --git a/code/modules/vehicles/armored/__armored.dm b/code/modules/vehicles/armored/__armored.dm index 774ff9bacad..eea9bddae48 100644 --- a/code/modules/vehicles/armored/__armored.dm +++ b/code/modules/vehicles/armored/__armored.dm @@ -114,7 +114,7 @@ icon_state += "_desert" if(minimap_icon_state) SSminimaps.add_marker(src, minimap_flags, image('icons/UI_icons/map_blips_large.dmi', null, minimap_icon_state)) - LAZYADD(GLOB.tank_list, src) + GLOB.tank_list += src /obj/vehicle/sealed/armored/Destroy() if(primary_weapon) @@ -132,7 +132,7 @@ if(isdatum(interior)) QDEL_NULL(interior) underlay = null - LAZYREMOVE(GLOB.tank_list, src) + GLOB.tank_list -= src return ..() /obj/vehicle/sealed/armored/generate_actions() From 987cde88d59c4112ee3850080bd062515799ad37 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 14:24:17 +0200 Subject: [PATCH 40/43] maybe this? --- code/datums/interior/_interior.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm index d9fb0e3cb38..f94d86ec13e 100644 --- a/code/datums/interior/_interior.dm +++ b/code/datums/interior/_interior.dm @@ -17,7 +17,7 @@ var/area/this_area /datum/interior/New(atom/container, datum/callback/exit_callback) - ..() + . = ..() src.container = container src.exit_callback = exit_callback RegisterSignal(container, COMSIG_QDELETING, PROC_REF(handle_container_del)) @@ -50,6 +50,7 @@ this_area = null loaded_turfs = null QDEL_NULL(reservation) //all the turfs/objs are deleted past this point + UnregisterSignal(container, list(COMSIG_QDELETING, COMSIG_ATOM_ENTERED)) container = null return ..() From 73ee1bf207e45cf686f4006f348df690ef2d0d3f Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 14:45:37 +0200 Subject: [PATCH 41/43] Revert "maybe this?" This reverts commit 987cde88d59c4112ee3850080bd062515799ad37. --- code/datums/interior/_interior.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm index f94d86ec13e..d9fb0e3cb38 100644 --- a/code/datums/interior/_interior.dm +++ b/code/datums/interior/_interior.dm @@ -17,7 +17,7 @@ var/area/this_area /datum/interior/New(atom/container, datum/callback/exit_callback) - . = ..() + ..() src.container = container src.exit_callback = exit_callback RegisterSignal(container, COMSIG_QDELETING, PROC_REF(handle_container_del)) @@ -50,7 +50,6 @@ this_area = null loaded_turfs = null QDEL_NULL(reservation) //all the turfs/objs are deleted past this point - UnregisterSignal(container, list(COMSIG_QDELETING, COMSIG_ATOM_ENTERED)) container = null return ..() From 58787e305ba8c000fb4d8d47c718a443694bdaba Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 20:48:03 +0200 Subject: [PATCH 42/43] Update vehicle.dm --- code/modules/reqs/ui/vehicle.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/reqs/ui/vehicle.dm b/code/modules/reqs/ui/vehicle.dm index 8b08be0395f..c69bb673d52 100644 --- a/code/modules/reqs/ui/vehicle.dm +++ b/code/modules/reqs/ui/vehicle.dm @@ -12,11 +12,11 @@ GLOBAL_LIST_EMPTY(purchased_tanks) vehtype = new vehtype GLOB.armored_modtypes[vehtype.type] = vehtype.permitted_mods .[vehtype.type] = vehtype.permitted_weapons - qdel(vehtype) + vehtype.Destroy() for(var/obj/item/armored_weapon/gun AS in typesof(/obj/item/armored_weapon)) gun = new gun GLOB.armored_gunammo[gun.type] = gun.accepted_ammo - qdel(gun) + gun.Destroy() /datum/supply_ui/vehicles tgui_name = "VehicleSupply" From 0da5a61fe89152676d75cbb4e98c605c9d7199e4 Mon Sep 17 00:00:00 2001 From: Helg2 Date: Thu, 5 Dec 2024 21:07:57 +0200 Subject: [PATCH 43/43] Update _interior.dm --- code/datums/interior/_interior.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/datums/interior/_interior.dm b/code/datums/interior/_interior.dm index f94d86ec13e..2b57344d6dd 100644 --- a/code/datums/interior/_interior.dm +++ b/code/datums/interior/_interior.dm @@ -50,7 +50,6 @@ this_area = null loaded_turfs = null QDEL_NULL(reservation) //all the turfs/objs are deleted past this point - UnregisterSignal(container, list(COMSIG_QDELETING, COMSIG_ATOM_ENTERED)) container = null return ..()