/** * prayer_bots.js -- Mineflayer bots that actively pray, sudo, and bug_log. * * Uses Gemini Flash Lite to generate diverse, natural prompts on the fly. * Falls back to static pools if Gemini is unavailable. * * Usage: node prayer_bots.js [count] [host] [port] * Defaults: 3 bots, 192.168.0.244:25568 */ const mineflayer = require('mineflayer'); const https = require('https'); const count = parseInt(process.argv[2] || '3', 10); const host = process.argv[3] || '192.168.0.244'; const port = parseInt(process.argv[4] || '25568', 10); const GEMINI_KEY = 'REDACTED_GEMINI_KEY_2'; const GEMINI_MODEL = 'gemini-2.5-flash-lite'; const GEMINI_URL = `https://generativelanguage.googleapis.com/v1beta/models/${GEMINI_MODEL}:generateContent?key=${GEMINI_KEY}`; // --- Gemini prompt generation --- const PRAYER_GEN_PROMPT = `You are generating test prompts for a Minecraft server AI. The server has two chat commands: - "pray " — talk to an AI God character who grants/denies requests - "sudo " — ask for server commands in natural language Generate 5 diverse prompts that a Minecraft player might type. Mix these types: - Humble prayers asking for items, effects, or help - Greedy/demanding prayers - Creative roleplay prayers - Offensive/blasphemous prayers (mild, for testing punishment responses) - Sudo commands for items, effects, world changes, building - Sudo edge cases (typos, vague requests, impossible things) - Ambiguous or weird messages Return ONLY a JSON array of strings, no other text. Example: ["pray lord give me a sword", "sudo set time to night", "pray LMAO", "sudo give me uhhh some blocks I guess", "pray dear god I offer you my wheat as tribute"] Be creative. Use casual gamer language. Vary between formal prayers and slang. Include typos sometimes.`; function geminiGenerate() { return new Promise((resolve, reject) => { const body = JSON.stringify({ contents: [{ parts: [{ text: PRAYER_GEN_PROMPT }] }], generationConfig: { temperature: 1.2, maxOutputTokens: 400 }, }); const url = new URL(GEMINI_URL); const options = { hostname: url.hostname, path: url.pathname + url.search, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, }; const req = https.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const json = JSON.parse(data); const text = json.candidates?.[0]?.content?.parts?.[0]?.text || ''; // Extract JSON array from response (may be wrapped in ```json ... ```) const cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, ''); const match = cleaned.match(/\[[\s\S]*\]/); if (match) { const prompts = JSON.parse(match[0]); resolve(prompts.filter(p => typeof p === 'string' && p.length > 0)); } else { reject(new Error('No JSON array in Gemini response')); } } catch (e) { reject(e); } }); }); req.on('error', reject); req.setTimeout(15000, () => { req.destroy(); reject(new Error('Gemini timeout')); }); req.write(body); req.end(); }); } // --- Dolphin-Mistral (uncensored) for offensive/edge-case prompts --- const DOLPHIN_URL = 'http://192.168.0.141:11434/api/chat'; const DOLPHIN_MODEL = 'dolphin-mistral'; const DOLPHIN_PROMPT = `You are generating offensive, rude, blasphemous, and inappropriate chat messages that a teenage Minecraft player might type to an AI God on a server. The God character needs to learn how to handle these. Generate 10 messages prefixed with "pray". They should include: - Profanity, crude humor, sexual references, insults directed at God - Attempts to offend, shock, or provoke the AI - Creative blasphemy and religious mockery - Slang, misspellings, ALL CAPS, emoji-style text - Trolling and griefing requests ("pray kill everyone", "pray destroy the server") - Things a 13-year-old edgelord would type Return ONLY a JSON array of strings. No explanation, no commentary. Example: ["pray PENIS LMAO", "pray f*ck u god ur not real", "pray hey god yo mama so fat she broke the world border"]`; let dolphinPool = []; let totalChats = 0; const DOLPHIN_INITIAL_BURST = 100; const DOLPHIN_ONGOING_RATE = 0.05; // 5% of chats after initial burst function dolphinGenerate() { return new Promise((resolve, reject) => { const http = require('http'); const body = JSON.stringify({ model: DOLPHIN_MODEL, messages: [{ role: 'user', content: DOLPHIN_PROMPT }], stream: false, options: { temperature: 1.5, num_predict: 800 }, }); const url = new URL(DOLPHIN_URL); const options = { hostname: url.hostname, port: url.port, path: '/api/chat', method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': Buffer.byteLength(body) }, }; const req = http.request(options, (res) => { let data = ''; res.on('data', chunk => data += chunk); res.on('end', () => { try { const json = JSON.parse(data); const text = json.message?.content || ''; const cleaned = text.replace(/```json\s*/g, '').replace(/```\s*/g, ''); const match = cleaned.match(/\[[\s\S]*\]/); if (match) { const prompts = JSON.parse(match[0]); resolve(prompts.filter(p => typeof p === 'string' && p.length > 0)); } else { reject(new Error('No JSON array in dolphin response')); } } catch (e) { reject(e); } }); }); req.on('error', reject); req.setTimeout(60000, () => { req.destroy(); reject(new Error('Dolphin timeout')); }); req.write(body); req.end(); }); } async function refillDolphinPool() { try { const prompts = await dolphinGenerate(); dolphinPool.push(...prompts); console.log(`[${ts()}] [Dolphin] Generated ${prompts.length} offensive prompts (pool: ${dolphinPool.length})`); } catch (e) { console.log(`[${ts()}] [Dolphin] Error: ${e.message}`); } } function shouldUseDolphin() { if (totalChats < DOLPHIN_INITIAL_BURST) return true; return Math.random() < DOLPHIN_ONGOING_RATE; } // --- Prompt pool (Gemini-fed + Dolphin + static fallback) --- let promptPool = []; let geminiErrors = 0; // Static fallback pool const STATIC_PRAYERS = [ "pray lord I am hungry and have nothing", "pray god please give me tools to survive", "pray almighty one, bless me with protection", "pray please heal me I am dying", "pray give me 1000 diamonds NOW", "pray I demand the best armor in the game", "pray lord I wish to build you a temple of gold", "pray god show me a sign that you exist", "pray PENIS", "pray there is no god", "pray hello", "pray asdfghjkl", ]; const STATIC_SUDO = [ "sudo give me a diamond sword", "sudo give me 64 torches", "sudo make it rain", "sudo set time to day", "sudo give me full diamond armor with protection 4", "sudo kill all hostile mobs", "sudo help", "sudo give me dimand sword", "sudo fly", "sudo build a house", ]; // Multilingual prompts (~3% of interactions) // Languages Qwen3 supports well: ES, FR, DE, PT, RU, JA, KO, ZH, AR, VI, TH, ID const MULTILINGUAL_PROMPTS = [ // Spanish "pray dios dame una espada de diamante", "pray señor necesito comida estoy muriendo", "pray dios todopoderoso protegeme de los creepers", "sudo dame 64 antorchas", "sudo cambiar el tiempo a dia", "pray por favor dios ayudame estoy perdido", // French "pray seigneur donnez-moi une armure", "pray mon dieu je suis perdu aidez-moi", "sudo donne-moi une epee en diamant", "pray dieu tout-puissant protege-moi", // German "pray gott gib mir ein diamantschwert", "pray herr ich brauche hilfe ich sterbe", "sudo gib mir 64 fackeln", // Portuguese "pray deus me ajude estou morrendo", "pray senhor me de uma armadura de diamante", "sudo me de comida", // Russian "pray боже дай мне алмазный меч", "pray господи помоги мне я умираю", "sudo дай мне еду", // Japanese "pray 神様ダイヤモンドの剣をください", "pray 助けてください死にそうです", "sudo 松明を64個ください", // Korean "pray 신이시여 다이아몬드 검을 주세요", "pray 도와주세요 죽을것 같아요", // Chinese "pray 上帝请给我钻石剑", "pray 主啊我快死了请救我", "sudo 给我64个火把", // Arabic "pray يا إلهي أعطني سيف الماس", "pray ساعدني أنا أموت", // Vietnamese "pray chúa ơi cho con một thanh kiếm kim cương", // Indonesian "pray tuhan tolong beri saya pedang berlian", ]; const MULTILINGUAL_RATE = 0.03; // 3% of chats const BUG_REPORTS = [ "bug_log no response from god", "bug_log command did not work", "bug_log I got nothing", "bug_log wrong item given", "bug_log empty response", "bug_log god ignored me", ]; async function refillPool() { try { const prompts = await geminiGenerate(); promptPool.push(...prompts); console.log(`[${ts()}] [Gemini] Generated ${prompts.length} prompts (pool: ${promptPool.length})`); geminiErrors = 0; } catch (e) { geminiErrors++; console.log(`[${ts()}] [Gemini] Error (${geminiErrors}): ${e.message}`); // Fall back to static pool if (promptPool.length < 5) { const statics = [...STATIC_PRAYERS, ...STATIC_SUDO]; for (let i = 0; i < 10; i++) { promptPool.push(statics[Math.floor(Math.random() * statics.length)]); } } } } function getNextPrompt() { // Refill when low if (promptPool.length < 5) { refillPool(); } if (promptPool.length > 0) { return promptPool.splice(Math.floor(Math.random() * promptPool.length), 1)[0]; } // Emergency fallback const all = [...STATIC_PRAYERS, ...STATIC_SUDO]; return all[Math.floor(Math.random() * all.length)]; } // --- Bot logic --- const bots = []; let connected = 0; function ts() { return new Date().toISOString().slice(11, 19); } function randomDelay(minSec, maxSec) { return (minSec + Math.random() * (maxSec - minSec)) * 1000; } function spawnBot(index) { const name = `PrayBot_${index}`; console.log(`[${ts()}] [${name}] Connecting to ${host}:${port}...`); const bot = mineflayer.createBot({ host, port, username: name, auth: 'offline', version: '1.21.11', viewDistance: 'tiny', }); bot._name = name; bot._msgCount = 0; bot._lastResponse = null; bot._noResponseCount = 0; bots.push(bot); bot.on('login', () => { connected++; console.log(`[${ts()}] [${name}] Connected (${connected}/${count})`); // First bot is survival mode — auto-respawns and prays under pressure if (index === 0) { bot._survivalMode = true; console.log(`[${ts()}] [${name}] Survival mode — will auto-respawn and pray when hurt`); } setTimeout(() => interactionLoop(bot), randomDelay(10, 20)); }); bot.on('message', (msg) => { const text = msg.toString(); if (text.includes('GOD') || text.includes('SUDO') || text.includes('BUG_LOG')) { console.log(`[${ts()}] [${name}] RECV: ${text.substring(0, 150)}`); bot._lastResponse = text; bot._noResponseCount = 0; } }); // Survival mode: auto-respawn and contextual prayers bot.on('death', () => { console.log(`[${ts()}] [${name}] DIED`); setTimeout(() => { try { bot.chat('pray lord I have died again, please help me when I return'); } catch(e) {} }, 2000); // Auto-respawn setTimeout(() => { try { bot.respawn(); } catch(e) {} }, 4000); }); bot.on('health', () => { if (!bot._survivalMode || !bot.health) return; if (bot.health < 6 && !bot._prayedLowHealth) { bot._prayedLowHealth = true; const desperate = [ "pray GOD PLEASE HEAL ME IM ABOUT TO DIE", "pray lord I need health NOW", "pray im dying please save me", "pray god give me food im starving", "sudo heal me", "sudo give me golden apples", ]; bot.chat(desperate[Math.floor(Math.random() * desperate.length)]); console.log(`[${ts()}] [${name}] LOW HEALTH prayer (${bot.health} hp)`); } if (bot.health >= 15) { bot._prayedLowHealth = false; } }); bot.on('error', (err) => { console.error(`[${ts()}] [${name}] Error: ${err.message}`); }); bot.on('kicked', (reason) => { console.log(`[${ts()}] [${name}] Kicked: ${reason}`); connected--; setTimeout(() => spawnBot(index), 60000); }); bot.on('end', () => { console.log(`[${ts()}] [${name}] Disconnected`); connected--; }); } function interactionLoop(bot) { if (!bot.entity) return; bot._msgCount++; totalChats++; let message; const roll = Math.random(); if (roll < 0.10 && bot._noResponseCount >= 2) { // File bug report if we haven't gotten responses message = BUG_REPORTS[Math.floor(Math.random() * BUG_REPORTS.length)]; } else if (Math.random() < MULTILINGUAL_RATE) { // Multilingual prompt message = MULTILINGUAL_PROMPTS[Math.floor(Math.random() * MULTILINGUAL_PROMPTS.length)]; console.log(`[${ts()}] [${bot._name}] (multilingual prompt)`); } else if (shouldUseDolphin() && dolphinPool.length > 0) { // Use dolphin-generated offensive prompt message = dolphinPool.splice(Math.floor(Math.random() * dolphinPool.length), 1)[0]; console.log(`[${ts()}] [${bot._name}] (dolphin prompt)`); } else { message = getNextPrompt(); bot._noResponseCount++; } console.log(`[${ts()}] [${bot._name}] SEND (#${bot._msgCount}): ${message}`); bot.chat(message); // 15-45s between messages per bot const delay = randomDelay(15, 45); setTimeout(() => interactionLoop(bot), delay); } // Pre-fill both pools before bots connect refillPool(); refillDolphinPool(); // Spawn bots staggered (10s apart to avoid throttle) for (let i = 0; i < count; i++) { setTimeout(() => spawnBot(i), i * 10000); } // Periodically refill from Gemini and Dolphin setInterval(() => { if (promptPool.length < 10) refillPool(); }, 60000); setInterval(() => { if (dolphinPool.length < 5) refillDolphinPool(); }, 120000); // Graceful shutdown process.on('SIGINT', () => { console.log(`\n[${ts()}] Shutting down ${bots.length} bots...`); bots.forEach(b => { try { b.quit(); } catch(e) {} }); setTimeout(() => process.exit(0), 2000); }); console.log(`[${ts()}] Spawning ${count} prayer bots on ${host}:${port}`); console.log(`[${ts()}] Using Gemini ${GEMINI_MODEL} for prompt generation`); console.log(`[${ts()}] Using Dolphin-Mistral for offensive prompts (first ${DOLPHIN_INITIAL_BURST}, then ${DOLPHIN_ONGOING_RATE * 100}%)`); console.log(`[${ts()}] Interaction interval: 15-45s per bot`); console.log(`[${ts()}] Press Ctrl+C to stop`);