diff --git a/citadel.dme b/citadel.dme
index 5ebc2fc7c5ac..afc15ac13484 100644
--- a/citadel.dme
+++ b/citadel.dme
@@ -611,28 +611,27 @@
#include "code\controllers\subsystem\job\joining.dm"
#include "code\controllers\subsystem\job\roundstart.dm"
#include "code\controllers\subsystem\job\spawnpoints.dm"
-#include "code\controllers\subsystem\mapping\_mapping.dm"
-#include "code\controllers\subsystem\mapping\allocation.dm"
-#include "code\controllers\subsystem\mapping\boot.dm"
-#include "code\controllers\subsystem\mapping\levels.dm"
-#include "code\controllers\subsystem\mapping\maps.dm"
-#include "code\controllers\subsystem\mapping\misc.dm"
-#include "code\controllers\subsystem\mapping\obfuscation.dm"
-#include "code\controllers\subsystem\mapping\reservations.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\air.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\attributes.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\baseturf.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\linkage.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\lookup.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\structs.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\traits.dm"
-#include "code\controllers\subsystem\mapping\level_helpers\virtualization.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\angle.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\dir.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\distance.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\loc.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\stack.dm"
-#include "code\controllers\subsystem\mapping\spatial_helpers\step.dm"
+#include "code\controllers\subsystem\mapping\mapping-allocation.dm"
+#include "code\controllers\subsystem\mapping\mapping-boot.dm"
+#include "code\controllers\subsystem\mapping\mapping-levels.dm"
+#include "code\controllers\subsystem\mapping\mapping-maps.dm"
+#include "code\controllers\subsystem\mapping\mapping-misc.dm"
+#include "code\controllers\subsystem\mapping\mapping-obfuscation.dm"
+#include "code\controllers\subsystem\mapping\mapping-reservations.dm"
+#include "code\controllers\subsystem\mapping\mapping.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-air.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-attributes.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-baseturf.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-lookup.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-structs.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-traits.dm"
+#include "code\controllers\subsystem\mapping\level\mapping-level-virtualization.dm"
+#include "code\controllers\subsystem\mapping\spatial\mapping-spatial-stack.dm"
+#include "code\controllers\subsystem\mapping\virtual\mapping-virtual-angle.dm"
+#include "code\controllers\subsystem\mapping\virtual\mapping-virtual-coords.dm"
+#include "code\controllers\subsystem\mapping\virtual\mapping-virtual-dir.dm"
+#include "code\controllers\subsystem\mapping\virtual\mapping-virtual-step.dm"
+#include "code\controllers\subsystem\mapping\virtual\mapping-vritual-dist.dm"
#include "code\controllers\subsystem\networks\_networks.dm"
#include "code\controllers\subsystem\networks\simple.dm"
#include "code\controllers\subsystem\persistence\bunker.dm"
@@ -2118,6 +2117,7 @@
#include "code\modules\admin\callproc\callproc.dm"
#include "code\modules\admin\DB ban\functions.dm"
#include "code\modules\admin\functions\modify_traits.dm"
+#include "code\modules\admin\modals\upload_map_sector.dm"
#include "code\modules\admin\permissionverbs\permissionedit.dm"
#include "code\modules\admin\secrets\admin_secrets\admin_logs.dm"
#include "code\modules\admin\secrets\admin_secrets\alter_narsie.dm"
diff --git a/code/controllers/subsystem/mapping/_mapping.dm b/code/controllers/subsystem/mapping/_mapping.dm
deleted file mode 100644
index eabccb9b489d..000000000000
--- a/code/controllers/subsystem/mapping/_mapping.dm
+++ /dev/null
@@ -1,78 +0,0 @@
-#define INIT_ANNOUNCE(X) to_chat(world, "[X]"); log_world(X)
-
-GLOBAL_VAR_INIT(used_engine, "None")
-// Handles map-related tasks, mostly here to ensure it does so after the MC initializes.
-SUBSYSTEM_DEF(mapping)
- name = "Mapping"
- init_order = INIT_ORDER_MAPPING
- subsystem_flags = SS_NO_FIRE
-
- /// global mutex for ensuring two map/level load ops don't go at once
- /// a separate mutex is used at the actual maploader level
- /// this ensures we aren't shoving maps in during map init, as that can be both laggy and/or bad to legacy code that
- /// expect zlevel adjacency.
- var/load_mutex = FALSE
-
- // todo: this is going to need a lot more documentation
- // the idea of a single zlevel for areas is sorta flawed
- // this is an acceptable lazy lookup but we need to standardize what this means / look at how this is generated.
- var/list/areas_in_z = list()
-
-/datum/controller/subsystem/mapping/Initialize(timeofday)
- // load data
- // todo: refactor
- load_map_templates()
- // todo: refactor
- preloadShelterTemplates()
-
- // init obfuscation
- init_obfuscation_data()
- // init maps
- init_maps()
- // load the map to use
- read_next_map()
-
- // load world - this also initializes our first reserved level, which is compiled in.
- load_station()
-
- // todo: refactor - Set up antagonists.
- populate_antag_type_list()
- // todo: refactor - Set up spawn points.
- populate_spawn_points()
-
- // finalize
- // todo: refactor
- repopulate_sorted_areas()
-
- return ..()
-
-//
-// Mapping subsystem handles initialization of random map elements at server start
-// For us that means loading our random roundstart engine!
-//
-/datum/controller/subsystem/mapping
- var/list/map_templates = list()
- var/list/shelter_templates = list()
-
-/datum/controller/subsystem/mapping/Recover()
- subsystem_flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
- shelter_templates = SSmapping.shelter_templates
-
-/datum/controller/subsystem/mapping/proc/load_map_templates()
- for(var/T in subtypesof(/datum/map_template))
- var/datum/map_template/template = T
- template = new T
- if(!template.map_path)
- qdel(template)
- continue
- map_templates[template.name] = template
- return TRUE
-
-/datum/controller/subsystem/mapping/proc/preloadShelterTemplates()
- for(var/item in subtypesof(/datum/map_template/shelter))
- var/datum/map_template/shelter/shelter_type = item
- if(!(initial(shelter_type.map_path)))
- continue
- var/datum/map_template/shelter/S = new shelter_type()
-
- shelter_templates[S.shelter_id] = S
diff --git a/code/controllers/subsystem/mapping/level_helpers/air.dm b/code/controllers/subsystem/mapping/level/mapping-level-air.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/air.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-air.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/attributes.dm b/code/controllers/subsystem/mapping/level/mapping-level-attributes.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/attributes.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-attributes.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/baseturf.dm b/code/controllers/subsystem/mapping/level/mapping-level-baseturf.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/baseturf.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-baseturf.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/lookup.dm b/code/controllers/subsystem/mapping/level/mapping-level-lookup.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/lookup.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-lookup.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/structs.dm b/code/controllers/subsystem/mapping/level/mapping-level-structs.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/structs.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-structs.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/traits.dm b/code/controllers/subsystem/mapping/level/mapping-level-traits.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/traits.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-traits.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/virtualization.dm b/code/controllers/subsystem/mapping/level/mapping-level-virtualization.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/level_helpers/virtualization.dm
rename to code/controllers/subsystem/mapping/level/mapping-level-virtualization.dm
diff --git a/code/controllers/subsystem/mapping/level_helpers/linkage.dm b/code/controllers/subsystem/mapping/level_helpers/linkage.dm
deleted file mode 100644
index 79b8d97723db..000000000000
--- a/code/controllers/subsystem/mapping/level_helpers/linkage.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-//* This file is explicitly licensed under the MIT license. *//
-//* Copyright (c) 2023 Citadel Station developers. *//
-
-/**
- * Returns all crosslinked z indices
- */
-/datum/controller/subsystem/mapping/proc/crosslinked_levels()
- RETURN_TYPE(/list)
- return list()
- // todo: crosslink support
- // . = list()
- // for(var/datum/map_level/L as anything in ordered_levels)
- // if(L.linkage == Z_LINKAGE_CROSSLINKED)
- // . += L.z_index
diff --git a/code/controllers/subsystem/mapping/allocation.dm b/code/controllers/subsystem/mapping/mapping-allocation.dm
similarity index 78%
rename from code/controllers/subsystem/mapping/allocation.dm
rename to code/controllers/subsystem/mapping/mapping-allocation.dm
index af4adad50094..499a910b1af9 100644
--- a/code/controllers/subsystem/mapping/allocation.dm
+++ b/code/controllers/subsystem/mapping/mapping-allocation.dm
@@ -15,18 +15,10 @@
* I do not recommend anyone use this unless they absolutely know what they're doing.
* (if you think you need this, you probably don't, to be blunt.)
*/
-/datum/controller/subsystem/mapping
- // list of levels ready for reuse
- var/static/list/reusable_levels = list()
-// todo: recover()
+// todo: add this module to recover()
// todo: zclear system will be in this later, for now, this is just a wrapper
-/datum/controller/subsystem/mapping/on_max_z_changed(old_z_count, new_z_count)
- . = ..()
- // just to make sure order of ops / assumptions are right
- ASSERT(length(ordered_levels) == world.maxz)
-
/**
* gets an reusable level, or increments world.maxz
* WARNING: AFTER THIS, YOU NEED TO USE THE LEVEL, OR READD TO REUSABLE, OR THIS IS A MEMORY LEAK!
diff --git a/code/controllers/subsystem/mapping/boot.dm b/code/controllers/subsystem/mapping/mapping-boot.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/boot.dm
rename to code/controllers/subsystem/mapping/mapping-boot.dm
diff --git a/code/controllers/subsystem/mapping/levels.dm b/code/controllers/subsystem/mapping/mapping-levels.dm
similarity index 87%
rename from code/controllers/subsystem/mapping/levels.dm
rename to code/controllers/subsystem/mapping/mapping-levels.dm
index 7bc62959a813..4642aa155513 100644
--- a/code/controllers/subsystem/mapping/levels.dm
+++ b/code/controllers/subsystem/mapping/mapping-levels.dm
@@ -6,49 +6,6 @@
*
* All adds/removes should go through this. Directly modifying zlevel amount/whatever is forbidden.
*/
-/datum/controller/subsystem/mapping
- //* level lookups
- /// indexed level datums
- var/static/list/datum/map_level/ordered_levels = list()
- /// k-v id to level datum lookup
- var/static/list/datum/map_level/keyed_levels = list()
- /// typepath to level datum lookup
- /// we do that because we automatically generate level ids
- /// so we can't use initial(id)
- var/static/list/datum/map_level/typed_levels = list()
-
- //* level fluff lookups
- /// literally just a random hexadecimal store to prevent collision
- var/static/list/random_fluff_level_hashes = list()
-
- //* multiz core
- /// Ordered lookup list for multiz up
- var/list/cached_level_up
- /// Ordered lookup list for multiz down
- var/list/cached_level_down
- /// Ordered lookup list for east transition
- var/list/cached_level_east
- /// Ordered lookup list for west transition
- var/list/cached_level_west
- /// Ordered lookup list for north transition
- var/list/cached_level_north
- /// Ordered lookup list for south transition
- var/list/cached_level_south
- /// Z access lookup - z = list() of zlevels it can directly access vertically
- /// * For performance, this is currently only including bidirectional links
- /// * For performance, this does not support looping.
- /// * This is a direct stack lookup. This does not take map_struct's into account.
- /// * You should only be using this for technical use cases like z-rendering and whatnot,
- /// for fluff this is not sufficient to determine if something is actually above/below if it's not actually connected.
- var/list/z_stack_lookup
- /// does z stack lookup need a rebuild?
- var/z_stack_dirty = TRUE
-
- //* struct system
- /// Active world_structs
- var/static/list/datum/map_struct/structs = list()
- /// World struct lookup by level
- var/static/list/datum/map_struct/struct_by_z = list()
//* Rebuilds / Caching
@@ -69,7 +26,6 @@
SYNC(cached_level_north)
SYNC(cached_level_south)
SYNC(z_stack_lookup)
- SYNC(struct_by_z)
z_stack_dirty = FALSE
if(.)
z_stack_dirty = TRUE
@@ -446,12 +402,6 @@
z_stack_lookup.len = world.maxz
var/list/left = list()
for(var/z in 1 to world.maxz)
- // todo: stacks
- // if(struct_by_z[z])
- // var/datum/world_struct/struct = struct_by_z[z]
- // z_stack_lookup[z] = struct.stack_lookup[struct.real_indices.Find(z)]
- // else
- // left += z
left += z
var/list/datum/map_level/bottoms = list()
// let's sing the bottom song
@@ -500,9 +450,5 @@
var/datum/map_level/level = ordered_levels[z]
level.link_above = null
level.link_below = null
- // if(struct_by_z[z])
- // var/datum/world_struct/struct = struct_by_z[z]
- // struct.Deconstruct()
- // qdel(struct)
stack_trace("WARNING: Up/Down loops found in zlevels [english_list(loops)]. This is not allowed and will cause both falling and zcopy to infinitely loop. All zlevels involved have been disconnected, and any structs involved have been destroyed.")
rebuild_verticality()
diff --git a/code/controllers/subsystem/mapping/maps.dm b/code/controllers/subsystem/mapping/mapping-maps.dm
similarity index 95%
rename from code/controllers/subsystem/mapping/maps.dm
rename to code/controllers/subsystem/mapping/mapping-maps.dm
index 4f069765e0e4..b6a7b93f378f 100644
--- a/code/controllers/subsystem/mapping/maps.dm
+++ b/code/controllers/subsystem/mapping/mapping-maps.dm
@@ -6,21 +6,6 @@
*
* Allows dynamic loading of clusters of zlevels (maps) and the initialization of the server with a single station map.
*/
-/datum/controller/subsystem/mapping
- /// station is loaded
- var/world_is_loaded = FALSE
- /// loaded station map
- var/static/datum/map/station/loaded_station
- /// next station map
- var/datum/map/station/next_station
- /// loaded maps
- var/static/list/datum/map/loaded_maps = list()
- /// available maps - k-v lookup by id
- var/list/datum/map/keyed_maps
-
-/datum/controller/subsystem/mapping/Shutdown()
- . = ..()
- write_next_map()
/**
* initializes the key-value store of map datums.
diff --git a/code/controllers/subsystem/mapping/misc.dm b/code/controllers/subsystem/mapping/mapping-misc.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/misc.dm
rename to code/controllers/subsystem/mapping/mapping-misc.dm
diff --git a/code/controllers/subsystem/mapping/obfuscation.dm b/code/controllers/subsystem/mapping/mapping-obfuscation.dm
similarity index 92%
rename from code/controllers/subsystem/mapping/obfuscation.dm
rename to code/controllers/subsystem/mapping/mapping-obfuscation.dm
index 192d67ada016..ca1025c340a8 100644
--- a/code/controllers/subsystem/mapping/obfuscation.dm
+++ b/code/controllers/subsystem/mapping/mapping-obfuscation.dm
@@ -14,18 +14,6 @@
* * It is usually already too late by the time Initialize() fires.
* * By default, /datum/map (not /datum/map_level), /datum/map_template, /datum/shuttle_template are the three things that form new mangling boundaries/contexts.
*/
-/datum/controller/subsystem/mapping
- /// used to ensure global-ness
- // todo: should this be here? this is used literally everywhere
- var/static/round_global_descriptor
- /// round-local hash storage for specific map ids
- var/static/round_local_mangling_cache = list()
- /// round-local hash storage for specific map ids, reverse lookup
- var/static/round_local_mangling_reverse_cache = list()
- /// round-local hash storage for obfuscated ids
- var/static/round_local_obfuscation_cache = list()
- /// round-local hash storage for obfuscated ids, reverse lookup
- var/static/round_local_obfuscation_reverse_cache = list()
/**
* Called at init first thing to setup mangling data
diff --git a/code/controllers/subsystem/mapping/reservations.dm b/code/controllers/subsystem/mapping/mapping-reservations.dm
similarity index 68%
rename from code/controllers/subsystem/mapping/reservations.dm
rename to code/controllers/subsystem/mapping/mapping-reservations.dm
index cd329e039ca7..dab44afaa6bd 100644
--- a/code/controllers/subsystem/mapping/reservations.dm
+++ b/code/controllers/subsystem/mapping/mapping-reservations.dm
@@ -4,39 +4,6 @@
/**
* turf reservation system
*/
-/datum/controller/subsystem/mapping
- /// reserved levels allocated
- var/static/reserved_level_count = 0
- /// reserved turfs allowed - we can over-allocate this if we're only going to be slightly over and can always allocate atleast one level.
- var/static/reserved_turfs_max = 192 * 192 * 3
- /// allocated space reservations
- var/static/list/datum/turf_reservation/reservations = list()
- /// list of reserved z-indices for fast access
- var/static/list/reserve_levels = list()
- /// doing some blocking op on reservation system
- var/static/reservation_blocking_op = FALSE
- /// singleton area holding all free reservation turfs
- var/static/area/reservation_unused/reservation_unallocated_area = new
- /// spatial grid of turf reservations. the owner of a chunk is the bottom left tile's owner.
- ///
- /// this is a list with length of world.maxz, with the actual spatial grid list being at the index of the z
- /// e.g. to grab a reserved level's lookup, do `reservation_spatia_lookups[z_index]`
- ///
- /// * null means that a level isn't a reservation level
- /// * this also means that we can't zclear / 'free' reserved levels; they're effectively immovable due to this datastructure
- /// * if it is a reserved level, it returns the spatial grid
- /// * to get a chunk, do `spatial_lookup[ceil(where.x / TURF_CHUNK_RESOLUTION) + (ceil(where.y / TURF_CHUNK_RESOLUTION) - 1) * ceil(world.maxx / TURF_CHUNK_RESOLUTION)]`
- /// * being in border counts as being in the reservation. you won't be soon, though.
- var/static/list/reservation_spatial_lookups = list()
-
-/datum/controller/subsystem/mapping/on_max_z_changed(old_z_count, new_z_count)
- . = ..()
- if(length(reservation_spatial_lookups) < new_z_count)
- reservation_spatial_lookups.len = new_z_count
-
-/datum/controller/subsystem/mapping/Recover()
- . = ..()
- reservation_blocking_op = FALSE
/**
* allocate a new reservation level
diff --git a/code/controllers/subsystem/mapping/mapping.dm b/code/controllers/subsystem/mapping/mapping.dm
new file mode 100644
index 000000000000..ac1f688455e2
--- /dev/null
+++ b/code/controllers/subsystem/mapping/mapping.dm
@@ -0,0 +1,190 @@
+#define INIT_ANNOUNCE(X) to_chat(world, "[X]"); log_world(X)
+
+GLOBAL_VAR_INIT(used_engine, "None")
+// Handles map-related tasks, mostly here to ensure it does so after the MC initializes.
+SUBSYSTEM_DEF(mapping)
+ name = "Mapping"
+ init_order = INIT_ORDER_MAPPING
+ subsystem_flags = SS_NO_FIRE
+
+ //* Allocation *//
+ // list of levels ready for reuse
+ var/static/list/reusable_levels = list()
+
+ //* Levels *//
+ /// indexed level datums
+ var/static/list/datum/map_level/ordered_levels = list()
+ /// k-v id to level datum lookup
+ var/static/list/datum/map_level/keyed_levels = list()
+ /// typepath to level datum lookup
+ /// we do that because we automatically generate level ids
+ /// so we can't use initial(id)
+ var/static/list/datum/map_level/typed_levels = list()
+
+ //* Levels - Fluff *//
+ /// literally just a random hexadecimal store to prevent collision
+ var/static/list/random_fluff_level_hashes = list()
+
+ //* Levels - Multiz *//
+ /// Ordered lookup list for multiz up
+ var/list/cached_level_up
+ /// Ordered lookup list for multiz down
+ var/list/cached_level_down
+ /// Ordered lookup list for east transition
+ var/list/cached_level_east
+ /// Ordered lookup list for west transition
+ var/list/cached_level_west
+ /// Ordered lookup list for north transition
+ var/list/cached_level_north
+ /// Ordered lookup list for south transition
+ var/list/cached_level_south
+ /// Z access lookup - z = list() of zlevels it can directly access vertically
+ /// * For performance, this is currently only including bidirectional links
+ /// * For performance, this does not support looping.
+ /// * This is a direct stack lookup. This does not take map_struct's into account.
+ /// * You should only be using this for technical use cases like z-rendering and whatnot,
+ /// for fluff this is not sufficient to determine if something is actually above/below if it's not actually connected.
+ var/list/z_stack_lookup
+ /// does z stack lookup need a rebuild?
+ var/z_stack_dirty = TRUE
+
+ //* Maps *//
+ /// station is loaded
+ var/world_is_loaded = FALSE
+ /// loaded station map
+ var/static/datum/map/station/loaded_station
+ /// next station map
+ var/datum/map/station/next_station
+ /// loaded maps
+ var/static/list/datum/map/loaded_maps = list()
+ /// available maps - k-v lookup by id
+ var/list/datum/map/keyed_maps
+
+ //* Obfuscation *//
+ /// used to ensure global-ness
+ // todo: should this be here? this is used literally everywhere
+ var/static/round_global_descriptor
+ /// round-local hash storage for specific map ids
+ var/static/round_local_mangling_cache = list()
+ /// round-local hash storage for specific map ids, reverse lookup
+ var/static/round_local_mangling_reverse_cache = list()
+ /// round-local hash storage for obfuscated ids
+ var/static/round_local_obfuscation_cache = list()
+ /// round-local hash storage for obfuscated ids, reverse lookup
+ var/static/round_local_obfuscation_reverse_cache = list()
+
+ //* Reservations *//
+ /// reserved levels allocated
+ var/static/reserved_level_count = 0
+ /// reserved turfs allowed - we can over-allocate this if we're only going to be slightly over and can always allocate atleast one level.
+ var/static/reserved_turfs_max = 192 * 192 * 3
+ /// allocated space reservations
+ var/static/list/datum/turf_reservation/reservations = list()
+ /// list of reserved z-indices for fast access
+ var/static/list/reserve_levels = list()
+ /// doing some blocking op on reservation system
+ var/static/reservation_blocking_op = FALSE
+ /// singleton area holding all free reservation turfs
+ var/static/area/reservation_unused/reservation_unallocated_area = new
+ /// spatial grid of turf reservations. the owner of a chunk is the bottom left tile's owner.
+ ///
+ /// this is a list with length of world.maxz, with the actual spatial grid list being at the index of the z
+ /// e.g. to grab a reserved level's lookup, do `reservation_spatia_lookups[z_index]`
+ ///
+ /// * null means that a level isn't a reservation level
+ /// * this also means that we can't zclear / 'free' reserved levels; they're effectively immovable due to this datastructure
+ /// * if it is a reserved level, it returns the spatial grid
+ /// * to get a chunk, do `spatial_lookup[ceil(where.x / TURF_CHUNK_RESOLUTION) + (ceil(where.y / TURF_CHUNK_RESOLUTION) - 1) * ceil(world.maxx / TURF_CHUNK_RESOLUTION)]`
+ /// * being in border counts as being in the reservation. you won't be soon, though.
+ var/static/list/reservation_spatial_lookups = list()
+
+ //* System *//
+ /// global mutex for ensuring two map/level load ops don't go at once
+ /// a separate mutex is used at the actual maploader level
+ /// this ensures we aren't shoving maps in during map init, as that can be both laggy and/or bad to legacy code that
+ /// expect zlevel adjacency.
+ var/load_mutex = FALSE
+
+ //! Legacy !//
+
+ // todo: this is going to need a lot more documentation
+ // the idea of a single zlevel for areas is sorta flawed
+ // this is an acceptable lazy lookup but we need to standardize what this means / look at how this is generated.
+ var/list/areas_in_z = list()
+
+/datum/controller/subsystem/mapping/Initialize(timeofday)
+ // load data
+ // todo: refactor
+ load_map_templates()
+ // todo: refactor
+ preloadShelterTemplates()
+
+ // init obfuscation
+ init_obfuscation_data()
+ // init maps
+ init_maps()
+ // load the map to use
+ read_next_map()
+
+ // load world - this also initializes our first reserved level, which is compiled in.
+ load_station()
+
+ // todo: refactor - Set up antagonists.
+ populate_antag_type_list()
+ // todo: refactor - Set up spawn points.
+ populate_spawn_points()
+
+ // finalize
+ // todo: refactor
+ repopulate_sorted_areas()
+
+ return ..()
+
+/datum/controller/subsystem/mapping/Recover()
+ . = ..()
+ reservation_blocking_op = FALSE
+
+/datum/controller/subsystem/mapping/Shutdown()
+ . = ..()
+ write_next_map()
+
+/datum/controller/subsystem/mapping/on_max_z_changed(old_z_count, new_z_count)
+ . = ..()
+ if(length(reservation_spatial_lookups) < new_z_count)
+ reservation_spatial_lookups.len = new_z_count
+ // just to make sure order of ops / assumptions are right
+ ASSERT(length(ordered_levels) == world.maxz)
+
+//! Legacy Below !//
+
+//
+// Mapping subsystem handles initialization of random map elements at server start
+// For us that means loading our random roundstart engine!
+//
+/datum/controller/subsystem/mapping
+ var/list/map_templates = list()
+ var/list/shelter_templates = list()
+
+/datum/controller/subsystem/mapping/Recover()
+ . = ..()
+ subsystem_flags |= SS_NO_INIT // Make extra sure we don't initialize twice.
+ shelter_templates = SSmapping.shelter_templates
+
+/datum/controller/subsystem/mapping/proc/load_map_templates()
+ for(var/T in subtypesof(/datum/map_template))
+ var/datum/map_template/template = T
+ template = new T
+ if(!template.map_path)
+ qdel(template)
+ continue
+ map_templates[template.name] = template
+ return TRUE
+
+/datum/controller/subsystem/mapping/proc/preloadShelterTemplates()
+ for(var/item in subtypesof(/datum/map_template/shelter))
+ var/datum/map_template/shelter/shelter_type = item
+ if(!(initial(shelter_type.map_path)))
+ continue
+ var/datum/map_template/shelter/S = new shelter_type()
+
+ shelter_templates[S.shelter_id] = S
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/stack.dm b/code/controllers/subsystem/mapping/spatial/mapping-spatial-stack.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/stack.dm
rename to code/controllers/subsystem/mapping/spatial/mapping-spatial-stack.dm
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/angle.dm b/code/controllers/subsystem/mapping/virtual/mapping-virtual-angle.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/angle.dm
rename to code/controllers/subsystem/mapping/virtual/mapping-virtual-angle.dm
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/loc.dm b/code/controllers/subsystem/mapping/virtual/mapping-virtual-coords.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/loc.dm
rename to code/controllers/subsystem/mapping/virtual/mapping-virtual-coords.dm
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/dir.dm b/code/controllers/subsystem/mapping/virtual/mapping-virtual-dir.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/dir.dm
rename to code/controllers/subsystem/mapping/virtual/mapping-virtual-dir.dm
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/step.dm b/code/controllers/subsystem/mapping/virtual/mapping-virtual-step.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/step.dm
rename to code/controllers/subsystem/mapping/virtual/mapping-virtual-step.dm
diff --git a/code/controllers/subsystem/mapping/spatial_helpers/distance.dm b/code/controllers/subsystem/mapping/virtual/mapping-vritual-dist.dm
similarity index 100%
rename from code/controllers/subsystem/mapping/spatial_helpers/distance.dm
rename to code/controllers/subsystem/mapping/virtual/mapping-vritual-dist.dm
diff --git a/code/game/landmarks/landmarks.dm b/code/game/landmarks/landmarks.dm
index 196b835db416..3397bf26def5 100644
--- a/code/game/landmarks/landmarks.dm
+++ b/code/game/landmarks/landmarks.dm
@@ -77,10 +77,6 @@ INITIALIZE_IMMEDIATE(/obj/landmark)
tdomeadmin += loc
if("tdomeobserve")
tdomeobserve += loc
- if("prisonsecuritywarp")
- prisonsecuritywarp += loc
- delete_on_roundstart = 1
- return
if("blobstart")
blobstart += loc
delete_on_roundstart = 1
diff --git a/code/modules/admin/admin_modal.dm b/code/modules/admin/admin_modal.dm
index ac6584d6760d..3f0f80bdf3fc 100644
--- a/code/modules/admin/admin_modal.dm
+++ b/code/modules/admin/admin_modal.dm
@@ -5,3 +5,6 @@
* Base type of admin modals, which tend to be standalone panels.
*/
/datum/admin_modal
+ /// TGUI ID
+ var/tgui_interface
+#warn impl
diff --git a/code/modules/admin/modals/upload_map_sector.dm b/code/modules/admin/modals/upload_map_sector.dm
new file mode 100644
index 000000000000..99ad9f582db2
--- /dev/null
+++ b/code/modules/admin/modals/upload_map_sector.dm
@@ -0,0 +1,36 @@
+//* This file is explicitly licensed under the MIT license. *//
+//* Copyright (c) 2024 Citadel Station Developers *//
+
+/**
+ * Modal supporting arbitrary map uploads.
+ *
+ * * Does not support shuttles. You must upload shuttles separately!
+ */
+/datum/admin_modal/upload_map_sector
+ #warn write modal
+ tgui_interface = "AdminModalUploadMapSector"
+
+ //* constraints *//
+
+ /// in bytes
+ var/max_upload_size = 1024 * 1024 * 10
+ /// in levels
+ var/max_upload_levels = 9
+
+ //* buffer *//
+
+ /// in bytes
+ var/current_upload_size = 0
+ /// in levels
+ var/current_upload_levels = 0
+
+ /// current max size
+ var/current_max_x = 0
+ /// current max size
+ var/current_max_y = 0
+
+ /// map level's
+ var/list/datum/map_level/level_buffers
+
+#warn impl
+
diff --git a/code/modules/mapping/map.dm b/code/modules/mapping/map.dm
index b0a72057a60d..b88cc8136e70 100644
--- a/code/modules/mapping/map.dm
+++ b/code/modules/mapping/map.dm
@@ -373,11 +373,6 @@
/datum/map/station/proc/get_network_access(var/network)
return 0
-// By default transition randomly to another zlevel
-/datum/map/station/proc/get_transit_zlevel(current_z_level)
- . = SSmapping.crosslinked_levels() - current_z_level
- return SAFEPICK(.)
-
/datum/map/station/proc/get_empty_zlevel()
if(empty_levels == null)
var/datum/map_level/level = SSmapping.allocate_level()
@@ -400,12 +395,14 @@
// Just the sector we're in
if(!long_range || (om_range < 0))
- return O.map_z.Copy()
+ return O.location?.get_z_indices() || list()
// Otherwise every sector we're on top of
var/list/connections = list()
for(var/obj/overmap/entity/visitable/V in bounds(O, om_range))
- connections |= V.map_z // Adding list to list adds contents
+ var/list/levels = V.location?.get_z_indices()
+ if(levels)
+ connections |= levels
return connections
// Traditional behavior
diff --git a/code/modules/mapping/map_level.dm b/code/modules/mapping/map_level.dm
index f3022142efc3..db7c012ba5e3 100644
--- a/code/modules/mapping/map_level.dm
+++ b/code/modules/mapping/map_level.dm
@@ -141,6 +141,7 @@
/// * the indices are zlevel, with the 'center ground floor' being list(0, 0, 0)
/// * all levels on a map must have this specified if the map is going to build a struct.
var/struct_create_pos
+ #warn hook
//* Virtual Coordinates *//
/// the coordinate of the lower-left / southwest corner border of the map
diff --git a/code/modules/mapping/map_struct.dm b/code/modules/mapping/map_struct.dm
index 4300d19e22e1..95605c4ca064 100644
--- a/code/modules/mapping/map_struct.dm
+++ b/code/modules/mapping/map_struct.dm
@@ -80,28 +80,28 @@
var/had_vertical = FALSE
var/had_horizontal = FALSE
- other = z_grid["[level.x+1],[level.y],[level.z]"]
+ other = z_grid["[level.struct_x+1],[level.struct_y],[level.struct_z]"]
if(other)
level.link_east = other
had_horizontal = TRUE
- other = z_grid["[level.x-1],[level.y],[level.z]"]
+ other = z_grid["[level.struct_x-1],[level.struct_y],[level.struct_z]"]
if(other)
level.link_west = other
had_horizontal = TRUE
- other = z_grid["[level.x],[level.y+1],[level.z]"]
+ other = z_grid["[level.struct_x],[level.struct_y+1],[level.struct_z]"]
if(other)
level.link_north = other
had_horizontal = TRUE
- other = z_grid["[level.x],[level.y-1],[level.z]"]
+ other = z_grid["[level.struct_x],[level.struct_y-1],[level.struct_z]"]
if(other)
level.link_south = other
had_horizontal = TRUE
- other = z_grid["[level.x],[level.y],[level.z+1]"]
+ other = z_grid["[level.struct_x],[level.struct_y],[level.struct_z+1]"]
if(other)
level.link_above = other
had_vertical = TRUE
- other = z_grid["[level.x],[level.y],[level.z-1]"]
+ other = z_grid["[level.struct_x],[level.struct_y],[level.struct_z-1]"]
if(other)
level.link_below = other
had_vertical = TRUE
@@ -182,6 +182,8 @@
CRASH("FATAL: duplicate level")
if(!resolved.loaded)
CRASH("FATAL: attempted to include an unloaded level in a struct. structs do not currently support lazy-loading.")
+ if(resolved.struct)
+ CRASH("FATAL: level already had struct")
// add to levels list
levels += resolved
@@ -264,75 +266,6 @@
constructed = FALSE
-#warn below
-
-#warn parse this file
-
-/datum/map_struct/proc/Register(rebuild = TRUE)
- SSmapping.structs += src
- SSmapping.z_stack_dirty = TRUE
- if(rebuild)
- SSmapping.rebuild_struct_lookup()
- SSmapping.rebuild_verticality()
- SSmapping.rebuild_transitions()
- SSmapping.RebuildCrosslinking()
-
-/datum/map_struct/proc/Unregister(rebuild = TRUE)
- SSmapping.structs -= src
- SSmapping.z_stack_dirty = TRUE
- if(rebuild)
- SSmapping.rebuild_struct_lookup()
- SSmapping.rebuild_verticality()
- SSmapping.rebuild_transitions()
- SSmapping.RebuildCrosslinking()
-
-/**
- * Ensures all level IDs exist as currently instantiated levels,
- * and also ensures there's no dupe keys/IDs
- */
-/datum/map_struct/proc/Verify()
- . = TRUE
- var/list/keymap = list()
- var/list/idmap = list()
- for(var/key in z_grid)
- if(keymap[key])
- stack_trace("Duplicate key [key].")
- . = FALSE
- keymap[key] = TRUE
- grid_parser.Find(key)
- if(key != "[grid_parser.group[1]],[grid_parser.group[2]],[grid_parser.group[3]]")
- stack_trace("Invalid key [key].")
- . = FALSE
- var/id = z_grid[key]
- if(!SSmapping.keyed_levels[id])
- stack_trace("Couldn't locate level id [id] in SSmapping keyed_levels list.")
- . = FALSE
- if(SSmapping.keyed_levels[id].struct)
- stack_trace("Level id [id] was already in a struct.")
- . = FALSE
- if(idmap[id])
- stack_trace("Duplicate level ID [id]")
- . = FALSE
- idmap[id] = TRUE
-
-#warn above
-
-//* Z-Access *//
-
-/**
- * returns mutable copy of real_indices
- */
-/datum/map_struct/proc/mutable_z_list()
- return z_indices.Copy()
-
-/**
- * directly fetches real indices
- *
- * * Do not modify returned list.
- */
-/datum/map_struct/proc/immutable_z_list()
- return z_indices
-
//* Helpers *//
/proc/cmp_map_level_struct_z(datum/map_level/A, datum/map_level/B)
diff --git a/code/modules/overmap/entity/entity-location.dm b/code/modules/overmap/entity/entity-location.dm
index a0d99d783d8c..e9f6b7024db3 100644
--- a/code/modules/overmap/entity/entity-location.dm
+++ b/code/modules/overmap/entity/entity-location.dm
@@ -2,22 +2,23 @@
//* Copyright (c) 2024 Citadel Station Developers *//
/**
- * get z-level indices in this entity
+ * get our z-level indices
*
* * entities that are on z's like shuttles instead of owning them use the z level they're on
*
- * @return null if there are none / this is not semantically an entity on a z
+ * @return null if there are none / this is not semantically an entity on a z, and list() if we're not in a level right now.
*/
/obj/overmap/entity/proc/get_z_indices()
RETURN_TYPE(/list)
return location?.get_z_indices()
/**
- * get a random z-level in this entity
+ * get our owned z-level indices
*
- * * entities that are on z's like shuttles instead of owning them use the z level they're on
+ * * shuttles and similar entities don't own their indices.
*
- * @return null if there are none / this is not semantically an entity on a z
+ * @return null if this is not semantically an entity on a z, and list() if none are owned, otherwise
*/
-/obj/overmap/entity/proc/get_random_z_index()
- return location?.get_random_z_index()
+/obj/overmap/entity/proc/get_owned_z_indices()
+ RETURN_TYPE(/list)
+ return location?.get_owned_z_indices()
diff --git a/code/modules/overmap/entity/entity-physics.dm b/code/modules/overmap/entity/entity-physics.dm
index bbea3c084f0b..509cfdfba155 100644
--- a/code/modules/overmap/entity/entity-physics.dm
+++ b/code/modules/overmap/entity/entity-physics.dm
@@ -51,8 +51,8 @@
vel_y += vy
var/interpolate_limiter
- if((interpolate_limiter = OVERMAP_DIST_TO_PIXEL(sqrt(vel_x ** 2 + vel_y ** 2))) > SSovermaps_physics.global_interpolate_limit)
- interpolate_limiter = SSovermaps_physics.global_interpolate_limit / interpolate_limiter
+ if((interpolate_limiter = OVERMAP_DIST_TO_PIXEL(sqrt(vel_x ** 2 + vel_y ** 2))) > SSovermap_physics.global_interpolate_limit)
+ interpolate_limiter = SSovermap_physics.global_interpolate_limit / interpolate_limiter
vel_x *= interpolate_limiter
vel_y *= interpolate_limiter
diff --git a/code/modules/overmap/entity/overmap_location.dm b/code/modules/overmap/entity/overmap_location.dm
index 002458381c51..a83029ba4ffc 100644
--- a/code/modules/overmap/entity/overmap_location.dm
+++ b/code/modules/overmap/entity/overmap_location.dm
@@ -9,6 +9,8 @@
* Descriptive, I know.
*/
/datum/overmap_location
+ /// owning entity, if any
+ var/obj/overmap/entity/entity
/**
* get our z-level indices
@@ -25,9 +27,9 @@
*
* * shuttles and similar entities don't own their indices.
*
- * @return null if this is not semantically an entity on a z, and list() if none are owned, otherwise
+ * @return null if this is not semantically an entity on a z, and list() if none are owned, otherwise
*/
-/datum/overmap_location/proc/get_z_indices()
+/datum/overmap_location/proc/get_owned_z_indices()
RETURN_TYPE(/list)
#warn impl
diff --git a/maps/stations/rift/sectors/lythios_43c.dm b/maps/stations/rift/sectors/lythios_43c.dm
index b8faffaeedda..5a6adb9ee8be 100644
--- a/maps/stations/rift/sectors/lythios_43c.dm
+++ b/maps/stations/rift/sectors/lythios_43c.dm
@@ -28,14 +28,7 @@
"NDV Quicksilver" = list("rift_specops_dock"),
"Pirate Skiff" = list("rift_pirate_dock"),
)
-
- extra_z_levels = list(
- /datum/map_level/rift/plains,
- /datum/map_level/rift/caves,
- /datum/map_level/rift/deep,
- /datum/map_level/rift/base,
- )
-
+
/obj/overmap/entity/visitable/sector/lythios43c/Crossed(var/atom/movable/AM)
. = ..()
announce_atc(AM,going = FALSE)
diff --git a/maps/tether/sectors.dm b/maps/tether/sectors.dm
index 08cafb27a5bc..278de42f4ef6 100644
--- a/maps/tether/sectors.dm
+++ b/maps/tether/sectors.dm
@@ -34,11 +34,6 @@
)
/obj/overmap/entity/visitable/sector/virgo3b
- extra_z_levels = list(
- /datum/map_level/tether/mine,
- /datum/map_level/tether/plains,
- /datum/map_level/tether/underdark,
- )
in_space = FALSE
var/list/snowflake_space_levels = list(