Makes space level removal and adding smooth

This commit is contained in:
Crazylemon64
2016-08-06 22:52:41 -07:00
parent f307ad7d30
commit 1180f9ddd4
4 changed files with 178 additions and 77 deletions
+24
View File
@@ -32,6 +32,7 @@
..()
var/datum/space_level/S = space_manager.get_zlev(z)
S.add_to_transit(src)
S.apply_transition(src)
/turf/space/proc/update_starlight()
if(!config.starlight)
@@ -209,3 +210,26 @@
/turf/space/can_have_cabling()
return 0
/turf/space/proc/set_transition_north(dest_z)
destination_x = x
destination_y = TRANSITIONEDGE + 2
destination_z = dest_z
/turf/space/proc/set_transition_south(dest_z)
destination_x = x
destination_y = world.maxy - TRANSITIONEDGE - 2
destination_z = dest_z
/turf/space/proc/set_transition_east(dest_z)
destination_x = TRANSITIONEDGE + 2
destination_y = y
destination_z = dest_z
/turf/space/proc/set_transition_west(dest_z)
destination_x = world.maxx - TRANSITIONEDGE - 2
destination_y = y
destination_z = dest_z
/turf/space/proc/remove_transitions()
destination_z = initial(destination_z)
+64 -9
View File
@@ -6,7 +6,9 @@
// Map transition stuff
var/list/neighbors = list()
// # How this level connects with others. See __MAP_DEFINES.dm for defines
var/linkage = SELFLOOPING
// It's UNAFFECTED by default because none of the space turfs are normally linked up
// so we don't need to rebuild transitions if an UNAFFECTED level is requested
var/linkage = UNAFFECTED
// # imaginary placements on the grid - these reflect the point it is linked to
var/xi
var/yi
@@ -21,15 +23,35 @@
/datum/space_level/New(z, name, transition_type = SELFLOOPING)
zpos = z
set_linkage(transition_type)
build_space_destination_arrays()
set_linkage(transition_type)
/datum/space_level/Destroy()
if(linkage == CROSSLINKED)
if(space_manager.linkage_map)
remove_from_space_network(space_manager.linkage_map)
space_manager.unbuilt_space_transitions -= src
space_manager.z_list -= "[zpos]"
return ..()
/datum/space_level/proc/build_space_destination_arrays()
var/timer = start_watch()
log_debug("Starting to build space destination arrays for z level '[zpos]'...")
for(var/turf/space/S in get_turfs())
add_to_transit(S)
log_debug("Building space destination arrays complete, took [stop_watch(timer)]s.")
// We skip `add_to_transit` here because we want to skip the checks in order to save time
// Bottom border
for(var/turf/space/S in block(locate(1,1,zpos),locate(world.maxx,TRANSITIONEDGE+1,zpos)))
transit_south |= S
// Top border
for(var/turf/space/S in block(locate(1,world.maxy,zpos),locate(world.maxx,world.maxy - TRANSITIONEDGE - 1,zpos)))
transit_north |= S
// Left border
for(var/turf/space/S in block(locate(1,TRANSITIONEDGE+1,zpos),locate(TRANSITIONEDGE+1,world.maxy - TRANSITIONEDGE - 2,zpos)))
transit_west |= S
// Right border
for(var/turf/space/S in block(locate(world.maxx - TRANSITIONEDGE - 1,TRANSITIONEDGE+1,zpos),locate(world.maxx,world.maxy - TRANSITIONEDGE - 2,zpos)))
transit_east |= S
/datum/space_level/proc/add_to_transit(turf/space/S)
if(S.y <= TRANSITIONEDGE)
@@ -69,13 +91,46 @@
if(S.x >= (world.maxx - TRANSITIONEDGE - 1))
transit_east -= S
/datum/space_level/proc/apply_transition(turf/space/S)
if(src in space_manager.unbuilt_space_transitions)
return // Let the space manager handle this one
switch(linkage)
if(UNAFFECTED)
S.remove_transitions()
if(SELFLOOPING,CROSSLINKED)
var/datum/space_level/E = get_connection()
if(S in transit_north)
E = get_connection("[NORTH]")
S.set_transition_north(E.zpos)
if(S in transit_south)
E = get_connection("[SOUTH]")
S.set_transition_south(E.zpos)
if(S in transit_east)
E = get_connection("[EAST]")
S.set_transition_east(E.zpos)
if(S in transit_west)
E = get_connection("[WEST]")
S.set_transition_west(E.zpos)
/datum/space_level/proc/get_turfs()
return block(locate(1, 1, zpos), locate(world.maxx, world.maxy, zpos))
/datum/space_level/proc/set_linkage(transition_type)
if(linkage == transition_type)
return
// Remove ourselves from the linkage map if we were cross-linked
if(linkage == CROSSLINKED)
if(space_manager.linkage_map)
remove_from_space_network(space_manager.linkage_map)
space_manager.unbuilt_space_transitions |= src
linkage = transition_type
if(transition_type == SELFLOOPING)
link_to_self() // `link_to_self` is defined in space_transitions.dm
switch(transition_type)
if(UNAFFECTED)
reset_connections()
if(SELFLOOPING)
link_to_self() // `link_to_self` is defined in space_transitions.dm
/datum/space_level/proc/resume_init()
@@ -16,8 +16,10 @@
if(Z_LEVEL_WEST)
return Z_LEVEL_EAST
/datum/space_level
var/list/direction_cache = list()
// Do this before setting up new connections, or the old ones will haunt you
/datum/space_level/proc/reset_connections()
neighbors.Cut()
/datum/space_level/proc/link_to_self()
neighbors = list()
@@ -25,6 +27,24 @@
for(var/A in L)
neighbors[A] = src
// Only call this when the `linkage_map` is already built
/datum/space_level/proc/add_to_space_network(datum/spacewalk_grid/SW)
// Make sure we don't bring any noise data into the network
reset_connections()
xi = initial(xi)
yi = initial(yi)
var/datum/point/P = SW.get_empty_node()
P.set_space_level(src)
/datum/space_level/proc/remove_from_space_network(datum/spacewalk_grid/SW)
var/datum/point/P = SW.get(xi,yi)
SW.release_node(P)
// Only do this when we're done, or we'll trample vars needed for releasing
// the level
xi = initial(xi)
yi = initial(yi)
reset_connections()
// This proc takes another space level, and establishes a connection between the
// two depending on how the `xi` and the `yi` values compare
/datum/space_level/proc/link_levels(datum/space_level/S)
@@ -41,26 +61,18 @@
else // yell about evil wizards, this shouldn't happen
log_debug("Two z levels attempted to link, but were not adjacent! Our z:([xi],[yi]). Other z:([S.xi],[S.yi])")
// Do this before setting up new connections, or the old ones will haunt you
/datum/space_level/proc/reset_connections()
neighbors.Cut()
direction_cache.Cut()
// `direction` here is the direction from `src` to `S`
/datum/space_level/proc/add_connection(datum/space_level/S, direction)
var/oppose = get_opposite_direction(direction)
neighbors[direction] = S
S.neighbors[oppose] = src
space_manager.unbuilt_space_transitions |= src
space_manager.unbuilt_space_transitions |= S
// The "direction cache" will need updating if a
/datum/space_level/proc/get_connection(direction)
if(direction in neighbors)
return neighbors[direction]
var/use_direction_cache = 0
if(use_direction_cache)
if(direction in direction_cache)
return direction_cache[direction]
// It's in a direction that loops - so we step as far in the opposite direction to get where to wrap to
var/datum/space_level/S = src
@@ -70,9 +82,6 @@
if(S.neighbors[oppose] == src) // we've got a tesseract, boys
CRASH("Tesseract formed when routing connections between z levels. Culprit: z level '[S.zpos]' to '[src.zpos]', direction [oppose]")
S = S.neighbors[oppose]
if(use_direction_cache)
direction_cache[direction] = S
return S
@@ -145,8 +154,6 @@
// This looks around itself to see if it has any active nodes within the cardinal directions
/datum/point/proc/has_no_neighbors(datum/spacewalk_grid/SW)
var/result = 1
if(spl)
return 1
if(!isnull(SW.get(x+1,y)))
result = 0
if(!isnull(SW.get(x-1,y)))
@@ -165,6 +172,7 @@
var/datum/space_level/S = spl.neighbors[direction]
var/oppose = get_opposite_direction(direction)
S.neighbors.Remove(oppose)
space_manager.unbuilt_space_transitions |= S
spl.reset_connections()
spl = initial(spl)
@@ -191,6 +199,14 @@
var/datum/point/P = new(0,0)
add_available_node(P)
/datum/spacewalk_grid/Destroy()
for(var/datum/point/P in filled_nodes)
release_node(P)
if(available_nodes.len > 1)
log_debug("Multiple nodes left behind after SW grid qdel: [available_nodes.len]")
for(var/datum/point/P in available_nodes)
log_debug("([P.x],[P.y])")
/datum/spacewalk_grid/proc/add_available_node(datum/point/P)
var/hash = P.hash()
if(hash in all_nodes)
@@ -225,9 +241,12 @@
for(var/datum/point/P2 in P.neighbors)
var/isolated = P2.has_no_neighbors(src)
if(isolated)
available_nodes -= P2
all_nodes -= P2.hash()
qdel(P)
if(!P2.spl)
available_nodes -= P2
all_nodes -= P2.hash()
qdel(P)
else
log_debug("Isolated z level at ([P2.x],[P2.y]): [P2.spl.zpos]")
P.deactivate()
P.neighbors.Cut()
@@ -307,75 +326,75 @@
// `grid` is a flat list of these same above points
// Each point represents a possible z level position
var/datum/spacewalk_grid/point_grid = new
// We do this so we can display the way the levels connect later
linkage_map = point_grid
var/datum/point/P
if(linkage_map)
qdel(linkage_map)
linkage_map = new
// Now, we pop entries in a random order from our list of space levels
// and assign its connections based on the grid
while(crosslinks.len)
D = pick(crosslinks)
crosslinks.Remove(D)
// We now choose a point in our imaginary grid adjacent to our current location
P = point_grid.get_empty_node()
// Let our z level know where in the imaginary grid it is
// This will also handle establishing neighborship with other z levels
P.set_space_level(D)
// Add it to our space grid
D.add_to_space_network(linkage_map)
// A heavy proc - loops through all space turfs and sets its destination
// based on its space level's linkage
// Takes 0.6 seconds per call on my machine - could have each z level
// have its own space turf cache, but I don't want to complicate this more
// than is necessary
/datum/zlev_manager/proc/setup_space_destinations()
// Used to loop through turfs in world, now just goes through each level's
// transit turf cache
/datum/zlev_manager/proc/setup_space_destinations(force_all_rebuilds = FALSE)
var/timer = start_watch()
log_debug("Assigning space turf destinations...")
var/datum/space_level/D
var/datum/space_level/E
var/turf/space/S
for(var/A in z_list) //Define the transistions of the z levels
D = z_list[A]
if(!D.neighbors.len)
continue
// Left border
for(var/B in D.transit_west)
S = B
E = D.get_connection(Z_LEVEL_WEST)
S.destination_z = E.zpos
S.destination_x = world.maxx - TRANSITIONEDGE - 2
S.destination_y = S.y
var/list/levels_to_rebuild = unbuilt_space_transitions
// Right border
for(var/B in D.transit_east)
S = B
E = D.get_connection(Z_LEVEL_EAST)
S.destination_x = TRANSITIONEDGE + 2
S.destination_y = S.y
S.destination_z = E.zpos
if(force_all_rebuilds)
// Assuming we don't have like 9000 zlevels this shouldn't hurt
levels_to_rebuild = list()
for(var/A in z_list)
levels_to_rebuild.Add(z_list[A])
// Bottom border
for(var/B in D.transit_south)
S = B
E = D.get_connection(Z_LEVEL_SOUTH)
S.destination_x = S.x
S.destination_y = world.maxy - TRANSITIONEDGE - 2
S.destination_z = E.zpos
// Top border
for(var/B in D.transit_north)
S = B
E = D.get_connection(Z_LEVEL_NORTH)
S.destination_x = S.x
S.destination_y = TRANSITIONEDGE + 2
S.destination_z = E.zpos
for(var/foo in levels_to_rebuild) //Define the transitions of the z levels
D = foo
log_debug("Z level [D.zpos]")
switch(D.linkage)
if(UNAFFECTED)
for(var/B in D.transit_west | D.transit_east | D.transit_south | D.transit_north)
S = B
S.remove_transitions()
if(SELFLOOPING,CROSSLINKED)
// Left border
for(var/B in D.transit_west)
S = B
E = D.get_connection(Z_LEVEL_WEST)
S.set_transition_west(E.zpos)
// Right border
for(var/B in D.transit_east)
S = B
E = D.get_connection(Z_LEVEL_EAST)
S.set_transition_east(E.zpos)
// Bottom border
for(var/B in D.transit_south)
S = B
E = D.get_connection(Z_LEVEL_SOUTH)
S.set_transition_south(E.zpos)
// Top border
for(var/B in D.transit_north)
S = B
E = D.get_connection(Z_LEVEL_NORTH)
S.set_transition_north(E.zpos)
unbuilt_space_transitions -= D
log_debug("Assigning space turf destinations complete. Took [stop_watch(timer)]s.")
// Nothing fancy, just does it all at once
/datum/zlev_manager/proc/do_transition_setup()
route_linkage()
setup_space_destinations()
setup_space_destinations(force_all_rebuilds = TRUE)
// A debugging proc that expresses the map's shape as a bunch of turfs
/datum/zlev_manager/proc/map_as_turfs(turf/center)
@@ -5,6 +5,9 @@ var/global/datum/zlev_manager/space_manager = new
var/list/z_list = list()
var/list/heaps = list()
// Levels that need their transitions rebuilt
var/list/unbuilt_space_transitions = list()
var/datum/spacewalk_grid/linkage_map
// Populate our space level list