✨ 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 {IConfig} from "../interfaces/IConfig";
|
||||||
import ICustomClient from "../interfaces/ICustomClient";
|
import {ICustomClient} from "../interfaces/ICustomClient";
|
||||||
import {Client} from "discord.js";
|
import {Client, Collection, GatewayIntentBits} from "discord.js";
|
||||||
import Handler from "./Handler";
|
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;
|
config: IConfig;
|
||||||
handler: Handler;
|
handler: Handler;
|
||||||
|
commands: Collection<string, Command>;
|
||||||
|
subCommands: Collection<string, SubCommand>;
|
||||||
|
cooldowns: Collection<string, Collection<string, number>>;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super({
|
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.config = require(`${process.cwd()}/data/config.json`);
|
||||||
this.handler = new Handler(this);
|
this.handler = new Handler(this);
|
||||||
|
this.commands = new Collection();
|
||||||
|
this.subCommands = new Collection();
|
||||||
|
this.cooldowns = new Collection();
|
||||||
}
|
}
|
||||||
async init(): Promise<void> {
|
async init(): Promise<void> {
|
||||||
await this.LoadHandlers();
|
await this.LoadHandlers();
|
||||||
@ -21,6 +32,7 @@ export default class CustomClient extends Client implements ICustomClient {
|
|||||||
|
|
||||||
async LoadHandlers(): Promise<void> {
|
async LoadHandlers(): Promise<void> {
|
||||||
await this.handler.loadEvents();
|
await this.handler.loadEvents();
|
||||||
|
await this.handler.loadCommands();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,11 +1,11 @@
|
|||||||
import { Events } from "discord.js";
|
import {ClientEvents} from "discord.js";
|
||||||
import IEvent from "../interfaces/IEvent";
|
import {IEvent} from "../interfaces/IEvent";
|
||||||
import CustomClient from "./CustomClient";
|
import {CustomClient} from "./CustomClient";
|
||||||
import IEventOptions from "../interfaces/IEventOptions";
|
import {IEventOptions} from "../interfaces/IEventOptions";
|
||||||
|
|
||||||
export default class Event implements IEvent {
|
export class Event implements IEvent {
|
||||||
client: CustomClient;
|
client: CustomClient;
|
||||||
name: Events;
|
name: keyof ClientEvents;
|
||||||
description: string;
|
description: string;
|
||||||
once: boolean;
|
once: boolean;
|
||||||
|
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
import IHandler from "../interfaces/IHandler";
|
import {IHandler} from "../interfaces/IHandler";
|
||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import {glob} from "glob";
|
import {glob} from "glob";
|
||||||
import CustomClient from "./CustomClient";
|
import {CustomClient} from "./CustomClient";
|
||||||
import Event from "./Event";
|
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;
|
client: CustomClient;
|
||||||
constructor(client: CustomClient) {
|
constructor(client: CustomClient) {
|
||||||
this.client = client;
|
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));
|
const files = (await glob(`dist/events/**/*.js`)).map(filePath => path.resolve(filePath));
|
||||||
|
|
||||||
files.map(async (file: string) => {
|
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)
|
if (!event.name)
|
||||||
return delete require.cache[require.resolve(file)] && console.log(`Event ${file.split('/').pop()} n'a pas de nom`);
|
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);
|
const execute = (...args: any[]) => event.execute(...args);
|
||||||
|
|
||||||
if (event.once) {
|
if (event.once) {
|
||||||
// @ts-ignore
|
|
||||||
this.client.once(event.name, execute);
|
this.client.once(event.name, execute);
|
||||||
} else {
|
} else {
|
||||||
// @ts-ignore
|
|
||||||
this.client.on(event.name, execute);
|
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;
|
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;
|
config: IConfig;
|
||||||
|
commands: Collection<string, Command>;
|
||||||
|
subCommands: Collection<string, SubCommand>;
|
||||||
|
cooldowns: Collection<string, Collection<string, number>>;
|
||||||
|
|
||||||
init(): void;
|
init(): void;
|
||||||
LoadHandlers(): void;
|
LoadHandlers(): void;
|
||||||
}
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import CustomClient from "../classes/CustomClient";
|
import {CustomClient} from "../classes/CustomClient";
|
||||||
import {Events} from "discord.js";
|
import {ClientEvents} from "discord.js";
|
||||||
|
|
||||||
export default interface IEvent {
|
export interface IEvent {
|
||||||
client: CustomClient;
|
client: CustomClient;
|
||||||
name: Events;
|
name: keyof ClientEvents;
|
||||||
description: string;
|
description: string;
|
||||||
once: boolean;
|
once: boolean;
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import {Events} from "discord.js";
|
import {ClientEvents} from "discord.js";
|
||||||
|
|
||||||
export default interface IEventOptions {
|
export interface IEventOptions {
|
||||||
name: Events;
|
name: keyof ClientEvents;
|
||||||
description: string;
|
description: string;
|
||||||
once: boolean;
|
once: boolean;
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
export default interface IHandler {
|
export interface IHandler {
|
||||||
loadEvents(): void;
|
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 {Event} from '../../base/classes/Event';
|
||||||
import CustomClient from "../../base/classes/CustomClient";
|
import {CustomClient} from "../../base/classes/CustomClient";
|
||||||
import {Events} from "discord.js";
|
import {Events} from "discord.js";
|
||||||
export default class Ready extends Event {
|
export class Ready extends Event {
|
||||||
constructor(client: CustomClient) {
|
constructor(client: CustomClient) {
|
||||||
super(client, {
|
super(client, {
|
||||||
name: Events.ClientReady,
|
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())();
|
(async () => await new CustomClient().init())();
|
Loading…
Reference in New Issue
Block a user