2023-04-24 15:49:03 +02:00

110 lines
4.8 KiB
C#

using System.Collections.Generic;
using Pathfinding.Util;
namespace Pathfinding {
/// <summary>
/// Contains useful functions for updating graphs.
/// This class works a lot with the GraphNode class, a useful function to get nodes is <see cref="AstarPath.GetNearest"/>.
///
/// See: <see cref="AstarPath.GetNearest"/>
/// See: <see cref="Pathfinding.PathUtilities"/>
///
/// \since Added in 3.1
///
/// \ingroup utils
/// </summary>
public static class GraphUpdateUtilities {
/// <summary>
/// Updates graphs and checks if all nodes are still reachable from each other.
/// Graphs are updated, then a check is made to see if the nodes are still reachable from each other.
/// If they are not, the graphs are reverted to before the update and false is returned.\n
/// This is slower than a normal graph update.
/// All queued graph updates and thread safe callbacks will be flushed during this function.
///
/// Returns: True if the given nodes are still reachable from each other after the guo has been applied. False otherwise.
///
/// <code>
/// var guo = new GraphUpdateObject(tower.GetComponent<Collider>().bounds);
/// var spawnPointNode = AstarPath.active.GetNearest(spawnPoint.position).node;
/// var goalNode = AstarPath.active.GetNearest(goalPoint.position).node;
///
/// if (GraphUpdateUtilities.UpdateGraphsNoBlock(guo, spawnPointNode, goalNode, false)) {
/// // Valid tower position
/// // Since the last parameter (which is called "alwaysRevert") in the method call was false
/// // The graph is now updated and the game can just continue
/// } else {
/// // Invalid tower position. It blocks the path between the spawn point and the goal
/// // The effect on the graph has been reverted
/// Destroy(tower);
/// }
/// </code>
/// </summary>
/// <param name="guo">The GraphUpdateObject to update the graphs with</param>
/// <param name="node1">Node which should have a valid path to node2. All nodes should be walkable or false will be returned.</param>
/// <param name="node2">Node which should have a valid path to node1. All nodes should be walkable or false will be returned.</param>
/// <param name="alwaysRevert">If true, reverts the graphs to the old state even if no blocking occurred</param>
public static bool UpdateGraphsNoBlock (GraphUpdateObject guo, GraphNode node1, GraphNode node2, bool alwaysRevert = false) {
List<GraphNode> buffer = ListPool<GraphNode>.Claim();
buffer.Add(node1);
buffer.Add(node2);
bool worked = UpdateGraphsNoBlock(guo, buffer, alwaysRevert);
ListPool<GraphNode>.Release(ref buffer);
return worked;
}
/// <summary>
/// Updates graphs and checks if all nodes are still reachable from each other.
/// Graphs are updated, then a check is made to see if the nodes are still reachable from each other.
/// If they are not, the graphs are reverted to before the update and false is returned.
/// This is slower than a normal graph update.
/// All queued graph updates will be flushed during this function.
///
/// Returns: True if the given nodes are still reachable from each other after the guo has been applied. False otherwise.
/// </summary>
/// <param name="guo">The GraphUpdateObject to update the graphs with</param>
/// <param name="nodes">Nodes which should have valid paths between them. All nodes should be walkable or false will be returned.</param>
/// <param name="alwaysRevert">If true, reverts the graphs to the old state even if no blocking occurred</param>
public static bool UpdateGraphsNoBlock (GraphUpdateObject guo, List<GraphNode> nodes, bool alwaysRevert = false) {
bool worked;
// Pause pathfinding while modifying the graphs
var graphLock = AstarPath.active.PausePathfinding();
try {
// Make sure any pending graph updates have been done before we start
AstarPath.active.FlushGraphUpdates();
// Make sure all nodes are walkable
for (int i = 0; i < nodes.Count; i++) if (!nodes[i].Walkable) return false;
// Track changed nodes to enable reversion of the guo
guo.trackChangedNodes = true;
AstarPath.active.UpdateGraphs(guo);
// Update the graphs immediately
AstarPath.active.FlushGraphUpdates();
// Check if all nodes are in the same area and that they are walkable, i.e that there are paths between all of them
worked = PathUtilities.IsPathPossible(nodes);
// If it did not work, revert the GUO
if (!worked || alwaysRevert) {
guo.RevertFromBackup();
// Recalculate connected components
AstarPath.active.hierarchicalGraph.RecalculateIfNecessary();
}
} finally {
graphLock.Release();
}
// Disable tracking nodes, not strictly necessary, but will slightly reduce the cance that some user causes errors
guo.trackChangedNodes = false;
return worked;
}
}
}