diff --git a/code/__defines/subsystems.dm b/code/__defines/subsystems.dm index 8c546c9135..85eeeae876 100644 --- a/code/__defines/subsystems.dm +++ b/code/__defines/subsystems.dm @@ -11,3 +11,5 @@ var/global/list/runlevel_flags = list(RUNLEVEL_LOBBY, RUNLEVEL_SETUP, RUNLEVEL_GAME, RUNLEVEL_POSTGAME) #define RUNLEVEL_FLAG_TO_INDEX(flag) (log(2, flag) + 1) // Convert from the runlevel bitfield constants to index in runlevel_flags list + +#define INIT_ORDER_LIGHTING 0 \ No newline at end of file diff --git a/code/controllers/Processes/lighting.dm b/code/controllers/Processes/lighting.dm deleted file mode 100644 index d46cab1d19..0000000000 --- a/code/controllers/Processes/lighting.dm +++ /dev/null @@ -1,98 +0,0 @@ -/var/lighting_overlays_initialised = FALSE - -/var/list/lighting_update_lights = list() // List of lighting sources queued for update. -/var/list/lighting_update_corners = list() // List of lighting corners queued for update. -/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. - -/var/list/lighting_update_lights_old = list() // List of lighting sources currently being updated. -/var/list/lighting_update_corners_old = list() // List of lighting corners currently being updated. -/var/list/lighting_update_overlays_old = list() // List of lighting overlays currently being updated. - - -/datum/controller/process/lighting - // Queues of update counts, waiting to be rolled into stats lists - var/list/stats_queues = list( - "Source" = list(), "Corner" = list(), "Overlay" = list()) - // Stats lists - var/list/stats_lists = list( - "Source" = list(), "Corner" = list(), "Overlay" = list()) - var/update_stats_every = (1 SECONDS) - var/next_stats_update = 0 - var/stat_updates_to_keep = 5 - -/datum/controller/process/lighting/setup() - name = "lighting" - - schedule_interval = 0 // run as fast as you possibly can - sleep_interval = 10 // Yield every 10% of a tick - defer_usage = 80 // Defer at 80% of a tick - create_all_lighting_overlays() - lighting_overlays_initialised = TRUE - - // Pre-process lighting once before the round starts. Wait 30 seconds so the away mission has time to load. - spawn(300) - doWork(1) - -/datum/controller/process/lighting/doWork(roundstart) - - lighting_update_lights_old = lighting_update_lights //We use a different list so any additions to the update lists during a delay from scheck() don't cause things to be cut from the list without being updated. - lighting_update_lights = list() - for(var/datum/light_source/L in lighting_update_lights_old) - - if(L.check() || L.destroyed || L.force_update) - L.remove_lum() - if(!L.destroyed) - L.apply_lum() - - else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. - L.smart_vis_update() - - L.vis_update = FALSE - L.force_update = FALSE - L.needs_update = FALSE - - SCHECK - - lighting_update_corners_old = lighting_update_corners //Same as above. - lighting_update_corners = list() - for(var/A in lighting_update_corners_old) - var/datum/lighting_corner/C = A - - C.update_overlays() - - C.needs_update = FALSE - - SCHECK - - lighting_update_overlays_old = lighting_update_overlays //Same as above. - lighting_update_overlays = list() - - for(var/A in lighting_update_overlays_old) - var/atom/movable/lighting_overlay/O = A - O.update_overlay() - O.needs_update = 0 - SCHECK - - stats_queues["Source"] += lighting_update_lights_old.len - stats_queues["Corner"] += lighting_update_corners_old.len - stats_queues["Overlay"] += lighting_update_overlays_old.len - - if(next_stats_update <= world.time) - next_stats_update = world.time + update_stats_every - for(var/stat_name in stats_queues) - var/stat_sum = 0 - var/list/stats_queue = stats_queues[stat_name] - for(var/count in stats_queue) - stat_sum += count - stats_queue.Cut() - - var/list/stats_list = stats_lists[stat_name] - stats_list.Insert(1, stat_sum) - if(stats_list.len > stat_updates_to_keep) - stats_list.Cut(stats_list.len) - -/datum/controller/process/lighting/statProcess() - ..() - stat(null, "[total_lighting_sources] sources, [total_lighting_corners] corners, [total_lighting_overlays] overlays") - for(var/stat_type in stats_lists) - stat(null, "[stat_type] updates: [jointext(stats_lists[stat_type], " | ")]") diff --git a/code/controllers/subsystems/lighting.dm b/code/controllers/subsystems/lighting.dm new file mode 100644 index 0000000000..01875cc397 --- /dev/null +++ b/code/controllers/subsystems/lighting.dm @@ -0,0 +1,166 @@ +/* +** Lighting Subsystem - Process the lighting! Do it! +*/ + +#define SSLIGHTING_STAGE_LIGHTS 1 +#define SSLIGHTING_STAGE_CORNERS 2 +#define SSLIGHTING_STAGE_OVERLAYS 3 +#define SSLIGHTING_STAGE_DONE 4 +// This subsystem's fire() method also gets called once during Master.Initialize(). +// During this fire we need to use CHECK_TICK to sleep and continue, but in all other fires we need to use MC_CHECK_TICK to pause and return. +// This leads us to a rather annoying little tidbit of code that I have stuffed into this macro so I don't have to see it. +#define DUAL_TICK_CHECK if (init_tick_checks) { CHECK_TICK; } else if (MC_TICK_CHECK) { return; } + +// Globals +/var/lighting_overlays_initialised = FALSE +/var/list/lighting_update_lights = list() // List of lighting sources queued for update. +/var/list/lighting_update_corners = list() // List of lighting corners queued for update. +/var/list/lighting_update_overlays = list() // List of lighting overlays queued for update. + +SUBSYSTEM_DEF(lighting) + name = "Lighting" + wait = 2 // Ticks, not deciseconds + init_order = INIT_ORDER_LIGHTING + flags = SS_TICKER + + var/list/currentrun = list() + var/stage = null + + var/cost_lights = 0 + var/cost_corners = 0 + var/cost_overlays = 0 + +/datum/controller/subsystem/lighting/Initialize(timeofday) + if(!lighting_overlays_initialised) + // TODO - TG initializes starlight here. + create_all_lighting_overlays() + lighting_overlays_initialised = TRUE + + // Pre-process lighting once before the round starts. + internal_process_lights(FALSE, TRUE) + internal_process_corners(FALSE, TRUE) + internal_process_overlays(FALSE, TRUE) + return ..() + +/datum/controller/subsystem/lighting/fire(resumed = FALSE) + var/timer + if(!resumed) + ASSERT(LAZYLEN(currentrun) == 0) // Santity checks to make sure we don't somehow have items left over from last cycle + ASSERT(stage == null) // Or somehow didn't finish all the steps from last cycle + stage = SSLIGHTING_STAGE_LIGHTS // Start with Step 1 of course + + if(stage == SSLIGHTING_STAGE_LIGHTS) + timer = world.tick_usage + internal_process_lights(resumed) + cost_lights = MC_AVERAGE(cost_lights, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_CORNERS + + if(stage == SSLIGHTING_STAGE_CORNERS) + timer = world.tick_usage + internal_process_corners(resumed) + cost_corners = MC_AVERAGE(cost_corners, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_OVERLAYS + + if(stage == SSLIGHTING_STAGE_OVERLAYS) + timer = world.tick_usage + internal_process_overlays(resumed) + cost_overlays = MC_AVERAGE(cost_overlays, TICK_DELTA_TO_MS(world.tick_usage - timer)) + if(state != SS_RUNNING) + return + resumed = 0 + stage = SSLIGHTING_STAGE_DONE + + // Okay, we're done! Woo! Got thru a whole air_master cycle! + ASSERT(LAZYLEN(currentrun) == 0) // Sanity checks to make sure there are really none left + ASSERT(stage == SSLIGHTING_STAGE_DONE) // And that we didn't somehow skip past the last step + currentrun = null + stage = null + +/datum/controller/subsystem/lighting/proc/internal_process_lights(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_lights + global.lighting_update_lights = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/datum/light_source/L = currentrun[currentrun.len] + currentrun.len-- + + if(!L) continue + if(L.check() || L.destroyed || L.force_update) + L.remove_lum() + if(!L.destroyed) + L.apply_lum() + + else if(L.vis_update) //We smartly update only tiles that became (in) visible to use. + L.smart_vis_update() + + L.vis_update = FALSE + L.force_update = FALSE + L.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/proc/internal_process_corners(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_corners + global.lighting_update_corners = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/datum/lighting_corner/C = currentrun[currentrun.len] + currentrun.len-- + + if(!C) continue + C.update_overlays() + C.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/proc/internal_process_overlays(resumed = FALSE, init_tick_checks = FALSE) + if (!resumed) + // We swap out the lists so any additions to the global list during a pause don't make things wierd. + src.currentrun = global.lighting_update_overlays + global.lighting_update_overlays = list() + + //cache for sanic speed (lists are references anyways) + var/list/currentrun = src.currentrun + while(currentrun.len) + var/atom/movable/lighting_overlay/O = currentrun[currentrun.len] + currentrun.len-- + + if(!O) continue + O.update_overlay() + O.needs_update = FALSE + + DUAL_TICK_CHECK + +/datum/controller/subsystem/lighting/stat_entry(msg_prefix) + var/list/msg = list(msg_prefix) + msg += "T:{" + msg += "S [total_lighting_sources] | " + msg += "C [total_lighting_corners] | " + msg += "O [total_lighting_overlays]" + msg += "}" + msg += "C:{" + msg += "S [round(cost_lights, 1)] | " + msg += "C [round(cost_corners, 1)] | " + msg += "O [round(cost_overlays, 1)]" + msg += "}" + ..(msg.Join()) + +#undef DUAL_TICK_CHECK +#undef SSLIGHTING_STAGE_LIGHTS +#undef SSLIGHTING_STAGE_CORNERS +#undef SSLIGHTING_STAGE_OVERLAYS +#undef SSLIGHTING_STAGE_STATS \ No newline at end of file diff --git a/code/modules/lighting/lighting_overlay.dm b/code/modules/lighting/lighting_overlay.dm index 690eba9326..e02f976281 100644 --- a/code/modules/lighting/lighting_overlay.dm +++ b/code/modules/lighting/lighting_overlay.dm @@ -125,7 +125,7 @@ if (force) total_lighting_overlays-- global.lighting_update_overlays -= src - global.lighting_update_overlays_old -= src + LAZYREMOVE(SSlighting.currentrun, src) var/turf/T = loc if(istype(T)) diff --git a/code/modules/lighting/lighting_setup.dm b/code/modules/lighting/lighting_setup.dm index 981de65864..b3e3cf7aa2 100644 --- a/code/modules/lighting/lighting_setup.dm +++ b/code/modules/lighting/lighting_setup.dm @@ -1,6 +1,14 @@ +// Create lighting overlays on all turfs with dynamic lighting in areas with dynamic lighting. /proc/create_all_lighting_overlays() - for(var/zlevel = 1 to world.maxz) - create_lighting_overlays_zlevel(zlevel) + for(var/area/A in world) + if(!A.dynamic_lighting) + continue + for(var/turf/T in A) + if(!T.dynamic_lighting) + continue + new /atom/movable/lighting_overlay(T, TRUE) + CHECK_TICK + CHECK_TICK /proc/create_lighting_overlays_zlevel(var/zlevel) ASSERT(zlevel) diff --git a/maps/southern_cross/southern_cross_defines.dm b/maps/southern_cross/southern_cross_defines.dm index 5650ad5554..40f3d4ef40 100644 --- a/maps/southern_cross/southern_cross_defines.dm +++ b/maps/southern_cross/southern_cross_defines.dm @@ -149,4 +149,11 @@ ..() teleport_x = src.x teleport_y = 2 - teleport_z = Z_LEVEL_SURFACE \ No newline at end of file + teleport_z = Z_LEVEL_SURFACE + +/datum/planet/sif + expected_z_levels = list( + Z_LEVEL_SURFACE, + Z_LEVEL_SURFACE_MINE, + Z_LEVEL_SURFACE_WILD + ) \ No newline at end of file diff --git a/polaris.dme b/polaris.dme index 44977f328a..fe832181f5 100644 --- a/polaris.dme +++ b/polaris.dme @@ -155,7 +155,6 @@ #include "code\controllers\Processes\event.dm" #include "code\controllers\Processes\game_master.dm" #include "code\controllers\Processes\inactivity.dm" -#include "code\controllers\Processes\lighting.dm" #include "code\controllers\Processes\machinery.dm" #include "code\controllers\Processes\mob.dm" #include "code\controllers\Processes\nanoui.dm" @@ -173,6 +172,7 @@ #include "code\controllers\ProcessScheduler\core\processScheduler.dm" #include "code\controllers\subsystems\creation.dm" #include "code\controllers\subsystems\garbage.dm" +#include "code\controllers\subsystems\lighting.dm" #include "code\datums\ai_law_sets.dm" #include "code\datums\ai_laws.dm" #include "code\datums\browser.dm" @@ -2262,7 +2262,6 @@ #include "interface\interface.dm" #include "interface\skin.dmf" #include "maps\northern_star\northern_star.dm" -#include "maps\northern_star\northern_star_defines.dm" #include "maps\submaps\_readme.dm" #include "maps\submaps\cave_submaps\cave.dm" #include "maps\submaps\space_submaps\space.dm"