Files
Bubberstation/code/modules/lighting/lighting_object.dm
T
Lucy 9b6e752f3e Makes lighting objects objects again (#95332)
## About The Pull Request

Continuation of https://github.com/tgstation/tgstation/pull/78857

FOR TOOO LONG WE HAVE SUFF-
Ok yeah so like, we made them overlays to save on maptick, but with
threaded maptick that is potentially not an issue anymore.
I'm opening this pr so I can tm it and see. If it works, it'll save
about 50% of lighting object update costs, which is pretty damn good.

I'm also removing the fullbright light icon state, since it is barely
ever used (it was added as a clientside op, but we don't hit fullbright
very much at all so it does nothing but eat my cpu time)

Also also changing how SSlighting does its resolution. Rather then
waiting for all sources to process, then working on corners and objects,
instead we will do all the sources we had at the start, then all the
sources after, and so on.
The goal is to avoid churn causing the system to constantly choke. it is
better to potentially double operate then it is for things to feel
horrifically slow.

## Why It's Good For The Game

Faster. Also you won't be able to see lights through walls anymore, so
mesons will be less dumb. Can maybe bump their nightvision a bit idk
we'll see.

## Current Issues

to be found

## Changelog
🆑 Absolucy, LemonInTheDark
fix: You can no longer see lights through walls when using mesons or
when ventcrawling.
/🆑

---------

Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
2026-04-23 08:55:26 +12:00

149 lines
5.4 KiB
Plaintext

/atom/movable/lighting_object
name = ""
anchored = TRUE
plane = LIGHTING_PLANE
icon = LIGHTING_ICON
icon_state = null
color = null //we manually set color in init instead
appearance_flags = RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
invisibility = INVISIBILITY_LIGHTING
move_resist = INFINITY
///whether we are already in the SSlighting.objects_queue list
var/needs_update = FALSE
///the turf that our light is applied to
var/turf/affected_turf
/atom/movable/lighting_object/Initialize(mapload, turf/affected_turf)
if(!isnull(loc))
if(isturf(loc))
affected_turf = loc
moveToNullspace()
stack_trace("a lighting object was improperly initialized - they should have a null loc, with the affected turf being the second argument")
else
qdel(src, force = TRUE)
CRASH("a lighting object tried to be spawned for a non-turf!")
if(!isturf(affected_turf))
qdel(src, force = TRUE)
CRASH("a lighting object was assigned to [affected_turf], a non turf!")
. = ..()
verbs.Cut()
src.affected_turf = affected_turf
layer = affected_turf.z * 0.01
if(SSmapping.max_plane_offset)
// generates the offset lighting plane to use. NOTE: this assumes the turf lighting
// plane is ALWAYS offsettable which is technically dependent on a plane master var.
// checking for that is slower and this is hot enough that this is a worthwhile risk to take
plane = LIGHTING_PLANE - (PLANE_RANGE * GET_Z_PLANE_OFFSET(affected_turf.z))
if (affected_turf.lighting_object)
qdel(affected_turf.lighting_object, force = TRUE)
stack_trace("a lighting object was assigned to a turf that already had a lighting object!")
affected_turf.lighting_object = src
affected_turf.vis_contents += src
// Default to fullbright, so things can "see" if they use view() before we update
affected_turf.luminosity = 1
// This path is really hot. this is faster
// Really this should be a global var or something, but lets not think about that yes?
for(var/turf/open/space/space_tile in RANGE_TURFS(1, affected_turf))
space_tile.enable_starlight()
needs_update = TRUE
SSlighting.objects_queue += src
/atom/movable/lighting_object/Destroy(force)
if (!force)
return QDEL_HINT_LETMELIVE
SSlighting.objects_queue -= src
if (isturf(affected_turf))
affected_turf.vis_contents -= src
affected_turf.lighting_object = null
affected_turf.luminosity = 1
affected_turf = null
return ..()
/atom/movable/lighting_object/proc/update()
var/turf/affected_turf = src.affected_turf
// To the future coder who sees this and thinks
// "Why didn't he just use a loop?"
// Well my man, it's because the loop performed like shit.
// And there's no way to improve it because
// without a loop you can make the list all at once which is the fastest you're gonna get.
// Oh it's also shorter line wise.
// Including with these comments.
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
#ifdef VISUALIZE_LIGHT_UPDATES
affected_turf.add_atom_colour(COLOR_BLUE_LIGHT, ADMIN_COLOUR_PRIORITY)
animate(affected_turf, 10, color = null)
addtimer(CALLBACK(affected_turf, TYPE_PROC_REF(/atom, remove_atom_colour), ADMIN_COLOUR_PRIORITY, COLOR_BLUE_LIGHT), 10, TIMER_UNIQUE|TIMER_OVERRIDE)
#endif
var/datum/lighting_corner/red_corner = affected_turf.lighting_corner_SW || dummy_lighting_corner
var/datum/lighting_corner/green_corner = affected_turf.lighting_corner_SE || dummy_lighting_corner
var/datum/lighting_corner/blue_corner = affected_turf.lighting_corner_NW || dummy_lighting_corner
var/datum/lighting_corner/alpha_corner = affected_turf.lighting_corner_NE || dummy_lighting_corner
var/max = max(red_corner.largest_color_luminosity, green_corner.largest_color_luminosity, blue_corner.largest_color_luminosity, alpha_corner.largest_color_luminosity)
#if LIGHTING_SOFT_THRESHOLD != 0
var/set_luminosity = max > LIGHTING_SOFT_THRESHOLD
#else
// Because of floating points™?, it won't even be a flat 0.
// This number is mostly arbitrary.
var/set_luminosity = max > 1e-6
#endif
if(!set_luminosity)
icon_state = "lighting_dark"
color = null
else
icon_state = null
color = list(
red_corner.cache_r, red_corner.cache_g, red_corner.cache_b, 00,
green_corner.cache_r, green_corner.cache_g, green_corner.cache_b, 00,
blue_corner.cache_r, blue_corner.cache_g, blue_corner.cache_b, 00,
alpha_corner.cache_r, alpha_corner.cache_g, alpha_corner.cache_b, 00,
00, 00, 00, 01
)
luminosity = set_luminosity
// Variety of overrides so the overlays don't get affected by weird things.
/atom/movable/lighting_object/ex_act(severity)
return FALSE
/atom/movable/lighting_object/singularity_act()
return
/atom/movable/lighting_object/singularity_pull()
return
/atom/movable/lighting_object/blob_act()
return
/atom/movable/lighting_object/on_changed_z_level(turf/old_turf, turf/new_turf, same_z_layer, notify_contents = TRUE)
SHOULD_CALL_PARENT(FALSE)
return
/atom/movable/lighting_object/wash(clean_types)
SHOULD_CALL_PARENT(FALSE) // lighting objects are dirty, confirmed
return
// Override here to prevent things accidentally moving around overlays.
/atom/movable/lighting_object/forceMove(atom/destination, no_tp = FALSE, harderforce = FALSE)
if(harderforce)
return ..()
/atom/movable/lighting_object/ref_search_details()
return "[text_ref(src)] (turf: [affected_turf ? "[affected_turf.type] @ [AREACOORD(affected_turf)]" : "null"] needs_update: [needs_update ? "true" : "false"])"