Files
+37 21b4095dfd [MDB IGNORE] [IDB IGNORE] Upstream Sync - 04/17/2026 (#5453)
Upstream 04/17/2026

fixes https://github.com/Bubberstation/Bubberstation/issues/5549

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: tgstation-ci[bot] <179393467+tgstation-ci[bot]@users.noreply.github.com>
Co-authored-by: ArcaneMusic <41715314+ArcaneMusic@users.noreply.github.com>
Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Rhials <28870487+Rhials@users.noreply.github.com>
Co-authored-by: rageguy505 <54517726+rageguy505@users.noreply.github.com>
Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com>
Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com>
Co-authored-by: Aliceee2ch <160794176+Aliceee2ch@users.noreply.github.com>
Co-authored-by: Time-Green <7501474+Time-Green@users.noreply.github.com>
Co-authored-by: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Co-authored-by: Maxipat <108554989+Maxipat112@users.noreply.github.com>
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: SimplyLogan <47579821+loganuk@users.noreply.github.com>
Co-authored-by: loganuk <fakeemail123@aol.com>
Co-authored-by: Leland Kemble <70413276+lelandkemble@users.noreply.github.com>
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
Co-authored-by: Roxy <75404941+TealSeer@users.noreply.github.com>
Co-authored-by: Lucy <lucy@absolucy.moe>
Co-authored-by: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com>
Co-authored-by: Isratosh <Isratosh@hotmail.com>
Co-authored-by: TheRyeGuyWhoWillNowDie <70169560+TheRyeGuyWhoWillNowDie@users.noreply.github.com>
Co-authored-by: Neocloudy <88008002+Neocloudy@users.noreply.github.com>
Co-authored-by: Alexander V. <volas@ya.ru>
Co-authored-by: ElGitificador <168473461+ElGitificador@users.noreply.github.com>
Co-authored-by: Twaticus <46540570+Twaticus@users.noreply.github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Bloop <13398309+vinylspiders@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Tim <timothymtorres@gmail.com>
Co-authored-by: Iamgoofball <iamgoofball@gmail.com>
Co-authored-by: Layzu666 <121319428+Layzu666@users.noreply.github.com>
Co-authored-by: Arturlang <24881678+Arturlang@users.noreply.github.com>
Co-authored-by: _0Steven <42909981+00-Steven@users.noreply.github.com>
Co-authored-by: mrmanlikesbt <99309552+mrmanlikesbt@users.noreply.github.com>
Co-authored-by: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Co-authored-by: John F. Kennedy <54908920+MacaroniCritter@users.noreply.github.com>
Co-authored-by: Cursor <102828457+theselfish@users.noreply.github.com>
Co-authored-by: Josh <josh.adam.powell@gmail.com>
Co-authored-by: Josh Powell <josh.powell@softwire.com>
Co-authored-by: Yobrocharlie <Charliemiller5617@gmail.com>
Co-authored-by: Hardly3D <66234359+Hardly3D@users.noreply.github.com>
Co-authored-by: shayoki <96078776+shayoki@users.noreply.github.com>
Co-authored-by: LT3 <83487515+lessthnthree@users.noreply.github.com>
2026-05-16 00:56:00 +02:00

167 lines
7.0 KiB
Plaintext

/**
* The AUTOMAPPER
*
* This is a subsystem designed to make modular mapping far easier.
*
* It does two things: Loads maps from an automapper config and loads area spawn datums for simpler items.
*
* The benefits? We no longer need to have _skyrat maps and can have a more unique feeling map experience as each time, it can be different.
*
* Please note, this uses some black magic to interject the templates mid world load to prevent mass runtimes down the line.
*
* LIMITED SUPPORT FOR NON-STATION LEVELS(until someone adds a better Z level handling system for this)
*/
SUBSYSTEM_DEF(automapper)
name = "Automapper"
ss_flags = SS_NO_FIRE
dependents = list(
/datum/controller/subsystem/mapping
)
/// The path to our TOML file
var/config_file = "_maps/bubber/automapper/automapper_config.toml" // BUBBER TODO - Merge our and skyrat's automapper in one
/// Our loaded TOML file
var/loaded_config
/// Our preloaded map templates
var/list/preloaded_map_templates = list()
/datum/controller/subsystem/automapper/Initialize()
loaded_config = rustg_read_toml_file(config_file)
return SS_INIT_SUCCESS
/**
* This will preload our templates into a cache ready to be loaded later.
*
* IMPORTANT: This requires Z levels to exist in order to function, so make sure it is preloaded AFTER that.
*/
/datum/controller/subsystem/automapper/proc/preload_templates_from_toml(map_names)
if(!islist(map_names))
map_names = list(map_names)
for(var/template in loaded_config["templates"])
var/selected_template = loaded_config["templates"][template]
var/required_map = selected_template["required_map"]
// !builtin is a magic code for built in maps, ie CentCom levels.
// We'll pretend it's loaded with the station z-level, because they by definition they are loaded before the station z-levels.
var/requires_builtin = (required_map == AUTOMAPPER_MAP_BUILTIN) && ((SSmapping.current_map.map_file in map_names) || SSmapping.current_map.map_file == map_names)
if(!requires_builtin && !(required_map in map_names))
continue
var/list/coordinates = selected_template["coordinates"]
if(LAZYLEN(coordinates) != 3)
CRASH("Invalid coordinates for automap template [template]!")
var/desired_z = SSmapping.levels_by_trait(selected_template["trait_name"])[coordinates[3]]
var/turf/load_turf = locate(coordinates[1], coordinates[2], desired_z)
if(!LAZYLEN(selected_template["map_files"]))
CRASH("Could not find any valid map files for automap template [template]!")
var/map_file = selected_template["directory"] + pick(selected_template["map_files"])
if(!fexists(map_file))
CRASH("[template] could not find map file [map_file]!")
var/datum/map_template/automap_template/map = new(map_file, template, required_map, load_turf)
preloaded_map_templates += map
/**
* Assuming we have preloaded our templates, this will load them from the cache.
*/
/datum/controller/subsystem/automapper/proc/load_templates_from_cache(map_names)
if(!islist(map_names))
map_names = list(map_names)
for(var/datum/map_template/automap_template/iterating_template as anything in preloaded_map_templates)
if(iterating_template.affects_builtin_map && ((SSmapping.current_map.map_file in map_names) || SSmapping.current_map.map_file == map_names))
// CentCom already started loading objects, place them in the netherzone
for(var/turf/old_turf as anything in iterating_template.get_affected_turfs(iterating_template.load_turf, FALSE))
init_contents(old_turf)
else if(!(iterating_template.required_map in map_names))
continue
if(iterating_template.load(iterating_template.load_turf, FALSE))
add_startup_message("Loaded [iterating_template.name] at [iterating_template.load_turf.x], [iterating_template.load_turf.y], [iterating_template.load_turf.z]!")
log_world("AUTOMAPPER: Successfully loaded map template [iterating_template.name] at [iterating_template.load_turf.x], [iterating_template.load_turf.y], [iterating_template.load_turf.z]!")
/**
* CentCom atoms aren't initialized but already exist, so must be properly initialized and then qdel'd.
* Arguments:
* * parent - parent turf
*/
/datum/controller/subsystem/automapper/proc/init_contents(atom/parent)
var/static/list/mapload_args = list(TRUE)
// Don't even initialize things in this list. Very specific edge cases.
var/static/list/type_blacklist = typecacheof(list(
/obj/docking_port/stationary,
/obj/structure/bookcase,
/obj/structure/closet,
/obj/item/storage,
/obj/item/reagent_containers,
))
var/previous_initialized_value = SSatoms.initialized
SSatoms.initialized = INITIALIZATION_INNEW_MAPLOAD
// Force everything to init as if INITIALIZE_IMMEDIATE was called on them.
for(var/atom/atom_to_init as anything in parent.get_all_contents_ignoring(type_blacklist) - parent)
if(atom_to_init.flags_1 & INITIALIZED_1)
continue
SSatoms.InitAtom(atom_to_init, FALSE, mapload_args)
SSatoms.initialized = previous_initialized_value
// NOW we can finally delete everything.
for(var/atom/atom_to_del as anything in parent.get_all_contents() - parent)
qdel(atom_to_del, TRUE)
/**
* Get whether a given turf of the map template is a /turf/template_noop.
*
* You'd think there would be a better API way of doing this, but there is not.
*
* Arguments:
* * map - The map_template we are looking at.
* * x - The zero-based x coordinate RELATIVE to the map_template.
* * y - The zero-based y coordinate RELATIVE to the map_template.
*/
/datum/controller/subsystem/automapper/proc/has_turf_noop(datum/map_template/map, x, y)
// Row of the map grid.
var/datum/grid_set/map_row = map.cached_map.gridSets[x + 1]
// Note that Y is upside-down in the map data.
// Which model, as in that key name in the map file, like pAK.
var/modelID = map_row.gridLines[map.height - y]
// Get the actual model text, ie the text of what's in this cell
var/model = map.cached_map.grid_models[modelID]
// If this doesn't work right, the map is horribly malformed and shoul fail,
// Or you've map-edited template_noop which I'm fine with failing as well.
return findtextEx(model, "/turf/template_noop,\n")
/**
* This returns a list of turfs that have been preloaded and preselected using our templates.
*
* Not really useful outside of load groups.
*/
/datum/controller/subsystem/automapper/proc/get_turf_blacklists(map_names)
if(!islist(map_names))
map_names = list(map_names)
var/list/blacklisted_turfs = list()
for(var/datum/map_template/automap_template/iterating_template as anything in preloaded_map_templates)
if(!(iterating_template.required_map in map_names))
continue
// Base of the coordinate system to introspect the templates.
var/base_x = iterating_template.load_turf.x
var/base_y = iterating_template.load_turf.y
for(var/turf/blacklisted_turf as anything in iterating_template.get_affected_turfs(iterating_template.load_turf, FALSE))
// Allow non-rectangular templates. Have to manually check the grid set since parsed_maps are not helpful for this.
if(has_turf_noop(iterating_template, blacklisted_turf.x - base_x, blacklisted_turf.y - base_y))
continue
blacklisted_turfs[blacklisted_turf] = TRUE
return blacklisted_turfs