✨ Début de l'implémentation du command handler
This commit is contained in:
parent
c09fc4f4e8
commit
a9b91137a1
32
src/base/classes/Command.ts
Normal file
32
src/base/classes/Command.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import { ChatInputCommandInteraction, AutocompleteInteraction } from "discord.js";
|
||||
import { Category } from "../enums/Category";
|
||||
import {ICommand} from "../interfaces/ICommand";
|
||||
import {CustomClient} from "./CustomClient";
|
||||
import {ICommandOptions} from "../interfaces/ICommandOptions";
|
||||
|
||||
export class Command implements ICommand {
|
||||
client: CustomClient;
|
||||
name: string;
|
||||
description: string;
|
||||
category: Category;
|
||||
options: object;
|
||||
default_member_permissions: bigint;
|
||||
dm_permissions: boolean;
|
||||
cooldown: number;
|
||||
|
||||
constructor(client: CustomClient, options: ICommandOptions) {
|
||||
this.client = client;
|
||||
this.name = options.name;
|
||||
this.description = options.description;
|
||||
this.category = options.category;
|
||||
this.options = options.options;
|
||||
this.default_member_permissions = options.default_member_permissions;
|
||||
this.dm_permissions = options.dm_permissions;
|
||||
this.cooldown = options.cooldown;
|
||||
}
|
||||
|
||||
execute(interaction: ChatInputCommandInteraction): void {
|
||||
}
|
||||
autocomplete(interaction: AutocompleteInteraction): void {
|
||||
}
|
||||
}
|
@ -1,18 +1,29 @@
|
||||
import IConfig from "../interfaces/IConfig";
|
||||
import ICustomClient from "../interfaces/ICustomClient";
|
||||
import {Client} from "discord.js";
|
||||
import Handler from "./Handler";
|
||||
import {IConfig} from "../interfaces/IConfig";
|
||||
import {ICustomClient} from "../interfaces/ICustomClient";
|
||||
import {Client, Collection, GatewayIntentBits} from "discord.js";
|
||||
import {Handler} from "./Handler";
|
||||
import {Command} from "./Command";
|
||||
import {SubCommand} from "./SubCommand";
|
||||
|
||||
export default class CustomClient extends Client implements ICustomClient {
|
||||
export class CustomClient extends Client implements ICustomClient {
|
||||
config: IConfig;
|
||||
handler: Handler;
|
||||
commands: Collection<string, Command>;
|
||||
subCommands: Collection<string, SubCommand>;
|
||||
cooldowns: Collection<string, Collection<string, number>>;
|
||||
|
||||
constructor() {
|
||||
super({
|
||||
intents: [],
|
||||
intents: Object.keys(GatewayIntentBits).map((a: string) => {
|
||||
return GatewayIntentBits[a as keyof typeof GatewayIntentBits];
|
||||
}),
|
||||
})
|
||||
|
||||
this.config = require(`${process.cwd()}/data/config.json`);
|
||||
this.handler = new Handler(this);
|
||||
this.commands = new Collection();
|
||||
this.subCommands = new Collection();
|
||||
this.cooldowns = new Collection();
|
||||
}
|
||||
async init(): Promise<void> {
|
||||
await this.LoadHandlers();
|
||||
@ -21,6 +32,7 @@ export default class CustomClient extends Client implements ICustomClient {
|
||||
|
||||
async LoadHandlers(): Promise<void> {
|
||||
await this.handler.loadEvents();
|
||||
await this.handler.loadCommands();
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import { Events } from "discord.js";
|
||||
import IEvent from "../interfaces/IEvent";
|
||||
import CustomClient from "./CustomClient";
|
||||
import IEventOptions from "../interfaces/IEventOptions";
|
||||
import {ClientEvents} from "discord.js";
|
||||
import {IEvent} from "../interfaces/IEvent";
|
||||
import {CustomClient} from "./CustomClient";
|
||||
import {IEventOptions} from "../interfaces/IEventOptions";
|
||||
|
||||
export default class Event implements IEvent {
|
||||
export class Event implements IEvent {
|
||||
client: CustomClient;
|
||||
name: Events;
|
||||
name: keyof ClientEvents;
|
||||
description: string;
|
||||
once: boolean;
|
||||
|
||||
|
@ -1,10 +1,12 @@
|
||||
import IHandler from "../interfaces/IHandler";
|
||||
import {IHandler} from "../interfaces/IHandler";
|
||||
import path from "node:path";
|
||||
import {glob} from "glob";
|
||||
import CustomClient from "./CustomClient";
|
||||
import Event from "./Event";
|
||||
import {CustomClient} from "./CustomClient";
|
||||
import {Event} from "./Event";
|
||||
import {Command} from "./Command";
|
||||
import {SubCommand} from "./SubCommand";
|
||||
|
||||
export default class Handler implements IHandler {
|
||||
export class Handler implements IHandler {
|
||||
client: CustomClient;
|
||||
constructor(client: CustomClient) {
|
||||
this.client = client;
|
||||
@ -13,18 +15,28 @@ export default class Handler implements IHandler {
|
||||
const files = (await glob(`dist/events/**/*.js`)).map(filePath => path.resolve(filePath));
|
||||
|
||||
files.map(async (file: string) => {
|
||||
const event : Event = new (await import(file)).default(this.client);
|
||||
let evt = await import(file);
|
||||
let EventClass: any;
|
||||
for (const key in evt) {
|
||||
if (typeof evt[key] === 'function') {
|
||||
EventClass = evt[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EventClass) {
|
||||
return delete require.cache[require.resolve(file)] && console.log(`Event ${file.split('/').pop()} n'a pas de classe`);
|
||||
}
|
||||
|
||||
const event : Event = new EventClass(this.client);
|
||||
|
||||
if (!event.name)
|
||||
return delete require.cache[require.resolve(file)] && console.log(`Event ${file.split('/').pop()} n'a pas de nom`);
|
||||
|
||||
const execute = (...args: any[]) => event.execute(...args);
|
||||
|
||||
if (event.once) {
|
||||
// @ts-ignore
|
||||
this.client.once(event.name, execute);
|
||||
} else {
|
||||
// @ts-ignore
|
||||
this.client.on(event.name, execute);
|
||||
}
|
||||
|
||||
@ -34,4 +46,39 @@ export default class Handler implements IHandler {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async loadCommands(): Promise<void> {
|
||||
const files = (await glob(`dist/commands/**/*.js`)).map(filePath => path.resolve(filePath));
|
||||
|
||||
files.map(async (file: string) => {
|
||||
let evt = await import(file);
|
||||
let EventClass: any;
|
||||
for (const key in evt) {
|
||||
if (typeof evt[key] === 'function') {
|
||||
EventClass = evt[key];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EventClass) {
|
||||
return delete require.cache[require.resolve(file)] && console.log(`Event ${file.split('/').pop()} n'a pas de classe`);
|
||||
}
|
||||
|
||||
const command : Command|SubCommand = new EventClass(this.client);
|
||||
|
||||
if (!command.name)
|
||||
return delete require.cache[require.resolve(file)] && console.log(`Event ${file.split('/').pop()} n'a pas de nom`);
|
||||
|
||||
if (file.split('/').pop()?.split(".")[2]) {
|
||||
console.log(`Sous Commande ${file.split('/').pop()} chargé`);
|
||||
this.client.subCommands.set(command.name, command as SubCommand);
|
||||
} else {
|
||||
console.log(`Commande ${file.split('/').pop()} chargé`);
|
||||
this.client.commands.set(command.name, command as Command);
|
||||
}
|
||||
|
||||
return delete require.cache[require.resolve(file)];
|
||||
});
|
||||
}
|
||||
|
||||
}
|
18
src/base/classes/SubCommand.ts
Normal file
18
src/base/classes/SubCommand.ts
Normal file
@ -0,0 +1,18 @@
|
||||
import { ChatInputCommandInteraction } from "discord.js";
|
||||
import {ISubCommand} from "../interfaces/ISubCommand";
|
||||
import {CustomClient} from "./CustomClient";
|
||||
import {ISubCommandOptions} from "../interfaces/ISubCommandOptions";
|
||||
|
||||
export class SubCommand implements ISubCommand {
|
||||
client: CustomClient;
|
||||
name: string;
|
||||
|
||||
constructor(client: CustomClient,options: ISubCommandOptions) {
|
||||
this.client = client;
|
||||
this.name = options.name;
|
||||
}
|
||||
|
||||
execute(interaction: ChatInputCommandInteraction): void {
|
||||
}
|
||||
|
||||
}
|
4
src/base/enums/Category.ts
Normal file
4
src/base/enums/Category.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export enum Category {
|
||||
UTILITIES = 'Utilitaires',
|
||||
}
|
||||
|
17
src/base/interfaces/ICommand.ts
Normal file
17
src/base/interfaces/ICommand.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {CustomClient} from "../classes/CustomClient";
|
||||
import {AutocompleteInteraction, ChatInputCommandInteraction} from "discord.js";
|
||||
import {Category} from "../enums/Category";
|
||||
|
||||
export interface ICommand {
|
||||
client: CustomClient;
|
||||
name: string;
|
||||
description: string;
|
||||
category: Category;
|
||||
options: object;
|
||||
default_member_permissions: bigint;
|
||||
dm_permissions: boolean;
|
||||
cooldown: number;
|
||||
|
||||
execute(interaction: ChatInputCommandInteraction): void;
|
||||
autocomplete(interaction: AutocompleteInteraction): void;
|
||||
}
|
11
src/base/interfaces/ICommandOptions.ts
Normal file
11
src/base/interfaces/ICommandOptions.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import {Category} from "../enums/Category";
|
||||
|
||||
export interface ICommandOptions {
|
||||
name: string;
|
||||
description: string;
|
||||
category: Category;
|
||||
options: object;
|
||||
default_member_permissions: bigint;
|
||||
dm_permissions: boolean;
|
||||
cooldown: number;
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
export default interface IConfig {
|
||||
export interface IConfig {
|
||||
token: string;
|
||||
}
|
@ -1,7 +1,14 @@
|
||||
import IConfig from "./IConfig";
|
||||
import {IConfig} from "./IConfig";
|
||||
import {Command} from "../classes/Command";
|
||||
import {Collection} from "discord.js";
|
||||
import {SubCommand} from "../classes/SubCommand";
|
||||
|
||||
export default interface ICustomClient {
|
||||
export interface ICustomClient {
|
||||
config: IConfig;
|
||||
commands: Collection<string, Command>;
|
||||
subCommands: Collection<string, SubCommand>;
|
||||
cooldowns: Collection<string, Collection<string, number>>;
|
||||
|
||||
init(): void;
|
||||
LoadHandlers(): void;
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import CustomClient from "../classes/CustomClient";
|
||||
import {Events} from "discord.js";
|
||||
import {CustomClient} from "../classes/CustomClient";
|
||||
import {ClientEvents} from "discord.js";
|
||||
|
||||
export default interface IEvent {
|
||||
export interface IEvent {
|
||||
client: CustomClient;
|
||||
name: Events;
|
||||
name: keyof ClientEvents;
|
||||
description: string;
|
||||
once: boolean;
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Events} from "discord.js";
|
||||
import {ClientEvents} from "discord.js";
|
||||
|
||||
export default interface IEventOptions {
|
||||
name: Events;
|
||||
export interface IEventOptions {
|
||||
name: keyof ClientEvents;
|
||||
description: string;
|
||||
once: boolean;
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
export default interface IHandler {
|
||||
export interface IHandler {
|
||||
loadEvents(): void;
|
||||
loadCommands(): void;
|
||||
}
|
9
src/base/interfaces/ISubCommand.ts
Normal file
9
src/base/interfaces/ISubCommand.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import {CustomClient} from "../classes/CustomClient";
|
||||
import {ChatInputCommandInteraction} from "discord.js";
|
||||
|
||||
export interface ISubCommand {
|
||||
client: CustomClient;
|
||||
name: string;
|
||||
|
||||
execute(interaction: ChatInputCommandInteraction): void;
|
||||
}
|
3
src/base/interfaces/ISubCommandOptions.ts
Normal file
3
src/base/interfaces/ISubCommandOptions.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface ISubCommandOptions {
|
||||
name: string;
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import Event from '../../base/classes/Event';
|
||||
import CustomClient from "../../base/classes/CustomClient";
|
||||
import {Event} from '../../base/classes/Event';
|
||||
import {CustomClient} from "../../base/classes/CustomClient";
|
||||
import {Events} from "discord.js";
|
||||
export default class Ready extends Event {
|
||||
export class Ready extends Event {
|
||||
constructor(client: CustomClient) {
|
||||
super(client, {
|
||||
name: Events.ClientReady,
|
||||
|
44
src/events/guild/CommandHandler.ts
Normal file
44
src/events/guild/CommandHandler.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import {ChatInputCommandInteraction, Collection, Events} from "discord.js";
|
||||
import {CustomClient} from "../../base/classes/CustomClient";
|
||||
import {Event} from "../../base/classes/Event";
|
||||
import {Command} from "../../base/classes/Command";
|
||||
|
||||
export class CommandHandler extends Event {
|
||||
constructor(client: CustomClient) {
|
||||
super(client, {
|
||||
name: Events.InteractionCreate,
|
||||
once: false,
|
||||
description: 'Event se déclenchant lorsqu\'une interaction est créée'
|
||||
});
|
||||
}
|
||||
|
||||
async execute(interaction: ChatInputCommandInteraction): Promise<void> {
|
||||
if (!interaction.isChatInputCommand()) return;
|
||||
|
||||
const command: Command = this.client.commands.get(interaction.commandName) as Command;
|
||||
|
||||
if (!command) {
|
||||
await interaction.reply({content: 'Commande inconnue', ephemeral: true})
|
||||
this.client.commands.delete(interaction.commandName);
|
||||
return;
|
||||
}
|
||||
const {cooldowns} = this.client;
|
||||
|
||||
if (!cooldowns.has(command.name)) {
|
||||
cooldowns.set(command.name, new Collection());
|
||||
}
|
||||
|
||||
const now = Date.now();
|
||||
const timestamps = cooldowns.get(command.name)!;
|
||||
const cooldownAmount = (command.cooldown || 3) * 1000;
|
||||
|
||||
if (timestamps.has(interaction.user.id) && now < (timestamps.get(interaction.user.id) || 0) + cooldownAmount) {
|
||||
await interaction.reply({
|
||||
content: `Veuillez patienter ${((timestamps.get(interaction.user.id) || 0) + cooldownAmount - now) / 1000} secondes avant de réutiliser la commande \`${command.name}\``
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
command.execute(interaction);
|
||||
}
|
||||
}
|
@ -1,2 +1,2 @@
|
||||
import CustomClient from "./base/classes/CustomClient";
|
||||
import {CustomClient} from "./base/classes/CustomClient";
|
||||
(async () => await new CustomClient().init())();
|
Loading…
Reference in New Issue
Block a user