113 lines
3.7 KiB
TypeScript
113 lines
3.7 KiB
TypeScript
import {Client, Permissions} from "discord.js";
|
|
import $, {unreact} from "./core/lib";
|
|
import setup from "./setup";
|
|
import FileManager from "./core/storage";
|
|
import {Config, Storage} from "./core/structures";
|
|
|
|
(async() => {
|
|
// Setup //
|
|
await setup.init();
|
|
const client = new Client();
|
|
const commands = await FileManager.loadCommands();
|
|
client.login(Config.token).catch(setup.again);
|
|
|
|
client.on("message", async message => {
|
|
// Message Setup //
|
|
if(message.author.bot)
|
|
return;
|
|
|
|
const prefix = Storage.getGuild(message.guild?.id || "N/A").prefix || Config.prefix;
|
|
|
|
if(!message.content.startsWith(prefix))
|
|
return;
|
|
|
|
const [header, ...args] = message.content.substring(prefix.length).split(/ +/);
|
|
|
|
if(!commands.has(header))
|
|
return;
|
|
if(message.channel.type === "text" && !message.channel.permissionsFor(client.user || "")?.has(Permissions.FLAGS.SEND_MESSAGES))
|
|
{
|
|
let status;
|
|
|
|
if(message.member?.hasPermission(Permissions.FLAGS.ADMINISTRATOR))
|
|
status = "Because you're a server admin, you have the ability to change that channel's permissions to match if that's what you intended.";
|
|
else
|
|
status = "Try using a different channel or contacting a server admin to change permissions of that channel if you think something's wrong.";
|
|
|
|
return message.author.send(`I don't have permission to send messages in ${message.channel.toString()}. ${status}`);
|
|
}
|
|
|
|
$.log(`${message.author.username}#${message.author.discriminator} executed the command "${header}" with arguments "${args}".`);
|
|
|
|
// Subcommand Recursion //
|
|
let command = commands.get(header);
|
|
if(!command) return $.warn(`Command "${header}" was called but for some reason it's still undefined!`);
|
|
const params: any[] = [];
|
|
let isEndpoint = false;
|
|
|
|
for(let param of args)
|
|
{
|
|
if(command.endpoint)
|
|
{
|
|
if(command.subcommands || command.user || command.number || command.any)
|
|
$.warn(`An endpoint cannot have subcommands! Check ${prefix}${header} again.`);
|
|
isEndpoint = true;
|
|
break;
|
|
}
|
|
|
|
if(command.subcommands?.[param])
|
|
command = command.subcommands[param];
|
|
// Any Discord ID format will automatically format to a user ID.
|
|
else if(command.user && (/\d{17,19}/.test(param)))
|
|
{
|
|
const id = param.match(/\d+/g)![0];
|
|
command = command.user;
|
|
try {params.push(await client.users.fetch(id))}
|
|
catch(error) {return message.channel.send(`No user found by the ID \`${id}\`!`)}
|
|
}
|
|
// Disallow infinity and allow for 0.
|
|
else if(command.number && (Number(param) || param === "0") && !param.includes("Infinity"))
|
|
{
|
|
command = command.number;
|
|
params.push(Number(param));
|
|
}
|
|
else if(command.any)
|
|
{
|
|
command = command.any;
|
|
params.push(param);
|
|
}
|
|
else
|
|
params.push(param);
|
|
}
|
|
|
|
if(isEndpoint)
|
|
return message.channel.send("Too many arguments!");
|
|
|
|
// Execute with dynamic library attached. //
|
|
// The purpose of using $.bind($) is to clone the function so as to not modify the original $.
|
|
// The cloned function doesn't copy the properties, so Object.assign() is used.
|
|
// Object.assign() modifies the first element and returns that, the second element applies its properties and the third element applies its own overriding the second one.
|
|
command.execute(Object.assign($.bind($), {
|
|
args: params,
|
|
author: message.author,
|
|
channel: message.channel,
|
|
client: client,
|
|
guild: message.guild,
|
|
member: message.member,
|
|
message: message
|
|
}, $));
|
|
});
|
|
|
|
client.once("ready", () => {
|
|
if(client.user)
|
|
{
|
|
$.ready(`Logged in as ${client.user.username}#${client.user.discriminator}.`);
|
|
client.user.setActivity({
|
|
type: "LISTENING",
|
|
name: `${Config.prefix}help`
|
|
});
|
|
}
|
|
});
|
|
|
|
client.on("messageReactionRemove", unreact);
|
|
})() |