Files
Bubberstation/code/controllers/subsystem/overlays.dm
LemonInTheDark ae5a4f955d Pulls apart the vestiges of components still hanging onto signals (#75914)
## About The Pull Request

Signals were initially only usable with component listeners, which while
no longer the case has lead to outdated documentation, names, and a
similar location in code.

This pr pulls the two apart. Partially because mso thinks we should, but
also because they really aren't directly linked anymore, and having them
in this midstate just confuses people.

[Renames comp_lookup to listen_lookup, since that's what it
does](102b79694f)

[Moves signal procs over to their own
file](33d07d01fd)

[Renames the PREQDELETING and QDELETING comsigs to drop the parent bit
since they can hook to more then just comps
now](335ea4ad08)

[Does something similar to the attackby comsigs (PARENT ->
ATOM)](210e57051d)

[And finally passes over the examine
signals](65917658fb)

## Why It's Good For The Game

Code makes more sense, things are better teased apart, s just good imo

## Changelog
🆑
refactor: Pulled apart the last vestiges of names/docs directly linking
signals to components
/🆑
2023-06-09 06:14:31 +00:00

234 lines
7.6 KiB
Plaintext

SUBSYSTEM_DEF(overlays)
name = "Overlay"
flags = SS_NO_FIRE|SS_NO_INIT
var/list/stats
/datum/controller/subsystem/overlays/PreInit()
stats = list()
/datum/controller/subsystem/overlays/Shutdown()
text2file(render_stats(stats), "[GLOB.log_directory]/overlay.log")
/datum/controller/subsystem/overlays/Recover()
stats = SSoverlays.stats
/// Converts an overlay list into text for debug printing
/// Of note: overlays aren't actually mutable appearances, they're just appearances
/// Don't have access to that type tho, so this is the best you're gonna get
/proc/overlays2text(list/overlays)
var/list/unique_overlays = list()
// As anything because we're basically doing type coerrsion, rather then actually filtering for mutable apperances
for(var/mutable_appearance/overlay as anything in overlays)
var/key = "[overlay.icon]-[overlay.icon_state]-[overlay.dir]"
unique_overlays[key] += 1
var/list/output_text = list()
for(var/key in unique_overlays)
output_text += "([key]) = [unique_overlays[key]]"
return output_text.Join("\n")
/proc/iconstate2appearance(icon, iconstate)
var/static/image/stringbro = new()
stringbro.icon = icon
stringbro.icon_state = iconstate
return stringbro.appearance
/proc/icon2appearance(icon)
var/static/image/iconbro = new()
iconbro.icon = icon
return iconbro.appearance
/atom/proc/build_appearance_list(list/build_overlays)
if (!islist(build_overlays))
build_overlays = list(build_overlays)
for (var/overlay in build_overlays)
if(!overlay)
build_overlays -= overlay
continue
if (istext(overlay))
// This is too expensive to run normally but running it during CI is a good test
if (PERFORM_ALL_TESTS(focus_only/invalid_overlays))
var/list/icon_states_available = icon_states(icon)
if(!(overlay in icon_states_available))
var/icon_file = "[icon]" || "Unknown Generated Icon"
stack_trace("Invalid overlay: Icon object '[icon_file]' [REF(icon)] used in '[src]' [type] is missing icon state [overlay].")
continue
var/index = build_overlays.Find(overlay)
build_overlays[index] = iconstate2appearance(icon, overlay)
else if(isicon(overlay))
var/index = build_overlays.Find(overlay)
build_overlays[index] = icon2appearance(overlay)
return build_overlays
/atom/proc/cut_overlays()
STAT_START_STOPWATCH
overlays = null
POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
/atom/proc/cut_overlay(list/remove_overlays)
if(!overlays)
return
STAT_START_STOPWATCH
overlays -= build_appearance_list(remove_overlays)
POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
/atom/proc/add_overlay(list/add_overlays)
if(!overlays)
return
STAT_START_STOPWATCH
overlays += build_appearance_list(add_overlays)
VALIDATE_OVERLAY_LIMIT(src)
POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
/atom/proc/copy_overlays(atom/other, cut_old) //copys our_overlays from another atom
if(!other)
if(cut_old)
cut_overlays()
return
STAT_START_STOPWATCH
var/list/cached_other = other.overlays.Copy()
if(cut_old)
if(cached_other)
overlays = cached_other
else
overlays = null
VALIDATE_OVERLAY_LIMIT(src)
POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
else if(cached_other)
overlays += cached_other
VALIDATE_OVERLAY_LIMIT(src)
POST_OVERLAY_CHANGE(src)
STAT_STOP_STOPWATCH
STAT_LOG_ENTRY(SSoverlays.stats, type)
//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)
cut_overlays()
return
var/list/cached_other = other.overlays.Copy()
if(cached_other)
if(cut_old || !overlays.len)
overlays = cached_other
else
overlays |= cached_other
else if(cut_old)
cut_overlays()
// Debug procs
/atom
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
/// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the underlays list
var/list/realized_underlays
/image
/// List of overlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the overlays list
var/list/realized_overlays
/// List of underlay "keys" (info about the appearance) -> mutable versions of static appearances
/// Drawn from the underlays list
var/list/realized_underlays
/// Takes the atoms's existing overlays and underlays, and makes them mutable so they can be properly vv'd in the realized_overlays/underlays list
/atom/proc/realize_overlays()
realized_overlays = realize_appearance_queue(overlays)
realized_underlays = realize_appearance_queue(underlays)
/// Takes the image's existing overlays, and makes them mutable so they can be properly vv'd in the realized_overlays list
/image/proc/realize_overlays()
realized_overlays = realize_appearance_queue(overlays)
realized_underlays = realize_appearance_queue(underlays)
/// Takes a list of appearnces, makes them mutable so they can be properly vv'd and inspected
/proc/realize_appearance_queue(list/appearances)
var/list/real_appearances = list()
var/list/queue = appearances.Copy()
var/queue_index = 0
while(queue_index < length(queue))
queue_index++
// If it's not a command, we assert that it's an appearance
var/mutable_appearance/appearance = queue[queue_index]
if(!appearance) // Who fucking adds nulls to their sublists god you people are the worst
continue
var/mutable_appearance/new_appearance = new /mutable_appearance()
new_appearance.appearance = appearance
var/key = "[appearance.icon]-[appearance.icon_state]-[appearance.plane]-[appearance.layer]-[appearance.dir]-[appearance.color]"
var/tmp_key = key
var/appearance_indx = 1
while(real_appearances[tmp_key])
tmp_key = "[key]-[appearance_indx]"
appearance_indx++
real_appearances[tmp_key] = new_appearance
var/add_index = queue_index
// Now check its children
for(var/mutable_appearance/child_appearance as anything in appearance.overlays)
add_index++
queue.Insert(add_index, child_appearance)
for(var/mutable_appearance/child_appearance as anything in appearance.underlays)
add_index++
queue.Insert(add_index, child_appearance)
return real_appearances
/// Takes two appearances as args, prints out, logs, and returns a text representation of their differences
/// Including suboverlays
/proc/diff_appearances(mutable_appearance/first, mutable_appearance/second, iter = 0)
var/list/diffs = list()
var/list/firstdeet = first.vars
var/list/seconddeet = second.vars
var/diff_found = FALSE
for(var/name in first.vars)
var/firstv = firstdeet[name]
var/secondv = seconddeet[name]
if(firstv ~= secondv)
continue
if((islist(firstv) || islist(secondv)) && length(firstv) == 0 && length(secondv) == 0)
continue
if(name == "vars") // Go away
continue
if(name == "_listen_lookup") // This is just gonna happen with marked datums, don't care
continue
if(name == "overlays")
first.realize_overlays()
second.realize_overlays()
var/overlays_differ = FALSE
for(var/i in 1 to length(first.realized_overlays))
if(diff_appearances(first.realized_overlays[i], second.realized_overlays[i], iter + 1))
overlays_differ = TRUE
if(!overlays_differ)
continue
diff_found = TRUE
diffs += "Diffs detected at [name]: First ([firstv]), Second ([secondv])"
var/text = "Depth of: [iter]\n\t[diffs.Join("\n\t")]"
message_admins(text)
log_world(text)
return diff_found