Initial project scaffold: dataset schema, 31 seed training examples, Mineflayer bot framework, and 7-phase roadmap
- IDEA.md: project scope (Minecraft ops AI assistant via qwen3-coder LoRA/SFT) - PLAN.md: complete roadmap with prior art analysis, architecture, phased plan, dev server docs - data/schema.json: training example JSON Schema with negative_output support - data/processed/seed_dataset.jsonl: 31 validated examples from repair code, prayer logs, session history - data/validate_dataset.py: schema validator with summary statistics - ingame/: Mineflayer bot framework (test_connect, spawn_bots, aware_bots with full event logging) - Directory structure for knowledge/, eval/, training/, agent/ (Phase 1.3+ work)
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* spawn_bots.js -- Spawn multiple Mineflayer bots on the dev server.
|
||||
*
|
||||
* Each bot connects, reports its state, and stays connected for
|
||||
* external control (RCON commands, chat interaction, etc.).
|
||||
*
|
||||
* Usage: node spawn_bots.js [count] [host] [port]
|
||||
* Defaults: 3 bots, 192.168.0.244:25568
|
||||
*
|
||||
* Bots are named: TrainBot_0, TrainBot_1, TrainBot_2, ...
|
||||
* They join staggered (1s apart) to avoid connection floods.
|
||||
*/
|
||||
|
||||
const mineflayer = require('mineflayer');
|
||||
|
||||
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 bots = [];
|
||||
let connected = 0;
|
||||
|
||||
function spawnBot(index) {
|
||||
const name = `TrainBot_${index}`;
|
||||
console.log(`[${name}] Connecting to ${host}:${port}...`);
|
||||
|
||||
const bot = mineflayer.createBot({
|
||||
host,
|
||||
port,
|
||||
username: name,
|
||||
auth: 'offline',
|
||||
version: '1.21.11',
|
||||
});
|
||||
|
||||
bot._botIndex = index;
|
||||
bot._botName = name;
|
||||
bots.push(bot);
|
||||
|
||||
bot.on('login', () => {
|
||||
console.log(`[${name}] Logged in`);
|
||||
});
|
||||
|
||||
bot.on('spawn', () => {
|
||||
connected++;
|
||||
const pos = bot.entity.position;
|
||||
console.log(`[${name}] Spawned at (${pos.x.toFixed(0)}, ${pos.y.toFixed(0)}, ${pos.z.toFixed(0)}) -- ${connected}/${count} connected`);
|
||||
|
||||
if (connected === count) {
|
||||
console.log(`\n=== All ${count} bots connected ===`);
|
||||
console.log('Bots are idle and ready for training commands.');
|
||||
console.log('Press Ctrl+C to disconnect all bots.\n');
|
||||
}
|
||||
});
|
||||
|
||||
bot.on('chat', (username, message) => {
|
||||
// Ignore own messages
|
||||
if (username === name) return;
|
||||
console.log(`[${name}] CHAT <${username}> ${message}`);
|
||||
});
|
||||
|
||||
bot.on('error', (err) => {
|
||||
console.error(`[${name}] ERROR: ${err.message}`);
|
||||
});
|
||||
|
||||
bot.on('kicked', (reason) => {
|
||||
console.error(`[${name}] KICKED: ${reason}`);
|
||||
connected = Math.max(0, connected - 1);
|
||||
});
|
||||
|
||||
bot.on('end', (reason) => {
|
||||
console.log(`[${name}] Disconnected: ${reason}`);
|
||||
connected = Math.max(0, connected - 1);
|
||||
});
|
||||
|
||||
return bot;
|
||||
}
|
||||
|
||||
// Stagger connections
|
||||
for (let i = 0; i < count; i++) {
|
||||
setTimeout(() => spawnBot(i), i * 1500);
|
||||
}
|
||||
|
||||
// Graceful shutdown
|
||||
process.on('SIGINT', () => {
|
||||
console.log('\nDisconnecting all bots...');
|
||||
for (const bot of bots) {
|
||||
try { bot.quit('Shutdown'); } catch (_) {}
|
||||
}
|
||||
setTimeout(() => process.exit(0), 2000);
|
||||
});
|
||||
|
||||
// Keep alive
|
||||
setInterval(() => {}, 60000);
|
||||
Reference in New Issue
Block a user