Files
CHOMPStation2/code/controllers/subsystems/lighting.dm
Leshana c6e8184b58 Ports https://github.com/tgstation/tgstation/pull/30184
* Adds defines for world.tick_usage
* This provides no useful benefit whatsoever, but /tg and Baystation12 have done it, so it will make porting future code easier if we do too.  No real harm done either.
2017-12-27 19:10:15 -05:00

166 lines
5.5 KiB
Plaintext

/*
** 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 = TICK_USAGE
internal_process_lights(resumed)
cost_lights = MC_AVERAGE(cost_lights, TICK_DELTA_TO_MS(TICK_USAGE - timer))
if(state != SS_RUNNING)
return
resumed = 0
stage = SSLIGHTING_STAGE_CORNERS
if(stage == SSLIGHTING_STAGE_CORNERS)
timer = TICK_USAGE
internal_process_corners(resumed)
cost_corners = MC_AVERAGE(cost_corners, TICK_DELTA_TO_MS(TICK_USAGE - timer))
if(state != SS_RUNNING)
return
resumed = 0
stage = SSLIGHTING_STAGE_OVERLAYS
if(stage == SSLIGHTING_STAGE_OVERLAYS)
timer = TICK_USAGE
internal_process_overlays(resumed)
cost_overlays = MC_AVERAGE(cost_overlays, TICK_DELTA_TO_MS(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