[Solved] ITraversalProvider is not providing the best path

Hi, I’m implementing a multi-tags system using ITraversalProvider. Those grey solid planes on the image are the places that have a higher penalty(3000) in my system.

So when my character walked from left to right, the search tree(green solid planes) bypasses those areas from below, GetTraversalCost() is working and the cost of the Path is higher than normal. But obviously, the final path(green line) is not the best one, it’s not following the search tree as well.

What could go wrong here?

Snipaste_2024-05-23_00-52-21
Snipaste_2024-05-23_00-59-47

Here are my ITraversalProvider.

public class PawnTraversalProvider : ITraversalProvider
{ 
    public TagPenaltyDictionary TagPenalities = new();

    public bool CanTraverse(Path path, GraphNode node)
    {
        return node.Walkable && (path.enabledTags >> (int)node.Tag & 0x1) != 0;
    }

    public bool CanTraverse(Path path, GraphNode from, GraphNode to)
    {
        return CanTraverse(path, to);
    }

    public uint GetTraversalCost(Path path, GraphNode node)
    {
        var penalty = path.GetTagPenalty((int)node.Tag) + node.Penalty;
        
        var tags = DungeonManager.Instance.GetTag((int)node.NodeIndex);
        if ((tags & (int)DungeonManager.NodeTag.Monster)!=0 && TagPenalities.TryGetValue(DungeonManager.NodeTag.Monster, out var p))
        {
            penalty += p;
        }

        return penalty;
    }
}

Character use ITraversalProvider like this

_seeker = GetComponent<Seeker>();
_seeker.traversalProvider = new PawnTraversalProvider()
{
    TagPenalities = tagPenaltyDict
};

DungeonManager is quite simple as well. It init arrays when A* scan is finished and uses node index to access extra data.

    void OnAStarScanFinished(GameEventArgs args)
    {
        _gg = AstarPath.active.graphs[0] as GridGraph;
        _nodeSize = _gg.nodeSize;
        var length = _gg.CountNodes();
        _tags = new NativeArray<int>(length, Allocator.Persistent);
        
#if UNITY_EDITOR 
        _tagPositions = new NativeArray<float3>(length, Allocator.Persistent);
        for (var i = 0; i < length; i++)
        {
            _tagPositions[i] = (Vector3)_gg.nodes[i].position;
        }
#endif
    }
    public void AddTag(NodeTag mask, Bounds bounds)
    {
        var nodes = _gg.GetNodesInRegion(bounds);
        for (var i = 0; i < nodes.Count; i++)
        {
            var index = (int)nodes[i].NodeIndex;
            _tags[index] |= (int)mask;
        }

        ListPool<GraphNode>.Release(nodes);
    }
    public int GetTag(int nodeIndex)
    {
        if (nodeIndex < 0 || nodeIndex >= _tags.Length)
            return 0;
        return _tags[nodeIndex];
    }

Alright, so after some debugging, it was the funnel script that made the unexpected shortcut.

Another problem is that I used NodeIndex everywhere in my code, it should be GridNode.NodeInGridIndex in this case.