using System.Linq; using Content.Server.NodeContainer; using Content.Server.NodeContainer.NodeGroups; using Content.Server.NodeContainer.Nodes; using Content.Shared.NodeContainer; using Content.Shared.NodeContainer.NodeGroups; using Robust.Shared.Map.Components; using Robust.Shared.Utility; namespace Content.Server.Power.Generation.Teg; /// /// Node group that connects the central TEG with its two circulators. /// /// /// /// [NodeGroup(NodeGroupID.Teg)] public sealed class TegNodeGroup : BaseNodeGroup { /// /// If true, this TEG is fully built and has all its parts properly connected. /// [ViewVariables(VVAccess.ReadWrite)] public bool IsFullyBuilt { get; private set; } /// /// The central generator component. /// /// [ViewVariables(VVAccess.ReadWrite)] public TegNodeGenerator? Generator { get; private set; } // Illustration for how the TEG A/B circulators are laid out. // Circulator B Generator Circulator A // ^ -> | // | V // They have rotations like the arrows point out. /// /// The A-side circulator. This is the circulator that is in the direction FACING the center component's rotation. /// /// /// Not filled in if there is no center piece to deduce relative rotation from. /// /// [ViewVariables(VVAccess.ReadWrite)] public TegNodeCirculator? CirculatorA { get; private set; } /// /// The B-side circulator. This circulator is opposite . /// /// /// Not filled in if there is no center piece to deduce relative rotation from. /// /// [ViewVariables(VVAccess.ReadWrite)] public TegNodeCirculator? CirculatorB { get; private set; } private IEntityManager? _entityManager; public override void Initialize(Node sourceNode, IEntityManager entMan) { base.Initialize(sourceNode, entMan); _entityManager = entMan; } public override void LoadNodes(List groupNodes) { DebugTools.Assert(_entityManager != null); base.LoadNodes(groupNodes); if (groupNodes.Count > 3) { // Somehow got more TEG parts. Probably shenanigans. Bail. return; } Generator = groupNodes.OfType().SingleOrDefault(); if (Generator != null) { // If we have a generator, we can assign CirculatorA and CirculatorB based on relative rotation. var xformGenerator = _entityManager.GetComponent(Generator.Owner); var genDir = xformGenerator.LocalRotation.GetDir(); foreach (var node in groupNodes) { if (node is not TegNodeCirculator circulator) continue; var xform = _entityManager.GetComponent(node.Owner); var dir = xform.LocalRotation.GetDir(); if (genDir.GetClockwise90Degrees() == dir) { CirculatorA = circulator; } else { CirculatorB = circulator; } } } IsFullyBuilt = Generator != null && CirculatorA != null && CirculatorB != null; var tegSystem = _entityManager.EntitySysManager.GetEntitySystem(); foreach (var node in groupNodes) { if (node is TegNodeGenerator generator) tegSystem.UpdateGeneratorConnectivity(generator.Owner, this); if (node is TegNodeCirculator circulator) tegSystem.UpdateCirculatorConnectivity(circulator.Owner, this); } } } /// /// Node used by the central TEG generator component. /// /// /// [DataDefinition] public sealed partial class TegNodeGenerator : Node { public override IEnumerable GetReachableNodes( TransformComponent xform, EntityQuery nodeQuery, EntityQuery xformQuery, MapGridComponent? grid, IEntityManager entMan) { if (!xform.Anchored || grid == null) yield break; var gridIndex = grid.TileIndicesFor(xform.Coordinates); var dir = xform.LocalRotation.GetDir(); var a = FindCirculator(dir); var b = FindCirculator(dir.GetOpposite()); if (a != null) yield return a; if (b != null) yield return b; TegNodeCirculator? FindCirculator(Direction searchDir) { var targetIdx = gridIndex.Offset(searchDir); foreach (var node in NodeHelpers.GetNodesInTile(nodeQuery, grid, targetIdx)) { if (node is not TegNodeCirculator circulator) continue; var entity = node.Owner; var entityXform = xformQuery.GetComponent(entity); var entityDir = entityXform.LocalRotation.GetDir(); if (entityDir == searchDir.GetClockwise90Degrees()) return circulator; } return null; } } } /// /// Node used by the central TEG circulator entities. /// /// /// [DataDefinition] public sealed partial class TegNodeCirculator : Node { public override IEnumerable GetReachableNodes( TransformComponent xform, EntityQuery nodeQuery, EntityQuery xformQuery, MapGridComponent? grid, IEntityManager entMan) { if (!xform.Anchored || grid == null) yield break; var gridIndex = grid.TileIndicesFor(xform.Coordinates); var dir = xform.LocalRotation.GetDir(); var searchDir = dir.GetClockwise90Degrees(); var targetIdx = gridIndex.Offset(searchDir); foreach (var node in NodeHelpers.GetNodesInTile(nodeQuery, grid, targetIdx)) { if (node is not TegNodeGenerator generator) continue; var entity = node.Owner; var entityXform = xformQuery.GetComponent(entity); var entityDir = entityXform.LocalRotation.GetDir(); if (entityDir == searchDir || entityDir == searchDir.GetOpposite()) { yield return generator; break; } } } }