const mineflayer = require("mineflayer"); const fs = require("fs"); const path = require("path"); // Configuration const BOT_CONFIG = { host: "java.donutsmp.net", username: "AFKBot", auth: "microsoft", version: "1.21.1", }; const LOG_FILE = path.join(__dirname, "afk.log"); const TELEPORT_DETECT_REGEX = /you teleported to\b/i; // Logging function log(message) { const timestamp = new Date().toISOString(); const logMessage = `[${timestamp}] ${message}`; console.log(logMessage); fs.appendFileSync(LOG_FILE, logMessage + "\n"); } function toPlainText(value) { if (value == null) return ""; if (typeof value === "string") return value; if ( typeof value.toString === "function" && value.toString !== Object.prototype.toString ) { const asString = value.toString(); if (asString && asString !== "[object Object]") return asString; } if (Array.isArray(value)) { return value.map(toPlainText).join(""); } if (typeof value === "object") { let text = ""; if (typeof value.text === "string") text += value.text; if (typeof value.translate === "string") text += value.translate; if (Array.isArray(value.with)) text += value.with.map(toPlainText).join(""); if (Array.isArray(value.extra)) text += value.extra.map(toPlainText).join(""); return text; } return String(value); } function logIfTeleport(source, text) { const normalized = String(text || "").trim(); if (!normalized) return; if (!TELEPORT_DETECT_REGEX.test(normalized)) return; log(`Teleport detected from ${source}: ${normalized}`); } // Create bot const bot = mineflayer.createBot({ host: BOT_CONFIG.host, username: BOT_CONFIG.username, auth: BOT_CONFIG.auth, version: BOT_CONFIG.version, }); // Event handlers bot.on("login", () => { log("Bot logged in"); bot.setControlState("forward", false); }); bot.on("spawn", () => { log("Bot spawned"); }); bot.on("error", (err) => { log(`Error: ${err.message}`); }); bot.on("kicked", (reason) => { log(`Kicked: ${reason}`); }); bot.on("end", () => { log("Bot disconnected"); process.exit(0); }); bot.on("chat", (username, message) => { if (username === bot.username) return; log(`Chat [${username}]: ${message}`); logIfTeleport("chat", message); }); bot.on("messagestr", (message, position) => { if (!message) return; if (position === "game_info") { log(`Hotbar: ${message}`); } logIfTeleport(`messagestr${position ? `:${position}` : ""}`, message); }); bot.on("message", (jsonMsg, position) => { const text = toPlainText(jsonMsg); if (!text) return; if (position === "game_info") { log(`Hotbar(json): ${text}`); } logIfTeleport(`message${position ? `:${position}` : ""}`, text); }); // Fallback packet hooks for title/actionbar channels on servers that do not // emit teleport text through regular chat events. bot._client.on("set_action_bar_text", (packet) => { const text = toPlainText(packet?.text); if (!text) return; log(`ActionBar: ${text}`); logIfTeleport("actionbar", text); }); bot._client.on("set_title_text", (packet) => { const text = toPlainText(packet?.text); if (!text) return; log(`Title: ${text}`); logIfTeleport("title", text); }); bot._client.on("set_subtitle_text", (packet) => { const text = toPlainText(packet?.text); if (!text) return; log(`Subtitle: ${text}`); logIfTeleport("subtitle", text); }); // Graceful shutdown process.on("SIGINT", () => { log("Shutdown signal received"); bot.quit(); }); log("Starting AFK bot...");