diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs index 39e0289d47..cdc701d36d 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs @@ -1,7 +1,9 @@ -using Content.Server.GameObjects.Components.NodeContainer; +#nullable enable +using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Log; using Robust.Shared.ViewVariables; using System.Linq; @@ -9,46 +11,34 @@ using System.Linq; namespace Content.Server.GameObjects.Components.Atmos.Piping { [RegisterComponent] - public class GasCanisterPortComponent : PipeNetDeviceComponent + public class GasCanisterPortComponent : Component { public override string Name => "GasCanisterPort"; [ViewVariables] - public GasCanisterComponent ConnectedCanister { get; private set; } + public GasCanisterComponent? ConnectedCanister { get; private set; } [ViewVariables] public bool ConnectedToCanister => ConnectedCanister != null; [ViewVariables] - private PipeNode _gasPort; + private PipeNode? _gasPort; public override void Initialize() { base.Initialize(); - if (!Owner.TryGetComponent(out var container)) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(GasCanisterPortComponent)} on entity {Owner.Uid} did not have a {nameof(NodeContainerComponent)}."); - return; - } - _gasPort = container.Nodes.OfType().FirstOrDefault(); - if (_gasPort == null) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(GasCanisterPortComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); - return; - } + Owner.EnsureComponentWarn(); + SetGasPort(); if (Owner.TryGetComponent(out var snapGrid)) { - var anchoredCanister = snapGrid.GetLocal() - .Select(entity => entity.TryGetComponent(out var canister) ? canister : null) - .Where(canister => canister != null) - .Where(canister => canister.Anchored) - .Where(canister => !canister.ConnectedToPort) - .FirstOrDefault(); - if (anchoredCanister != null) + var entities = snapGrid.GetLocal(); + foreach (var entity in entities) { - anchoredCanister.TryConnectToPort(); + if (entity.TryGetComponent(out var canister) && canister.Anchored && !canister.ConnectedToPort) + { + canister.TryConnectToPort(); + break; + } } } } @@ -59,10 +49,24 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping ConnectedCanister?.DisconnectFromPort(); } - public override void Update() + public override void HandleMessage(ComponentMessage message, IComponent? component) { - ConnectedCanister?.Air.Share(_gasPort.Air, 1); - ConnectedCanister?.AirWasUpdated(); + base.HandleMessage(message, component); + switch (message) + { + case PipeNetUpdateMessage: + Update(); + break; + } + } + + public void Update() + { + if (_gasPort == null || ConnectedCanister == null) + return; + + ConnectedCanister.Air.Share(_gasPort.Air, 1); + ConnectedCanister.AirWasUpdated(); } public void ConnectGasCanister(GasCanisterComponent gasCanister) @@ -74,5 +78,20 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping { ConnectedCanister = null; } + + private void SetGasPort() + { + if (!Owner.TryGetComponent(out var container)) + { + Logger.Error($"{typeof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + return; + } + _gasPort = container.Nodes.OfType().FirstOrDefault(); + if (_gasPort == null) + { + Logger.Error($"{typeof(GasCanisterPortComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + return; + } + } } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs index 3f41f36f37..0b2b94d92f 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/PipeNetDeviceComponent.cs @@ -1,4 +1,5 @@ -using Content.Server.Atmos; +#nullable enable +using Content.Server.Atmos; using Content.Server.GameObjects.EntitySystems; using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; @@ -9,11 +10,14 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping /// Adds itself to a to be updated by. /// TODO: Make compatible with unanchoring/anchoring. Currently assumes that the Owner does not move. /// - public abstract class PipeNetDeviceComponent : Component + [RegisterComponent] + public class PipeNetDeviceComponent : Component { - public abstract void Update(); + public override string Name => "PipeNetDevice"; - protected IGridAtmosphereComponent JoinedGridAtmos { get; private set; } + private IGridAtmosphereComponent? JoinedGridAtmos { get; set; } + + private PipeNetUpdateMessage _cachedUpdateMessage = new(); public override void Initialize() { @@ -27,6 +31,11 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping LeaveGridAtmos(); } + public void Update() + { + SendMessage(_cachedUpdateMessage); + } + private void JoinGridAtmos() { var gridAtmos = EntitySystem.Get() @@ -41,4 +50,9 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping JoinedGridAtmos = null; } } + + public class PipeNetUpdateMessage : ComponentMessage + { + + } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs index d3521e9c8a..6c9558b035 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Pumps/BasePumpComponent.cs @@ -1,11 +1,12 @@ -using System.Linq; +#nullable enable +using System.Linq; using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Shared.GameObjects.Components.Atmos; using Robust.Server.GameObjects; using Robust.Shared.GameObjects; -using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Log; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -15,7 +16,7 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps /// /// Transfer gas from one to another. /// - public abstract class BasePumpComponent : PipeNetDeviceComponent + public abstract class BasePumpComponent : Component { /// /// If the pump is currently pumping. @@ -33,87 +34,88 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Pumps private bool _pumpEnabled; /// - /// Needs to be same as that of a on this entity. + /// Needs to be same as that of a on this entity. /// [ViewVariables] - private PipeDirection _inletDirection; + private PipeDirection _initialInletDirection; /// - /// Needs to be same as that of a on this entity. + /// Needs to be same as that of a on this entity. /// [ViewVariables] - private PipeDirection _outletDirection; + private PipeDirection _initialOutletDirection; [ViewVariables] - private PipeNode _inletPipe; + private PipeNode? _inletPipe; [ViewVariables] - private PipeNode _outletPipe; + private PipeNode? _outletPipe; - private AppearanceComponent _appearance; + private AppearanceComponent? _appearance; public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); - serializer.DataField(ref _inletDirection, "inletDirection", PipeDirection.None); - serializer.DataField(ref _outletDirection, "outletDirection", PipeDirection.None); + serializer.DataField(ref _initialInletDirection, "inletDirection", PipeDirection.None); + serializer.DataField(ref _initialOutletDirection, "outletDirection", PipeDirection.None); serializer.DataField(ref _pumpEnabled, "pumpEnabled", false); } public override void Initialize() { base.Initialize(); - UpdatePipes(); - Owner.EntityManager.EventBus.SubscribeEvent(EventSource.Local, this, RotateEvent); + Owner.EnsureComponentWarn(); + SetPipes(); Owner.TryGetComponent(out _appearance); UpdateAppearance(); } - public override void Update() + public override void HandleMessage(ComponentMessage message, IComponent? component) + { + base.HandleMessage(message, component); + switch (message) + { + case PipeNetUpdateMessage: + Update(); + break; + } + } + + public void Update() { if (!PumpEnabled) return; + if (_inletPipe == null || _outletPipe == null) + return; + PumpGas(_inletPipe.Air, _outletPipe.Air); } protected abstract void PumpGas(GasMixture inletGas, GasMixture outletGas); - private void RotateEvent(RotateEvent ev) - { - if (ev.Sender != Owner || ev.NewRotation == ev.OldRotation) - return; - - var diff = ev.NewRotation - ev.OldRotation; - _inletDirection = _inletDirection.RotatePipeDirection(diff); - _outletDirection = _outletDirection.RotatePipeDirection(diff); - UpdatePipes(); - } - private void UpdateAppearance() { if (_inletPipe == null || _outletPipe == null) return; - _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_inletDirection, _outletDirection, _inletPipe.ConduitLayer, _outletPipe.ConduitLayer, PumpEnabled)); + _appearance?.SetData(PumpVisuals.VisualState, new PumpVisualState(_initialInletDirection, _initialOutletDirection, _inletPipe.ConduitLayer, _outletPipe.ConduitLayer, PumpEnabled)); } - private void UpdatePipes() + private void SetPipes() { _inletPipe = null; _outletPipe = null; if (!Owner.TryGetComponent(out var container)) { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BasePumpComponent)} on entity {Owner.Uid} did not have a {nameof(NodeContainerComponent)}."); + Logger.Error($"{typeof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); return; } var pipeNodes = container.Nodes.OfType(); - _inletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _inletDirection).FirstOrDefault(); - _outletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _outletDirection).FirstOrDefault(); - if (_inletPipe == null | _outletPipe == null) + _inletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialInletDirection).FirstOrDefault(); + _outletPipe = pipeNodes.Where(pipe => pipe.PipeDirection == _initialOutletDirection).FirstOrDefault(); + if (_inletPipe == null || _outletPipe == null) { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BasePumpComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + Logger.Error($"{typeof(BasePumpComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); return; } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs index 77acc61780..fe30881d58 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Scrubbers/BaseSiphonComponent.cs @@ -1,13 +1,14 @@ -using System.Linq; +#nullable enable +using System.Linq; using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Atmos; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.ViewVariables; @@ -16,13 +17,13 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Scrubbers /// /// Transfers gas from the tile it is on to a . /// - public abstract class BaseSiphonComponent : PipeNetDeviceComponent + public abstract class BaseSiphonComponent : Component { [ViewVariables] - private PipeNode _scrubberOutlet; + private PipeNode? _scrubberOutlet; - private AtmosphereSystem _atmosSystem; + private AtmosphereSystem? _atmosSystem; [ViewVariables(VVAccess.ReadWrite)] public bool SiphonEnabled @@ -36,43 +37,60 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Scrubbers } private bool _siphonEnabled = true; - private AppearanceComponent _appearance; + private AppearanceComponent? _appearance; public override void Initialize() { base.Initialize(); + Owner.EnsureComponentWarn(); _atmosSystem = EntitySystem.Get(); - if (!Owner.TryGetComponent(out var container)) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BaseSiphonComponent)} on entity {Owner.Uid} did not have a {nameof(NodeContainerComponent)}."); - return; - } - _scrubberOutlet = container.Nodes.OfType().FirstOrDefault(); - if (_scrubberOutlet == null) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BaseSiphonComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); - return; - } + SetOutlet(); Owner.TryGetComponent(out _appearance); UpdateAppearance(); } - public override void Update() + public override void HandleMessage(ComponentMessage message, IComponent? component) + { + base.HandleMessage(message, component); + switch (message) + { + case PipeNetUpdateMessage: + Update(); + break; + } + } + + public void Update() { if (!SiphonEnabled) return; var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(Owner.EntityManager); - if (tileAtmos == null) + + if (_scrubberOutlet == null || tileAtmos == null || tileAtmos.Air == null) return; + ScrubGas(tileAtmos.Air, _scrubberOutlet.Air); tileAtmos.Invalidate(); } protected abstract void ScrubGas(GasMixture inletGas, GasMixture outletGas); + private void SetOutlet() + { + if (!Owner.TryGetComponent(out var container)) + { + Logger.Error($"{typeof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + return; + } + _scrubberOutlet = container.Nodes.OfType().FirstOrDefault(); + if (_scrubberOutlet == null) + { + Logger.Error($"{typeof(BaseSiphonComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + return; + } + } + private void UpdateAppearance() { _appearance?.SetData(SiphonVisuals.VisualState, new SiphonVisualState(SiphonEnabled)); diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs index 8c0ba7f833..db4508959b 100644 --- a/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/Piping/Vents/BaseVentComponent.cs @@ -1,13 +1,14 @@ -using System.Linq; +#nullable enable +using System.Linq; using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer; using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.EntitySystems; using Content.Shared.GameObjects.Components.Atmos; using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; using Robust.Shared.GameObjects.Systems; using Robust.Shared.Interfaces.GameObjects; -using Robust.Shared.IoC; using Robust.Shared.Log; using Robust.Shared.ViewVariables; @@ -16,13 +17,13 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Vents /// /// Transfers gas from a to the tile it is on. /// - public abstract class BaseVentComponent : PipeNetDeviceComponent + public abstract class BaseVentComponent : Component { [ViewVariables] - private PipeNode _ventInlet; + private PipeNode? _ventInlet; - private AtmosphereSystem _atmosSystem; + private AtmosphereSystem? _atmosSystem; [ViewVariables(VVAccess.ReadWrite)] public bool VentEnabled @@ -36,43 +37,60 @@ namespace Content.Server.GameObjects.Components.Atmos.Piping.Vents } private bool _ventEnabled = true; - private AppearanceComponent _appearance; + private AppearanceComponent? _appearance; public override void Initialize() { base.Initialize(); + Owner.EnsureComponentWarn(); _atmosSystem = EntitySystem.Get(); - if (!Owner.TryGetComponent(out var container)) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BaseVentComponent)} on entity {Owner.Uid} did not have a {nameof(NodeContainerComponent)}."); - return; - } - _ventInlet = container.Nodes.OfType().FirstOrDefault(); - if (_ventInlet == null) - { - JoinedGridAtmos?.RemovePipeNetDevice(this); - Logger.Error($"{typeof(BaseVentComponent)} on entity {Owner.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); - return; - } + SetInlet(); Owner.TryGetComponent(out _appearance); UpdateAppearance(); } - public override void Update() + public override void HandleMessage(ComponentMessage message, IComponent? component) + { + base.HandleMessage(message, component); + switch (message) + { + case PipeNetUpdateMessage: + Update(); + break; + } + } + + public void Update() { if (!VentEnabled) return; var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(Owner.EntityManager); - if (tileAtmos == null) + + if (_ventInlet == null || tileAtmos == null || tileAtmos.Air == null) return; + VentGas(_ventInlet.Air, tileAtmos.Air); tileAtmos.Invalidate(); } protected abstract void VentGas(GasMixture inletGas, GasMixture outletGas); + private void SetInlet() + { + if (!Owner.TryGetComponent(out var container)) + { + Logger.Error($"{typeof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} did not have a {nameof(NodeContainerComponent)}."); + return; + } + _ventInlet = container.Nodes.OfType().FirstOrDefault(); + if (_ventInlet == null) + { + Logger.Error($"{typeof(BaseVentComponent)} on {Owner?.Prototype?.ID}, Uid {Owner?.Uid} could not find compatible {nameof(PipeNode)}s on its {nameof(NodeContainerComponent)}."); + return; + } + } + private void UpdateAppearance() { _appearance?.SetData(VentVisuals.VisualState, new VentVisualState(VentEnabled));