From e0c3019dc30dd5487d596b0d7bb5395538127aae Mon Sep 17 00:00:00 2001 From: Kyle Spier-Swenson Date: Thu, 10 Jun 2021 14:42:11 -0700 Subject: [PATCH] [READY] Lighting list cleanup. (#59002) Removed a bunch of back reference lists that were either entirely unused, or contained references that could be found within the datums contained in other lists. lighting corner datums now get deleted with unused. light sources no longer track lighting corners where the appiled light rounds to 0. Fix lighting on turfs that gained dynamic lighting mid round. lazy init corner datums. these two are related. by decoupling corner datums from the turfs dynamic lighting state, we can use them to know what level of light a non-dynamic light turf should have once it gains dynamic light. Also should free up some memory not storing these datums in maint. Corner datums only exist on a turf that has light cast upon it by the dynamic lighting system. Lighting corners are now lazy inited and deleted. they should always (and only exist) if there is a light source shining on it within range (even if the turf has no dynamic lighting). This is needed to support turfs that become lighting enabled mid round. On the plus side, they will no longer be generated on full dark turfs. --- code/controllers/subsystem/lighting.dm | 3 +- code/game/turfs/change_turf.dm | 14 ++- code/game/turfs/turf.dm | 9 +- code/modules/lighting/lighting_corner.dm | 114 ++++++++++++------- code/modules/lighting/lighting_object.dm | 14 +-- code/modules/lighting/lighting_source.dm | 134 +++++++++-------------- code/modules/lighting/lighting_turf.dm | 72 +++++------- 7 files changed, 174 insertions(+), 186 deletions(-) diff --git a/code/controllers/subsystem/lighting.dm b/code/controllers/subsystem/lighting.dm index 992b1d12c92..808e3074a36 100644 --- a/code/controllers/subsystem/lighting.dm +++ b/code/controllers/subsystem/lighting.dm @@ -55,8 +55,9 @@ SUBSYSTEM_DEF(lighting) for (i in 1 to length(queue)) var/datum/lighting_corner/C = queue[i] + C.needs_update = FALSE //update_objects() can call qdel if the corner is storing no data C.update_objects() - C.needs_update = FALSE + if(init_tick_checks) CHECK_TICK else if (MC_TICK_CHECK) diff --git a/code/game/turfs/change_turf.dm b/code/game/turfs/change_turf.dm index b5bc7f1be6f..df8a08c4295 100644 --- a/code/game/turfs/change_turf.dm +++ b/code/game/turfs/change_turf.dm @@ -77,9 +77,11 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( return new path(src) var/old_dynamic_lighting = dynamic_lighting - var/old_affecting_lights = affecting_lights var/old_lighting_object = lighting_object - var/old_corners = corners + var/old_lighting_corner_NE = lighting_corner_NE + var/old_lighting_corner_SE = lighting_corner_SE + var/old_lighting_corner_SW = lighting_corner_SW + var/old_lighting_corner_NW = lighting_corner_NW var/old_directional_opacity = directional_opacity var/old_rcd_memory = rcd_memory @@ -110,10 +112,14 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list( W.blueprint_data = old_bp W.rcd_memory = old_rcd_memory + lighting_corner_NE = old_lighting_corner_NE + lighting_corner_SE = old_lighting_corner_SE + lighting_corner_SW = old_lighting_corner_SW + lighting_corner_NW = old_lighting_corner_NW + if(SSlighting.initialized) lighting_object = old_lighting_object - affecting_lights = old_affecting_lights - corners = old_corners + directional_opacity = old_directional_opacity recalculate_directional_opacity() diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 8e69b52a768..e080f83a927 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -45,11 +45,14 @@ GLOBAL_LIST_EMPTY(station_turfs) var/tmp/lighting_corners_initialised = FALSE - ///List of light sources affecting this turf. - var/tmp/list/datum/light_source/affecting_lights ///Our lighting object. var/tmp/atom/movable/lighting_object/lighting_object - var/tmp/list/datum/lighting_corner/corners + ///Lighting Corner datums. + var/tmp/datum/lighting_corner/lighting_corner_NE + var/tmp/datum/lighting_corner/lighting_corner_SE + var/tmp/datum/lighting_corner/lighting_corner_SW + var/tmp/datum/lighting_corner/lighting_corner_NW + ///Which directions does this turf block the vision of, taking into account both the turf's opacity and the movable opacity_sources. var/directional_opacity = NONE diff --git a/code/modules/lighting/lighting_corner.dm b/code/modules/lighting/lighting_corner.dm index 6111d3193a4..6d8e14c98db 100644 --- a/code/modules/lighting/lighting_corner.dm +++ b/code/modules/lighting/lighting_corner.dm @@ -2,17 +2,19 @@ // And corners get shared between multiple turfs (unless you're on the corners of the map, then 1 corner doesn't). // For the record: these should never ever ever be deleted, even if the turf doesn't have dynamic lighting. -// This list is what the code that assigns corners listens to, the order in this list is the order in which corners are added to the /turf/corners list. -GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, NORTHWEST)) + /datum/lighting_corner - var/list/turf/masters var/list/datum/light_source/affecting // Light sources affecting us. - var/active = FALSE // TRUE if one of our masters has dynamic lighting. var/x = 0 var/y = 0 + var/turf/master_NE + var/turf/master_SE + var/turf/master_SW + var/turf/master_NW + var/lum_r = 0 var/lum_g = 0 var/lum_b = 0 @@ -26,8 +28,7 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, /datum/lighting_corner/New(turf/new_turf, diagonal) . = ..() - masters = list() - masters[new_turf] = turn(diagonal, 180) + save_master(new_turf, turn(diagonal, 180)) var/vertical = diagonal & ~(diagonal - 1) // The horizontal directions (4 and 8) are bigger than the vertical ones (1 and 2), so we can reliably say the lsb is the horizontal direction. var/horizontal = diagonal & ~vertical // Now that we know the horizontal one we can get the vertical one. @@ -39,49 +40,48 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, // Issue being that the only way I could think of doing it was very messy, slow and honestly overengineered. // So we'll have this hardcode instead. var/turf/T - var/i // Diagonal one is easy. T = get_step(new_turf, diagonal) if (T) // In case we're on the map's border. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = diagonal - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(diagonal, 180)) - T.corners[i] = src + save_master(T, diagonal) // Now the horizontal one. T = get_step(new_turf, horizontal) if (T) // Ditto. - if (!T.corners) - T.corners = list(null, null, null, null) - - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src + save_master(T, ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. // And finally the vertical one. T = get_step(new_turf, vertical) if (T) - if (!T.corners) - T.corners = list(null, null, null, null) + save_master(T, ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH)) // Get the dir based on coordinates. - masters[T] = ((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH) // Get the dir based on coordinates. - i = GLOB.LIGHTING_CORNER_DIAGONAL.Find(turn(masters[T], 180)) - T.corners[i] = src +/datum/lighting_corner/proc/save_master(turf/master, dir) + switch (dir) + if (NORTHEAST) + master_NE = master + master.lighting_corner_SW = src + if (SOUTHEAST) + master_SE = master + master.lighting_corner_NW = src + if (SOUTHWEST) + master_SW = master + master.lighting_corner_NE = src + if (NORTHWEST) + master_NW = master + master.lighting_corner_SE = src - update_active() +/datum/lighting_corner/proc/self_destruct_if_idle() + if (!LAZYLEN(affecting)) + qdel(src, force = TRUE) -/datum/lighting_corner/proc/update_active() - active = FALSE - var/turf/T - var/thing - for (thing in masters) - T = thing - if (T.lighting_object) - active = TRUE - return +/datum/lighting_corner/proc/vis_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.vis_update() + +/datum/lighting_corner/proc/full_update() + for (var/datum/light_source/light_source as anything in affecting) + light_source.recalc_corner(src) // God that was a mess, now to do the rest of the corner code! Hooray! /datum/lighting_corner/proc/update_lumcount(delta_r, delta_g, delta_b) @@ -120,11 +120,27 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, #endif cache_mx = round(mx, LIGHTING_ROUND_VALUE) - for (var/TT in masters) - var/turf/T = TT - if (T.lighting_object && !T.lighting_object.needs_update) - T.lighting_object.needs_update = TRUE - SSlighting.objects_queue += T.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 + + lighting_object = master_SE?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_SW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + lighting_object = master_NW?.lighting_object + if (lighting_object && !lighting_object.needs_update) + lighting_object.needs_update = TRUE + SSlighting.objects_queue += lighting_object + + self_destruct_if_idle() /datum/lighting_corner/dummy/New() @@ -134,6 +150,24 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST, if (!force) return QDEL_HINT_LETMELIVE - stack_trace("Ok, Look, /tg/, I need you to find whatever fucker decided to call qdel on a fucking lighting corner, then tell him very nicely and politely that he is brain damaged and needs his head checked. Thanks. Send them my regards by the way.") + + for (var/datum/light_source/light_source as anything in affecting) + LAZYREMOVE(light_source.effect_str, src) + affecting = null + + if (master_NE) + master_NE.lighting_corner_SW = null + master_NE.lighting_corners_initialised = FALSE + if (master_SE) + master_SE.lighting_corner_NW = null + master_SE.lighting_corners_initialised = FALSE + if (master_SW) + master_SW.lighting_corner_NE = null + master_SW.lighting_corners_initialised = FALSE + if (master_NW) + master_NW.lighting_corner_SE = null + master_NW.lighting_corners_initialised = FALSE + if (needs_update) + SSlighting.corners_queue -= src return ..() diff --git a/code/modules/lighting/lighting_object.dm b/code/modules/lighting/lighting_object.dm index c33ef60854a..5fe78389a26 100644 --- a/code/modules/lighting/lighting_object.dm +++ b/code/modules/lighting/lighting_object.dm @@ -71,16 +71,10 @@ // See LIGHTING_CORNER_DIAGONAL in lighting_corner.dm for why these values are what they are. var/static/datum/lighting_corner/dummy/dummy_lighting_corner = new - var/list/corners = myturf.corners - var/datum/lighting_corner/cr = dummy_lighting_corner - var/datum/lighting_corner/cg = dummy_lighting_corner - var/datum/lighting_corner/cb = dummy_lighting_corner - var/datum/lighting_corner/ca = dummy_lighting_corner - if (corners) //done this way for speed - cr = corners[3] || dummy_lighting_corner - cg = corners[2] || dummy_lighting_corner - cb = corners[4] || dummy_lighting_corner - ca = corners[1] || dummy_lighting_corner + var/datum/lighting_corner/cr = myturf.lighting_corner_SW || dummy_lighting_corner + var/datum/lighting_corner/cg = myturf.lighting_corner_SE || dummy_lighting_corner + var/datum/lighting_corner/cb = myturf.lighting_corner_NW || dummy_lighting_corner + var/datum/lighting_corner/ca = myturf.lighting_corner_NE || dummy_lighting_corner var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx) diff --git a/code/modules/lighting/lighting_source.dm b/code/modules/lighting/lighting_source.dm index 12206a408e1..df056ae3bf6 100644 --- a/code/modules/lighting/lighting_source.dm +++ b/code/modules/lighting/lighting_source.dm @@ -22,7 +22,6 @@ var/tmp/applied_lum_b var/list/datum/lighting_corner/effect_str // List used to store how much we're affecting corners. - var/list/turf/affecting_turfs var/applied = FALSE // Whether we have applied our light yet or not. @@ -103,45 +102,34 @@ // The braces and semicolons are there to be able to do this on a single line. #define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range))) -#define APPLY_CORNER(C) \ - . = LUM_FALLOFF(C, pixel_turf); \ - . *= light_power; \ - var/OLD = effect_str[C]; \ - effect_str[C] = .; \ - \ - C.update_lumcount \ - ( \ - (. * lum_r) - (OLD * applied_lum_r), \ - (. * lum_g) - (OLD * applied_lum_g), \ - (. * lum_b) - (OLD * applied_lum_b) \ - ); +#define APPLY_CORNER(C) \ + . = LUM_FALLOFF(C, pixel_turf); \ + . *= light_power; \ + var/OLD = effect_str[C]; \ + \ + C.update_lumcount \ + ( \ + (. * lum_r) - (OLD * applied_lum_r), \ + (. * lum_g) - (OLD * applied_lum_g), \ + (. * lum_b) - (OLD * applied_lum_b) \ + ); \ -#define REMOVE_CORNER(C) \ - . = -effect_str[C]; \ - C.update_lumcount \ - ( \ - . * applied_lum_r, \ - . * applied_lum_g, \ - . * applied_lum_b \ +#define REMOVE_CORNER(C) \ + . = -effect_str[C]; \ + C.update_lumcount \ + ( \ + . * applied_lum_r, \ + . * applied_lum_g, \ + . * applied_lum_b \ ); // This is the define used to calculate falloff. /datum/light_source/proc/remove_lum() applied = FALSE - var/thing - for (thing in affecting_turfs) - var/turf/T = thing - LAZYREMOVE(T.affecting_lights, src) - - affecting_turfs = null - - var/datum/lighting_corner/C - for (thing in effect_str) - C = thing - REMOVE_CORNER(C) - - LAZYREMOVE(C.affecting, src) + for (var/datum/lighting_corner/corner as anything in effect_str) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) effect_str = null @@ -152,7 +140,7 @@ effect_str[C] = 0 APPLY_CORNER(C) - UNSETEMPTY(effect_str) + effect_str[C] = . /datum/light_source/proc/update_corners() @@ -218,77 +206,55 @@ var/list/datum/lighting_corner/corners = list() var/list/turf/turfs = list() - var/thing - var/datum/lighting_corner/C - var/turf/T if (source_turf) var/oldlum = source_turf.luminosity source_turf.luminosity = CEILING(light_range, 1) - for(T in view(CEILING(light_range, 1), source_turf)) - if((!IS_DYNAMIC_LIGHTING(T) && !T.light_sources)) - continue + for(var/turf/T in view(CEILING(light_range, 1), source_turf)) if(!IS_OPAQUE_TURF(T)) if (!T.lighting_corners_initialised) T.generate_missing_corners() - for (thing in T.corners) - C = thing - corners[C] = 0 + corners[T.lighting_corner_NE] = 0 + corners[T.lighting_corner_SE] = 0 + corners[T.lighting_corner_SW] = 0 + corners[T.lighting_corner_NW] = 0 turfs += T source_turf.luminosity = oldlum - LAZYINITLIST(affecting_turfs) - var/list/L = turfs - affecting_turfs // New turfs, add us to the affecting lights of them. - affecting_turfs += L - for (thing in L) - T = thing - LAZYADD(T.affecting_lights, src) - - L = affecting_turfs - turfs // Now-gone turfs, remove us from the affecting lights. - affecting_turfs -= L - for (thing in L) - T = thing - LAZYREMOVE(T.affecting_lights, src) - + var/list/datum/lighting_corner/new_corners = (corners - effect_str) LAZYINITLIST(effect_str) if (needs_update == LIGHTING_VIS_UPDATE) - for (thing in corners - effect_str) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . else - L = corners - effect_str - for (thing in L) // New corners - C = thing - LAZYADD(C.affecting, src) - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) + for (var/datum/lighting_corner/corner as anything in new_corners) + APPLY_CORNER(corner) + if (. != 0) + LAZYADD(corner.affecting, src) + effect_str[corner] = . - for (thing in corners - L) // Existing corners - C = thing - if (!C.active) - effect_str[C] = 0 - continue - APPLY_CORNER(C) + for (var/datum/lighting_corner/corner as anything in corners - new_corners) // Existing corners + APPLY_CORNER(corner) + if (. != 0) + effect_str[corner] = . + else + LAZYREMOVE(corner.affecting, src) + effect_str -= corner - L = effect_str - corners - for (thing in L) // Old, now gone, corners. - C = thing - REMOVE_CORNER(C) - LAZYREMOVE(C.affecting, src) - effect_str -= L + var/list/datum/lighting_corner/gone_corners = effect_str - corners + for (var/datum/lighting_corner/corner as anything in gone_corners) + REMOVE_CORNER(corner) + LAZYREMOVE(corner.affecting, src) + effect_str -= gone_corners applied_lum_r = lum_r applied_lum_g = lum_g applied_lum_b = lum_b UNSETEMPTY(effect_str) - UNSETEMPTY(affecting_turfs) #undef EFFECT_UPDATE #undef LUM_FALLOFF diff --git a/code/modules/lighting/lighting_turf.dm b/code/modules/lighting/lighting_turf.dm index efe49695eae..35c3bee62a6 100644 --- a/code/modules/lighting/lighting_turf.dm +++ b/code/modules/lighting/lighting_turf.dm @@ -1,23 +1,14 @@ // Causes any affecting light sources to be queued for a visibility update, for example a door got opened. /turf/proc/reconsider_lights() - var/datum/light_source/L - var/thing - for (thing in affecting_lights) - L = thing - L.vis_update() + lighting_corner_NE?.vis_update() + lighting_corner_SE?.vis_update() + lighting_corner_SW?.vis_update() + lighting_corner_NW?.vis_update() /turf/proc/lighting_clear_overlay() if (lighting_object) qdel(lighting_object, TRUE) - var/datum/lighting_corner/C - var/thing - for (thing in corners) - if(!thing) - continue - C = thing - C.update_active() - // Builds a lighting object for us, but only if our area is dynamic. /turf/proc/lighting_build_overlay() if (lighting_object) @@ -27,37 +18,28 @@ if (!IS_DYNAMIC_LIGHTING(A) && !light_sources) return - if (!lighting_corners_initialised) - generate_missing_corners() - new/atom/movable/lighting_object(src) - var/thing - var/datum/lighting_corner/C - var/datum/light_source/S - for (thing in corners) - if(!thing) - continue - C = thing - if (!C.active) // We would activate the corner, calculate the lighting for it. - for (thing in C.affecting) - S = thing - S.recalc_corner(C) - C.active = TRUE - // Used to get a scaled lumcount. /turf/proc/get_lumcount(minlum = 0, maxlum = 1) if (!lighting_object) return 1 var/totallums = 0 - var/thing var/datum/lighting_corner/L - for (thing in corners) - if(!thing) - continue - L = thing + L = lighting_corner_NE + if (L) totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SE + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_SW + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + L = lighting_corner_NW + if (L) + totallums += L.lum_r + L.lum_b + L.lum_g + totallums /= 12 // 4 corners, each with 3 channels, get the average. @@ -123,14 +105,16 @@ lighting_clear_overlay() /turf/proc/generate_missing_corners() - if (!IS_DYNAMIC_LIGHTING(src) && !light_sources) - return + if (!lighting_corner_NE) + lighting_corner_NE = new/datum/lighting_corner(src, NORTH|EAST) + + if (!lighting_corner_SE) + lighting_corner_SE = new/datum/lighting_corner(src, SOUTH|EAST) + + if (!lighting_corner_SW) + lighting_corner_SW = new/datum/lighting_corner(src, SOUTH|WEST) + + if (!lighting_corner_NW) + lighting_corner_NW = new/datum/lighting_corner(src, NORTH|WEST) + lighting_corners_initialised = TRUE - if (!corners) - corners = list(null, null, null, null) - - for (var/i = 1 to 4) - if (corners[i]) // Already have a corner on this direction. - continue - - corners[i] = new/datum/lighting_corner(src, GLOB.LIGHTING_CORNER_DIAGONAL[i])