diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm index 40dd7b5f35..47db1dbc06 100644 --- a/code/__DEFINES/is_helpers.dm +++ b/code/__DEFINES/is_helpers.dm @@ -10,6 +10,8 @@ #define isatom(A) (isloc(A)) +#define isweakref(D) (istype(D, /datum/weakref)) + //Turfs //#define isturf(A) (istype(A, /turf)) This is actually a byond built-in. Added here for completeness sake. diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 303c6a6846..4e2b793069 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1440,7 +1440,6 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new) var/time_low = num2hex(world.time, 3) var/time_clock = num2hex(TICK_DELTA_TO_MS(world.tick_usage), 3) - return "{[time_high]-[time_mid]-[GUID_VERSION][time_low]-[GUID_VARIANT][time_clock]-[node_id]}" // \ref behaviour got changed in 512 so this is necesary to replicate old behaviour. diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 1df7eb2c10..4c08b1000d 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -4,6 +4,7 @@ var/list/datum_components //for /datum/components var/ui_screen = "home" //for tgui var/use_tag = FALSE + var/datum/weakref/weak_reference #ifdef TESTING var/running_find_references @@ -15,6 +16,7 @@ // Return the appropriate QDEL_HINT; in most cases this is QDEL_HINT_QUEUE. /datum/proc/Destroy(force=FALSE, ...) tag = null + weak_reference = null //ensure prompt GCing of weakref. var/list/timers = active_timers active_timers = null for(var/thing in timers) diff --git a/code/datums/weakrefs.dm b/code/datums/weakrefs.dm new file mode 100644 index 0000000000..09193aea57 --- /dev/null +++ b/code/datums/weakrefs.dm @@ -0,0 +1,19 @@ + +/proc/WEAKREF(datum/input) + if(istype(input) && !QDELETED(input)) + if(!input.weak_reference) + input.weak_reference = new /datum/weakref(input) + return input.weak_reference + +/datum/weakref + var/reference + +/datum/weakref/New(datum/thing) + reference = REF(thing) + +/datum/weakref/Destroy() + return QDEL_HINT_LETMELIVE //Let BYOND autoGC thiswhen nothing is using it anymore. + +/datum/weakref/proc/resolve() + var/datum/D = locate(reference) + return D.weak_reference == src? D : null diff --git a/code/game/area/ai_monitored.dm b/code/game/area/ai_monitored.dm index e21d4e273b..a5216fb44c 100644 --- a/code/game/area/ai_monitored.dm +++ b/code/game/area/ai_monitored.dm @@ -2,7 +2,7 @@ name = "AI Monitored Area" clockwork_warp_allowed = FALSE var/list/obj/machinery/camera/motioncameras = list() - var/list/motionTargets = list() + var/list/datum/weakref/motionTargets = list() /area/ai_monitored/Initialize(mapload) . = ..() @@ -27,5 +27,5 @@ if (ismob(O) && motioncameras.len) for(var/X in motioncameras) var/obj/machinery/camera/cam = X - cam.lostTarget(O) + cam.lostTargetRef(WEAKREF(O)) return diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm index 68b3f284e4..75d2ffaea2 100644 --- a/code/game/machinery/camera/motion.dm +++ b/code/game/machinery/camera/motion.dm @@ -1,6 +1,6 @@ /obj/machinery/camera - var/list/localMotionTargets = list() + var/list/datum/weakref/localMotionTargets = list() var/detectTime = 0 var/area/ai_monitored/area_motion = null var/alarm_delay = 30 // Don't forget, there's another 3 seconds in queueAlarm() @@ -15,11 +15,11 @@ if (elapsed > alarm_delay) triggerAlarm() else if (detectTime == -1) - for (var/targetref in getTargetList()) - var/mob/target = locate(targetref) in GLOB.mob_list - if (QDELETED(target) || target.stat == DEAD || (!area_motion && !in_range(src, target))) + for (var/datum/weakref/targetref in getTargetList()) + var/mob/target = targetref.resolve() + if(QDELETED(target) || target.stat == DEAD || (!area_motion && !in_range(src, target))) //If not part of a monitored area and the camera is not in range or the target is dead - lostTarget(target) + lostTargetRef(targetref) /obj/machinery/camera/proc/getTargetList() if(area_motion) @@ -28,22 +28,23 @@ /obj/machinery/camera/proc/newTarget(mob/target) if(isAI(target)) - return 0 + return FALSE if (detectTime == 0) detectTime = world.time // start the clock var/list/targets = getTargetList() - targets |= "[REF(target)]" - return 1 + targets |= WEAKREF(target) + return TRUE /obj/machinery/camera/Destroy() var/area/ai_monitored/A = get_area(src) + localMotionTargets = null if(istype(A)) A.motioncameras -= src return ..() -/obj/machinery/camera/proc/lostTarget(mob/target) +/obj/machinery/camera/proc/lostTargetRef(datum/weakref/R) var/list/targets = getTargetList() - targets -= "[REF(target)]" + targets -= R if (targets.len == 0) cancelAlarm() @@ -53,19 +54,20 @@ if (status) aiPlayer.cancelAlarm("Motion", get_area(src), src) detectTime = 0 - return 1 + return TRUE /obj/machinery/camera/proc/triggerAlarm() if (!detectTime) - return 0 + return FALSE for (var/mob/living/silicon/aiPlayer in GLOB.player_list) if (status) aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src) detectTime = -1 - return 1 + return TRUE /obj/machinery/camera/HasProximity(atom/movable/AM as mob|obj) // Motion cameras outside of an "ai monitored" area will use this to detect stuff. if (!area_motion) if(isliving(AM)) newTarget(AM) + diff --git a/tgstation.dme b/tgstation.dme index 038a896bc3..a23a8a0c36 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -305,6 +305,7 @@ #include "code\datums\soullink.dm" #include "code\datums\spawners_menu.dm" #include "code\datums\verbs.dm" +#include "code\datums\weakrefs.dm" #include "code\datums\world_topic.dm" #include "code\datums\actions\flightsuit.dm" #include "code\datums\actions\ninja.dm"