Mob Destroy Refactoring (#22573)

Refactoring the entire destroy proc path from Mob Human all the way down
to Atom while trying to find the causes for the damn mob human hard
deletes. This PR comprehensively reorganizes every single stray
snowflake var used by /atom/ all the way to /mob/living/carbon/human,
and makes sure that every var that COULD store a reference, is now
cleared during the entirety of the Mob Destroy() parent hierarchy.

This may very well be the end of the lag war. 

In total, I've hunted down and cleared 39 hanging references between
/atom and /mob/living/carbon/human

---------

Signed-off-by: VMSolidus <evilexecutive@gmail.com>
This commit is contained in:
VMSolidus
2026-06-03 15:15:56 +00:00
committed by GitHub
parent 7799ea7355
commit 201592f6bd
58 changed files with 383 additions and 345 deletions
+8 -3
View File
@@ -39,14 +39,19 @@
. = 1
/mob/living/carbon/Destroy()
QDEL_NULL(touching)
species = null
QDEL_NULL(handcuffed)
QDEL_NULL(legcuffed)
QDEL_NULL(op_stage)
chem_doses?.Cut()
QDEL_NULL(bloodstr)
QDEL_NULL(dna)
QDEL_NULL(touching)
QDEL_NULL(breathing)
// Delete and null a direct list of references to our internal organs (such as brain, lungs, heart, etc).
QDEL_LIST(internal_organs)
// Null an Associative list of String = Reference to the same organs.
internal_organs_by_name = null
internal_organs_by_name?.Cut()
QDEL_LIST(hallucinations)
return ..()
/mob/living/carbon/rejuvenate()
@@ -50,7 +50,9 @@
/// Map organ names to organs.
var/list/organs_by_name = list()
/// So internal organs have less ickiness too.
/// List of references to all internal organs
var/list/internal_organs = list()
/// Associative List of "name" = ref
var/list/internal_organs_by_name = list()
var/list/stasis_sources = list()
@@ -58,3 +60,8 @@
/// For special cases where something permanently removes a mob's ability to feel pain.
var/pain_immune = FALSE
/// Hallucination spam limit var
var/next_hallucination = 0
/// Hallucinations currently affecting the mob. Not to be confused with singular "hallucination" which is a NUM variable like confused/drowsy/eye_blind etc
var/list/hallucinations = list()
var/shock_stage = 0
@@ -7,10 +7,6 @@
#define COLD_DAMAGE_LEVEL_2 1.5
#define COLD_DAMAGE_LEVEL_3 3
/mob/living/carbon/human
var/datum/dionastats/DS
/mob/living/carbon/human/proc/setup_gestalt()
composition_reagent = /singleton/reagent/nutriment //Dionae aren't animals, so eating them doesn't give animal protein
setup_dionastats()
+14 -22
View File
@@ -4,21 +4,12 @@
voice_name = "unknown"
icon = 'icons/mob/human.dmi'
icon_state = "body_m_s"
mob_size = 9 //Based on average weight of a human
var/pronouns = NEUTER
/// Used so species that need special items (autoinhalers for vaurca/RMT for offworlders) don't get them twice when they shouldn't.
var/species_items_equipped
var/list/hud_list[11]
/// To check if we've need to roll for damage on movement while an item is imbedded in us.
var/embedded_flag
/// This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
var/obj/item/rig/wearing_rig
/// Pref holder for the speech bubble style.
var/speech_bubble_type
mob_bump_flag = HUMAN
mob_push_flags = ~HEAVY
mob_swap_flags = ~HEAVY
light_system = MOVABLE_LIGHT
blocks_emissive = EMISSIVE_BLOCK_NONE
/mob/living/carbon/human/Initialize(mapload, var/new_species = null)
if(!dna)
@@ -105,7 +96,7 @@
set_default_attack(species.unarmed_attacks[1])
/mob/living/carbon/human/Destroy(force)
ghost_spawner = null
QDEL_NULL(ghost_spawner)
//Srom (Shared Dreaming)
srom_pulled_by = null
@@ -118,9 +109,9 @@
// It's actually the set of all Limbs (left arm, head, leg leg, etc) we have. We Qdel and null the set of all limbs, which is unique to /human.
QDEL_LIST(organs)
// Then also null the associative list of those same limbs, which contains the same references.
organs_by_name = null
bad_internal_organs = null
bad_external_organs = null
QDEL_LIST_ASSOC_VAL(organs_by_name)
bad_internal_organs?.Cut()
bad_external_organs?.Cut()
QDEL_NULL(vessel)
@@ -150,13 +141,14 @@
//Yes this is shit, but since someone had the brillant mind to use images for this, we must suffer
if(length(hud_list))
for(var/image/hud_overlay/an_hud_overlay in hud_list)
if(an_hud_overlay.owner)
an_hud_overlay.owner.client?.images -= an_hud_overlay
if(length(an_hud_overlay.owner?.client?.images))
an_hud_overlay.owner.client.images -= an_hud_overlay
an_hud_overlay.owner = null
qdel(an_hud_overlay)
hud_list = null
hud_list.Cut()
. = ..()
wearing_rig = null
return ..()
/mob/living/carbon/human/can_devour(atom/movable/victim, var/silent = FALSE)
if(!should_have_organ(BP_STOMACH))
@@ -1,8 +1,4 @@
/mob/living/carbon/human
light_system = MOVABLE_LIGHT
blocks_emissive = EMISSIVE_BLOCK_NONE
// Tail Style
var/tail_style = null
@@ -103,10 +99,6 @@
var/list/gunshot_residue
var/pulling_punches // Are you trying not to hurt your opponent?
mob_bump_flag = HUMAN
mob_push_flags = ~HEAVY
mob_swap_flags = ~HEAVY
var/flash_protection = 0 // Total level of flash protection
var/equipment_tint_total = 0 // Total level of visualy impairing items
var/equipment_darkness_modifier // Darkvision modifier from equipped items
@@ -134,3 +126,48 @@
var/triage_tag = TRIAGE_NONE
var/lobotomized = FALSE //additional check for isAdvancedToolUser that can be set manually by things
var/list/organs = list()
///Container for blood and BLOOD ONLY. Do not transfer other chems here.
var/datum/reagents/vessel
/// Used for cryo to free up a slot when a ghost cryos.
var/datum/weakref/ghost_spawner
var/next_stance_collapse = 0
var/datum/dionastats/DS
var/oxygen_alert = 0
var/phoron_alert = 0
var/co2_alert = 0
var/fire_alert = 0
var/pressure_alert = 0
var/temperature_alert = 0
var/datum/weakref/srom_pulled_by
var/datum/weakref/srom_pulling
/// Our set of "raw" overlays that can be modified, but cannot be directly applied to the mob without preprocessing.
var/list/overlays_raw[TOTAL_LAYERS]
/// store what the body last looked like, so we only have to update it if something changed
var/previous_damage_appearance
var/singleton/origin_item/culture/culture
var/singleton/origin_item/origin/origin
var/tmp/centcomm_despawn_timer
var/pronouns = NEUTER
/// Used so species that need special items (autoinhalers for vaurca/RMT for offworlders) don't get them twice when they shouldn't.
var/species_items_equipped
var/list/hud_list[11]
/// To check if we've need to roll for damage on movement while an item is imbedded in us.
var/embedded_flag
/// This is very not good, but it's much much better than calling get_rig() every update_canmove() call.
var/obj/item/rig/wearing_rig
/// Pref holder for the speech bubble style.
var/speech_bubble_type
@@ -4,10 +4,6 @@
eyes.update_colour()
regenerate_icons()
/mob/living/carbon/var/list/internal_organs = list()
/mob/living/carbon/var/shock_stage = 0
/mob/living/carbon/human/var/list/organs = list()
/mob/living/carbon/human/proc/recheck_bad_external_organs()
var/damage_this_tick = getToxLoss()
var/arterial_check = 0
@@ -57,9 +53,6 @@
if (W.infection_check())
W.germ_level += 1
/mob/living/carbon/human
var/next_stance_collapse = 0
/mob/living/carbon/human/proc/handle_stance()
// Don't need to process any of this if they aren't standing anyways
// unless their stance is damaged, and we want to check if they should stay down
@@ -45,14 +45,6 @@
///The maximum dose that can be received, above this level all further radiation is taken as damage directly to the body, ignoring armor. Very rapidly fatal.
#define RADIATION_MAX_DOSE 1000
/mob/living/carbon/human
var/oxygen_alert = 0
var/phoron_alert = 0
var/co2_alert = 0
var/fire_alert = 0
var/pressure_alert = 0
var/temperature_alert = 0
/mob/living/carbon/human/Life(seconds_per_tick, times_fired)
if (transforming)
return
@@ -100,10 +100,6 @@ There are several things that need to be remembered:
ret.layer = layer
return ret
/mob/living/carbon/human
var/list/overlays_raw[TOTAL_LAYERS] // Our set of "raw" overlays that can be modified, but cannot be directly applied to the mob without preprocessing.
var/previous_damage_appearance // store what the body last looked like, so we only have to update it if something changed
// Updates overlays from overlays_raw.
/mob/living/carbon/human/update_icon()
if (QDELETED(src))
@@ -1,6 +1,3 @@
/mob/living
var/datum/language/default_language
/mob/living/verb/set_default_language_verb()
set name = "Set Default Language"
set category = "IC.Language"
-3
View File
@@ -196,9 +196,6 @@
/mob/living/proc/handle_hud_icons_health()
return
/mob/living
var/datum/weakref/last_weather
/mob/living/proc/is_outside()
var/turf/T = loc
return istype(T) && T.is_outside()
+13 -19
View File
@@ -53,9 +53,6 @@ default behaviour is:
return TRUE
return FALSE
/mob/living
var/tmp/last_push_notif
/mob/living/Collide(atom/movable/target_movable_atom)
if(now_pushing || !loc)
return
@@ -922,19 +919,17 @@ default behaviour is:
AddElement(/datum/element/connect_loc, loc_connections)
/mob/living/Destroy()
cameraFollow = null
if (length(actions))
for (var/datum/action/action in actions)
action.Remove(src)
actions -= action
//Aiming overlay
QDEL_NULL(stamina_bar)
QDEL_LIST(auras)
QDEL_NULL(psi)
QDEL_NULL(aiming)
QDEL_LIST(aimed_at_by)
//Psi complexus
QDEL_NULL(psi)
if(vr_mob)
vr_mob = null
if(old_mob)
old_mob = null
//Remove contained mobs
if(loc)
for(var/mob/M in contents)
@@ -943,12 +938,11 @@ default behaviour is:
for(var/mob/M in contents)
qdel(M)
QDEL_NULL(reagents)
if(auras)
for(var/a in auras)
remove_aura(a)
prepared_maneuver = null
available_maneuvers?.Cut()
default_language = null
QDEL_NULL(z_eye)
QDEL_NULL(last_weather)
return ..()
/mob/living/proc/nervous_system_failure()
+24
View File
@@ -102,3 +102,27 @@
/// Time since last weather effect
var/weather_cooldown_time = 0
var/datum/psi_complexus/psi
///The obj to overlay on the aim target
var/obj/aiming_overlay/aiming
///A list of mobs the target is being aimed at by
var/list/aimed_at_by
var/singleton/maneuver/prepared_maneuver
var/list/available_maneuvers = list()
var/datum/language/default_language
var/atom/movable/z_observer/z_eye
atom_flags = CRITICAL_ATOM
var/instability = 0
var/last_instability = 0 // Used to calculate instability delta.
var/last_instability_event = null // most recent world.time that something bad happened due to instability.
var/datum/weakref/last_weather
var/tmp/last_push_notif
@@ -1,7 +1,3 @@
/mob/living
var/singleton/maneuver/prepared_maneuver
var/list/available_maneuvers = list()
/mob/living/begin_falling(var/lastloc, var/below)
if(throwing)
return