diff --git a/src/client/client.js b/src/client/client.js index 150e5c3..94c878d 100644 --- a/src/client/client.js +++ b/src/client/client.js @@ -1,22 +1,32 @@ +// Required Components const { Client } = require('discord.js'); const { existsSync } = require('fs'); const events = require('./events'); const util = require('./util'); +// Client Class class client extends Client { constructor(config) { + // Call Discord.JS Client super(); + + // Set the client's configuration, initialise events, initialise utilities this.config = config; this.events = new events(); this.util = new util(this); } + // Method to start the bot start() { + // Events to handle commands super.on("message", this.events.message); super.on("ready", this.events.ready); + + // Login to discord using Discord.JS super.login(this._config.token); + // Load events this.util.loadEvents(); } @@ -27,12 +37,16 @@ class client extends Client { set config(config) { // Validate the config + + // Only allow config to be set once and only as a JSON object if (this._config) throw "Config has already been set"; if (typeof config != "object") throw "Config is not a JSON object"; + // Make sure the token and prefix are strings if (typeof config.token != "string") throw "Token is not a string"; if (typeof config.prefix != "string") throw "Prefix is not a string"; + // Make sure commands and events are arrays, each item inside will be validated later if (typeof config.commands != "object") throw "Commands is not a string"; if (typeof config.events != "object") throw "Events is not a string"; diff --git a/src/client/events.js b/src/client/events.js index 9eabab9..0180a7a 100644 --- a/src/client/events.js +++ b/src/client/events.js @@ -1,21 +1,30 @@ +// Events Class class event { + // Emit when a message is sent + // Used to check for commands message(message) { + // Make sure command is sent within a guild and not by a bot, otherwise return and ignore if (!message.guild) return; if (message.author.bot) return; + // Get the prefix from the config let prefix = this.config.prefix; + // If the message starts with the prefix, then treat it as a command if (message.content.substring(0, prefix.length).toLowerCase() == prefix.toLowerCase()) { + // Get the arguments in the message, after the first space (after the command name) let args = message.content.substring(prefix.length).split(" "); let name = args.shift(); + // Load the command from the util class this.util.loadCommand(name, args, message); } } + // Emit when bot is logged in and ready to use ready() { console.log("Ready"); } } -module.exports = event; \ No newline at end of file +module.exports = event; diff --git a/src/client/util.js b/src/client/util.js index ec42570..67038bd 100644 --- a/src/client/util.js +++ b/src/client/util.js @@ -1,49 +1,68 @@ +// Required Components const { stat, readdirSync } = require('fs'); const { config } = require('process'); +// Util Class class util { constructor(client) { + // Set the client this._client = client; } + // Load a command and send the arguments with it loadCommand(name, args, message) { + // Loop through all folders set in config + // c = command folder index for (let c = 0; c < this._client.config.commands.length; c++) { + // Get the current folder to check let folder = this._client.config.commands[c]; + // See if the folder being checked has the command being sent stat(`${process.cwd()}/${folder}/${name}.js`, err => { + // If no error, attempt to run the command if (err == null) { + // Require the command file, now that we know it exists and initialise it let commandFile = require(`${process.cwd()}/${folder}/${name}.js`); let command = new commandFile(); + // Get the list of required configurations the command needs let requiredConfigs = command.requiredConfigs; + // Loop through all the required configs of the command for (let i = 0; i < requiredConfigs.length; i++) { - if (!this._client.config[name]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`; - if (!this._client.config[name][requiredConfigs[i]]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`; - } + // If the command doesn't have the configs in the config string, throw an error + if (!this._client.config[name]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`; + if (!this._client.config[name][requiredConfigs[i]]) throw `${commandFile.name} requires ${requiredConfigs[i]} in it's configuration`; + } - let requiredRoles = command.roles; + // Get the roles required for this command to run + let requiredRoles = command.roles; - for (let i = 0; i < requiredRoles.length; i++) { - if (!message.member.roles.cache.find(role => role.name == requiredRoles[i])) { - message.reply(`You require the \`${requiredRoles[i]}\` role to run this command`); - return; - } + // Loop through all roles required + for (let i = 0; i < requiredRoles.length; i++) { + // If the user doesn't have a required role, don't run the command and let the user know + if (!message.member.roles.cache.find(role => role.name == requiredRoles[i])) { + message.reply(`You require the \`${requiredRoles[i]}\` role to run this command`); + return; } + } + // Get the ids of the users that are only permitted to run this command let users = command.users; + // If the user isn't in the list, don't run the command if (!users.includes(message.member.id)) { message.reply(`You do not have permission to run this command`); return; } - command[command.run]({ - "command": name, - "arguments": args, - "client": this._client, - "message": message, - "config": config + // Run the command and pass the command context with it + command[command.run]({ + "command": name, + "arguments": args, + "client": this._client, + "message": message, + "config": config }); } else if (err.code === 'ENOENT') { // FILE DOESN'T EXIST @@ -52,18 +71,28 @@ class util { } } + // Load the events loadEvents() { + // Loop through all the event folders for (let e = 0; e < this._client.config.events.length; e++) { + // Get the current folder to check let folder = this._client.config.events[e]; + // Get the files inside of this folder let eventFiles = readdirSync(`${process.cwd()}/${folder}/`); + // Loop through all the files in the folder for (let i = 0; i < eventFiles.length; i++) { + // Get the event name, by taking the command file and removing the ".js" from the end let eventName = eventFiles[i].split('.')[0]; + + // Get the file of the event let file = require(`${process.cwd()}/${folder}/${eventName}.js`); + // Initialise the event class let event = new file; + // Set the client to emit to this event this._client.on(eventName, event[event.run]); } }