mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-23 13:10:02 +01:00
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>
This commit is contained in:
@@ -39,7 +39,7 @@
|
||||
#define POINT_PLANE 5
|
||||
|
||||
//---------- LIGHTING -------------
|
||||
/// Normal 1 per turf dynamic lighting underlays
|
||||
/// Normal 1 per turf dynamic lighting objects
|
||||
#define LIGHTING_PLANE 10
|
||||
|
||||
/// Lighting objects that are "free floating"
|
||||
|
||||
@@ -4,7 +4,7 @@ SUBSYSTEM_DEF(lighting)
|
||||
/datum/controller/subsystem/atoms,
|
||||
/datum/controller/subsystem/mapping,
|
||||
)
|
||||
wait = 2
|
||||
wait = 1
|
||||
ss_flags = SS_TICKER
|
||||
var/static/list/sources_queue = list() // List of lighting sources queued for update.
|
||||
var/static/list/corners_queue = list() // List of lighting corners queued for update.
|
||||
@@ -38,7 +38,7 @@ SUBSYSTEM_DEF(lighting)
|
||||
for(var/turf/area_turf as anything in zlevel_turfs)
|
||||
if(area_turf.space_lit)
|
||||
continue
|
||||
new /datum/lighting_object(area_turf)
|
||||
new /atom/movable/lighting_object(null, area_turf)
|
||||
CHECK_TICK
|
||||
CHECK_TICK
|
||||
|
||||
@@ -53,6 +53,7 @@ SUBSYSTEM_DEF(lighting)
|
||||
|
||||
// UPDATE SOURCE QUEUE
|
||||
var/i = 0
|
||||
// something something cache locally for sonic speed
|
||||
var/list/queue = current_sources
|
||||
while(i < length(queue)) //we don't use for loop here because i cannot be changed during an iteration
|
||||
i += 1
|
||||
@@ -110,7 +111,7 @@ SUBSYSTEM_DEF(lighting)
|
||||
while(i < length(queue)) //we don't use for loop here because i cannot be changed during an iteration
|
||||
i += 1
|
||||
|
||||
var/datum/lighting_object/O = queue[i]
|
||||
var/atom/movable/lighting_object/O = queue[i]
|
||||
if(QDELETED(O))
|
||||
continue
|
||||
O.update()
|
||||
@@ -132,3 +133,13 @@ SUBSYSTEM_DEF(lighting)
|
||||
/datum/controller/subsystem/lighting/Recover()
|
||||
initialized = SSlighting.initialized
|
||||
..()
|
||||
|
||||
/// Takes a list of turfs in, and sets up static lighting for them as needed.
|
||||
/// Exactly what it says on the tin.
|
||||
/datum/controller/subsystem/lighting/proc/setup_static_lighting_if_needed(list/turfs)
|
||||
for(var/turf/unlit as anything in turfs)
|
||||
if(unlit.space_lit)
|
||||
continue
|
||||
var/area/loc_area = unlit.loc
|
||||
if(loc_area.static_lighting)
|
||||
unlit.lighting_build_overlay()
|
||||
|
||||
@@ -744,11 +744,6 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away
|
||||
if(contain_turfs)
|
||||
build_area_turfs(z_value, filled_with_space)
|
||||
|
||||
// And finally, misc global generation
|
||||
|
||||
// We'll have to update this if offsets change, because we load lowest z to highest z
|
||||
generate_lighting_appearance_by_z(z_value)
|
||||
|
||||
/datum/controller/subsystem/mapping/proc/build_area_turfs(z_level, space_guaranteed)
|
||||
// If we know this is filled with default tiles, we can use the default area
|
||||
// Faster
|
||||
@@ -785,11 +780,6 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away
|
||||
z_level_to_lowest_plane_offset[level_to_update.z_value] = plane_offset
|
||||
z_level_to_stack[level_to_update.z_value] = z_stack
|
||||
|
||||
// This can be affected by offsets, so we need to update it
|
||||
// PAIN
|
||||
for(var/i in 1 to length(z_list))
|
||||
generate_lighting_appearance_by_z(i)
|
||||
|
||||
var/old_max = max_plane_offset
|
||||
max_plane_offset = max(max_plane_offset, plane_offset)
|
||||
if(max_plane_offset == old_max)
|
||||
@@ -875,11 +865,6 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away
|
||||
CRASH("Attempted to lazy load a template key that does not exist: '[template_key]'")
|
||||
return target.lazy_load()
|
||||
|
||||
/proc/generate_lighting_appearance_by_z(z_level)
|
||||
if(length(GLOB.default_lighting_underlays_by_z) < z_level)
|
||||
GLOB.default_lighting_underlays_by_z.len = z_level
|
||||
GLOB.default_lighting_underlays_by_z[z_level] = mutable_appearance(LIGHTING_ICON, "transparent", z_level * 0.01, null, LIGHTING_PLANE, 255, RESET_COLOR | RESET_ALPHA | RESET_TRANSFORM, offset_const = GET_Z_PLANE_OFFSET(z_level))
|
||||
|
||||
/// Returns true if the map we're playing on is on a planet
|
||||
/datum/controller/subsystem/mapping/proc/is_planetary()
|
||||
return current_map.planetary
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
loaded_atom_movables |= thing
|
||||
|
||||
SSatoms.InitializeAtoms(loaded_areas + loaded_atom_movables + loaded_turfs)
|
||||
SSlighting.setup_static_lighting_if_needed(loaded_turfs)
|
||||
SSmachines.setup_template_powernets(loaded_cables)
|
||||
SSair.setup_template_machinery(loaded_atmospherics)
|
||||
|
||||
|
||||
@@ -158,8 +158,12 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
|
||||
if(SSlighting.initialized)
|
||||
// Space tiles should never have lighting objects
|
||||
if(!space_lit)
|
||||
if(old_lighting_object)
|
||||
lighting_object = old_lighting_object
|
||||
vis_contents += lighting_object
|
||||
// Should have a lighting object if we never had one
|
||||
lighting_object = old_lighting_object || new /datum/lighting_object(src)
|
||||
else
|
||||
new /atom/movable/lighting_object(null, src)
|
||||
else if (old_lighting_object)
|
||||
qdel(old_lighting_object, force = TRUE)
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ GLOBAL_LIST_EMPTY(station_turfs)
|
||||
var/tmp/lighting_corners_initialised = FALSE
|
||||
|
||||
///Our lighting object.
|
||||
var/tmp/datum/lighting_object/lighting_object
|
||||
var/tmp/atom/movable/lighting_object/lighting_object
|
||||
///Lighting Corner datums.
|
||||
var/tmp/datum/lighting_corner/lighting_corner_NE
|
||||
var/tmp/datum/lighting_corner/lighting_corner_SE
|
||||
|
||||
@@ -19,6 +19,7 @@ GLOBAL_ALIST_EMPTY(reftracker_skip_typecache_b)
|
||||
/icon,
|
||||
/matrix,
|
||||
/regex,
|
||||
/atom/movable/lighting_object, // only contains turf and MA refs
|
||||
/atom/movable/mirage_holder,
|
||||
/atom/movable/render_step/emissive_blocker,
|
||||
/datum/armor,
|
||||
@@ -31,7 +32,6 @@ GLOBAL_ALIST_EMPTY(reftracker_skip_typecache_b)
|
||||
/datum/greyscale_layer,
|
||||
/datum/icon_transformer,
|
||||
/datum/instrument_key,
|
||||
/datum/lighting_object, // only contains turf and MA refs
|
||||
/datum/movespeed_modifier,
|
||||
/datum/painting,
|
||||
/datum/paper_input,
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
return
|
||||
#endif
|
||||
|
||||
var/datum/lighting_object/lighting_object = master_NE?.lighting_object
|
||||
var/atom/movable/lighting_object/lighting_object = master_NE?.lighting_object
|
||||
if (lighting_object && !lighting_object.needs_update)
|
||||
lighting_object.needs_update = TRUE
|
||||
SSlighting.objects_queue += lighting_object
|
||||
@@ -163,10 +163,6 @@
|
||||
|
||||
self_destruct_if_idle()
|
||||
|
||||
|
||||
/datum/lighting_corner/dummy/New()
|
||||
return
|
||||
|
||||
/datum/lighting_corner/Destroy(force)
|
||||
if (!force)
|
||||
return QDEL_HINT_LETMELIVE
|
||||
|
||||
@@ -1,32 +1,50 @@
|
||||
/datum/lighting_object
|
||||
///the underlay we are currently applying to our turf to apply light
|
||||
var/mutable_appearance/current_underlay
|
||||
|
||||
/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
|
||||
|
||||
// Global list of lighting underlays, indexed by z level
|
||||
GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
|
||||
|
||||
/datum/lighting_object/New(turf/source)
|
||||
if(!isturf(source))
|
||||
qdel(src, force=TRUE)
|
||||
stack_trace("a lighting object was assigned to [source], a non turf! ")
|
||||
return
|
||||
/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!")
|
||||
|
||||
. = ..()
|
||||
|
||||
current_underlay = new(GLOB.default_lighting_underlays_by_z[source.z])
|
||||
verbs.Cut()
|
||||
|
||||
affected_turf = source
|
||||
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
|
||||
|
||||
@@ -38,18 +56,20 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
|
||||
needs_update = TRUE
|
||||
SSlighting.objects_queue += src
|
||||
|
||||
/datum/lighting_object/Destroy(force)
|
||||
/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.underlays -= current_underlay
|
||||
affected_turf = null
|
||||
return ..()
|
||||
|
||||
/datum/lighting_object/proc/update()
|
||||
/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.
|
||||
@@ -60,8 +80,6 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
|
||||
|
||||
var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new
|
||||
|
||||
var/turf/affected_turf = src.affected_turf
|
||||
|
||||
#ifdef VISUALIZE_LIGHT_UPDATES
|
||||
affected_turf.add_atom_colour(COLOR_BLUE_LIGHT, ADMIN_COLOUR_PRIORITY)
|
||||
animate(affected_turf, 10, color = null)
|
||||
@@ -84,20 +102,12 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
|
||||
var/set_luminosity = max > 1e-6
|
||||
#endif
|
||||
|
||||
var/mutable_appearance/current_underlay = src.current_underlay
|
||||
affected_turf.underlays -= current_underlay
|
||||
if(red_corner.cache_r & green_corner.cache_r & blue_corner.cache_r & alpha_corner.cache_r && \
|
||||
(red_corner.cache_g + green_corner.cache_g + blue_corner.cache_g + alpha_corner.cache_g + \
|
||||
red_corner.cache_b + green_corner.cache_b + blue_corner.cache_b + alpha_corner.cache_b == 8))
|
||||
//anything that passes the first case is very likely to pass the second, and addition is a little faster in this case
|
||||
current_underlay.icon_state = "lighting_transparent"
|
||||
current_underlay.color = null
|
||||
else if(!set_luminosity)
|
||||
current_underlay.icon_state = "lighting_dark"
|
||||
current_underlay.color = null
|
||||
if(!set_luminosity)
|
||||
icon_state = "lighting_dark"
|
||||
color = null
|
||||
else
|
||||
current_underlay.icon_state = null
|
||||
current_underlay.color = list(
|
||||
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,
|
||||
@@ -105,7 +115,34 @@ GLOBAL_LIST_EMPTY(default_lighting_underlays_by_z)
|
||||
00, 00, 00, 01
|
||||
)
|
||||
|
||||
// Of note. Most of the cost in this proc is here, I think because color matrix'd underlays DO NOT cache well, which is what adding to underlays does
|
||||
// We use underlays because objects on each tile would fuck with maptick. if that ever changes, use an object for this instead
|
||||
affected_turf.underlays += current_underlay
|
||||
affected_turf.luminosity = set_luminosity
|
||||
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"])"
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
if (lighting_object)
|
||||
qdel(lighting_object, force=TRUE) //Shitty fix for lighting objects persisting after death
|
||||
|
||||
new /datum/lighting_object(src)
|
||||
new /atom/movable/lighting_object(null, src)
|
||||
|
||||
// Used to get a scaled lumcount.
|
||||
/turf/proc/get_lumcount(minlum = 0, maxlum = 1)
|
||||
|
||||
@@ -90,14 +90,7 @@
|
||||
return
|
||||
|
||||
SSatoms.InitializeAtoms(areas + turfs + movables, returns_created_atoms ? created_atoms : null)
|
||||
|
||||
for(var/turf/unlit as anything in turfs)
|
||||
if(unlit.space_lit)
|
||||
continue
|
||||
var/area/loc_area = unlit.loc
|
||||
if(!loc_area.static_lighting)
|
||||
continue
|
||||
unlit.lighting_build_overlay()
|
||||
SSlighting.setup_static_lighting_if_needed(turfs)
|
||||
|
||||
// NOTE, now that Initialize and LateInitialize run correctly, do we really
|
||||
// need these two below?
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
atoms += new /obj/effect/appearance_clone(newT, T.loc)
|
||||
if(T.lighting_object)
|
||||
var/obj/effect/appearance_clone/lighting_overlay = new(newT)
|
||||
lighting_overlay.appearance = T.lighting_object.current_underlay
|
||||
lighting_overlay.appearance = T.lighting_object.appearance
|
||||
lighting_overlay.underlays += backdrop
|
||||
lighting_overlay.blend_mode = BLEND_MULTIPLY
|
||||
lighting += lighting_overlay
|
||||
@@ -61,7 +61,7 @@
|
||||
atoms += T
|
||||
if(T.lighting_object)
|
||||
var/obj/effect/appearance_clone/lighting_overlay = new(T)
|
||||
lighting_overlay.appearance = T.lighting_object.current_underlay
|
||||
lighting_overlay.appearance = T.lighting_object.appearance
|
||||
lighting_overlay.underlays += backdrop
|
||||
lighting_overlay.blend_mode = BLEND_MULTIPLY
|
||||
lighting += lighting_overlay
|
||||
|
||||
@@ -78,6 +78,13 @@ All ShuttleMove procs go here
|
||||
|
||||
if(rotation)
|
||||
shuttleRotate(rotation, params = ALL) //see shuttle_rotate.dm
|
||||
|
||||
// if we have a lighting object that needs to be updated
|
||||
if(lighting_object?.needs_update)
|
||||
lighting_object.update()
|
||||
lighting_object.needs_update = FALSE
|
||||
SSlighting.objects_queue -= lighting_object
|
||||
|
||||
SEND_SIGNAL(src, COMSIG_TURF_AFTER_SHUTTLE_MOVE, oldT)
|
||||
|
||||
return TRUE
|
||||
@@ -402,6 +409,9 @@ All ShuttleMove procs go here
|
||||
|
||||
/************************************Misc move procs************************************/
|
||||
|
||||
/atom/movable/lighting_object/onShuttleMove()
|
||||
return FALSE
|
||||
|
||||
/obj/docking_port/mobile/hypotheticalShuttleMove(rotation, move_mode, obj/docking_port/mobile/moving_dock)
|
||||
. = ..()
|
||||
if(moving_dock == src)
|
||||
|
||||
@@ -279,6 +279,9 @@ GLOBAL_VAR_INIT(focused_tests, focused_tests())
|
||||
/obj/effect/decal/cleanable/blood/trail,
|
||||
//Should not exist outside of ethereals
|
||||
/obj/item/stock_parts/power_store/cell/ethereal,
|
||||
// Abstract type, controlled by turfs
|
||||
// Literally errors on creation/deletion
|
||||
/atom/movable/lighting_object,
|
||||
)
|
||||
|
||||
// Everything that follows is a typesof() check.
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 1.5 KiB |
Reference in New Issue
Block a user