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;
}
}
}
}