remove embed stuff

This commit is contained in:
legop3
2026-09-18 16:36:19 -04:00
parent b712fb89c6
commit 8e301e7db7
3 changed files with 15 additions and 53 deletions
@@ -32,7 +32,7 @@ module.exports = {
token: string({ title: 'Bot token', description: 'Discord bot token used to log in. The saved value is never returned to the browser.', examples: ['DISCORD_BOT_TOKEN'], writeOnly: true, maxLength: 10000 }), token: string({ title: 'Bot token', description: 'Discord bot token used to log in. The saved value is never returned to the browser.', examples: ['DISCORD_BOT_TOKEN'], writeOnly: true, maxLength: 10000 }),
guildId: string({ title: 'Guild id', description: 'Reserved Discord server identifier. The current bot runtime does not restrict commands or events using this value.', examples: ['123456789012345678'], maxLength: 100 }), guildId: string({ title: 'Guild id', description: 'Reserved Discord server identifier. The current bot runtime does not restrict commands or events using this value.', examples: ['123456789012345678'], maxLength: 100 }),
channels: strictObject({ channels: strictObject({
liveStatus: string({ title: 'Live status', description: 'Dedicated live fleet report channel ID. The bot deletes ALL other messages here. Requires View Channel, Read Message History, Send Messages, Embed Links, and Manage Messages. Leave empty to disable.', examples: ['123456789012345678'], maxLength: 100 }), liveStatus: string({ title: 'Live status', description: 'Dedicated live fleet report channel ID. The bot deletes ALL other messages here. Requires View Channel, Read Message History, Send Messages, and Manage Messages. Leave empty to disable.', examples: ['123456789012345678'], maxLength: 100 }),
general: string({ description: 'Channel ID used by the button-box stalker-role and everyone-ping rewards.', examples: ['123456789012345678'], maxLength: 100 }), general: string({ description: 'Channel ID used by the button-box stalker-role and everyone-ping rewards.', examples: ['123456789012345678'], maxLength: 100 }),
announcements: string({ description: 'Channel ID used for public-mode openings, objective changes, and all-rovers-unlocked announcements.', examples: ['123456789012345678'], maxLength: 100 }), announcements: string({ description: 'Channel ID used for public-mode openings, objective changes, and all-rovers-unlocked announcements.', examples: ['123456789012345678'], maxLength: 100 }),
adminAlerts: string({ description: 'Channel ID used for rover health, battery, dock, help, and daily fleet-report notifications.', examples: ['123456789012345678'], maxLength: 100 }), adminAlerts: string({ description: 'Channel ID used for rover health, battery, dock, help, and daily fleet-report notifications.', examples: ['123456789012345678'], maxLength: 100 }),
@@ -338,8 +338,8 @@ function createDiscordRuntime() {
const integrationHandlers = integrations.register(); const integrationHandlers = integrations.register();
const liveStatus = createLiveStatus({ const liveStatus = createLiveStatus({
client, logger, discordConfig, roverManager, getActiveDrivers, getNickname, client, logger, discordConfig, roverManager, getActiveDrivers, getNickname,
io, getMode, getGlobalObjective, fetchChannel: channelIO.fetchChannel, sanitizeMentions, io, fetchChannel: channelIO.fetchChannel, sanitizeMentions,
turnEvents, nicknameEvents, subscribe, turnEvents, nicknameEvents,
}); });
function isTextCommand(content) { function isTextCommand(content) {
@@ -1,10 +1,10 @@
// Owns the single-message live report and the dedicated channel's cleanup. // Owns the single-message live report and the dedicated channel's cleanup.
const { escapeMarkdown, PermissionFlagsBits } = require('discord.js'); const { PermissionFlagsBits } = require('discord.js');
const { buildRoverStatusSnapshot } = require('./batteryEmbeds'); const { buildRoverStatusSnapshot } = require('./batteryEmbeds');
function createLiveStatus({ client, logger, discordConfig, roverManager, getActiveDrivers, function createLiveStatus({ client, logger, discordConfig, roverManager, getActiveDrivers,
getNickname, io, getMode, getGlobalObjective, fetchChannel, sanitizeMentions, getNickname, io, fetchChannel, sanitizeMentions,
turnEvents, nicknameEvents, subscribe }) { turnEvents, nicknameEvents }) {
const COOLDOWN_MS = 3000; const COOLDOWN_MS = 3000;
let timer = null; let timer = null;
let sweepTimer = null; let sweepTimer = null;
@@ -17,60 +17,26 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
let running = false; let running = false;
let channelId = null; let channelId = null;
let messageId = null; let messageId = null;
let lastSignature = null; let lastContent = null;
const clean = (value, limit = 120) => sanitizeMentions(String(value ?? '')) const clean = (value, limit = 120) => sanitizeMentions(String(value ?? ''))
.replace(/[\r\n]+/g, ' ').slice(0, limit); .replace(/[\r\n]+/g, ' ').slice(0, limit);
const rich = (value, limit) => escapeMarkdown(clean(value, limit));
function buildReport() { function buildReport() {
const drivers = getActiveDrivers(); const drivers = getActiveDrivers();
const roster = roverManager.getRoster(); const roster = roverManager.getRoster();
const lines = []; const lines = [];
const fields = [];
let budget = 4800;
for (const rover of roster) { for (const rover of roster) {
const snapshot = buildRoverStatusSnapshot(roverManager.rovers.get(rover.id)); const snapshot = buildRoverStatusSnapshot(roverManager.rovers.get(rover.id));
const driverId = drivers[rover.id]; const driverId = drivers[rover.id];
const driver = driverId ? clean(getNickname(io.sockets.sockets.get(driverId)) || 'Someone', 32) : null; const driver = driverId ? clean(getNickname(io.sockets.sockets.get(driverId)) || 'Someone', 32) : null;
const status = rover.needsHelp ? 'needs help' : driver ? `${driver} driving` const status = snapshot?.docked ? 'docked' : rover.needsHelp ? 'needs help'
: snapshot?.docked ? 'docked' : rover.locked ? 'locked' : 'available'; : driver ? `${driver} driving` : rover.locked ? 'locked' : 'available';
lines.push(`${clean(rover.name, 60)}: ${status}`); lines.push(`${clean(rover.name, 60)}: ${status}`);
const battery = snapshot?.batteryState;
const value = [
`**${rich(status)}**`,
`Driver: ${rich(driver || 'none')}`,
`Battery: ${battery?.percentDisplay == null ? 'unknown' : `${battery.percentDisplay}%`}`,
`Charge: ${battery?.charge ?? '?'} / ${battery?.capacity ?? '?'} mAh`,
`Dock: ${snapshot?.docked ? 'docked' : 'undocked'}`,
`Charging: ${rich(snapshot?.chargingLabel || 'unknown')}`,
`Lock: ${rover.locked ? rich(rover.lockReason || 'locked') : 'unlocked'}`,
`Operating mode: ${rich(snapshot?.oiMode || 'unknown')}`,
].join('\n').slice(0, 1024);
const name = `${rover.needsHelp ? '🆘' : snapshot?.docked ? '🏠' : '🤖'} ${rich(rover.name, 60)}`;
// Leave room for the header/footer and stay within Discord's single-message limits.
if (fields.length < 25 && name.length + value.length <= budget) {
fields.push({ name, value, inline: true });
budget -= name.length + value.length;
}
} }
let content = lines.join('\n') || 'No rovers online.'; let content = lines.join('\n') || 'No rovers online.';
if (content.length > 2000) content = `${content.slice(0, 1950)}\n… More rovers online.`; if (content.length > 2000) content = `${content.slice(0, 1950)}\n… More rovers online.`;
const objective = getGlobalObjective()?.text; return { content, allowedMentions: { parse: [] } };
return {
content,
allowedMentions: { parse: [] },
embeds: [{
title: 'Live rover status',
color: roster.some((rover) => rover.needsHelp) ? 0xe74c3c : 0x2ecc71,
description: [`**${rich(getMode(), 60)}** · ${roster.length} online`,
objective ? `Objective: ${rich(objective, 300)}` : null].filter(Boolean).join('\n'),
fields,
footer: { text: fields.length < roster.length
? `${roster.length - fields.length} rover details omitted due to Discord limits · Live updates`
: 'Live updates' },
}],
};
} }
function schedule() { function schedule() {
@@ -99,7 +65,7 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
if (target !== channelId) { if (target !== channelId) {
channelId = target; channelId = target;
messageId = null; messageId = null;
lastSignature = null; lastContent = null;
} }
if (!target) return; if (!target) return;
running = true; running = true;
@@ -110,8 +76,7 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
&& discordConfig.channels?.liveStatus?.trim() === target; && discordConfig.channels?.liveStatus?.trim() === target;
try { try {
const report = buildReport(); const report = buildReport();
const signature = JSON.stringify(report); const replace = report.content !== lastContent;
const replace = signature !== lastSignature;
// Sensor events can arrive many times per second. Compare the rendered // Sensor events can arrive many times per second. Compare the rendered
// report locally before consuming any Discord API capacity. // report locally before consuming any Discord API capacity.
if (!replace && !cleanup) return; if (!replace && !cleanup) return;
@@ -123,8 +88,8 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
} }
const permissions = channel.permissionsFor(client.user); const permissions = channel.permissionsFor(client.user);
if (!permissions?.has([PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ReadMessageHistory, if (!permissions?.has([PermissionFlagsBits.ViewChannel, PermissionFlagsBits.ReadMessageHistory,
PermissionFlagsBits.SendMessages, PermissionFlagsBits.EmbedLinks, PermissionFlagsBits.ManageMessages])) { PermissionFlagsBits.SendMessages, PermissionFlagsBits.ManageMessages])) {
throw new Error('Live status requires View Channel, Read Message History, Send Messages, Embed Links, and Manage Messages'); throw new Error('Live status requires View Channel, Read Message History, Send Messages, and Manage Messages');
} }
let found = false; let found = false;
let before; let before;
@@ -150,11 +115,10 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
} }
if (!active()) return; if (!active()) return;
if (replace || !found) { if (replace || !found) {
report.embeds[0].timestamp = new Date().toISOString();
const message = await channel.send(report); const message = await channel.send(report);
if (!active()) return; if (!active()) return;
messageId = message.id; messageId = message.id;
lastSignature = signature; lastContent = report.content;
} }
} catch (err) { } catch (err) {
cleanupNeeded = true; cleanupNeeded = true;
@@ -196,8 +160,6 @@ function createLiveStatus({ client, logger, discordConfig, roverManager, getActi
() => nicknameEvents.off('change', onChange), () => nicknameEvents.off('change', onChange),
() => client.off('messageDelete', onDelete), () => client.off('messageDelete', onDelete),
() => client.off('messageDeleteBulk', onBulkDelete), () => client.off('messageDeleteBulk', onBulkDelete),
subscribe('mode.changed', onChange),
subscribe('globalObjective.updated', onChange),
); );
} }
clearInterval(sweepTimer); clearInterval(sweepTimer);