baritone icon indicating copy to clipboard operation
baritone copied to clipboard

Exposing standalone access to path planning capabilities in api

Open commandblock2 opened this issue 6 months ago • 5 comments

Describe your suggestion

Baritone has awesome capabilities in planning path with it's AStarPathFinder. When writing certain functions in other clients, it makes sense to want to use baritone's path planning while leaving path execution to the client (eg. KillAura bot on with baritone, so that the killaura bot can decide when to take control of the bot). It can technically be called if I use the unoptimized jar, but that wouldn't be the proper way of doing this.

Settings

Not applicable.

Context

I was writing a script for LiquidBounce, which uses baritone for it's path planning. However it only works if I am using the unoptimized jar.

Image

The example ts script is shown as below. But it doesn't run on vanilla LiquidBounce yet.

import { BaritoneAPI } from "jvm-types/baritone/api/BaritoneAPI"
import { GoalXZ } from "jvm-types/baritone/api/pathing/goals/GoalXZ"
import { CalculationContext } from "jvm-types/baritone/pathing/movement/CalculationContext"
import { Favoring } from "jvm-types/baritone/utils/pathing/Favoring"
import { BetterBlockPos } from "jvm-types/baritone/api/utils/BetterBlockPos"
import { IPath } from "jvm-types/baritone/api/pathing/calc/IPath"
import { VisualizationManager } from "lbng-utils-typed/dist/visualization-utils"
import { PathCalculationResult$Type } from "jvm-types/baritone/api/utils/PathCalculationResult$Type"

// note: this import is not from baritone-api jar
// it is only presented in the baritone-unoptimized jar
// as the `AStarPathFinder` class is possibly obfuscated in the baritone-standalone jar
// so you will have to install the baritone-unoptimized jar to use this import
import { AStarPathFinder } from "jvm-types/baritone/pathing/calc/AStarPathFinder"


const script = registerScript.apply({
    name: "astar-pathfinder-example",
    version: "1.0.0",
    authors: ["commandblock2"]
});

script.registerModule({
    name: "baritone-api-example",
    description: "Baritone example module",
    category: "Client",

}, (mod) => {
    mod.on("enable", () => {
        BaritoneAPI.getSettings().allowSprint.value = true;
        BaritoneAPI.getSettings().primaryTimeoutMS.value = Primitives.long(2000);
        const baritone = BaritoneAPI.getProvider().getPrimaryBaritone();
        baritone.getCustomGoalProcess().setGoalAndPath(new GoalXZ(100, 100))
    })
})

script.registerModule({
    name: "astar-pathfinder-example",
    description: "Direct AStarPathFinder construction example",
    category: "Client",
    settings: {
        goalX: Setting.float({
            name: "Goal X",
            default: 100,
            range: [-10000, 10000] // Assuming a reasonable range
        }),
        goalZ: Setting.float({
            name: "Goal Z",
            default: 100,
            range: [-10000, 10000] // Assuming a reasonable range
        }),
        recalculateInterval: Setting.int({
            name: "Recalculate Interval (ticks)",
            default: 20,
            range: [1, 200]
        })
    }
}, (mod) => {

    const viz = new VisualizationManager(mod);

    let previousPath: IPath | null = null;

    let lastRecalculateTick = 0;

    const calculatePath = () => {
        const baritone = BaritoneAPI.getProvider().getPrimaryBaritone();

        // Get current player position
        const playerPos = baritone.getPlayerContext().playerFeet();
        const start = new BetterBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());

        // Create calculation context for threaded use
        const context = new CalculationContext(baritone, true);

        // Create favoring (empty favoring for no preferences)
        const favoring = new Favoring(baritone.getPlayerContext(), previousPath as unknown as IPath, context);

        // Create goal using settings
        const goal = new GoalXZ(mod.settings.goalX.get(), mod.settings.goalZ.get());

        // Construct AStarPathFinder directly
        const pathfinder = new AStarPathFinder(
            start,           // realStart
            start.getX(),    // startX
            start.getY(),    // startY
            start.getZ(),    // startZ
            goal,            // goal
            favoring,        // favoring
            context          // context
        );

        // @ts-expect-error
        UnsafeThread.run(() => {
            const result = pathfinder.calculate(Primitives.long(2000), Primitives.long(5000));

            // Handle result
            if (result.getType() != PathCalculationResult$Type.CANCELLATION) {
                const path = result.getPath().get();
                console.log("Path found! Length: " + path.length());
                mc.execute(() => {
                    viz.addVisualization({
                        lineData: {
                            positions: path.positions().map((pos) => new Vec3d(pos.x + .5, pos.y, pos.z + .5)),

                        },
                        durationTicks: 20 * 60,
                    });
                    previousPath = path;
                });
                // Use the path as needed - you now have direct access without execution
            } else {
                console.log("Path calculation failed: " + result.getType().toString());
            }
        });
    };

    mod.on("enable", () => {
        viz.clearAllVisualizations();
        lastRecalculateTick = 0; // Reset on enable
        calculatePath(); // Initial calculation
    });

    mod.on("gametick", () => {
        if (mc.player && mc.world && (mc.player.age - lastRecalculateTick) >= (mod.settings.recalculateInterval.get() as unknown as number)) {
            calculatePath();
            lastRecalculateTick = mc.player.age;
        }
    });
});

export { }

Final checklist

  • [x] I know how to properly use check boxes
  • [x] I have not used any OwO's or UwU's in this issue.

commandblock2 avatar Aug 02 '25 16:08 commandblock2

Wouldn't making AStarPathFinder unoptimized in the API cause a pretty significant performance decrease? I mean, it's literally the class that holds the calculations for pathing, so maybe this isn't such a good idea. Also, even if you create the PR, @leijurv is probably going to wait a zillion years to even consider merging it :). So if you really want the change, just edit the code and build it.

Murat65536 avatar Aug 02 '25 21:08 Murat65536

That being said, I am looking at giving Baritone some attacking functionality. I've implemented a way to move in any direction while looking in any other direction (as part of #4752) and expanded it to track entities here. I'll probably put settings for external autoaim and killaura as well as options to only target players, entities, or a mix of both with blacklists.

Murat65536 avatar Aug 02 '25 21:08 Murat65536

Before reading your comment, I was not aware of how optimization was working for baritone. I do think that it should be possible to make a api that calls the optimized internal implementation though. I do understand that it may bring extra maintenance cost on baritone, and I do indeed have a low expectation for this proposal to be actually accepted. For now, the unoptimized jar should be enough for me as I do not expect to use the AStarPathFinder in a online scenario yet. And I do appreciate that baritone does provide a jar without obfuscation, please keep it and thank you for your effort so much. And I also appreciate the work you have done in the your pr for adding more settings to the baritone. By the way, I am actually quite curious about how much faster is it for baritone if it were to be optimized?

commandblock2 avatar Aug 03 '25 16:08 commandblock2

By the way, I am actually quite curious about how much faster is it for baritone if it were to be optimized?

No idea on the specifics, but the difference is enough for it to matter. You can probably look up "JVM optimization" to get an idea of what it's doing and how it helps execution speed. Also, the standalone version is smaller than the unoptimized one since everything is obfuscated, which is also a plus I guess.

Murat65536 avatar Aug 03 '25 17:08 Murat65536

There's now a PR for this: #4838

Murat65536 avatar Aug 05 '25 23:08 Murat65536