Skip to content

NavigationPointProvider and NavigationPoint

Benjamin Sommerfeld edited this page Nov 20, 2025 · 3 revisions

Pathetic is an engine, not a mind reader. It doesn't know if your world is made of voxels, navigation meshes, or abstract data.

You have the map data. We have the pathfinding logic. The Provider is the handshake between the two.


The Interfaces

You need to implement two things. Don't overthink them.

  • NavigationPoint (The Atom) Represents a single coordinate in your world.

    • Job: Answer one question: "Can I stand here?" (isTraversable()).
  • NavigationPointProvider (The Map) The translator.

    • Job: Take an (x, y, z) coordinate and return a NavigationPoint.

Implementation Example

Let's assume you are building a Voxel game (because of course you are). Your world is a char[][][] array where 'X' is a wall.

1. The Point (The Data)

Wrapper for your world data.

public class VoxelNavigationPoint implements NavigationPoint {
    private final boolean solid;

    public VoxelNavigationPoint(boolean solid) {
        this.solid = solid;
    }

    @Override
    public boolean isTraversable() {
        // If it's solid, we can't walk there. Simple.
        return !solid;
    }
}

2. The Provider (The Lookup)

This is where the pathfinder asks: "What is at 10, 50, -20?"

public class VoxelProvider implements NavigationPointProvider {
    private final char[][][] grid;

    public VoxelProvider(char[][][] grid) {
        this.grid = grid;
    }

    @Override
    public NavigationPoint getNavigationPoint(PathPosition pos, EnvironmentContext context) {
        int x = pos.getX();
        int y = pos.getY();
        int z = pos.getZ();

        // 1. Safety Check: Don't let the pathfinder read outside your array.
        if (isOutOfBounds(x, y, z)) {
            return new VoxelNavigationPoint(true); // Treat void as solid wall
        }

        // 2. Lookup: Read your actual game data
        char block = grid[x][y][z];
        
        // 3. Wrap it: Return the interface
        return new VoxelNavigationPoint(block == 'X');
    }
    
    private boolean isOutOfBounds(int x, int y, int z) {
        return x < 0 || x >= grid.length ||
               y < 0 || y >= grid[0].length ||
               z < 0 || z >= grid[0][0].length;
    }
}

Wiring it up

Tell the engine to use their eyes.

// 1. Your Game Data
char[][][] myWorld = new char[100][100][100];

// 2. Connect the Bridge
PathfinderConfiguration config = PathfinderConfiguration.builder()
    .provider(new VoxelProvider(myWorld))
    .build();

Pro Tip: The One-Liner (Lambdas)

If your logic is simple, don't waste time writing a VoxelNavigationPoint class. NavigationPoint is a functional interface. You can implement it on the fly.

// Look ma, no extra classes!
public class LazyProvider implements NavigationPointProvider {
    @Override
    public NavigationPoint getNavigationPoint(PathPosition pos, EnvironmentContext ctx) {
        // Return a lambda for the NavigationPoint
        return () -> {
             // Your logic here. Return true if walkable.
             return MyGame.getBlock(pos.getX(), pos.getY(), pos.getZ()) != Material.BEDROCK;
        };
    }
}

Clone this wiki locally