import Config from "./config.js"; import mcdataLib from "minecraft-data"; import { createBot } from "mineflayer"; import { pathfinder, Movements, default as mpf } from "mineflayer-pathfinder"; const { GoalBlock, GoalNear } = mpf.goals; import Vec3 from "vec3"; const bot = createBot(Config.mc.bot); const mcData = mcdataLib(bot.version); let upperLeft = null; let bottomRight = null; bot.loadPlugin(pathfinder); const defaultMove = new Movements(bot, mcData); bot.pathfinder.setMovements(defaultMove); bot.once("spawn", () => { console.log("[MC] Bot spawned!"); }); bot.on('chat', (username, message) => { if (username === bot.username) return; const cmd = message.split(" ", 2)[0]; switch (cmd) { case "!help": bot.chat("Prefix: !; Commands: help, check, holding, field-set, field, till, sow, reap, stop"); break; case "!check": checkBlockUnder(); break; case "!holding": bot.chat(`holding ${bot.heldItem}`); console.log("holding: %s", bot.heldItem); break; case "!field-set": let parts = message.split(" "); let [x1, y1, z1, x2, y2, z2] = parts.slice(1); upperLeft = new Vec3(~~x1, ~~y1, ~~z1); bottomRight = new Vec3(~~x2, ~~y2, ~~z2); bot.chat(`Set field rect to ${upperLeft} til ${bottomRight}`); break; case "!field": findFieldBorders(); break; case "!till": startTilling(); break; case "!sow": startSowing(); break; case "!reap": startReaping(); break; case "!stop": bot.pathfinder.stop(); break; default: break; } }); bot.on('kicked', console.log); bot.on('error', console.log); const gotoUntill = async (dx, dy, dz, predicateOnBlock) => { try { let ul = bot.entity.position.offset(dx, dy, dz); let targetBlock = bot.blockAt(ul); while (predicateOnBlock(targetBlock)) { await bot.pathfinder.goto(new GoalBlock(ul.x, ul.y, ul.z)); ul = bot.entity.position.offset(dx, dy, dz); targetBlock = bot.blockAt(ul); } } catch (e) { bot.chat(`Shit happened! ${e}`); console.error(e); } } const checkBlockUnder = async () => { let targetBlock = bot.blockAt(bot.entity.position.offset(0, -1, 0)); bot.chat(`Block under: ${targetBlock}`) } const findFieldBorders = async () => { try { await gotoUntill(1, 0, 0, block => block.name === "air"); // go left await gotoUntill(0, 0, 1, block => block.name === "air"); // go up upperLeft = bot.entity.position; await gotoUntill(-1, 0, 0, block => block.name === "air"); // go right await gotoUntill(0, 0, -1, block => block.name === "air"); // go down bottomRight = bot.entity.position; bot.chat(`Done, ${upperLeft} to ${bottomRight}`); } catch (e) { bot.chat(`Shit happened! ${e}`); console.error(e); } } const isSowable = (block) => { const blockAbove = bot.blockAt(block.position.offset(0, 1, 0)); return !blockAbove || blockAbove.name === mcData.blocksByName.air.name; } const findDrops = (dropItemId) => { return Object.values(bot.entities).filter(entity => { return entity.name === "item" && entity.metadata.length >= 8 && entity.metadata[8].itemId == dropItemId }).map(item => { return item.position; }); } const startTilling = async () => { if (!upperLeft || !bottomRight) { bot.chat("I dont know about field rect!"); return; } const diamond_hoe_id = mcData.itemsByName.diamond_hoe.id; await bot.equip(diamond_hoe_id, "hand"); if (bot.heldItem === null || bot.heldItem.type !== diamond_hoe_id) { bot.chat("No hoe in my inventory :("); return; } let uy = ~~bot.entity.position.y; let lx = Math.floor(Math.min(upperLeft.x, bottomRight.x)); let hx = Math.floor(Math.max(upperLeft.x, bottomRight.x)); let lz = Math.floor(Math.min(upperLeft.z, bottomRight.z)); let hz = Math.floor(Math.max(upperLeft.z, bottomRight.z)); bot.chat("Started tilling the field"); try { for (let desiredX = lx; desiredX <= hx; desiredX++) { for (let desiredZ = lz; desiredZ <= hz; desiredZ++) { await bot.pathfinder.goto(new GoalBlock(desiredX, uy, desiredZ)); let targetBlock = bot.blockAt(new Vec3(desiredX, uy - 1, desiredZ)); await bot.activateBlock(targetBlock); } } } catch (e) { bot.chat(`Shit happened! ${e}`); console.error(e); } bot.chat("Done, tilled the field"); } const startSowing = async () => { if (!upperLeft || !bottomRight) { bot.chat("I dont know about field rect!"); return; } const carrot_id = mcData.itemsByName.carrot.id; await bot.equip(carrot_id, "hand"); if (bot.heldItem === null || bot.heldItem.type !== carrot_id) { bot.chat("No carrot in my inventory :("); return; } let uy = ~~bot.entity.position.y; let lx = Math.floor(Math.min(upperLeft.x, bottomRight.x)); let hx = Math.floor(Math.max(upperLeft.x, bottomRight.x)); let lz = Math.floor(Math.min(upperLeft.z, bottomRight.z)); let hz = Math.floor(Math.max(upperLeft.z, bottomRight.z)); bot.chat("Started sowing the field"); try { for (let desiredX = lx; desiredX <= hx; desiredX++) { for (let desiredZ = lz; desiredZ <= hz; desiredZ++) { await bot.pathfinder.goto(new GoalNear(desiredX, uy, desiredZ, 2)); let targetBlock = bot.blockAt(new Vec3(desiredX, uy, desiredZ)); if (isSowable(targetBlock)) { await bot.placeBlock(targetBlock, new Vec3(0, 1, 0)) } } } } catch (e) { bot.chat(`Shit happened! ${e}`); console.error(e); } bot.chat("Done, sowed the field"); } const startReaping = async () => { if (!upperLeft || !bottomRight) { bot.chat("I dont know about field rect!"); return; } const carrot_id = mcData.itemsByName.carrot.id; const carrot_block_id = mcData.blocksByName.carrots.id; let uy = ~~bot.entity.position.y; let lx = Math.floor(Math.min(upperLeft.x, bottomRight.x)); let hx = Math.floor(Math.max(upperLeft.x, bottomRight.x)); let lz = Math.floor(Math.min(upperLeft.z, bottomRight.z)); let hz = Math.floor(Math.max(upperLeft.z, bottomRight.z)); bot.chat("Started reaping the field"); try { for (let desiredX = lx; desiredX <= hx; desiredX++) { for (let desiredZ = lz; desiredZ <= hz; desiredZ++) { await bot.pathfinder.goto(new GoalNear(desiredX, uy, desiredZ, 2)); let targetBlock = bot.blockAt(new Vec3(desiredX, uy + 1, desiredZ)); if (targetBlock.type === carrot_block_id && targetBlock.metadata === 7) { await bot.dig(targetBlock); try { await bot.equip(carrot_id, "hand"); if (bot.heldItem === null || bot.heldItem.type !== carrot_id) { bot.chat("No carrot in my inventory :("); return; } await bot.placeBlock(bot.blockAt(targetBlock.position.offset(0, -1, 0)), new Vec3(0, 1, 0)) } catch (e) { console.error(e); } } } } } catch (e) { bot.chat(`Shit happened! ${e}`); console.error(e); } for (let pos of findDrops(mcData.itemsByName.carrot.id)) { await bot.pathfinder.goto(new GoalNear(pos.x, pos.y, pos.z, 1)); await bot.waitForTicks(5); } bot.chat("Done, reaped the field"); }