Parses the AtmosSystem architecture in Space Station 14 at the server/shared/client level: processing cycle, tile state, invalidations, connection with DeltaPressure and overlay synchronization. Use it when you need to understand how the system actually works, where it is safe to expand, and how not to break the performance/consistency of the atmosphere.
Use this skill as an architectural playbook for AtmosSystem :)
Keep your focus on the current code and check for freshness via git blame (cutoff: 2024-02-19).
references/fresh-pattern-catalog.md - fresh working patterns ✅references/rejected-snippets.md - old/problem areas that cannot be taken as a standard ⚠️references/docs-context.md - supporting ideas from docs (not the source of truth)GridAtmosphereComponent: each grid has a set of TileAtmosphere, queues of the current cycle and a processing-state.Revalidate -> TileEqualize -> ActiveTiles -> ExcitedGroups -> HighPressureDelta -> DeltaPressure -> Hotspots -> Superconductivity -> PipeNet -> AtmosDevices.Revalidate stage.grid tile -> map atmosphere -> SpaceGas fallback.ProcessingPaused.IsTileAirBlockedCached(...), and not the on-the-fly option.GetTileMixtures(...) instead of multiple single calls.excite: true only when you really need an immediate response from the atmosphere/visuals.InvalidateTile(...), do not run a manual mass recalculation.DeltaPressureParallelProcessPerIteration and DeltaPressureParallelBatchSize for the server load.IsTileSpace(...) + IsTileAirBlockedCached(...).SetMapAtmosphere/SetMapGasMixture/SetMapSpace), and not by tile.// Each stage returns: continue, move to the next, or pause the cycle.
switch (atmosphere.State)
{
case AtmosphereProcessingState.Revalidate:
if (!ProcessRevalidate(ent))
return AtmosphereProcessingCompletionState.Return; // time-budget exceeded
atmosphere.State = MonstermosEqualization
? AtmosphereProcessingState.TileEqualize
: AtmosphereProcessingState.ActiveTiles;
return AtmosphereProcessingCompletionState.Continue;
case AtmosphereProcessingState.DeltaPressure:
if (!ProcessDeltaPressure(ent))
return AtmosphereProcessingCompletionState.Return;
atmosphere.State = AtmosphereProcessingState.Hotspots;
return AtmosphereProcessingCompletionState.Continue;
}
// When changing the position/state of an airtight entity, mark the tile as invalid.
public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
{
_explosionSystem.UpdateAirtightMap(grid, pos, grid);
_atmosphereSystem.InvalidateTile(grid.Owner, pos);
}
// At the Revalidate stage, the tile rebuilds TileData/AirtightData and visuals.
UpdateTileData(ent, mapAtmos, tile);
UpdateAdjacentTiles(ent, tile, activate: true);
UpdateTileAir(ent, tile, volume);
InvalidateVisuals(ent, tile);
// The pressure calculation is performed in batches in parallel-job.
var job = new DeltaPressureParallelJob(this, atmosphere, atmosphere.DeltaPressureCursor, DeltaPressureParallelBatchSize);
_parallel.ProcessNow(job, toProcess);
// The damage itself is applied in a separate pass from the results queue.
while (atmosphere.DeltaPressureDamageResults.TryDequeue(out var result))
{
PerformDamage(result.Ent, result.Pressure, result.DeltaPressure);
}
// When turning off the mask, we try to connect the breathing instrument to the internals of the wearer.
private void OnMaskToggled(Entity<BreathToolComponent> ent, ref ItemMaskToggledEvent args)
{
if (args.Mask.Comp.IsToggled)
{
DisconnectInternals(ent, forced: true);
}
else if (_internalsQuery.TryComp(args.Wearer, out var internals))
{
_internals.ConnectBreathTool((args.Wearer.Value, internals), ent);
}
}
// The client accepts either full state or delta state, but applies the same via modifiedChunks.
switch (args.Current)
{
case GasTileOverlayDeltaState delta:
modifiedChunks = delta.ModifiedChunks;
// We delete local chunks that are no longer in the server list.
break;
case GasTileOverlayState state:
modifiedChunks = state.Chunks;
break;
}
foreach (var (index, data) in modifiedChunks)
{
comp.Chunks[index] = data; // single way of application
}
references/rejected-snippets.md and only then make the change.Think of it as a pipeline with queues, not as a "single function atmos" 🧪