From e85bdb061b5aa7ef6c21d33a2c472ec1858db4ec Mon Sep 17 00:00:00 2001 From: "C.L" Date: Wed, 5 Oct 2022 11:16:58 -0400 Subject: [PATCH 1/3] Upgrades OverlaySS. Fixes #3627 Tested on my test server and nothing appeared to be broken. Overlays were showing up as expected. Ghosts no longer became space/stairs/stole someone's tail --- code/__defines/subsystems.dm | 23 -- code/controllers/subsystems/overlays.dm | 357 +++++++++--------- code/datums/datacore.dm | 13 +- code/game/jobs/job/job.dm | 2 +- .../items/weapons/id cards/station_ids.dm | 3 +- code/modules/admin/admin_verb_lists_vr.dm | 2 +- code/modules/admin/verbs/debug.dm | 5 +- .../mob/new_player/preferences_setup.dm | 2 +- code/modules/resleeving/designer.dm | 6 +- 9 files changed, 181 insertions(+), 232 deletions(-) diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 8ed8125dac..716a1c1540 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -118,26 +118,3 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_G #define FIRE_PRIORITY_CHAT 400 #define FIRE_PRIORITY_OVERLAYS 500 #define FIRE_PRIORITY_INPUT 1000 // This must always always be the max highest priority. Player input must never be lost. - -// Macro defining the actual code applying our overlays lists to the BYOND overlays list. (I guess a macro for speed) -// TODO - I don't really like the location of this macro define. Consider it. ~Leshana -#define COMPILE_OVERLAYS(A)\ - do {\ - var/list/oo = A.our_overlays;\ - var/list/po = A.priority_overlays;\ - if(LAZYLEN(po)){\ - if(LAZYLEN(oo)){\ - A.overlays = oo + po;\ - }\ - else{\ - A.overlays = po;\ - }\ - }\ - else if(LAZYLEN(oo)){\ - A.overlays = oo;\ - }\ - else{\ - A.overlays.Cut();\ - }\ - A.flags &= ~OVERLAY_QUEUED;\ - } while (FALSE) diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index 92400e495b..119685de33 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -1,176 +1,149 @@ SUBSYSTEM_DEF(overlays) name = "Overlay" flags = SS_TICKER - wait = 1 + wait = 1 // SS_TICKER - Ticks priority = FIRE_PRIORITY_OVERLAYS init_order = INIT_ORDER_OVERLAY - var/list/queue // Queue of atoms needing overlay compiling (TODO-VERIFY!) - var/list/stats - var/list/overlay_icon_state_caches // Cache thing - var/list/overlay_icon_cache // Cache thing + /// The queue of atoms that need overlay updates. + var/static/tmp/list/queue = list() - var/static/image/stringbro - var/static/image/iconbro - var/static/image/appearance_bro + /// A list([icon] = list([state] = [appearance], ...), ...) cache of appearances. + var/static/tmp/list/state_cache = list() -/datum/controller/subsystem/overlays/PreInit() - overlay_icon_state_caches = list() - overlay_icon_cache = list() - queue = list() - stats = list() + /// A list([icon] = [appearance], ...) cache of appearances. + var/static/tmp/list/icon_cache = list() - stringbro = new() - iconbro = new() - appearance_bro = new() + /// The number of appearances currently cached. + var/static/tmp/cache_size = 0 -/datum/controller/subsystem/overlays/Initialize() - fire(mc_check = FALSE) - ..() - -/datum/controller/subsystem/overlays/stat_entry() - ..("Ov:[length(queue)]") - - -/datum/controller/subsystem/overlays/Shutdown() - text2file(render_stats(stats), "[log_path]-overlay.log") /datum/controller/subsystem/overlays/Recover() - overlay_icon_state_caches = SSoverlays.overlay_icon_state_caches - overlay_icon_cache = SSoverlays.overlay_icon_cache - queue = SSoverlays.queue + queue.Cut() + state_cache.Cut() + icon_cache.Cut() + cache_size = 0 + for (var/atom/atom) + atom.flags &= ~OVERLAY_QUEUED + CHECK_TICK -/datum/controller/subsystem/overlays/fire(resumed = FALSE, mc_check = TRUE) - var/list/queue = src.queue - var/static/count = 0 - if (count) - var/c = count - count = 0 //so if we runtime on the Cut, we don't try again. - queue.Cut(1,c+1) +/datum/controller/subsystem/overlays/Initialize(timeofday) + fire(FALSE, TRUE) - for (var/thing in queue) - count++ - if(thing) - STAT_START_STOPWATCH - var/atom/A = thing - COMPILE_OVERLAYS(A) - STAT_STOP_STOPWATCH - STAT_LOG_ENTRY(stats, A.type) - if(mc_check) - if(MC_TICK_CHECK) - break - else + +/datum/controller/subsystem/overlays/stat_entry() + ..("Queued Atoms: [queue.len], Cache Size: [cache_size]") + + +/datum/controller/subsystem/overlays/fire(resumed, no_mc_tick) + var/count = 1 + for (var/atom/atom as anything in queue) + ++count + atom?.UpdateOverlays() + if (no_mc_tick) CHECK_TICK + else if (MC_TICK_CHECK) + queue.Cut(1, count) + return + queue.Cut() - if (count) - queue.Cut(1,count+1) - count = 0 -/proc/iconstate2appearance(icon, iconstate) - // var/static/image/stringbro = new() // Moved to be superglobal due to BYOND insane init order stupidness. - var/list/icon_states_cache = SSoverlays.overlay_icon_state_caches - var/list/cached_icon = icon_states_cache[icon] - if (cached_icon) - var/cached_appearance = cached_icon["[iconstate]"] - if (cached_appearance) - return cached_appearance - SSoverlays.stringbro.icon = icon - SSoverlays.stringbro.icon_state = iconstate - if (!cached_icon) //not using the macro to save an associated lookup - cached_icon = list() - icon_states_cache[icon] = cached_icon - var/cached_appearance = SSoverlays.stringbro.appearance - cached_icon["[iconstate]"] = cached_appearance - return cached_appearance +/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 = new (icon, null, state) + subcache[state] = image.appearance + ++cache_size + return subcache[state] -/proc/icon2appearance(icon) - // var/static/image/iconbro = new() // Moved to be superglobal due to BYOND insane init order stupidness. - var/list/icon_cache = SSoverlays.overlay_icon_cache - . = icon_cache[icon] - if (!.) - SSoverlays.iconbro.icon = icon - . = SSoverlays.iconbro.appearance - icon_cache[icon] = . -/atom/proc/build_appearance_list(old_overlays) - // var/static/image/appearance_bro = new() // Moved to be superglobal due to BYOND insane init order stupidness. - var/list/new_overlays = list() - if (!islist(old_overlays)) - old_overlays = list(old_overlays) - for (var/overlay in old_overlays) - if(!overlay) +/datum/controller/subsystem/overlays/proc/GetIconAppearance(icon) + if (!icon_cache[icon]) + var/image/image = new (icon) + icon_cache[icon] = image.appearance + ++cache_size + return icon_cache[icon] + + +/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 + for (var/atom/entry as anything in sources) + if (!entry) continue - if (istext(overlay)) - new_overlays += iconstate2appearance(icon, overlay) - else if(isicon(overlay)) - new_overlays += icon2appearance(overlay) + else if (istext(entry)) + result += GetStateAppearance(icon, entry) + else if (isicon(entry)) + result += GetIconAppearance(entry) else - if(isloc(overlay)) - var/atom/A = overlay - if (A.flags & OVERLAY_QUEUED) - COMPILE_OVERLAYS(A) - SSoverlays.appearance_bro.appearance = overlay //this works for images and atoms too! - if(!ispath(overlay)) - var/image/I = overlay - SSoverlays.appearance_bro.dir = I.dir - new_overlays += SSoverlays.appearance_bro.appearance - return new_overlays + if (isloc(entry)) + if (entry.flags & OVERLAY_QUEUED) + entry.ImmediateOverlayUpdate() + if (!ispath(entry)) + result += entry.appearance + else + var/image/image = entry + result += image.appearance + return result -#define NOT_QUEUED_ALREADY (!(flags & OVERLAY_QUEUED)) -#define QUEUE_FOR_COMPILE flags |= OVERLAY_QUEUED; SSoverlays.queue += src; -/** - * Cut all of atom's normal overlays. Usually leaves "priority" overlays untouched. - * - * @param priority If true, also will cut priority overlays. - */ -/atom/proc/cut_overlays(priority = FALSE) - var/list/cached_overlays = our_overlays - var/list/cached_priority = priority_overlays - - var/need_compile = FALSE - - if(LAZYLEN(cached_overlays)) //don't queue empty lists, don't cut priority overlays - cached_overlays.Cut() //clear regular overlays - need_compile = TRUE - - if(priority && LAZYLEN(cached_priority)) - cached_priority.Cut() - need_compile = TRUE - - if(NOT_QUEUED_ALREADY && need_compile) - QUEUE_FOR_COMPILE - -/** - * Removes specific overlay(s) from the atom. Usually does not remove them from "priority" overlays. - * - * @param overlays The overlays to removed, type can be anything that is allowed for add_overlay(). - * @param priority If true, also will remove them from the "priority" overlays. - */ -/atom/proc/cut_overlay(list/overlays, priority) - if(!overlays) +/// Enqueues the atom for an overlay update if not already queued +/atom/proc/QueueOverlayUpdate() + if (flags & OVERLAY_QUEUED) return + SSoverlays.queue += src + flags |= OVERLAY_QUEUED - overlays = build_appearance_list(overlays) - var/list/cached_overlays = our_overlays //sanic - var/list/cached_priority = priority_overlays - var/init_o_len = LAZYLEN(cached_overlays) - var/init_p_len = LAZYLEN(cached_priority) //starter pokemon +/// Builds the atom's overlay state from caches +/atom/proc/UpdateOverlays() + if (gc_destroyed) + if (length(overlays)) + overlays.Cut() + return + flags &= ~OVERLAY_QUEUED + if (length(priority_overlays)) + if (length(our_overlays)) + overlays = priority_overlays + our_overlays + else + overlays = priority_overlays + else if (length(our_overlays)) + overlays = our_overlays + else + overlays.Cut() - LAZYREMOVE(cached_overlays, overlays) - if(priority) - LAZYREMOVE(cached_priority, overlays) - if(NOT_QUEUED_ALREADY && ((init_o_len != LAZYLEN(cached_overlays)) || (init_p_len != LAZYLEN(cached_priority)))) - QUEUE_FOR_COMPILE +/// Immediately runs an overlay update and dequeues the atom +/atom/proc/ImmediateOverlayUpdate() + SSoverlays.queue -= src + UpdateOverlays() + + +/// Clears the atom's overlay cache(s) and queues an update if needed +/atom/proc/cut_overlays(priority) + if (priority) + if (!length(priority_overlays)) + return + priority_overlays.Cut() + QueueOverlayUpdate() + else if (length(our_overlays)) + our_overlays.Cut() + QueueOverlayUpdate() + /** * Adds specific overlay(s) to the atom. * It is designed so any of the types allowed to be added to /atom/overlays can be added here too. More details below. * - * @param overlays The overlay(s) to add. These may be + * @param add The overlay(s) to add. These may be * - A string: In which case it is treated as an icon_state of the atom's icon. * - An icon: It is treated as an icon. * - An atom: Its own overlays are compiled and then it's appearance is added. (Meaning its current apperance is frozen). @@ -179,30 +152,46 @@ SUBSYSTEM_DEF(overlays) * - Or a list containing any of the above. * @param priority The overlays are added to the "priority" list istead of the normal one. */ -/atom/proc/add_overlay(list/overlays, priority = FALSE) - if(!overlays) +/atom/proc/add_overlay(list/add, priority) + if (!add) return - - overlays = build_appearance_list(overlays) - - LAZYINITLIST(our_overlays) //always initialized after this point - LAZYINITLIST(priority_overlays) - - var/list/cached_overlays = our_overlays //sanic - var/list/cached_priority = priority_overlays - var/init_o_len = cached_overlays.len - var/init_p_len = cached_priority.len //starter pokemon - var/need_compile - - if(priority) - cached_priority += overlays //or in the image. Can we use [image] = image? - need_compile = init_p_len != cached_priority.len + add = SSoverlays.GetAppearanceList(src, add) + if (!length(add)) + return + if (priority) + if (priority_overlays) + priority_overlays += add + else + priority_overlays = add + else if (our_overlays) + our_overlays += add else - cached_overlays += overlays - need_compile = init_o_len != cached_overlays.len + our_overlays = add + QueueOverlayUpdate() + + +/** + * Removes specific overlay(s) from the atom. Usually does not remove them from "priority" overlays. + * + * @param overlays The overlays to removed, type can be anything that is allowed for add_overlay(). + * @param priority If true, also will remove them from the "priority" overlays. + */ +/atom/proc/cut_overlay(list/cut, priority) + if (!cut) + return + cut = SSoverlays.GetAppearanceList(src, cut) + if (!length(cut)) + return + var/update + if (priority && length(priority_overlays)) + priority_overlays -= cut + update = TRUE + if (length(our_overlays)) + our_overlays -= cut + update = TRUE + if (update) + QueueOverlayUpdate() - if(NOT_QUEUED_ALREADY && need_compile) //have we caught more pokemon? - QUEUE_FOR_COMPILE /** * Copy the overlays from another atom, either replacing all of ours or appending to our existing overlays. @@ -211,22 +200,21 @@ SUBSYSTEM_DEF(overlays) * @param other The atom to copy overlays from. * @param cut_old If true, all of our overlays will be *replaced* by the other's. If other is null, that means cutting all ours. */ -/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom - if(!other) - if(cut_old) +/atom/proc/copy_overlays(atom/other, cut) + if (!other) + if (cut) cut_overlays() return + if (!length(other.our_overlays)) + if (cut) + cut_overlays() + return + if (cut || !length(our_overlays)) + our_overlays = other.our_overlays.Copy() + else + our_overlays |= other.our_overlays + QueueOverlayUpdate() - var/list/cached_other = other.our_overlays - if(cached_other) - if(cut_old || !LAZYLEN(our_overlays)) - our_overlays = cached_other.Copy() - else - our_overlays |= cached_other - if(NOT_QUEUED_ALREADY) - QUEUE_FOR_COMPILE - else if(cut_old) - cut_overlays() /** * Returns a list of overlays that the target atom has @@ -236,37 +224,32 @@ SUBSYSTEM_DEF(overlays) */ /proc/get_overlays(atom/other, priority, special) var/list/including = list() - if(!other) + if (!other) return including - - for(var/image/I as anything in other.our_overlays) - if(!special && I.plane > 0) + for (var/image/I as anything in other.our_overlays) + if (!special && I.plane > 0) continue including += I - - if(!priority) + if (!priority) return including - - for(var/image/I as anything in other.priority_overlays) - if(!special && I.plane > 0) + for (var/image/I as anything in other.priority_overlays) + if (!special && I.plane > 0) continue including += I - return including -#undef NOT_QUEUED_ALREADY -#undef QUEUE_FOR_COMPILE - -//TODO: Better solution for these? /image/proc/add_overlay(x) overlays += x + /image/proc/cut_overlay(x) overlays -= x + /image/proc/cut_overlays(x) overlays.Cut() + /image/proc/copy_overlays(atom/other, cut_old) if(!other) if(cut_old) diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm index b2ff9beff4..04f489be7c 100644 --- a/code/datums/datacore.dm +++ b/code/datums/datacore.dm @@ -338,18 +338,7 @@ var/global/list/PDA_Manifest = list() var/datum/job/J = SSjob.get_job(H.mind.assigned_role) hidden = J?.offmap_spawn - /* Note: Due to cached_character_icon, a number of emergent properties occur due to the initialization - * order of readied-up vs latejoiners. Namely, latejoiners will get a uniform in their datacore picture, but readied-up will - * not. This is due to the fact that SSticker calls data_core.manifest_inject() inside of ticker/proc/create_characters(), - * but does not equip them until ticker/proc/equip_characters(), which is called later. So, this proc is literally called before - * they ever get their equipment, and so it can't get a picture of them in their equipment. - * Latejoiners do not have this problem, because /mob/new_player/proc/AttemptLateSpawn calls EquipRank() before it calls - * this proc, which means that they're already clothed by the time they get their picture taken here. - * The COMPILE_OVERLAYS() here is just to bypass SSoverlays taking for-fucking-ever to update the mob, since we're about to - * take a picture of them, we want all the overlays. - */ - COMPILE_OVERLAYS(H) - SSoverlays.queue -= H + H.ImmediateOverlayUpdate() var/id = generate_record_id() //General Record diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm index 509572aa98..cf09d52861 100644 --- a/code/game/jobs/job/job.dm +++ b/code/game/jobs/job/job.dm @@ -147,7 +147,7 @@ var/mob/living/carbon/human/dummy/mannequin/mannequin = get_mannequin("#job_icon") dress_mannequin(mannequin) mannequin.dir = SOUTH - COMPILE_OVERLAYS(mannequin) + mannequin.ImmediateOverlayUpdate() var/icon/preview_icon = getFlatIcon(mannequin) preview_icon.Scale(preview_icon.Width() * 2, preview_icon.Height() * 2) // Scaling here to prevent blurring in the browser. diff --git a/code/game/objects/items/weapons/id cards/station_ids.dm b/code/game/objects/items/weapons/id cards/station_ids.dm index 148df8db50..9154f34843 100644 --- a/code/game/objects/items/weapons/id cards/station_ids.dm +++ b/code/game/objects/items/weapons/id cards/station_ids.dm @@ -53,8 +53,7 @@ name = "[src.registered_name]'s ID Card ([src.assignment])" /obj/item/weapon/card/id/proc/set_id_photo(var/mob/M) - COMPILE_OVERLAYS(M) - SSoverlays.queue -= M + M.ImmediateOverlayUpdate() var/icon/F = getFlatIcon(M, defdir = SOUTH, no_anim = TRUE) front = "'data:image/png;base64,[icon2base64(F)]'" diff --git a/code/modules/admin/admin_verb_lists_vr.dm b/code/modules/admin/admin_verb_lists_vr.dm index 75def8052b..d5356564bf 100644 --- a/code/modules/admin/admin_verb_lists_vr.dm +++ b/code/modules/admin/admin_verb_lists_vr.dm @@ -230,7 +230,7 @@ var/list/admin_verbs_debug = list( /client/proc/cmd_debug_tog_aliens, /client/proc/cmd_display_del_log, /client/proc/cmd_display_init_log, - /client/proc/cmd_display_overlay_log, + // /client/proc/cmd_display_overlay_log, /client/proc/air_report, /client/proc/reload_admins, /client/proc/reload_eventMs, diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index c2e4b671f7..e453842124 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -249,6 +249,7 @@ if(!check_rights(R_DEBUG)) return src << browse(replacetext(SSatoms.InitLog(), "\n", "
"), "window=initlog") +/* /client/proc/cmd_display_overlay_log() set category = "Debug" set name = "Display overlay Log" @@ -256,7 +257,7 @@ if(!check_rights(R_DEBUG)) return render_stats(SSoverlays.stats, src) - +*/ // Render stats list for round-end statistics. /proc/render_stats(list/stats, user, sort = /proc/cmp_generic_stat_item_time) sortTim(stats, sort, TRUE) @@ -676,4 +677,4 @@ var/log = "[key_name(src)] changed [planet.name]'s time to [planet.current_time.show_time("hh:mm")]." message_admins(log) - log_admin(log) \ No newline at end of file + log_admin(log) diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm index c2e5a31951..f3dfe624ba 100644 --- a/code/modules/mob/new_player/preferences_setup.dm +++ b/code/modules/mob/new_player/preferences_setup.dm @@ -262,7 +262,7 @@ mannequin.toggle_tail(setting = TRUE) mannequin.toggle_wing(setting = TRUE) mannequin.update_tail_showing() - COMPILE_OVERLAYS(mannequin) + mannequin.ImmediateOverlayUpdate() update_character_previews(new /mutable_appearance(mannequin)) diff --git a/code/modules/resleeving/designer.dm b/code/modules/resleeving/designer.dm index 3bc4cf64bb..66de574997 100644 --- a/code/modules/resleeving/designer.dm +++ b/code/modules/resleeving/designer.dm @@ -263,7 +263,7 @@ if("menu") menu = params["menu"] temp = "" - + if("href_conversion") PrefHrefMiddleware(params, usr) @@ -281,8 +281,8 @@ mannequin.delete_inventory(TRUE) update_preview_mob(mannequin) - COMPILE_OVERLAYS(mannequin) - + mannequin.ImmediateOverlayUpdate() + var/mutable_appearance/MA = new(mannequin) south_preview.appearance = MA south_preview.dir = SOUTH From a5b52257a31fc4a44d9c36c478d876323e62b9a6 Mon Sep 17 00:00:00 2001 From: "C.L" Date: Wed, 5 Oct 2022 11:50:27 -0400 Subject: [PATCH 2/3] wake up travis --- code/modules/power/smes_vr.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/power/smes_vr.dm b/code/modules/power/smes_vr.dm index a333660a43..fe46cae7f0 100644 --- a/code/modules/power/smes_vr.dm +++ b/code/modules/power/smes_vr.dm @@ -32,3 +32,5 @@ /obj/machinery/power/smes/buildable/hybrid/process() charge += min(recharge_rate, capacity - charge) ..() + +//hey travis wake up \ No newline at end of file From d1901aed214ceb35dd1b40d9a532994d95a0a60e Mon Sep 17 00:00:00 2001 From: "C.L" Date: Wed, 5 Oct 2022 18:44:52 -0400 Subject: [PATCH 3/3] gives it the has-been-initalized flag --- code/controllers/subsystems/overlays.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm index 119685de33..25dbfbd62a 100644 --- a/code/controllers/subsystems/overlays.dm +++ b/code/controllers/subsystems/overlays.dm @@ -30,7 +30,7 @@ SUBSYSTEM_DEF(overlays) /datum/controller/subsystem/overlays/Initialize(timeofday) fire(FALSE, TRUE) - + ..() /datum/controller/subsystem/overlays/stat_entry() ..("Queued Atoms: [queue.len], Cache Size: [cache_size]")