Add private multiplayer diagnostics to admin stats
This commit is contained in:
1 parent
a0397073f7
commit
0f953f060b
2 files changed
+39
-1
No files matched your search
@@ -232,6 +232,40 @@ if ($httpKey !== '') {
|
||||
} else {
|
||||
$promoListError = 'Die interne Codeverwaltung ist noch nicht mit Nakama verbunden.';
|
||||
}
|
||||
|
||||
$diagnosticRows = null;
|
||||
$diagnosticReports = [];
|
||||
$diagnosticError = '';
|
||||
$diagnosticRound = strtolower(trim((string) ($_GET['round_id'] ?? '')));
|
||||
if ($diagnosticRound !== '' && !preg_match('/^[a-f0-9]{16}$/D', $diagnosticRound)) $diagnosticRound = '';
|
||||
if ($httpKey !== '') {
|
||||
$diagnosticRpc = preg_replace('~/private_stats$~', '/list_online_diagnostics', (string) ($config['nakama_rpc_url'] ?? ''));
|
||||
if (is_string($diagnosticRpc) && $diagnosticRpc !== (string) ($config['nakama_rpc_url'] ?? '')) {
|
||||
$diagnosticUrl = $diagnosticRpc . '?http_key=' . rawurlencode($httpKey) . '&unwrap';
|
||||
$diagnosticResponse = fetchJson($diagnosticUrl, 'POST', '{}');
|
||||
if (is_array($diagnosticResponse) && isset($diagnosticResponse['payload']) && is_string($diagnosticResponse['payload'])) {
|
||||
$decoded = json_decode($diagnosticResponse['payload'], true);
|
||||
if (is_array($decoded)) $diagnosticResponse = $decoded;
|
||||
}
|
||||
if (is_array($diagnosticResponse) && isset($diagnosticResponse['reports']) && is_array($diagnosticResponse['reports'])) {
|
||||
$diagnosticRows = $diagnosticResponse['reports'];
|
||||
if ($diagnosticRound !== '') {
|
||||
$detailResponse = fetchJson($diagnosticUrl, 'POST', json_encode(['round_id' => $diagnosticRound], JSON_THROW_ON_ERROR));
|
||||
if (is_array($detailResponse) && isset($detailResponse['payload']) && is_string($detailResponse['payload'])) {
|
||||
$decoded = json_decode($detailResponse['payload'], true);
|
||||
if (is_array($decoded)) $detailResponse = $decoded;
|
||||
}
|
||||
if (is_array($detailResponse) && isset($detailResponse['reports']) && is_array($detailResponse['reports'])) {
|
||||
$diagnosticReports = $detailResponse['reports'];
|
||||
} else {
|
||||
$diagnosticError = 'Die ausgewählte Runde konnte nicht geladen werden.';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$diagnosticError = 'Die Online-Diagnose konnte nicht geladen werden. Servermodul eventuell noch nicht aktualisiert.';
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
<!doctype html>
|
||||
<html lang="de"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="robots" content="noindex,nofollow,noarchive"><meta http-equiv="refresh" content="300"><title>Void Bastion – Interne Statistik</title><style>
|
||||
@@ -239,7 +273,10 @@ if ($httpKey !== '') {
|
||||
.delete-form{margin:0}.panel .delete-form button{width:auto;min-height:36px;padding:6px 10px;background:#602c38;border-color:#ad5963;font-size:.9rem;white-space:nowrap}
|
||||
</style></head><body><main class="shell"><header><div><p>GERGAMES · NICHT ÖFFENTLICH</p><h1>Void Bastion Statistik</h1></div><a href="?logout=1">Abmelden</a></header>
|
||||
<section class="grid"><article class="card"><strong><?= $downloadTotal ?></strong><span>Downloads insgesamt</span></article><article class="card"><strong><?= $latestDownloads ?></strong><span>Downloads aktuelles Release</span></article><article class="card"><strong><?= $players ?></strong><span>Registrierte Piloten</span></article><article class="card"><strong><?= $activeToday ?></strong><span>Heute aktive Piloten</span></article><article class="card"><strong><?= $platformDownloads['windows'] ?></strong><span>Windows-Downloads</span></article><article class="card"><strong><?= $platformDownloads['android'] ?></strong><span>Android-Downloads</span></article></section>
|
||||
<section class="panel"><h2><?= e($latestRelease) ?></h2><p>Die Downloadwerte stammen direkt aus den Gitea-Release-Anhängen und werden alle fünf Minuten neu geladen.</p><?php if ($playerStats === null): ?><p class="warning">Die private Nakama-Statistik ist noch nicht mit dem HTTP-Schlüssel verbunden.</p><?php else: ?><p>Letzte Spieleraktualisierung: <?= e($updatedAt) ?></p><?php endif; ?><p class="meta">Diese Seite ist nicht verlinkt, von Suchmaschinen ausgeschlossen und verlangt eine Anmeldung. Es werden ausschließlich zusammengefasste Werte dargestellt.</p></section>
|
||||
<section class="panel"><h2><?= e($latestRelease) ?></h2><p>Die Downloadwerte stammen direkt aus den Gitea-Release-Anhängen und werden alle fünf Minuten neu geladen.</p><?php if ($playerStats === null): ?><p class="warning">Die private Nakama-Statistik ist noch nicht mit dem HTTP-Schlüssel verbunden.</p><?php else: ?><p>Letzte Spieleraktualisierung: <?= e($updatedAt) ?></p><?php endif; ?><p class="meta">Diese Seite ist nicht verlinkt, von Suchmaschinen ausgeschlossen und verlangt eine Anmeldung. Spielerzahlen sind zusammengefasst; technische Rundenberichte sind nur hier einsehbar.</p></section>
|
||||
<section class="panel" id="diagnose"><h2>Online-Diagnose</h2><p>Die beiden PCs senden ihre technischen Messwerte am Ende einer Online-Partie automatisch mit derselben Rundenkennung. Berichte sind maximal 14 Tage relevant; Namen und Raumcodes werden hier nicht gespeichert.</p>
|
||||
<?php if ($diagnosticError !== ''): ?><p class="warning"><?= e($diagnosticError) ?></p><?php elseif ($diagnosticRows === null): ?><p class="warning">Noch keine Verbindung zur privaten Online-Diagnose.</p><?php elseif (!$diagnosticRows): ?><p>Noch keine Berichte aus der neuen Spielversion vorhanden.</p><?php else: ?><div class="table-wrap"><table class="codes"><thead><tr><th>Runde</th><th>Seite</th><th>Zeitpunkt</th><th>Version</th><th>Messungen</th></tr></thead><tbody><?php foreach ($diagnosticRows as $row): ?><?php $rowRound = (string) ($row['round_id'] ?? ''); if (!preg_match('/^[a-f0-9]{16}$/D', $rowRound)) continue; ?><tr><td><a href="?round_id=<?= e($rowRound) ?>#diagnose"><code><?= e($rowRound) ?></code></a></td><td><?= (int) ($row['slot'] ?? -1) + 1 ?></td><td><?= e(date('d.m.Y H:i:s', intdiv((int) ($row['created_at'] ?? 0), 1000))) ?></td><td><?= e((string) ($row['version'] ?? '')) ?></td><td><?= (int) ($row['record_count'] ?? 0) ?></td></tr><?php endforeach; ?></tbody></table></div><?php endif; ?>
|
||||
<?php if ($diagnosticRound !== ''): ?><h3>Runde <?= e($diagnosticRound) ?></h3><?php if (!$diagnosticReports): ?><p>Für diese Kennung liegen noch keine Berichte vor.</p><?php else: ?><?php foreach ($diagnosticReports as $report): ?><h4>Seite <?= (int) ($report['slot'] ?? -1) + 1 ?> · <?= e((string) ($report['version'] ?? '')) ?></h4><div class="table-wrap"><table class="codes"><thead><tr><th>UTC</th><th>Spielstände/s</th><th>Abstand p95 / max</th><th>Tick-Sprünge</th><th>Warteschlange verworfen</th><th>Bildaussetzer</th><th>Gegner / Türme</th></tr></thead><tbody><?php foreach (($report['records'] ?? []) as $record): if (($record['event'] ?? '') !== 'window') continue; ?><tr><td><?= e((string) ($record['utc'] ?? '')) ?></td><td><?= e((string) ($record['snapshots_per_second'] ?? 0)) ?></td><td><?= (int) ($record['gap_p95_ms'] ?? 0) ?> / <?= (int) ($record['gap_max_ms'] ?? 0) ?> ms</td><td><?= (int) ($record['tick_jumps_over_1'] ?? 0) ?></td><td><?= (int) ($record['queue_dropped'] ?? 0) ?></td><td><?= (int) ($record['frame_stalls_over_200_ms'] ?? 0) ?> (max <?= (int) ($record['frame_max_ms'] ?? 0) ?> ms)</td><td><?= (int) ($record['enemies'] ?? 0) ?> / <?= (int) ($record['towers'] ?? 0) ?></td></tr><?php endforeach; ?></tbody></table></div><details><summary>Einzelereignisse anzeigen</summary><div class="table-wrap"><table class="codes"><thead><tr><th>UTC</th><th>Ereignis</th><th>Dauer</th><th>Server-Tick</th></tr></thead><tbody><?php foreach (($report['records'] ?? []) as $record): if (($record['event'] ?? '') === 'window') continue; ?><tr><td><?= e((string) ($record['utc'] ?? '')) ?></td><td><?= e((string) ($record['event'] ?? '')) ?></td><td><?= (int) ($record['duration_ms'] ?? 0) ?> ms</td><td><?= (int) ($record['last_server_tick'] ?? 0) ?></td></tr><?php endforeach; ?></tbody></table></div></details><?php endforeach; ?><?php endif; ?><p><a href="./#diagnose">Zur Übersicht</a></p><?php endif; ?></section>
|
||||
<section class="panel"><h2>Freischaltcodes erstellen</h2><p>Codes und Bemerkungen werden ausschließlich in der geschützten Serverablage verwaltet. Der Klartext ist nur in diesem angemeldeten Bereich sichtbar.</p>
|
||||
<?php if (is_array($promoFlash)): ?><div class="result"><strong>Code erstellt:</strong><code><?= e((string) $promoFlash['code']) ?></code><span><?= e((string) $promoFlash['reward']) ?> · offen · maximal <?= (int) $promoFlash['max_uses'] ?> Einlösungen<?php if (($promoFlash['note'] ?? '') !== ''): ?> · <?= e((string) $promoFlash['note']) ?><?php endif; ?></span></div><?php endif; ?>
|
||||
<?php if ($promoDeleteFlash !== ''): ?><div class="result"><?= e($promoDeleteFlash) ?></div><?php endif; ?>
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
<h2>4. GerGames-Onlinekonto und Nakama</h2>
|
||||
<p>Für Ranglisten und Online-Multiplayer werden eine zufällige Konto-ID, Spielername, verknüpfte Anmeldeanbieter, Bestenlistenwerte und für laufende Partien erforderliche Spielzustände an den von GerGames betriebenen Nakama-Server übertragen. Zusätzlich fallen technisch erforderliche Verbindungs- und Sicherheitsdaten wie IP-Adresse und Zeitstempel an. Die Verarbeitung ist zur Bereitstellung der Onlinefunktionen erforderlich; Rechtsgrundlage ist Art. 6 Abs. 1 lit. b DSGVO. Sicherheitsprotokolle können auf Grundlage von Art. 6 Abs. 1 lit. f DSGVO verarbeitet werden.</p>
|
||||
<p>Für eine interne, nicht öffentliche Nutzungsstatistik werden außerdem die pseudonyme Konto-ID, Plattform, App-Version sowie der erste und letzte Aktivitätstag verarbeitet. Daraus werden ausschließlich zusammengefasste Spielerzahlen gebildet. Die Statistik dient der technischen Planung, Fehlererkennung und Weiterentwicklung des Spiels. Rechtsgrundlage ist Art. 6 Abs. 1 lit. f DSGVO; unser berechtigtes Interesse liegt im sicheren und bedarfsgerechten Betrieb des Spiels. Es werden dafür keine Analyse-Cookies und kein externer Analysedienst eingesetzt.</p>
|
||||
<p>Zur Fehleranalyse im Online-Multiplayer übermitteln neuere Spielversionen am Ende einer Partie automatisch technische Messwerte beider Geräte an den eigenen Nakama-Server. Dazu gehören unter anderem Abstände und Größe empfangener Spielzustände, ausgelassene Server-Ticks, Warteschlangen und lokale Bildaussetzer. Beide Berichte werden über eine pseudonyme Rundenkennung zusammengeführt. Im Bericht werden keine Chatnachrichten, IP-Adressen, Spielernamen, Raumcodes oder vollständigen Partieverläufe gespeichert; die Zugriffsprüfung nutzt vorübergehend eine getrennte, serverprivate Teilnehmerzuordnung. Berichte und Zuordnung werden 14 Tage nach Erstellung beim nächsten Diagnoseabruf oder -upload bereinigt. Die Messung dient der Fehlersuche und Stabilisierung des Onlinebetriebs.</p>
|
||||
<p>Kontodaten werden grundsätzlich bis zur Löschung des Kontos gespeichert. Kurzlebige Matchdaten werden nach Ende beziehungsweise Ablauf der Partie nicht dauerhaft als vollständige Partieaufzeichnung gespeichert. Datenbank-Sicherungen werden täglich erstellt und nach 14 Tagen automatisch überschrieben. Gesetzlich erforderliche oder zur Missbrauchsabwehr zwingend benötigte Daten können im erforderlichen Umfang länger aufbewahrt werden.</p>
|
||||
<h2>5. Apple, Google und Plattformkonten</h2>
|
||||
<p>Wenn du später freiwillig „Mit Apple anmelden“, Game Center oder Google Play Games verknüpfst, übermittelt der jeweilige Plattformanbieter eine technische Kennung und gegebenenfalls einen dort gewählten Anzeigenamen. Zweck ist die Anmeldung und Wiederherstellung desselben GerGames-Kontos auf mehreren Geräten. Es gelten zusätzlich die Datenschutzbestimmungen von Apple beziehungsweise Google. Eine Verknüpfung findet erst nach einer aktiven Auswahl statt.</p>
|
||||
|
||||
Reference in new issue
Block a user