/* TODO join message should contain your current position in the queue, editing it to keep it current */ import { Client, CommandInteraction, GuildMember, MessageEmbed, TextChannel } from "discord.js"; import * as fs from 'fs'; import { emsg, getChannel, getMember, memberIsModThrow, queueInfo, queueInfoBase } from "./util"; import { Lang } from './lang'; //load queues from file if (!fs.existsSync('./queues.json')) fs.writeFileSync('./queues.json', '{}'); const _QUEUE = fs.readFileSync('./queues.json').toString(), QUEUE = new Map(); try { let queueJson = JSON.parse(_QUEUE); for (let channelId in queueJson) { let {teamsize} = queueJson[channelId] as queueInfoBase; if (teamsize) QUEUE.set(channelId, { teamsize, players: [] }) } } catch(e) {} function SaveQueue() { let queueJson = Object.fromEntries(QUEUE), queueFileJson: {[keys: string]: queueInfoBase} = {}; for (let channelId of QUEUE.keys()) queueFileJson[channelId] = { teamsize: queueJson[channelId].teamsize }; fs.writeFileSync('./queues.json', JSON.stringify(queueFileJson, null, 2)); } async function checkQueue(channel: TextChannel) { let info = QUEUE.get(channel.id); if (!info) return; if (info.players.length >= info.teamsize) { let team = info.players.splice(0, info.teamsize).map(m => m.toString()); //TODO add embeds to lang.ts let embed = new MessageEmbed() .setTitle('Team') .setDescription(team.join('\n')); await channel.send({embeds: [embed]}); } } namespace Queue { export function create(channelId: string, teamsize: number) { if (!QUEUE.has(channelId)) { QUEUE.set(channelId, {teamsize, players: []}); SaveQueue(); } } export function remove(channelId: string) { if (QUEUE.has(channelId)) { QUEUE.delete(channelId); SaveQueue(); } } export function addPlayer(channelId: string, member: GuildMember) { if (QUEUE.has(channelId)) { QUEUE.delete(channelId); } } export function removePlayer(channelId: string, member: GuildMember) { if (QUEUE.has(channelId)) { QUEUE.delete(channelId); } } } SaveQueue(); export async function discordInit(client: Client) { for (let channelId of QUEUE.keys()) { let info = QUEUE.get(channelId), channel = await client.channels.fetch(channelId); if (!info) { //no idea what could cause this but TS complains Queue.remove(channelId); continue; } if (!channel || !(channel instanceof TextChannel)) { console.error(Lang.get('discord.error.noChannel'), { channelId, teamsize: info.teamsize }); Queue.remove(channelId); continue; } channel.send(Lang.get('discord.botRestart')); } } export namespace QueueCommands { /** * get the queueInfo of an interaction * @param interaction * @throws errorMessage class if it does not exist * @returns queue info */ function getInfo(interaction: CommandInteraction): queueInfo { let info = QUEUE.get(interaction.channelId); if (!info) throw emsg(Lang.get('discord.error.noQueue')); return info; } /** * compiles all the get functions above * @param interaction * @throws if another get function throws * @returns object containing each */ const getAll = (interaction: CommandInteraction) => ({ member: getMember(interaction), channel: getChannel(interaction), info: getInfo(interaction) }); /** * checks if the interaction data is already in the queue * @param interaction * @returns boolean */ export function queueContains(interaction: CommandInteraction): boolean { let {member, info} = getAll(interaction); if (info.players.map(m=>m.id).includes(member.id)) return true; return false; } /** * creates a queue from an interaction * @param interaction * @throws errorMessage class if it cannot be left */ export function queueCreate(interaction: CommandInteraction) { memberIsModThrow(interaction); let {channelId} = interaction, teamsize = interaction.options.getInteger('teamsize', true); if (QUEUE.has(channelId)) throw emsg(Lang.get('discord.error.noCreate', { teamsize: QUEUE.get(channelId)?.teamsize })); Queue.create(channelId, teamsize); interaction.reply(Lang.get('discord.create', { teamsize })) } /** * opens a queue * @param interaction * @throws errorMessage class if it cannot be left */ export async function open(interaction: CommandInteraction) { queueCreate(interaction); } /** * closes a queue * @param interaction * @throws errorMessage class if it cannot be joined */ export async function close(interaction: CommandInteraction) { memberIsModThrow(interaction); QUEUE.delete(interaction.channelId); await interaction.reply(Lang.get('discord.close')); } /** * gives info about the queue * @param interaction * @throws errorMessage class if it cannot be left */ export async function queue(interaction: CommandInteraction) { let info = getInfo(interaction); let embed = new MessageEmbed() .setTitle('Active Queue') .addField('Team Size', info.teamsize.toString(), true) .addField('Players Joined', info.players.length.toString(), true) .setFooter({text: 'type /join'}); //TODO await interaction.reply({embeds: [embed], ephemeral: true}); } /** * joins a queue * @param interaction * @throws errorMessage class if it cannot be readied */ export async function join(interaction: CommandInteraction) { let {member, info, channel} = getAll(interaction); if (queueContains(interaction)) throw emsg(Lang.get('discord.error.inQueue')); info.players.push(member); QUEUE.set(interaction.channelId, info); await interaction.reply(Lang.get('discord.join')); checkQueue(channel); } /** * leaves a queue * @param interaction * @throws errorMessage class if it cannot be reset */ export async function leave(interaction: CommandInteraction) { let {member, info} = getAll(interaction); if (!queueContains(interaction)) throw emsg(Lang.get('discord.error.notInQueue')); info.players.splice(info.players.indexOf(member), 1); QUEUE.set(interaction.channelId, info); await interaction.reply(Lang.get('discord.leave')); } }