@zerospacegg/vynthra
Version:
Discord bot for ZeroSpace.gg data
126 lines • 4.75 kB
JavaScript
const { renderSearchResultAsMarkdown, searchEntities, } = require("../../lib/index.cjs");
const statsSubcommand = {
name: "stats",
description: "Get stats for a unit, building, faction, or map",
builder: (subcommand) => subcommand
.setName("stats")
.setDescription("Get stats for a unit, building, faction, or map")
.addStringOption((option) => option
.setName("query")
.setDescription("Search term (unit name, building, faction, etc.)")
.setRequired(true))
.addBooleanOption((option) => option
.setName("public")
.setDescription("Show publicly (default: private)")
.setRequired(false)),
async execute(interaction) {
const query = interaction.options.getString("query", true);
const isPublic = interaction.options.getBoolean("public") ?? false;
try {
// Use public flag to determine ephemeral behavior
if (!interaction.deferred) {
await interaction.deferReply({ ephemeral: !isPublic });
}
const result = searchEntities(query);
const markdown = renderSearchResultAsMarkdown(result);
// Discord has a 2000 character limit for messages
// If the response is too long, we'll need to truncate or split it
if (markdown.length <= 2000) {
await interaction.editReply(markdown);
}
else {
// Split the message into chunks
const chunks = splitMessage(markdown, 2000);
// Send the first chunk as the reply
await interaction.editReply(chunks[0]);
// Send additional chunks as follow-up messages (match the ephemeral setting)
for (let i = 1; i < chunks.length; i++) {
await interaction.followUp({
content: chunks[i],
ephemeral: !isPublic,
});
}
}
}
catch (error) {
console.error("Error processing stats command:", error);
// If we haven't deferred yet, defer as ephemeral for errors
if (!interaction.deferred) {
await interaction.deferReply({ ephemeral: true });
}
await interaction.editReply({
content: `❌ Error searching for "${query}": ${error instanceof Error ? error.message : "Unknown error"}`,
});
}
},
};
/**
* Split a message into chunks that fit within Discord's character limit
* Tries to split at logical boundaries (newlines) when possible
*/
function splitMessage(message, maxLength) {
if (message.length <= maxLength) {
return [message];
}
const chunks = [];
let currentChunk = "";
const lines = message.split("\n");
for (const line of lines) {
// If adding this line would exceed the limit
if (currentChunk.length + line.length + 1 > maxLength) {
// If we have content in the current chunk, save it
if (currentChunk.trim()) {
chunks.push(currentChunk.trim());
currentChunk = "";
}
// If this single line is too long, we need to split it
if (line.length > maxLength) {
const lineParts = splitLongLine(line, maxLength);
chunks.push(...lineParts.slice(0, -1));
currentChunk = lineParts[lineParts.length - 1];
}
else {
currentChunk = line;
}
}
else {
// Add the line to current chunk
if (currentChunk) {
currentChunk += "\n" + line;
}
else {
currentChunk = line;
}
}
}
// Don't forget the last chunk
if (currentChunk.trim()) {
chunks.push(currentChunk.trim());
}
return chunks;
}
/**
* Split a single long line into multiple parts
*/
function splitLongLine(line, maxLength) {
const parts = [];
let remaining = line;
while (remaining.length > maxLength) {
// Try to find a good break point (space, comma, etc.)
let breakPoint = maxLength;
for (let i = maxLength - 1; i > maxLength * 0.7; i--) {
if (/\s|,|;|\|/.test(remaining[i])) {
breakPoint = i;
break;
}
}
parts.push(remaining.substring(0, breakPoint).trim());
remaining = remaining.substring(breakPoint).trim();
}
if (remaining) {
parts.push(remaining);
}
return parts;
}
//# sourceMappingURL=stats.js.map
exports.statsSubcommand = statsSubcommand;