mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-07-21 12:04:48 +01:00
Merge pull request #6675 from Crazylemon64/monster_allocator_port
Ports Monster's finishing of the space allocator
This commit is contained in:
@@ -1,15 +1,62 @@
|
||||
// This represents a level we can carve up as we please, and hand out
|
||||
// chunks of to whatever requests it
|
||||
/datum/space_level/heap
|
||||
var/datum/space_chunk/top
|
||||
linkage = UNAFFECTED
|
||||
name = "Heap level #ERROR"
|
||||
var/datum/space_chunk/top
|
||||
linkage = UNAFFECTED
|
||||
|
||||
/datum/space_level/heap/New()
|
||||
..()
|
||||
top = new
|
||||
/datum/space_level/heap/New(z, name, transition_type, traits)
|
||||
..(z, "Heap level #[z]", UNAFFECTED, traits)
|
||||
top = new(1, 1, zpos, world.maxx, world.maxy)
|
||||
flags = traits
|
||||
|
||||
/datum/space_level/heap/proc/request(width, height)
|
||||
return 1 // All are welcome! At least until I add code for this
|
||||
return top.can_fit_space(width, height)
|
||||
|
||||
/datum/zlevel/heap/proc/allocate(width, height)
|
||||
return
|
||||
// Returns a space chunk datum for some nerd to work with - tells them what's safe to write into, and such
|
||||
/datum/space_level/heap/proc/allocate(width, height)
|
||||
if(!request(width, height))
|
||||
return null
|
||||
|
||||
var/datum/space_chunk/C = top.get_optimal_chunk(width, height)
|
||||
if(!C)
|
||||
return null
|
||||
C.children.Cut()
|
||||
|
||||
if(C.width == width && C.height == height && C.is_empty)
|
||||
C.set_occupied(TRUE)
|
||||
return C
|
||||
|
||||
// Split the chunk into 4 pieces
|
||||
var/datum/space_chunk/return_chunk = new(C.x, C.y, C.zpos, width, height)
|
||||
C.children += return_chunk
|
||||
C.children += new /datum/space_chunk(C.x+width, C.y, C.zpos, C.width-width, height)
|
||||
C.children += new /datum/space_chunk(C.x, C.y+height, C.zpos, width, C.height-height)
|
||||
C.children += new /datum/space_chunk(C.x+width, C.y+height, C.zpos, C.width-width, C.height-height)
|
||||
|
||||
for(var/datum/space_chunk/C2 in C.children)
|
||||
C2.parent = C
|
||||
return_chunk.set_occupied(TRUE)
|
||||
return return_chunk
|
||||
|
||||
/datum/space_level/heap/proc/free(datum/space_chunk/C)
|
||||
if(!istype(C))
|
||||
return
|
||||
if(C.zpos != zpos)
|
||||
return
|
||||
C.set_occupied(FALSE)
|
||||
for(var/turf/T in block(locate(C.x, C.y, C.zpos), locate(C.x+C.width-1, C.y+C.height-1, C.zpos)))
|
||||
for(var/atom/movable/M in T)
|
||||
if(istype(M, /mob/dead/observer))
|
||||
continue
|
||||
M.loc = null
|
||||
qdel(M, TRUE)
|
||||
T.ChangeTurf(/turf/space)
|
||||
var/datum/space_chunk/last_empty_parent = C
|
||||
while(last_empty_parent.parent && last_empty_parent.parent.is_empty)
|
||||
last_empty_parent = last_empty_parent.parent
|
||||
// Prevent a self-qdel from killing this proc
|
||||
src = null
|
||||
for(var/datum/space_chunk/child in last_empty_parent.children)
|
||||
qdel(child)
|
||||
last_empty_parent.children.Cut()
|
||||
|
||||
@@ -10,14 +10,81 @@
|
||||
var/width
|
||||
var/height
|
||||
var/zpos
|
||||
// Whether dedicated for use or not
|
||||
var/occupied = FALSE
|
||||
// Whether the chunk contains used children or not
|
||||
var/is_empty = TRUE
|
||||
var/list/children = list()
|
||||
var/datum/space_chunk/parent = null
|
||||
|
||||
/datum/space_chunk/New(w, h, z, new_x, new_y)
|
||||
/datum/space_chunk/New(new_x, new_y, z, w, h)
|
||||
x = new_x
|
||||
y = new_y
|
||||
zpos = z
|
||||
width = w
|
||||
height = h
|
||||
|
||||
/datum/space_chunk/Destroy()
|
||||
set_occupied(FALSE)
|
||||
if(parent)
|
||||
parent.children -= src
|
||||
for(var/datum/space_chunk/child in children)
|
||||
qdel(child)
|
||||
children.Cut()
|
||||
parent = null
|
||||
. = ..()
|
||||
|
||||
/datum/space_chunk/proc/can_fit_space(w, h)
|
||||
if(w > width || h > height)
|
||||
return FALSE
|
||||
if(occupied)
|
||||
return FALSE
|
||||
if(is_empty)
|
||||
return TRUE
|
||||
for(var/datum/space_chunk/C in children)
|
||||
if(C.can_fit_space(w, h))
|
||||
return TRUE
|
||||
return FALSE
|
||||
|
||||
// Recursively drops down the tree and finds the most efficient chunk to use
|
||||
/datum/space_chunk/proc/get_optimal_chunk(w, h)
|
||||
if(w > width || h > height)
|
||||
return null
|
||||
if(occupied)
|
||||
return null
|
||||
if(is_empty)
|
||||
return src
|
||||
var/datum/space_chunk/optimal_chunk
|
||||
var/optimal_chunk_optimalness = 99999
|
||||
for(var/datum/space_chunk/C in children)
|
||||
var/datum/space_chunk/C2 = C.get_optimal_chunk(w, h)
|
||||
if(!C2)
|
||||
continue
|
||||
var/optimalness = C2.width + C2.height-w-h
|
||||
if(optimalness < optimal_chunk_optimalness)
|
||||
optimal_chunk_optimalness = optimalness
|
||||
optimal_chunk = C2
|
||||
return optimal_chunk
|
||||
|
||||
/datum/space_chunk/proc/set_occupied(new_occupied)
|
||||
var/datum/space_chunk/C = parent
|
||||
if(new_occupied)
|
||||
occupied = TRUE
|
||||
while(C)
|
||||
C.is_empty = FALSE
|
||||
C = C.parent
|
||||
else
|
||||
occupied = FALSE
|
||||
while(C)
|
||||
var/is_children_empty = TRUE
|
||||
for(var/datum/space_chunk/C2 in C.children)
|
||||
if(!C2.is_empty || C2.occupied)
|
||||
is_children_empty = FALSE
|
||||
if(!is_children_empty)
|
||||
break
|
||||
C.is_empty = TRUE
|
||||
C = C.parent
|
||||
|
||||
/datum/space_chunk/proc/check_sanity()
|
||||
var/i_am_sane = 1
|
||||
i_am_sane |= (x > 0)
|
||||
|
||||
@@ -134,18 +134,36 @@ var/global/datum/zlev_manager/space_manager = new
|
||||
/datum/zlev_manager/proc/add_new_heap()
|
||||
world.maxz++
|
||||
var/our_z = world.maxz
|
||||
var/datum/space_level/yup = new /datum/space_level/heap(our_z)
|
||||
var/datum/space_level/yup = new /datum/space_level/heap(our_z, traits = list(BLOCK_TELEPORT, ADMIN_LEVEL))
|
||||
z_list["[our_z]"] = yup
|
||||
return yup
|
||||
|
||||
// This is what you can call to allocate a section of space
|
||||
// Later, I'll add an argument to let you define the flags on the region
|
||||
/datum/zlev_manager/proc/allocate_space(width, height)
|
||||
if(width > world.maxx || height > world.maxy)
|
||||
throw EXCEPTION("Too much space requested! \[[width],[height]\]")
|
||||
if(!heaps.len)
|
||||
heaps.len++
|
||||
heaps[heaps.len] = add_new_heap()
|
||||
var/datum/space_level/heap/our_heap
|
||||
var/weve_got_vacancy = 0
|
||||
for(our_heap in heaps)
|
||||
var/weve_got_vacancy = our_heap.request(width, height)
|
||||
weve_got_vacancy = our_heap.request(width, height)
|
||||
if(weve_got_vacancy)
|
||||
break // We're sticking with the present value of `our_heap` - it's got room
|
||||
// This loop will also run out if no vacancies are found
|
||||
|
||||
if(!weve_got_vacancy)
|
||||
heaps.len++
|
||||
our_heap = add_new_heap()
|
||||
heaps[heaps.len] = our_heap
|
||||
return our_heap.allocate(width, height)
|
||||
|
||||
/datum/zlev_manager/proc/free_space(datum/space_chunk/C)
|
||||
if(!istype(C))
|
||||
return
|
||||
var/datum/space_level/heap/heap = z_list["[C.zpos]"]
|
||||
if(!istype(heap))
|
||||
throw EXCEPTION("Attempted to free chunk at invalid z-level ([C.x],[C.y],[C.zpos]) [C.width]x[C.height]")
|
||||
heap.free(C)
|
||||
|
||||
Reference in New Issue
Block a user