mirror of
				https://github.com/keanuplayz/TravBot-v3.git
				synced 2024-08-15 02:33:12 +00:00 
			
		
		
		
	Reworked event loading
This commit is contained in:
		
							parent
							
								
									3ef487c4a4
								
							
						
					
					
						commit
						945102b7cf
					
				
					 18 changed files with 272 additions and 344 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
										
									
									
										vendored
									
									
								
							|  | @ -1,7 +1,6 @@ | |||
| # Specific to this repository | ||||
| dist/ | ||||
| data/* | ||||
| !data/endpoints.json | ||||
| data/ | ||||
| tmp/ | ||||
| test* | ||||
| !test/ | ||||
|  |  | |||
|  | @ -1,38 +0,0 @@ | |||
| import {Client, ClientEvents, Constants} from "discord.js"; | ||||
| import Storage from "./storage"; | ||||
| 
 | ||||
| interface EventOptions<K extends keyof ClientEvents> { | ||||
|     readonly on?: (...args: ClientEvents[K]) => void; | ||||
|     readonly once?: (...args: ClientEvents[K]) => void; | ||||
| } | ||||
| 
 | ||||
| export default class Event<K extends keyof ClientEvents> { | ||||
|     private readonly on?: (...args: ClientEvents[K]) => void; | ||||
|     private readonly once?: (...args: ClientEvents[K]) => void; | ||||
| 
 | ||||
|     constructor(options: EventOptions<K>) { | ||||
|         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.)` | ||||
|             ); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										158
									
								
								src/core/handler.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								src/core/handler.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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` | ||||
|         }); | ||||
|     } | ||||
| }); | ||||
|  | @ -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<string, (emote: string, id: string) => 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.
 | ||||
|  |  | |||
|  | @ -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}'`); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|  | @ -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}'`); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
|  | @ -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 | ||||
|         }); | ||||
|     } | ||||
| }); | ||||
|  | @ -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<string, (emote: string, id: string) => 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); | ||||
|         } | ||||
|     } | ||||
| }); | ||||
|  | @ -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(); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										13
									
								
								src/index.ts
									
										
									
									
									
								
							
							
						
						
									
										13
									
								
								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"; | ||||
|  |  | |||
							
								
								
									
										20
									
								
								src/modules/channelListener.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/modules/channelListener.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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}'`); | ||||
|     } | ||||
| }); | ||||
							
								
								
									
										53
									
								
								src/modules/emoteRegistry.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								src/modules/emoteRegistry.ts
									
										
									
									
									
										Normal file
									
								
							|  | @ -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(); | ||||
| }); | ||||
|  | @ -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,7 +29,6 @@ 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
 | ||||
| // <https://github.com/discordjs/discord.js/blob/cee6cf70ce76e9b06dc7f25bfd77498e18d7c8d4/src/client/actions/PresenceUpdate.js#L7-L41>.
 | ||||
| export function attachToClient(client: Client) { | ||||
| (client["actions"] as any)["PresenceUpdate"].handle = () => {}; | ||||
| 
 | ||||
| (client as any).music = LavalinkMusic(client, { | ||||
|  | @ -50,4 +50,3 @@ export function attachToClient(client: Client) { | |||
|     helpCmd: "mhelp", | ||||
|     admins: ["717352467280691331"] | ||||
| }); | ||||
| } | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue