Files
Bloop 7754938c72 Makes a bunch of lists lazy (#94239)
## About The Pull Request

Empy lists. There are a lot of 'em.

<img width="981" height="512" alt="image"
src="https://github.com/user-attachments/assets/b94b041a-2904-466b-ab89-54bd1de11b4e"
/>

Going through ways to reduce memory I found a few easy ones here. Wires,
the edible component, the seethrough component. None of these are really
a concern when it comes to needing lists in memory for performance
reasons. Wires aren't going to be cut most of the time for each door. A
lot of food does not have any junkiness. Seethrough component lies
dormant most of the round. Etc.

Making lists lazy in these cases should be a no brainer.

Everything I tested still seems to work exactly the same.

## Why It's Good For The Game

Frees memory that is just taking up space a lot of the time.

## Changelog

Not player-facing, this is all under-the-hood stuff.
2025-12-03 13:42:16 -07:00

163 lines
6.1 KiB
Plaintext

///A component that lets you turn an object invisible when you're standing on certain relative turfs to it, like behind a tree
/datum/component/seethrough
///A list of turfs on which we make ourself transparent
var/list/watched_turfs
///Associate list, with client = trickery_image. Track which client is being tricked with which image
var/list/tricked_mobs
///Which alpha do we animate towards?
var/target_alpha
///How long our fase in/out takes
var/animation_time
///After we somehow moved (because ss13 is godless and does not respect anything), how long do we need to stand still to feel safe to setup our "behind" area again
var/perimeter_reset_timer
///Does this object let clicks from players its transparent to pass through it
var/clickthrough
/// Define for the area which is considered behind
var/see_through_map
///see_through_map is a define pointing to a specific map. It's basically defining the area which is considered behind. See see_through_maps.dm for a list of maps
/datum/component/seethrough/Initialize(see_through_map = SEE_THROUGH_MAP_DEFAULT, target_alpha = 100, animation_time = 0.5 SECONDS, perimeter_reset_timer = 2 SECONDS, clickthrough = TRUE)
. = ..()
//GLOB.see_through_maps[see_through_map is a list of lists that represent relative coordinates to the source atom
if(!isatom(parent) || !LAZYLEN(GLOB.see_through_maps[see_through_map]))
return COMPONENT_INCOMPATIBLE
src.see_through_map = see_through_map
src.target_alpha = target_alpha
src.animation_time = animation_time
src.perimeter_reset_timer = perimeter_reset_timer
src.clickthrough = clickthrough
RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(dismantle_perimeter))
setup_perimeter(parent)
///Loop through a list with relative coordinate lists to mark those tiles and hide our parent when someone enters those tiles
/datum/component/seethrough/proc/setup_perimeter(atom/parent)
watched_turfs = list()
for(var/list/coordinates as anything in GLOB.see_through_maps[see_through_map])
var/turf/target = TURF_FROM_COORDS_LIST(list(parent.x + coordinates[1], parent.y + coordinates[2], parent.z + coordinates[3]))
if(isnull(target))
continue
RegisterSignal(target, COMSIG_ATOM_ENTERED, PROC_REF(on_entered))
RegisterSignal(target, COMSIG_ATOM_EXITED, PROC_REF(on_exited))
watched_turfs.Add(target)
///Someone entered one of our tiles, so sent an override overlay and a cute animation to make us fade out a bit
/datum/component/seethrough/proc/on_entered(atom/source, atom/movable/entered)
SIGNAL_HANDLER
if(!ismob(entered))
return
var/mob/mob = entered
if(!mob.client)
RegisterSignal(mob, COMSIG_MOB_LOGIN, PROC_REF(trick_mob))
return
if(mob in tricked_mobs)
return
trick_mob(mob)
///Remove the screen object and make us appear solid to the client again
/datum/component/seethrough/proc/on_exited(atom/source, atom/movable/exited, direction)
SIGNAL_HANDLER
if(!ismob(exited))
return
var/mob/mob = exited
if(!mob.client)
UnregisterSignal(mob, COMSIG_MOB_LOGIN)
return
var/turf/moving_to = get_turf(exited)
if(moving_to in watched_turfs)
return
//Check if we're being 'tricked'
if(mob in tricked_mobs)
var/image/trickery_image = tricked_mobs[mob]
animate(trickery_image, alpha = 255, time = animation_time)
LAZYREMOVE(tricked_mobs, mob)
UnregisterSignal(mob, COMSIG_MOB_LOGOUT)
//after playing the fade-in animation, remove the screen obj
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/seethrough,clear_image), trickery_image, mob.client), animation_time)
///Apply the trickery image and animation
/datum/component/seethrough/proc/trick_mob(mob/fool)
var/datum/hud/our_hud = fool.hud_used
for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.unhide_plane(fool)
var/atom/atom_parent = parent
var/image/user_overlay = new(atom_parent)
user_overlay.loc = atom_parent
user_overlay.override = TRUE
if(clickthrough)
//Special plane so we can click through the overlay
SET_PLANE_EXPLICIT(user_overlay, SEETHROUGH_PLANE, atom_parent)
//These are inherited, but we already use the atom's loc so we end up at double the pixel offset
user_overlay.pixel_x = 0
user_overlay.pixel_y = 0
fool.client.images += user_overlay
animate(user_overlay, alpha = target_alpha, time = animation_time)
LAZYSET(tricked_mobs, fool, user_overlay)
RegisterSignal(fool, COMSIG_MOB_LOGOUT, PROC_REF(on_client_disconnect))
///Unrout ourselves after we somehow moved, and start a timer so we can re-restablish our behind area after standing still for a bit
/datum/component/seethrough/proc/dismantle_perimeter()
SIGNAL_HANDLER
for(var/turf in watched_turfs)
UnregisterSignal(turf, list(COMSIG_ATOM_ENTERED, COMSIG_ATOM_EXITED))
watched_turfs = null
clear_all_images()
//Timer override, so if our atom keeps moving the timer is reset until they stop for X time
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/component/seethrough,setup_perimeter), parent), perimeter_reset_timer, TIMER_OVERRIDE | TIMER_UNIQUE)
///Remove a screen image from a client
/datum/component/seethrough/proc/clear_image(image/removee, client/remove_from)
remove_from?.images -= removee //player could've logged out during the animation, so check just in case
/datum/component/seethrough/proc/clear_all_images()
for(var/mob/fool in tricked_mobs)
var/image/trickery_image = tricked_mobs[fool]
fool.client?.images -= trickery_image
UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
var/datum/hud/our_hud = fool.hud_used
for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.hide_plane(fool)
LAZYNULL(tricked_mobs)
///Image is removed when they log out because client gets deleted, so drop the mob reference
/datum/component/seethrough/proc/on_client_disconnect(mob/fool)
SIGNAL_HANDLER
LAZYREMOVE(tricked_mobs, fool)
UnregisterSignal(fool, COMSIG_MOB_LOGOUT)
RegisterSignal(fool, COMSIG_MOB_LOGIN, PROC_REF(trick_mob))
var/datum/hud/our_hud = fool.hud_used
for(var/atom/movable/screen/plane_master/seethrough in our_hud.get_true_plane_masters(SEETHROUGH_PLANE))
seethrough.hide_plane(fool)