diff --git a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs index 8ad6ad43c56..7a873b2fb5d 100644 --- a/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs +++ b/Content.Server/Shuttles/Systems/EmergencyShuttleSystem.cs @@ -8,6 +8,7 @@ using Content.Server.Communications; using Content.Server.DeviceNetwork.Systems; using Content.Server.GameTicking.Events; +using Content.Server._HL.Cleanup; using Content.Server.Pinpointer; using Content.Server.Popups; using Content.Server.RoundEnd; @@ -81,6 +82,8 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem private EntityUid? _singletonColcommMap; private EntityUid? _singletonColcommGrid; private EntityUid? _singletonColcommShuttle; + private TimeSpan _nextColcommValidation; + private static readonly TimeSpan ColcommValidationInterval = TimeSpan.FromSeconds(30); public override void Initialize() { @@ -165,6 +168,72 @@ public override void Update(float frameTime) { base.Update(frameTime); UpdateEmergencyConsole(frameTime); + ValidateColcommState(); + } + + private void ValidateColcommState() + { + if (_timing.CurTime < _nextColcommValidation) + return; + + _nextColcommValidation = _timing.CurTime + ColcommValidationInterval; + + var singletonValid = _singletonColcommMap != null && _singletonColcommGrid != null + && Exists(_singletonColcommMap.Value) && Exists(_singletonColcommGrid.Value); + var needsRespawn = false; + + var query = AllEntityQuery(); + while (query.MoveNext(out var _, out var colcomm)) + { + if (colcomm.Entity != null && Exists(colcomm.Entity.Value)) + { + EnsureComp(colcomm.Entity.Value); + + if (TryComp(colcomm.Entity.Value, out TransformComponent? xform) && xform.MapUid != null) + colcomm.MapEntity = xform.MapUid; + + if (!singletonValid) + { + _singletonColcommGrid = colcomm.Entity; + _singletonColcommMap = colcomm.MapEntity; + singletonValid = _singletonColcommMap != null && _singletonColcommGrid != null + && Exists(_singletonColcommMap.Value) && Exists(_singletonColcommGrid.Value); + } + + continue; + } + + if (singletonValid) + { + colcomm.Entity = _singletonColcommGrid; + colcomm.MapEntity = _singletonColcommMap; + continue; + } + + colcomm.Entity = null; + colcomm.MapEntity = null; + needsRespawn = true; + } + + if (needsRespawn) + RespawnColcommViaSpawnPath(); + } + + private void RespawnColcommViaSpawnPath() + { + _singletonColcommMap = null; + _singletonColcommGrid = null; + _singletonColcommShuttle = null; + + var query = AllEntityQuery(); + while (query.MoveNext(out var _, out var colcomm)) + { + colcomm.Entity = null; + colcomm.MapEntity = null; + } + + // Reuse the normal startup flow to restore ColComm + shuttle consistently. + SetupEmergencyShuttle(); } /// @@ -516,6 +585,7 @@ private void AddColcomm(EntityUid station, StationColcommComponent component) { component.MapEntity = _singletonColcommMap; component.Entity = _singletonColcommGrid; + EnsureComp(_singletonColcommGrid.Value); return; } @@ -544,6 +614,7 @@ private void AddColcomm(EntityUid station, StationColcommComponent component) component.Entity = grid; _singletonColcommMap = map; _singletonColcommGrid = grid; + EnsureComp(grid.Value); _metaData.SetEntityName(map, Loc.GetString("map-name-Colcomm")); _shuttle.TryAddFTLDestination(mapId, true, out _); Log.Info($"Created Colcomm grid {ToPrettyString(grid)} on map {ToPrettyString(map)} for station {ToPrettyString(station)}"); @@ -618,6 +689,7 @@ private void AddEmergencyShuttle(Entity(shuttle.Value); + EnsureComp(shuttle.Value); EnsureComp(shuttle.Value); EnsureComp(shuttle.Value); diff --git a/Content.Server/Trash/TrashCleanupSystem.cs b/Content.Server/Trash/TrashCleanupSystem.cs index 77aacf94452..558820e46d2 100644 --- a/Content.Server/Trash/TrashCleanupSystem.cs +++ b/Content.Server/Trash/TrashCleanupSystem.cs @@ -208,6 +208,10 @@ private bool ShouldProtectGrid(EntityUid gridUid) if (HasComp(gridUid)) return true; + // A grid with a world loader is an active world-loading anchor and should never be trash-cleaned. + if (HasComp(gridUid)) + return true; + // Protect grids with important components that indicate they shouldn't be deleted if (HasComp(gridUid) || HasComp(gridUid)) return true; diff --git a/Resources/Maps/colcomm.yml b/Resources/Maps/colcomm.yml index dedb4f116d0..6eb81d70ced 100644 --- a/Resources/Maps/colcomm.yml +++ b/Resources/Maps/colcomm.yml @@ -515,6 +515,7 @@ entities: - type: GridPathfinding - type: BecomesStation id: Colcomm + - type: CleanupProtectedGrid - type: Gravity gravityShakeSound: !type:SoundPathSpecifier path: /Audio/Effects/alert.ogg