diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm
index 34b32d5873..32c1e37a6e 100644
--- a/code/controllers/subsystems/garbage.dm
+++ b/code/controllers/subsystems/garbage.dm
@@ -169,7 +169,12 @@ SUBSYSTEM_DEF(garbage)
#endif
var/type = D.type
var/datum/qdel_item/I = items[type]
- testing("GC: -- \ref[D] | [type] was unable to be GC'd --")
+ var/extrainfo = "--"
+ if(istype(D,/image))
+ var/image/img = D
+ var/icon/ico = img.icon
+ extrainfo = "L:[img.loc] -- I:[ico] -- IS:[img.icon_state] --"
+ testing("GC: -- \ref[D] | [type] was unable to be GC'd [extrainfo]")
I.failures++
if (GC_QUEUE_HARDDELETE)
HardDelete(D)
diff --git a/code/controllers/subsystems/transcore_vr.dm b/code/controllers/subsystems/transcore_vr.dm
index 4663406485..f98bf6d2c0 100644
--- a/code/controllers/subsystems/transcore_vr.dm
+++ b/code/controllers/subsystems/transcore_vr.dm
@@ -1,3 +1,6 @@
+#define SSTRANSCORE_IMPLANTS 1
+#define SSTRANSCORE_BACKUPS 2
+
////////////////////////////////
//// Mind/body data storage system
//// for the resleeving tech
@@ -6,39 +9,102 @@
SUBSYSTEM_DEF(transcore)
name = "Transcore"
priority = 20
- wait = 1 MINUTE
- flags = SS_BACKGROUND|SS_NO_TICK_CHECK|SS_NO_INIT
+ wait = 3 MINUTES
+ flags = SS_BACKGROUND|SS_NO_INIT
runlevels = RUNLEVEL_GAME
// THINGS
var/overdue_time = 15 MINUTES
var/core_dumped = FALSE // Core has been dumped! Also set can_fire = 0 when you set this.
+ var/current_step = SSTRANSCORE_IMPLANTS
+
+ var/cost_backups = 0
+ var/cost_implants = 0
+
var/datum/transhuman/mind_record/list/backed_up = list() // All known mind records, indexed by MR.mindname/mind.name
var/datum/transhuman/mind_record/list/has_left = list() // Why do we even have this?
var/datum/transhuman/body_record/list/body_scans = list() // All known body records, indexed by BR.mydna.name
+ var/obj/item/weapon/implant/backup/list/implants = list() // All OPERATING implants that are being ticked
-/datum/controller/subsystem/transcore/fire()
- for(var/N in backed_up)
- var/datum/transhuman/mind_record/curr_MR = backed_up[N]
- if(!curr_MR)
- log_debug("Tried to process [N] in transcore w/o a record!")
+ var/list/current_run = list()
+
+/datum/controller/subsystem/transcore/fire(resumed = 0)
+ var/timer = TICK_USAGE
+
+ INTERNAL_PROCESS_STEP(SSTRANSCORE_IMPLANTS,TRUE,process_implants,cost_implants,SSTRANSCORE_BACKUPS)
+ INTERNAL_PROCESS_STEP(SSTRANSCORE_BACKUPS,FALSE,process_backups,cost_backups,SSTRANSCORE_IMPLANTS)
+
+/datum/controller/subsystem/transcore/proc/process_implants(resumed = 0)
+ if (!resumed)
+ src.current_run = implants.Copy()
+
+ var/list/current_run = src.current_run
+ while(current_run.len)
+ var/obj/item/weapon/implant/backup/imp = current_run[current_run.len]
+ current_run.len--
+
+ //Remove if not in a human anymore.
+ if(!imp || !ishuman(imp.loc))
+ implants -= imp
continue
+
+ //We're in a human, at least.
+ var/mob/living/carbon/human/H = imp.loc
+ BITSET(H.hud_updateflag, BACKUP_HUD)
+
+ if(H == imp.imp_in && H.mind && H.stat < DEAD)
+ SStranscore.m_backup(H.mind,H.nif)
+ persist_nif_data(H)
+
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/transcore/proc/process_backups(resumed = 0)
+ if (!resumed)
+ src.current_run = backed_up.Copy()
+
+ var/list/current_run = src.current_run
+ while(current_run.len)
+ var/name = current_run[current_run.len]
+ var/datum/transhuman/mind_record/curr_MR = current_run[name]
+ current_run -= name
+
+ //Invalid record
+ if(!curr_MR)
+ log_debug("Tried to process [name] in transcore w/o a record!")
+ backed_up -= name
+ continue
+
+ //Onetimes do not get processing or notifications
if(curr_MR.one_time)
continue
+
+ //Timing check
var/since_backup = world.time - curr_MR.last_update
if(since_backup < overdue_time)
curr_MR.dead_state = MR_NORMAL
else
if(curr_MR.dead_state != MR_DEAD) //First time switching to dead
- notify(N)
+ notify(name)
curr_MR.dead_state = MR_DEAD
-/datum/controller/subsystem/transcore/stat_entry(msg)
+ if(MC_TICK_CHECK)
+ return
+
+/datum/controller/subsystem/transcore/stat_entry()
+ var/msg = list()
if(core_dumped)
msg += "CORE DUMPED | "
- msg += "MR: [backed_up.len] | BR: [body_scans.len]"
- ..(msg)
+ msg += "$:{"
+ msg += "IM:[round(cost_implants,1)]|"
+ msg += "BK:[round(cost_backups,1)]"
+ msg += "} "
+ msg += "#:{"
+ msg += "IM:[implants.len]|"
+ msg += "BK:[backed_up.len]"
+ msg += "} "
+ ..(jointext(msg, null))
/datum/controller/subsystem/transcore/Recover()
if (istype(SStranscore.body_scans))
@@ -131,3 +197,6 @@ SUBSYSTEM_DEF(transcore)
core_dumped = TRUE
can_fire = FALSE
return disk.stored.len
+
+#undef SSTRANSCORE_BACKUPS
+#undef SSTRANSCORE_IMPLANTS
\ No newline at end of file
diff --git a/code/datums/EPv2.dm b/code/datums/EPv2.dm
index 37a1a0ba1f..a41175f424 100644
--- a/code/datums/EPv2.dm
+++ b/code/datums/EPv2.dm
@@ -40,6 +40,10 @@ var/global/list/all_exonet_connections = list()
src.holder = holder
..()
+/datum/exonet_protocol/Destroy()
+ remove_address()
+ holder = null
+ return ..()
// Proc: make_address()
// Parameters: 1 (string - used to make into a hash that will be part of the new address)
diff --git a/code/datums/mixed.dm b/code/datums/mixed.dm
index ab53596d8c..191868e489 100644
--- a/code/datums/mixed.dm
+++ b/code/datums/mixed.dm
@@ -34,8 +34,7 @@
data_core.medical -= src
data_core.general -= src
data_core.security -= src
- ..()
- return QDEL_HINT_FINDREFERENCE // If we must, we can resort to QDEL_HINT_HARDDEL. But lets see how this works in practice ~Leshana
+ . = ..()
/datum/data/text
name = "text"
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index bed0f33275..afcb65a8c1 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -22,8 +22,10 @@
/datum/progressbar/Destroy()
if (client)
client.images -= bar
- qdel(bar)
- . = ..()
+ qdel_null(bar)
+ user = null
+ client = null
+ return ..()
/datum/progressbar/proc/update(progress)
//world << "Update [progress] - [goal] - [(progress / goal)] - [((progress / goal) * 100)] - [round(((progress / goal) * 100), 5)]"
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index cac80c84d0..f809bcb9b2 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -287,17 +287,20 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
to_chat(voice, "\icon[src] Connection timed out with remote host.")
qdel(voice)
close_connection(reason = "Connection timed out")
+
+ //Clean up all references we might have to others
communicating.Cut()
voice_requests.Cut()
voice_invites.Cut()
+ node = null
+
+ //Clean up references that might point at us
all_communicators -= src
processing_objects -= src
listening_objects.Remove(src)
- qdel(camera)
- camera = null
- if(exonet)
- exonet.remove_address()
- exonet = null
+ qdel_null(camera)
+ qdel_null(exonet)
+
return ..()
// Proc: update_icon()
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 1d515e863b..d28779fc08 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -52,7 +52,9 @@
/obj/item/weapon/implant/Destroy()
if(part)
part.implants.Remove(src)
+ listening_objects.Remove(src)
part = null
+ imp_in = null
return ..()
/obj/item/weapon/implant/attackby(obj/item/I, mob/user)
@@ -82,7 +84,6 @@
/obj/item/weapon/implant/tracking/implanted(var/mob/source)
processing_objects.Add(src)
- listening_objects |= src
return 1
/obj/item/weapon/implant/tracking/Destroy()
diff --git a/code/modules/mob/login_vr.dm b/code/modules/mob/login_vr.dm
index a9ce4bd51d..ac2344d5c6 100644
--- a/code/modules/mob/login_vr.dm
+++ b/code/modules/mob/login_vr.dm
@@ -4,3 +4,6 @@
if(viewing_alternate_appearances && viewing_alternate_appearances.len)
for(var/datum/alternate_appearance/AA in viewing_alternate_appearances)
AA.display_to(list(src))
+
+ var/obj/screen/plane_master/augmented/aug = plane_holder.plane_masters[VIS_AUGMENTED]
+ aug.apply()
diff --git a/code/modules/mob/mob_planes.dm b/code/modules/mob/mob_planes.dm
index 048992c380..1252ed6649 100644
--- a/code/modules/mob/mob_planes.dm
+++ b/code/modules/mob/mob_planes.dm
@@ -94,6 +94,9 @@
var/invis_toggle = FALSE
var/list/sub_planes
+/obj/screen/plane_master/New()
+ ..(null) //Never be in anything ever.
+
/obj/screen/plane_master/proc/set_desired_alpha(var/new_alpha)
if(new_alpha != alpha && new_alpha > 0 && new_alpha <= 255)
desired_alpha = new_alpha
diff --git a/code/modules/mob/mob_planes_vr.dm b/code/modules/mob/mob_planes_vr.dm
index 2ea9d49cc4..5d41209b19 100644
--- a/code/modules/mob/mob_planes_vr.dm
+++ b/code/modules/mob/mob_planes_vr.dm
@@ -5,7 +5,7 @@
plane_masters[VIS_CH_BACKUP] = new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
plane_masters[VIS_CH_VANTAG] = new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
- plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(null,my_mob) //Augmented reality
+ plane_masters[VIS_AUGMENTED] = new /obj/screen/plane_master/augmented(my_mob) //Augmented reality
/////////////////
//AR planemaster does some special image handling
@@ -14,13 +14,11 @@
var/state = FALSE //Saves cost with the lists
var/mob/my_mob
-/obj/screen/plane_master/augmented/New(var/newloc, var/mob/M)
- ..(newloc)
+/obj/screen/plane_master/augmented/New(var/mob/M)
+ ..()
my_mob = M
- logged_in_event.register(my_mob,src,/obj/screen/plane_master/augmented/proc/apply)
/obj/screen/plane_master/augmented/Destroy()
- logged_in_event.unregister(my_mob,src)
my_mob = null
return ..()
diff --git a/code/modules/nano/modules/nano_module.dm b/code/modules/nano/modules/nano_module.dm
index 0cdf451d6f..8ced14f4c5 100644
--- a/code/modules/nano/modules/nano_module.dm
+++ b/code/modules/nano/modules/nano_module.dm
@@ -5,6 +5,10 @@
/datum/nano_module/New(var/host)
src.host = host
+/datum/nano_module/Destroy()
+ host = null
+ return ..()
+
/datum/nano_module/nano_host()
return host ? host : src
diff --git a/code/modules/nifsoft/software/14_commlink.dm b/code/modules/nifsoft/software/14_commlink.dm
index f6a1f567cd..158846ebcc 100644
--- a/code/modules/nifsoft/software/14_commlink.dm
+++ b/code/modules/nifsoft/software/14_commlink.dm
@@ -13,6 +13,10 @@
if((. = ..()))
nif.comm = new(nif,src)
+ uninstall()
+ if((. = ..()))
+ qdel_null(nif.comm)
+
activate()
if((. = ..()))
nif.comm.initialize_exonet(nif.human)
diff --git a/code/modules/resleeving/implant.dm b/code/modules/resleeving/implant.dm
index 389673cfa5..856e7bac2c 100644
--- a/code/modules/resleeving/implant.dm
+++ b/code/modules/resleeving/implant.dm
@@ -9,8 +9,6 @@
desc = "A mindstate backup implant that occasionally stores a copy of one's mind on a central server for backup purposes."
icon = 'icons/vore/custom_items_vr.dmi'
icon_state = "backup_implant"
- var/last_attempt
- var/attempt_delay = 5 MINUTES
/obj/item/weapon/implant/backup/get_data()
var/dat = {"
@@ -25,6 +23,10 @@
Integrity: Generally very survivable. Susceptible to being destroyed by acid."}
return dat
+/obj/item/weapon/implant/backup/Destroy()
+ SStranscore.implants -= src
+ return ..()
+
/obj/item/weapon/implant/backup/implanted(var/mob/living/carbon/human/H)
..()
if(istype(H))
@@ -32,29 +34,10 @@
if(other_imp && other_imp.imp_in == H)
qdel(other_imp) //implant fight
- if(H.mind && H.stat < DEAD) //One right now, on implanting.
- SStranscore.m_backup(H.mind)
- last_attempt = world.time
-
- backup()
+ SStranscore.implants |= src
return 1
-/obj/item/weapon/implant/backup/proc/backup()
- last_attempt = world.time
- var/mob/living/carbon/human/H = loc
-
- //We're in a human, at least.
- if(istype(H))
- BITSET(H.hud_updateflag, BACKUP_HUD)
- //Okay we've got a mind at least
- if(H == imp_in && H.mind && H.stat < DEAD)
- SStranscore.m_backup(H.mind,H.nif)
- persist_nif_data(H)
-
- spawn(attempt_delay)
- backup()
-
//New, modern implanter instead of old style implanter.
/obj/item/weapon/backup_implanter
name = "backup implanter"