using Content.Server.Construction.Components;
using Content.Shared.Construction;
using Content.Shared.Construction.Prototypes;
namespace Content.Server.Construction
{
public sealed partial class ConstructionSystem
{
///
/// Sets or clears a pathfinding target node for a given construction entity.
///
/// The target entity.
/// The target node to pathfind, or null to clear the current pathfinding node.
/// The construction component of the target entity. Will be resolved if null.
/// Whether we could set/clear the pathfinding target node.
public bool SetPathfindingTarget(EntityUid uid, string? targetNodeId, ConstructionComponent? construction = null)
{
if (!Resolve(uid, ref construction))
return false;
// Clear current target, just in case.
ClearPathfinding(uid, construction);
// Null means clear pathfinding target only.
if (targetNodeId == null)
{
return true;
}
if (GetCurrentGraph(uid, construction) is not {} graph)
return false;
if (GetNodeFromGraph(graph, construction.Node) is not { } node)
return false;
if (GetNodeFromGraph(graph, targetNodeId) is not {} targetNode)
return false;
return UpdatePathfinding(uid, graph, node, targetNode, GetCurrentEdge(uid, construction), construction);
}
///
/// Updates the pathfinding state for the current construction state of an entity.
///
/// The target entity.
/// The construction component of the target entity. Will be resolved if null.
/// Whether we could update the pathfinding state correctly.
public bool UpdatePathfinding(EntityUid uid, ConstructionComponent? construction = null)
{
if (!Resolve(uid, ref construction))
return false;
if (construction.TargetNode is not {} targetNodeId)
return false;
if (GetCurrentGraph(uid, construction) is not {} graph
|| GetNodeFromGraph(graph, construction.Node) is not {} node
|| GetNodeFromGraph(graph, targetNodeId) is not {} targetNode)
return false;
return UpdatePathfinding(uid, graph, node, targetNode, GetCurrentEdge(uid, construction), construction);
}
///
/// Internal version of , which expects a valid construction state and
/// actually performs the pathfinding update logic.
///
/// The target entity.
/// The construction graph the entity is at.
/// The current construction node the entity is at.
/// The target node we are trying to reach on the graph.
/// The current edge the entity is at, or null if none.
/// The construction component of the target entity. Will be resolved if null.
/// Whether we could update the pathfinding state correctly.
private bool UpdatePathfinding(EntityUid uid, ConstructionGraphPrototype graph,
ConstructionGraphNode currentNode, ConstructionGraphNode targetNode,
ConstructionGraphEdge? currentEdge,
ConstructionComponent? construction = null)
{
if (!Resolve(uid, ref construction))
return false;
construction.TargetNode = targetNode.Name;
// Check if we reached the target node.
if (currentNode == targetNode)
{
ClearPathfinding(uid, construction);
return true;
}
// If we don't have a path, generate it.
if (construction.NodePathfinding == null)
{
var path = graph.PathId(currentNode.Name, targetNode.Name);
if (path == null || path.Length == 0)
{
// No path.
ClearPathfinding(uid, construction);
return false;
}
construction.NodePathfinding = new Queue(path);
}
// If the next pathfinding node is the one we're at, dequeue it.
if (construction.NodePathfinding.Peek() == currentNode.Name)
{
construction.NodePathfinding.Dequeue();
}
if (currentEdge != null && construction.TargetEdgeIndex is {} targetEdgeIndex)
{
if (currentNode.Edges.Count >= targetEdgeIndex)
{
// Target edge is incorrect.
construction.TargetEdgeIndex = null;
}
else if (currentNode.Edges[targetEdgeIndex] != currentEdge)
{
// We went the wrong way, clean up!
ClearPathfinding(uid, construction);
return false;
}
}
if (construction.EdgeIndex == null
&& construction.TargetEdgeIndex == null
&& construction.NodePathfinding != null)
construction.TargetEdgeIndex = (currentNode.GetEdgeIndex(construction.NodePathfinding.Peek()));
return true;
}
///
/// Clears the pathfinding targets on a construction entity.
///
/// The target entity.
/// The construction component of the target entity. Will be resolved if null.
public void ClearPathfinding(EntityUid uid, ConstructionComponent? construction = null)
{
if (!Resolve(uid, ref construction))
return;
construction.TargetNode = null;
construction.TargetEdgeIndex = null;
construction.NodePathfinding = null;
}
}
}