Server-Seite ueberarbeitet, und die Spielauswahl kommt jetzt aus gamedig
LS25 fehlte, aber nicht nur LS25: die Auswahl im Panel war eine von Hand gepflegte Liste mit neunzehn Eintraegen, und fuenf davon gab es bei gamedig gar nicht — "arkse", "ark", "sevendaystodie", "minecraftbe" und "terraria". Wer eines davon auswaehlte, bekam einen Server, der dauerhaft offline stand, ohne dass irgendwo ein Grund stand. Die echten IDs heissen ase, sdtd, mbe und terrariatshock. Also nicht LS25 nachtragen, sondern die Liste abschaffen: sie kommt jetzt aus gamedig selbst, 360 Eintraege, sortiert, mit Suche. Jedes Update bringt neue Spiele automatisch mit. Dazu der Standard-Query-Port als Vorschlag, sobald man ein Spiel waehlt. Bestehende Eintraege mit den toten IDs werden beim Start einmalig umgebogen. Farming Simulator hat noch eine zweite Huerde: der Server antwortet nur mit Zugangs-Code, und den hat queryServer nie durchgereicht. LS25 waere also auch mit richtiger ID offline geblieben. Jetzt gibt es eine Spalte dafuer, das Feld erscheint nur bei Spielen, die einen brauchen (Farming Simulator, Terraria — bei Satisfactory optional), und Speichern ohne Code wird abgelehnt statt stillschweigend hingenommen. Der Code steht nicht in der oeffentlichen API. Nebenbei aufgefallen: input[type=password] war im CSS nirgends erfasst. Das erste solche Feld kam voellig ungestylt daher. Die /server-Seite dazu: - Auslastungs-Balken mit eigener Farbe statt des XP-Balkens vom Level-System. Gruen frei, gelb ab 80 Prozent, rot voll — die Zahl steht rechtsbuendig, mittig laege sie bei 50 Prozent genau auf der Fuellkante. - Map, Version und Ping als Chips. Vorher standen sie mit Punkten getrennt in der Statuszeile und wurden auf dem Handy zu Brei. - Wer gerade drauf ist. Die Namen holt der Monitor ohnehin schon fuers Embed, auf der Seite standen sie nur nirgends. - Welches Spiel es ueberhaupt ist. Das stand nirgends ausser im Emoji. - Offline-Karten waren bisher leer bis auf das Wort. Jetzt steht dort, seit wann — soweit der Verlauf reicht, sonst gar nichts statt einer Schaetzung. - Zeitachse und Peak-Linie am Verlauf. Eine Flaeche ohne Bezugspunkt sagt nicht, wie hoch hoch ist. - Plaetze insgesamt in der Uebersicht oben. Geprueft: Token speichern und aendern, Spielnamen inklusive unbekannter ID, Token-Bedarf pro Protokoll, Liste ohne Doppler, alle Icon-Schluessel gegen gamedig, "zuletzt online" ignoriert Offline-Proben, und die Migration mit einer Datenbank im alten Stand. Beide Seiten am laufenden Frontend angesehen, auch auf Handybreite. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
// pro Server ein Live-Embed (Spieler-Balken, Map, Player-Liste, Connect-Link),
|
||||
// Down/Up-Alerts mit 2-Fails-Schwelle. Verwaltet im Setup-Tab "Server".
|
||||
import { ActivityType, EmbedBuilder, Events } from 'discord.js';
|
||||
import { GameDig } from 'gamedig';
|
||||
import { GameDig, games as gamedigGames } from 'gamedig';
|
||||
import { getSetting, listGameservers, setGameserverMessage, recordPlayerSample, prunePlayerHistory } from '../db.js';
|
||||
import { brandFooter, botStatusText } from '../runtime-settings.js';
|
||||
import { brandEmbed } from '../embeds.js';
|
||||
@@ -12,15 +12,59 @@ import { tuning, tuningMs, everyTuned } from '../tuning.js';
|
||||
const GREEN = 0x23a55a;
|
||||
const RED = 0xf23f43;
|
||||
|
||||
// Emoji pro Spieltyp (Fallback 🎮)
|
||||
// Emoji pro Spieltyp (Fallback 🎮). Die Schlüssel sind gamedig-IDs — hier
|
||||
// standen mal ausgedachte wie "arkse" oder "terraria", die es dort gar nicht
|
||||
// gibt. Beim Ändern gegen `games` aus gamedig prüfen, nicht gegen das Gefühl.
|
||||
export const GAME_ICONS = {
|
||||
fivem: '🚗', http: '🌐', minecraft: '⛏️', minecraftbe: '⛏️',
|
||||
fivem: '🚗', http: '🌐', minecraft: '⛏️', mbe: '⛏️',
|
||||
teamfortress2: '🎩', counterstrike2: '🔫', csgo: '🔫', garrysmod: '🔧',
|
||||
rust: '🪓', valheim: '🛡️', palworld: '🐑', ark: '🦖', arkse: '🦖',
|
||||
dayz: '🧟', projectzomboid: '🧟', sevendaystodie: '🧟',
|
||||
satisfactory: '🏭', terraria: '🌳', arma3: '🪖', squad: '🪖', unturned: '🏝️',
|
||||
rust: '🪓', valheim: '🛡️', palworld: '🐑', ase: '🦖', asa: '🦖', pixark: '🦖',
|
||||
dayz: '🧟', projectzomboid: '🧟', sdtd: '🧟',
|
||||
satisfactory: '🏭', terrariatshock: '🌳', arma3: '🪖', squad: '🪖', unturned: '🏝️',
|
||||
farmingsimulator19: '🚜', farmingsimulator22: '🚜', farmingsimulator25: '🚜',
|
||||
};
|
||||
|
||||
// fivem und http sind unsere eigenen Typen — gamedig kennt sie nicht.
|
||||
const EIGENE = {
|
||||
fivem: { name: 'FiveM', port: 30120 },
|
||||
http: { name: 'HTTP-Check', port: null },
|
||||
};
|
||||
|
||||
// Protokolle, die ohne Zugangs-Code gar nicht antworten. Der Code steht im
|
||||
// Webinterface des jeweiligen Servers — bei Farming Simulator zum Beispiel
|
||||
// unter http://host:8080/settings.html. Ohne ihn wirft gamedig, und der Server
|
||||
// stünde dauerhaft auf "offline", ohne dass man den Grund sähe.
|
||||
const TOKEN_PFLICHT = new Set(['farmingsimulator', 'terraria']);
|
||||
// Hier ist der Code optional: gamedig holt sich sonst selbst einen.
|
||||
const TOKEN_OPTIONAL = new Set(['satisfactory']);
|
||||
|
||||
/** Klartext-Name eines Typs — "farmingsimulator25" → "Farming Simulator 25" */
|
||||
export function spielName(type) {
|
||||
return EIGENE[type]?.name ?? gamedigGames[type]?.name ?? type;
|
||||
}
|
||||
|
||||
/** 'pflicht' | 'optional' | null — steuert das Token-Feld im Panel */
|
||||
export function tokenBedarf(type) {
|
||||
const protokoll = gamedigGames[type]?.options?.protocol;
|
||||
if (TOKEN_PFLICHT.has(protokoll)) return 'pflicht';
|
||||
if (TOKEN_OPTIONAL.has(protokoll)) return 'optional';
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Alle abfragbaren Spiele für die Auswahl im Panel, nach Namen sortiert */
|
||||
export function spielListe() {
|
||||
const eigene = Object.entries(EIGENE).map(([id, e]) => ({
|
||||
id, name: e.name, port: e.port, token: null, eigen: true,
|
||||
}));
|
||||
const aus_gamedig = Object.entries(gamedigGames)
|
||||
.map(([id, g]) => ({
|
||||
id, name: g.name, port: g.options?.port ?? null,
|
||||
token: tokenBedarf(id), eigen: false,
|
||||
}))
|
||||
.sort((a, b) => a.name.localeCompare(b.name, 'de'));
|
||||
return [...eigene, ...aus_gamedig];
|
||||
}
|
||||
|
||||
// Alert-Zustand pro Server (in-memory)
|
||||
const alertState = new Map(); // id → { fails, down, since }
|
||||
|
||||
@@ -31,7 +75,7 @@ export const lastResults = new Map(); // id → Query-Ergebnis + checkedAt
|
||||
export async function queryServer(server) {
|
||||
const base = {
|
||||
...server, online: false, players: null, max: null, map: null,
|
||||
playerNames: [], ping: null,
|
||||
playerNames: [], ping: null, version: null,
|
||||
};
|
||||
const started = Date.now();
|
||||
try {
|
||||
@@ -62,6 +106,9 @@ export async function queryServer(server) {
|
||||
type: server.type,
|
||||
host: server.host,
|
||||
port: server.port || undefined,
|
||||
// Manche Spiele antworten nur mit Code — Farming Simulator etwa.
|
||||
// Leer weglassen, sonst schickt gamedig "token=" mit.
|
||||
token: server.token || undefined,
|
||||
maxRetries: 1,
|
||||
socketTimeout: tuningMs.seconds('monitor_timeout'),
|
||||
});
|
||||
@@ -70,6 +117,7 @@ export async function queryServer(server) {
|
||||
players: state.players?.length ?? state.numplayers ?? 0,
|
||||
max: state.maxplayers ?? null,
|
||||
map: state.map || null,
|
||||
version: state.version || null,
|
||||
playerNames: (state.players ?? []).map((p) => p?.name).filter(Boolean).slice(0, 15),
|
||||
};
|
||||
} catch {
|
||||
@@ -103,6 +151,7 @@ export function buildServerEmbed(r) {
|
||||
});
|
||||
}
|
||||
if (r.map) embed.addFields({ name: 'Map', value: r.map, inline: true });
|
||||
if (r.version) embed.addFields({ name: 'Version', value: String(r.version).slice(0, 60), inline: true });
|
||||
if (r.connect_url) {
|
||||
// steam:// & Co. sind in Embeds klickbar (Link-Buttons erlauben nur https)
|
||||
embed.addFields({ name: 'Connect', value: `[${r.connect_url}](${r.connect_url})`, inline: false });
|
||||
|
||||
Reference in New Issue
Block a user