mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-28 18:21:51 +00:00
Our SSOverlays system is outdated, and is likely the cause of many of the issues seen in #18895. It has also been linked to a massive server performance decrease. This brings an updated system from Baystation, hopefully with speed increases. Should be testmerged, ideally with #18895. --------- Co-authored-by: Cody Brittain <cbrittain10@live.com>
308 lines
8.9 KiB
Plaintext
308 lines
8.9 KiB
Plaintext
/// SSoverlays. Target the normal overlay cache.
|
|
var/global/const/ATOM_ICON_CACHE_NORMAL = FLAG(0)
|
|
|
|
/// SSoverlays. Target the protected overlay cache.
|
|
var/global/const/ATOM_ICON_CACHE_PROTECTED = FLAG(1)
|
|
|
|
/// SSoverlays. Target both normal and protected overlay caches.
|
|
var/global/const/ATOM_ICON_CACHE_ALL = (ATOM_ICON_CACHE_NORMAL | ATOM_ICON_CACHE_PROTECTED)
|
|
|
|
|
|
SUBSYSTEM_DEF(overlays)
|
|
name = "Overlays"
|
|
flags = SS_TICKER
|
|
wait = 1 // ticks
|
|
priority = SS_PRIORITY_OVERLAY
|
|
init_order = INIT_ORDER_OVERLAY
|
|
|
|
/// The queue of atoms that need under/overlay updates.
|
|
var/static/list/atom/queue = list()
|
|
|
|
/// A list([icon] = list([state] = [appearance], ...), ...) cache of appearances.
|
|
var/static/list/state_cache = list()
|
|
|
|
/// A list([icon] = [appearance], ...) cache of appearances.
|
|
var/static/list/icon_cache = list()
|
|
|
|
/// The number of appearances currently cached.
|
|
var/static/cache_size = 0
|
|
|
|
initialized = FALSE
|
|
|
|
/datum/controller/subsystem/overlays/Recover()
|
|
LIST_RESIZE(queue, 0)
|
|
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
|
|
CHECK_TICK
|
|
|
|
/datum/controller/subsystem/overlays/Initialize(start_uptime)
|
|
initialized = TRUE
|
|
fire(FALSE, TRUE)
|
|
|
|
return SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/overlays/stat_entry(msg)
|
|
msg = "Queued Atoms: [length(queue)], Cache Size: [cache_size]"
|
|
return ..()
|
|
|
|
/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/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]
|
|
|
|
|
|
/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]
|
|
|
|
|
|
/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)
|
|
continue
|
|
else if (istext(entry))
|
|
result += GetStateAppearance(icon, entry)
|
|
else if (isicon(entry))
|
|
result += GetIconAppearance(entry)
|
|
else
|
|
if (isloc(entry))
|
|
if (entry.atom_flags & ATOM_AWAITING_OVERLAY_UPDATE)
|
|
entry.UpdateOverlays()
|
|
if (!ispath(entry))
|
|
result += entry.appearance
|
|
else
|
|
var/image/image = entry
|
|
result += image.appearance
|
|
return result
|
|
|
|
|
|
/// Immediately runs an overlay update.
|
|
/atom/proc/ImmediateOverlayUpdate()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
UpdateOverlays()
|
|
|
|
/**
|
|
* Shared behavior for ClearOverlays & CutUnderlays. Do not use directly.
|
|
* null: nothing changed, do nothing
|
|
* FALSE: update should be queued
|
|
* TRUE: update should be queued, cache should be nulled
|
|
*/
|
|
/atom/proc/CutCacheBehavior(sources, cache)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
var/initial_length = length(cache)
|
|
if (!initial_length)
|
|
return
|
|
cache -= sources
|
|
var/after_length = length(cache)
|
|
if (!after_length)
|
|
return TRUE
|
|
if (initial_length > after_length)
|
|
return FALSE
|
|
|
|
|
|
/// 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
|
|
|
|
|
|
/// Builds the atom's overlay state from caches
|
|
/atom/proc/UpdateOverlays()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
atom_flags &= ~ATOM_AWAITING_OVERLAY_UPDATE
|
|
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
|
|
else
|
|
overlays = atom_protected_overlay_cache
|
|
else if (length(atom_overlay_cache))
|
|
overlays = atom_overlay_cache
|
|
else
|
|
LIST_RESIZE(overlays, 0)
|
|
|
|
|
|
/// Clears the atom's overlay cache(s) and queues an update if needed. Use CLEAR_TARGET_* flags.
|
|
/atom/proc/ClearOverlays(cache_target = ATOM_ICON_CACHE_NORMAL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if (cache_target & ATOM_ICON_CACHE_PROTECTED)
|
|
if (!atom_protected_overlay_cache)
|
|
return
|
|
LAZYCLEARLIST(atom_protected_overlay_cache)
|
|
QueueOverlayUpdate()
|
|
if (cache_target & ATOM_ICON_CACHE_NORMAL)
|
|
if (!atom_overlay_cache)
|
|
return
|
|
LAZYCLEARLIST(atom_overlay_cache)
|
|
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 sources 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).
|
|
* - An image: Image's apperance is added (i.e. subsequently editing the image will not edit the overlay)
|
|
* - A type path: Added to overlays as is. Does whatever it is BYOND does when you add paths to overlays.
|
|
* - Or a list containing any of the above.
|
|
* @param cache_target If ATOM_ICON_CACHE_PROTECTED, add to the protected cache instead of normal.
|
|
*/
|
|
/atom/proc/AddOverlays(sources, cache_target = ATOM_ICON_CACHE_NORMAL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if (!sources)
|
|
return
|
|
sources = SSoverlays.GetAppearanceList(src, sources)
|
|
if (!length(sources))
|
|
return
|
|
if (cache_target & ATOM_ICON_CACHE_PROTECTED)
|
|
if (atom_protected_overlay_cache)
|
|
atom_protected_overlay_cache += sources
|
|
else
|
|
atom_protected_overlay_cache = sources
|
|
else if (atom_overlay_cache)
|
|
atom_overlay_cache += sources
|
|
else
|
|
atom_overlay_cache = sources
|
|
QueueOverlayUpdate()
|
|
|
|
|
|
/**
|
|
* Removes specific overlay(s) from the atom's normal or protected overlay cache and queue an update.
|
|
*
|
|
* @param overlays The overlays to removed. See AddOverlays for legal source types.
|
|
* @param cache_target A mask of ICON_CACHE_TARGET_*.
|
|
*/
|
|
/atom/proc/CutOverlays(sources, cache_target = ATOM_ICON_CACHE_NORMAL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if (!sources)
|
|
return
|
|
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)
|
|
if (!isnull(outcome))
|
|
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()
|
|
|
|
|
|
/// AddOverlays with ClearOverlays first. See AddOverlays for behavior.
|
|
/atom/proc/SetOverlays(sources, cache_target = ATOM_ICON_CACHE_NORMAL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
ClearOverlays(cache_target)
|
|
AddOverlays(sources, cache_target)
|
|
|
|
|
|
/**
|
|
* Copy the overlays from another atom.
|
|
*
|
|
* @param other The atom to copy overlays from.
|
|
* @param clear If TRUE, clear before adding other's overlays.
|
|
* @param cache_target A mask of ICON_CACHE_TARGET_* indicating what to copy.
|
|
*/
|
|
/atom/proc/CopyOverlays(atom/other, clear, cache_target = ATOM_ICON_CACHE_NORMAL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if (clear)
|
|
ClearOverlays(cache_target)
|
|
if (!istype(other))
|
|
return
|
|
if (cache_target & ATOM_ICON_CACHE_PROTECTED)
|
|
AddOverlays(other.atom_protected_overlay_cache, ATOM_ICON_CACHE_PROTECTED)
|
|
if (cache_target & ATOM_ICON_CACHE_NORMAL)
|
|
AddOverlays(other.atom_overlay_cache, ATOM_ICON_CACHE_NORMAL)
|
|
|
|
|
|
// Skin-deep API parity for images.
|
|
// Reference <https://www.byond.com/docs/ref/#/atom/var/overlays> for permitted types.
|
|
|
|
/// Adds sources to the image's overlays.
|
|
/image/proc/AddOverlays(sources)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
overlays |= sources
|
|
|
|
|
|
/// Removes sources from the image's overlays.
|
|
/image/proc/CutOverlays(sources)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
overlays -= sources
|
|
|
|
|
|
/// Removes all of the image's overlays.
|
|
/image/proc/ClearOverlays()
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
LIST_RESIZE(overlays, 0)
|
|
|
|
|
|
/// Copies the overlays from the atom other, clearing first if set, and using the caches indicated.
|
|
/image/proc/CopyOverlays(atom/other, clear, cache_target = ATOM_ICON_CACHE_ALL)
|
|
SHOULD_NOT_OVERRIDE(TRUE)
|
|
if (clear)
|
|
LIST_RESIZE(overlays, 0)
|
|
if (!istype(other))
|
|
return
|
|
if (cache_target & ATOM_ICON_CACHE_PROTECTED)
|
|
overlays |= other.atom_protected_overlay_cache
|
|
if (cache_target & ATOM_ICON_CACHE_NORMAL)
|
|
overlays |= other.atom_overlay_cache
|
|
|