diff --git a/src/bot.ts b/src/bot.ts index f5178cf..0727f24 100644 --- a/src/bot.ts +++ b/src/bot.ts @@ -1,24 +1,24 @@ -import {Client, Collection, Events, GatewayIntentBits, Interaction, Message} from "discord.js" +import {Client, Collection, Events, GatewayIntentBits, Interaction} from "discord.js" import {Player} from "./player"; import fs from "node:fs"; -import {Command} from "./command"; -import path from "node:path"; +import {Command, loadCommands} from "./command"; export class UEMEloBot extends Client { players: Player[] = [] fileName = "players.json" - commands: Collection = new Collection(); + commands = new Collection(); constructor() { super({intents: [GatewayIntentBits.Guilds]}); this.once(Events.ClientReady, this.onReady); this.on(Events.InteractionCreate, this.onInteractionCreate); this.parsePlayersFromFile(); - this.loadCommands().then(async () => { + loadCommands().then(async commands => { + this.commands = commands; const token = await this.login(); console.log(`Discord Token: ${token}`); - setInterval(this.updateStartElo.bind(this), 5000); + setInterval(this.updatePlayers.bind(this), 30 * 60 * 1000); await this.addPlayer("benjo", "tgm"); await this.addPlayer("unclebenss", "euw"); await this.addPlayer("moché", "EUw"); @@ -29,7 +29,7 @@ export class UEMEloBot extends Client { if (!interaction.isChatInputCommand()) return; let commandName = interaction.commandName; - let command = this.commands.ensure(commandName, () => this.commands.get("help") as Command); + let command = this.commands.get(commandName) as Command; await command.execute(interaction); } @@ -39,9 +39,7 @@ export class UEMEloBot extends Client { try { this.players = []; for (let obj of JSON.parse(fileContent)){ - let p = new Player(obj.account); - if (obj.hasOwnProperty("startElo")) - p.startElo = obj.startElo; + let p = Player.Load(obj); this.players.push(p); console.log(`Parsed player: ${p}`); } @@ -52,13 +50,15 @@ export class UEMEloBot extends Client { } savePlayersToFile(){ - fs.writeFileSync(this.fileName, JSON.stringify(this.players)); + fs.writeFileSync(this.fileName, JSON.stringify(this.players, null, 4)); } - async updateStartElo(){ + async updatePlayers(){ for (let p of this.players){ + await p.updateFullName(); + await p.updateCurrentElo(); if (!p.startElo){ - p.startElo = await p.fetchCurrentElo(); + p.startElo = p.currentElo; console.log(`Updated start elo for ${p}`); } } @@ -66,40 +66,28 @@ export class UEMEloBot extends Client { } async addPlayer(gameName: string, tag: string){ - let player = await Player.Create(gameName, tag) as Player; + let player = await Player.TryCreateFrom(gameName, tag) as Player; if (player === undefined) return; - if (this.players.find(p => p.account.puuid === player.account.puuid)){ + if (this.players.find(p => p.puuid === player.puuid)){ console.error(`${player} already registered!`); return; } this.players.push(player); - console.log(`Added ${player}!`); - this.savePlayersToFile(); } - async loadCommands(){ - const commandFiles = fs.readdirSync(path.join(__dirname, "commands")).filter(file => file.endsWith('.js')); - for (const file of commandFiles){ - const module = await import(`./commands/${file}`); - const cmd = module.default; - if (cmd instanceof Command) - this.commands.set(cmd.data.name, cmd); - } - } - async onReady(readyClient: Client){ console.log(`Logged in as ${readyClient.user.tag}`); } stop(){ this.destroy().then(() => { - console.log("Bot stopped!"); + console.log("Logged out!"); process.exit(0); }); } diff --git a/src/command.ts b/src/command.ts index b9d9f45..ce5c603 100644 --- a/src/command.ts +++ b/src/command.ts @@ -1,4 +1,6 @@ -import {Interaction, SlashCommandBuilder} from "discord.js"; +import {Collection, Interaction, SlashCommandBuilder} from "discord.js"; +import fs from "node:fs"; +import path from "node:path"; export abstract class Command { data: SlashCommandBuilder @@ -8,4 +10,16 @@ export abstract class Command { } abstract execute(interaction: Interaction): Promise; +} + +export async function loadCommands(){ + let commands = new Collection(); + const commandFiles = fs.readdirSync(path.join(__dirname, "commands")).filter(file => file.endsWith('.js')); + for (const file of commandFiles){ + const module = await import(`./commands/${file}`); + const cmd = module.default; + if (cmd instanceof Command) + commands.set(cmd.data.name, cmd); + } + return commands; } \ No newline at end of file diff --git a/src/commands/add.ts b/src/commands/add.ts new file mode 100644 index 0000000..9e0546b --- /dev/null +++ b/src/commands/add.ts @@ -0,0 +1,15 @@ +import {Interaction} from "discord.js"; +import {Command} from "../command"; + +class Add extends Command { + constructor() { + super("add", "add a player"); + } + async execute(interaction: Interaction) { + + if (interaction.isRepliable()) + await interaction.reply("Pong!"); + } +} + +export default new Add(); \ No newline at end of file diff --git a/src/deploy-commands.ts b/src/deploy-commands.ts index ac3b664..d9faf8e 100644 --- a/src/deploy-commands.ts +++ b/src/deploy-commands.ts @@ -1,4 +1,6 @@ import {REST, Routes} from 'discord.js'; +import {loadCommands} from "./command"; + require("dotenv").config(); let token = process.env["DISCORD_TOKEN"] as string; @@ -7,4 +9,7 @@ let guildId = process.env["GUILD_ID"] as string; const rest = new REST().setToken(token); -rest.put(Routes.applicationGuildCommands(clientId, guildId), {body: [require("./commands/ping").data.toJSON()]}); \ No newline at end of file +loadCommands().then(async commands => { + let cmdData = Array.from(commands.values()).map(cmd => cmd.data.toJSON()); + await rest.put(Routes.applicationGuildCommands(clientId, guildId), {body: cmdData}); +}); diff --git a/src/index.ts b/src/index.ts index 7b0bc5b..41f8a5c 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,11 +1,7 @@ -import {Command} from "./command"; - require("dotenv").config(); import {UEMEloBot} from "./bot"; import readline from "readline"; -import Ping from "./commands/ping"; - readline.createInterface({input: process.stdin}).on('line', async line => { if (line == "stop") client.stop(); diff --git a/src/player.ts b/src/player.ts index 7d3d70f..2fb8c14 100644 --- a/src/player.ts +++ b/src/player.ts @@ -5,25 +5,72 @@ const riotAPI = new RiotAPI(process.env["RIOT_API_KEY"] as string); export class Player { - account: AccountDTO + puuid: string + + gameName?: string + tagLine?: string startElo?: Elo + currentElo?: Elo - constructor(account: AccountDTO) { - this.account = account; + constructor(puuid: string) { + this.puuid = puuid; } - async fetchCurrentElo(): Promise { - let entries = await riotAPI.league.getEntriesBySummonerId({ - region: PlatformId.EUW1, - summonerId: (await riotAPI.summoner.getByPUUID({ - region: PlatformId.EUW1, - puuid: this.account.puuid - })).id + static Load(raw: any): Player { + let p = new Player(raw.puuid); + p.startElo = raw.startElo; + p.gameName = raw.gameName; + p.tagLine = raw.tagLine; + return p; + } + + static async TryCreateFrom(gameName: string, tagLine: string) { + let account: AccountDTO; + try { + account = await riotAPI.account.getByRiotId({ + region: PlatformId.EUROPE, + gameName: gameName, + tagLine: tagLine + }); + } catch (error) { + console.error(`Riot ID not found: ${gameName}#${tagLine}!`); + return; + } + let p = new Player(account.puuid); + p.gameName = account.gameName; + p.tagLine = account.tagLine; + await p.updateCurrentElo(); + p.startElo = p.currentElo; + return p; + } + + async updateFullName(){ + const account = await riotAPI.account.getByPUUID({ + region: PlatformId.EUROPE, + puuid: this.puuid }); + this.gameName = account.gameName; + this.tagLine = account.tagLine; + } + + async updateCurrentElo() { + let entries; + try { + entries = await riotAPI.league.getEntriesBySummonerId({ + region: PlatformId.EUW1, + summonerId: (await riotAPI.summoner.getByPUUID({ + region: PlatformId.EUW1, + puuid: this.puuid + })).id + }); + } catch (error){ + console.error(await(error as Response).json()); + return; + } let soloQ = entries.find(e => e.queueType == "RANKED_SOLO_5x5"); if (soloQ && ((soloQ.wins + soloQ.losses) >= 5)){ - return { + this.currentElo = { tier: soloQ.tier, rank: soloQ.rank, points: soloQ.leaguePoints @@ -32,24 +79,17 @@ export class Player { } toString() { - return `${this.account.gameName}#${this.account.tagLine}`; + return `${this.gameName}#${this.tagLine}`; } - static async Create(gameName: string, tag: string) { - let account: AccountDTO; - try { - account = await riotAPI.account.getByRiotId({ - region: PlatformId.EUROPE, - gameName: gameName, - tagLine: tag - }); - } catch (error) { - console.error(`Riot ID not found: ${gameName}#${tag}!`); - return; + // noinspection JSUnusedGlobalSymbols + toJSON(){ + return { + puuid: this.puuid, + gameName: this.gameName, + tagLine: this.tagLine, + startElo: this.startElo } - let p = new Player(account); - p.startElo = await p.fetchCurrentElo(); - return p; } }