mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-27 15:01:04 +01:00
Adaptive lighting updates (#1679)
This PR simplifies the lighting update system (removes update_type) and instead makes the lighting system decide which update method to use based on server load. Instant updates are used during low-load, scheduled during high. Also removes: update_lights_now() (redundant), diff_light() (unused).
This commit is contained in:
+3
-3
@@ -137,13 +137,13 @@ turf/proc/hotspot_expose(exposed_temperature, exposed_volume, soh = 0)
|
||||
|
||||
if(firelevel > 6)
|
||||
icon_state = "3"
|
||||
set_light(7, FIRE_LIGHT_3, update_type = UPDATE_NONE) // We set color later in the proc, that should trigger an update.
|
||||
set_light(7, FIRE_LIGHT_3, no_update = TRUE) // We set color later in the proc, that should trigger an update.
|
||||
else if(firelevel > 2.5)
|
||||
icon_state = "2"
|
||||
set_light(5, FIRE_LIGHT_2, update_type = UPDATE_NONE)
|
||||
set_light(5, FIRE_LIGHT_2, no_update = TRUE)
|
||||
else
|
||||
icon_state = "1"
|
||||
set_light(3, FIRE_LIGHT_1, update_type = UPDATE_NONE)
|
||||
set_light(3, FIRE_LIGHT_1, no_update = TRUE)
|
||||
|
||||
for(var/mob/living/L in loc)
|
||||
L.FireBurn(firelevel, air_contents.temperature, air_contents.return_pressure()) //Burn the mobs!
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
/datum/controller/process/lighting/statProcess()
|
||||
..()
|
||||
stat(null, "Current server tick usage is [world.tick_usage], threshold is [TICK_LIMIT].")
|
||||
stat(null, "[all_lighting_overlays.len] overlays ([all_lighting_corners.len] corners)")
|
||||
stat(null, "Lights: [lighting_update_lights.len] queued, [curr_lights.len] processing")
|
||||
stat(null, "Corners: [lighting_update_corners.len] queued, [curr_corners.len] processing")
|
||||
@@ -43,7 +44,7 @@
|
||||
var/datum/light_source/L = curr_lights[curr_lights.len]
|
||||
curr_lights.len--
|
||||
|
||||
if(L.check() || L.destroyed || L.force_update)
|
||||
if(L.destroyed || L.check() || L.force_update)
|
||||
L.remove_lum()
|
||||
if(!L.destroyed)
|
||||
L.apply_lum()
|
||||
|
||||
@@ -565,12 +565,12 @@ About the new airlock wires panel:
|
||||
if(locked && lights && src.arePowerSystemsOn())
|
||||
icon_state = "door_locked"
|
||||
if (!has_set_boltlight)
|
||||
set_light(2, 0.75, COLOR_RED_LIGHT, update_type = UPDATE_NONE)
|
||||
set_light(2, 0.75, COLOR_RED_LIGHT, no_update = TRUE)
|
||||
has_set_boltlight = TRUE
|
||||
else
|
||||
icon_state = "door_closed"
|
||||
if (has_set_boltlight)
|
||||
set_light(0, update_type = UPDATE_NONE)
|
||||
set_light(0, no_update = TRUE)
|
||||
has_set_boltlight = FALSE
|
||||
if(p_open || welded)
|
||||
overlays = list()
|
||||
@@ -597,13 +597,13 @@ About the new airlock wires panel:
|
||||
if((stat & BROKEN) && !(stat & NOPOWER))
|
||||
overlays += image(icon, "sparks_open")
|
||||
if (has_set_boltlight)
|
||||
set_light(0, update_type = UPDATE_NONE)
|
||||
set_light(0, no_update = TRUE)
|
||||
has_set_boltlight = FALSE
|
||||
|
||||
if (src)
|
||||
var/turf/T = get_turf(src)
|
||||
if (T)
|
||||
T.update_lights_now()
|
||||
T.reconsider_lights()
|
||||
return
|
||||
|
||||
/obj/machinery/door/airlock/do_animate(animation)
|
||||
|
||||
@@ -540,7 +540,7 @@
|
||||
update_heat_protection(turf)
|
||||
air_master.mark_for_update(turf)
|
||||
|
||||
T.update_lights_now()
|
||||
T.reconsider_lights()
|
||||
|
||||
return 1
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@
|
||||
/obj/item/device/flashlight/update_icon()
|
||||
if(on)
|
||||
icon_state = "[initial(icon_state)]-on"
|
||||
set_light(brightness_on, update_type = UPDATE_NOW)
|
||||
set_light(brightness_on)
|
||||
else
|
||||
icon_state = "[initial(icon_state)]"
|
||||
set_light(0, update_type = UPDATE_NOW)
|
||||
set_light(0)
|
||||
|
||||
/obj/item/device/flashlight/attack_self(mob/user)
|
||||
if(!isturf(user.loc))
|
||||
@@ -231,7 +231,7 @@
|
||||
|
||||
/obj/item/device/flashlight/slime/New()
|
||||
..()
|
||||
set_light(brightness_on, update_type = UPDATE_NOW)
|
||||
set_light(brightness_on)
|
||||
|
||||
/obj/item/device/flashlight/slime/update_icon()
|
||||
return
|
||||
|
||||
@@ -12,24 +12,8 @@
|
||||
// Nonesensical value for l_color default, so we can detect if it gets set to null.
|
||||
#define NONSENSICAL_VALUE -99999
|
||||
|
||||
#define SET_LIGHT set_light(l_range,l_power,l_color,uv,update_type);return;
|
||||
// Same as set_light(), but only does something if there's actually a change in state.
|
||||
/atom/proc/diff_light(/var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE, var/uv = NONSENSICAL_VALUE, var/update_type = UPDATE_SCHEDULE)
|
||||
if (l_range != light_range)
|
||||
SET_LIGHT
|
||||
if (l_power && l_power != light_power)
|
||||
SET_LIGHT
|
||||
if (l_color != NONSENSICAL_VALUE && l_color != light_color)
|
||||
SET_LIGHT
|
||||
if (uv != NONSENSICAL_VALUE)
|
||||
SET_LIGHT
|
||||
if (update_type != UPDATE_SCHEDULE)
|
||||
SET_LIGHT
|
||||
|
||||
#undef SET_LIGHT
|
||||
|
||||
// The proc you should always use to set the light of this atom.
|
||||
/atom/proc/set_light(var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE, var/uv = NONSENSICAL_VALUE, var/update_type = UPDATE_SCHEDULE)
|
||||
/atom/proc/set_light(var/l_range, var/l_power, var/l_color = NONSENSICAL_VALUE, var/uv = NONSENSICAL_VALUE, var/no_update = FALSE)
|
||||
lprof_write(src, "atom_setlight")
|
||||
|
||||
if(l_range > 0 && l_range < MINIMUM_USEFUL_LIGHT_RANGE)
|
||||
@@ -44,28 +28,29 @@
|
||||
light_color = l_color
|
||||
|
||||
if (uv != NONSENSICAL_VALUE)
|
||||
set_uv(uv, update_type = UPDATE_NONE)
|
||||
set_uv(uv, no_update = TRUE)
|
||||
|
||||
switch (update_type)
|
||||
if (UPDATE_SCHEDULE)
|
||||
update_light()
|
||||
if (UPDATE_NOW)
|
||||
update_light(TRUE)
|
||||
if (no_update)
|
||||
return
|
||||
|
||||
update_light()
|
||||
|
||||
#undef NONSENSICAL_VALUE
|
||||
|
||||
/atom/proc/set_uv(var/intensity, var/update_type = UPDATE_SCHEDULE)
|
||||
/atom/proc/set_uv(var/intensity, var/no_update)
|
||||
if (intensity < 0 || intensity > 255)
|
||||
intensity = min(max(intensity, 255), 0)
|
||||
|
||||
uv_intensity = intensity
|
||||
|
||||
if (update_type != UPDATE_NONE)
|
||||
update_light(update_type)
|
||||
if (no_update)
|
||||
return
|
||||
|
||||
update_light()
|
||||
|
||||
// Will update the light (duh).
|
||||
// Creates or destroys it if needed, makes it update values, makes sure it's got the correct source turf...
|
||||
/atom/proc/update_light(var/update_type = UPDATE_SCHEDULE)
|
||||
/atom/proc/update_light()
|
||||
set waitfor = FALSE
|
||||
if (gcDestroyed)
|
||||
return
|
||||
@@ -83,7 +68,7 @@
|
||||
. = loc
|
||||
|
||||
if (light) // Update the light or create it if it does not exist.
|
||||
light.update(., update_type)
|
||||
light.update(.)
|
||||
else
|
||||
light = new/datum/light_source(src, .)
|
||||
|
||||
@@ -143,11 +128,11 @@
|
||||
|
||||
if (Obj && OldLoc != src)
|
||||
for (var/datum/light_source/L in Obj.light_sources) // Cycle through the light sources on this atom and tell them to update.
|
||||
L.source_atom.update_light(update_type = UPDATE_NOW)
|
||||
L.source_atom.update_light()
|
||||
|
||||
/atom/Exited(var/atom/movable/Obj, var/atom/newloc)
|
||||
. = ..()
|
||||
|
||||
if (!newloc && Obj && newloc != src) // Incase the atom is being moved to nullspace, we handle queuing for a lighting update here.
|
||||
for (var/datum/light_source/L in Obj.light_sources) // Cycle through the light sources on this atom and tell them to update.
|
||||
L.source_atom.update_light(update_type = UPDATE_NOW)
|
||||
L.source_atom.update_light()
|
||||
|
||||
@@ -90,20 +90,23 @@
|
||||
active = TRUE
|
||||
|
||||
// God that was a mess, now to do the rest of the corner code! Hooray!
|
||||
/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b, var/delta_u, var/update_type = UPDATE_SCHEDULE)
|
||||
/datum/lighting_corner/proc/update_lumcount(var/delta_r, var/delta_g, var/delta_b, var/delta_u, var/now = FALSE)
|
||||
lum_r += delta_r
|
||||
lum_g += delta_g
|
||||
lum_b += delta_b
|
||||
lum_u += delta_u
|
||||
|
||||
if (update_type == UPDATE_SCHEDULE && !needs_update)
|
||||
needs_update = TRUE
|
||||
update_overlays(update_type)
|
||||
lighting_update_corners += src
|
||||
else if (!needs_update)
|
||||
update_overlays(UPDATE_NOW)
|
||||
if (needs_update)
|
||||
return
|
||||
|
||||
/datum/lighting_corner/proc/update_overlays(var/update_type = UPDATE_SCHEDULE)
|
||||
if (!now)
|
||||
needs_update = TRUE
|
||||
update_overlays(FALSE)
|
||||
lighting_update_corners += src
|
||||
else
|
||||
update_overlays(TRUE)
|
||||
|
||||
/datum/lighting_corner/proc/update_overlays(var/now = FALSE)
|
||||
|
||||
// Cache these values a head of time so 4 individual lighting overlays don't all calculate them individually.
|
||||
var/mx = max(lum_r, lum_g, lum_b) // Scale it so 1 is the strongest lum, if it is above 1.
|
||||
@@ -123,9 +126,8 @@
|
||||
for (var/TT in masters)
|
||||
var/turf/T = TT
|
||||
if (T.lighting_overlay)
|
||||
if (update_type == UPDATE_NOW) // UPDATE_NONE is meaningless here.
|
||||
if (now)
|
||||
T.lighting_overlay.update_overlay()
|
||||
|
||||
else if (!T.lighting_overlay.needs_update)
|
||||
T.lighting_overlay.needs_update = TRUE
|
||||
lighting_update_overlays += T.lighting_overlay
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
var/destroyed // Whether we are destroyed and need to stop emitting light.
|
||||
var/force_update
|
||||
|
||||
/datum/light_source/New(var/atom/owner, var/atom/top, var/update_t = UPDATE_SCHEDULE)
|
||||
/datum/light_source/New(var/atom/owner, var/atom/top)
|
||||
source_atom = owner // Set our new owner.
|
||||
if (!source_atom.light_sources)
|
||||
source_atom.light_sources = list()
|
||||
@@ -57,7 +57,7 @@
|
||||
effect_str = list()
|
||||
affecting_turfs = list()
|
||||
|
||||
update(update_type = update_t)
|
||||
update()
|
||||
|
||||
lprof_write(src, "source_new")
|
||||
|
||||
@@ -73,32 +73,40 @@
|
||||
if (top_atom && top_atom.light_sources)
|
||||
top_atom.light_sources -= src
|
||||
|
||||
/datum/light_source/proc/effect_update_now()
|
||||
lprof_write(src, "source_updatenow")
|
||||
if (check() || destroyed || force_update)
|
||||
remove_lum(TRUE)
|
||||
if (!destroyed)
|
||||
apply_lum(update_type = UPDATE_NOW)
|
||||
// Process the light RIGHT NOW.
|
||||
#define DO_UPDATE \
|
||||
if (destroyed || check() || force_update) { \
|
||||
remove_lum(TRUE); \
|
||||
if (!destroyed) { \
|
||||
apply_lum(TRUE); \
|
||||
} \
|
||||
} \
|
||||
else if (vis_update) { \
|
||||
smart_vis_update(TRUE); \
|
||||
} \
|
||||
vis_update = FALSE; \
|
||||
force_update = FALSE; \
|
||||
needs_update = FALSE;
|
||||
|
||||
else if (vis_update) // We smartly update only tiles that became (in) visible to use.
|
||||
smart_vis_update(update_type = UPDATE_NOW)
|
||||
|
||||
vis_update = FALSE
|
||||
force_update = FALSE
|
||||
needs_update = FALSE
|
||||
|
||||
// Call it dirty, I don't care.
|
||||
// This is here so there's no performance loss on non-instant updates from the fact that the engine can also do instant updates.
|
||||
// If you're wondering what's with the "BYOND" argument: BYOND won't let me have a () macro that has no arguments :|.
|
||||
#define effect_update(BYOND) \
|
||||
// Queue an update.
|
||||
#define QUEUE_UPDATE \
|
||||
if (!needs_update) \
|
||||
{ \
|
||||
lighting_update_lights += src; \
|
||||
needs_update = TRUE; \
|
||||
}
|
||||
|
||||
// Picks either scheduled or instant updates based on current server load.
|
||||
#define INTELLIGENT_UPDATE \
|
||||
if (world.tick_usage > TICK_LIMIT || !ticker) { \
|
||||
QUEUE_UPDATE; \
|
||||
} \
|
||||
else { \
|
||||
DO_UPDATE; \
|
||||
}
|
||||
|
||||
// This proc will cause the light source to update the top atom, and add itself to the update queue.
|
||||
/datum/light_source/proc/update(var/atom/new_top_atom, var/update_type = UPDATE_SCHEDULE)
|
||||
/datum/light_source/proc/update(var/atom/new_top_atom)
|
||||
// This top atom is different.
|
||||
if (new_top_atom && new_top_atom != top_atom)
|
||||
if(top_atom != source_atom) // Remove ourselves from the light sources of that top atom.
|
||||
@@ -114,23 +122,20 @@
|
||||
|
||||
lprof_write(src, "source_update")
|
||||
|
||||
if (update_type == UPDATE_NOW)
|
||||
effect_update_now()
|
||||
else if (update_type == UPDATE_SCHEDULE) // I don't know why you would call this with UPDATE_NONE, but hey.
|
||||
effect_update(null)
|
||||
INTELLIGENT_UPDATE
|
||||
|
||||
// Will force an update without checking if it's actually needed.
|
||||
/datum/light_source/proc/force_update()
|
||||
lprof_write(src, "source_forceupdate")
|
||||
force_update = 1
|
||||
|
||||
effect_update(null)
|
||||
INTELLIGENT_UPDATE
|
||||
|
||||
// Will cause the light source to recalculate turfs that were removed or added to visibility only.
|
||||
/datum/light_source/proc/vis_update()
|
||||
vis_update = 1
|
||||
|
||||
effect_update(null)
|
||||
INTELLIGENT_UPDATE
|
||||
|
||||
// Will check if we actually need to update, and update any variables that may need to be updated.
|
||||
/datum/light_source/proc/check()
|
||||
@@ -188,7 +193,7 @@
|
||||
// As such this all gets counted as a single line.
|
||||
// The braces and semicolons are there to be able to do this on a single line.
|
||||
|
||||
#define APPLY_CORNER(C) \
|
||||
#define APPLY_CORNER(C,now) \
|
||||
. = LUM_FALLOFF(C, source_turf); \
|
||||
\
|
||||
. *= light_power; \
|
||||
@@ -201,11 +206,11 @@
|
||||
. * applied_lum_g, \
|
||||
. * applied_lum_b, \
|
||||
. * applied_lum_u, \
|
||||
update_type \
|
||||
now \
|
||||
);
|
||||
|
||||
// I don't need to explain what this does, do I?
|
||||
#define REMOVE_CORNER(C) \
|
||||
#define REMOVE_CORNER(C,now) \
|
||||
. = -effect_str[C]; \
|
||||
C.update_lumcount \
|
||||
( \
|
||||
@@ -213,13 +218,13 @@
|
||||
. * applied_lum_g, \
|
||||
. * applied_lum_b, \
|
||||
. * applied_lum_u, \
|
||||
update_type \
|
||||
now \
|
||||
);
|
||||
|
||||
// This is the define used to calculate falloff.
|
||||
#define LUM_FALLOFF(C, T) (1 - CLAMP01(sqrt((C.x - T.x) ** 2 + (C.y - T.y) ** 2 + LIGHTING_HEIGHT) / max(1, light_range)))
|
||||
|
||||
/datum/light_source/proc/apply_lum(var/update_type = UPDATE_SCHEDULE)
|
||||
/datum/light_source/proc/apply_lum(var/now = FALSE)
|
||||
var/static/update_gen = 1
|
||||
applied = 1
|
||||
|
||||
@@ -244,7 +249,7 @@
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
|
||||
APPLY_CORNER(C)
|
||||
APPLY_CORNER(C, now)
|
||||
|
||||
if (!T.affecting_lights)
|
||||
T.affecting_lights = list()
|
||||
@@ -254,7 +259,7 @@
|
||||
|
||||
update_gen++
|
||||
|
||||
/datum/light_source/proc/remove_lum(var/update_type = UPDATE_SCHEDULE)
|
||||
/datum/light_source/proc/remove_lum(var/now = FALSE)
|
||||
applied = FALSE
|
||||
|
||||
for (var/turf/T in affecting_turfs)
|
||||
@@ -266,20 +271,19 @@
|
||||
affecting_turfs.Cut()
|
||||
|
||||
for (var/datum/lighting_corner/C in effect_str)
|
||||
REMOVE_CORNER(C)
|
||||
REMOVE_CORNER(C,now)
|
||||
|
||||
C.affecting -= src
|
||||
|
||||
effect_str.Cut()
|
||||
|
||||
/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C)
|
||||
var/update_type = UPDATE_SCHEDULE // for (APPLY|REMOVE)_CORNER.
|
||||
/datum/light_source/proc/recalc_corner(var/datum/lighting_corner/C, var/now = FALSE)
|
||||
if (effect_str.Find(C)) // Already have one.
|
||||
REMOVE_CORNER(C)
|
||||
REMOVE_CORNER(C,now)
|
||||
|
||||
APPLY_CORNER(C)
|
||||
APPLY_CORNER(C,now)
|
||||
|
||||
/datum/light_source/proc/smart_vis_update(var/update_type = UPDATE_SCHEDULE)
|
||||
/datum/light_source/proc/smart_vis_update(var/now = FALSE)
|
||||
var/list/datum/lighting_corner/corners = list()
|
||||
var/list/turf/turfs = list()
|
||||
FOR_DVIEW(var/turf/T, light_range, source_turf, 0)
|
||||
@@ -307,14 +311,16 @@
|
||||
effect_str[C] = 0
|
||||
continue
|
||||
|
||||
APPLY_CORNER(C)
|
||||
APPLY_CORNER(C,now)
|
||||
|
||||
for (var/datum/lighting_corner/C in effect_str - corners) // Old, now gone, corners.
|
||||
REMOVE_CORNER(C)
|
||||
REMOVE_CORNER(C,now)
|
||||
C.affecting -= src
|
||||
effect_str -= C
|
||||
|
||||
#undef effect_update
|
||||
#undef QUEUE_UPDATE
|
||||
#undef DO_UPDATE
|
||||
#undef INTELLIGENT_UPDATE
|
||||
#undef LUM_FALLOFF
|
||||
#undef REMOVE_CORNER
|
||||
#undef APPLY_CORNER
|
||||
|
||||
@@ -21,12 +21,6 @@
|
||||
for (var/datum/light_source/L in affecting_lights)
|
||||
L.vis_update()
|
||||
|
||||
// Avoid calling this if you can, bypasses the lighting scheduler (potentially creating lag).
|
||||
/turf/proc/update_lights_now()
|
||||
lprof_write(src, "turf_updatenow")
|
||||
for (var/datum/light_source/L in affecting_lights)
|
||||
L.update(update_type = UPDATE_NOW)
|
||||
|
||||
/turf/proc/lighting_clear_overlay()
|
||||
if (lighting_overlay)
|
||||
returnToPool(lighting_overlay)
|
||||
@@ -50,7 +44,7 @@
|
||||
if (!C.active) // We would activate the corner, calculate the lighting for it.
|
||||
for (var/L in C.affecting)
|
||||
var/datum/light_source/S = L
|
||||
S.recalc_corner(C)
|
||||
S.recalc_corner(C, TRUE)
|
||||
|
||||
C.active = TRUE
|
||||
|
||||
@@ -71,7 +65,7 @@
|
||||
|
||||
return CLAMP01(totallums)
|
||||
|
||||
// Gets the current UV illumination of the turf. Always 100% for space.
|
||||
// Gets the current UV illumination of the turf. Always 100% for space & other static-lit tiles.
|
||||
/turf/proc/get_uv_lumcount(var/minlum = 0, var/maxlum = 1)
|
||||
if (!lighting_overlay)
|
||||
return 1
|
||||
|
||||
Reference in New Issue
Block a user