Files
mc-bot-town-2/nodejs/controller/mc-bot.js
T
2026-07-12 17:26:59 -04:00

144 lines
4.6 KiB
JavaScript

'use strict';
// Require log-web early to capture all console output from other modules
const LogWeb = require('./log-web');
const {sleep} = require('../utils');
const conf = require('../conf');
const {CJbot} = require('../model/minecraft');
const commands = require('./commands');
CJbot.pluginAdd(require('./swing'));
CJbot.pluginAdd(require('./craft'));
CJbot.pluginAdd(require('./tp'));
CJbot.pluginAdd(require('./ai'));
CJbot.pluginAdd(require('./guardianFarm'));
CJbot.pluginAdd(require('./goldFarm'));
CJbot.pluginAdd(require('./storage'));
CJbot.pluginAdd(require('./auto-eat'));
CJbot.pluginAdd(require('./farm-supply'));
CJbot.pluginAdd(require('./commands/navigation'));
for(let name in conf.mc.bots){
if(CJbot.bots[name]) continue;
let bot = new CJbot({name, host: conf.mc.host, ...conf.mc.bots[name]});
CJbot.bots[name] = bot;
for(let command of conf.mc.bots[name].commands || ['default']){
for(let [name, toAdd] of Object.entries(commands[command])){
bot.addCommand(name, toAdd)
}
}
}
const Database = require('./storage/database');
const SettingsManager = require('./settings/manager');
// Start web server immediately — it serves static/web routes independently of bot state
const webServer = require('./web-server');
const ActivityWeb = require('./activity-web');
const ChatWeb = require('./chat-web');
const InvitePlugin = require('./invite');
webServer.queuePlugin(ChatWeb);
webServer.queuePlugin(ActivityWeb);
webServer.queuePlugin(LogWeb);
webServer.queuePlugin(InvitePlugin);
const SettingsWeb = require('./settings/web');
webServer.queuePlugin(SettingsWeb);
webServer.start().catch(err => console.error('Failed to start web server:', err));
async function initDatabase() {
if (Database.db) return;
await Database.initialize(conf.storage.dbPath || './storage/storage.db');
console.log('DB initialized');
// Seed settings defaults (INSERT OR IGNORE — won't overwrite user changes)
const registry = SettingsManager.getRegistry();
const seedDefaults = registry.map(r => {
const parts = r.key.split('.');
let node = conf;
for (const p of parts) node = node?.[p];
let value = '';
if (node !== undefined && node !== null) {
if (r.key === 'ai.prompts' && typeof node === 'object') {
const templates = {};
for (const [name, fn] of Object.entries(node)) {
if (typeof fn === 'function') {
const fnStr = fn.toString();
const m = fnStr.match(/=>\s*`([\s\S]*)`\s*$/);
templates[name] = m ? m[1] : '';
}
}
value = JSON.stringify(templates);
} else if (r.type === 'json') {
value = JSON.stringify(node);
} else {
value = String(node);
}
}
return { key: r.key, value, type: r.type, category: r.category, label: r.label, description: r.description };
});
await Database.seedDefaultSettings(seedDefaults);
// Initialize settings cache from DB
await SettingsManager.initialize();
// Seed per-bot settings from config defaults
await Database.seedDefaultBotSettings();
// Apply DB-stored bot settings to live bot instances
for (const [botName, bot] of Object.entries(CJbot.bots)) {
try {
const rows = await Database.getAllBotSettings(botName);
for (const row of rows) {
let val = row.value;
if (row.type === 'number') val = Number(val) || 0;
else if (row.type === 'boolean') val = val === 'true';
else if (row.type === 'json') { try { val = JSON.parse(val); } catch (e) { val = null; } }
switch (row.key) {
case 'username': if (val) bot.username = val; break;
case 'password': if (val) bot.password = val; break;
case 'auth': if (val) bot.auth = val; break;
case 'autoConnect': bot.autoConnect = val; break;
case 'autoReConnect': bot.autoReConnect = val; break;
case 'onDemand': bot.onDemand = val; break;
case 'idleTimeout': bot._idleTimeout = Number(val) || 30000; break;
case 'commands': bot._dbCommands = val; break;
case 'plugins': bot.pluginsWanted = val || {}; break;
case 'hasAi': bot.hasAi = val; break;
}
}
console.log(`Applied DB settings for ${botName}`);
} catch (e) { /* bot may not exist in DB yet */ }
}
if (conf.invite?.seedSites) {
await Database.seedInviteSites(conf.invite.seedSites);
console.log('Invite sites seeded');
}
}
(async () => {
try {
// DB and settings must be ready before bots connect, so Storage
// constructors always see the correct DB-stored config values.
await initDatabase();
for (let name in CJbot.bots) {
const bot = CJbot.bots[name];
if (bot.autoConnect) {
console.log('Trying to connect', name);
console.log('Status for', name, await bot.connect());
await sleep(30000);
}
}
} catch (e) {
console.log('!!!!!!!! error:', e);
}
})();