mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-23 08:46:57 +01:00
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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user