flight-tools.ts•2.33 kB
import { z } from "zod";
import mineflayer from 'mineflayer';
import { Vec3 } from 'vec3';
import { ToolFactory } from '../tool-factory.js';
function createCancellableFlightOperation(
bot: mineflayer.Bot,
destination: Vec3,
controller: AbortController
): Promise<boolean> {
return new Promise((resolve, reject) => {
let aborted = false;
controller.signal.addEventListener('abort', () => {
aborted = true;
bot.creative.stopFlying();
reject(new Error("Flight operation cancelled"));
});
bot.creative.flyTo(destination)
.then(() => {
if (!aborted) {
resolve(true);
}
})
.catch((err: Error) => {
if (!aborted) {
reject(err);
}
});
});
}
export function registerFlightTools(factory: ToolFactory, getBot: () => mineflayer.Bot): void {
factory.registerTool(
"fly-to",
"Make the bot fly to a specific position",
{
x: z.number().describe("X coordinate"),
y: z.number().describe("Y coordinate"),
z: z.number().describe("Z coordinate")
},
async ({ x, y, z }) => {
const bot = getBot();
if (!bot.creative) {
return factory.createResponse("Creative mode is not available. Cannot fly.");
}
const controller = new AbortController();
const FLIGHT_TIMEOUT_MS = 20000;
const timeoutId = setTimeout(() => {
if (!controller.signal.aborted) {
controller.abort();
}
}, FLIGHT_TIMEOUT_MS);
try {
const destination = new Vec3(x, y, z);
await createCancellableFlightOperation(bot, destination, controller);
return factory.createResponse(`Successfully flew to position (${x}, ${y}, ${z}).`);
} catch (error) {
if (controller.signal.aborted) {
const currentPosAfterTimeout = bot.entity.position;
return factory.createErrorResponse(
`Flight timed out after ${FLIGHT_TIMEOUT_MS / 1000} seconds. The destination may be unreachable. ` +
`Current position: (${Math.floor(currentPosAfterTimeout.x)}, ${Math.floor(currentPosAfterTimeout.y)}, ${Math.floor(currentPosAfterTimeout.z)})`
);
}
throw error;
} finally {
clearTimeout(timeoutId);
bot.creative.stopFlying();
}
}
);
}