Fix Centcomm (#16772)

This commit is contained in:
metalgearsloth
2023-05-24 21:28:44 +10:00
committed by GitHub
parent b1596c9f18
commit af5eaec932
9 changed files with 232 additions and 130 deletions

View File

@@ -207,13 +207,16 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
if (component.WinType == WinType.OpsMajor || component.WinType == WinType.CrewMajor)
return;
foreach (var (nuke, nukeTransform) in EntityQuery<NukeComponent, TransformComponent>(true))
var nukeQuery = AllEntityQuery<NukeComponent, TransformComponent>();
var centcomms = _emergency.GetCentcommMaps();
while (nukeQuery.MoveNext(out var nuke, out var nukeTransform))
{
if (nuke.Status != NukeStatus.ARMED)
continue;
// UH OH
if (nukeTransform.MapID == _emergency.CentComMap)
if (centcomms.Contains(nukeTransform.MapID))
{
component.WinConditions.Add(WinCondition.NukeActiveAtCentCom);
SetWinType(uid, WinType.OpsMajor, component);
@@ -259,10 +262,12 @@ public sealed class NukeopsRuleSystem : GameRuleSystem<NukeopsRuleComponent>
component.WinConditions.Add(WinCondition.SomeNukiesAlive);
var diskAtCentCom = false;
foreach (var (_, transform) in EntityManager.EntityQuery<NukeDiskComponent, TransformComponent>())
var diskQuery = AllEntityQuery<NukeDiskComponent, TransformComponent>();
while (diskQuery.MoveNext(out _, out var transform))
{
var diskMapId = transform.MapID;
diskAtCentCom = _emergency.CentComMap == diskMapId;
diskAtCentCom = centcomms.Contains(diskMapId);
// TODO: The target station should be stored, and the nuke disk should store its original station.
// This is fine for now, because we can assume a single station in base SS14.

View File

@@ -0,0 +1,28 @@
using Robust.Shared.Map;
using Robust.Shared.Utility;
namespace Content.Server.Shuttles.Components;
/// <summary>
/// Spawns Central Command (emergency destination) for a station.
/// </summary>
[RegisterComponent]
public sealed class StationCentcommComponent : Component
{
/// <summary>
/// Crude shuttle offset spawning.
/// </summary>
[DataField("shuttleIndex")]
public float ShuttleIndex;
[DataField("map")]
public ResPath Map = new("/Maps/centcomm.yml");
/// <summary>
/// Centcomm entity that was loaded.
/// </summary>
[DataField("entity")]
public EntityUid Entity = EntityUid.Invalid;
public MapId MapId = MapId.Nullspace;
}

View File

@@ -154,27 +154,28 @@ public sealed partial class EmergencyShuttleSystem
{
_launchedShuttles = true;
if (CentComMap != null)
{
var dataQuery = AllEntityQuery<StationEmergencyShuttleComponent>();
while (dataQuery.MoveNext(out var comp))
while (dataQuery.MoveNext(out var stationUid, out var comp))
{
if (!TryComp<ShuttleComponent>(comp.EmergencyShuttle, out var shuttle) ||
!TryComp<StationCentcommComponent>(stationUid, out var centcomm))
{
if (!TryComp<ShuttleComponent>(comp.EmergencyShuttle, out var shuttle))
continue;
}
if (Deleted(CentComGrid))
if (Deleted(centcomm.Entity))
{
// TODO: Need to get non-overlapping positions.
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
new EntityCoordinates(
_mapManager.GetMapEntityId(CentComMap.Value),
_mapManager.GetMapEntityId(centcomm.MapId),
_random.NextVector2(1000f)), _consoleAccumulator, TransitTime);
}
else
{
_shuttle.FTLTravel(comp.EmergencyShuttle.Value, shuttle,
CentComGrid.Value, _consoleAccumulator, TransitTime, true);
centcomm.Entity, _consoleAccumulator, TransitTime, true);
}
}
@@ -188,19 +189,21 @@ public sealed partial class EmergencyShuttleSystem
podLaunchOffset += _random.NextFloat(0.5f, 2.5f);
}
}
}
var podLaunchQuery = EntityQueryEnumerator<EscapePodComponent, ShuttleComponent>();
while (podLaunchQuery.MoveNext(out var uid, out var pod, out var shuttle))
{
if (CentComGrid == null || pod.LaunchTime == null || pod.LaunchTime < _timing.CurTime)
var stationUid = _station.GetOwningStation(uid);
if (!TryComp<StationCentcommComponent>(stationUid, out var centcomm) ||
Deleted(centcomm.Entity) || pod.LaunchTime == null || pod.LaunchTime < _timing.CurTime)
{
continue;
}
// Don't dock them. If you do end up doing this then stagger launch.
_shuttle.FTLTravel(uid, shuttle,
CentComGrid.Value, hyperspaceTime: TransitTime);
_shuttle.FTLTravel(uid, shuttle, centcomm.Entity, hyperspaceTime: TransitTime);
RemCompDeferred<EscapePodComponent>(uid);
}
@@ -210,16 +213,22 @@ public sealed partial class EmergencyShuttleSystem
_leftShuttles = true;
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("emergency-shuttle-left", ("transitTime", $"{TransitTime:0}")));
_roundEndCancelToken = new CancellationTokenSource();
Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken.Token);
Timer.Spawn((int) (TransitTime * 1000) + _bufferTime.Milliseconds, () => _roundEnd.EndRound(), _roundEndCancelToken?.Token ?? default);
}
// All the others.
if (_consoleAccumulator < minTime)
{
var query = AllEntityQuery<StationCentcommComponent>();
// Guarantees that emergency shuttle arrives first before anyone else can FTL.
if (CentComGrid != null)
_shuttle.AddFTLDestination(CentComGrid.Value, true);
while (query.MoveNext(out var comp))
{
if (Deleted(comp.Entity))
continue;
_shuttle.AddFTLDestination(comp.Entity, true);
}
}
}
@@ -371,7 +380,9 @@ public sealed partial class EmergencyShuttleSystem
public bool DelayEmergencyRoundEnd()
{
if (_roundEndCancelToken == null) return false;
if (_roundEndCancelToken == null)
return false;
_roundEndCancelToken?.Cancel();
_roundEndCancelToken = null;
return true;

View File

@@ -1,4 +1,4 @@
using System.Diagnostics;
using System.Threading;
using Content.Server.Access.Systems;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
@@ -23,7 +23,6 @@ using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Random;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Server.Shuttles.Systems;
@@ -54,14 +53,6 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
private ISawmill _sawmill = default!;
public MapId? CentComMap { get; private set; }
public EntityUid? CentComGrid { get; private set; }
/// <summary>
/// Used for multiple shuttle spawn offsets.
/// </summary>
private float _shuttleIndex;
private const float ShuttleSpawnBuffer = 1f;
private bool _emergencyShuttleEnabled;
@@ -76,14 +67,35 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
_configManager.OnValueChanged(CCVars.EmergencyShuttleEnabled, SetEmergencyShuttleEnabled);
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
SubscribeLocalEvent<StationEmergencyShuttleComponent, ComponentStartup>(OnStationStartup);
SubscribeLocalEvent<StationCentcommComponent, ComponentShutdown>(OnCentcommShutdown);
SubscribeLocalEvent<StationCentcommComponent, ComponentInit>(OnCentcommInit);
SubscribeNetworkEvent<EmergencyShuttleRequestPositionMessage>(OnShuttleRequestPosition);
InitializeEmergencyConsole();
}
private void OnRoundStart(RoundStartingEvent ev)
{
CleanupEmergencyConsole();
_roundEndCancelToken?.Cancel();
_roundEndCancelToken = new CancellationTokenSource();
}
private void OnCentcommShutdown(EntityUid uid, StationCentcommComponent component, ComponentShutdown args)
{
QueueDel(component.Entity);
component.Entity = EntityUid.Invalid;
if (_mapManager.MapExists(component.MapId))
_mapManager.DeleteMap(component.MapId);
component.MapId = MapId.Nullspace;
}
private void SetEmergencyShuttleEnabled(bool value)
{
if (_emergencyShuttleEnabled == value)
return;
_emergencyShuttleEnabled = value;
if (value)
@@ -96,6 +108,16 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
}
}
private void CleanupEmergencyShuttle()
{
var query = AllEntityQuery<StationCentcommComponent>();
while (query.MoveNext(out var uid, out _))
{
RemCompDeferred<StationCentcommComponent>(uid);
}
}
public override void Update(float frameTime)
{
base.Update(frameTime);
@@ -146,22 +168,22 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
/// <summary>
/// Calls the emergency shuttle for the station.
/// </summary>
public void CallEmergencyShuttle(EntityUid? stationUid)
public void CallEmergencyShuttle(EntityUid stationUid, StationEmergencyShuttleComponent? stationShuttle = null)
{
if (!TryComp<StationEmergencyShuttleComponent>(stationUid, out var stationShuttle) ||
if (!Resolve(stationUid, ref stationShuttle) ||
!TryComp<TransformComponent>(stationShuttle.EmergencyShuttle, out var xform) ||
!TryComp<ShuttleComponent>(stationShuttle.EmergencyShuttle, out var shuttle))
{
return;
}
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(stationUid.Value));
var targetGrid = _station.GetLargestGrid(Comp<StationDataComponent>(stationUid));
// UHH GOOD LUCK
if (targetGrid == null)
{
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} unable to dock with station {ToPrettyString(stationUid.Value)}");
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-good-luck"), playDefaultSound: false);
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to dock with station {ToPrettyString(stationUid)}");
_chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-good-luck"), playDefaultSound: false);
// TODO: Need filter extensions or something don't blame me.
_audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
return;
@@ -174,10 +196,10 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
{
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
_chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-docked", ("time", $"{_consoleAccumulator:0}"), ("direction", angle.GetDir())), playDefaultSound: false);
}
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} docked with stations");
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} docked with stations");
// TODO: Need filter extensions or something don't blame me.
_audio.PlayGlobal("/Audio/Announcements/shuttle_dock.ogg", Filter.Broadcast(), true);
}
@@ -186,35 +208,33 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
if (TryComp<TransformComponent>(targetGrid.Value, out var targetXform))
{
var angle = _dock.GetAngle(stationShuttle.EmergencyShuttle.Value, xform, targetGrid.Value, targetXform, xformQuery);
_chatSystem.DispatchStationAnnouncement(stationUid.Value, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
_chatSystem.DispatchStationAnnouncement(stationUid, Loc.GetString("emergency-shuttle-nearby", ("direction", angle.GetDir())), playDefaultSound: false);
}
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid.Value)} unable to find a valid docking port for {ToPrettyString(stationUid.Value)}");
_logger.Add(LogType.EmergencyShuttle, LogImpact.High, $"Emergency shuttle {ToPrettyString(stationUid)} unable to find a valid docking port for {ToPrettyString(stationUid)}");
// TODO: Need filter extensions or something don't blame me.
_audio.PlayGlobal("/Audio/Misc/notice1.ogg", Filter.Broadcast(), true);
}
}
private void OnStationStartup(EntityUid uid, StationEmergencyShuttleComponent component, ComponentStartup args)
private void OnCentcommInit(EntityUid uid, StationCentcommComponent component, ComponentInit args)
{
AddEmergencyShuttle(component);
if (!_emergencyShuttleEnabled)
return;
// Post mapinit? fancy
if (TryComp<TransformComponent>(component.Entity, out var xform))
{
component.MapId = xform.MapID;
return;
}
private void OnRoundStart(RoundStartingEvent ev)
AddCentcomm(component);
}
private void OnStationStartup(EntityUid uid, StationEmergencyShuttleComponent component, ComponentStartup args)
{
if (CentComMap != null)
_mapManager.DeleteMap(CentComMap.Value);
// Just in case the grid isn't on the map.
DebugTools.Assert(Deleted(CentComGrid));
if (CentComGrid != null)
Del(CentComGrid.Value);
CentComGrid = null;
CentComMap = null;
CleanupEmergencyConsole();
SetupEmergencyShuttle();
AddEmergencyShuttle(uid, component);
}
/// <summary>
@@ -234,14 +254,11 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
_consoleAccumulator = _configManager.GetCVar(CCVars.EmergencyShuttleDockTime);
EmergencyShuttleArrived = true;
if (CentComMap != null)
_mapManager.SetMapPaused(CentComMap.Value, false);
var query = AllEntityQuery<StationDataComponent>();
var query = AllEntityQuery<StationEmergencyShuttleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
CallEmergencyShuttle(uid);
CallEmergencyShuttle(uid, comp);
}
_commsConsole.UpdateCommsConsoleInterface();
@@ -249,80 +266,111 @@ public sealed partial class EmergencyShuttleSystem : EntitySystem
private void SetupEmergencyShuttle()
{
if (!_emergencyShuttleEnabled || CentComMap != null && _mapManager.MapExists(CentComMap.Value)) return;
if (!_emergencyShuttleEnabled)
return;
CentComMap = _mapManager.CreateMap();
_mapManager.SetMapPaused(CentComMap.Value, true);
var centcommQuery = AllEntityQuery<StationCentcommComponent>();
// Load CentCom
var centComPath = _configManager.GetCVar(CCVars.CentcommMap);
if (!string.IsNullOrEmpty(centComPath))
while (centcommQuery.MoveNext(out var centcomm))
{
var centcomm = _map.LoadGrid(CentComMap.Value, "/Maps/centcomm.yml");
CentComGrid = centcomm;
AddCentcomm(centcomm);
}
if (CentComGrid != null)
_shuttle.AddFTLDestination(CentComGrid.Value, false);
var query = AllEntityQuery<StationEmergencyShuttleComponent>();
while (query.MoveNext(out var uid, out var comp))
{
AddEmergencyShuttle(uid, comp);
}
}
private void AddCentcomm(StationCentcommComponent component)
{
// Check for existing centcomms and just point to that
var query = AllEntityQuery<StationCentcommComponent>();
while (query.MoveNext(out var uid, out var otherComp))
{
if (otherComp == component)
continue;
component.MapId = otherComp.MapId;
component.ShuttleIndex = otherComp.ShuttleIndex;
return;
}
var mapId = _mapManager.CreateMap();
component.MapId = mapId;
if (!string.IsNullOrEmpty(component.Map.ToString()))
{
var ent = _map.LoadGrid(mapId, component.Map.ToString());
if (ent != null)
{
component.Entity = ent.Value;
_shuttle.AddFTLDestination(ent.Value, false);
}
}
else
{
_sawmill.Info("No CentCom map found, skipping setup.");
_sawmill.Warning("No CentComm map found, skipping setup.");
}
}
foreach (var comp in EntityQuery<StationEmergencyShuttleComponent>(true))
public HashSet<MapId> GetCentcommMaps()
{
AddEmergencyShuttle(comp);
}
var query = AllEntityQuery<StationCentcommComponent>();
var maps = new HashSet<MapId>(Count<StationCentcommComponent>());
while (query.MoveNext(out var comp))
{
maps.Add(comp.MapId);
}
private void AddEmergencyShuttle(StationEmergencyShuttleComponent component)
return maps;
}
private void AddEmergencyShuttle(EntityUid uid, StationEmergencyShuttleComponent component)
{
if (!_emergencyShuttleEnabled
|| CentComMap == null
|| component.EmergencyShuttle != null)
|| component.EmergencyShuttle != null ||
!TryComp<StationCentcommComponent>(uid, out var centcomm))
{
return;
}
// Load escape shuttle
var shuttlePath = component.EmergencyShuttlePath;
var shuttle = _map.LoadGrid(CentComMap.Value, shuttlePath.ToString(), new MapLoadOptions()
var shuttle = _map.LoadGrid(centcomm.MapId, shuttlePath.ToString(), new MapLoadOptions()
{
// Should be far enough... right? I'm too lazy to bounds check CentCom rn.
Offset = new Vector2(500f + _shuttleIndex, 0f)
Offset = new Vector2(500f + centcomm.ShuttleIndex, 0f)
});
if (shuttle == null)
{
_sawmill.Error($"Unable to spawn emergency shuttle {shuttlePath} for {ToPrettyString(component.Owner)}");
_sawmill.Error($"Unable to spawn emergency shuttle {shuttlePath} for {ToPrettyString(uid)}");
return;
}
_shuttleIndex += _mapManager.GetGrid(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer;
centcomm.ShuttleIndex += _mapManager.GetGrid(shuttle.Value).LocalAABB.Width + ShuttleSpawnBuffer;
// Update indices for all centcomm comps pointing to same map
var query = AllEntityQuery<StationCentcommComponent>();
while (query.MoveNext(out var comp))
{
if (comp == centcomm || comp.MapId != centcomm.MapId)
continue;
comp.ShuttleIndex = comp.ShuttleIndex;
}
component.EmergencyShuttle = shuttle;
EnsureComp<ProtectedGridComponent>(shuttle.Value);
}
private void CleanupEmergencyShuttle()
{
// If we get cleaned up mid roundend just end it.
if (_launchedShuttles)
{
_roundEnd.EndRound();
}
_shuttleIndex = 0f;
if (CentComMap == null || !_mapManager.MapExists(CentComMap.Value))
{
CentComMap = null;
return;
}
_mapManager.DeleteMap(CentComMap.Value);
}
private void OnEscapeUnpaused(EntityUid uid, EscapePodComponent component, ref EntityUnpausedEvent args)
{
if (component.LaunchTime == null)

View File

@@ -1,4 +1,5 @@
using Content.Server.Shuttles.Components;
using Content.Server.Station.Components;
using Content.Shared.CCVar;
namespace Content.Server.Shuttles.Systems;
@@ -39,6 +40,12 @@ public sealed partial class ShuttleSystem
if (config != null)
{
FTLDock(config, shuttleXform);
if (TryComp<StationMemberComponent>(xform.GridUid, out var stationMember))
{
_station.AddGridToStation(stationMember.Station, ent[0]);
}
valid = true;
}
}

View File

@@ -1,6 +1,7 @@
using Content.Server.Body.Systems;
using Content.Server.Doors.Systems;
using Content.Server.Shuttles.Components;
using Content.Server.Station.Systems;
using Content.Server.Stunnable;
using Content.Shared.GameTicking;
using Content.Shared.Mobs.Systems;
@@ -33,6 +34,7 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
[Dependency] private readonly ShuttleConsoleSystem _console = default!;
[Dependency] private readonly StationSystem _station = default!;
[Dependency] private readonly StunSystem _stuns = default!;
[Dependency] private readonly ThrusterSystem _thruster = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;

View File

@@ -1171,12 +1171,6 @@ namespace Content.Shared.CCVar
public static readonly CVarDef<int> EmergencyShuttleAutoCallExtensionTime =
CVarDef.Create("shuttle.auto_call_extension_time", 45, CVar.SERVERONLY);
/// <summary>
/// The map to load for CentCom for the emergency shuttle to dock to.
/// </summary>
public static readonly CVarDef<string> CentcommMap =
CVarDef.Create("shuttle.centcomm_map", "/Maps/centcomm.yml", CVar.SERVERONLY);
/*
* Crew Manifests
*/

View File

@@ -31,6 +31,12 @@
components:
- type: StationArrivals
- type: entity
id: BaseStationCentcomm
abstract: true
components:
- type: StationCentcomm
- type: entity
id: BaseStationEvacuation
abstract: true

View File

@@ -14,6 +14,7 @@
- BaseStationJobsSpawning
- BaseStationRecords
- BaseStationArrivals
- BaseStationCentcomm
- BaseStationEvacuation
- BaseStationAlertLevels
- BaseStationExpeditions