diff --git a/aurora/slashcommands/town.ts b/aurora/slashcommands/town.ts index 6ba4b04d..5284cba5 100644 --- a/aurora/slashcommands/town.ts +++ b/aurora/slashcommands/town.ts @@ -52,7 +52,7 @@ export default { .then(m => setTimeout(() => m.delete(), 10000)) const townEmbed = new EmbedBuilder() - const nameArg = interaction.options.getString("name") + const nameArg = interaction.options.getString("name", true) const subCmdName = interaction.options.getSubcommand().toLowerCase() if (subCmdName == "list") { @@ -120,20 +120,18 @@ export default { } else { // /t list const nation = towns.some(town => town.nation.toLowerCase() == comparator) - if (!nation) return interaction.editReply({embeds: [ - new EmbedBuilder() - .setTitle("Invalid town name!") - .setDescription(comparator + " doesn't seem to be a valid town name, please try again.") - .setTimestamp().setColor(Colors.Red) - ] //ephemeral: true - }) + if (!nation) return interaction.editReply({embeds: [new EmbedBuilder() + .setTitle("Invalid Nation!") + .setDescription(`No nation with name \`${args2}\` exists.`) + .setTimestamp().setColor(Colors.Red) + ]}) // It exists, get only towns within the nation, and sort. towns.map(town => town.nation.toLowerCase() == comparator) towns = defaultSort(towns) } } - else if (subCmdName == "activity" && nameArg != null) { + else if (subCmdName == "activity") { const town = towns.find(t => t.name.toLowerCase() == nameArg.toLowerCase()) if (!town) return interaction.editReply({embeds: [new EmbedBuilder() .setTitle("Invalid town name!") @@ -180,13 +178,12 @@ export default { } else if (subCmdName == "lookup") { // /t const town = towns.find(t => t.name.toLowerCase() == nameArg.toLowerCase()) - if (!town) return await interaction.editReply({embeds: [new EmbedBuilder() - .setTitle("Invalid town name!") - .setDescription(nameArg + " doesn't seem to be a valid town name, please try again.") + .setTitle("Invalid Town!") + .setDescription(`No town with name \`${nameArg}\` exists.`) .setColor(Colors.Red) .setTimestamp() - ] /*ephemeral: true */}) + ]}) towns = defaultSort(towns) @@ -349,21 +346,40 @@ export default { .addSubcommand(subCmd => subCmd .setName('lookup') .setDescription('Get detailed information for a town') - .addStringOption(option => option.setName("name").setDescription("The name of the town to lookup.").setRequired(true))) + .addStringOption(option => option.setName("name") + .setDescription("The name of the town to lookup.") + .setRequired(true) + ) + ) .addSubcommand(subCmd => subCmd .setName('activity') .setDescription('Gets activity data for members of a town.') - .addStringOption(option => option.setName("name").setDescription("The name of the town to get activity data for.").setRequired(true))) + .addStringOption(option => option.setName("name") + .setDescription("The name of the town to get activity data for.") + .setRequired(true) + ) + ) .addSubcommand(subCmd => subCmd .setName('list') .setDescription('List towns using various comparators.') - .addStringOption(option => option.setName("comparator").setDescription("The comparator to use which the list will be filtered by."))) + .addStringOption(option => option.setName("comparator") + .setDescription("The comparator to use which the list will be filtered by.") + ) + ) +} + +interface ExtractedTown { + name: string + nation: string + residentNames: string[] + area: number + wealth: number } -function extractTownData(towns: DBSquaremapTown[]) { +const extractTownData = (towns: DBSquaremapTown[]) => { if (!towns) return [] - const townData = [] + const townData: ExtractedTown[] = [] const len = towns.length for (let i = 0; i < len; i++) { diff --git a/aurora/slashcommands/townless.ts b/aurora/slashcommands/townless.ts index 62a43e69..b4f68883 100644 --- a/aurora/slashcommands/townless.ts +++ b/aurora/slashcommands/townless.ts @@ -5,7 +5,7 @@ import { } from "discord.js" import { Aurora } from 'earthmc' -import { paginatorInteraction } from '../../bot/utils/fn.js' +import { fastMerge, fetchError, paginatorInteraction } from '../../bot/utils/fn.js' import { lastSeenPlayers } from "../../bot/constants.js" const embed = (len: number, desc: string, footer?: { text: string, iconURL?: string }) => { @@ -37,67 +37,71 @@ const townlessLastSeen = async () => { return [...lastSeenPlayers.values()].filter(p => !residentNames.has(p.name)) } +const send = (interaction: ChatInputCommandInteraction, allData: RegExpMatchArray, townless: { name: string }[]) => { + const len = allData.length + if (len <= 1) { + // If only one page, don't create paginator. + const desc = "```" + `${townless[0].name}\n${allData}` + "```" + return interaction.reply({ embeds: [embed(townless.length, desc)] }) + } + + const botEmbed: EmbedBuilder[] = [] + for (let page = 0; page < len; page++) { + const desc = "```" + `${townless[0].name}\n${allData[page]}` + "```" + botEmbed[page] = embed(townless.length, desc, { text: `Page ${page+1}/${len}` }) + } + + interaction.reply({ embeds: [botEmbed[0]] }) + .then(() => paginatorInteraction(interaction, botEmbed, 0)) + .catch(console.log) +} + export default { name: "townless", description: "Lists all online players without a town.", run: async (_: Client, interaction: ChatInputCommandInteraction) => { - // const townlessPlayers = await Aurora.Players.townless() - // if (!townlessPlayers) return await interaction.reply({ embeds: [fetchError], ephemeral: true }) - - const townless = await townlessLastSeen() + let townless = await townlessLastSeen() const townlessAmt = townless.length - + if (townlessAmt < 1) { // Try emc.Townless() + const townless = await Aurora.Players.townless() + if (!townless) return await interaction.reply({ embeds: [fetchError], ephemeral: true }) // Definitely no townless online, send appropriate msg. - return interaction.reply({ + if (townless.length) return interaction.reply({ embeds: [embed(0, "There are currently no townless players.")], ephemeral: true }) + + const allData = townless.map(p => p.name).join('\n').match(/(?:^.*$\n?){1,15}/mg) + return send(interaction, allData, townless) } - // const onlineTownless: SeenPlayer[] = [] - // const offlineTownless: SeenPlayer[] = [] + // Separate online and offline items + const online = townless.filter(p => p.online) + const offline = townless.filter(p => !p.online).sort((a, b) => b.timestamp - a.timestamp) - // // Single pass [O(n)] to avoid slight overhead of two filter/map calls. [O(2n)] - // for (let i = 0; i < townlessAmt; i++) { - // const player = townless[i] - - // if (player.online) onlineTownless.push(player) - // else offlineTownless.push(player) - // } + // Concatenate online items (in original order) and sorted offline items + townless = fastMerge(online, offline) - const allData = townless.sort((a, b) => (a.online === b.online) ? 0 : a.online ? -1 : 1).map(p => { + const allData = townless.map(p => { if (p.online) return `${p.name}` const minSinceSeen = ((Date.now() - p.timestamp) / 60000) - if (minSinceSeen >= 1) return `(Seen: ${minSinceSeen.toFixed(0)}m ago) ${p.name}` + if (minSinceSeen >= 1) { + return `${p.name} (${minSinceSeen.toFixed(0)}m ago)` + } const secSinceSeen = ((Date.now() - p.timestamp) / 1000) - return `(Seen: ${secSinceSeen.toFixed(0)}s ago) ${p.name}` + return `${p.name} (${secSinceSeen.toFixed(0)}s ago)` }).join('\n').match(/(?:^.*$\n?){1,15}/mg) // console.log("---- Online Townless ----", onlineTownlessData) // console.log("----------------------------") // console.log("---- Offline Townless ----", offlineTownlessData) - const len = allData.length - if (len <= 1) { - // If only one page, don't create paginator. - const desc = "```" + `${townless[0].name}\n${allData}` + "```" - return interaction.reply({ embeds: [embed(len, desc)] }) - } - - const botEmbed: EmbedBuilder[] = [] - for (let page = 0; page < len; page++) { - const desc = "```" + `${townless[0].name}\n${allData[page]}` + "```" - botEmbed[page] = embed(townlessAmt, desc, { text: `Page ${page+1}/${len}` }) - } - - await interaction.reply({ embeds: [botEmbed[0]] }) - .then(() => paginatorInteraction(interaction, botEmbed, 0)) - .catch(console.log) + return send(interaction, allData, townless) }, data: new SlashCommandBuilder() .setName("townless") .setDescription("Lists all online townless players.")