'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); } })();