feature/5-drop-command #17
12 changed files with 197 additions and 20 deletions
|
@ -32,5 +32,6 @@ const client = new CoreClient([
|
||||||
|
|
||||||
Registry.RegisterCommands();
|
Registry.RegisterCommands();
|
||||||
Registry.RegisterEvents();
|
Registry.RegisterEvents();
|
||||||
|
Registry.RegisterButtonEvents();
|
||||||
|
|
||||||
client.start();
|
client.start();
|
38
src/buttonEvents/Claim.ts
Normal file
38
src/buttonEvents/Claim.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { ButtonInteraction } from "discord.js";
|
||||||
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
|
import Inventory from "../database/entities/app/Inventory";
|
||||||
|
import { CoreClient } from "../client/client";
|
||||||
|
|
||||||
|
export default class Claim extends ButtonEvent {
|
||||||
|
public override async execute(interaction: ButtonInteraction) {
|
||||||
|
if (!interaction.guild || !interaction.guildId) return;
|
||||||
|
|
||||||
|
const cardNumber = interaction.customId.split(' ')[1];
|
||||||
|
const claimId = interaction.customId.split(' ')[2];
|
||||||
|
const userId = interaction.user.id;
|
||||||
|
|
||||||
|
const claimed = await Inventory.FetchOneByClaimId(claimId);
|
||||||
|
|
||||||
|
if (claimed) {
|
||||||
|
await interaction.reply('This card has already been claimed');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (claimId != CoreClient.ClaimId) {
|
||||||
|
await interaction.reply('This card has expired');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let inventory = await Inventory.FetchOneByCardNumberAndUserId(userId, cardNumber);
|
||||||
|
|
||||||
|
if (!inventory) {
|
||||||
|
inventory = new Inventory(userId, cardNumber, 1, claimId);
|
||||||
|
} else {
|
||||||
|
inventory.SetQuantity(inventory.Quantity + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.Save(Inventory, inventory);
|
||||||
|
|
||||||
|
await interaction.reply('Card claimed');
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,15 +10,21 @@ import { Util } from "./util";
|
||||||
import CardSetupFunction from "../Functions/CardSetupFunction";
|
import CardSetupFunction from "../Functions/CardSetupFunction";
|
||||||
import CardDataSource from "../database/dataSources/cardDataSource";
|
import CardDataSource from "../database/dataSources/cardDataSource";
|
||||||
import CardDropHelper from "../helpers/CardDropHelper";
|
import CardDropHelper from "../helpers/CardDropHelper";
|
||||||
|
import IButtonEventItem from "../contracts/IButtonEventItem";
|
||||||
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
|
import AppDataSource from "../database/dataSources/appDataSource";
|
||||||
|
|
||||||
export class CoreClient extends Client {
|
export class CoreClient extends Client {
|
||||||
private static _commandItems: ICommandItem[];
|
private static _commandItems: ICommandItem[];
|
||||||
private static _eventItems: IEventItem[];
|
private static _eventItems: IEventItem[];
|
||||||
|
private static _buttonEvents: IButtonEventItem[];
|
||||||
|
|
||||||
private _events: Events;
|
private _events: Events;
|
||||||
private _util: Util;
|
private _util: Util;
|
||||||
private _cardSetupFunc: CardSetupFunction;
|
private _cardSetupFunc: CardSetupFunction;
|
||||||
|
|
||||||
|
public static ClaimId: string;
|
||||||
|
|
||||||
public static get commandItems(): ICommandItem[] {
|
public static get commandItems(): ICommandItem[] {
|
||||||
return this._commandItems;
|
return this._commandItems;
|
||||||
}
|
}
|
||||||
|
@ -27,12 +33,17 @@ export class CoreClient extends Client {
|
||||||
return this._eventItems;
|
return this._eventItems;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static get buttonEvents(): IButtonEventItem[] {
|
||||||
|
return this._buttonEvents;
|
||||||
|
}
|
||||||
|
|
||||||
constructor(intents: number[]) {
|
constructor(intents: number[]) {
|
||||||
super({ intents: intents });
|
super({ intents: intents });
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
|
|
||||||
CoreClient._commandItems = [];
|
CoreClient._commandItems = [];
|
||||||
CoreClient._eventItems = [];
|
CoreClient._eventItems = [];
|
||||||
|
CoreClient._buttonEvents = [];
|
||||||
|
|
||||||
this._events = new Events();
|
this._events = new Events();
|
||||||
this._util = new Util();
|
this._util = new Util();
|
||||||
|
@ -45,6 +56,10 @@ export class CoreClient extends Client {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await AppDataSource.initialize()
|
||||||
|
.then(() => console.log("App Data Source Initialised"))
|
||||||
|
.catch(err => console.error("Error initialising App Data Source", err));
|
||||||
|
|
||||||
await CardDataSource.initialize()
|
await CardDataSource.initialize()
|
||||||
.then(() => console.log("Card Data Source Initialised"))
|
.then(() => console.log("Card Data Source Initialised"))
|
||||||
.catch(err => console.error("Error initialising Card Data Source", err));
|
.catch(err => console.error("Error initialising Card Data Source", err));
|
||||||
|
@ -78,4 +93,13 @@ export class CoreClient extends Client {
|
||||||
|
|
||||||
CoreClient._eventItems.push(item);
|
CoreClient._eventItems.push(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RegisterButtonEvent(buttonId: string, event: ButtonEvent) {
|
||||||
|
const item: IButtonEventItem = {
|
||||||
|
ButtonId: buttonId,
|
||||||
|
Event: event,
|
||||||
|
};
|
||||||
|
|
||||||
|
CoreClient._buttonEvents.push(item);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,29 +1,18 @@
|
||||||
import { Interaction } from "discord.js";
|
import { Interaction } from "discord.js";
|
||||||
import ICommandItem from "../contracts/ICommandItem";
|
import ChatInputCommand from "./interactionCreate/ChatInputCommand";
|
||||||
import { CoreClient } from "./client";
|
import Button from "./interactionCreate/Button";
|
||||||
|
|
||||||
export class Events {
|
export class Events {
|
||||||
public async onInteractionCreate(interaction: Interaction) {
|
public async onInteractionCreate(interaction: Interaction) {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
|
||||||
if (!interaction.guildId) return;
|
if (!interaction.guildId) return;
|
||||||
|
|
||||||
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
|
if (interaction.isChatInputCommand()) {
|
||||||
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
|
ChatInputCommand.onChatInput(interaction);
|
||||||
|
|
||||||
let itemToUse: ICommandItem;
|
|
||||||
|
|
||||||
if (!itemForServer) {
|
|
||||||
if (!item) {
|
|
||||||
await interaction.reply('Command not found');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itemToUse = item;
|
if (interaction.isButton()) {
|
||||||
} else {
|
Button.onButtonClicked(interaction);
|
||||||
itemToUse = itemForServer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
itemToUse.Command.execute(interaction);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit when bot is logged in and ready to use
|
// Emit when bot is logged in and ready to use
|
||||||
|
|
17
src/client/interactionCreate/Button.ts
Normal file
17
src/client/interactionCreate/Button.ts
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import { ButtonInteraction, Interaction } from "discord.js";
|
||||||
|
import { CoreClient } from "../client";
|
||||||
|
|
||||||
|
export default class Button {
|
||||||
|
public static async onButtonClicked(interaction: ButtonInteraction) {
|
||||||
|
if (!interaction.isButton) return;
|
||||||
|
|
||||||
|
const item = CoreClient.buttonEvents.find(x => x.ButtonId == interaction.customId.split(' ')[0]);
|
||||||
|
|
||||||
|
if (!item) {
|
||||||
|
await interaction.reply('Event not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
item.Event.execute(interaction);
|
||||||
|
}
|
||||||
|
}
|
27
src/client/interactionCreate/ChatInputCommand.ts
Normal file
27
src/client/interactionCreate/ChatInputCommand.ts
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import { Interaction } from "discord.js";
|
||||||
|
import { CoreClient } from "../client";
|
||||||
|
import ICommandItem from "../../contracts/ICommandItem";
|
||||||
|
|
||||||
|
export default class ChatInputCommand {
|
||||||
|
public static async onChatInput(interaction: Interaction) {
|
||||||
|
if (!interaction.isChatInputCommand()) return;
|
||||||
|
|
||||||
|
const item = CoreClient.commandItems.find(x => x.Name == interaction.commandName && !x.ServerId);
|
||||||
|
const itemForServer = CoreClient.commandItems.find(x => x.Name == interaction.commandName && x.ServerId == interaction.guildId);
|
||||||
|
|
||||||
|
let itemToUse: ICommandItem;
|
||||||
|
|
||||||
|
if (!itemForServer) {
|
||||||
|
if (!item) {
|
||||||
|
await interaction.reply('Command not found');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemToUse = item;
|
||||||
|
} else {
|
||||||
|
itemToUse = itemForServer;
|
||||||
|
}
|
||||||
|
|
||||||
|
itemToUse.Command.execute(interaction);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
import { AttachmentBuilder, CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
|
import { ActionRowBuilder, AttachmentBuilder, ButtonBuilder, ButtonStyle, CommandInteraction, EmbedBuilder, SlashCommandBuilder } from "discord.js";
|
||||||
import { Command } from "../type/command";
|
import { Command } from "../type/command";
|
||||||
import CardDropHelper from "../helpers/CardDropHelper";
|
import CardDropHelper from "../helpers/CardDropHelper";
|
||||||
import { CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
|
import { CardRarityToColour, CardRarityToString } from "../constants/CardRarity";
|
||||||
import { readFileSync } from "fs";
|
import { readFileSync } from "fs";
|
||||||
|
import { CoreClient } from "../client/client";
|
||||||
|
import { v4 } from "uuid";
|
||||||
|
|
||||||
export default class Drop extends Command {
|
export default class Drop extends Command {
|
||||||
constructor() {
|
constructor() {
|
||||||
|
@ -27,9 +29,22 @@ export default class Drop extends Command {
|
||||||
.setColor(CardRarityToColour(randomCard.Rarity))
|
.setColor(CardRarityToColour(randomCard.Rarity))
|
||||||
.setImage(`attachment://${randomCard.Id}.png`);
|
.setImage(`attachment://${randomCard.Id}.png`);
|
||||||
|
|
||||||
await interaction.reply({
|
const row = new ActionRowBuilder<ButtonBuilder>();
|
||||||
|
|
||||||
|
const claimId = v4();
|
||||||
|
|
||||||
|
row.addComponents(
|
||||||
|
new ButtonBuilder()
|
||||||
|
.setCustomId(`claim ${randomCard.CardNumber} ${claimId}`)
|
||||||
|
.setLabel("Claim")
|
||||||
|
.setStyle(ButtonStyle.Primary));
|
||||||
|
|
||||||
|
const message = await interaction.reply({
|
||||||
embeds: [ embed ],
|
embeds: [ embed ],
|
||||||
files: [ attachment ],
|
files: [ attachment ],
|
||||||
|
components: [ row ],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
CoreClient.ClaimId = claimId;
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/contracts/IButtonEventItem.ts
Normal file
6
src/contracts/IButtonEventItem.ts
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
import { ButtonEvent } from "../type/buttonEvent";
|
||||||
|
|
||||||
|
export default interface IButtonEventItem {
|
||||||
|
ButtonId: string,
|
||||||
|
Event: ButtonEvent,
|
||||||
|
}
|
47
src/database/entities/app/Inventory.ts
Normal file
47
src/database/entities/app/Inventory.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { Column, Entity } from "typeorm";
|
||||||
|
import AppBaseEntity from "../../../contracts/AppBaseEntity";
|
||||||
|
import AppDataSource from "../../dataSources/appDataSource";
|
||||||
|
|
||||||
|
@Entity()
|
||||||
|
export default class Inventory extends AppBaseEntity {
|
||||||
|
constructor(userId: string, cardNumber: string, quantity: number, claimId: string) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.UserId = userId;
|
||||||
|
this.CardNumber = cardNumber;
|
||||||
|
this.Quantity = quantity;
|
||||||
|
this.ClaimId = claimId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
UserId: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
CardNumber: string;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
Quantity: number;
|
||||||
|
|
||||||
|
@Column()
|
||||||
|
ClaimId: string;
|
||||||
|
|
||||||
|
public SetQuantity(quantity: number) {
|
||||||
|
this.Quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async FetchOneByCardNumberAndUserId(userId: string, cardNumber: string): Promise<Inventory | null> {
|
||||||
|
const repository = AppDataSource.getRepository(Inventory);
|
||||||
|
|
||||||
|
const single = await repository.findOne({ where: { UserId: userId, CardNumber: cardNumber }});
|
||||||
|
|
||||||
|
return single;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async FetchOneByClaimId(claimId: string): Promise<Inventory | null> {
|
||||||
|
const repository = AppDataSource.getRepository(Inventory);
|
||||||
|
|
||||||
|
const single = await repository.findOne({ where: { ClaimId: claimId }});
|
||||||
|
|
||||||
|
return single;
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,6 +3,8 @@ import { CoreClient } from "./client/client";
|
||||||
import About from "./commands/about";
|
import About from "./commands/about";
|
||||||
import Drop from "./commands/drop";
|
import Drop from "./commands/drop";
|
||||||
|
|
||||||
|
import Claim from "./buttonEvents/Claim";
|
||||||
|
|
||||||
export default class Registry {
|
export default class Registry {
|
||||||
public static RegisterCommands() {
|
public static RegisterCommands() {
|
||||||
CoreClient.RegisterCommand('about', new About());
|
CoreClient.RegisterCommand('about', new About());
|
||||||
|
@ -12,4 +14,8 @@ export default class Registry {
|
||||||
public static RegisterEvents() {
|
public static RegisterEvents() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RegisterButtonEvents() {
|
||||||
|
CoreClient.RegisterButtonEvent('claim', new Claim());
|
||||||
|
}
|
||||||
}
|
}
|
7
src/type/buttonEvent.ts
Normal file
7
src/type/buttonEvent.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { ButtonInteraction } from "discord.js";
|
||||||
|
|
||||||
|
export class ButtonEvent {
|
||||||
|
public execute(interaction: ButtonInteraction) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue