Files
tbd-station-14/Content.Server/Atmos/Monitor/Components/AirAlarmComponent.cs
Flipp Syder 565bfa86a4 Air alarm fixes (again, oops) (#7715)
* fixes critical issue

* alright, this might be the actual fix

* removes useless null checks

* couple more

* removes default functions from unary device data
2022-04-22 23:21:00 -07:00

221 lines
8.1 KiB
C#

using System;
using System.Threading;
using System.Collections.Generic;
using Content.Server.Atmos.Monitor.Systems;
using Content.Server.DeviceNetwork.Components;
using Content.Server.Power.Components;
using Content.Server.VendingMachines; // TODO: Move this out of vending machines???
using Content.Server.WireHacking;
using Content.Shared.Atmos.Monitor.Components;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Network;
using Robust.Shared.ViewVariables;
using static Content.Shared.Wires.SharedWiresComponent;
using static Content.Shared.Wires.SharedWiresComponent.WiresAction;
namespace Content.Server.Atmos.Monitor.Components
{
[RegisterComponent]
public sealed class AirAlarmComponent : Component, IWires
{
[Dependency] private readonly IEntityManager _entMan = default!;
private AirAlarmSystem? _airAlarmSystem;
[ViewVariables] public AirAlarmMode CurrentMode { get; set; } = AirAlarmMode.Filtering;
// Remember to null this afterwards.
[ViewVariables] public IAirAlarmModeUpdate? CurrentModeUpdater { get; set; }
public Dictionary<string, IAtmosDeviceData> DeviceData = new();
public HashSet<NetUserId> ActivePlayers = new();
public bool FullAccess = false;
public bool CanSync = true;
// <-- Wires -->
private CancellationTokenSource _powerPulsedCancel = new();
private int PowerPulsedTimeout = 30;
private enum Wires
{
// Cutting this kills power.
// Pulsing it disrupts power.
Power,
// Cutting this allows full access.
// Pulsing this does nothing.
Access,
// Cutting/Remending this resets ONLY from panic mode.
// Pulsing this sets panic mode.
Panic,
// Cutting this clears sync'd devices, and makes
// the alarm unable to resync.
// Pulsing this resyncs all devices (ofc current
// implementation just auto-does this anyways)
DeviceSync,
// This does nothing. (placeholder for AI wire,
// if that ever gets implemented)
Dummy
}
public void RegisterWires(WiresComponent.WiresBuilder builder)
{
foreach (var wire in Enum.GetValues<Wires>())
builder.CreateWire(wire);
UpdateWires();
}
public void UpdateWires()
{
if (_airAlarmSystem == null)
_airAlarmSystem = EntitySystem.Get<AirAlarmSystem>();
if (!_entMan.TryGetComponent<WiresComponent>(Owner, out var wires)) return;
var pwrLightState = (PowerPulsed, PowerCut) switch {
(true, false) => StatusLightState.BlinkingFast,
(_, true) => StatusLightState.Off,
(_, _) => StatusLightState.On
};
var powerLight = new StatusLightData(Color.Yellow, pwrLightState, "POWR");
var accessLight = new StatusLightData(
Color.Green,
wires.IsWireCut(Wires.Access) ? StatusLightState.Off : StatusLightState.On,
"ACC"
);
var panicLight = new StatusLightData(
Color.Red,
CurrentMode == AirAlarmMode.Panic ? StatusLightState.On : StatusLightState.Off,
"PAN"
);
var syncLightState = StatusLightState.BlinkingSlow;
if (_entMan.TryGetComponent<AtmosMonitorComponent>(Owner, out var atmosMonitorComponent) && !atmosMonitorComponent.NetEnabled)
syncLightState = StatusLightState.Off;
else if (DeviceData.Count != 0)
syncLightState = StatusLightState.On;
var syncLight = new StatusLightData(Color.Orange, syncLightState, "NET");
wires.SetStatus(AirAlarmWireStatus.Power, powerLight);
wires.SetStatus(AirAlarmWireStatus.Access, accessLight);
wires.SetStatus(AirAlarmWireStatus.Panic, panicLight);
wires.SetStatus(AirAlarmWireStatus.DeviceSync, syncLight);
}
private bool _powerCut;
private bool PowerCut
{
get => _powerCut;
set
{
_powerCut = value;
SetPower();
}
}
private bool _powerPulsed;
private bool PowerPulsed
{
get => _powerPulsed && !_powerCut;
set
{
_powerPulsed = value;
SetPower();
}
}
private void SetPower()
{
if (_entMan.TryGetComponent<ApcPowerReceiverComponent>(Owner, out var receiverComponent)
&& _entMan.HasComponent<WiresComponent>(Owner))
receiverComponent.PowerDisabled = PowerPulsed || PowerCut;
}
public void WiresUpdate(WiresUpdateEventArgs args)
{
if (!_entMan.TryGetComponent<DeviceNetworkComponent>(Owner, out var deviceNetworkComponent)) return;
if (_airAlarmSystem == null)
_airAlarmSystem = EntitySystem.Get<AirAlarmSystem>();
switch (args.Action)
{
case Pulse:
switch (args.Identifier)
{
case Wires.Power:
PowerPulsed = true;
_powerPulsedCancel.Cancel();
_powerPulsedCancel = new CancellationTokenSource();
Owner.SpawnTimer(TimeSpan.FromSeconds(PowerPulsedTimeout),
() => PowerPulsed = false,
_powerPulsedCancel.Token);
break;
case Wires.Panic:
if (CurrentMode != AirAlarmMode.Panic)
_airAlarmSystem.SetMode(Owner, deviceNetworkComponent.Address, AirAlarmMode.Panic, true, false);
break;
case Wires.DeviceSync:
_airAlarmSystem.SyncAllDevices(Owner);
break;
}
break;
case Mend:
switch (args.Identifier)
{
case Wires.Power:
_powerPulsedCancel.Cancel();
PowerPulsed = false;
PowerCut = false;
break;
case Wires.Panic:
if (CurrentMode == AirAlarmMode.Panic)
_airAlarmSystem.SetMode(Owner, deviceNetworkComponent.Address, AirAlarmMode.Filtering, true, false);
break;
case Wires.Access:
FullAccess = false;
break;
case Wires.DeviceSync:
if (_entMan.TryGetComponent<AtmosMonitorComponent>(Owner, out var atmosMonitorComponent))
atmosMonitorComponent.NetEnabled = true;
break;
}
break;
case Cut:
switch (args.Identifier)
{
case Wires.DeviceSync:
DeviceData.Clear();
if (_entMan.TryGetComponent<AtmosMonitorComponent>(Owner, out var atmosMonitorComponent))
{
atmosMonitorComponent.NetworkAlarmStates.Clear();
atmosMonitorComponent.NetEnabled = false;
}
break;
case Wires.Power:
PowerCut = true;
break;
case Wires.Access:
FullAccess = true;
break;
}
break;
}
UpdateWires();
}
}
}