CopyPasted from misaBot
This commit is contained in:
parent
31f7383ca6
commit
cb09663742
21
package-lock.json
generated
21
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "conjurebot",
|
"name": "conjurebot",
|
||||||
"version": "0.1.0",
|
"version": "0.0.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@ -9,6 +9,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.5.tgz",
|
||||||
"integrity": "sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw=="
|
"integrity": "sha512-CU1q0UXQUpFNzNB7gufgoisDHP7n+T3tkqTsp3MNUkVJ5+hS3BCvME8uCXAUFlz+6T2FbTCu75A+yQ7HMKqRKw=="
|
||||||
},
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"version": "13.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.9.0.tgz",
|
||||||
|
"integrity": "sha512-0ARSQootUG1RljH2HncpsY2TJBfGQIKOOi7kxzUY6z54ePu/ZD+wJA8zI2Q6v8rol2qpG/rvqsReco8zNMPvhQ=="
|
||||||
|
},
|
||||||
|
"@types/ws": {
|
||||||
|
"version": "7.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.2.2.tgz",
|
||||||
|
"integrity": "sha512-oqnI3DbGCVI9zJ/WHdFo3CUE8jQ8CVQDUIKaDtlTcNeT4zs6UCg9Gvk5QrFx2QPkRszpM6yc8o0p4aGjCsTi+w==",
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"abort-controller": {
|
"abort-controller": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
|
||||||
@ -36,9 +49,9 @@
|
|||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||||
},
|
},
|
||||||
"discord.js": {
|
"discord.js": {
|
||||||
"version": "12.0.1",
|
"version": "12.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-12.0.2.tgz",
|
||||||
"integrity": "sha512-lUlrkAWSb5YTB1WpSZHjeUXxGlHK8VDjrlHLEP4lJj+etFAellURpmRYl29OPJ/7arQWB879pP4rvhhzpdOF7w==",
|
"integrity": "sha512-iZiEA4Y61gqq/EjFfLXnkRK9pLapnax/vTVDUhs/mAhyqozAy0GOlk/MZI9rSa1iIoKTWRq6P9CRKhLNT2wUnA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@discordjs/collection": "^0.1.5",
|
"@discordjs/collection": "^0.1.5",
|
||||||
"abort-controller": "^3.0.0",
|
"abort-controller": "^3.0.0",
|
||||||
|
|||||||
@ -9,7 +9,9 @@
|
|||||||
"author": "misabiko",
|
"author": "misabiko",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^12.0.1",
|
"@types/node": "^13.9.0",
|
||||||
|
"@types/ws": "^7.2.2",
|
||||||
|
"discord.js": "^12.0.2",
|
||||||
"typescript": "^3.8.3"
|
"typescript": "^3.8.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
74
src/Command.ts
Normal file
74
src/Command.ts
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import {Message} from 'discord.js';
|
||||||
|
import {CustomClient} from "./index";
|
||||||
|
|
||||||
|
export class CommandCollection {
|
||||||
|
private commands : { [commandName : string] : Command } = {};
|
||||||
|
|
||||||
|
get(commandName : string, aliased = true) : Command {
|
||||||
|
let command = this.commands[commandName];
|
||||||
|
|
||||||
|
if (!command && aliased)
|
||||||
|
command = Object.values(this.commands).find(
|
||||||
|
(cmd : Command) => cmd.checkName(commandName)
|
||||||
|
) as Command;
|
||||||
|
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
has(commandName : string, aliased = true) : boolean {
|
||||||
|
return !!this.get(commandName, aliased);
|
||||||
|
}
|
||||||
|
|
||||||
|
add(command : Command) {
|
||||||
|
if (this.commands[command.name])
|
||||||
|
return console.error(`Command ${command.name} is already in the collection`);
|
||||||
|
|
||||||
|
this.commands[command.name] = command;
|
||||||
|
}
|
||||||
|
|
||||||
|
clear(exceptions : Command[]) {
|
||||||
|
for (const commandName in this.commands)
|
||||||
|
if (!exceptions.find(cmd => cmd.checkName(commandName)))
|
||||||
|
delete this.commands[commandName];
|
||||||
|
}
|
||||||
|
|
||||||
|
getNames() {
|
||||||
|
return Object.keys(this.commands);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Command {
|
||||||
|
description? : string;
|
||||||
|
args? : string[];
|
||||||
|
guildOnly? : boolean;
|
||||||
|
cooldown? : number;
|
||||||
|
aliases? : string[];
|
||||||
|
usage? : string;
|
||||||
|
permissions? : string[];
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
public name : string,
|
||||||
|
public execute : (message? : Message, args? : string[], client? : CustomClient) => void,
|
||||||
|
{
|
||||||
|
description = null as string,
|
||||||
|
args = null as string[],
|
||||||
|
guildOnly = false,
|
||||||
|
cooldown = 0,
|
||||||
|
aliases = null as string[],
|
||||||
|
usage = null as string,
|
||||||
|
permissions = null as string[],
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
this.description = description;
|
||||||
|
this.args = args;
|
||||||
|
this.guildOnly = guildOnly;
|
||||||
|
this.cooldown = cooldown;
|
||||||
|
this.aliases = aliases;
|
||||||
|
this.usage = usage;
|
||||||
|
this.permissions = permissions;
|
||||||
|
}
|
||||||
|
|
||||||
|
checkName(commandName : string) {
|
||||||
|
return commandName === this.name || (this.aliases && this.aliases.includes(commandName));
|
||||||
|
}
|
||||||
|
}
|
||||||
12
src/commands/echo.ts
Normal file
12
src/commands/echo.ts
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
import {Command} from "../Command";
|
||||||
|
|
||||||
|
const echo = new Command(
|
||||||
|
'echo',
|
||||||
|
(message, args) => {
|
||||||
|
message.channel.send(args.join(' '));
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Echo's the arguments as a message"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default echo;
|
||||||
13
src/commands/echolog.ts
Normal file
13
src/commands/echolog.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {Command} from "../Command";
|
||||||
|
|
||||||
|
const echolog = new Command(
|
||||||
|
'echolog',
|
||||||
|
(message, args) => {
|
||||||
|
console.log("Echolog:");
|
||||||
|
for (const arg of args)
|
||||||
|
console.log(arg);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "Echo's the arguments on the console"
|
||||||
|
});
|
||||||
|
export default echolog;
|
||||||
42
src/commands/help.ts
Normal file
42
src/commands/help.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import {Command} from "../Command";
|
||||||
|
import {CustomClient} from "../index";
|
||||||
|
|
||||||
|
const {prefix} = require("../config.json");
|
||||||
|
|
||||||
|
const help = new Command(
|
||||||
|
'help',
|
||||||
|
(message, args) => {
|
||||||
|
const data = [];
|
||||||
|
const {commandCollection} = message.client as CustomClient;
|
||||||
|
|
||||||
|
if (!args.length) {
|
||||||
|
data.push("Here's a list of the commands:");
|
||||||
|
data.push(commandCollection.getNames().join(", "));
|
||||||
|
data.push(`\nSend \`${prefix}help [command name]\` for info on a specific command.`);
|
||||||
|
|
||||||
|
return message.channel.send(data, {split: true});
|
||||||
|
}
|
||||||
|
|
||||||
|
const name = args[0].toLowerCase();
|
||||||
|
const command = commandCollection.get(name);
|
||||||
|
|
||||||
|
if (!command)
|
||||||
|
return message.reply(`${name} isn't not a valid command, call ${prefix}help for the list of available commands.`);
|
||||||
|
|
||||||
|
data.push(`**Name:** ${command.name}`);
|
||||||
|
|
||||||
|
if (command.aliases) data.push(`**Aliases:** ${command.aliases.join(', ')}`);
|
||||||
|
if (command.description) data.push(`**Description:** ${command.description}`);
|
||||||
|
if (command.usage) data.push(`**Usage:** ${prefix}${command.name} ${command.usage}`);
|
||||||
|
|
||||||
|
data.push(`**Cooldown:** ${command.cooldown || 1} second(s)`);
|
||||||
|
|
||||||
|
message.channel.send(data, {split: true});
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "List every commands or info about a specific command.",
|
||||||
|
aliases: ["commands"],
|
||||||
|
usage: "[command name]"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default help;
|
||||||
58
src/commands/reloadcommand.ts
Normal file
58
src/commands/reloadcommand.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
import {Message} from "discord.js";
|
||||||
|
import {Command} from "../Command";
|
||||||
|
import {CustomClient} from "../index";
|
||||||
|
|
||||||
|
const {userDict} = require("../config.json");
|
||||||
|
|
||||||
|
const reloadcommand = new Command(
|
||||||
|
'reloadcommand',
|
||||||
|
async (message, args, client) => {
|
||||||
|
if (args.length)
|
||||||
|
await reloadSingleCommand(args[0].toLowerCase(), client, message);
|
||||||
|
else
|
||||||
|
await reloadCommands(client, message);
|
||||||
|
}, {
|
||||||
|
description: "Reloads either every, or a given command module.",
|
||||||
|
aliases: ["reload"],
|
||||||
|
usage: "[commandName]",
|
||||||
|
permissions: [userDict.misabiko]
|
||||||
|
}
|
||||||
|
);
|
||||||
|
export default reloadcommand;
|
||||||
|
|
||||||
|
async function reloadSingleCommand(commandName : string, client : CustomClient, message : Message) {
|
||||||
|
const {commandCollection} = client;
|
||||||
|
|
||||||
|
if (commandName === 'reloadcommand')
|
||||||
|
return message.channel.send("You have to restart the bot to reload this command.");
|
||||||
|
|
||||||
|
if (!commandCollection.has(commandName))
|
||||||
|
return message.channel.send(`The ${commandName} command doesn't exist.`);
|
||||||
|
|
||||||
|
if (await client.importCommand(`./${commandName}.js`, message))
|
||||||
|
await message.channel.send(`Successfully reloaded the ${commandName} command.`);
|
||||||
|
else
|
||||||
|
await message.channel.send(`Failed to reload the ${commandName} command.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function reloadCommands(client : CustomClient, message : Message) {
|
||||||
|
const {commandCollection} = client;
|
||||||
|
|
||||||
|
commandCollection.clear([
|
||||||
|
commandCollection.get('reloadcommand')
|
||||||
|
]);
|
||||||
|
|
||||||
|
const commandFiles = fs.readdirSync(__dirname).filter(file => file.endsWith(".js"));
|
||||||
|
|
||||||
|
let hadErrors = false;
|
||||||
|
for (const file of commandFiles)
|
||||||
|
if (file !== "reloadcommand.js")
|
||||||
|
hadErrors = hadErrors || !(await client.importCommand(path.join(__dirname, file), message));
|
||||||
|
|
||||||
|
if (hadErrors)
|
||||||
|
await message.channel.send(`Failed to reload some commands.`);
|
||||||
|
else
|
||||||
|
await message.channel.send(`Successfully reloaded the commands.`);
|
||||||
|
}
|
||||||
108
src/index.ts
Normal file
108
src/index.ts
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
import * as path from 'path';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as Discord from "discord.js";
|
||||||
|
import {Message, Snowflake} from "discord.js";
|
||||||
|
import {Command, CommandCollection} from "./Command";
|
||||||
|
import {prefix, token, userDict} from "./config.json";
|
||||||
|
|
||||||
|
export class CustomClient extends Discord.Client {
|
||||||
|
commandCollection = new CommandCollection();
|
||||||
|
cooldowns : { [name : string] : Discord.Collection<Snowflake, number> } = {};
|
||||||
|
prefix = prefix;
|
||||||
|
|
||||||
|
async importCommand(commandPath : string, message? : Message) : Promise<boolean> {
|
||||||
|
try {
|
||||||
|
this.commandCollection.add((await import(commandPath)).default);
|
||||||
|
}catch(error) {
|
||||||
|
const errorMessage = "Error while importing command " + commandPath;
|
||||||
|
console.error(errorMessage);
|
||||||
|
console.error(error);
|
||||||
|
|
||||||
|
if (message)
|
||||||
|
await message.reply(errorMessage);
|
||||||
|
else {
|
||||||
|
const user = await this.users.fetch(userDict.misabiko);
|
||||||
|
await user.send(errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMessage(message : Message) {
|
||||||
|
//If message doesn't have prefix or is bot-made, ignore
|
||||||
|
if (!message.content.startsWith(prefix) || message.author.bot) return;
|
||||||
|
|
||||||
|
const args = message.content.slice(prefix.length).split(/ +/);
|
||||||
|
const commandName = args.shift().toLowerCase();
|
||||||
|
|
||||||
|
const command = client.commandCollection.get(commandName);
|
||||||
|
if (!command) return;
|
||||||
|
|
||||||
|
if (command.args && !args.length) {
|
||||||
|
let reply = `You didn't provide any arguments, ${message.author}.`;
|
||||||
|
|
||||||
|
if (command.usage)
|
||||||
|
reply += `\nUsage: \`${prefix}${command.name} ${command.usage}\``;
|
||||||
|
|
||||||
|
return message.channel.send(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (command.guildOnly && message.channel.type !== 'text')
|
||||||
|
return message.reply(`You can only call the ${command} commmand on a server.`);
|
||||||
|
|
||||||
|
if (command.permissions && !command.permissions.includes(message.author.id))
|
||||||
|
return message.reply(`You don't have the permission for that command, ask <@${userDict.misabiko}> for help.`);
|
||||||
|
|
||||||
|
if (!this.cooldowns[command.name])
|
||||||
|
this.cooldowns[command.name] = new Discord.Collection();
|
||||||
|
|
||||||
|
const timeLeft = this.getTimeLeft(command, message.author.id);
|
||||||
|
if (timeLeft)
|
||||||
|
return message.reply(`Please wait ${timeLeft.toFixed(1)} more second(s) before reusing the \`${command.name}\` command.`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
command.execute(message, args, client);
|
||||||
|
}catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
message.reply("There was an error trying to execute the command.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTimeLeft(command : Command, authorId : string) {
|
||||||
|
const now = Date.now();
|
||||||
|
const timestamps : Discord.Collection<Snowflake, number> = this.cooldowns[command.name];
|
||||||
|
const cooldownAmount = command.cooldown * 1000;
|
||||||
|
|
||||||
|
if (!timestamps.has(authorId)) {
|
||||||
|
timestamps.set(authorId, now);
|
||||||
|
setTimeout(() => timestamps.delete(authorId), cooldownAmount);
|
||||||
|
}else {
|
||||||
|
const expirationTime = timestamps.get(authorId) + cooldownAmount;
|
||||||
|
|
||||||
|
if (now < expirationTime)
|
||||||
|
return (expirationTime - now) / 1000;
|
||||||
|
|
||||||
|
timestamps.set(authorId, now);
|
||||||
|
setTimeout(() => timestamps.delete(authorId), cooldownAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getCommand(message : string) {
|
||||||
|
return message.substring(this.prefix.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const client = new CustomClient();
|
||||||
|
const commandFiles = fs.readdirSync(path.join(__dirname, "commands")).filter((file : string) => file.endsWith(".js"));
|
||||||
|
|
||||||
|
for (const file of commandFiles)
|
||||||
|
client.importCommand(path.join(__dirname, "commands", file)).then();
|
||||||
|
|
||||||
|
client.on("message", message => client.handleMessage(message as Message));
|
||||||
|
|
||||||
|
client.on("ready", () => console.log("Ready!"));
|
||||||
|
|
||||||
|
client.login(token).then(() => console.log("ConjureBot logged in!"));
|
||||||
Loading…
x
Reference in New Issue
Block a user