using System; using System.Collections.Generic; using System.Linq; using Content.Server.Atmos; using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.Interfaces; using Content.Shared.GameObjects.Components.Atmos; using Robust.Server.GameObjects; using Robust.Shared.GameObjects.Components.Transform; using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Maths; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.NodeContainer.Nodes { /// /// Connects with other s whose /// correctly correspond. /// public class PipeNode : Node, IGasMixtureHolder, IRotatableNode { [ViewVariables] public PipeDirection PipeDirection { get => _pipeDirection; set => SetPipeDirection(value); } private PipeDirection _pipeDirection; /// /// Controls what visuals are applied in . /// public ConduitLayer ConduitLayer => _conduitLayer; private ConduitLayer _conduitLayer; [ViewVariables] private IPipeNet _pipeNet = PipeNet.NullNet; [ViewVariables] private bool _needsPipeNet = true; /// /// The gases in this pipe. /// [ViewVariables] public GasMixture Air { get => _needsPipeNet ? LocalAir : _pipeNet.Air; set { if (_needsPipeNet) LocalAir = value; else _pipeNet.Air = value; } } /// /// Stores gas in this pipe when disconnected from a . /// Only for usage by s. /// [ViewVariables] public GasMixture LocalAir { get; set; } [ViewVariables] 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 => LocalAir, "gasMixture", new GasMixture(DefaultVolume)); serializer.DataField(ref _conduitLayer, "conduitLayer", ConduitLayer.Two); } public override void Initialize(IEntity owner) { base.Initialize(owner); Owner.TryGetComponent(out _appearance); UpdateAppearance(); } public void JoinPipeNet(IPipeNet pipeNet) { _pipeNet = pipeNet; _needsPipeNet = false; } public void ClearPipeNet() { _pipeNet = PipeNet.NullNet; _needsPipeNet = true; } void IRotatableNode.RotateEvent(RotateEvent ev) { var diff = ev.NewRotation - ev.OldRotation; PipeDirection = PipeDirection.RotatePipeDirection(diff); } protected override IEnumerable GetReachableNodes() { for (var i = 0; i < PipeDirectionHelpers.PipeDirections; i++) { var pipeDirection = (PipeDirection) (1 << i); var ownNeededConnection = pipeDirection; var theirNeededConnection = ownNeededConnection.GetOpposite(); if (!_pipeDirection.HasFlag(ownNeededConnection)) { continue; } var pipeNodesInDirection = Owner.GetComponent() .GetInDir(pipeDirection.ToDirection()) .Select(entity => entity.TryGetComponent(out var container) ? container : null) .Where(container => container != null) .SelectMany(container => container.Nodes) .OfType() .Where(pipeNode => pipeNode._pipeDirection.HasFlag(theirNeededConnection)); foreach (var pipeNode in pipeNodesInDirection) { yield return pipeNode; } } } private void UpdateAppearance() { _appearance?.SetData(PipeVisuals.VisualState, new PipeVisualState(PipeDirection, ConduitLayer)); } private void SetPipeDirection(PipeDirection pipeDirection) { _pipeDirection = pipeDirection; RefreshNodeGroup(); UpdateAppearance(); } } }