Going to add stretch effect on text and etc ..
And going to write a click gui similar to this menu with accent settings built into the theme.

Community members who have proven to be competent supporters.
Going to add stretch effect on text and etc ..
And going to write a click gui similar to this menu with accent settings built into the theme.

Yarn support has been dropped because minecraft is going to release versions that are not obfuscated at all. we had a project that generates some ts definition(https://www.npmjs.com/package/@ccbluex/liquidbounce-script-api?activeTab=versions), I started it but that's not exactly very accurate because ts and Java have a slightly different OOP model, and writing script for script api doesn't feel like writing native ts, but I think I would just wait a little bit and pick it again when obfuscation has totally dropped(I am much looking forward to it).
For a shameless self-advertising, I did have some scripts written before I got the ts generator maintained by LB maintainers, but those scripts likely won't run on current version https://github.com/commandblock2/minecraft-LBNG-types/tree/master/src , and I have yet to migrate them to our current api version.
now back in progress, going to vibe it with some LLM now
https://github.com/CCBlueX/LiquidBounce/issues/2523
I would that's a valid request
but anyway here a possible version
export function interactPlaceMidAir(pos: Vec3d) {
const blockPos = new BlockPos(pos.x, pos.y, pos.z);
const hitResult = new BlockHitResult(
pos, // hit position
Direction.UP, // side of the block hit (e.g., placing on top)
blockPos, // block position
false // insideBlock
);
// @ts-expect-error - The type definition for ClientPlayerInteractionManager.sendSequencedPacket expects a specific Packet type, but the lambda returns a generic Packet.
mc.interactionManager.sendSequencedPacket(mc.world, (sequence: number) => {
return new PlayerInteractBlockC2SPacket(
Hand.MAIN_HAND,
hitResult,
sequence
);
});
}
but somehow it did place 2 block for me, not so sure about it?
It's definitely doable, but you need to use the unoptimized jar to directly call this. Here is the script in ts, but you may need to adapt the imports to Java.type in js. And also for the visualization manager it's not yet available outside of my project. will release once the api is well designed and performance becomes decent and after a proper name is found for the npm package.
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() as unknown as number, mod.settings.goalZ.get() as unknown as number);
// 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 { }

it probably does have a AStarPathFinder just for this, but it's gonna be tested if this is really going to work.


ts version (npm package subject to change in the near future once a proper name is found)
import { BaritoneAPI } from "jvm-types/baritone/api/BaritoneAPI"
import { GoalXZ } from "jvm-types/baritone/api/pathing/goals/GoalXZ"
const script = registerScript.apply({
name: "baritone-api-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))
})
})
export { }
js version, but slightly changed from the compiled one (imports to Java.type), probably should work but never tested.
Edit: The directly compiled version works on my custom branch. But I was kinda disappointed for baritone not documenting if they provide access to their path finding engine without path execution, if any one knows, please leave a comment.
const BaritoneAPI_1 = Java.type("baritone.api.BaritoneAPI");
const GoalXZ_1 = Java.type("baritone.api.pathing.goals.GoalXZ");
const script = registerScript.apply({
name: "baritone-api-example",
version: "1.0.0",
authors: ["commandblock2"]
});
script.registerModule({
name: "baritone-api-example",
description: "Baritone example module",
category: "Client",
}, (mod) => {
mod.on("enable", () => {
BaritoneAPI_1.BaritoneAPI.getSettings().allowSprint.value = true;
BaritoneAPI_1.BaritoneAPI.getSettings().primaryTimeoutMS.value = Primitives.long(2000);
const baritone = BaritoneAPI_1.BaritoneAPI.getProvider().getPrimaryBaritone();
baritone.getCustomGoalProcess().setGoalAndPath(new GoalXZ_1.GoalXZ(100, 100));
});
});
@dj It actually makes much more sense if they knew about the legacy script api because it had more examples and exists longer. ScriptApi has not been a static and unified thing.
I was recently working on writing typescript for scriptapi (would probably still take a bit of time to get the changes into master branch), and I made the following prompt for roo code for my specific setup. And it turned out to be better than I thought.
You are Roo, a highly skilled software engineer with extensive knowledge in many programming languages, frameworks, design patterns, and best practices.
You are working with a project with the runtime environment of Liquidbounce Next Generation script api (graaljs on jvm) with typescript support. You may assume that classes use the yarn mapping on the latest minecraft protocol.
When you are not confident about if a api exists in current api, you may look up the type information at `node_modules/jvm-types/`. eg. `node_modules/jvm-types/types/net/minecraft/client/MinecraftClient.d.ts` contains the definition for `export class MinecraftClient extends ReentrantThreadExecutor<() => void> implements WindowEventHandler, MinecraftClientAccessor {` and `node_modules/jvm-types/types/net/ccbluex/liquidbounce/utils/movement/MovementUtilsKt.d.ts` contains `export class MovementUtilsKt extends Object {`
The manually maintained augmentations can be found at `node_modules/jvm-types/augmentations/ScriptModule.augmentation.d.ts` (with all events definined in LiquidBounce avaliable). Before you are going to use a event, view this file to make sure you are using the correct event.
If no existing script examples are given, use `src/complete.ts` to understand the script api.
You will use `Outter$innver` syntax to access inner classes.
You will use `import` instead of `Java.type` for imports from JVM, as the custom `require`/`import` implementation will be redirected to the graaljs's `Java.type`, direct useage of `Java.type` will loose all type information.
Seeing errors like the following may suggest that the generated TypeScript definition has some problems instead of your work does. When seeing those errors, you will consider if they are errors made by the definition generator and ignore them if appropriate.
```
Conversion of type 'LivingEntity' to type 'Entity' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.
Types of property 'getBoundingBox' are incompatible.
Type '(pose: EntityPose) => Box' is not comparable to type '() => Box'.
Target signature provides too few arguments. Expected 1 or more, but got 0.
```
btw, gemini 2.5 flash is definitely a great model of choice. It is significantly cheaper/faster than sonnet and is good enough to write scripts, and I almost couldn't believe how powerful it is given it's price.
@dj You are probably right about the ChatGPT thing, I personally have never used the ChatGPT in website for anything related. My model of choice is usually sonnet, used with continue.dev or roo code. You do need to remind them that they are writing graaljs and needs to be aware of how it works. They may also sometimes give wrong/outdated Minecraft api reference to the Class/Function definitions.
It can be quite difficult to write script if you are new to programming. https://liquidbounce.net/docs/script-api/installation this is the official docs for writing scripts, and gpt(or generally all frontier models) are your friend you can just ask those however you want. But note that current script api is not perfect and neither is gpt's answer, the only thing you could to is to try write and test, and also see the debug session. If you have difficulties writing a specific script you can just ask help in this forum(I prefer this one though) or on discord.