diff --git a/Content.Client/IgnoredComponents.cs b/Content.Client/IgnoredComponents.cs index d234452111..4a02dd15fb 100644 --- a/Content.Client/IgnoredComponents.cs +++ b/Content.Client/IgnoredComponents.cs @@ -180,6 +180,8 @@ "Headset", "ComputerBoard", "BreakableConstruction", + "GasCanister", + "GasCanisterPort", }; } } diff --git a/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs b/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs index a2afda77de..bc35419ac1 100644 --- a/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs +++ b/Content.Server/GameObjects/Components/Atmos/GasCanisterComponent.cs @@ -1,10 +1,91 @@ -using Robust.Shared.GameObjects; +using Content.Server.Atmos; +using Content.Server.GameObjects.Components.Atmos.Piping; +using Content.Server.Interfaces; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components; +using Robust.Shared.GameObjects.Components.Transform; +using Robust.Shared.Serialization; +using Robust.Shared.ViewVariables; +using System; +using System.Linq; namespace Content.Server.GameObjects.Components.Atmos { [RegisterComponent] - public class GasCanisterComponent : Component + public class GasCanisterComponent : Component, IGasMixtureHolder { public override string Name => "GasCanister"; + + [ViewVariables] + public GasMixture Air { get; set; } + + [ViewVariables] + public bool Anchored => !Owner.TryGetComponent(out var collidable) || collidable.Anchored; + + [ViewVariables] + public GasCanisterPortComponent ConnectedPort { get; private set; } + + [ViewVariables] + public bool ConnectedToPort => ConnectedPort != null; + + private const float DefaultVolume = 10; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(this, x => Air, "gasMixture", new GasMixture(DefaultVolume)); + } + + public override void Initialize() + { + base.Initialize(); + if (Owner.TryGetComponent(out var collidable)) + { + AnchorUpdate(); + collidable.AnchoredChanged += AnchorUpdate; + } + } + + public override void OnRemove() + { + base.OnRemove(); + if (Owner.TryGetComponent(out var collidable)) + { + collidable.AnchoredChanged -= AnchorUpdate; + } + DisconnectFromPort(); + } + + + public void TryConnectToPort() + { + if (!Owner.TryGetComponent(out var snapGrid)) return; + var port = snapGrid.GetLocal() + .Select(entity => entity.TryGetComponent(out var port) ? port : null) + .Where(port => port != null) + .Where(port => !port.ConnectedToCanister) + .FirstOrDefault(); + if (port == null) return; + ConnectedPort = port; + ConnectedPort.ConnectGasCanister(this); + } + + public void DisconnectFromPort() + { + ConnectedPort?.DisconnectGasCanister(); + ConnectedPort = null; + } + + private void AnchorUpdate() + { + if (Anchored) + { + TryConnectToPort(); + } + else + { + DisconnectFromPort(); + } + } } } diff --git a/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs new file mode 100644 index 0000000000..3fe989f7a2 --- /dev/null +++ b/Content.Server/GameObjects/Components/Atmos/Piping/GasCanisterPortComponent.cs @@ -0,0 +1,77 @@ +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.Log; +using Robust.Shared.ViewVariables; +using System.Linq; + +namespace Content.Server.GameObjects.Components.Atmos.Piping +{ + [RegisterComponent] + public class GasCanisterPortComponent : PipeNetDeviceComponent + { + public override string Name => "GasCanisterPort"; + + [ViewVariables] + public GasCanisterComponent ConnectedCanister { get; private set; } + + [ViewVariables] + public bool ConnectedToCanister => ConnectedCanister != null; + + [ViewVariables] + 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; + } + 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) + { + anchoredCanister.TryConnectToPort(); + } + } + } + + public override void OnRemove() + { + base.OnRemove(); + ConnectedCanister?.DisconnectFromPort(); + } + + public override void Update() + { + ConnectedCanister?.Air.Share(_gasPort.Air, 1); + } + + public void ConnectGasCanister(GasCanisterComponent gasCanister) + { + ConnectedCanister = gasCanister; + } + + public void DisconnectGasCanister() + { + ConnectedCanister = null; + } + } +} diff --git a/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs b/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs index c3bde03905..e2c3aa4f32 100644 --- a/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs +++ b/Content.Server/GameObjects/Components/NodeContainer/Nodes/PipeNode.cs @@ -60,22 +60,23 @@ namespace Content.Server.GameObjects.Components.NodeContainer.Nodes public GasMixture LocalAir { get; set; } [ViewVariables] - public float Volume { get; private set; } + public float Volume => LocalAir.Volume; private AppearanceComponent _appearance; + private const float DefaultVolume = 1; + public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); serializer.DataField(ref _pipeDirection, "pipeDirection", PipeDirection.None); - serializer.DataField(this, x => Volume, "volume", 10); + serializer.DataField(this, x => LocalAir, "gasMixture", new GasMixture(DefaultVolume)); serializer.DataField(ref _conduitLayer, "conduitLayer", ConduitLayer.Two); } public override void Initialize(IEntity owner) { base.Initialize(owner); - LocalAir = new GasMixture(Volume); Owner.TryGetComponent(out _appearance); UpdateAppearance(); } diff --git a/Resources/Prototypes/Entities/Constructible/Ground/gascanisterports.yml b/Resources/Prototypes/Entities/Constructible/Ground/gascanisterports.yml new file mode 100644 index 0000000000..7cfdb46500 --- /dev/null +++ b/Resources/Prototypes/Entities/Constructible/Ground/gascanisterports.yml @@ -0,0 +1,30 @@ +- type: entity + abstract: true + id: GasCanisterPortBase + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: InteractionOutline + - type: Collidable + - type: SnapGrid + offset: Center + - type: Sprite + - type: Destructible + thresholdvalue: 100 + - type: GasCanisterPort + +- type: entity + parent: GasCanisterPortBase + id: FourwayGasCanisterPort + name: Fourway Gas Canister Port + components: + - type: NodeContainer + nodes: + - !type:PipeNode + nodeGroupID: Pipe + pipeDirection: Fourway + - type: Sprite + sprite: Constructible/Power/smes.rsi + state: smes + \ No newline at end of file diff --git a/Resources/Prototypes/Entities/Constructible/Ground/gascanisters.yml b/Resources/Prototypes/Entities/Constructible/Ground/gascanisters.yml new file mode 100644 index 0000000000..cddf2a7550 --- /dev/null +++ b/Resources/Prototypes/Entities/Constructible/Ground/gascanisters.yml @@ -0,0 +1,27 @@ +- type: entity + abstract: true + id: GasCanisterBase + placement: + mode: SnapgridCenter + components: + - type: Clickable + - type: InteractionOutline + - type: Collidable + - type: SnapGrid + offset: Center + - type: Sprite + - type: Destructible + thresholdvalue: 100 + - type: GasCanister + - type: Anchorable + - type: Pullable + +- type: entity + parent: GasCanisterBase + id: GasCanister + name: Gas Canister + components: + - type: Sprite + sprite: "Constructible/Power/apc.rsi" + state: apc0 + \ No newline at end of file