From 945102b7cf54ce67f1c5abaf82664884444aeb01 Mon Sep 17 00:00:00 2001 From: WatDuhHekBro <44940783+WatDuhHekBro@users.noreply.github.com> Date: Tue, 30 Mar 2021 21:56:25 -0500 Subject: [PATCH] Reworked event loading --- .gitignore | 3 +- src/core/event.ts | 38 ------- src/core/handler.ts | 158 ++++++++++++++++++++++++++++ src/core/libd.ts | 37 +++---- src/events/channelCreate.ts | 13 --- src/events/channelDelete.ts | 13 --- src/events/emojiCreate.ts | 9 -- src/events/emojiDelete.ts | 9 -- src/events/emojiUpdate.ts | 9 -- src/events/guildCreate.ts | 9 -- src/events/guildDelete.ts | 9 -- src/events/message.ts | 149 -------------------------- src/events/messageReactionRemove.ts | 18 ---- src/events/ready.ts | 17 --- src/index.ts | 13 ++- src/modules/channelListener.ts | 20 ++++ src/modules/emoteRegistry.ts | 53 ++++++++++ src/modules/lavalink.ts | 39 ++++--- 18 files changed, 272 insertions(+), 344 deletions(-) delete mode 100644 src/core/event.ts create mode 100644 src/core/handler.ts delete mode 100644 src/events/channelCreate.ts delete mode 100644 src/events/channelDelete.ts delete mode 100644 src/events/emojiCreate.ts delete mode 100644 src/events/emojiDelete.ts delete mode 100644 src/events/emojiUpdate.ts delete mode 100644 src/events/guildCreate.ts delete mode 100644 src/events/guildDelete.ts delete mode 100644 src/events/message.ts delete mode 100644 src/events/messageReactionRemove.ts delete mode 100644 src/events/ready.ts create mode 100644 src/modules/channelListener.ts create mode 100644 src/modules/emoteRegistry.ts diff --git a/.gitignore b/.gitignore index a3becd9..109f5cd 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ # Specific to this repository dist/ -data/* -!data/endpoints.json +data/ tmp/ test* !test/ diff --git a/src/core/event.ts b/src/core/event.ts deleted file mode 100644 index d2b6f9a..0000000 --- a/src/core/event.ts +++ /dev/null @@ -1,38 +0,0 @@ -import {Client, ClientEvents, Constants} from "discord.js"; -import Storage from "./storage"; - -interface EventOptions { - readonly on?: (...args: ClientEvents[K]) => void; - readonly once?: (...args: ClientEvents[K]) => void; -} - -export default class Event { - private readonly on?: (...args: ClientEvents[K]) => void; - private readonly once?: (...args: ClientEvents[K]) => void; - - constructor(options: EventOptions) { - this.on = options.on; - this.once = options.once; - } - - // For this function, I'm going to assume that the event is used with the correct arguments and that the event tag is checked in "storage.ts". - public attach(client: Client, event: K) { - if (this.on) client.on(event, this.on); - if (this.once) client.once(event, this.once); - } -} - -export async function loadEvents(client: Client) { - for (const file of Storage.open("dist/events", (filename: string) => filename.endsWith(".js"))) { - const header = file.substring(0, file.indexOf(".js")); - const event = (await import(`../events/${header}`)).default; - - if ((Object.values(Constants.Events) as string[]).includes(header)) { - event.attach(client, header); - console.log(`Loading Event: ${header}`); - } else - console.warn( - `"${header}" is not a valid event type! Did you misspell it? (Note: If you fixed the issue, delete "dist" because the compiler won't automatically delete any extra files.)` - ); - } -} diff --git a/src/core/handler.ts b/src/core/handler.ts new file mode 100644 index 0000000..1de6c1e --- /dev/null +++ b/src/core/handler.ts @@ -0,0 +1,158 @@ +import {client} from "../index"; +import Command, {loadableCommands} from "../core/command"; +import {hasPermission, getPermissionLevel, getPermissionName} from "../core/permissions"; +import {Permissions} from "discord.js"; +import {getPrefix} from "../core/structures"; +import {replyEventListeners} from "../core/libd"; +import quote from "../modules/message_embed"; +import {Config} from "../core/structures"; + +client.on("message", async (message) => { + const commands = await loadableCommands; + + if (message.content.toLowerCase().includes("remember to drink water")) { + message.react("🚱"); + } + + // Message Setup // + if (message.author.bot) return; + + // If there's an inline reply, fire off that event listener (if it exists). + if (message.reference) { + const reference = message.reference; + replyEventListeners.get(`${reference.channelID}-${reference.messageID}`)?.(message); + } + + let prefix = getPrefix(message.guild); + const originalPrefix = prefix; + let exitEarly = !message.content.startsWith(prefix); + const clientUser = message.client.user; + let usesBotSpecificPrefix = false; + + if (!message.content.startsWith(prefix)) { + return quote(message); + } + + // If the client user exists, check if it starts with the bot-specific prefix. + if (clientUser) { + // If the prefix starts with the bot-specific prefix, go off that instead (these two options must mutually exclude each other). + // The pattern here has an optional space at the end to capture that and make it not mess with the header and args. + const matches = message.content.match(new RegExp(`^<@!?${clientUser.id}> ?`)); + + if (matches) { + prefix = matches[0]; + exitEarly = false; + usesBotSpecificPrefix = true; + } + } + + // If it doesn't start with the current normal prefix or the bot-specific unique prefix, exit the thread of execution early. + // Inline replies should still be captured here because if it doesn't exit early, two characters for a two-length prefix would still trigger commands. + if (exitEarly) return; + + const [header, ...args] = message.content.substring(prefix.length).split(/ +/); + + // If the message is just the prefix itself, move onto this block. + if (header === "" && args.length === 0) { + // I moved the bot-specific prefix to a separate conditional block to separate the logic. + // And because it listens for the mention as a prefix instead of a free-form mention, inline replies (probably) shouldn't ever trigger this unintentionally. + if (usesBotSpecificPrefix) { + message.channel.send(`${message.author.toString()}, my prefix on this guild is \`${originalPrefix}\`.`); + return; + } + } + + if (!commands.has(header)) return; + + if ( + message.channel.type === "text" && + !message.channel.permissionsFor(message.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}` + ); + } + + console.log( + `${message.author.username}#${message.author.discriminator} executed the command "${header}" with arguments "${args}".` + ); + + // Subcommand Recursion // + let command = commands.get(header); + if (!command) return console.warn(`Command "${header}" was called but for some reason it's still undefined!`); + const params: any[] = []; + let isEndpoint = false; + let permLevel = command.permission ?? 0; + + for (let param of args) { + if (command.endpoint) { + if (command.subcommands.size > 0 || command.user || command.number || command.any) + console.warn(`An endpoint cannot have subcommands! Check ${originalPrefix}${header} again.`); + isEndpoint = true; + break; + } + + const type = command.resolve(param); + command = command.get(param); + permLevel = command.permission ?? permLevel; + + if (type === Command.TYPES.USER) { + const id = param.match(/\d+/g)![0]; + try { + params.push(await message.client.users.fetch(id)); + } catch (error) { + return message.channel.send(`No user found by the ID \`${id}\`!`); + } + } else if (type === Command.TYPES.NUMBER) params.push(Number(param)); + else if (type !== Command.TYPES.SUBCOMMAND) params.push(param); + } + + if (!message.member) + return console.warn("This command was likely called from a DM channel meaning the member object is null."); + + if (!hasPermission(message.member, permLevel)) { + const userPermLevel = getPermissionLevel(message.member); + return message.channel.send( + `You don't have access to this command! Your permission level is \`${getPermissionName( + userPermLevel + )}\` (${userPermLevel}), but this command requires a permission level of \`${getPermissionName( + permLevel + )}\` (${permLevel}).` + ); + } + + 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({ + args: params, + author: message.author, + channel: message.channel, + client: message.client, + guild: message.guild, + member: message.member, + message: message + }); +}); + +client.once("ready", () => { + if (client.user) { + console.ready(`Logged in as ${client.user.username}#${client.user.discriminator}.`); + client.user.setActivity({ + type: "LISTENING", + name: `${Config.prefix}help` + }); + } +}); diff --git a/src/core/libd.ts b/src/core/libd.ts index ab391cf..71ba70a 100644 --- a/src/core/libd.ts +++ b/src/core/libd.ts @@ -9,36 +9,25 @@ import { NewsChannel, MessageOptions } from "discord.js"; -import FileManager from "./storage"; -import {eventListeners} from "../events/messageReactionRemove"; import {client} from "../index"; -import {EmoteRegistryDump} from "./structures"; + +// A list of message ID and callback pairs. You get the emote name and ID of the user reacting. +const eventListeners: Map void> = new Map(); + +// Attached to the client, there can be one event listener attached to a message ID which is executed if present. +client.on("messageReactionRemove", (reaction, user) => { + const canDeleteEmotes = botHasPermission(reaction.message.guild, Permissions.FLAGS.MANAGE_MESSAGES); + + if (!canDeleteEmotes) { + const callback = eventListeners.get(reaction.message.id); + callback && callback(reaction.emoji.name, user.id); + } +}); export function botHasPermission(guild: Guild | null, permission: number): boolean { return !!guild?.me?.hasPermission(permission); } -export function updateGlobalEmoteRegistry(): void { - const data: EmoteRegistryDump = {version: 1, list: []}; - - for (const guild of client.guilds.cache.values()) { - for (const emote of guild.emojis.cache.values()) { - data.list.push({ - ref: emote.name, - id: emote.id, - name: emote.name, - requires_colons: emote.requiresColons || false, - animated: emote.animated, - url: emote.url, - guild_id: emote.guild.name, - guild_name: emote.guild.name - }); - } - } - - FileManager.write("emote-registry", data, true); -} - // Maybe promisify this section to reduce the potential for creating callback hell? Especially if multiple questions in a row are being asked. // Pagination function that allows for customization via a callback. diff --git a/src/events/channelCreate.ts b/src/events/channelCreate.ts deleted file mode 100644 index 47c2aa3..0000000 --- a/src/events/channelCreate.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Event from "../core/event"; -import {client} from "../index"; -import * as discord from "discord.js"; - -export default new Event<"channelCreate">({ - async on(channel) { - const botGuilds = client.guilds; - if (channel instanceof discord.GuildChannel) { - const createdGuild = await botGuilds.fetch(channel.guild.id); - console.log(`Channel created in '${createdGuild.name}' called '#${channel.name}'`); - } - } -}); diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts deleted file mode 100644 index ac835ed..0000000 --- a/src/events/channelDelete.ts +++ /dev/null @@ -1,13 +0,0 @@ -import Event from "../core/event"; -import {client} from "../index"; -import * as discord from "discord.js"; - -export default new Event<"channelDelete">({ - async on(channel) { - const botGuilds = client.guilds; - if (channel instanceof discord.GuildChannel) { - const createdGuild = await botGuilds.fetch(channel.guild.id); - console.log(`Channel deleted in '${createdGuild.name}' called '#${channel.name}'`); - } - } -}); diff --git a/src/events/emojiCreate.ts b/src/events/emojiCreate.ts deleted file mode 100644 index 92ef88e..0000000 --- a/src/events/emojiCreate.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Event from "../core/event"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"emojiCreate">({ - on(emote) { - console.log(`Updated emote registry. ${emote.name}`); - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/events/emojiDelete.ts b/src/events/emojiDelete.ts deleted file mode 100644 index dc34190..0000000 --- a/src/events/emojiDelete.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Event from "../core/event"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"emojiDelete">({ - on() { - console.log("Updated emote registry."); - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/events/emojiUpdate.ts b/src/events/emojiUpdate.ts deleted file mode 100644 index bd0b6b0..0000000 --- a/src/events/emojiUpdate.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Event from "../core/event"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"emojiUpdate">({ - on() { - console.log("Updated emote registry."); - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/events/guildCreate.ts b/src/events/guildCreate.ts deleted file mode 100644 index 480bd4d..0000000 --- a/src/events/guildCreate.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Event from "../core/event"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"guildCreate">({ - on() { - console.log("Updated emote registry."); - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/events/guildDelete.ts b/src/events/guildDelete.ts deleted file mode 100644 index 755a049..0000000 --- a/src/events/guildDelete.ts +++ /dev/null @@ -1,9 +0,0 @@ -import Event from "../core/event"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"guildDelete">({ - on() { - console.log("Updated emote registry."); - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/events/message.ts b/src/events/message.ts deleted file mode 100644 index d805ed8..0000000 --- a/src/events/message.ts +++ /dev/null @@ -1,149 +0,0 @@ -import Event from "../core/event"; -import Command, {loadableCommands} from "../core/command"; -import {hasPermission, getPermissionLevel, getPermissionName} from "../core/permissions"; -import {Permissions} from "discord.js"; -import {getPrefix} from "../core/structures"; -import {replyEventListeners} from "../core/libd"; -import quote from "../modules/message_embed"; - -export default new Event<"message">({ - async on(message) { - const commands = await loadableCommands; - - if (message.content.toLowerCase().includes("remember to drink water")) { - message.react("🚱"); - } - - // Message Setup // - if (message.author.bot) return; - - // If there's an inline reply, fire off that event listener (if it exists). - if (message.reference) { - const reference = message.reference; - replyEventListeners.get(`${reference.channelID}-${reference.messageID}`)?.(message); - } - - let prefix = getPrefix(message.guild); - const originalPrefix = prefix; - let exitEarly = !message.content.startsWith(prefix); - const clientUser = message.client.user; - let usesBotSpecificPrefix = false; - - if (!message.content.startsWith(prefix)) { - return quote(message); - } - - // If the client user exists, check if it starts with the bot-specific prefix. - if (clientUser) { - // If the prefix starts with the bot-specific prefix, go off that instead (these two options must mutually exclude each other). - // The pattern here has an optional space at the end to capture that and make it not mess with the header and args. - const matches = message.content.match(new RegExp(`^<@!?${clientUser.id}> ?`)); - - if (matches) { - prefix = matches[0]; - exitEarly = false; - usesBotSpecificPrefix = true; - } - } - - // If it doesn't start with the current normal prefix or the bot-specific unique prefix, exit the thread of execution early. - // Inline replies should still be captured here because if it doesn't exit early, two characters for a two-length prefix would still trigger commands. - if (exitEarly) return; - - const [header, ...args] = message.content.substring(prefix.length).split(/ +/); - - // If the message is just the prefix itself, move onto this block. - if (header === "" && args.length === 0) { - // I moved the bot-specific prefix to a separate conditional block to separate the logic. - // And because it listens for the mention as a prefix instead of a free-form mention, inline replies (probably) shouldn't ever trigger this unintentionally. - if (usesBotSpecificPrefix) { - message.channel.send(`${message.author.toString()}, my prefix on this guild is \`${originalPrefix}\`.`); - return; - } - } - - if (!commands.has(header)) return; - - if ( - message.channel.type === "text" && - !message.channel.permissionsFor(message.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}` - ); - } - - console.log( - `${message.author.username}#${message.author.discriminator} executed the command "${header}" with arguments "${args}".` - ); - - // Subcommand Recursion // - let command = commands.get(header); - if (!command) return console.warn(`Command "${header}" was called but for some reason it's still undefined!`); - const params: any[] = []; - let isEndpoint = false; - let permLevel = command.permission ?? 0; - - for (let param of args) { - if (command.endpoint) { - if (command.subcommands.size > 0 || command.user || command.number || command.any) - console.warn(`An endpoint cannot have subcommands! Check ${originalPrefix}${header} again.`); - isEndpoint = true; - break; - } - - const type = command.resolve(param); - command = command.get(param); - permLevel = command.permission ?? permLevel; - - if (type === Command.TYPES.USER) { - const id = param.match(/\d+/g)![0]; - try { - params.push(await message.client.users.fetch(id)); - } catch (error) { - return message.channel.send(`No user found by the ID \`${id}\`!`); - } - } else if (type === Command.TYPES.NUMBER) params.push(Number(param)); - else if (type !== Command.TYPES.SUBCOMMAND) params.push(param); - } - - if (!message.member) - return console.warn("This command was likely called from a DM channel meaning the member object is null."); - - if (!hasPermission(message.member, permLevel)) { - const userPermLevel = getPermissionLevel(message.member); - return message.channel.send( - `You don't have access to this command! Your permission level is \`${getPermissionName( - userPermLevel - )}\` (${userPermLevel}), but this command requires a permission level of \`${getPermissionName( - permLevel - )}\` (${permLevel}).` - ); - } - - 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({ - args: params, - author: message.author, - channel: message.channel, - client: message.client, - guild: message.guild, - member: message.member, - message: message - }); - } -}); diff --git a/src/events/messageReactionRemove.ts b/src/events/messageReactionRemove.ts deleted file mode 100644 index 4b3dbb2..0000000 --- a/src/events/messageReactionRemove.ts +++ /dev/null @@ -1,18 +0,0 @@ -import Event from "../core/event"; -import {Permissions} from "discord.js"; -import {botHasPermission} from "../core/libd"; - -// A list of message ID and callback pairs. You get the emote name and ID of the user reacting. -export const eventListeners: Map void> = new Map(); - -// Attached to the client, there can be one event listener attached to a message ID which is executed if present. -export default new Event<"messageReactionRemove">({ - on(reaction, user) { - const canDeleteEmotes = botHasPermission(reaction.message.guild, Permissions.FLAGS.MANAGE_MESSAGES); - - if (!canDeleteEmotes) { - const callback = eventListeners.get(reaction.message.id); - callback && callback(reaction.emoji.name, user.id); - } - } -}); diff --git a/src/events/ready.ts b/src/events/ready.ts deleted file mode 100644 index a4e1b9c..0000000 --- a/src/events/ready.ts +++ /dev/null @@ -1,17 +0,0 @@ -import Event from "../core/event"; -import {client} from "../index"; -import {Config} from "../core/structures"; -import {updateGlobalEmoteRegistry} from "../core/libd"; - -export default new Event<"ready">({ - once() { - if (client.user) { - console.ready(`Logged in as ${client.user.username}#${client.user.discriminator}.`); - client.user.setActivity({ - type: "LISTENING", - name: `${Config.prefix}help` - }); - } - updateGlobalEmoteRegistry(); - } -}); diff --git a/src/index.ts b/src/index.ts index 2ccf92c..9f709e0 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,17 +1,20 @@ +// Bootstrapping Section // import "./globals"; import {Client} from "discord.js"; import setup from "./setup"; import {Config} from "./core/structures"; -import {loadEvents} from "./core/event"; -import {attachToClient} from "./modules/lavalink"; // This is here in order to make it much less of a headache to access the client from other files. // This of course won't actually do anything until the setup process is complete and it logs in. export const client = new Client(); -attachToClient(client); -// Command loading will start as soon as an instance of "core/command" is loaded, which is loaded during "events/message". +// Send the login request to Discord's API and then load modules while waiting for it. setup.init().then(() => { - loadEvents(client); client.login(Config.token).catch(setup.again); }); + +// Initialize Modules // +import "./core/handler"; // Command loading will start as soon as an instance of "core/command" is loaded, which is loaded in "core/handler". +import "./modules/lavalink"; +import "./modules/emoteRegistry"; +import "./modules/channelListener"; diff --git a/src/modules/channelListener.ts b/src/modules/channelListener.ts new file mode 100644 index 0000000..910d1ab --- /dev/null +++ b/src/modules/channelListener.ts @@ -0,0 +1,20 @@ +import {client} from "../index"; +import {GuildChannel} from "discord.js"; + +client.on("channelCreate", async (channel) => { + const botGuilds = client.guilds; + + if (channel instanceof GuildChannel) { + const createdGuild = await botGuilds.fetch(channel.guild.id); + console.log(`Channel created in '${createdGuild.name}' called '#${channel.name}'`); + } +}); + +client.on("channelDelete", async (channel) => { + const botGuilds = client.guilds; + + if (channel instanceof GuildChannel) { + const createdGuild = await botGuilds.fetch(channel.guild.id); + console.log(`Channel deleted in '${createdGuild.name}' called '#${channel.name}'`); + } +}); diff --git a/src/modules/emoteRegistry.ts b/src/modules/emoteRegistry.ts new file mode 100644 index 0000000..bcc7ed0 --- /dev/null +++ b/src/modules/emoteRegistry.ts @@ -0,0 +1,53 @@ +import {client} from "../index"; +import FileManager from "../core/storage"; +import {EmoteRegistryDump} from "../core/structures"; + +function updateGlobalEmoteRegistry(): void { + const data: EmoteRegistryDump = {version: 1, list: []}; + + for (const guild of client.guilds.cache.values()) { + for (const emote of guild.emojis.cache.values()) { + data.list.push({ + ref: emote.name, + id: emote.id, + name: emote.name, + requires_colons: emote.requiresColons || false, + animated: emote.animated, + url: emote.url, + guild_id: emote.guild.name, + guild_name: emote.guild.name + }); + } + } + + FileManager.write("emote-registry", data, true); +} + +client.on("emojiCreate", (emote) => { + console.log(`Updated emote registry. ${emote.name}`); + updateGlobalEmoteRegistry(); +}); + +client.on("emojiDelete", () => { + console.log("Updated emote registry."); + updateGlobalEmoteRegistry(); +}); + +client.on("emojiUpdate", () => { + console.log("Updated emote registry."); + updateGlobalEmoteRegistry(); +}); + +client.on("guildCreate", () => { + console.log("Updated emote registry."); + updateGlobalEmoteRegistry(); +}); + +client.on("guildDelete", () => { + console.log("Updated emote registry."); + updateGlobalEmoteRegistry(); +}); + +client.on("ready", () => { + updateGlobalEmoteRegistry(); +}); diff --git a/src/modules/lavalink.ts b/src/modules/lavalink.ts index 5e0ff90..39dc5c8 100644 --- a/src/modules/lavalink.ts +++ b/src/modules/lavalink.ts @@ -1,6 +1,7 @@ -import {Presence, Client} from "discord.js"; +import {Presence} from "discord.js"; import LavalinkMusic from "discord.js-lavalink-lib"; import {Config} from "../core/structures"; +import {client} from "../index"; declare module "discord.js" { interface Presence { @@ -28,26 +29,24 @@ Presence.prototype.patch = function patch(data: any) { // the function which handles those packets is NOP-ed out, which, among other // things, skips the code which caches the referenced users in the packet. See // . -export function attachToClient(client: Client) { - (client["actions"] as any)["PresenceUpdate"].handle = () => {}; +(client["actions"] as any)["PresenceUpdate"].handle = () => {}; - (client as any).music = LavalinkMusic(client, { - lavalink: { - restnode: { +(client as any).music = LavalinkMusic(client, { + lavalink: { + restnode: { + host: "localhost", + port: 2333, + password: "youshallnotpass" + }, + nodes: [ + { host: "localhost", port: 2333, password: "youshallnotpass" - }, - nodes: [ - { - host: "localhost", - port: 2333, - password: "youshallnotpass" - } - ] - }, - prefix: Config.prefix, - helpCmd: "mhelp", - admins: ["717352467280691331"] - }); -} + } + ] + }, + prefix: Config.prefix, + helpCmd: "mhelp", + admins: ["717352467280691331"] +});