Misc. Optimizations (#3993)

changes:

Overlays now creates less temporary lists.
Falling no longer queues unsimulated atoms that wouldn't fall anyways (incl. LOs).
Pixel-shifted AO is now cached too.
Changed some references to get_map_cell() to macro equivalents in random maps.
Added smoothing hinting to the icon smoother, allowing for major performance improvements in common cases.
Space initialization no longer involves appearance churn (and is much faster as a result).
This commit is contained in:
Lohikar
2017-12-23 13:27:51 -06:00
committed by Erki
parent 64d24c6979
commit bb5a34eaf8
12 changed files with 213 additions and 131 deletions
+90 -54
View File
@@ -39,6 +39,10 @@
#define SMOOTH_QUEUED 16 //atom is currently queued to smooth.
#define SMOOTH_NO_CLEAR_ICON 32 // don't clear the atom's icon_state on smooth.
#define SMOOTHHINT_CUT_ON_ALL_F 1 // Don't apply overlays if they're all the 'f' state.
#define SMOOTHHINT_ONLY_MATCH_TURF 2 // Only try to match turfs (this is faster than matching all atoms)
#define SMOOTHHINT_TARGETS_NOT_UNIQUE 4 // The smoother can assume that all atoms of this type will have the same canSmoothWith value.
#define NULLTURF_BORDER 123456789
#define DEFAULT_UNDERLAY_ICON 'icons/turf/floors.dmi'
@@ -47,6 +51,7 @@
/atom
var/smooth = SMOOTH_FALSE
var/smoothing_hints = SMOOTHHINT_TARGETS_NOT_UNIQUE
var/tmp/top_left_corner
var/tmp/top_right_corner
var/tmp/bottom_left_corner
@@ -75,47 +80,63 @@
var/adjacencies = 0
var/atom/movable/AM
if (smoothing_hints & SMOOTHHINT_ONLY_MATCH_TURF)
var/turf/T
var/list/tcache
if (smoothing_hints & SMOOTHHINT_TARGETS_NOT_UNIQUE)
tcache = SSicon_smooth.typecachecache[type]
if (!tcache)
tcache = typecacheof(canSmoothWith || type, FALSE, !(smooth & SMOOTH_MORE))
SSicon_smooth.typecachecache[type] = tcache
else
tcache = typecacheof(canSmoothWith || type, FALSE, !(smooth & SMOOTH_MORE))
for(var/direction in cardinal)
AM = find_type_in_direction(src, direction)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
if (smooth & SMOOTH_BORDER)
CALCULATE_NEIGHBORS(src, adjacencies, T, !T || tcache[T.type])
else
CALCULATE_NEIGHBORS(src, adjacencies, T, T && tcache[T.type])
else
var/atom/movable/AM
for(var/direction in cardinal)
AM = find_type_in_direction(src, direction)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
adjacencies |= 1 << direction
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= 1 << direction
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= 1 << direction
if(adjacencies & N_NORTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(src, NORTHWEST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
if(adjacencies & N_NORTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(src, NORTHWEST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
adjacencies |= N_NORTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHWEST
if(adjacencies & N_EAST)
AM = find_type_in_direction(src, NORTHEAST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
if(adjacencies & N_EAST)
AM = find_type_in_direction(src, NORTHEAST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
adjacencies |= N_NORTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_NORTHEAST
if(adjacencies & N_SOUTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(src, SOUTHWEST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
if(adjacencies & N_SOUTH)
if(adjacencies & N_WEST)
AM = find_type_in_direction(src, SOUTHWEST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
adjacencies |= N_SOUTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHWEST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHWEST
if(adjacencies & N_EAST)
AM = find_type_in_direction(src, SOUTHEAST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
if(adjacencies & N_EAST)
AM = find_type_in_direction(src, SOUTHEAST)
if(AM == NULLTURF_BORDER)
if((smooth & SMOOTH_BORDER))
adjacencies |= N_SOUTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHEAST
else if( (AM && !istype(AM)) || (istype(AM) && AM.anchored) )
adjacencies |= N_SOUTHEAST
return adjacencies
@@ -207,11 +228,13 @@
underlays = U
/proc/cardinal_smooth(atom/A, adjacencies)
var/num_of_f = 0
//NW CORNER
var/nw = "1-i"
if((adjacencies & N_NORTH) && (adjacencies & N_WEST))
if(adjacencies & N_NORTHWEST)
nw = "1-f"
num_of_f++
else
nw = "1-nw"
else
@@ -225,6 +248,7 @@
if((adjacencies & N_NORTH) && (adjacencies & N_EAST))
if(adjacencies & N_NORTHEAST)
ne = "2-f"
num_of_f++
else
ne = "2-ne"
else
@@ -238,6 +262,7 @@
if((adjacencies & N_SOUTH) && (adjacencies & N_WEST))
if(adjacencies & N_SOUTHWEST)
sw = "3-f"
num_of_f++
else
sw = "3-sw"
else
@@ -251,6 +276,7 @@
if((adjacencies & N_SOUTH) && (adjacencies & N_EAST))
if(adjacencies & N_SOUTHEAST)
se = "4-f"
num_of_f++
else
se = "4-se"
else
@@ -289,7 +315,7 @@
if(Old)
A.cut_overlay(Old)
if(New)
if(New && (num_of_f != 4 || !(A.smoothing_hints & SMOOTHHINT_CUT_ON_ALL_F)))
A.add_overlay(New)
if (A.icon_state && !(A.smooth & SMOOTH_NO_CLEAR_ICON))
@@ -362,33 +388,43 @@
if(!target_turf)
return NULLTURF_BORDER
if(source.canSmoothWith)
var/atom/A
if(source.smooth & SMOOTH_MORE)
if (source.smoothing_hints & SMOOTHHINT_TARGETS_NOT_UNIQUE)
var/list/tcache = SSicon_smooth.typecachecache[source.type]
if (!tcache)
tcache = typecacheof(source.canSmoothWith || source.type, FALSE, !(source.smooth & SMOOTH_MORE))
SSicon_smooth.typecachecache[source.type] = tcache
if (is_type_in_typecache(target_turf, tcache))
return target_turf
return typecache_first_match(target_turf.contents, tcache)
else
if(source.canSmoothWith)
var/atom/A
if(source.smooth & SMOOTH_MORE)
for(var/a_type in source.canSmoothWith)
if( istype(target_turf, a_type) )
return target_turf
if (ispath(a_type, /turf))
continue
A = locate(a_type) in target_turf
if(A)
return A
return null
for(var/a_type in source.canSmoothWith)
if( istype(target_turf, a_type) )
if(a_type == target_turf.type)
return target_turf
if (ispath(a_type, /turf))
continue
A = locate(a_type) in target_turf
if(A)
if(A && A.type == a_type)
return A
return null
for(var/a_type in source.canSmoothWith)
if(a_type == target_turf.type)
return target_turf
if (ispath(a_type, /turf))
continue
A = locate(a_type) in target_turf
if(A && A.type == a_type)
return A
return null
else
if(isturf(source))
return source.type == target_turf.type ? target_turf : null
var/atom/A = locate(source.type) in target_turf
return A && A.type == source.type ? A : null
else
if(isturf(source))
return source.type == target_turf.type ? target_turf : null
var/atom/A = locate(source.type) in target_turf
return A && A.type == source.type ? A : null
//Icon smoothing helpers
/proc/smooth_zlevel(var/zlevel, now = FALSE)
+6
View File
@@ -318,6 +318,12 @@
if(typecache_include[A.type] && !typecache_exclude[A.type])
. += A
/proc/typecache_first_match(list/target, list/typecache)
for (var/thing in target)
var/datum/D = thing
if (typecache[D.type])
return D
//Like typesof() or subtypesof(), but returns a typecache instead of a list
/proc/typecacheof(path, ignore_root_path, only_root_path = FALSE)
if(ispath(path))
+30 -1
View File
@@ -2,7 +2,8 @@
/datum/controller/subsystem/icon_cache
name = "Icon Cache"
flags = SS_NO_FIRE | SS_NO_INIT
flags = SS_NO_FIRE
init_order = SS_INIT_MISC_FIRST
// Cached bloody overlays, key is object type.
var/list/bloody_cache = list()
@@ -67,9 +68,20 @@
var/list/rgb_blend_cache = list() // not an icon per-se, but this proc could be expensive so we might as well cache it.
var/list/space_dust_cache = list()
var/list/space_cache = list()
/datum/controller/subsystem/icon_cache/New()
NEW_SS_GLOBAL(SSicon_cache)
/datum/controller/subsystem/icon_cache/Initialize()
build_dust_cache()
build_space_cache()
setup_collar_mappings()
setup_uniform_mappings()
..()
/datum/controller/subsystem/icon_cache/proc/setup_collar_mappings()
collar_states = list()
for (var/i in icon_states('icons/mob/collar.dmi'))
@@ -94,3 +106,20 @@
var/image/I = new(icon, icon_state)
I.color = color
return I
/datum/controller/subsystem/icon_cache/proc/build_dust_cache()
for (var/i in 0 to 25)
var/image/im = image('icons/turf/space_parallax1.dmi',"[i]")
im.plane = PLANE_SPACE_DUST
im.alpha = 80
im.blend_mode = BLEND_ADD
space_dust_cache["[i]"] = im
/datum/controller/subsystem/icon_cache/proc/build_space_cache()
for (var/i in 0 to 25)
var/image/I = new()
I.appearance = /turf/space
var/istr = "[i]"
I.icon_state = istr
I.overlays += space_dust_cache[istr]
space_cache[istr] = I
@@ -8,6 +8,7 @@ var/datum/controller/subsystem/icon_smooth/SSicon_smooth
flags = SS_TICKER | SS_FIRE_IN_LOBBY
var/list/smooth_queue = list()
var/list/typecachecache = list()
var/explosion_in_progress = FALSE
+27 -19
View File
@@ -102,25 +102,33 @@ var/datum/controller/subsystem/overlays/SSoverlays
. = iconbro.appearance
icon_cache[icon] = .
/atom/proc/build_appearance_list(new_overlays)
var/static/image/appearance_bro = new()
if (!islist(new_overlays))
new_overlays = list(new_overlays)
else
listclearnulls(new_overlays)
for (var/i in 1 to length(new_overlays))
var/image/cached_overlay = new_overlays[i]
if (istext(cached_overlay))
new_overlays[i] = iconstate2appearance(icon, cached_overlay)
else if(isicon(cached_overlay))
new_overlays[i] = icon2appearance(cached_overlay)
else //image probable
appearance_bro.appearance = cached_overlay
if(!ispath(cached_overlay))
appearance_bro.dir = cached_overlay.dir
new_overlays[i] = appearance_bro.appearance
return new_overlays
#define APPEARANCEIFY(origin, target) \
if (istext(origin)) { \
target = iconstate2appearance(icon, origin); \
} \
else if (isicon(origin)) { \
target = icon2appearance(origin); \
} \
else { \
appearance_bro.appearance = origin; \
if (!ispath(origin)) { \
appearance_bro.dir = origin.dir; \
} \
target = appearance_bro.appearance; \
}
/atom/proc/build_appearance_list(atom/new_overlays)
var/static/image/appearance_bro = new
if (islist(new_overlays))
listclearnulls(new_overlays)
for (var/i in 1 to length(new_overlays))
var/image/cached_overlay = new_overlays[i]
APPEARANCEIFY(cached_overlay, new_overlays[i])
return new_overlays
else
APPEARANCEIFY(new_overlays, .)
#undef APPEARANCEIFY
#define NOT_QUEUED_ALREADY (!(overlay_queued))
#define QUEUE_FOR_COMPILE overlay_queued = TRUE; SSoverlays.processing += src;
@@ -165,7 +173,7 @@ var/datum/controller/subsystem/overlays/SSoverlays
overlays = build_appearance_list(overlays)
if (!overlays.len)
if (!overlays || (islist(overlays) && !overlays.len))
// No point trying to compile if we don't have any overlays.
return
+1
View File
@@ -22,6 +22,7 @@
icon = 'icons/turf/smooth/cult_wall.dmi'
canSmoothWith = null
smooth = SMOOTH_TRUE
smoothing_hints = SMOOTHHINT_TARGETS_NOT_UNIQUE | SMOOTHHINT_ONLY_MATCH_TURF
icon_state = "cult"
/turf/simulated/wall/rusty
+3 -17
View File
@@ -10,30 +10,15 @@
temperature = T20C
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
var/static/list/dust_cache
// heat_capacity = 700000 No.
is_hole = TRUE
permit_ao = FALSE
/turf/space/proc/build_dust_cache()
LAZYINITLIST(dust_cache)
for (var/i in 0 to 25)
var/image/im = image('icons/turf/space_parallax1.dmi',"[i]")
im.plane = PLANE_SPACE_DUST
im.alpha = 80
im.blend_mode = BLEND_ADD
dust_cache["[i]"] = im
// Copypaste of parent for performance.
/turf/space/Initialize()
icon_state = "[((x + y) ^ ~(x * y) + z) % 25]"
if (!dust_cache)
build_dust_cache()
add_overlay(dust_cache[icon_state])
appearance = SSicon_cache.space_cache["[((x + y) ^ ~(x * y) + z) % 25]"]
update_starlight()
if (initialized)
@@ -76,7 +61,8 @@
set_light(config.starlight)
return
set_light(0)
if (light_range)
set_light(0)
/turf/space/attackby(obj/item/C as obj, mob/user as mob)
+11 -16
View File
@@ -26,15 +26,21 @@
var/turf/T
CALCULATE_NEIGHBORS(src, ao_neighbors, T, AO_TURF_CHECK(T))
/proc/make_ao_image(corner, i)
/proc/make_ao_image(corner, i, px = 0, py = 0, pz = 0, pw = 0)
var/list/cache = SSicon_cache.ao_cache
var/cstr = "[corner]"
var/key = "[cstr]-[i]"
var/key = "[cstr]-[i]-[px]/[py]/[pz]/[pw]"
var/image/I = image('icons/turf/flooring/shadows.dmi', cstr, dir = 1 << (i-1))
I.alpha = WALL_AO_ALPHA
I.blend_mode = BLEND_OVERLAY
I.appearance_flags = RESET_ALPHA|RESET_COLOR|TILE_BOUND
// If there's an offset, counteract it.
if (px || py || pz || pw)
I.pixel_x = -px
I.pixel_y = -py
I.pixel_z = -pz
I.pixel_w = -pw
. = cache[key] = I
@@ -71,22 +77,11 @@
corner |= 4
if (corner != 7) // 7 is the 'no shadows' state, no reason to add overlays for it.
var/image/I = cache["[corner]-[i]"]
var/image/I = cache["[corner]-[i]-[pixel_x]/[pixel_y]/[pixel_z]/[pixel_w]"]
if (!I)
I = make_ao_image(corner, i) // this will also add the image to the cache.
I = make_ao_image(corner, i, pixel_x, pixel_y, pixel_z, pixel_w) // this will also add the image to the cache.
if (!pixel_x && !pixel_y && !pixel_w && !pixel_z) // We can only use the cache if we're not shifting.
LAZYADD(ao_overlays, I)
else
// There's a pixel var set, so we're going to need to make a new instance just for this type.
var/mutable_appearance/MA = new(I)
// We invert the offsets here to counteract the pixel shifting of the parent turf.
MA.pixel_x = -(pixel_x)
MA.pixel_y = -(pixel_y)
MA.pixel_w = -(pixel_w)
MA.pixel_z = -(pixel_z)
LAZYADD(ao_overlays, MA)
LAZYADD(ao_overlays, I)
UNSETEMPTY(ao_overlays)
+2 -2
View File
@@ -45,7 +45,7 @@
/atom/movable/lighting_overlay/proc/update_overlay()
var/turf/T = loc
if (!istype(T)) // Erm...
if (!isturf(T)) // Erm...
if (loc)
warning("A lighting overlay realised its loc was NOT a turf (actual loc: [loc], [loc.type]) in update_overlay() and got deleted!")
@@ -92,7 +92,7 @@
else if (!luminosity)
icon_state = LIGHTING_DARKNESS_ICON_STATE
color = null
else if (ALL_EQUAL && rr == LIGHTING_DEFAULT_TUBE_R && rg == LIGHTING_DEFAULT_TUBE_G && rb == LIGHTING_DEFAULT_TUBE_B)
else if (rr == LIGHTING_DEFAULT_TUBE_R && rg == LIGHTING_DEFAULT_TUBE_G && rb == LIGHTING_DEFAULT_TUBE_B && ALL_EQUAL)
icon_state = LIGHTING_STATION_ICON_STATE
color = null
else
+4 -1
View File
@@ -15,13 +15,15 @@
gender = PLURAL
var/icon/actual_icon = 'icons/turf/smooth/rock_wall.dmi'
layer = 2.01
smooth = SMOOTH_MORE | SMOOTH_BORDER
smooth = SMOOTH_MORE | SMOOTH_BORDER | SMOOTH_NO_CLEAR_ICON
smoothing_hints = SMOOTHHINT_CUT_ON_ALL_F | SMOOTHHINT_ONLY_MATCH_TURF | SMOOTHHINT_TARGETS_NOT_UNIQUE
canSmoothWith = list(
/turf/simulated/mineral,
/turf/simulated/wall,
/turf/unsimulated/wall,
/turf/simulated/shuttle
)
oxygen = 0
nitrogen = 0
opacity = 1
@@ -509,6 +511,7 @@
icon_state = "ash"
desc = "A fine grey ash. Looks pretty tightly packed."
smooth = SMOOTH_MORE | SMOOTH_BORDER | SMOOTH_NO_CLEAR_ICON
smoothing_hints = SMOOTHHINT_CUT_ON_ALL_F | SMOOTHHINT_ONLY_MATCH_TURF | SMOOTHHINT_TARGETS_NOT_UNIQUE
gender = PLURAL
canSmoothWith = list(
/turf/simulated/floor/asteroid,
+18 -10
View File
@@ -162,7 +162,7 @@
..()
update()
/turf/simulated/open/Initialize()
/turf/simulated/open/Initialize(mapload)
. = ..()
icon_state = "" // Clear out the debug icon.
SSopenturf.openspace_turfs += src
@@ -170,23 +170,31 @@
if (no_mutate && plane == PLANE_SPACE_BACKGROUND)
// If the plane is default and we're a no_mutate turf, force it to 0 so the icon works properly.
plane = 0
update()
update(mapload)
/**
* Updates the turf with open turf's variables and basically resets it properly.
*/
/turf/simulated/open/proc/update()
/turf/simulated/open/proc/update(mapload = FALSE)
below = GetBelow(src)
// Edge case for when an open turf is above space on the lowest level.
if (below)
below.above = src
levelupdate()
if (is_hole)
for (var/atom/movable/A in src)
ADD_FALLING_ATOM(A)
update_icon()
if (mapload)
for (var/obj/O in src) // We're not going to try to make mobs fall here for performance reasons - they shouldn't be mapped in on openturfs anyways.
if (is_hole && O.simulated)
ADD_FALLING_ATOM(O)
else
for (var/thing in src)
var/obj/O = thing // This might not be an obj.
if (isobj(O))
O.hide(0)
if (is_hole && O.simulated)
ADD_FALLING_ATOM(O)
update_icon(mapload)
/turf/simulated/open/update_dirt()
return 0
@@ -196,12 +204,12 @@
for(var/obj/O in src)
O.hide(0)
/turf/simulated/open/update_icon()
/turf/simulated/open/update_icon(mapload)
if(!updating && below)
updating = TRUE
SSopenturf.queued_turfs += src
if (above) // Even if we're already updating, the turf above us might not be.
if (!mapload && above) // Even if we're already updating, the turf above us might not be.
// Cascade updates until we hit the top openturf.
above.update_icon()
+20 -11
View File
@@ -26,6 +26,7 @@ var/global/list/map_count = list()
// Storage for the final iteration of the map.
var/list/map = list() // Actual map.
var/tmp/map_len = 0
// If set, all sleep(-1) calls will be skipped.
// Test to see if rand_seed() can be used reliably.
@@ -100,23 +101,28 @@ var/global/list/map_count = list()
if(!user)
user = world
var/dat = "<code>+------+<br>"
map_len = map.len
var/list/dat = "<code>+------+<br>"
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
if(current_cell)
dat += get_map_char(map[current_cell])
var/tmp_cell
TRANSLATE_AND_VERIFY_COORD_MLEN(x, y, map_len)
if(tmp_cell)
dat += get_map_char(map[tmp_cell])
dat += "<br>"
user << "[dat]+------+</code>"
dat += "+------+</code>"
user << dat.Join()
/datum/random_map/proc/set_map_size()
map = list()
map.len = limit_x * limit_y
/datum/random_map/proc/seed_map()
map_len = map.len
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
var/current_cell = get_map_cell(x,y)
var/current_cell = TRANSLATE_COORD(x, y) // Coordinate cannot be invalid here, so use the faster no-validate one.
if(prob(initial_wall_cell))
map[current_cell] = WALL_CHAR
else
@@ -125,7 +131,7 @@ var/global/list/map_count = list()
/datum/random_map/proc/clear_map()
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
map[get_map_cell(x,y)] = 0
map[TRANSLATE_COORD(x, y)] = 0
/datum/random_map/proc/generate()
seed_map()
@@ -154,6 +160,8 @@ var/global/list/map_count = list()
if(!origin_y) origin_y = 1
if(!origin_z) origin_z = 1
map_len = map.len
for(var/x = 1, x <= limit_x, x++)
for(var/y = 1, y <= limit_y, y++)
if(!priority_process)
@@ -161,16 +169,17 @@ var/global/list/map_count = list()
apply_to_turf(x,y)
/datum/random_map/proc/apply_to_turf(var/x,var/y)
var/current_cell = get_map_cell(x,y)
if(!current_cell)
var/tmp_cell
TRANSLATE_AND_VERIFY_COORD_MLEN(x, y, map_len)
if(!tmp_cell)
return 0
var/turf/T = locate((origin_x-1)+x,(origin_y-1)+y,origin_z)
if(!T || (target_turf_type && !istype(T,target_turf_type)))
return 0
var/newpath = get_appropriate_path(map[current_cell])
var/newpath = get_appropriate_path(map[tmp_cell])
if(newpath)
T.ChangeTurf(newpath)
get_additional_spawns(map[current_cell],T,get_spawn_dir(x, y))
get_additional_spawns(map[tmp_cell],T,get_spawn_dir(x, y))
return T
/datum/random_map/proc/get_spawn_dir()