Implements "forbidden" areas into atmospherics_sanity unit test (#96141)

## About The Pull Request
I originally just wanted to change the logging for this so that it's
more helpful for mappers, but I realized that this test doesn't cover
the case where a mapper mistakenly connects a illegal area into the air
loop, so I implemented that.

I had to remap Catwalk so that the actual server room was isolated from
everything else. I tried to keep everything intact to the best of my
ability but there simply wasn't much room.

Also, I added a new subtype for the supermatter engine's area, and
included an UpdatePaths file for it. Behaviour should be identical
across the board.
## Why It's Good For The Game
So we can be 100% absolutely definitely sure we didn't attach the waste
loop inside the supermatter engine.

## Mold Spore

<img width="400" height="400" alt="image"
src="https://github.com/user-attachments/assets/f231ba77-097d-4365-b467-17580aceae14"
/>
This commit is contained in:
tonty
2026-06-03 14:21:31 -06:00
committed by GitHub
parent 74a161aaaf
commit ddb4b35bc2
13 changed files with 3478 additions and 3633 deletions
+73 -44
View File
@@ -1,51 +1,58 @@
/**
* This test checks that all expected areas are connected to a starting area
* This test checks that all areas are connected to their distribution loops
*/
/datum/unit_test/atmospherics_sanity
// we iterate over all atmospherics devices on the starting networks
priority = TEST_LONGER
priority = TEST_LONGER // we iterate over all atmospherics devices on the starting networks
/// List of areas remaining to be checked
var/list/area/remaining_areas
/// List of areas to start crawling from
var/list/area/starting_areas
/// List of areas already crawled, to prevent needless crawling
var/list/area/crawled_areas
/// List of areas to start crawling from
var/list/area/starting_areas
/// List of areas remaining to be checked
var/list/area/remaining_areas
/// List of areas that should absolutely not be encountered
var/list/area/forbidden_areas
/// We run this test in parallel, so we need to keep track of how many crawls are running
/// This is to prevent stack overflow mostly
var/crawls = 0
/datum/unit_test/atmospherics_sanity/proc/get_areas()
/datum/unit_test/atmospherics_sanity/proc/prepare_crawl()
starting_areas = list()
forbidden_areas = list()
crawled_areas = list()
remaining_areas = list()
for(var/obj/effect/landmark/atmospheric_sanity/start_area/start_marker in GLOB.landmarks_list)
var/area/starting_area = get_area(start_marker)
if(starting_area in starting_areas)
TEST_FAIL("Duplicate atmospherics sanity starting marker in '[starting_area]'([starting_area.type]) at ([start_marker.x], [start_marker.y], [start_marker.z])")
continue
if(starting_area.outdoors)
TEST_FAIL("Atmospherics sanity starting marker in outdoors area '[starting_area]'([starting_area.type]) at ([start_marker.x], [start_marker.y], [start_marker.z])")
TEST_FAIL("Atmospherics sanity starting marker cannot be in outdoors area '[starting_area]'([starting_area.type]) at ([start_marker.x], [start_marker.y], [start_marker.z])")
continue
starting_areas |= get_area(start_marker)
// If there are no starting areas, default to these
var/static/list/area/default_starting_areas = list(
/area/station/ai/satellite/chamber,
/area/station/engineering/atmos,
/area/station/medical/virology,
/area/station/science/xenobiology,
)
if(!length(starting_areas))
log_test("No starting areas found, defaulting...")
var/list/area/default_starting_areas = list(
// These areas have their own air supply
/area/station/ai/satellite/chamber,
/area/station/medical/virology,
/area/station/science/xenobiology,
// Otherwise, this should connect to the rest of the station
/area/station/engineering/atmos,
)
for(var/area/starting_area as anything in default_starting_areas)
var/area/station_area = GLOB.areas_by_type[starting_area]
if(!isnull(station_area))
starting_areas += station_area
remaining_areas = list()
var/atom/mark_all_station_areas_marker = locate(/obj/effect/landmark/atmospheric_sanity/mark_all_station_areas_as_goal) in GLOB.landmarks_list
if(!isnull(mark_all_station_areas_marker))
@@ -61,58 +68,76 @@
if(goal_area.outdoors)
TEST_FAIL("Atmospherics sanity goal marker in outdoors area '[goal_area]'([goal_area.type]) at ([goal_marker.x], [goal_marker.y], [goal_marker.z])")
continue
if(istype(goal_area, /area/space))
TEST_FAIL("Atmospherics sanity goal marker in space at ([goal_marker.x], [goal_marker.y], [goal_marker.z])")
continue
remaining_areas |= get_area(goal_marker)
if(!length(remaining_areas))
log_test("No goal areas found, defaulting...")
mark_station_areas_as_goals()
else
for(var/obj/effect/landmark/atmospheric_sanity/forbidden_area/forbidden_marker in GLOB.landmarks_list)
var/area/forbidden_area = get_area(forbidden_marker)
if(forbidden_area in remaining_areas)
var/obj/effect/landmark/atmospheric_sanity/goal_area/goal_marker = locate() in forbidden_area
TEST_FAIL("Area '[forbidden_area]'([forbidden_area.type]) \
has a goal marker at ([goal_marker.x], [goal_marker.y], [goal_marker.z]) \
and a forbidden marker at ([forbidden_marker.x], ([forbidden_marker.y], ([forbidden_marker.z])")
continue
if(forbidden_area in forbidden_areas)
TEST_FAIL("Area '[forbidden_area]'([forbidden_area.type]) is so forbidden it has a duplicate marker at at ([forbidden_marker.x], ([forbidden_marker.y], ([forbidden_marker.z])")
continue
forbidden_areas |= forbidden_area
for(var/obj/effect/landmark/atmospheric_sanity/ignore_area/ignore_marker in GLOB.landmarks_list)
remaining_areas -= get_area(ignore_marker)
/datum/unit_test/atmospherics_sanity/proc/mark_station_areas_as_goals()
// We don't want to check these areas
var/static/list/area/ignored_types = list(
// We don't care if we find these
var/list/area/ignored_types = list(
/area/station/asteroid,
/area/station/engineering/supermatter,
/area/station/holodeck,
/area/station/maintenance,
/area/station/science/ordnance/bomb,
/area/station/solars,
// FIXME, burnchamber is usually mapped with a vent in the buffer airlock
// which causes us to leak into freezer. These two should be forbidden
/area/station/science/ordnance/burnchamber,
/area/station/science/ordnance/freezerchamber,
/area/station/solars,
/area/station/tcommsat/server,
)
for(var/area/ignored as anything in ignored_types)
ignored_types |= subtypesof(ignored)
for(var/area/station/station_area_type as anything in subtypesof(/area/station) - ignored_types)
// We should never find these
var/list/area/forbidden_types = list(
/area/station/engineering/supermatter/engine,
/area/station/tcommsat/server,
)
for(var/area/forbidden as anything in forbidden_types)
forbidden_types |= subtypesof(forbidden)
for(var/area/station/station_area_type as anything in subtypesof(/area/station) - ignored_types - forbidden_types)
var/area/station_area = GLOB.areas_by_type[station_area_type]
if(!isnull(station_area))
remaining_areas += station_area
/datum/unit_test/atmospherics_sanity/Run()
get_areas()
crawl_areas()
UNTIL(crawls == 0)
for(var/area/missed as anything in remaining_areas)
if(missed.has_contained_turfs())
var/turf/first_turf = missed.get_zlevel_turf_lists()[1][1]
TEST_FAIL("Disconnected Area '[missed]'([missed.type]) at ([first_turf.x], [first_turf.y], [first_turf.z])")
else
TEST_NOTICE(src, "Disconnected Area '[missed]'([missed.type]) with no turfs?")
for(var/area/station/forbidden_area_type as anything in forbidden_types)
var/area/forbidden_area = GLOB.areas_by_type[forbidden_area_type]
if(!isnull(forbidden_area))
forbidden_areas += forbidden_area
/// Iterates over starting_areas and ensures that all goal areas are connected to atleast one start
/datum/unit_test/atmospherics_sanity/proc/crawl_areas()
crawled_areas = list()
/datum/unit_test/atmospherics_sanity/Run()
prepare_crawl()
for(var/area/start_area as anything in starting_areas)
ASYNC
crawl_area(start_area)
starting_areas = null
UNTIL(crawls == 0)
for(var/area/missed as anything in remaining_areas)
var/turf/first_turf = missed.get_zlevel_turf_lists()[1][1]
TEST_FAIL("Goal area '[missed]'([missed.type]) is isolated from any distribution loops ([first_turf.x], [first_turf.y], [first_turf.z])")
/// Crawls through an area, iterating over all vents/scrubbers and their connected pipelines
/datum/unit_test/atmospherics_sanity/proc/crawl_area(area/the_area)
@@ -126,12 +151,16 @@
for(var/obj/machinery/atmospherics/components/component as anything in (the_area.air_vents + the_area.air_scrubbers))
for(var/datum/pipeline/parent as anything in component.parents)
if(isnull(parent))
TEST_NOTICE(src, "Found a null parent for [component] in [the_area] at ([component.x], [component.y], [component.z])")
TEST_NOTICE(src, "[component] at ([component.x], [component.y], [component.z]) isn't attached to a pipenet, is this on purpose?")
continue
pipelines |= parent
for(var/datum/pipeline/pipeline as anything in pipelines)
crawl_pipeline(pipeline)
if((the_area in forbidden_areas) && length(pipelines)) // we don't care if this area is forbidden if it isn't actually connected to the air
var/turf/first_turf = the_area.get_zlevel_turf_lists()[1][1]
TEST_FAIL("Forbidden area '[the_area]'([the_area.type]) is connected to a distribution loop at ([first_turf.x], [first_turf.y], [first_turf.z])")
else
for(var/datum/pipeline/pipeline as anything in pipelines)
crawl_pipeline(pipeline)
crawls -= 1