Files
Mortdecai/ingame/prayer_bots.js
T
Seth 7b9e4a9517 Dolphin-Mistral offensive prompts (5%), survival bot, cost-triggered POS printer
Bots:
- Dolphin-Mistral generates uncensored/offensive prompts (first 100, then 5%)
- PrayBot_0 runs survival mode: auto-respawn, contextual low-health prayers
- Gemini 2.5 Flash Lite for diverse natural prompts
- Fixed Gemini markdown wrapper parsing, dolphin JSON format

POS printer:
- Triggers on $0.50 Gemini cost threshold instead of fixed interval
- Checks every 15 min, only prints when threshold crossed
- --check flag to see current cost status

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 17:54:17 -04:00

411 lines
13 KiB
JavaScript

/**
* 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 <message>" — talk to an AI God character who grants/denies requests
- "sudo <command>" — 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",
];
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 (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`);