fast turf reservation lookups & aligned spatial grid lookups (#6532)

# why?

non-player facing

we're going to need fast lookups for "is this thing in range of this
other thing" at some point, for things like telecomms

this current solution consumes about 16KB per reservation level

we also add the capability to use spatial grids to quickly get atoms on
a level.
spatial grids are also at 16KB per grid, per world level

all in all worth it in my opinion.
This commit is contained in:
silicons
2024-06-20 17:26:53 -06:00
committed by GitHub
parent 83bc9a7ebf
commit 7b5c263ae5
8 changed files with 211 additions and 60 deletions
+57 -8
View File
@@ -27,6 +27,13 @@
/// type of our area - null for default
var/area_type
//* spatial lookup *//
var/spatial_bl_x
var/spatial_bl_y
var/spatial_tr_x
var/spatial_tr_y
var/spatial_z
/datum/turf_reservation/New()
if(isnull(turf_type))
turf_type = RESERVED_TURF_TYPE
@@ -43,6 +50,21 @@
allocated = FALSE
SSmapping.reservations -= src
// unegister from lookup
var/list/spatial_lookup = SSmapping.reservation_spatial_lookups[spatial_z]
var/spatial_width = ceil(world.maxx / TURF_CHUNK_RESOLUTION)
for(var/spatial_x in spatial_bl_x to spatial_tr_x)
for(var/spatial_y in spatial_bl_y to spatial_tr_y)
var/index = spatial_x + (spatial_y - 1) * spatial_width
if(spatial_lookup[index] != src)
stack_trace("index [index] wasn't self, what happened?")
continue
spatial_lookup[index] = null
spatial_bl_x = spatial_tr_x = spatial_bl_y = spatial_tr_y = spatial_z = null
return TRUE
/datum/turf_reservation/proc/reserve(width, height, z_override)
if(width > world.maxx || height > world.maxy || width < 1 || height < 1)
CRASH("invalid request")
@@ -58,26 +80,35 @@
var/list/turf/final
var/area/area_path = area_type
var/area/area_instance = initial(area_path.unique)? (GLOB.areas_by_type[area_path] || new area_path) : new area_path
var/found_a_spot = FALSE
var/how_many_wide = FLOOR(width / RESERVED_TURF_RESOLUTION, 1)
var/how_many_high = FLOOR(height / RESERVED_TURF_RESOLUTION, 1)
var/total_many_wide = FLOOR(world.maxx / RESERVED_TURF_RESOLUTION, 1)
var/total_many_high = FLOOR(world.maxy / RESERVED_TURF_RESOLUTION, 1)
var/how_many_wide = ceil(width / TURF_CHUNK_RESOLUTION)
var/how_many_high = ceil(height / TURF_CHUNK_RESOLUTION)
var/total_many_wide = floor(world.maxx / TURF_CHUNK_RESOLUTION)
var/total_many_high = floor(world.maxy / TURF_CHUNK_RESOLUTION)
// the dreaded 5 deep for loop
while((level_index = z_override) || (level_index = pick_n_take(possible_levels)))
/**
* here's the magic
* because reservations are aligned to RESERVED_TURF_RESOLUTION,
* because reservations are aligned to TURF_CHUNK_RESOLUTION,
* we just have to check the start spots, since we always align to them.
*
* bottom-right turfs on reservations align to 0 * RESERVED_TURF_RESOLUTION + 1, 1 * RESERVED_TURF_RESOLUTION + 1, 2 * RESERVED_TURF_RESOLUTION + 1, ...
* bottom-left turfs on reservations align to
* (chunk_x - 1) * TURF_CHUNK_RESOLUTION + 1
* (chunk_y - 1) * TURF_CHUNK_RESOLUTION + 1
*/
for(var/outer_x in 1 to (total_many_wide - how_many_wide + 1))
for(var/outer_y in 1 to (total_many_high - how_many_high + 1))
var/passing = TRUE
for(var/inner_x in outer_x to outer_x + how_many_wide - 1)
for(var/inner_y in outer_y to outer_y + how_many_high - 1)
var/turf/checking = locate(1 + RESERVED_TURF_RESOLUTION * (inner_x - 1), 1 + RESERVED_TURF_RESOLUTION * (inner_y - 1), level_index)
var/turf/checking = locate(
1 + (inner_x - 1) * TURF_CHUNK_RESOLUTION,
1 + (inner_y - 1) * TURF_CHUNK_RESOLUTION,
level_index,
)
if(!(checking.turf_flags & UNUSED_RESERVATION_TURF))
passing = FALSE
break
@@ -85,7 +116,7 @@
break
if(!passing)
continue
BL = locate(1 + RESERVED_TURF_RESOLUTION * (outer_x - 1), 1 + RESERVED_TURF_RESOLUTION * (outer_y - 1), level_index)
BL = locate(1 + TURF_CHUNK_RESOLUTION * (outer_x - 1), 1 + TURF_CHUNK_RESOLUTION * (outer_y - 1), level_index)
TR = locate(BL.x + width - 1, BL.y + height - 1, BL.z)
final = block(BL, TR)
found_a_spot = TRUE
@@ -116,4 +147,22 @@
allocated = TRUE
SSmapping.reservation_blocking_op = FALSE
SSmapping.reservations += src
// register in lookup
ASSERT(bottom_left_coords[3] == top_right_coords[3]) // just to make sure assumptions made at time of writing are still true
src.spatial_bl_x = ceil(bottom_left_coords[1] / TURF_CHUNK_RESOLUTION)
src.spatial_bl_y = ceil(bottom_left_coords[2] / TURF_CHUNK_RESOLUTION)
src.spatial_tr_x = ceil(top_right_coords[1] / TURF_CHUNK_RESOLUTION)
src.spatial_tr_y = ceil(top_right_coords[2] / TURF_CHUNK_RESOLUTION)
src.spatial_z = bottom_left_coords[3]
var/spatial_width = ceil(world.maxx / TURF_CHUNK_RESOLUTION)
var/list/spatial_lookup = SSmapping.reservation_spatial_lookups[spatial_z]
for(var/spatial_x in src.spatial_bl_x to src.spatial_tr_x)
for(var/spatial_y in src.spatial_bl_y to src.spatial_tr_y)
var/index = spatial_x + (spatial_y - 1) * spatial_width
if(spatial_lookup[index])
stack_trace("index [index] wasn't null, what happened?")
continue
spatial_lookup[index] = src
return TRUE