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:
kevinz000
2020-05-23 13:47:42 -07:00
committed by GitHub
parent a6d7170d5b
commit e9068f05eb
12 changed files with 164 additions and 133 deletions
@@ -65,6 +65,7 @@
return ..()
/obj/screen/storage/volumetric_box/Destroy()
makeItemInactive()
our_item = null
return ..()
@@ -87,10 +88,14 @@
makeItemInactive()
/obj/screen/storage/volumetric_box/proc/makeItemInactive()
if(!our_item)
return
our_item.layer = VOLUMETRIC_STORAGE_ITEM_LAYER
our_item.plane = VOLUMETRIC_STORAGE_ITEM_PLANE
/obj/screen/storage/volumetric_box/proc/makeItemActive()
if(!our_item)
return
our_item.layer = VOLUMETRIC_STORAGE_ACTIVE_ITEM_LAYER //make sure we display infront of the others!
our_item.plane = VOLUMETRIC_STORAGE_ACTIVE_ITEM_PLANE
+15
View File
@@ -451,3 +451,18 @@ SUBSYSTEM_DEF(garbage)
#endif
#endif
#ifdef TESTING
/proc/writeDatumCount()
var/list/datums = list()
for(var/datum/D in world)
datums[D.type] += 1
for(var/datum/D)
datums[D.type] += 1
datums = sortTim(datums, /proc/cmp_numeric_dsc, associative = TRUE)
if(fexists("data/DATUMCOUNT.txt"))
fdel("data/DATUMCOUNT.txt")
var/outfile = file("data/DATUMCOUNT.txt")
for(var/path in datums)
outfile << "[datums[path]]\t\t\t\t\t[path]"
#endif
+4 -3
View File
@@ -43,7 +43,7 @@ SUBSYSTEM_DEF(input)
// LET'S PLAY THE BIND EVERY KEY GAME!
// oh except for Backspace and Enter; if you want to use those you shouldn't have used oldmode!
var/list/classic_ctrl_override_keys = list(
"\[", "\]", "\\", ";", "'", ",", ".", "/", "-", "\\=", "`"
"\[", "\]", "\\\\", ";", "'", ",", ".", "/", "-", "=", "`"
)
// i'm lazy let's play the list iteration game of numbers
for(var/i in 0 to 9)
@@ -58,8 +58,9 @@ SUBSYSTEM_DEF(input)
macroset_classic_input["Ctrl+L"] = "looc"
// let's play the list iteration game x2
for(var/key in classic_ctrl_override_keys)
macroset_classic_input["Ctrl+[key]"] = "\"KeyDown [key]\""
macroset_classic_input["Ctrl+[key]+UP"] = "\"KeyUp [key]\""
// make sure to double double quote to ensure things are treated as a key combo instead of addition/semicolon logic.
macroset_classic_input["\"Ctrl+[key]\""] = "\"KeyDown [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
macroset_classic_input["\"Ctrl+[key]+UP\""] = "\"KeyUp [istext(classic_ctrl_override_keys[key])? classic_ctrl_override_keys[key] : key]\""
// Misc
macroset_classic_input["Tab"] = "\".winset \\\"mainwindow.macro=[SKIN_MACROSET_CLASSIC_HOTKEYS] map.focus=true input.background-color=[COLOR_INPUT_DISABLED]\\\"\""
macroset_classic_input["Escape"] = "\".winset \\\"input.text=\\\"\\\"\\\"\""
+28 -11
View File
@@ -23,18 +23,12 @@
if(can_user_rotate)
src.can_user_rotate = can_user_rotate
else
src.can_user_rotate = CALLBACK(src,.proc/default_can_user_rotate)
if(can_be_rotated)
src.can_be_rotated = can_be_rotated
else
src.can_be_rotated = CALLBACK(src,.proc/default_can_be_rotated)
if(after_rotation)
src.after_rotation = after_rotation
else
src.after_rotation = CALLBACK(src,.proc/default_after_rotation)
//Try Clockwise,counter,flip in order
if(src.rotation_flags & ROTATION_FLIP)
@@ -103,14 +97,34 @@
examine_list += "<span class='notice'>Alt-click to rotate it clockwise.</span>"
/datum/component/simple_rotation/proc/HandRot(datum/source, mob/user, rotation = default_rotation_direction)
if(!can_be_rotated.Invoke(user, rotation) || !can_user_rotate.Invoke(user, rotation))
return
if(can_be_rotated)
if(!can_be_rotated.Invoke(user, default_rotation_direction))
return
else
if(!default_can_be_rotated(user, default_rotation_direction))
return
if(can_user_rotate)
if(!can_user_rotate.Invoke(user, default_rotation_direction))
return
else
if(!default_can_user_rotate(user, default_rotation_direction))
return
BaseRot(user, rotation)
return TRUE
/datum/component/simple_rotation/proc/WrenchRot(datum/source, obj/item/I, mob/living/user)
if(!can_be_rotated.Invoke(user,default_rotation_direction) || !can_user_rotate.Invoke(user,default_rotation_direction))
return
if(can_be_rotated)
if(!can_be_rotated.Invoke(user, default_rotation_direction))
return
else
if(!default_can_be_rotated(user, default_rotation_direction))
return
if(can_user_rotate)
if(!can_user_rotate.Invoke(user, default_rotation_direction))
return
else
if(!default_can_user_rotate(user, default_rotation_direction))
return
if(istype(I,/obj/item/wrench))
BaseRot(user,default_rotation_direction)
return COMPONENT_NO_AFTERATTACK
@@ -126,7 +140,10 @@
if(ROTATION_FLIP)
rot_degree = 180
AM.setDir(turn(AM.dir,rot_degree))
after_rotation.Invoke(user,rotation_type)
if(after_rotation)
after_rotation.Invoke(user, rotation_type)
else
default_after_rotation(user, rotation_type)
/datum/component/simple_rotation/proc/default_can_user_rotate(mob/living/user, rotation_type)
if(!istype(user) || !user.canUseTopic(parent, BE_CLOSE, NO_DEXTERY))
@@ -136,9 +136,7 @@
var/mob/M = parent.loc
I.dropped(M)
if(new_location)
//Reset the items values
_removal_reset(AM)
AM.forceMove(new_location)
AM.forceMove(new_location) // exited comsig will handle removal reset.
//We don't want to call this if the item is being destroyed
AM.on_exit_storage(src)
else
+1 -1
View File
@@ -351,7 +351,6 @@
return master._removal_reset(thing)
/datum/component/storage/proc/_remove_and_refresh(datum/source, atom/movable/thing)
_removal_reset(thing)
if(LAZYACCESS(ui_item_blocks, thing))
var/obj/screen/storage/volumetric_box/center/C = ui_item_blocks[thing]
for(var/i in can_see_contents()) //runtimes result if mobs can access post deletion.
@@ -359,6 +358,7 @@
M.client?.screen -= C.on_screen_objects()
ui_item_blocks -= thing
qdel(C)
_removal_reset(thing) // THIS NEEDS TO HAPPEN AFTER SO LAYERING DOESN'T BREAK!
refresh_mob_views()
//Call this proc to handle the removal of an item from the storage item. The item will be moved to the new_location target, if that is null it's being deleted
+8 -2
View File
@@ -80,7 +80,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
var/old_dynamic_lighting = dynamic_lighting
var/old_affecting_lights = affecting_lights
var/old_lighting_object = lighting_object
var/old_corners = corners
var/old_lc_topright = lc_topright
var/old_lc_topleft = lc_topleft
var/old_lc_bottomright = lc_bottomright
var/old_lc_bottomleft = lc_bottomleft
var/old_exl = explosion_level
var/old_exi = explosion_id
@@ -119,7 +122,10 @@ GLOBAL_LIST_INIT(blacklisted_automated_baseturfs, typecacheof(list(
recalc_atom_opacity()
lighting_object = old_lighting_object
affecting_lights = old_affecting_lights
corners = old_corners
lc_topright = old_lc_topright
lc_topleft = old_lc_topleft
lc_bottomright = old_lc_bottomright
lc_bottomleft = old_lc_bottomleft
if (old_opacity != opacity || dynamic_lighting != old_dynamic_lighting)
reconsider_lights()
@@ -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
+34 -51
View File
@@ -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
+5 -11
View File
@@ -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)
+11 -4
View File
@@ -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)
+37 -47
View File
@@ -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