From 5761ecd3dad408f8b06d106d7bf6f99f091be2d3 Mon Sep 17 00:00:00 2001 From: UEDCommander <52104104+UEDCommander@users.noreply.github.com> Date: Thu, 11 Apr 2024 17:36:06 +0300 Subject: [PATCH] Downstream refactors (#2104) --- baystation12.dme | 1 + code/__defines/dcs/signals/signals_area.dm | 10 ++ code/controllers/subsystems/atoms.dm | 45 +++-- code/controllers/subsystems/garbage.dm | 4 + code/controllers/subsystems/overlays.dm | 163 ++++++++++-------- .../subsystems/processing/icon_updates.dm | 69 ++++---- code/game/area/area_power.dm | 22 +++ .../objects/items/devices/radio/intercom.dm | 68 ++++---- code/modules/power/apc.dm | 6 +- 9 files changed, 230 insertions(+), 158 deletions(-) create mode 100644 code/__defines/dcs/signals/signals_area.dm diff --git a/baystation12.dme b/baystation12.dme index f22a037290f3b..f8da9d1219587 100644 --- a/baystation12.dme +++ b/baystation12.dme @@ -98,6 +98,7 @@ #include "code\__defines\zmimic.dm" #include "code\__defines\dcs\flags.dm" #include "code\__defines\dcs\helpers.dm" +#include "code\__defines\dcs\signals\signals_area.dm" #include "code\__defines\dcs\signals\signals_atom.dm" #include "code\__defines\dcs\signals\signals_atom_movable.dm" #include "code\__defines\dcs\signals\signals_datum.dm" diff --git a/code/__defines/dcs/signals/signals_area.dm b/code/__defines/dcs/signals/signals_area.dm new file mode 100644 index 0000000000000..7e05ef6a0479f --- /dev/null +++ b/code/__defines/dcs/signals/signals_area.dm @@ -0,0 +1,10 @@ +// Main area signals. Format: +// When the signal is called: (signal arguments) +// All signals send the source datum of the signal as the first argument + +///from base of /area/proc/power_change(): (area/apc_area) +#define COMSIG_AREA_POWER_CHANGE "area_apc_power_change" +///from base of /area/proc/set_apc(): (area/apc_area) +#define COMSIG_AREA_APC_ADDED "area_apc_added" +///from base of /area/proc/remove_apc(): (area/apc_area) +#define COMSIG_AREA_APC_REMOVED "area_apc_removed" diff --git a/code/controllers/subsystems/atoms.dm b/code/controllers/subsystems/atoms.dm index d7236a00638c9..cc550d2ede5e8 100644 --- a/code/controllers/subsystems/atoms.dm +++ b/code/controllers/subsystems/atoms.dm @@ -44,33 +44,32 @@ SUBSYSTEM_DEF(atoms) return atom_init_stage = INITIALIZATION_INNEW_MAPLOAD var/list/mapload_arg = list(TRUE) - var/atom/atom - var/list/params var/count = 0 var/time = Uptime() - if (!initialized) - for (atom in world) - if (!atom || atom.atom_flags & ATOM_FLAG_INITIALIZED) - continue - InitAtom(atom, mapload_arg) - if (++count % 1000) + if(!initialized) + for(var/atom/atom_to_initialize as anything in world) + if(!atom_to_initialize || atom_to_initialize.atom_flags & ATOM_FLAG_INITIALIZED) continue + InitAtom(atom_to_initialize, mapload_arg) + count++ CHECK_TICK + var/init_queue_length = length(init_queue) - if (init_queue_length) - for (var/i = 1 to init_queue_length) - atom = init_queue[i] - if (!atom || atom.atom_flags & ATOM_FLAG_INITIALIZED) + if(init_queue_length) + for(var/i = 1 to init_queue_length) + var/atom/atom_to_initialize = init_queue[i] + if (!atom_to_initialize || atom_to_initialize.atom_flags & ATOM_FLAG_INITIALIZED) continue - params = init_queue[atom] + + var/list/params = init_queue[atom_to_initialize] if (params) - InitAtom(atom, mapload_arg + params) + InitAtom(atom_to_initialize, mapload_arg + params) else - InitAtom(atom, mapload_arg) - if (++count % 500) - continue + InitAtom(atom_to_initialize, mapload_arg) + count++ CHECK_TICK init_queue.Cut(1, init_queue_length + 1) + time = max((Uptime() - time) * 0.1, 0.1) report_progress("Initialized [count] atom\s in [time]s ([floor(count/time)]/s)") atom_init_stage = INITIALIZATION_INNEW_REGULAR @@ -78,13 +77,13 @@ SUBSYSTEM_DEF(atoms) if (late_queue_length) count = 0 time = Uptime() - for (var/i = 1 to late_queue_length) - atom = late_init_queue[i] - if (!atom) - continue - atom.LateInitialize(arglist(late_init_queue[atom])) - if (++count % 250) + for(var/i = 1 to late_queue_length) + var/atom/atom_to_late_init = late_init_queue[i] + if (!atom_to_late_init) continue + + atom_to_late_init.LateInitialize(arglist(late_init_queue[atom_to_late_init])) + count++ CHECK_TICK late_init_queue.Cut(1, late_queue_length + 1) time = max((Uptime() - time) * 0.1, 0.1) diff --git a/code/controllers/subsystems/garbage.dm b/code/controllers/subsystems/garbage.dm index d8cfe79fe21ce..a0a1bbf954cb0 100644 --- a/code/controllers/subsystems/garbage.dm +++ b/code/controllers/subsystems/garbage.dm @@ -219,9 +219,13 @@ SUBSYSTEM_DEF(garbage) ++details.qdels switch (datum.gc_destroyed) if (null) + if(SEND_SIGNAL(datum, COMSIG_PREQDELETED)) // Gives any signal listener a chance to prevent atom qdel + return + datum.gc_destroyed = GC_CURRENTLY_BEING_QDELETED var/start_time = world.time var/start_tick = world.tick_usage + SEND_SIGNAL(datum, COMSIG_QDELETING) // Leting signal listeners know, that datum is being qdeleted var/hint = datum.Destroy() if (world.time != start_time) ++details.slept_destroy diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index 6090afe02c78e..baf3141f9a0b2 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -11,21 +11,17 @@ var/global/const/ATOM_ICON_CACHE_ALL = (ATOM_ICON_CACHE_NORMAL | ATOM_ICON_CACHE SUBSYSTEM_DEF(overlays) name = "Overlays" flags = SS_TICKER - wait = 1 // ticks + wait = 1 priority = FIRE_PRIORITY_OVERLAYS init_order = SS_INIT_OVERLAYS - /// The queue of atoms that need under/overlay updates. - var/static/list/atom/queue = list() - + VAR_PRIVATE/static/list/atom/queue = list() /// A list([icon] = list([state] = [appearance], ...), ...) cache of appearances. - var/static/list/state_cache = list() - + VAR_PRIVATE/static/list/state_cache = list() /// A list([icon] = [appearance], ...) cache of appearances. - var/static/list/icon_cache = list() - + VAR_PRIVATE/static/list/icon_cache = list() /// The number of appearances currently cached. - var/static/cache_size = 0 + VAR_PRIVATE/static/cache_size = 0 /datum/controller/subsystem/overlays/Recover() @@ -33,16 +29,15 @@ SUBSYSTEM_DEF(overlays) LIST_RESIZE(state_cache, 0) LIST_RESIZE(icon_cache, 0) cache_size = 0 - var/count = 0 - for (var/atom/atom) - atom.atom_flags &= ~ATOM_AWAITING_OVERLAY_UPDATE - if (++count % 500) - continue + for(var/atom/atom as anything in world) + if(atom.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) + SSoverlays.queue += atom + CHECK_TICK /datum/controller/subsystem/overlays/Initialize(start_uptime) - fire(FALSE, TRUE) + flush_queue() /datum/controller/subsystem/overlays/UpdateStat(time) @@ -51,73 +46,100 @@ SUBSYSTEM_DEF(overlays) ..({"Queued Atoms: [length(queue)], Cache Size: [cache_size]"}) -/datum/controller/subsystem/overlays/fire(resumed, no_mc_tick) - var/queue_length = length(queue) - if (queue_length) - var/atom/atom - for (var/i = 1 to queue_length) - atom = queue[i] - if (QDELETED(atom)) - continue - if (atom.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) - atom.UpdateOverlays() - if (no_mc_tick) - if (i % 1000) - continue - CHECK_TICK - else if (MC_TICK_CHECK) - queue.Cut(1, i + 1) - return - queue.Cut(1, queue_length + 1) +/datum/controller/subsystem/overlays/fire(resumed) + var/queue_position = 1 + while(length(queue) >= queue_position) + var/atom/atom_to_update = queue[queue_position] + if(!QDELETED(atom_to_update) && atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) + atom_to_update.UpdateOverlays() + + queue_position++ + if(MC_TICK_CHECK) + break + + queue.Cut(1, queue_position) + +/datum/controller/subsystem/overlays/proc/flush_queue() + var/queue_position = 1 + while(length(queue) >= queue_position) + process_atom_overlays_update(queue[queue_position]) + queue_position++ + CHECK_TICK + + LIST_RESIZE(queue, 0) + +/datum/controller/subsystem/overlays/proc/process_atom_overlays_update(atom/atom_to_update) + if(!QDELETED(atom_to_update) && atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) + atom_to_update.UpdateOverlays() /datum/controller/subsystem/overlays/proc/GetStateAppearance(icon, state) - var/list/subcache = state_cache[icon] - if (!subcache) - subcache = list() - state_cache[icon] = subcache - if (!subcache[state]) - var/image/image = image(icon, null, state) - subcache[state] = image.appearance - ++cache_size - return subcache[state] + var/list/state_to_appearance = state_cache[icon] + if(!state_to_appearance) + state_to_appearance = list() + state_cache[icon] = state_to_appearance + + var/state_appearance = state_to_appearance[state] + if(!state_appearance) + var/image/state_image = image(icon, null, state) + state_appearance = state_image.appearance + state_to_appearance[state] = state_appearance + cache_size++ + + return state_appearance /datum/controller/subsystem/overlays/proc/GetIconAppearance(icon) - if (!icon_cache[icon]) - var/image/image = image(icon) - icon_cache[icon] = image.appearance - ++cache_size - return icon_cache[icon] + var/icon_appearance = icon_cache[icon] + if (!icon_appearance) + var/image/icon_image = image(icon) + icon_appearance = icon_image.appearance + icon_cache[icon] = icon_appearance + cache_size++ + + return icon_appearance -/datum/controller/subsystem/overlays/proc/GetAppearanceList(atom/subject, list/sources) +/datum/controller/subsystem/overlays/proc/getAppearanceList(atom/subject, list/sources) if (!sources) return list() + if (!islist(sources)) sources = list(sources) + var/list/result = list() - var/icon/icon = subject.icon - var/atom/entry - for (var/i = 1 to length(sources)) - entry = sources[i] - if (!entry) + for (var/atom/source as anything in sources) + if(!source) continue - else if (istext(entry)) - result += GetStateAppearance(icon, entry) - else if (isicon(entry)) - result += GetIconAppearance(entry) + + if(istext(source)) + result += GetStateAppearance(subject.icon, source) + + else if(isicon(source)) + result += GetIconAppearance(source) + else - if (isloc(entry)) - if (entry.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) - entry.UpdateOverlays() - if (!ispath(entry)) - result += entry.appearance + if(isatom(source) && source.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) + source.UpdateOverlays() + + if(!ispath(source)) + result += source.appearance else - var/image/image = entry + var/image/image = source result += image.appearance + return result +/datum/controller/subsystem/overlays/proc/enque_atom_overlay_update(atom/atom_to_update) + if(!atom_to_update) + return + + if(atom_to_update.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) + return + + atom_to_update.atom_flags |= ATOM_AWAITING_OVERLAY_UPDATE + SSoverlays.queue += atom_to_update + /// Immediately runs an overlay update. /atom/proc/ImmediateOverlayUpdate() @@ -147,11 +169,7 @@ SUBSYSTEM_DEF(overlays) /// Enqueues the atom for an overlay update if not already queued /atom/proc/QueueOverlayUpdate() SHOULD_NOT_OVERRIDE(TRUE) - if (atom_flags & ATOM_AWAITING_OVERLAY_UPDATE) - return - atom_flags |= ATOM_AWAITING_OVERLAY_UPDATE - SSoverlays.queue += src - + SSoverlays.enque_atom_overlay_update(src) /// Builds the atom's overlay state from caches /atom/proc/UpdateOverlays() @@ -160,6 +178,7 @@ SUBSYSTEM_DEF(overlays) if (QDELING(src)) LIST_RESIZE(overlays, 0) return + if (length(atom_protected_overlay_cache)) if (length(atom_overlay_cache)) overlays = atom_protected_overlay_cache + atom_overlay_cache @@ -203,7 +222,7 @@ SUBSYSTEM_DEF(overlays) SHOULD_NOT_OVERRIDE(TRUE) if (!sources) return - sources = SSoverlays.GetAppearanceList(src, sources) + sources = SSoverlays.getAppearanceList(src, sources) if (!length(sources)) return if (cache_target & ATOM_ICON_CACHE_PROTECTED) @@ -228,9 +247,11 @@ SUBSYSTEM_DEF(overlays) SHOULD_NOT_OVERRIDE(TRUE) if (!sources) return - sources = SSoverlays.GetAppearanceList(src, sources) + + sources = SSoverlays.getAppearanceList(src, sources) if (!length(sources)) return + var/update if (cache_target & ATOM_ICON_CACHE_PROTECTED) var/outcome = CutCacheBehavior(sources, atom_protected_overlay_cache) @@ -238,12 +259,14 @@ SUBSYSTEM_DEF(overlays) update = TRUE if (outcome == TRUE) atom_protected_overlay_cache = null + if (cache_target & ATOM_ICON_CACHE_NORMAL) var/outcome = CutCacheBehavior(sources, atom_overlay_cache) if (!isnull(outcome)) update = TRUE if (outcome == TRUE) atom_overlay_cache = null + if (update) QueueOverlayUpdate() diff --git a/code/controllers/subsystems/processing/icon_updates.dm b/code/controllers/subsystems/processing/icon_updates.dm index 1d2c918118104..5ce611a23d7f2 100644 --- a/code/controllers/subsystems/processing/icon_updates.dm +++ b/code/controllers/subsystems/processing/icon_updates.dm @@ -4,7 +4,7 @@ SUBSYSTEM_DEF(icon_update) flags = SS_TICKER priority = FIRE_PRIORITY_ICON_UPDATE init_order = SS_INIT_ICON_UPDATE - var/static/list/queue = list() + VAR_PRIVATE/static/list/queue = list() /datum/controller/subsystem/icon_update/Recover() @@ -19,44 +19,47 @@ SUBSYSTEM_DEF(icon_update) /datum/controller/subsystem/icon_update/Initialize(start_uptime) - fire(FALSE, TRUE) - - -/datum/controller/subsystem/icon_update/fire(resumed, no_mc_tick) - var/atom/atom - var/list/params - var/queue_length = length(queue) - for (var/i = 1 to queue_length) - atom = queue[i] - if (QDELETED(atom)) - continue - params = queue[atom] - if (islist(params)) - atom.update_icon(arglist(params)) - else - atom.update_icon() - if (no_mc_tick) - if (i % 100) - continue - CHECK_TICK - else if (MC_TICK_CHECK) - queue.Cut(1, i + 1) - return - if (queue_length) - queue.Cut(1, queue_length + 1) - suspend() + flush_queue() +/datum/controller/subsystem/icon_update/fire(resumed) + var/queue_position = 1 + while(length(queue) >= queue_position) + process_atom_icon_update(queue[queue_position]) + queue_position++ + if(MC_TICK_CHECK) + break + + queue.Cut(1, queue_position) + +/datum/controller/subsystem/icon_update/proc/flush_queue() + var/queue_position = 1 + while(length(queue) >= queue_position) + process_atom_icon_update(queue[queue_position]) + queue_position++ + CHECK_TICK + + LIST_RESIZE(queue, 0) + +/datum/controller/subsystem/icon_update/proc/process_atom_icon_update(atom/atom_to_update) + if(QDELETED(atom_to_update)) + return + + var/list/params = queue[atom_to_update] + if (islist(params)) + atom_to_update.update_icon(arglist(params)) + else + atom_to_update.update_icon() + +/datum/controller/subsystem/icon_update/proc/enque_atom_icon_update(atom/atom_to_update, arguments) + SSicon_update.queue[atom_to_update] = arguments /** * Adds the atom to the icon_update subsystem to be queued for icon updates. Use this if you're going to be pushing a * lot of icon updates at once. */ /atom/proc/queue_icon_update(...) - SSicon_update.queue[src] = length(args) ? args : TRUE - if (SSicon_update.suspended) - SSicon_update.wake() - + SSicon_update.enque_atom_icon_update(src, length(args) ? args : TRUE) -/hook/game_ready/proc/FlushIconUpdateQueue() - SSicon_update.fire(FALSE, TRUE) +/hook/game_ready/proc/flush_icon_update_queue() + SSicon_update.flush_queue() return TRUE diff --git a/code/game/area/area_power.dm b/code/game/area/area_power.dm index 963a86903be97..f67f32b2b282e 100644 --- a/code/game/area/area_power.dm +++ b/code/game/area/area_power.dm @@ -28,9 +28,31 @@ /area/proc/power_change() for(var/obj/machinery/M as anything in machinery_list) // for each machine in the area M.power_change() // reverify power status (to update icons etc.) + SEND_SIGNAL(src, COMSIG_AREA_POWER_CHANGE) if (fire || eject || party) update_icon() +/// Sets the apc in area. Sends COMSIG_AREA_APC_ADDED signal +/area/proc/set_apc(obj/machinery/power/apc/new_apc) + if(!istype(new_apc)) + CRASH("Invalid apc passed [log_info_line(new_apc)]") + + if(apc) + stack_trace("Apc set in area when old one is still present") + remove_apc() + + apc = new_apc + SEND_SIGNAL(src, COMSIG_AREA_APC_ADDED, new_apc) + +/// Removes current apc from area, if present. Sends COMSIG_AREA_APC_REMOVED signal +/area/proc/remove_apc() + if(!apc) + return + + SEND_SIGNAL(src, COMSIG_AREA_APC_REMOVED, apc) + apc = null + + /// Returns Integer. The total amount of power usage queued for the area from both `used_*` and `oneoff_*` for the given power channel, or all channels if `TOTAL` is passed instead. /area/proc/usage(chan) switch(chan) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index d2e549fb6405e..ccbb2f4ac2d85 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -15,7 +15,7 @@ ///2 = wired/built, 1 = circuit installed, 0 = frame var/buildstage = 2 var/number = 0 - var/last_tick //used to delay the powercheck + var/area/linked_area intercom_handling = TRUE /obj/item/device/radio/intercom/get_storage_cost() @@ -93,7 +93,7 @@ /obj/item/device/radio/intercom/Initialize(loc, dir, atom/frame) . = ..() - START_PROCESSING(SSobj, src) + find_and_set_linked_area() if (dir) set_dir(dir) @@ -148,10 +148,6 @@ . = ..() internal_channels[num2text(RAID_FREQ)] = list(access_syndicate) -/obj/item/device/radio/intercom/Destroy() - STOP_PROCESSING(SSobj, src) - return ..() - /obj/item/device/radio/intercom/attack_ai(mob/user) add_fingerprint(user) if (buildstage == 2) @@ -322,26 +318,6 @@ .["Wirecutters"] += "
Used for deconstruction. See deconstruction steps.
" .["Wrench"] += "Used for deconstruction. See deconstruction steps.
" -/obj/item/device/radio/intercom/Process() - if (wiresexposed) - on = FALSE - return - if(((world.timeofday - last_tick) > 30) || ((world.timeofday - last_tick) < 0)) - last_tick = world.timeofday - var/old_on = on - - if(!src.loc) - on = FALSE - else - var/area/A = get_area(src) - if(!A) - on = FALSE - else - on = A.powered(EQUIP) // set "on" to the power status - - if (on != old_on) - update_icon() - /obj/item/device/radio/intercom/on_update_icon() if (buildstage == 2 && wiresexposed) icon_state = "intercom-b2" @@ -349,10 +325,11 @@ icon_state = "intercom-b1" else if (buildstage == 0) icon_state = "intercom-f" - else if (!on) - icon_state = "intercom-p" else - icon_state = "intercom_[broadcasting][listening]" + if(on) + icon_state = "intercom_[broadcasting][listening]" + else + icon_state = "intercom-p" /obj/item/device/radio/intercom/ToggleBroadcast() ..() @@ -362,6 +339,39 @@ ..() update_icon() +/obj/item/device/radio/intercom/proc/find_and_set_linked_area() + var/area/target_area = get_area(src) + if(!target_area.apc) + RegisterSignal(target_area, COMSIG_AREA_APC_ADDED, PROC_REF(on_apc_add)) + return + + on_apc_add(target_area) + +/obj/item/device/radio/intercom/proc/on_apc_add(area/apc_area) + SIGNAL_HANDLER + + UnregisterSignal(apc_area, COMSIG_AREA_APC_ADDED) + linked_area = apc_area + RegisterSignal(apc_area, COMSIG_AREA_APC_REMOVED, PROC_REF(on_apc_removal)) + RegisterSignal(apc_area, COMSIG_AREA_POWER_CHANGE, PROC_REF(change_status)) + +/obj/item/device/radio/intercom/proc/on_apc_removal(area/apc_area) + SIGNAL_HANDLER + + UnregisterSignal(apc_area, COMSIG_AREA_APC_REMOVED) + UnregisterSignal(apc_area, COMSIG_AREA_POWER_CHANGE) + linked_area = null + on = FALSE + update_icon() + + RegisterSignal(apc_area, COMSIG_AREA_APC_ADDED, PROC_REF(on_apc_add)) + +/obj/item/device/radio/intercom/proc/change_status() + SIGNAL_HANDLER + + on = linked_area.powered(EQUIP) + update_icon() + /obj/item/device/radio/intercom/broadcasting broadcasting = 1 diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm index 649e52794e871..01c6ea536ad95 100644 --- a/code/modules/power/apc.dm +++ b/code/modules/power/apc.dm @@ -176,7 +176,7 @@ area = A if(autoname) SetName("\improper [area.name] APC") - area.apc = src + area.set_apc(src) . = ..() @@ -193,8 +193,8 @@ power_change() /obj/machinery/power/apc/Destroy() - src.update() - area.apc = null + update() + area.remove_apc() area.power_light = 0 area.power_equip = 0 area.power_environ = 0