Разбирает архитектуру AtmosSystem в Space Station 14 на уровне server/shared/client: цикл обработки, состояние тайлов, инвалидации, связь с DeltaPressure и overlay-синхронизацией. Используй, когда нужно понять как система реально работает, где расширять безопасно, и как не ломать производительность/согласованность атмоса.
Используй этот skill как архитектурный playbook по AtmosSystem 🙂
Держи фокус на актуальном коде и проверяй свежесть через git blame (cutoff: 2024-02-19).
references/fresh-pattern-catalog.md — свежие рабочие паттерны ✅references/rejected-snippets.md — старые/проблемные зоны, которые нельзя брать как эталон ⚠️references/docs-context.md — вспомогательные идеи из docs (не источник истины)GridAtmosphereComponent: у каждой сетки есть набор TileAtmosphere, очереди текущего цикла и processing-state.Revalidate -> TileEqualize -> ActiveTiles -> ExcitedGroups -> HighPressureDelta -> DeltaPressure -> Hotspots -> Superconductivity -> PipeNet -> AtmosDevices.Revalidate.grid tile -> map atmosphere -> SpaceGas fallback.ProcessingPaused.IsTileAirBlockedCached(...), а не on-the-fly вариант.GetTileMixtures(...) вместо многократных одиночных вызовов.excite: true только когда действительно нужен немедленный отклик атмоса/визуалов.InvalidateTile(...), не запускай ручной массовый пересчет.DeltaPressureParallelProcessPerIteration и DeltaPressureParallelBatchSize под нагрузку сервера.IsTileSpace(...) + IsTileAirBlockedCached(...).SetMapAtmosphere/SetMapGasMixture/SetMapSpace), а не по тайлу.// Каждая стадия возвращает: продолжать, перейти к следующей или приостановить цикл.
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;
}
// При изменении позиции/состояния airtight-энтити помечай тайл как invalid.
public void InvalidatePosition(Entity<MapGridComponent?> grid, Vector2i pos)
{
_explosionSystem.UpdateAirtightMap(grid, pos, grid);
_atmosphereSystem.InvalidateTile(grid.Owner, pos);
}
// На стадии Revalidate тайл пересобирает TileData/AirtightData и визуалы.
UpdateTileData(ent, mapAtmos, tile);
UpdateAdjacentTiles(ent, tile, activate: true);
UpdateTileAir(ent, tile, volume);
InvalidateVisuals(ent, tile);
// Расчет давления выполняется батчами в parallel-job.
var job = new DeltaPressureParallelJob(this, atmosphere, atmosphere.DeltaPressureCursor, DeltaPressureParallelBatchSize);
_parallel.ProcessNow(job, toProcess);
// Сам урон применяется отдельным проходом из очереди результатов.
while (atmosphere.DeltaPressureDamageResults.TryDequeue(out var result))
{
PerformDamage(result.Ent, result.Pressure, result.DeltaPressure);
}
// При выключении маски пробуем подключить дыхательный инструмент к интерналам носителя.
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);
}
}
// Клиент принимает либо full state, либо delta state, но применяет одинаково через modifiedChunks.
switch (args.Current)
{
case GasTileOverlayDeltaState delta:
modifiedChunks = delta.ModifiedChunks;
// Удаляем локальные чанки, которых больше нет в серверном списке.
break;
case GasTileOverlayState state:
modifiedChunks = state.Chunks;
break;
}
foreach (var (index, data) in modifiedChunks)
{
comp.Chunks[index] = data; // единый путь применения
}
references/rejected-snippets.md и только потом вноси изменение.Думай как о конвейере с очередями, а не как о «одной функции атмоса» 🧪