mirror of
https://github.com/Citadel-Station-13/Citadel-Station-13-RP.git
synced 2026-08-18 02:38:11 +01:00
199 lines
6.9 KiB
Plaintext
199 lines
6.9 KiB
Plaintext
#define INIT_ANNOUNCE(X) to_chat(world, "<span class='boldannounce'>[X]</span>"); log_world(X)
|
|
|
|
/**
|
|
* The map management subsystem.
|
|
*/
|
|
SUBSYSTEM_DEF(mapping)
|
|
name = "Mapping"
|
|
init_order = INIT_ORDER_MAPPING
|
|
subsystem_flags = SS_NO_FIRE
|
|
|
|
//* Allocation *//
|
|
/// list of levels ready for reuse
|
|
/// * This must be sorted from low z-index to high.
|
|
var/static/list/ordered_reusable_levels = list()
|
|
|
|
//* Levels *//
|
|
/// indexed level datums
|
|
/// * If an index is null, there's no level there.
|
|
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()
|
|
|
|
//* 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.
|
|
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/reservation_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/reservation_turf_limit = 192 * 192 * 3
|
|
/// allocated space reservations
|
|
var/static/list/datum/map_reservation/reservations = list()
|
|
/// list of reserved z-indices for fast access
|
|
var/static/list/reservation_levels = list()
|
|
/// doing some blocking op on reservation system
|
|
var/static/reservation_system_mutex = 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/map_system_mutex = FALSE
|
|
|
|
/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 SS_INIT_SUCCESS
|
|
|
|
/datum/controller/subsystem/mapping/Recover()
|
|
. = ..()
|
|
reservation_system_mutex = 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)
|
|
synchronize_datastructures()
|
|
|
|
/**
|
|
* Ensure all synchronized lists are valid
|
|
*/
|
|
/datum/controller/subsystem/mapping/proc/synchronize_datastructures()
|
|
#define SYNC(var) if(!var) { var = list() ; } ; if(var.len != world.maxz) { . = TRUE ; var.len = world.maxz; }
|
|
. = FALSE
|
|
SYNC(cached_level_up)
|
|
SYNC(cached_level_down)
|
|
SYNC(cached_level_east)
|
|
SYNC(cached_level_west)
|
|
SYNC(cached_level_north)
|
|
SYNC(cached_level_south)
|
|
SYNC(z_stack_lookup)
|
|
z_stack_dirty = FALSE
|
|
if(.)
|
|
z_stack_dirty = TRUE
|
|
#undef SYNC
|
|
|
|
//! 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
|