// We need some kind of module resolver for @shared/db. We use module-alias. require("module-alias/register"); import dotenv from "dotenv"; if (process.env.NODE_ENV == "dev") { dotenv.config({ path: "../.env" }); dotenv.config({ path: "../db.env" }); process.env.TYPEORM_HOST = "localhost"; process.env.TYPEORM_USERNAME = process.env.DB_USERNAME; process.env.TYPEORM_PASSWORD = process.env.DB_PASSWORD; process.env.TYPEORM_DATABASE = process.env.DB_NAME; } import * as fs from "fs"; import * as path from "path"; import { client } from "./client"; import * as mCmd from "./model/command"; import "reflect-metadata"; import { createConnection, getConnectionOptions } from "typeorm"; import { getNumberEnums } from "./util"; import { DB_ENTITIES } from "@shared/db/entities"; import { BOT_COMMAND_DESCRIPTOR } from "./model/command"; const REACT_PROBABILITY = 0.3; async function trigger(type: mCmd.ActionType, ...params: any[]) { let actionDone = false; let actions = botEvents[type]; for (let i = 0; i < actions.length; i++) { const action = actions[i] as (...args: any[]) => boolean | Promise; let actionResult = action(actionDone, ...params); if (actionResult instanceof Promise) actionDone = (await actionResult) || actionDone; else actionDone = actionResult || actionDone; } return actionDone; } let commandSets: mCmd.ICommand[] = []; let botCommands: mCmd.IBotCommand[] = []; let botEvents: { [event in mCmd.ActionType]: mCmd.BotAction[] } = getNumberEnums(mCmd.ActionType).reduce((p, c) => { p[c] = []; return p; }, {} as any); let startActions: Array<() => void | Promise> = []; client.bot.on('ready', async () => { console.log("Starting up NoctBot!"); client.botUser.setActivity(process.env.NODE_ENV == "dev" ? "Maintenance" : "@NoctBot help", { type: "PLAYING" }); for (let i = 0; i < startActions.length; i++) { const action = startActions[i]; let val = action(); if (val instanceof Promise) await val; } console.log("NoctBot is ready!"); }); client.bot.on("message", async m => { if (m.author.id == client.botUser.id) return; if(process.env.FOOLS == "TRUE" && (m.channel.id == "297109482905796608" || m.channel.id == "429295461099110402") && Math.random() <= 0.01) { const neighs = ["*NEIGH*", "neeeeeigh!", "Gimme carrots!", "NEEEEIIIIGH", "**N E I G H**"]; await m.channel.send(neighs[Math.floor(Math.random() * neighs.length)]); return; } let content = m.cleanContent.trim(); if (await trigger(mCmd.ActionType.MESSAGE, m, content)) return; if (m.mentions.users.size > 0 && m.mentions.users.has(client.botUser.id)) { if (m.content.trim().startsWith(client.botUser.id) || m.content.trim().startsWith(client.botUser.discriminator)) { content = content.substring(`@${client.botUser.username}`.length).trim(); let lowerCaseContent = content.toLowerCase(); for (let c of botCommands) { if (typeof (c.pattern) == "string" && lowerCaseContent.startsWith(c.pattern)) { c.action(m, content); return; } else if (c.pattern instanceof RegExp) { let result = c.pattern.exec(content); if (result != null) { c.action(m, content, result); return; } } } if (await trigger(mCmd.ActionType.DIRECT_MENTION, m, lowerCaseContent)) return; } if (await trigger(mCmd.ActionType.INDIRECT_MENTION, m)) return; } await trigger(mCmd.ActionType.POST_MESSAGE); }); client.bot.on("messageReactionAdd", (r, u) => { if (Math.random() <= REACT_PROBABILITY && !u.bot) { console.log(`Reacting to message ${r.message.id} because user ${u.tag} reacted to it`); r.message.react(r.emoji); } }); function loadCommand(mod: any) { for (let i in mod) { if (!mod.hasOwnProperty(i)) continue; let commandClass = mod[i] as any; // Ensure this is indeed a command class if (!commandClass.prototype || commandClass.prototype.BOT_COMMAND !== BOT_COMMAND_DESCRIPTOR) continue; let cmd = new commandClass() as mCmd.ICommand; commandSets.push(cmd); if (cmd._botCommands) botCommands.push(...cmd._botCommands.map(c => ({ ...c, action: c.action.bind(cmd) }))); if (cmd._botEvents) for (let [i, event] of Object.entries(cmd._botEvents)) { botEvents[+i as mCmd.ActionType].push((event as Function).bind(cmd)); } if(cmd.onStart) startActions.push(cmd.onStart.bind(cmd)); } } export function getDocumentation() { return botCommands.filter(m => m.documentation !== undefined).map(m => ({ name: m.pattern.toString(), doc: m.documentation?.description, example: m.documentation?.example, auth: m.auth || false })); } async function main() { await createConnection({ ...await getConnectionOptions(), entities: DB_ENTITIES }); let commandsPath = path.resolve(path.dirname(module.filename), "commands"); let files = fs.readdirSync(commandsPath); for (const file of files) { let ext = path.extname(file); if (ext != ".js") continue; loadCommand(require(path.resolve(commandsPath, file))); } client.bot.login(process.env.BOT_TOKEN); } main();