namespace Pathfinding {
///
/// Provides additional traversal information to a path request.
///
/// Example implementation:
///
/// public class MyCustomTraversalProvider : ITraversalProvider {
/// public bool CanTraverse (Path path, GraphNode node) {
/// // Make sure that the node is walkable and that the 'enabledTags' bitmask
/// // includes the node's tag.
/// return node.Walkable && (path.enabledTags >> (int)node.Tag & 0x1) != 0;
/// // alternatively:
/// // return DefaultITraversalProvider.CanTraverse(path, node);
/// }
///
/// /** [CanTraverseDefault] */
/// public bool CanTraverse (Path path, GraphNode from, GraphNode to) {
/// return CanTraverse(path, to);
/// }
/// /** [CanTraverseDefault] */
///
/// public uint GetTraversalCost (Path path, GraphNode node) {
/// // The traversal cost is the sum of the penalty of the node's tag and the node's penalty
/// return path.GetTagPenalty((int)node.Tag) + node.Penalty;
/// // alternatively:
/// // return DefaultITraversalProvider.GetTraversalCost(path, node);
/// }
///
/// // This can be omitted in Unity 2021.3 and newer because a default implementation (returning true) can be used there.
/// public bool filterDiagonalGridConnections {
/// get {
/// return true;
/// }
/// }
/// }
///
///
/// See: traversal_provider (view in online documentation for working links)
///
public interface ITraversalProvider {
///
/// Filter diagonal connections using for effects applied by this ITraversalProvider.
/// This includes tags and other effects that this ITraversalProvider controls.
///
/// This only has an effect if is set to false and your grid has set to Eight.
///
/// Take this example, the grid is completely walkable, but an ITraversalProvider is used to make the nodes marked with '#'
/// as unwalkable. The agent 'S' is in the middle.
///
///
/// ..........
/// ....#.....
/// ...#....
/// ....#.....
/// ..........
///
///
/// If filterDiagonalGridConnections is false the agent will be free to use the diagonal connections to move away from that spot.
/// However, if filterDiagonalGridConnections is true (the default) then the diagonal connections will be disabled and the agent will be stuck.
///
/// Typically, there are a few common use cases:
/// - If your ITraversalProvider makes walls and obstacles and you want it to behave identically to obstacles included in the original grid graph scan, then this should be true.
/// - If your ITraversalProvider is used for agent to agent avoidance and you want them to be able to move around each other more freely, then this should be false.
///
/// See:
///
bool filterDiagonalGridConnections => true;
/// True if node should be able to be traversed by the path.
bool CanTraverse(Path path, GraphNode node) => DefaultITraversalProvider.CanTraverse(path, node);
///
/// True if the path can traverse a link between from and to and if to can be traversed itself.
/// If this method returns true then a call to CanTraverse(path,to) must also return true.
/// Thus this method is a more flexible version of .
///
/// If you only need the functionality for then you may implement this method by just forwarding it to
///
///
/// public bool CanTraverse (Path path, GraphNode from, GraphNode to) {
/// return CanTraverse(path, to);
/// }
///
///
bool CanTraverse(Path path, GraphNode from, GraphNode to) => CanTraverse(path, to);
///
/// Cost of traversing a given node.
/// Should return the additional cost for traversing this node. By default if no tags or penalties
/// are used then the traversal cost is zero. A cost of 1000 corresponds roughly to the cost of moving 1 world unit.
///
uint GetTraversalCost(Path path, GraphNode node) => DefaultITraversalProvider.GetTraversalCost(path, node);
}
/// Convenience class to access the default implementation of the ITraversalProvider
public static class DefaultITraversalProvider {
public static bool CanTraverse (Path path, GraphNode node) {
return node.Walkable && (path == null || (path.enabledTags >> (int)node.Tag & 0x1) != 0);
}
public static uint GetTraversalCost (Path path, GraphNode node) {
return node.Penalty + (path != null ? path.GetTagPenalty((int)node.Tag) : 0);
}
}
}