mirror of
https://github.com/CHOMPStation2/CHOMPStation2.git
synced 2025-12-11 02:34:00 +00:00
Fixes the Sun/Weather and Ports Vore's Lighting SS
New lighting system is needed to handle updating literally 14k+ tiles whenever the sun moves. The straight port seems to have had no adverse effects from what I could see. Don't know if it's more performant but it doesn't seem to be less. I didn't expect the latter would be needed for the former.
This commit is contained in:
@@ -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
|
||||
@@ -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], " | ")]")
|
||||
166
code/controllers/subsystems/lighting.dm
Normal file
166
code/controllers/subsystems/lighting.dm
Normal file
@@ -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
|
||||
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -150,3 +150,10 @@
|
||||
teleport_x = src.x
|
||||
teleport_y = 2
|
||||
teleport_z = Z_LEVEL_SURFACE
|
||||
|
||||
/datum/planet/sif
|
||||
expected_z_levels = list(
|
||||
Z_LEVEL_SURFACE,
|
||||
Z_LEVEL_SURFACE_MINE,
|
||||
Z_LEVEL_SURFACE_WILD
|
||||
)
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user