mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-14 04:02:31 +00:00
Port of @PsiOmegaDelta's Baystation12/Baystation12#16820
Ports tg's garbage collector subsystem and Destroy() returning qdel hints.
This commit is contained in:
@@ -63,11 +63,11 @@
|
|||||||
return parent.return_network(reference)
|
return parent.return_network(reference)
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/Destroy()
|
/obj/machinery/atmospherics/pipe/Destroy()
|
||||||
qdel(parent)
|
qdel_null(parent)
|
||||||
if(air_temporary)
|
if(air_temporary)
|
||||||
loc.assume_air(air_temporary)
|
loc.assume_air(air_temporary)
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
/obj/machinery/atmospherics/pipe/attackby(var/obj/item/weapon/W as obj, var/mob/user as mob)
|
||||||
if (istype(src, /obj/machinery/atmospherics/pipe/tank))
|
if (istype(src, /obj/machinery/atmospherics/pipe/tank))
|
||||||
@@ -227,10 +227,12 @@
|
|||||||
/obj/machinery/atmospherics/pipe/simple/Destroy()
|
/obj/machinery/atmospherics/pipe/simple/Destroy()
|
||||||
if(node1)
|
if(node1)
|
||||||
node1.disconnect(src)
|
node1.disconnect(src)
|
||||||
|
node1 = null
|
||||||
if(node2)
|
if(node2)
|
||||||
node2.disconnect(src)
|
node2.disconnect(src)
|
||||||
|
node1 = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
|
/obj/machinery/atmospherics/pipe/simple/pipeline_expansion()
|
||||||
return list(node1, node2)
|
return list(node1, node2)
|
||||||
@@ -461,12 +463,15 @@
|
|||||||
/obj/machinery/atmospherics/pipe/manifold/Destroy()
|
/obj/machinery/atmospherics/pipe/manifold/Destroy()
|
||||||
if(node1)
|
if(node1)
|
||||||
node1.disconnect(src)
|
node1.disconnect(src)
|
||||||
|
node1 = null
|
||||||
if(node2)
|
if(node2)
|
||||||
node2.disconnect(src)
|
node2.disconnect(src)
|
||||||
|
node2 = null
|
||||||
if(node3)
|
if(node3)
|
||||||
node3.disconnect(src)
|
node3.disconnect(src)
|
||||||
|
node3 = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
|
/obj/machinery/atmospherics/pipe/manifold/disconnect(obj/machinery/atmospherics/reference)
|
||||||
if(reference == node1)
|
if(reference == node1)
|
||||||
@@ -705,14 +710,18 @@
|
|||||||
/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
|
/obj/machinery/atmospherics/pipe/manifold4w/Destroy()
|
||||||
if(node1)
|
if(node1)
|
||||||
node1.disconnect(src)
|
node1.disconnect(src)
|
||||||
|
node1 = null
|
||||||
if(node2)
|
if(node2)
|
||||||
node2.disconnect(src)
|
node2.disconnect(src)
|
||||||
|
node2 = null
|
||||||
if(node3)
|
if(node3)
|
||||||
node3.disconnect(src)
|
node3.disconnect(src)
|
||||||
|
node3 = null
|
||||||
if(node4)
|
if(node4)
|
||||||
node4.disconnect(src)
|
node4.disconnect(src)
|
||||||
|
node4 = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
|
/obj/machinery/atmospherics/pipe/manifold4w/disconnect(obj/machinery/atmospherics/reference)
|
||||||
if(reference == node1)
|
if(reference == node1)
|
||||||
@@ -967,8 +976,9 @@
|
|||||||
/obj/machinery/atmospherics/pipe/cap/Destroy()
|
/obj/machinery/atmospherics/pipe/cap/Destroy()
|
||||||
if(node)
|
if(node)
|
||||||
node.disconnect(src)
|
node.disconnect(src)
|
||||||
|
node = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
|
/obj/machinery/atmospherics/pipe/cap/disconnect(obj/machinery/atmospherics/reference)
|
||||||
if(reference == node)
|
if(reference == node)
|
||||||
@@ -1081,8 +1091,9 @@
|
|||||||
/obj/machinery/atmospherics/pipe/tank/Destroy()
|
/obj/machinery/atmospherics/pipe/tank/Destroy()
|
||||||
if(node1)
|
if(node1)
|
||||||
node1.disconnect(src)
|
node1.disconnect(src)
|
||||||
|
node1 = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
|
/obj/machinery/atmospherics/pipe/tank/pipeline_expansion()
|
||||||
return list(node1)
|
return list(node1)
|
||||||
@@ -1251,8 +1262,9 @@
|
|||||||
/obj/machinery/atmospherics/pipe/vent/Destroy()
|
/obj/machinery/atmospherics/pipe/vent/Destroy()
|
||||||
if(node1)
|
if(node1)
|
||||||
node1.disconnect(src)
|
node1.disconnect(src)
|
||||||
|
node1 = null
|
||||||
|
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
|
/obj/machinery/atmospherics/pipe/vent/pipeline_expansion()
|
||||||
return list(node1)
|
return list(node1)
|
||||||
|
|||||||
17
code/__defines/qdel.dm
Normal file
17
code/__defines/qdel.dm
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
//defines that give qdel hints. these can be given as a return in destory() or by calling
|
||||||
|
|
||||||
|
#define QDEL_HINT_QUEUE 0 //qdel should queue the object for deletion.
|
||||||
|
#define QDEL_HINT_LETMELIVE 1 //qdel should let the object live after calling destory.
|
||||||
|
#define QDEL_HINT_IWILLGC 2 //functionally the same as the above. qdel should assume the object will gc on its own, and not check it.
|
||||||
|
#define QDEL_HINT_HARDDEL 3 //qdel should assume this object won't gc, and queue a hard delete using a hard reference.
|
||||||
|
#define QDEL_HINT_HARDDEL_NOW 4 //qdel should assume this object won't gc, and hard del it post haste.
|
||||||
|
#define QDEL_HINT_FINDREFERENCE 5 //functionally identical to QDEL_HINT_QUEUE if TESTING is not enabled in _compiler_options.dm.
|
||||||
|
//if TESTING is enabled, qdel will call this object's find_references() verb.
|
||||||
|
//defines for the gc_destroyed var
|
||||||
|
|
||||||
|
#define GC_QUEUED_FOR_QUEUING -1
|
||||||
|
#define GC_QUEUED_FOR_HARD_DEL -2
|
||||||
|
#define GC_CURRENTLY_BEING_QDELETED -3
|
||||||
|
|
||||||
|
#define QDELETED(X) (!X || X.gc_destroyed)
|
||||||
|
#define QDESTROYING(X) (!X || X.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||||
@@ -228,7 +228,7 @@ Proc for attack log creation, because really why not
|
|||||||
. = 0
|
. = 0
|
||||||
break
|
break
|
||||||
|
|
||||||
if(target_loc && (!target || target_loc != target.loc))
|
if(target_loc && (QDELETED(target) || target_loc != target.loc))
|
||||||
. = 0
|
. = 0
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -387,6 +387,6 @@
|
|||||||
exceptions[eid] = 0
|
exceptions[eid] = 0
|
||||||
|
|
||||||
/datum/controller/process/proc/catchBadType(var/datum/caught)
|
/datum/controller/process/proc/catchBadType(var/datum/caught)
|
||||||
if(isnull(caught) || !istype(caught) || !isnull(caught.gcDestroyed))
|
if(isnull(caught) || !istype(caught) || QDELETED(caught))
|
||||||
return // Only bother with types we can identify and that don't belong
|
return // Only bother with types we can identify and that don't belong
|
||||||
catchException("Type [caught.type] does not belong in process' queue")
|
catchException("Type [caught.type] does not belong in process' queue")
|
||||||
|
|||||||
@@ -1,254 +0,0 @@
|
|||||||
// The time a datum was destroyed by the GC, or null if it hasn't been
|
|
||||||
/datum/var/gcDestroyed
|
|
||||||
|
|
||||||
#define GC_COLLECTIONS_PER_RUN 300
|
|
||||||
#define GC_COLLECTION_TIMEOUT (30 SECONDS)
|
|
||||||
#define GC_FORCE_DEL_PER_RUN 30
|
|
||||||
|
|
||||||
var/datum/controller/process/garbage_collector/garbage_collector
|
|
||||||
var/list/delayed_garbage = list()
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector
|
|
||||||
var/garbage_collect = 1 // Whether or not to actually do work
|
|
||||||
var/total_dels = 0 // number of total del()'s
|
|
||||||
var/tick_dels = 0 // number of del()'s we've done this tick
|
|
||||||
var/soft_dels = 0
|
|
||||||
var/hard_dels = 0 // number of hard dels in total
|
|
||||||
var/list/destroyed = list() // list of refID's of things that should be garbage collected
|
|
||||||
// refID's are associated with the time at which they time out and need to be manually del()
|
|
||||||
// we do this so we aren't constantly locating them and preventing them from being gc'd
|
|
||||||
|
|
||||||
var/list/logging = list() // list of all types that have failed to GC associated with the number of times that's happened.
|
|
||||||
// the types are stored as strings
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/setup()
|
|
||||||
name = "garbage"
|
|
||||||
schedule_interval = 5 SECONDS
|
|
||||||
start_delay = 3
|
|
||||||
|
|
||||||
if(!garbage_collector)
|
|
||||||
garbage_collector = src
|
|
||||||
|
|
||||||
for(var/garbage in delayed_garbage)
|
|
||||||
qdel(garbage)
|
|
||||||
delayed_garbage.Cut()
|
|
||||||
delayed_garbage = null
|
|
||||||
|
|
||||||
#ifdef GC_FINDREF
|
|
||||||
world/loop_checks = 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/doWork()
|
|
||||||
if(!garbage_collect)
|
|
||||||
return
|
|
||||||
|
|
||||||
tick_dels = 0
|
|
||||||
var/time_to_kill = world.time - GC_COLLECTION_TIMEOUT
|
|
||||||
var/checkRemain = GC_COLLECTIONS_PER_RUN
|
|
||||||
var/remaining_force_dels = GC_FORCE_DEL_PER_RUN
|
|
||||||
|
|
||||||
|
|
||||||
while(destroyed.len && --checkRemain >= 0)
|
|
||||||
if(remaining_force_dels <= 0)
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
testing("GC: Reached max force dels per tick [dels] vs [maxDels]")
|
|
||||||
#endif
|
|
||||||
break // Server's already pretty pounded, everything else can wait 2 seconds
|
|
||||||
var/refID = destroyed[1]
|
|
||||||
var/GCd_at_time = destroyed[refID]
|
|
||||||
if(GCd_at_time > time_to_kill)
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
testing("GC: [refID] not old enough, breaking at [world.time] for [GCd_at_time - time_to_kill] deciseconds until [GCd_at_time + collection_timeout]")
|
|
||||||
#endif
|
|
||||||
break // Everything else is newer, skip them
|
|
||||||
var/datum/A = locate(refID)
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
testing("GC: [refID] old enough to test: GCd_at_time: [GCd_at_time] time_to_kill: [time_to_kill] current: [world.time]")
|
|
||||||
#endif
|
|
||||||
if(A && A.gcDestroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake
|
|
||||||
// Something's still referring to the qdel'd object. Kill it.
|
|
||||||
testing("GC: -- \ref[A] | [A.type] was unable to be GC'd and was deleted --")
|
|
||||||
logging["[A.type]"]++
|
|
||||||
del(A)
|
|
||||||
|
|
||||||
hard_dels++
|
|
||||||
remaining_force_dels--
|
|
||||||
else
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
testing("GC: [refID] properly GC'd at [world.time] with timeout [GCd_at_time]")
|
|
||||||
#endif
|
|
||||||
soft_dels++
|
|
||||||
tick_dels++
|
|
||||||
total_dels++
|
|
||||||
destroyed.Cut(1, 2)
|
|
||||||
SCHECK
|
|
||||||
|
|
||||||
#undef GC_FORCE_DEL_PER_TICK
|
|
||||||
#undef GC_COLLECTION_TIMEOUT
|
|
||||||
#undef GC_COLLECTIONS_PER_TICK
|
|
||||||
|
|
||||||
#ifdef GC_FINDREF
|
|
||||||
/datum/controller/process/garbage_collector/proc/LookForRefs(var/datum/D, var/list/targ)
|
|
||||||
. = 0
|
|
||||||
for(var/V in D.vars)
|
|
||||||
if(V == "contents")
|
|
||||||
continue
|
|
||||||
if(istype(D.vars[V], /atom))
|
|
||||||
var/atom/A = D.vars[V]
|
|
||||||
if(A in targ)
|
|
||||||
testing("GC: [A] | [A.type] referenced by [D] | [D.type], var [V]")
|
|
||||||
. += 1
|
|
||||||
else if(islist(D.vars[V]))
|
|
||||||
. += LookForListRefs(D.vars[V], targ, D, V)
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/proc/LookForListRefs(var/list/L, var/list/targ, var/datum/D, var/V)
|
|
||||||
. = 0
|
|
||||||
for(var/F in L)
|
|
||||||
if(istype(F, /atom))
|
|
||||||
var/atom/A = F
|
|
||||||
if(A in targ)
|
|
||||||
testing("GC: [A] | [A.type] referenced by [D] | [D.type], list [V]")
|
|
||||||
. += 1
|
|
||||||
if(islist(F))
|
|
||||||
. += LookForListRefs(F, targ, D, "[F] in list [V]")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/proc/AddTrash(datum/A)
|
|
||||||
if(!istype(A) || !isnull(A.gcDestroyed))
|
|
||||||
return
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
testing("GC: AddTrash(\ref[A] - [A.type])")
|
|
||||||
#endif
|
|
||||||
A.gcDestroyed = world.time
|
|
||||||
destroyed -= "\ref[A]" // Removing any previous references that were GC'd so that the current object will be at the end of the list.
|
|
||||||
destroyed["\ref[A]"] = world.time
|
|
||||||
|
|
||||||
/datum/controller/process/garbage_collector/statProcess()
|
|
||||||
..()
|
|
||||||
stat(null, "[garbage_collect ? "On" : "Off"], [destroyed.len] queued")
|
|
||||||
stat(null, "Dels: [total_dels], [soft_dels] soft, [hard_dels] hard, [tick_dels] last run")
|
|
||||||
|
|
||||||
|
|
||||||
// Tests if an atom has been deleted.
|
|
||||||
/proc/deleted(atom/A)
|
|
||||||
return !A || !isnull(A.gcDestroyed)
|
|
||||||
|
|
||||||
// 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(var/datum/A)
|
|
||||||
if(!A)
|
|
||||||
return
|
|
||||||
if(!istype(A))
|
|
||||||
warning("qdel() passed object of type [A.type]. qdel() can only handle /datum types.")
|
|
||||||
crash_with("qdel() passed object of type [A.type]. qdel() can only handle /datum types.")
|
|
||||||
del(A)
|
|
||||||
if(garbage_collector)
|
|
||||||
garbage_collector.total_dels++
|
|
||||||
garbage_collector.hard_dels++
|
|
||||||
else if(isnull(A.gcDestroyed))
|
|
||||||
// Let our friend know they're about to get collected
|
|
||||||
. = !A.Destroy()
|
|
||||||
if(. && A)
|
|
||||||
A.finalize_qdel()
|
|
||||||
|
|
||||||
/datum/proc/finalize_qdel()
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
/atom/finalize_qdel()
|
|
||||||
if(garbage_collector)
|
|
||||||
garbage_collector.AddTrash(src)
|
|
||||||
else
|
|
||||||
delayed_garbage |= src
|
|
||||||
|
|
||||||
/icon/finalize_qdel()
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
/image/finalize_qdel()
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
/mob/finalize_qdel()
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
/turf/finalize_qdel()
|
|
||||||
del(src)
|
|
||||||
|
|
||||||
// Default implementation of clean-up code.
|
|
||||||
// This should be overridden to remove all references pointing to the object being destroyed.
|
|
||||||
// Return true if the the GC controller should allow the object to continue existing.
|
|
||||||
/datum/proc/Destroy()
|
|
||||||
nanomanager.close_uis(src)
|
|
||||||
tag = null
|
|
||||||
return
|
|
||||||
|
|
||||||
#ifdef TESTING
|
|
||||||
/client/var/running_find_references
|
|
||||||
|
|
||||||
/mob/verb/create_thing()
|
|
||||||
set category = "Debug"
|
|
||||||
set name = "Create Thing"
|
|
||||||
|
|
||||||
var/path = input("Enter path")
|
|
||||||
var/atom/thing = new path(loc)
|
|
||||||
thing.find_references()
|
|
||||||
|
|
||||||
/atom/verb/find_references()
|
|
||||||
set category = "Debug"
|
|
||||||
set name = "Find References"
|
|
||||||
set background = 1
|
|
||||||
set src in world
|
|
||||||
|
|
||||||
if(!usr || !usr.client)
|
|
||||||
return
|
|
||||||
|
|
||||||
if(usr.client.running_find_references)
|
|
||||||
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
|
||||||
usr.client.running_find_references = null
|
|
||||||
return
|
|
||||||
|
|
||||||
if(alert("Running this will create a lot of lag until it finishes. You can cancel it by running it again. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
|
||||||
return
|
|
||||||
|
|
||||||
// Remove this object from the list of things to be auto-deleted.
|
|
||||||
if(garbage_collector)
|
|
||||||
garbage_collector.destroyed -= "\ref[src]"
|
|
||||||
|
|
||||||
usr.client.running_find_references = type
|
|
||||||
testing("Beginning search for references to a [type].")
|
|
||||||
var/list/things = list()
|
|
||||||
for(var/client/thing)
|
|
||||||
things += thing
|
|
||||||
for(var/datum/thing)
|
|
||||||
things += thing
|
|
||||||
for(var/atom/thing)
|
|
||||||
things += thing
|
|
||||||
testing("Collected list of things in search for references to a [type]. ([things.len] Thing\s)")
|
|
||||||
for(var/datum/thing in things)
|
|
||||||
if(!usr.client.running_find_references) return
|
|
||||||
for(var/varname in thing.vars)
|
|
||||||
var/variable = thing.vars[varname]
|
|
||||||
if(variable == src)
|
|
||||||
testing("Found [src.type] \ref[src] in [thing.type]'s [varname] var.")
|
|
||||||
else if(islist(variable))
|
|
||||||
if(src in variable)
|
|
||||||
testing("Found [src.type] \ref[src] in [thing.type]'s [varname] list var.")
|
|
||||||
testing("Completed search for references to a [type].")
|
|
||||||
usr.client.running_find_references = null
|
|
||||||
|
|
||||||
/client/verb/purge_all_destroyed_objects()
|
|
||||||
set category = "Debug"
|
|
||||||
if(garbage_collector)
|
|
||||||
while(garbage_collector.destroyed.len)
|
|
||||||
var/datum/o = locate(garbage_collector.destroyed[1])
|
|
||||||
if(istype(o) && o.gcDestroyed)
|
|
||||||
del(o)
|
|
||||||
garbage_collector.dels++
|
|
||||||
garbage_collector.destroyed.Cut(1, 2)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GC_DEBUG
|
|
||||||
#undef GC_DEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef GC_FINDREF
|
|
||||||
#undef GC_FINDREF
|
|
||||||
#endif
|
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
/datum/controller/process/machinery/proc/internal_process_machinery()
|
/datum/controller/process/machinery/proc/internal_process_machinery()
|
||||||
for(last_object in machines)
|
for(last_object in machines)
|
||||||
var/obj/machinery/M = last_object
|
var/obj/machinery/M = last_object
|
||||||
if(M && !M.gcDestroyed)
|
if(M && !QDELETED(M))
|
||||||
if(M.process() == PROCESS_KILL)
|
if(M.process() == PROCESS_KILL)
|
||||||
//M.inMachineList = 0 We don't use this debugging function
|
//M.inMachineList = 0 We don't use this debugging function
|
||||||
machines.Remove(M)
|
machines.Remove(M)
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
/datum/controller/process/machinery/proc/internal_process_power()
|
/datum/controller/process/machinery/proc/internal_process_power()
|
||||||
for(last_object in powernets)
|
for(last_object in powernets)
|
||||||
var/datum/powernet/powerNetwork = last_object
|
var/datum/powernet/powerNetwork = last_object
|
||||||
if(istype(powerNetwork) && isnull(powerNetwork.gcDestroyed))
|
if(istype(powerNetwork) && !QDELETED(powerNetwork))
|
||||||
powerNetwork.reset()
|
powerNetwork.reset()
|
||||||
SCHECK
|
SCHECK
|
||||||
continue
|
continue
|
||||||
@@ -52,7 +52,7 @@
|
|||||||
/datum/controller/process/machinery/proc/internal_process_pipenets()
|
/datum/controller/process/machinery/proc/internal_process_pipenets()
|
||||||
for(last_object in pipe_networks)
|
for(last_object in pipe_networks)
|
||||||
var/datum/pipe_network/pipeNetwork = last_object
|
var/datum/pipe_network/pipeNetwork = last_object
|
||||||
if(istype(pipeNetwork) && isnull(pipeNetwork.gcDestroyed))
|
if(istype(pipeNetwork) && !QDELETED(pipeNetwork))
|
||||||
pipeNetwork.process()
|
pipeNetwork.process()
|
||||||
SCHECK
|
SCHECK
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -14,7 +14,7 @@
|
|||||||
/datum/controller/process/mob/doWork()
|
/datum/controller/process/mob/doWork()
|
||||||
for(last_object in mob_list)
|
for(last_object in mob_list)
|
||||||
var/mob/M = last_object
|
var/mob/M = last_object
|
||||||
if(M && isnull(M.gcDestroyed))
|
if(M && !QDELETED(M))
|
||||||
try
|
try
|
||||||
M.Life()
|
M.Life()
|
||||||
catch(var/exception/e)
|
catch(var/exception/e)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
/datum/controller/process/nanoui/doWork()
|
/datum/controller/process/nanoui/doWork()
|
||||||
for(last_object in nanomanager.processing_uis)
|
for(last_object in nanomanager.processing_uis)
|
||||||
var/datum/nanoui/NUI = last_object
|
var/datum/nanoui/NUI = last_object
|
||||||
if(istype(NUI) && isnull(NUI.gcDestroyed))
|
if(istype(NUI) && !QDELETED(NUI))
|
||||||
try
|
try
|
||||||
NUI.process()
|
NUI.process()
|
||||||
catch(var/exception/e)
|
catch(var/exception/e)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
/datum/controller/process/obj/doWork()
|
/datum/controller/process/obj/doWork()
|
||||||
for(last_object in processing_objects)
|
for(last_object in processing_objects)
|
||||||
var/datum/O = last_object
|
var/datum/O = last_object
|
||||||
if(O && isnull(O.gcDestroyed))
|
if(!QDELETED(O))
|
||||||
try
|
try
|
||||||
O:process()
|
O:process()
|
||||||
catch(var/exception/e)
|
catch(var/exception/e)
|
||||||
|
|||||||
@@ -30,8 +30,8 @@
|
|||||||
// Note: We won't be informed about tasks being destroyed, but this is the best we can do.
|
// Note: We won't be informed about tasks being destroyed, but this is the best we can do.
|
||||||
/datum/controller/process/scheduler/copyStateFrom(var/datum/controller/process/scheduler/target)
|
/datum/controller/process/scheduler/copyStateFrom(var/datum/controller/process/scheduler/target)
|
||||||
scheduled_tasks = list()
|
scheduled_tasks = list()
|
||||||
for(var/st in target.scheduled_tasks)
|
for(var/datum/scheduled_task/st in target.scheduled_tasks)
|
||||||
if(!deleted(st) && istype(st, /datum/scheduled_task))
|
if(!QDELETED(st) && istype(st))
|
||||||
schedule(st)
|
schedule(st)
|
||||||
scheduler = src
|
scheduler = src
|
||||||
|
|
||||||
|
|||||||
@@ -33,13 +33,13 @@ var/datum/controller/failsafe/Failsafe
|
|||||||
/datum/controller/failsafe/Initialize()
|
/datum/controller/failsafe/Initialize()
|
||||||
set waitfor = 0
|
set waitfor = 0
|
||||||
Failsafe.Loop()
|
Failsafe.Loop()
|
||||||
if(!deleted(src))
|
if(!QDELETED(src))
|
||||||
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
|
qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us
|
||||||
|
|
||||||
/datum/controller/failsafe/Destroy()
|
/datum/controller/failsafe/Destroy()
|
||||||
running = FALSE
|
running = FALSE
|
||||||
..()
|
..()
|
||||||
// return QDEL_HINT_HARDDEL_NOW // TODO - Once we port garbage.dm
|
return QDEL_HINT_HARDDEL_NOW
|
||||||
|
|
||||||
/datum/controller/failsafe/proc/Loop()
|
/datum/controller/failsafe/proc/Loop()
|
||||||
while(running)
|
while(running)
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ var/CURRENT_TICKLIMIT = TICK_LIMIT_RUNNING
|
|||||||
/datum/controller/master/Destroy()
|
/datum/controller/master/Destroy()
|
||||||
..()
|
..()
|
||||||
// Tell qdel() to Del() this object.
|
// Tell qdel() to Del() this object.
|
||||||
// return QDEL_HINT_HARDDEL_NOW // TODO - Once we port garbage.dm
|
return QDEL_HINT_HARDDEL_NOW
|
||||||
|
|
||||||
/datum/controller/master/Shutdown()
|
/datum/controller/master/Shutdown()
|
||||||
processing = FALSE
|
processing = FALSE
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ datum/controller/game_controller/proc/setup_objects()
|
|||||||
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
|
admin_notice("<span class='danger'>Initializing objects</span>", R_DEBUG)
|
||||||
sleep(-1)
|
sleep(-1)
|
||||||
for(var/atom/movable/object in world)
|
for(var/atom/movable/object in world)
|
||||||
if(isnull(object.gcDestroyed))
|
if(!QDELETED(object))
|
||||||
object.initialize()
|
object.initialize()
|
||||||
|
|
||||||
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
|
admin_notice("<span class='danger'>Initializing areas</span>", R_DEBUG)
|
||||||
@@ -80,8 +80,8 @@ datum/controller/game_controller/proc/setup_objects()
|
|||||||
|
|
||||||
admin_notice("<span class='danger'>Initializing turbolifts</span>", R_DEBUG)
|
admin_notice("<span class='danger'>Initializing turbolifts</span>", R_DEBUG)
|
||||||
for(var/thing in turbolifts)
|
for(var/thing in turbolifts)
|
||||||
if(!deleted(thing))
|
|
||||||
var/obj/turbolift_map_holder/lift = thing
|
var/obj/turbolift_map_holder/lift = thing
|
||||||
|
if(!QDELETED(lift))
|
||||||
lift.initialize()
|
lift.initialize()
|
||||||
sleep(-1)
|
sleep(-1)
|
||||||
|
|
||||||
|
|||||||
354
code/controllers/subsystems/garbage.dm
Normal file
354
code/controllers/subsystems/garbage.dm
Normal file
@@ -0,0 +1,354 @@
|
|||||||
|
var/datum/controller/subsystem/garbage_collector/SSgarbage
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector
|
||||||
|
name = "Garbage"
|
||||||
|
priority = 15
|
||||||
|
wait = 5
|
||||||
|
flags = SS_FIRE_IN_LOBBY|SS_POST_FIRE_TIMING|SS_BACKGROUND|SS_NO_INIT
|
||||||
|
|
||||||
|
var/collection_timeout = 3000// deciseconds to wait to let running procs finish before we just say fuck it and force del() the object
|
||||||
|
var/delslasttick = 0 // number of del()'s we've done this tick
|
||||||
|
var/gcedlasttick = 0 // number of things that gc'ed last tick
|
||||||
|
var/totaldels = 0
|
||||||
|
var/totalgcs = 0
|
||||||
|
|
||||||
|
var/highest_del_time = 0
|
||||||
|
var/highest_del_tickusage = 0
|
||||||
|
|
||||||
|
var/list/queue = list() // list of refID's of things that should be garbage collected
|
||||||
|
// refID's are associated with the time at which they time out and need to be manually del()
|
||||||
|
// we do this so we aren't constantly locating them and preventing them from being gc'd
|
||||||
|
|
||||||
|
var/list/tobequeued = list() //We store the references of things to be added to the queue seperately so we can spread out GC overhead over a few ticks
|
||||||
|
|
||||||
|
var/list/didntgc = list() // list of all types that have failed to GC associated with the number of times that's happened.
|
||||||
|
// the types are stored as strings
|
||||||
|
var/list/sleptDestroy = list() //Same as above but these are paths that slept during their Destroy call
|
||||||
|
|
||||||
|
var/list/noqdelhint = list()// list of all types that do not return a QDEL_HINT
|
||||||
|
// all types that did not respect qdel(A, force=TRUE) and returned one
|
||||||
|
// of the immortality qdel hints
|
||||||
|
var/list/noforcerespect = list()
|
||||||
|
|
||||||
|
#ifdef TESTING
|
||||||
|
var/list/qdel_list = list() // list of all types that have been qdel()eted
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/New()
|
||||||
|
NEW_SS_GLOBAL(SSgarbage)
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/stat_entry(msg)
|
||||||
|
msg += "Q:[queue.len]|D:[delslasttick]|G:[gcedlasttick]|"
|
||||||
|
msg += "GR:"
|
||||||
|
if (!(delslasttick+gcedlasttick))
|
||||||
|
msg += "n/a|"
|
||||||
|
else
|
||||||
|
msg += "[round((gcedlasttick/(delslasttick+gcedlasttick))*100, 0.01)]%|"
|
||||||
|
|
||||||
|
msg += "TD:[totaldels]|TG:[totalgcs]|"
|
||||||
|
if (!(totaldels+totalgcs))
|
||||||
|
msg += "n/a|"
|
||||||
|
else
|
||||||
|
msg += "TGR:[round((totalgcs/(totaldels+totalgcs))*100, 0.01)]%"
|
||||||
|
..(msg)
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/fire()
|
||||||
|
HandleToBeQueued()
|
||||||
|
if(state == SS_RUNNING)
|
||||||
|
HandleQueue()
|
||||||
|
|
||||||
|
//If you see this proc high on the profile, what you are really seeing is the garbage collection/soft delete overhead in byond.
|
||||||
|
//Don't attempt to optimize, not worth the effort.
|
||||||
|
/datum/controller/subsystem/garbage_collector/proc/HandleToBeQueued()
|
||||||
|
var/list/tobequeued = src.tobequeued
|
||||||
|
var/starttime = world.time
|
||||||
|
var/starttimeofday = world.timeofday
|
||||||
|
while(tobequeued.len && starttime == world.time && starttimeofday == world.timeofday)
|
||||||
|
if (MC_TICK_CHECK)
|
||||||
|
break
|
||||||
|
var/ref = tobequeued[1]
|
||||||
|
Queue(ref)
|
||||||
|
tobequeued.Cut(1, 2)
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/proc/HandleQueue()
|
||||||
|
delslasttick = 0
|
||||||
|
gcedlasttick = 0
|
||||||
|
var/time_to_kill = world.time - collection_timeout // Anything qdel() but not GC'd BEFORE this time needs to be manually del()
|
||||||
|
var/list/queue = src.queue
|
||||||
|
var/starttime = world.time
|
||||||
|
var/starttimeofday = world.timeofday
|
||||||
|
while(queue.len && starttime == world.time && starttimeofday == world.timeofday)
|
||||||
|
if (MC_TICK_CHECK)
|
||||||
|
break
|
||||||
|
var/refID = queue[1]
|
||||||
|
if (!refID)
|
||||||
|
queue.Cut(1, 2)
|
||||||
|
continue
|
||||||
|
|
||||||
|
var/GCd_at_time = queue[refID]
|
||||||
|
if(GCd_at_time > time_to_kill)
|
||||||
|
break // Everything else is newer, skip them
|
||||||
|
queue.Cut(1, 2)
|
||||||
|
var/datum/A
|
||||||
|
A = locate(refID)
|
||||||
|
if (A && A.gc_destroyed == GCd_at_time) // So if something else coincidently gets the same ref, it's not deleted by mistake
|
||||||
|
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||||
|
A.find_references()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Something's still referring to the qdel'd object. Kill it.
|
||||||
|
var/type = A.type
|
||||||
|
testing("GC: -- \ref[A] | [type] was unable to be GC'd and was deleted --")
|
||||||
|
didntgc["[type]"]++
|
||||||
|
var/time = world.timeofday
|
||||||
|
var/tick = world.tick_usage
|
||||||
|
var/ticktime = world.time
|
||||||
|
del(A)
|
||||||
|
tick = (world.tick_usage-tick+((world.time-ticktime)/world.tick_lag*100))
|
||||||
|
|
||||||
|
if (tick > highest_del_tickusage)
|
||||||
|
highest_del_tickusage = tick
|
||||||
|
time = world.timeofday - time
|
||||||
|
if (!time && TICK_DELTA_TO_MS(tick) > 1)
|
||||||
|
time = TICK_DELTA_TO_MS(tick)/100
|
||||||
|
if (time > highest_del_time)
|
||||||
|
highest_del_time = time
|
||||||
|
if (time > 10)
|
||||||
|
log_game("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete)")
|
||||||
|
message_admins("Error: [type]([refID]) took longer then 1 second to delete (took [time/10] seconds to delete).")
|
||||||
|
postpone(time/5)
|
||||||
|
break
|
||||||
|
++delslasttick
|
||||||
|
++totaldels
|
||||||
|
else
|
||||||
|
++gcedlasttick
|
||||||
|
++totalgcs
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/proc/QueueForQueuing(datum/A)
|
||||||
|
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||||
|
tobequeued += A
|
||||||
|
A.gc_destroyed = GC_QUEUED_FOR_QUEUING
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/proc/Queue(datum/A)
|
||||||
|
if (!istype(A) || (!isnull(A.gc_destroyed) && A.gc_destroyed >= 0))
|
||||||
|
return
|
||||||
|
if (A.gc_destroyed == GC_QUEUED_FOR_HARD_DEL)
|
||||||
|
del(A)
|
||||||
|
return
|
||||||
|
var/gctime = world.time
|
||||||
|
var/refid = "\ref[A]"
|
||||||
|
|
||||||
|
A.gc_destroyed = gctime
|
||||||
|
|
||||||
|
if (queue[refid])
|
||||||
|
queue -= refid // Removing any previous references that were GC'd so that the current object will be at the end of the list.
|
||||||
|
|
||||||
|
queue[refid] = gctime
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/proc/HardQueue(datum/A)
|
||||||
|
if (istype(A) && A.gc_destroyed == GC_CURRENTLY_BEING_QDELETED)
|
||||||
|
tobequeued += A
|
||||||
|
A.gc_destroyed = GC_QUEUED_FOR_HARD_DEL
|
||||||
|
|
||||||
|
/datum/controller/subsystem/garbage_collector/Recover()
|
||||||
|
if (istype(SSgarbage.queue))
|
||||||
|
queue |= SSgarbage.queue
|
||||||
|
if (istype(SSgarbage.tobequeued))
|
||||||
|
tobequeued |= SSgarbage.tobequeued
|
||||||
|
|
||||||
|
// 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(!D)
|
||||||
|
return
|
||||||
|
#ifdef TESTING
|
||||||
|
SSgarbage.qdel_list += D.type
|
||||||
|
#endif
|
||||||
|
if(!istype(D))
|
||||||
|
log_debug("qdel() was passed [log_info_line(D)]. qdel() can only handle instances of (sub)type /datum.")
|
||||||
|
del(D)
|
||||||
|
else if(isnull(D.gc_destroyed))
|
||||||
|
D.gc_destroyed = GC_CURRENTLY_BEING_QDELETED
|
||||||
|
var/start_time = world.time
|
||||||
|
var/hint = D.Destroy(force) // Let our friend know they're about to get fucked up.
|
||||||
|
if(world.time != start_time)
|
||||||
|
SSgarbage.sleptDestroy[D.type]++
|
||||||
|
if(!D)
|
||||||
|
return
|
||||||
|
switch(hint)
|
||||||
|
if (QDEL_HINT_QUEUE) //qdel should queue the object for deletion.
|
||||||
|
SSgarbage.QueueForQueuing(D)
|
||||||
|
if (QDEL_HINT_IWILLGC)
|
||||||
|
D.gc_destroyed = world.time
|
||||||
|
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
|
||||||
|
if(!SSgarbage.noforcerespect[D.type])
|
||||||
|
SSgarbage.noforcerespect[D.type] = D.type
|
||||||
|
crash_with("[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.")
|
||||||
|
SSgarbage.QueueForQueuing(D)
|
||||||
|
if (QDEL_HINT_HARDDEL) //qdel should assume this object won't gc, and queue a hard delete using a hard reference to save time from the locate()
|
||||||
|
SSgarbage.HardQueue(D)
|
||||||
|
if (QDEL_HINT_HARDDEL_NOW) //qdel should assume this object won't gc, and hard del it post haste.
|
||||||
|
del(D)
|
||||||
|
if (QDEL_HINT_FINDREFERENCE)//qdel will, if TESTING is enabled, display all references to this object, then queue the object for deletion.
|
||||||
|
SSgarbage.QueueForQueuing(D)
|
||||||
|
#ifdef TESTING
|
||||||
|
D.find_references()
|
||||||
|
#endif
|
||||||
|
else
|
||||||
|
if(!SSgarbage.noqdelhint[D.type])
|
||||||
|
SSgarbage.noqdelhint[D.type] = D.type
|
||||||
|
crash_with("[D.type] is not returning a qdel hint. It is being placed in the queue. Further instances of this type will also be queued.")
|
||||||
|
SSgarbage.QueueForQueuing(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")
|
||||||
|
|
||||||
|
// Default implementation of clean-up code.
|
||||||
|
// This should be overridden to remove all references pointing to the object being destroyed.
|
||||||
|
// Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE.
|
||||||
|
/datum/proc/Destroy(force=FALSE)
|
||||||
|
tag = null
|
||||||
|
nanomanager.close_uis(src)
|
||||||
|
return QDEL_HINT_QUEUE
|
||||||
|
|
||||||
|
/datum/var/gc_destroyed //Time when this object was destroyed.
|
||||||
|
|
||||||
|
#ifdef TESTING
|
||||||
|
/datum/var/running_find_references
|
||||||
|
/datum/var/last_find_references = 0
|
||||||
|
|
||||||
|
/datum/verb/find_refs()
|
||||||
|
set category = "Debug"
|
||||||
|
set name = "Find References"
|
||||||
|
set background = 1
|
||||||
|
set src in world
|
||||||
|
|
||||||
|
find_references(FALSE)
|
||||||
|
|
||||||
|
/datum/proc/find_references(skip_alert)
|
||||||
|
running_find_references = type
|
||||||
|
if(usr && usr.client)
|
||||||
|
if(usr.client.running_find_references)
|
||||||
|
testing("CANCELLED search for references to a [usr.client.running_find_references].")
|
||||||
|
usr.client.running_find_references = null
|
||||||
|
running_find_references = null
|
||||||
|
//restart the garbage collector
|
||||||
|
SSgarbage.can_fire = 1
|
||||||
|
SSgarbage.next_fire = world.time + world.tick_lag
|
||||||
|
return
|
||||||
|
|
||||||
|
if(!skip_alert)
|
||||||
|
if(alert("Running this will lock everything up for about 5 minutes. Would you like to begin the search?", "Find References", "Yes", "No") == "No")
|
||||||
|
running_find_references = null
|
||||||
|
return
|
||||||
|
|
||||||
|
//this keeps the garbage collector from failing to collect objects being searched for in here
|
||||||
|
SSgarbage.can_fire = 0
|
||||||
|
|
||||||
|
if(usr && usr.client)
|
||||||
|
usr.client.running_find_references = type
|
||||||
|
|
||||||
|
testing("Beginning search for references to a [type].")
|
||||||
|
last_find_references = world.time
|
||||||
|
find_references_in_globals()
|
||||||
|
for(var/datum/thing in world)
|
||||||
|
DoSearchVar(thing, "WorldRef: [thing]")
|
||||||
|
testing("Completed search for references to a [type].")
|
||||||
|
if(usr && usr.client)
|
||||||
|
usr.client.running_find_references = null
|
||||||
|
running_find_references = null
|
||||||
|
|
||||||
|
//restart the garbage collector
|
||||||
|
SSgarbage.can_fire = 1
|
||||||
|
SSgarbage.next_fire = world.time + world.tick_lag
|
||||||
|
|
||||||
|
/client/verb/purge_all_destroyed_objects()
|
||||||
|
set category = "Debug"
|
||||||
|
if(SSgarbage)
|
||||||
|
while(SSgarbage.queue.len)
|
||||||
|
var/datum/o = locate(SSgarbage.queue[1])
|
||||||
|
if(istype(o) && o.gc_destroyed)
|
||||||
|
del(o)
|
||||||
|
SSgarbage.totaldels++
|
||||||
|
SSgarbage.queue.Cut(1, 2)
|
||||||
|
|
||||||
|
/datum/verb/qdel_then_find_references()
|
||||||
|
set category = "Debug"
|
||||||
|
set name = "qdel() then Find References"
|
||||||
|
set background = 1
|
||||||
|
set src in world
|
||||||
|
|
||||||
|
qdel(src)
|
||||||
|
if(!running_find_references)
|
||||||
|
find_references(TRUE)
|
||||||
|
|
||||||
|
/client/verb/show_qdeleted()
|
||||||
|
set category = "Debug"
|
||||||
|
set name = "Show qdel() Log"
|
||||||
|
set desc = "Render the qdel() log and display it"
|
||||||
|
|
||||||
|
var/dat = "<B>List of things that have been qdel()eted this round</B><BR><BR>"
|
||||||
|
|
||||||
|
var/tmplist = list()
|
||||||
|
for(var/elem in SSgarbage.qdel_list)
|
||||||
|
if(!(elem in tmplist))
|
||||||
|
tmplist[elem] = 0
|
||||||
|
tmplist[elem]++
|
||||||
|
|
||||||
|
for(var/path in tmplist)
|
||||||
|
dat += "[path] - [tmplist[path]] times<BR>"
|
||||||
|
|
||||||
|
usr << browse(dat, "window=qdeletedlog")
|
||||||
|
|
||||||
|
/datum/proc/DoSearchVar(X, Xname)
|
||||||
|
if(usr && usr.client && !usr.client.running_find_references) return
|
||||||
|
if(istype(X, /datum))
|
||||||
|
var/datum/D = X
|
||||||
|
if(D.last_find_references == last_find_references)
|
||||||
|
return
|
||||||
|
D.last_find_references = last_find_references
|
||||||
|
for(var/V in D.vars)
|
||||||
|
for(var/varname in D.vars)
|
||||||
|
var/variable = D.vars[varname]
|
||||||
|
if(variable == src)
|
||||||
|
testing("Found [src.type] \ref[src] in [D.type]'s [varname] var. [Xname]")
|
||||||
|
else if(islist(variable))
|
||||||
|
if(src in variable)
|
||||||
|
testing("Found [src.type] \ref[src] in [D.type]'s [varname] list var. Global: [Xname]")
|
||||||
|
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||||
|
for(var/I in variable)
|
||||||
|
DoSearchVar(I, TRUE)
|
||||||
|
else
|
||||||
|
DoSearchVar(variable, "[Xname]: [varname]")
|
||||||
|
#endif
|
||||||
|
else if(islist(X))
|
||||||
|
if(src in X)
|
||||||
|
testing("Found [src.type] \ref[src] in list [Xname].")
|
||||||
|
#ifdef GC_FAILURE_HARD_LOOKUP
|
||||||
|
for(var/I in X)
|
||||||
|
DoSearchVar(I, Xname + ": list")
|
||||||
|
#else
|
||||||
|
CHECK_TICK
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//if find_references isn't working for some datum
|
||||||
|
//update this list using tools/GenerateGlobalVarAccess
|
||||||
|
/datum/proc/find_references_in_globals()
|
||||||
|
// TODO - Impement Global Variable Access
|
||||||
|
// for(var/global_var in _all_globals)
|
||||||
|
// DoSearchVar(readglobal(global_var), "Global: [global_var]")
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/image/Destroy()
|
||||||
|
..()
|
||||||
|
return QDEL_HINT_HARDDEL_NOW
|
||||||
@@ -155,4 +155,5 @@ Data storage vars:
|
|||||||
tag = null
|
tag = null
|
||||||
arg_list.Cut()
|
arg_list.Cut()
|
||||||
stop()
|
stop()
|
||||||
|
return QDEL_HINT_LETMELIVE
|
||||||
//Do not call ..()
|
//Do not call ..()
|
||||||
|
|||||||
@@ -36,4 +36,4 @@
|
|||||||
|
|
||||||
/decls/Destroy()
|
/decls/Destroy()
|
||||||
crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]")
|
crash_with("Prevented attempt to delete a decl instance: [log_info_line(src)]")
|
||||||
return 1 // Prevents Decl destruction
|
return QDEL_HINT_LETMELIVE // Prevents Decl destruction
|
||||||
|
|||||||
@@ -7,7 +7,9 @@
|
|||||||
|
|
||||||
//obtain a weak reference to a datum
|
//obtain a weak reference to a datum
|
||||||
/proc/weakref(datum/D)
|
/proc/weakref(datum/D)
|
||||||
if(D.gcDestroyed)
|
if(!istype(D))
|
||||||
|
return
|
||||||
|
if(QDELETED(D))
|
||||||
return
|
return
|
||||||
if(!D.weakref)
|
if(!D.weakref)
|
||||||
D.weakref = new/weakref(D)
|
D.weakref = new/weakref(D)
|
||||||
@@ -22,7 +24,7 @@
|
|||||||
/weakref/Destroy()
|
/weakref/Destroy()
|
||||||
// A weakref datum should not be manually destroyed as it is a shared resource,
|
// A weakref datum should not be manually destroyed as it is a shared resource,
|
||||||
// rather it should be automatically collected by the BYOND GC when all references are gone.
|
// rather it should be automatically collected by the BYOND GC when all references are gone.
|
||||||
return 0
|
return QDEL_HINT_LETMELIVE
|
||||||
|
|
||||||
/weakref/proc/resolve()
|
/weakref/proc/resolve()
|
||||||
var/datum/D = locate(ref)
|
var/datum/D = locate(ref)
|
||||||
|
|||||||
@@ -23,16 +23,6 @@
|
|||||||
if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING)
|
if(auto_init && ticker && ticker.current_state == GAME_STATE_PLAYING)
|
||||||
initialize()
|
initialize()
|
||||||
|
|
||||||
/atom/movable/Del()
|
|
||||||
if(isnull(gcDestroyed) && loc)
|
|
||||||
testing("GC: -- [type] was deleted via del() rather than qdel() --")
|
|
||||||
crash_with("GC: -- [type] was deleted via del() rather than qdel() --") // stick a stack trace in the runtime logs
|
|
||||||
// else if(isnull(gcDestroyed))
|
|
||||||
// testing("GC: [type] was deleted via GC without qdel()") //Not really a huge issue but from now on, please qdel()
|
|
||||||
// else
|
|
||||||
// testing("GC: [type] was deleted via GC with qdel()")
|
|
||||||
..()
|
|
||||||
|
|
||||||
/atom/movable/Destroy()
|
/atom/movable/Destroy()
|
||||||
. = ..()
|
. = ..()
|
||||||
if(reagents)
|
if(reagents)
|
||||||
@@ -53,7 +43,7 @@
|
|||||||
pulledby = null
|
pulledby = null
|
||||||
|
|
||||||
/atom/movable/proc/initialize()
|
/atom/movable/proc/initialize()
|
||||||
if(!isnull(gcDestroyed))
|
if(QDELETED(src))
|
||||||
crash_with("GC: -- [type] had initialize() called after qdel() --")
|
crash_with("GC: -- [type] had initialize() called after qdel() --")
|
||||||
|
|
||||||
/atom/movable/Bump(var/atom/A, yes)
|
/atom/movable/Bump(var/atom/A, yes)
|
||||||
|
|||||||
@@ -37,7 +37,6 @@ var/global/universe_has_ended = 0
|
|||||||
// Apply changes when entering state
|
// Apply changes when entering state
|
||||||
/datum/universal_state/supermatter_cascade/OnEnter()
|
/datum/universal_state/supermatter_cascade/OnEnter()
|
||||||
set background = 1
|
set background = 1
|
||||||
garbage_collector.garbage_collect = 0
|
|
||||||
world << "<span class='sinister' style='font-size:22pt'>You are blinded by a brilliant flash of energy.</span>"
|
world << "<span class='sinister' style='font-size:22pt'>You are blinded by a brilliant flash of energy.</span>"
|
||||||
|
|
||||||
world << sound('sound/effects/cascade.ogg')
|
world << sound('sound/effects/cascade.ogg')
|
||||||
|
|||||||
@@ -73,7 +73,7 @@
|
|||||||
visible_message("A red light flashes on \the [src].")
|
visible_message("A red light flashes on \the [src].")
|
||||||
return
|
return
|
||||||
cable.use(amount)
|
cable.use(amount)
|
||||||
if(deleted(cable))
|
if(QDELETED(cable))
|
||||||
cable = null
|
cable = null
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,9 @@
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/machinery/portable_atmospherics/Destroy()
|
/obj/machinery/portable_atmospherics/Destroy()
|
||||||
qdel(air_contents)
|
qdel_null(air_contents)
|
||||||
qdel(holding)
|
qdel_null(holding)
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/portable_atmospherics/initialize()
|
/obj/machinery/portable_atmospherics/initialize()
|
||||||
. = ..()
|
. = ..()
|
||||||
@@ -40,11 +40,6 @@
|
|||||||
else
|
else
|
||||||
update_icon()
|
update_icon()
|
||||||
|
|
||||||
/obj/machinery/portable_atmospherics/Destroy()
|
|
||||||
qdel(air_contents)
|
|
||||||
|
|
||||||
..()
|
|
||||||
|
|
||||||
/obj/machinery/portable_atmospherics/proc/StandardAirMix()
|
/obj/machinery/portable_atmospherics/proc/StandardAirMix()
|
||||||
return list(
|
return list(
|
||||||
"oxygen" = O2STANDARD * MolesForPressure(),
|
"oxygen" = O2STANDARD * MolesForPressure(),
|
||||||
|
|||||||
@@ -73,8 +73,7 @@
|
|||||||
/obj/machinery/door/Destroy()
|
/obj/machinery/door/Destroy()
|
||||||
density = 0
|
density = 0
|
||||||
update_nearby_tiles()
|
update_nearby_tiles()
|
||||||
..()
|
. = ..()
|
||||||
return
|
|
||||||
|
|
||||||
/obj/machinery/door/process()
|
/obj/machinery/door/process()
|
||||||
if(close_door_at && world.time >= close_door_at)
|
if(close_door_at && world.time >= close_door_at)
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ var/list/floor_light_cache = list()
|
|||||||
var/area/A = get_area(src)
|
var/area/A = get_area(src)
|
||||||
if(A)
|
if(A)
|
||||||
on = 0
|
on = 0
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/machinery/floor_light/cultify()
|
/obj/machinery/floor_light/cultify()
|
||||||
default_light_colour = "#FF0000"
|
default_light_colour = "#FF0000"
|
||||||
|
|||||||
@@ -485,7 +485,7 @@ Buildable meters
|
|||||||
var/turf/T = P.loc
|
var/turf/T = P.loc
|
||||||
P.level = !T.is_plating() ? 2 : 1
|
P.level = !T.is_plating() ? 2 : 1
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -504,7 +504,7 @@ Buildable meters
|
|||||||
var/turf/T = P.loc
|
var/turf/T = P.loc
|
||||||
P.level = !T.is_plating() ? 2 : 1
|
P.level = !T.is_plating() ? 2 : 1
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -523,7 +523,7 @@ Buildable meters
|
|||||||
var/turf/T = P.loc
|
var/turf/T = P.loc
|
||||||
P.level = !T.is_plating() ? 2 : 1
|
P.level = !T.is_plating() ? 2 : 1
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -542,7 +542,7 @@ Buildable meters
|
|||||||
var/turf/T = P.loc
|
var/turf/T = P.loc
|
||||||
P.level = !T.is_plating() ? 2 : 1
|
P.level = !T.is_plating() ? 2 : 1
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -559,7 +559,7 @@ Buildable meters
|
|||||||
P.initialize_directions = pipe_dir //this var it's used to know if the pipe is bent or not
|
P.initialize_directions = pipe_dir //this var it's used to know if the pipe is bent or not
|
||||||
P.initialize_directions_he = pipe_dir
|
P.initialize_directions_he = pipe_dir
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -594,7 +594,7 @@ Buildable meters
|
|||||||
var/turf/T = M.loc
|
var/turf/T = M.loc
|
||||||
M.level = !T.is_plating() ? 2 : 1
|
M.level = !T.is_plating() ? 2 : 1
|
||||||
M.initialize()
|
M.initialize()
|
||||||
if (deleted(M))
|
if (QDELETED(M))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
M.build_network()
|
M.build_network()
|
||||||
@@ -663,7 +663,7 @@ Buildable meters
|
|||||||
var/turf/T = M.loc
|
var/turf/T = M.loc
|
||||||
M.level = !T.is_plating() ? 2 : 1
|
M.level = !T.is_plating() ? 2 : 1
|
||||||
M.initialize()
|
M.initialize()
|
||||||
if (deleted(M))
|
if (QDELETED(M))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
M.build_network()
|
M.build_network()
|
||||||
@@ -740,7 +740,7 @@ Buildable meters
|
|||||||
P.initialize_directions = src.get_pdir()
|
P.initialize_directions = src.get_pdir()
|
||||||
P.initialize_directions_he = src.get_hdir()
|
P.initialize_directions_he = src.get_hdir()
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext //"There's nothing to connect this pipe to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)"
|
usr << pipefailtext //"There's nothing to connect this pipe to! (with how the pipe code works, at least one end needs to be connected to something, otherwise the game deletes the segment)"
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
@@ -922,7 +922,7 @@ Buildable meters
|
|||||||
var/turf/T = P.loc
|
var/turf/T = P.loc
|
||||||
P.level = !T.is_plating() ? 2 : 1
|
P.level = !T.is_plating() ? 2 : 1
|
||||||
P.initialize()
|
P.initialize()
|
||||||
if (deleted(P))
|
if (QDELETED(P))
|
||||||
usr << pipefailtext
|
usr << pipefailtext
|
||||||
return 1
|
return 1
|
||||||
P.build_network()
|
P.build_network()
|
||||||
|
|||||||
@@ -140,18 +140,14 @@
|
|||||||
cell = null
|
cell = null
|
||||||
internal_tank = null
|
internal_tank = null
|
||||||
|
|
||||||
qdel(pr_int_temp_processor)
|
qdel_null(pr_int_temp_processor)
|
||||||
qdel(pr_inertial_movement)
|
qdel_null(pr_inertial_movement)
|
||||||
qdel(pr_give_air)
|
qdel_null(pr_give_air)
|
||||||
qdel(pr_internal_damage)
|
qdel_null(pr_internal_damage)
|
||||||
qdel(spark_system)
|
qdel_null(spark_system)
|
||||||
pr_int_temp_processor = null
|
|
||||||
pr_give_air = null
|
|
||||||
pr_internal_damage = null
|
|
||||||
spark_system = null
|
|
||||||
|
|
||||||
mechas_list -= src //global mech list
|
mechas_list -= src //global mech list
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
////////////////////////
|
////////////////////////
|
||||||
////// Helpers /////////
|
////// Helpers /////////
|
||||||
|
|||||||
@@ -169,7 +169,7 @@
|
|||||||
|
|
||||||
valve_open = 0
|
valve_open = 0
|
||||||
|
|
||||||
if(deleted(tank_one) || deleted(tank_two))
|
if(QDELETED(tank_one) || QDELETED(tank_two))
|
||||||
return
|
return
|
||||||
|
|
||||||
var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume
|
var/ratio1 = tank_one.air_contents.volume/tank_two.air_contents.volume
|
||||||
|
|||||||
@@ -27,15 +27,10 @@
|
|||||||
|
|
||||||
|
|
||||||
/obj/item/weapon/flamethrower/Destroy()
|
/obj/item/weapon/flamethrower/Destroy()
|
||||||
if(weldtool)
|
qdel_null(weldtool)
|
||||||
qdel(weldtool)
|
qdel_null(igniter)
|
||||||
if(igniter)
|
qdel_null(ptank)
|
||||||
qdel(igniter)
|
. = ..()
|
||||||
if(ptank)
|
|
||||||
qdel(ptank)
|
|
||||||
..()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
/obj/item/weapon/flamethrower/process()
|
/obj/item/weapon/flamethrower/process()
|
||||||
if(!lit)
|
if(!lit)
|
||||||
|
|||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
/obj/item/weapon/material/Destroy()
|
/obj/item/weapon/material/Destroy()
|
||||||
processing_objects -= src
|
processing_objects -= src
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/item/weapon/material/apply_hit_effect()
|
/obj/item/weapon/material/apply_hit_effect()
|
||||||
..()
|
..()
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
/obj/structure/Destroy()
|
/obj/structure/Destroy()
|
||||||
if(parts)
|
if(parts)
|
||||||
new parts(loc)
|
new parts(loc)
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/structure/attack_hand(mob/user)
|
/obj/structure/attack_hand(mob/user)
|
||||||
if(breakable)
|
if(breakable)
|
||||||
|
|||||||
@@ -39,7 +39,7 @@
|
|||||||
spawn(1)
|
spawn(1)
|
||||||
if(istype(O)) // If we built a new floor with the lattice, the open turf won't exist anymore.
|
if(istype(O)) // If we built a new floor with the lattice, the open turf won't exist anymore.
|
||||||
O.update() // This lattice may be supporting things on top of it. If it's being deleted, they need to fall down.
|
O.update() // This lattice may be supporting things on top of it. If it's being deleted, they need to fall down.
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/structure/lattice/ex_act(severity)
|
/obj/structure/lattice/ex_act(severity)
|
||||||
switch(severity)
|
switch(severity)
|
||||||
|
|||||||
@@ -47,6 +47,7 @@
|
|||||||
/turf/Destroy()
|
/turf/Destroy()
|
||||||
turfs -= src
|
turfs -= src
|
||||||
..()
|
..()
|
||||||
|
return QDEL_HINT_IWILLGC
|
||||||
|
|
||||||
/turf/ex_act(severity)
|
/turf/ex_act(severity)
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -1,8 +1,4 @@
|
|||||||
|
|
||||||
// Keep these two together, they *must* be defined on both
|
|
||||||
// If /client ever becomes /datum/client or similar, they can be merged
|
|
||||||
/client/proc/get_view_variables_header()
|
|
||||||
return "<b>[src]</b>"
|
|
||||||
/datum/proc/get_view_variables_header()
|
/datum/proc/get_view_variables_header()
|
||||||
return "<b>[src]</b>"
|
return "<b>[src]</b>"
|
||||||
|
|
||||||
@@ -31,9 +27,6 @@
|
|||||||
</font>
|
</font>
|
||||||
"}
|
"}
|
||||||
|
|
||||||
// Same for these as for get_view_variables_header() above
|
|
||||||
/client/proc/get_view_variables_options()
|
|
||||||
return ""
|
|
||||||
/datum/proc/get_view_variables_options()
|
/datum/proc/get_view_variables_options()
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|||||||
@@ -187,4 +187,4 @@
|
|||||||
if(radio_controller)
|
if(radio_controller)
|
||||||
radio_controller.remove_object(src,frequency)
|
radio_controller.remove_object(src,frequency)
|
||||||
frequency = 0
|
frequency = 0
|
||||||
..()
|
. = ..()
|
||||||
|
|||||||
@@ -1,4 +1,8 @@
|
|||||||
/client
|
/client
|
||||||
|
//////////////////////
|
||||||
|
//BLACK MAGIC THINGS//
|
||||||
|
//////////////////////
|
||||||
|
parent_type = /datum
|
||||||
////////////////
|
////////////////
|
||||||
//ADMIN THINGS//
|
//ADMIN THINGS//
|
||||||
////////////////
|
////////////////
|
||||||
|
|||||||
@@ -181,6 +181,9 @@
|
|||||||
clients -= src
|
clients -= src
|
||||||
return ..()
|
return ..()
|
||||||
|
|
||||||
|
/client/Destroy()
|
||||||
|
..()
|
||||||
|
return QDEL_HINT_HARDDEL_NOW
|
||||||
|
|
||||||
// here because it's similar to below
|
// here because it's similar to below
|
||||||
|
|
||||||
|
|||||||
@@ -116,7 +116,7 @@
|
|||||||
var/obj/effect/plant/child = new(get_turf(src),seed,parent)
|
var/obj/effect/plant/child = new(get_turf(src),seed,parent)
|
||||||
|
|
||||||
spawn(1) // This should do a little bit of animation.
|
spawn(1) // This should do a little bit of animation.
|
||||||
if(deleted(child))
|
if(QDELETED(child))
|
||||||
return
|
return
|
||||||
|
|
||||||
//move out to the destination
|
//move out to the destination
|
||||||
|
|||||||
@@ -131,4 +131,4 @@
|
|||||||
T.lighting_overlay = null
|
T.lighting_overlay = null
|
||||||
T.luminosity = 1
|
T.luminosity = 1
|
||||||
|
|
||||||
return ..()
|
. = ..()
|
||||||
|
|||||||
@@ -443,7 +443,7 @@ var/global/list/damage_icon_parts = list()
|
|||||||
//For legacy support.
|
//For legacy support.
|
||||||
/mob/living/carbon/human/regenerate_icons()
|
/mob/living/carbon/human/regenerate_icons()
|
||||||
..()
|
..()
|
||||||
if(transforming) return
|
if(transforming || QDELETED(src)) return
|
||||||
|
|
||||||
update_mutations(0)
|
update_mutations(0)
|
||||||
update_body(0)
|
update_body(0)
|
||||||
|
|||||||
@@ -184,7 +184,7 @@
|
|||||||
wrapped.force = 0.0
|
wrapped.force = 0.0
|
||||||
wrapped.attack(M,user)
|
wrapped.attack(M,user)
|
||||||
M.attackby(wrapped, user) //attackby reportedly gets procced by being clicked on, at least according to Anewbe.
|
M.attackby(wrapped, user) //attackby reportedly gets procced by being clicked on, at least according to Anewbe.
|
||||||
if(deleted(wrapped) || wrapped.loc != src.loc)
|
if(QDELETED(wrapped) || wrapped.loc != src.loc)
|
||||||
wrapped = null
|
wrapped = null
|
||||||
return 1
|
return 1
|
||||||
return 0
|
return 0
|
||||||
|
|||||||
@@ -14,6 +14,7 @@
|
|||||||
spellremove(src)
|
spellremove(src)
|
||||||
ghostize()
|
ghostize()
|
||||||
..()
|
..()
|
||||||
|
return QDEL_HINT_HARDDEL_NOW
|
||||||
|
|
||||||
/mob/proc/remove_screen_obj_references()
|
/mob/proc/remove_screen_obj_references()
|
||||||
hands = null
|
hands = null
|
||||||
|
|||||||
@@ -83,7 +83,9 @@
|
|||||||
|
|
||||||
|
|
||||||
//This makes sure that the grab screen object is displayed in the correct hand.
|
//This makes sure that the grab screen object is displayed in the correct hand.
|
||||||
/obj/item/weapon/grab/proc/synch()
|
/obj/item/weapon/grab/proc/synch() //why is this needed?
|
||||||
|
if(QDELETED(src))
|
||||||
|
return
|
||||||
if(affecting)
|
if(affecting)
|
||||||
if(assailant.r_hand == src)
|
if(assailant.r_hand == src)
|
||||||
hud.screen_loc = ui_rhand
|
hud.screen_loc = ui_rhand
|
||||||
@@ -91,7 +93,7 @@
|
|||||||
hud.screen_loc = ui_lhand
|
hud.screen_loc = ui_lhand
|
||||||
|
|
||||||
/obj/item/weapon/grab/process()
|
/obj/item/weapon/grab/process()
|
||||||
if(gcDestroyed) // GC is trying to delete us, we'll kill our processing so we can cleanly GC
|
if(QDELETED(src)) // GC is trying to delete us, we'll kill our processing so we can cleanly GC
|
||||||
return PROCESS_KILL
|
return PROCESS_KILL
|
||||||
|
|
||||||
confirm()
|
confirm()
|
||||||
@@ -221,6 +223,8 @@
|
|||||||
animate(affecting, pixel_x =-shift, pixel_y = 0, 5, 1, LINEAR_EASING)
|
animate(affecting, pixel_x =-shift, pixel_y = 0, 5, 1, LINEAR_EASING)
|
||||||
|
|
||||||
/obj/item/weapon/grab/proc/s_click(obj/screen/S)
|
/obj/item/weapon/grab/proc/s_click(obj/screen/S)
|
||||||
|
if(QDELETED(src))
|
||||||
|
return
|
||||||
if(!affecting)
|
if(!affecting)
|
||||||
return
|
return
|
||||||
if(state == GRAB_UPGRADING)
|
if(state == GRAB_UPGRADING)
|
||||||
@@ -291,6 +295,8 @@
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
/obj/item/weapon/grab/attack(mob/M, mob/living/user)
|
/obj/item/weapon/grab/attack(mob/M, mob/living/user)
|
||||||
|
if(QDELETED(src))
|
||||||
|
return
|
||||||
if(!affecting)
|
if(!affecting)
|
||||||
return
|
return
|
||||||
if(world.time < (last_action + 20))
|
if(world.time < (last_action + 20))
|
||||||
@@ -336,7 +342,7 @@
|
|||||||
|
|
||||||
/obj/item/weapon/grab/dropped()
|
/obj/item/weapon/grab/dropped()
|
||||||
loc = null
|
loc = null
|
||||||
if(!destroying)
|
if(!QDELETED(src))
|
||||||
qdel(src)
|
qdel(src)
|
||||||
|
|
||||||
/obj/item/weapon/grab/proc/reset_kill_state()
|
/obj/item/weapon/grab/proc/reset_kill_state()
|
||||||
|
|||||||
@@ -67,10 +67,8 @@
|
|||||||
brainmob.client.screen.len = null //clear the hud
|
brainmob.client.screen.len = null //clear the hud
|
||||||
|
|
||||||
/obj/item/organ/internal/brain/Destroy()
|
/obj/item/organ/internal/brain/Destroy()
|
||||||
if(brainmob)
|
qdel_null(brainmob)
|
||||||
qdel(brainmob)
|
. = ..()
|
||||||
brainmob = null
|
|
||||||
..()
|
|
||||||
|
|
||||||
/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H)
|
/obj/item/organ/internal/brain/proc/transfer_identity(var/mob/living/carbon/H)
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@
|
|||||||
chemical_reagents_list[D.id] = D
|
chemical_reagents_list[D.id] = D
|
||||||
|
|
||||||
/datum/reagents/Destroy()
|
/datum/reagents/Destroy()
|
||||||
..()
|
. = ..()
|
||||||
if(chemistryProcess)
|
if(chemistryProcess)
|
||||||
chemistryProcess.active_holders -= src
|
chemistryProcess.active_holders -= src
|
||||||
|
|
||||||
|
|||||||
@@ -488,7 +488,7 @@
|
|||||||
var/amount_to_take = max(0,min(stack.amount,round(remaining_volume/REAGENTS_PER_SHEET)))
|
var/amount_to_take = max(0,min(stack.amount,round(remaining_volume/REAGENTS_PER_SHEET)))
|
||||||
if(amount_to_take)
|
if(amount_to_take)
|
||||||
stack.use(amount_to_take)
|
stack.use(amount_to_take)
|
||||||
if(deleted(stack))
|
if(QDELETED(stack))
|
||||||
holdingitems -= stack
|
holdingitems -= stack
|
||||||
beaker.reagents.add_reagent(sheet_reagents[stack.type], (amount_to_take*REAGENTS_PER_SHEET))
|
beaker.reagents.add_reagent(sheet_reagents[stack.type], (amount_to_take*REAGENTS_PER_SHEET))
|
||||||
continue
|
continue
|
||||||
|
|||||||
@@ -118,8 +118,8 @@
|
|||||||
return null
|
return null
|
||||||
|
|
||||||
/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
|
/datum/reagent/Destroy() // This should only be called by the holder, so it's already handled clearing its references
|
||||||
..()
|
|
||||||
holder = null
|
holder = null
|
||||||
|
. = ..()
|
||||||
|
|
||||||
/* DEPRECATED - TODO: REMOVE EVERYWHERE */
|
/* DEPRECATED - TODO: REMOVE EVERYWHERE */
|
||||||
|
|
||||||
|
|||||||
@@ -210,8 +210,8 @@
|
|||||||
/obj/item/weapon/reagent_containers/food/snacks/Destroy()
|
/obj/item/weapon/reagent_containers/food/snacks/Destroy()
|
||||||
if(contents)
|
if(contents)
|
||||||
for(var/atom/movable/something in contents)
|
for(var/atom/movable/something in contents)
|
||||||
something.loc = get_turf(src)
|
something.dropInto(loc)
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
/// FOOD END
|
/// FOOD END
|
||||||
|
|||||||
@@ -55,7 +55,7 @@
|
|||||||
|
|
||||||
check_failure()
|
check_failure()
|
||||||
set_opacity(1)
|
set_opacity(1)
|
||||||
spawn(20) if(!deleted(src)) set_opacity(0)
|
spawn(20) if(!QDELETED(src)) set_opacity(0)
|
||||||
|
|
||||||
..()
|
..()
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
..()
|
..()
|
||||||
check_failure()
|
check_failure()
|
||||||
set_opacity(1)
|
set_opacity(1)
|
||||||
spawn(20) if(!deleted(src)) set_opacity(0)
|
spawn(20) if(!QDELETED(src)) set_opacity(0)
|
||||||
|
|
||||||
/obj/machinery/shield/ex_act(severity)
|
/obj/machinery/shield/ex_act(severity)
|
||||||
switch(severity)
|
switch(severity)
|
||||||
@@ -114,7 +114,7 @@
|
|||||||
|
|
||||||
//The shield becomes dense to absorb the blow.. purely asthetic.
|
//The shield becomes dense to absorb the blow.. purely asthetic.
|
||||||
set_opacity(1)
|
set_opacity(1)
|
||||||
spawn(20) if(!deleted(src)) set_opacity(0)
|
spawn(20) if(!QDELETED(src)) set_opacity(0)
|
||||||
|
|
||||||
..()
|
..()
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -79,7 +79,7 @@
|
|||||||
update_connections(1) // Update tables around us to ignore us (material=null forces no connections)
|
update_connections(1) // Update tables around us to ignore us (material=null forces no connections)
|
||||||
for(var/obj/structure/table/T in oview(src, 1))
|
for(var/obj/structure/table/T in oview(src, 1))
|
||||||
T.update_icon()
|
T.update_icon()
|
||||||
..()
|
. = ..()
|
||||||
|
|
||||||
/obj/structure/table/examine(mob/user)
|
/obj/structure/table/examine(mob/user)
|
||||||
. = ..()
|
. = ..()
|
||||||
|
|||||||
@@ -37,6 +37,7 @@
|
|||||||
#include "code\__defines\mobs.dm"
|
#include "code\__defines\mobs.dm"
|
||||||
#include "code\__defines\planets.dm"
|
#include "code\__defines\planets.dm"
|
||||||
#include "code\__defines\process_scheduler.dm"
|
#include "code\__defines\process_scheduler.dm"
|
||||||
|
#include "code\__defines\qdel.dm"
|
||||||
#include "code\__defines\research.dm"
|
#include "code\__defines\research.dm"
|
||||||
#include "code\__defines\species_languages.dm"
|
#include "code\__defines\species_languages.dm"
|
||||||
#include "code\__defines\targeting.dm"
|
#include "code\__defines\targeting.dm"
|
||||||
@@ -152,7 +153,6 @@
|
|||||||
#include "code\controllers\Processes\emergencyShuttle.dm"
|
#include "code\controllers\Processes\emergencyShuttle.dm"
|
||||||
#include "code\controllers\Processes\event.dm"
|
#include "code\controllers\Processes\event.dm"
|
||||||
#include "code\controllers\Processes\game_master.dm"
|
#include "code\controllers\Processes\game_master.dm"
|
||||||
#include "code\controllers\Processes\garbage.dm"
|
|
||||||
#include "code\controllers\Processes\inactivity.dm"
|
#include "code\controllers\Processes\inactivity.dm"
|
||||||
#include "code\controllers\Processes\lighting.dm"
|
#include "code\controllers\Processes\lighting.dm"
|
||||||
#include "code\controllers\Processes\machinery.dm"
|
#include "code\controllers\Processes\machinery.dm"
|
||||||
@@ -170,6 +170,7 @@
|
|||||||
#include "code\controllers\Processes\vote.dm"
|
#include "code\controllers\Processes\vote.dm"
|
||||||
#include "code\controllers\ProcessScheduler\core\process.dm"
|
#include "code\controllers\ProcessScheduler\core\process.dm"
|
||||||
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
|
#include "code\controllers\ProcessScheduler\core\processScheduler.dm"
|
||||||
|
#include "code\controllers\subsystems\garbage.dm"
|
||||||
#include "code\datums\ai_law_sets.dm"
|
#include "code\datums\ai_law_sets.dm"
|
||||||
#include "code\datums\ai_laws.dm"
|
#include "code\datums\ai_laws.dm"
|
||||||
#include "code\datums\browser.dm"
|
#include "code\datums\browser.dm"
|
||||||
|
|||||||
Reference in New Issue
Block a user