let's play the optimization game featuring lighting (#12310)
* debug proc * kinda quirky * let's play the lighting game * let's play the macro game * let's play the refactor game * let's play the optimization game * let's play the optimization game x2 * yeehaw * e * let's play the memory game * fix * lighting fix * sanitization and checks * mh * hotkeys fix * ok
This commit is contained in:
@@ -317,8 +317,23 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
|
||||
no_tetris_storage = sanitize_integer(no_tetris_storage, 0, 1, initial(no_tetris_storage))
|
||||
key_bindings = sanitize_islist(key_bindings, list())
|
||||
|
||||
verify_keybindings_valid() // one of these days this will runtime and you'll be glad that i put it in a different proc so no one gets their saves wiped
|
||||
|
||||
return 1
|
||||
|
||||
/datum/preferences/proc/verify_keybindings_valid()
|
||||
// Sanitize the actual keybinds to make sure they exist.
|
||||
for(var/key in key_bindings)
|
||||
if(!islist(key_bindings[key]))
|
||||
key_bindings -= key
|
||||
var/list/binds = key_bindings[key]
|
||||
for(var/bind in binds)
|
||||
if(!GLOB.keybindings_by_name[bind])
|
||||
binds -= bind
|
||||
if(!length(binds))
|
||||
key_bindings -= key
|
||||
// End
|
||||
|
||||
/datum/preferences/proc/save_preferences()
|
||||
if(!path)
|
||||
return 0
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
// 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/turf/northeast
|
||||
var/turf/northwest
|
||||
var/turf/southeast
|
||||
var/turf/southwest
|
||||
var/list/datum/light_source/affecting // Light sources affecting us.
|
||||
var/active = FALSE // TRUE if one of our masters has dynamic lighting.
|
||||
|
||||
@@ -25,10 +25,18 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
|
||||
var/cache_b = LIGHTING_SOFT_THRESHOLD
|
||||
var/cache_mx = 0
|
||||
|
||||
/datum/lighting_corner/New(var/turf/new_turf, var/diagonal)
|
||||
// Diagonal is our direction FROM them, not to.
|
||||
/datum/lighting_corner/New(turf/new_turf, diagonal)
|
||||
. = ..()
|
||||
masters = list()
|
||||
masters[new_turf] = turn(diagonal, 180)
|
||||
|
||||
#define SET_DIAGONAL(turf, diagonal) \
|
||||
switch(diagonal){ \
|
||||
if(SOUTHWEST) { northeast = turf; turf.lc_bottomleft = src; } \
|
||||
if(SOUTHEAST) { northwest = turf; turf.lc_bottomright = src; } \
|
||||
if(NORTHEAST) { southwest = turf; turf.lc_topright = src; } \
|
||||
if(NORTHWEST) { southeast = turf; turf.lc_topleft = src; } \
|
||||
}
|
||||
SET_DIAGONAL(new_turf, diagonal)
|
||||
z = new_turf.z
|
||||
|
||||
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.
|
||||
@@ -37,52 +45,28 @@ GLOBAL_LIST_INIT(LIGHTING_CORNER_DIAGONAL, list(NORTHEAST, SOUTHEAST, SOUTHWEST,
|
||||
x = new_turf.x + (horizontal == EAST ? 0.5 : -0.5)
|
||||
y = new_turf.y + (vertical == NORTH ? 0.5 : -0.5)
|
||||
|
||||
// My initial plan was to make this loop through a list of all the dirs (horizontal, vertical, diagonal).
|
||||
// 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.
|
||||
// Build diagonal one
|
||||
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
|
||||
|
||||
// Now the horizontal one.
|
||||
if(T)
|
||||
SET_DIAGONAL(T, turn(diagonal, 180))
|
||||
// Build horizontal
|
||||
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
|
||||
|
||||
// And finally the vertical one.
|
||||
if(T)
|
||||
SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180))
|
||||
// Build vertical
|
||||
T = get_step(new_turf, vertical)
|
||||
if (T)
|
||||
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
|
||||
if(T)
|
||||
SET_DIAGONAL(T, turn(((T.x > x) ? EAST : WEST) | ((T.y > y) ? NORTH : SOUTH), 180))
|
||||
|
||||
update_active()
|
||||
|
||||
#undef SET_DIAGONAL
|
||||
|
||||
/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
|
||||
if(northeast?.lighting_object || northwest?.lighting_object || southeast?.lighting_object || southwest?.lighting_object)
|
||||
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)
|
||||
@@ -122,13 +106,12 @@ 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)
|
||||
if (!T.lighting_object.needs_update)
|
||||
T.lighting_object.needs_update = TRUE
|
||||
GLOB.lighting_update_objects += T.lighting_object
|
||||
|
||||
#define QUEUE(turf) if(turf?.lighting_object && !turf.lighting_object.needs_update) { turf.lighting_object.needs_update = TRUE; GLOB.lighting_update_objects += turf.lighting_object }
|
||||
QUEUE(northeast)
|
||||
QUEUE(northwest)
|
||||
QUEUE(southeast)
|
||||
QUEUE(southwest)
|
||||
#undef QUEUE
|
||||
|
||||
/datum/lighting_corner/dummy/New()
|
||||
return
|
||||
|
||||
@@ -55,7 +55,7 @@
|
||||
if (loc)
|
||||
var/turf/oldturf = get_turf(myturf)
|
||||
var/turf/newturf = get_turf(loc)
|
||||
warning("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
|
||||
stack_trace("A lighting object realised it's loc had changed in update() ([myturf]\[[myturf ? myturf.type : "null"]]([COORD(oldturf)]) -> [loc]\[[ loc ? loc.type : "null"]]([COORD(newturf)]))!")
|
||||
|
||||
qdel(src, TRUE)
|
||||
return
|
||||
@@ -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.lc_bottomleft || dummy_lighting_corner
|
||||
var/datum/lighting_corner/cg = myturf.lc_bottomright || dummy_lighting_corner
|
||||
var/datum/lighting_corner/cb = myturf.lc_topleft || dummy_lighting_corner
|
||||
var/datum/lighting_corner/ca = myturf.lc_topright || dummy_lighting_corner
|
||||
|
||||
var/max = max(cr.cache_mx, cg.cache_mx, cb.cache_mx, ca.cache_mx)
|
||||
|
||||
|
||||
@@ -237,18 +237,25 @@
|
||||
return //nothing's changed
|
||||
|
||||
var/list/datum/lighting_corner/corners = list()
|
||||
var/datum/lighting_corner/C
|
||||
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))
|
||||
for (thing in T.get_corners(source_turf))
|
||||
C = thing
|
||||
corners[C] = 0
|
||||
turfs += T
|
||||
if(!IS_DYNAMIC_LIGHTING(T) && !T.light_sources)
|
||||
continue
|
||||
if(!T.lighting_corners_initialised)
|
||||
T.generate_missing_corners()
|
||||
if(T.has_opaque_atom)
|
||||
continue
|
||||
corners[T.lc_topright] = 0
|
||||
corners[T.lc_bottomright] = 0
|
||||
corners[T.lc_bottomleft] = 0
|
||||
corners[T.lc_topleft] = 0
|
||||
source_turf.luminosity = oldlum
|
||||
|
||||
LAZYINITLIST(affecting_turfs)
|
||||
|
||||
@@ -6,9 +6,15 @@
|
||||
|
||||
var/tmp/list/datum/light_source/affecting_lights // List of light sources affecting this turf.
|
||||
var/tmp/atom/movable/lighting_object/lighting_object // Our lighting object.
|
||||
var/tmp/list/datum/lighting_corner/corners
|
||||
var/tmp/datum/lighting_corner/lc_topleft
|
||||
var/tmp/datum/lighting_corner/lc_topright
|
||||
var/tmp/datum/lighting_corner/lc_bottomleft
|
||||
var/tmp/datum/lighting_corner/lc_bottomright
|
||||
var/tmp/has_opaque_atom = FALSE // Not to be confused with opacity, this will be TRUE if there's any opaque atom on the tile.
|
||||
|
||||
// counterclockwisse 0 to 360
|
||||
#define PROC_ON_CORNERS(operation) lc_topright?.##operation;lc_bottomright?.##operation;lc_bottomleft?.##operation;lc_topleft?.##operation
|
||||
|
||||
// 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
|
||||
@@ -21,13 +27,7 @@
|
||||
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()
|
||||
PROC_ON_CORNERS(update_active())
|
||||
|
||||
// Builds a lighting object for us, but only if our area is dynamic.
|
||||
/turf/proc/lighting_build_overlay()
|
||||
@@ -43,32 +43,31 @@
|
||||
|
||||
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
|
||||
var/i
|
||||
#define OPERATE(corner) \
|
||||
if(corner && !corner.active) { \
|
||||
for(i in corner.affecting) { \
|
||||
S = i ; \
|
||||
S.recalc_corner(corner) \
|
||||
} \
|
||||
corner.active = TRUE \
|
||||
}
|
||||
OPERATE(lc_topright)
|
||||
OPERATE(lc_bottomright)
|
||||
OPERATE(lc_bottomleft)
|
||||
OPERATE(lc_topleft)
|
||||
#undef OPERATE
|
||||
|
||||
// Used to get a scaled lumcount.
|
||||
/turf/proc/get_lumcount(var/minlum = 0, var/maxlum = 1)
|
||||
if (!lighting_object)
|
||||
if(!lighting_object)
|
||||
return 1
|
||||
|
||||
var/totallums = 0
|
||||
var/thing
|
||||
var/datum/lighting_corner/L
|
||||
for (thing in corners)
|
||||
if(!thing)
|
||||
continue
|
||||
L = thing
|
||||
totallums += L.lum_r + L.lum_b + L.lum_g
|
||||
var/totallums = (lc_topright? (lc_topright.lum_r + lc_topright.lum_g + lc_topright.lum_b) : 0) \
|
||||
+ (lc_bottomright? (lc_bottomright.lum_r + lc_bottomright.lum_g + lc_bottomright.lum_b) : 0) \
|
||||
+ (lc_bottomleft? (lc_bottomleft.lum_r + lc_bottomleft.lum_g + lc_bottomleft.lum_b) : 0) \
|
||||
+ (lc_topleft? (lc_topleft.lum_r + lc_topleft.lum_g + lc_topleft.lum_b) : 0)
|
||||
|
||||
totallums /= 12 // 4 corners, each with 3 channels, get the average.
|
||||
|
||||
@@ -110,27 +109,18 @@
|
||||
else
|
||||
lighting_clear_overlay()
|
||||
|
||||
/turf/proc/get_corners()
|
||||
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
|
||||
return null
|
||||
if (!lighting_corners_initialised)
|
||||
generate_missing_corners()
|
||||
if (has_opaque_atom)
|
||||
return null // Since this proc gets used in a for loop, null won't be looped though.
|
||||
|
||||
return corners
|
||||
|
||||
/turf/proc/generate_missing_corners()
|
||||
if (!IS_DYNAMIC_LIGHTING(src) && !light_sources)
|
||||
return
|
||||
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])
|
||||
|
||||
// counterclockwise from 0 to 360.
|
||||
if(!lc_topright)
|
||||
new /datum/lighting_corner(src, NORTHEAST)
|
||||
if(!lc_bottomright)
|
||||
new /datum/lighting_corner(src, SOUTHEAST)
|
||||
if(!lc_bottomleft)
|
||||
new /datum/lighting_corner(src, SOUTHWEST)
|
||||
if(!lc_topleft)
|
||||
new /datum/lighting_corner(src, NORTHWEST)
|
||||
|
||||
#undef PROC_ON_CORNERS
|
||||
|
||||
Reference in New Issue
Block a user