Add autocomplete manager + context menu bugfixes

This commit is contained in:
DJj123dj
2025-06-21 22:16:50 +02:00
parent 2ea38cd7a5
commit e987c176b7
4 changed files with 90 additions and 19 deletions
+81 -15
View File
@@ -78,6 +78,8 @@ export class ODClientManager {
textCommands: ODTextCommandManager textCommands: ODTextCommandManager
/**The context menu manager is responsible for all context menus & their events inside the bot. */ /**The context menu manager is responsible for all context menus & their events inside the bot. */
contextMenus: ODContextMenuManager contextMenus: ODContextMenuManager
/**The autocomplete manager is responsible for all autocomplete events inside the bot. */
autocompletes: ODAutocompleteManager
constructor(debug:ODDebugger){ constructor(debug:ODDebugger){
this.#debug = debug this.#debug = debug
@@ -85,6 +87,7 @@ export class ODClientManager {
this.slashCommands = new ODSlashCommandManager(this.#debug,this) this.slashCommands = new ODSlashCommandManager(this.#debug,this)
this.textCommands = new ODTextCommandManager(this.#debug,this) this.textCommands = new ODTextCommandManager(this.#debug,this)
this.contextMenus = new ODContextMenuManager(this.#debug,this) this.contextMenus = new ODContextMenuManager(this.#debug,this)
this.autocompletes = new ODAutocompleteManager(this.#debug,this)
} }
/**Initiate the `client` variable & add the intents & partials to the bot. */ /**Initiate the `client` variable & add the intents & partials to the bot. */
@@ -152,6 +155,7 @@ export class ODClientManager {
if (!this.client.application) throw new ODSystemError("Couldn't get client application for slashCommand & contextMenu managers!") if (!this.client.application) throw new ODSystemError("Couldn't get client application for slashCommand & contextMenu managers!")
this.slashCommands.commandManager = this.client.application.commands this.slashCommands.commandManager = this.client.application.commands
this.contextMenus.commandManager = this.client.application.commands this.contextMenus.commandManager = this.client.application.commands
this.autocompletes.commandManager = this.client.application.commands
if (this.readyListener) await this.readyListener() if (this.readyListener) await this.readyListener()
resolve(true) resolve(true)
@@ -1920,7 +1924,7 @@ export class ODContextMenuComparator {
} }
/**## ODContextMenuInteractionCallback `type` /**## ODContextMenuInteractionCallback `type`
* Callback for the message context menu interaction listener. * Callback for the context menu interaction listener.
*/ */
export type ODContextMenuInteractionCallback = (interaction:discord.ContextMenuCommandInteraction,cmd:ODContextMenu) => void export type ODContextMenuInteractionCallback = (interaction:discord.ContextMenuCommandInteraction,cmd:ODContextMenu) => void
@@ -1928,29 +1932,29 @@ export type ODContextMenuInteractionCallback = (interaction:discord.ContextMenuC
* The result which will be returned when getting all (un)registered user context menu's from the manager. * The result which will be returned when getting all (un)registered user context menu's from the manager.
*/ */
export type ODContextMenuRegisteredResult = { export type ODContextMenuRegisteredResult = {
/**A list of all registered message context menus. */ /**A list of all registered context menus. */
registered:{ registered:{
/**The instance (`ODContextMenu`) from this message context menu. */ /**The instance (`ODContextMenu`) from this context menu. */
instance:ODContextMenu, instance:ODContextMenu,
/**The universal object/template/builder of this message context menu. */ /**The universal object/template/builder of this context menu. */
menu:ODContextMenuUniversalMenu, menu:ODContextMenuUniversalMenu,
/**Does this message context menu require an update? */ /**Does this context menu require an update? */
requiresUpdate:boolean requiresUpdate:boolean
}[], }[],
/**A list of all unregistered message context menus. */ /**A list of all unregistered context menus. */
unregistered:{ unregistered:{
/**The instance (`ODContextMenu`) from this message context menu. */ /**The instance (`ODContextMenu`) from this context menu. */
instance:ODContextMenu, instance:ODContextMenu,
/**The universal object/template/builder of this message context menu. */ /**The universal object/template/builder of this context menu. */
menu:null, menu:null,
/**Does this message context menu require an update? */ /**Does this context menu require an update? */
requiresUpdate:true requiresUpdate:true
}[], }[],
/**A list of all unused message context menus (not found in `ODContextMenuManager`). */ /**A list of all unused context menus (not found in `ODContextMenuManager`). */
unused:{ unused:{
/**The instance (`ODContextMenu`) from this message context menu. */ /**The instance (`ODContextMenu`) from this context menu. */
instance:null, instance:null,
/**The universal object/template/builder of this message context menu. */ /**The universal object/template/builder of this context menu. */
menu:ODContextMenuUniversalMenu, menu:ODContextMenuUniversalMenu,
/**Does this context menu require an update? */ /**Does this context menu require an update? */
requiresUpdate:false requiresUpdate:false
@@ -1958,11 +1962,11 @@ export type ODContextMenuRegisteredResult = {
} }
/**## ODContextMenuManager `class` /**## ODContextMenuManager `class`
* This is an Open Ticket client message context menu manager. * This is an Open Ticket client context menu manager.
* *
* It's responsible for managing all the message context interactions from the client. * It's responsible for managing all the context interactions from the client.
* *
* Here, you can add & remove message context interactions & the bot will do the (de)registering. * Here, you can add & remove context interactions & the bot will do the (de)registering.
*/ */
export class ODContextMenuManager extends ODManager<ODContextMenu> { export class ODContextMenuManager extends ODManager<ODContextMenu> {
/**Alias to Open Ticket debugger. */ /**Alias to Open Ticket debugger. */
@@ -2175,4 +2179,66 @@ export class ODContextMenu extends ODManagerData {
set name(name:string){ set name(name:string){
this.builder.name = name this.builder.name = name
} }
}
/**## ODAutocompleteInteractionCallback `type`
* Callback for the autocomplete interaction listener.
*/
export type ODAutocompleteInteractionCallback = (interaction:discord.AutocompleteInteraction) => void
/**## ODAutocompleteManager `class`
* This is an Open Ticket client autocomplete interaction manager.
*
* It's responsible for managing all the autocomplete interactions from the client.
*/
export class ODAutocompleteManager {
/**Alias to Open Ticket debugger. */
#debug: ODDebugger
/**Refrerence to discord.js client. */
manager: ODClientManager
/**Discord.js application commands manager. */
commandManager: discord.ApplicationCommandManager|null
/**Collection of all interaction listeners. */
#interactionListeners: {cmdName:string|RegExp, optName:string|RegExp, callback:ODAutocompleteInteractionCallback}[] = []
/**Set the soft limit for maximum amount of listeners. A warning will be shown when there are more listeners than this limit. */
listenerLimit: number = 100
constructor(debug:ODDebugger, manager:ODClientManager){
this.#debug = debug
this.manager = manager
this.commandManager = (manager.client.application) ? manager.client.application.commands : null
}
/**Start listening to the discord.js client `interactionCreate` event. */
startListeningToInteractions(){
this.manager.client.on("interactionCreate",(interaction) => {
//return when not in main server or DM
if (!this.manager.mainServer || (interaction.guild && interaction.guild.id != this.manager.mainServer.id)) return
if (!interaction.isAutocomplete()) return
this.#interactionListeners.forEach((listener) => {
if (typeof listener.cmdName == "string" && (interaction.commandName != listener.cmdName)) return
else if (listener.cmdName instanceof RegExp && !listener.cmdName.test(interaction.commandName)) return
if (typeof listener.optName == "string" && (interaction.options.getFocused(true).name != listener.optName)) return
else if (listener.optName instanceof RegExp && !listener.optName.test(interaction.options.getFocused(true).name)) return
//this is a valid listener
listener.callback(interaction)
})
})
}
/**Callback on interaction from one or multiple autocompletes. */
onInteraction(cmdName:string|RegExp,optName:string|RegExp,callback:ODAutocompleteInteractionCallback){
this.#interactionListeners.push({
cmdName,optName,callback
})
if (this.#interactionListeners.length > this.listenerLimit){
this.#debug.console.log("Possible autocomplete interaction memory leak detected!","warning",[
{key:"listeners",value:this.#interactionListeners.length.toString()}
])
}
}
} }
+4 -1
View File
@@ -47,7 +47,10 @@ export const loadVersionMigrationSystem = async () => {
if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.defaults.setDefault("pluginLoading",false) if (opendiscord.flags.exists("opendiscord:no-plugins") && opendiscord.flags.get("opendiscord:no-plugins").value) opendiscord.defaults.setDefault("pluginLoading",false)
if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.defaults.setDefault("softPluginLoading",true) if (opendiscord.flags.exists("opendiscord:soft-plugins") && opendiscord.flags.get("opendiscord:soft-plugins").value) opendiscord.defaults.setDefault("softPluginLoading",true)
if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.defaults.setDefault("crashOnError",true) if (opendiscord.flags.exists("opendiscord:crash") && opendiscord.flags.get("opendiscord:crash").value) opendiscord.defaults.setDefault("crashOnError",true)
if (opendiscord.flags.exists("opendiscord:force-slash-update") && opendiscord.flags.get("opendiscord:force-slash-update").value) opendiscord.defaults.setDefault("forceSlashCommandRegistration",true) if (opendiscord.flags.exists("opendiscord:force-slash-update") && opendiscord.flags.get("opendiscord:force-slash-update").value){
opendiscord.defaults.setDefault("forceSlashCommandRegistration",true)
opendiscord.defaults.setDefault("forceContextMenuRegistration",true)
}
if (opendiscord.flags.exists("opendiscord:silent") && opendiscord.flags.get("opendiscord:silent").value) opendiscord.console.silent = true if (opendiscord.flags.exists("opendiscord:silent") && opendiscord.flags.get("opendiscord:silent").value) opendiscord.console.silent = true
+2
View File
@@ -62,6 +62,8 @@ export const loadStartListeningInteractionsCode = async () => {
opendiscord.code.add(new api.ODCode("opendiscord:start-listening-interactions",13,() => { opendiscord.code.add(new api.ODCode("opendiscord:start-listening-interactions",13,() => {
opendiscord.client.slashCommands.startListeningToInteractions() opendiscord.client.slashCommands.startListeningToInteractions()
opendiscord.client.textCommands.startListeningToInteractions() opendiscord.client.textCommands.startListeningToInteractions()
opendiscord.client.contextMenus.startListeningToInteractions()
opendiscord.client.autocompletes.startListeningToInteractions()
})) }))
} }
+3 -3
View File
@@ -384,7 +384,7 @@ const main = async () => {
if (!mainServer || !client.checkBotInGuild(mainServer)){ if (!mainServer || !client.checkBotInGuild(mainServer)){
console.log("\n") console.log("\n")
opendiscord.log("The bot isn't a member of the server provided in the config!","error") opendiscord.log("The bot isn't a member of the server provided in the config!","error")
opendiscord.log("Please invite your bot to the server!","info") opendiscord.log("Please invite your bot to this server!","info")
console.log("\n") console.log("\n")
process.exit(1) process.exit(1)
} }
@@ -399,8 +399,8 @@ const main = async () => {
if (opendiscord.defaults.getDefault("clientMultiGuildWarning")){ if (opendiscord.defaults.getDefault("clientMultiGuildWarning")){
//warn if bot is in multiple servers //warn if bot is in multiple servers
if (botServers.length > 1){ if (botServers.length > 1){
opendiscord.log("This bot is part of multiple servers, but Open Ticket doesn't have support for it!","warning") opendiscord.log("This bot is part of multiple servers, but Open Ticket doesn't provide support for this!","warning")
opendiscord.log("It may result in the bot crashing & glitching when used in these servers!","info") opendiscord.log("As a result, the bot may crash & glitch when used in the additional servers!","info")
} }
botServers.forEach((server) => { botServers.forEach((server) => {
//warn if bot doesn't have permissions in multiple servers //warn if bot doesn't have permissions in multiple servers