mirror of https://github.com/clickscodes/nucleus
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
10 KiB
228 lines
10 KiB
import type { CommandInteraction } from 'discord.js';
|
|
import Discord, { Interaction, SlashCommandBuilder, ApplicationCommandType } from 'discord.js';
|
|
import config from "../../config/main.json" assert { type: "json" };
|
|
import client from "../client.js";
|
|
import fs from "fs";
|
|
import EmojiEmbed from '../generateEmojiEmbed.js';
|
|
import getEmojiByName from '../getEmojiByName.js';
|
|
|
|
const colours = {
|
|
red: "\x1b[31m",
|
|
green: "\x1b[32m",
|
|
yellow: "\x1b[33m",
|
|
blue: "\x1b[34m",
|
|
purple: "\x1b[35m",
|
|
none: "\x1b[0m"
|
|
}
|
|
|
|
async function registerCommands() {
|
|
const commands = [];
|
|
|
|
const files: fs.Dirent[] = fs.readdirSync(config.commandsFolder, { withFileTypes: true }).filter(
|
|
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
|
|
);
|
|
console.log(`Registering ${files.length} commands`)
|
|
let i = 0;
|
|
for (const file of files) {
|
|
const last = i === files.length - 1 ? "└" : "├";
|
|
if (file.isDirectory()) {
|
|
console.log(`${last}─ ${colours.yellow}Loading subcommands of ${file.name}${colours.none}`)
|
|
const fetched = (await import(`../../../${config.commandsFolder}/${file.name}/_meta.js`));
|
|
commands.push(fetched.command);
|
|
} else if (file.name.endsWith(".js")) {
|
|
console.log(`${last}─ ${colours.yellow}Loading command ${file.name}${colours.none}`)
|
|
const fetched = (await import(`../../../${config.commandsFolder}/${file.name}`));
|
|
fetched.command.setDMPermission(fetched.allowedInDMs ?? false)
|
|
fetched.command.setNameLocalizations(fetched.nameLocalizations ?? {})
|
|
fetched.command.setDescriptionLocalizations(fetched.descriptionLocalizations ?? {})
|
|
// if (fetched.nameLocalizations || fetched.descriptionLocalizations)
|
|
commands.push(fetched.command);
|
|
client.commands["commands/" + fetched.command.name] = [
|
|
fetched,
|
|
{name: fetched.name ?? fetched.command.name, description: fetched.description ?? fetched.command.description}
|
|
];
|
|
}
|
|
i++;
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${files.length}]${colours.none}`)
|
|
}
|
|
console.log(`${colours.yellow}Loaded ${commands.length} commands, processing...`)
|
|
const processed = []
|
|
|
|
for (const subcommand of commands) {
|
|
if (subcommand instanceof Function) {
|
|
processed.push(subcommand(new SlashCommandBuilder()))
|
|
} else {
|
|
processed.push(subcommand)
|
|
}
|
|
}
|
|
|
|
console.log(`${colours.green}Processed ${processed.length} commands`)
|
|
return processed;
|
|
|
|
};
|
|
|
|
async function registerEvents() {
|
|
console.log("Reading events")
|
|
const files = fs.readdirSync(config.eventsFolder, { withFileTypes: true }).filter(
|
|
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
|
|
);
|
|
console.log(`Registering ${files.length} events`)
|
|
let i = 0;
|
|
let errors = 0;
|
|
for (const file of files) {
|
|
const last = i === files.length - 1 ? "└" : "├";
|
|
i++;
|
|
try {
|
|
console.log(`${last}─ ${colours.yellow}Loading event ${file.name}${colours.none}`)
|
|
const event = (await import(`../../../${config.eventsFolder}/${file.name}`));
|
|
|
|
client.on(event.event, event.callback.bind(null, client));
|
|
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${files.length}]${colours.none}`)
|
|
} catch (e) {
|
|
errors++;
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${files.length}]${colours.none}`)
|
|
}
|
|
}
|
|
console.log(`Loaded ${files.length - errors} events (${errors} failed)`)
|
|
};
|
|
|
|
async function registerContextMenus() {
|
|
console.log("Reading context menus")
|
|
const messageFiles = fs.readdirSync(config.messageContextFolder, { withFileTypes: true }).filter(
|
|
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
|
|
);
|
|
const userFiles = fs.readdirSync(config.userContextFolder, { withFileTypes: true }).filter(
|
|
file => !file.name.endsWith(".ts") && !file.name.endsWith(".map")
|
|
);
|
|
console.log(`Registering ${messageFiles.length} message context menus and ${userFiles.length} user context menus`)
|
|
let i = 0;
|
|
let errors = 0;
|
|
const commands: (Discord.ContextMenuCommandBuilder)[] = []
|
|
const totalFiles = messageFiles.length + userFiles.length;
|
|
for (const file of messageFiles) {
|
|
const last = i === totalFiles - 1 ? "└" : "├";
|
|
i++;
|
|
try {
|
|
console.log(`${last}─ ${colours.yellow}Loading message context menu ${file.name}${colours.none}`)
|
|
const context = (await import(`../../../${config.messageContextFolder}/${file.name}`));
|
|
context.command.setType(ApplicationCommandType.Message);
|
|
context.command.setDMPermission(context.allowedInDMs ?? false)
|
|
context.command.setNameLocalizations(context.nameLocalizations ?? {})
|
|
commands.push(context.command);
|
|
|
|
client.commands["contextCommands/message/" + context.command.name] = context;
|
|
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${totalFiles}]${colours.none}`)
|
|
} catch (e) {
|
|
errors++;
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${totalFiles}] | ${e}${colours.none}`)
|
|
}
|
|
}
|
|
for (const file of userFiles) {
|
|
const last = i === totalFiles - 1 ? "└" : "├";
|
|
i++;
|
|
try {
|
|
console.log(`${last}─ ${colours.yellow}Loading user context menu ${file.name}${colours.none}`)
|
|
const context = (await import(`../../../${config.userContextFolder}/${file.name}`));
|
|
context.command.setType(ApplicationCommandType.User);
|
|
commands.push(context.command);
|
|
|
|
client.commands["contextCommands/user/" + context.command.name] = context;
|
|
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.green}Loaded ${file.name} [${i} / ${totalFiles}]${colours.none}`)
|
|
} catch (e) {
|
|
errors++;
|
|
console.log(`${last.replace("└", " ").replace("├", "│")} └─ ${colours.red}Failed to load ${file.name} [${i} / ${totalFiles}]${colours.none}`)
|
|
}
|
|
}
|
|
|
|
console.log(`Loaded ${messageFiles.length + userFiles.length - errors} context menus (${errors} failed)`)
|
|
return commands;
|
|
};
|
|
|
|
async function registerCommandHandler() {
|
|
client.on("interactionCreate", async (interaction: Interaction) => {
|
|
if (interaction.isUserContextMenuCommand()) {;
|
|
const commandName = "contextCommands/user/" + interaction.commandName;
|
|
execute(client.commands[commandName]![0]?.check, client.commands[commandName]![0]?.callback, interaction)
|
|
return;
|
|
} else if (interaction.isMessageContextMenuCommand()) {
|
|
const commandName = "contextCommands/message/" + interaction.commandName;
|
|
execute(client.commands[commandName]![0]?.check, client.commands[commandName]![0]?.callback, interaction)
|
|
return;
|
|
} else if (interaction.isAutocomplete()) {
|
|
const commandName = interaction.commandName;
|
|
const subcommandGroupName = interaction.options.getSubcommandGroup(false);
|
|
const subcommandName = interaction.options.getSubcommand(false);
|
|
|
|
const fullCommandName = "commands/" + commandName + (subcommandGroupName ? `/${subcommandGroupName}` : "") + (subcommandName ? `/${subcommandName}` : "");
|
|
|
|
const choices = await client.commands[fullCommandName]![0]?.autocomplete(interaction);
|
|
|
|
const formatted = (choices ?? []).map(choice => {
|
|
return { name: choice, value: choice }
|
|
})
|
|
interaction.respond(formatted)
|
|
} else if (interaction.isChatInputCommand()) {
|
|
const commandName = interaction.commandName;
|
|
const subcommandGroupName = interaction.options.getSubcommandGroup(false);
|
|
const subcommandName = interaction.options.getSubcommand(false);
|
|
|
|
const fullCommandName = "commands/" + commandName + (subcommandGroupName ? `/${subcommandGroupName}` : "") + (subcommandName ? `/${subcommandName}` : "");
|
|
|
|
console.log(fullCommandName, client.commands[fullCommandName])
|
|
const command = client.commands[fullCommandName]![0];
|
|
const callback = command?.callback;
|
|
const check = command?.check;
|
|
execute(check, callback, interaction);
|
|
}
|
|
});
|
|
}
|
|
|
|
async function execute(check: Function | undefined, callback: Function | undefined, data: CommandInteraction) {
|
|
if (!callback) return;
|
|
if (check) {
|
|
let result;
|
|
try {
|
|
result = await check(data);
|
|
} catch(e) {
|
|
result = false;
|
|
}
|
|
if (result === false) return;
|
|
if (typeof result === "string") {
|
|
const { NucleusColors } = client.logger
|
|
return data.reply({embeds: [new EmojiEmbed()
|
|
.setDescription(result)
|
|
.setColor(NucleusColors.red)
|
|
.setEmoji(getEmojiByName("CONTROL.BLOCKCROSS"))
|
|
], ephemeral: true});
|
|
};
|
|
}
|
|
callback(data);
|
|
}
|
|
|
|
|
|
export default async function register() {
|
|
let commandList: ( Discord.SlashCommandBuilder | Discord.ContextMenuCommandBuilder )[] = [];
|
|
commandList = commandList.concat(await registerCommands());
|
|
commandList = commandList.concat(await registerContextMenus());
|
|
if (process.argv.includes("--update-commands")) {
|
|
if (config.enableDevelopment) {
|
|
const guild = await client.guilds.fetch(config.developmentGuildID);
|
|
console.log(`${colours.purple}Registering commands in ${guild!.name}${colours.none}`)
|
|
await guild.commands.set(commandList);
|
|
} else {
|
|
console.log(`${colours.blue}Registering commands in production mode${colours.none}`)
|
|
await client.application?.commands.set(commandList);
|
|
}
|
|
}
|
|
await registerCommandHandler();
|
|
await registerEvents();
|
|
console.log(`${colours.green}Registered commands, events and context menus${colours.none}`)
|
|
console.log(
|
|
(config.enableDevelopment ? `${colours.purple}Bot started in Development mode` :
|
|
`${colours.blue}Bot started in Production mode`) + colours.none)
|
|
console.log(client.commands)
|
|
};
|