Rollback: Runden aus CS2-Sicherungen zurückspielen (nur Admin)

Beim Konfigurieren aktiviert CS2 Mapveto die Rundensicherung des Servers
(mp_backup_round_auto, Präfix mit Match-ID). Im Admin-Modus lassen sich
die Sicherungen der laufenden Map auflisten und zurückspielen. Der
Live-Stand wird auf die Runden bis zur Sicherung gekürzt. Organisatoren
haben keinen Zugang zu den Rollback-Routen.

Sicherheit: Dateinamen werden gegen Match-ID und Muster geprüft, damit
keine fremden Dateien oder Befehle in die RCON-Zeile gelangen.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
SPP UserandClaude Haiku 5.5 committed 2026-10-25 23:24:49 +01:00
1 parent 22996cc4e4
commit a4218c47d1
13 files changed
+327 -5

No files matched your search

+15
View File
@@ -2,6 +2,7 @@ import { EventEmitter } from 'node:events';
import { BEST_OF, computeVetoState, resolveAction, VetoError } from './veto.js';
import { formatCode, hashToken, normalizeCode, randomCode, randomId, randomToken, safeEqual } from './security.js';
import { applyLogLines, initialLiveState, seriesScore, splitLogBody } from './liveScore.js';
import { trimLiveState } from './rounds.js';
import { sanitizeConsoleText } from './servers/cs2Config.js';
export class HttpError extends Error {
@@ -448,6 +449,20 @@ export class MatchService extends EventEmitter {
.run(matchId, number);
}
/** Stand auf den Zeitpunkt nach einer Runde zurückstellen (nach Rollback). */
rewindLiveScore(matchId, roundNumber, file) {
const match = this.getMatch(matchId);
const row = this.seriesMaps(matchId).find((m) => m.number === match.current_map_number);
if (!row) return;
const live = row.live ? trimLiveState(JSON.parse(row.live), roundNumber) : null;
const score = live ? live.score : { A: 0, B: 0 };
this.db
.prepare("UPDATE series_maps SET score_a = ?, score_b = ?, winner = NULL, status = 'live', live = ?, live_updated_at = ? WHERE match_id = ? AND number = ?")
.run(score.A, score.B, live ? JSON.stringify(live) : null, this.now(), matchId, row.number);
this.log(matchId, 'rollback', `Map ${row.number} zurückgespielt auf Runde ${roundNumber} (${file})`);
this.changed(matchId);
}
/** Organisator hat die Aufwärmphase beendet: ab dem nächsten Match_Start wird gezählt. */
markWarmupEnded(matchId, ended = true) {
const match = this.getMatch(matchId);