AMP und feste Host-Namen aus Doku und Tests entfernen

Der Docker-Host ist beliebig; Beispiele nutzen jetzt DOCKER-HOST-IP bzw.
den SSH-Alias docker-host statt eines Rechnernamens. Testfixture heißt
echte-logs-wingman.log.

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
This commit is contained in:
SPP UserandClaude Haiku 5.5 committed 2026-10-25 22:54:38 +01:00
1 parent 413df03237
commit 726974fe82
4 files changed
+16 -16

No files matched your search

+2 -2
View File
@@ -18,7 +18,7 @@ Webanwendung zur Organisation von Counter-Strike-2-Matches: Match-Lobbys mit Tea
CS2-Server-Container auf demselben Docker-Host startet. Siehe [docs/container.md](docs/container.md): CS2-Server-Container auf demselben Docker-Host startet. Siehe [docs/container.md](docs/container.md):
```powershell ```powershell
docker -H ssh://cs2docker build -t cs2-mapveto:latest . docker -H ssh://USER@DOCKER-HOST-IP build -t cs2-mapveto:latest .
``` ```
…dann den Stack aus der Anleitung in Portainer anlegen. …dann den Stack aus der Anleitung in Portainer anlegen.
@@ -298,7 +298,7 @@ Beim Konfigurieren setzt CS2 Mapveto auf dem Server `log on` und `logaddress_add
- Stream-Seite - Stream-Seite
- **Nach dem Spielende:** Ist die Serie noch offen, lädt CS2 Mapveto nach `SERIES_AUTO_ADVANCE_SECONDS` (Standard 30) die nächste Map. Ist sie entschieden (z. B. 2:0 im Best of 3), wird das Match abgeschlossen und der Server freigegeben. Mit `-1` geht beides nur manuell. - **Nach dem Spielende:** Ist die Serie noch offen, lädt CS2 Mapveto nach `SERIES_AUTO_ADVANCE_SECONDS` (Standard 30) die nächste Map. Ist sie entschieden (z. B. 2:0 im Best of 3), wird das Match abgeschlossen und der Server freigegeben. Mit `-1` geht beides nur manuell.
- **Voraussetzung:** Der CS2-Server muss `LOG_RECEIVER_URL` erreichen, im LAN z. B. `http://192.168.178.31:3000`. Ob Daten ankommen, zeigt das Serverpanel des Organisators. Mit `LOG_DEBUG=true` gibt das Backend alle empfangenen Zeilen aus. - **Voraussetzung:** Der CS2-Server muss `LOG_RECEIVER_URL` erreichen, im LAN z. B. `http://192.168.178.31:3000`. Ob Daten ankommen, zeigt das Serverpanel des Organisators. Mit `LOG_DEBUG=true` gibt das Backend alle empfangenen Zeilen aus.
- **Geprüft:** mit einem AMP-Server (Wingman), siehe `server/test/fixtures/amp-wingman-inferno.log`. - **Geprüft:** mit echten Logzeilen eines CS2-Servers (Wingman), siehe `server/test/fixtures/echte-logs-wingman.log`.
Zwei Eigenheiten von CS2 berücksichtigt der Parser: Zwei Eigenheiten von CS2 berücksichtigt der Parser:
- CS2 sendet `Match_Start` schon beim Laden der Map. Gezählt wird erst, nachdem der Organisator „Aufwärmphase beenden“ geklickt hat. - CS2 sendet `Match_Start` schon beim Laden der Map. Gezählt wird erst, nachdem der Organisator „Aufwärmphase beenden“ geklickt hat.
+1 -1
View File
@@ -2,7 +2,7 @@
CS2 Mapveto läuft als **ein** Container: Webseite, Backend, Datenbank (SQLite) und ein Docker-Client. CS2 Mapveto läuft als **ein** Container: Webseite, Backend, Datenbank (SQLite) und ein Docker-Client.
Er steht auf demselben Docker-Host wie die CS2-Server und startet pro Match über `/var/run/docker.sock` Er steht auf demselben Docker-Host wie die CS2-Server und startet pro Match über `/var/run/docker.sock`
einen eigenen CS2-Container. Der Host kann jeder Linux-Rechner mit Docker sein, ein AMP-Server ist nicht nötig. einen eigenen CS2-Container. Der Host kann jeder Linux-Rechner mit Docker sein.
``` ```
Docker-Host (beliebig, Linux, Adresse z. B. 192.168.178.111) Docker-Host (beliebig, Linux, Adresse z. B. 192.168.178.111)
+7 -7
View File
@@ -220,22 +220,22 @@ Läuft CS2 Mapveto auf einem anderen Rechner als Docker (z. B. Windows-PC → Do
```bash ```bash
sudo usermod -aG docker server sudo usermod -aG docker server
``` ```
2. Auf dem Rechner mit CS2 Mapveto einen SSH-Eintrag anlegen (Windows: `C:\Users\<Name>\.ssh\config`) und die Anmeldung per Schlüssel einrichten: 2. Auf dem Rechner mit CS2 Mapveto einen SSH-Eintrag anlegen (Windows: `C:\Users\<Name>\.ssh\config`) und die Anmeldung per Schlüssel einrichten. `DOCKER-HOST-IP` und `USER` durch deine Werte ersetzen:
``` ```
Host cs2docker Host docker-host
HostName 192.168.178.111 HostName DOCKER-HOST-IP
User server User USER
``` ```
3. Testen, **auf dem Rechner mit CS2 Mapveto**, nicht auf dem Docker-Host: 3. Testen, **auf dem Rechner mit CS2 Mapveto**, nicht auf dem Docker-Host:
```powershell ```powershell
docker -H ssh://cs2docker ps docker -H ssh://docker-host ps
``` ```
### 2. `.env` von CS2 Mapveto ### 2. `.env` von CS2 Mapveto
```env ```env
SERVER_ADAPTER=docker SERVER_ADAPTER=docker
DOCKER_HOST=ssh://cs2docker DOCKER_HOST=ssh://docker-host
# leer = LAN-Modus (sv_lan 1), sonst ein Game Server Login Token # leer = LAN-Modus (sv_lan 1), sonst ein Game Server Login Token
CS2_GSLT= CS2_GSLT=
# Adresse, unter der Spieler den Docker-Host erreichen # Adresse, unter der Spieler den Docker-Host erreichen
@@ -257,7 +257,7 @@ Wichtig dabei:
- **Starts laufen nacheinander:** Jeder Match-Container prüft beim Start per SteamCMD auf Updates. Damit nie zwei Container gleichzeitig das Volume aktualisieren, startet CS2 Mapveto den nächsten erst, wenn der vorige seinen Update-Check abgeschlossen hat. Nach einem CS2-Patch dauert der erste Start dadurch länger, die übrigen warten kurz. - **Starts laufen nacheinander:** Jeder Match-Container prüft beim Start per SteamCMD auf Updates. Damit nie zwei Container gleichzeitig das Volume aktualisieren, startet CS2 Mapveto den nächsten erst, wenn der vorige seinen Update-Check abgeschlossen hat. Nach einem CS2-Patch dauert der erste Start dadurch länger, die übrigen warten kurz.
- **Ein GSLT gilt nur für einen laufenden Server.** Ohne Token (LAN-Modus) gibt es diese Grenze nicht. - **Ein GSLT gilt nur für einen laufenden Server.** Ohne Token (LAN-Modus) gibt es diese Grenze nicht.
- **Hardware:** Ein CS2-Server braucht etwa 1–2 CPU-Kerne und 2–3 GB RAM. 6 Kerne und 16 GB reichen für etwa 2–3 gleichzeitige Matches. - **Hardware:** Ein CS2-Server braucht etwa 1–2 CPU-Kerne und 2–3 GB RAM. 6 Kerne und 16 GB reichen für etwa 2–3 gleichzeitige Matches.
- **Plätze:** CSTV belegt selbst einen Spielerplatz. Der Adapter startet Container deshalb mit 6 (Wingman) bzw. 12 (5 gegen 5) Plätzen: alle Spieler, CSTV und eine Reserve. Bei festen Servern (AMP, Stack) `maxplayers` genauso hoch setzen, sonst kommt der letzte Spieler nicht drauf. - **Plätze:** CSTV belegt selbst einen Spielerplatz. Der Adapter startet Container deshalb mit 6 (Wingman) bzw. 12 (5 gegen 5) Plätzen: alle Spieler, CSTV und eine Reserve. Bei festen Servern (Stack) `maxplayers` genauso hoch setzen, sonst kommt der letzte Spieler nicht drauf.
- **Serverliste:** Match-Container tauchen im LAN-Tab von CS2 nicht auf. Der Client sucht dort nur auf den Ports 27015–27020, und Broadcasts erreichen Docker-Container kaum. Spieler verbinden sich über den Befehl bzw. den Knopf „In CS2 verbinden“ auf der Match-Seite. Jedes Match hat ohnehin ein eigenes Passwort. - **Serverliste:** Match-Container tauchen im LAN-Tab von CS2 nicht auf. Der Client sucht dort nur auf den Ports 27015–27020, und Broadcasts erreichen Docker-Container kaum. Spieler verbinden sich über den Befehl bzw. den Knopf „In CS2 verbinden“ auf der Match-Seite. Jedes Match hat ohnehin ein eigenes Passwort.
- **Bots zum Testen:** Ohne menschliche Spieler entfernt CS2 Bots zum Matchstart wieder (`bot_join_after_player 1`). Für Tests `CS2_EXTRA_COMMANDS=bot_join_after_player 0;bot_quota 4;bot_quota_mode fill` setzen. - **Bots zum Testen:** Ohne menschliche Spieler entfernt CS2 Bots zum Matchstart wieder (`bot_join_after_player 1`). Für Tests `CS2_EXTRA_COMMANDS=bot_join_after_player 0;bot_quota 4;bot_quota_mode fill` setzen.
+6 -6
View File
@@ -60,10 +60,10 @@ test('Seitenzuordnung nach dem Rundenende hat Vorrang, veraltete Zeilen zu Runde
assert.deepEqual(s.rounds.map((r) => r.winner), ['A', 'B']); assert.deepEqual(s.rounds.map((r) => r.winner), ['A', 'B']);
}); });
test('Echte Logzeilen eines AMP-Servers (Wingman, 4 Runden, Halbzeit nach 2)', () => { test('Echte Logzeilen eines CS2-Servers (Wingman, 4 Runden, Halbzeit nach 2)', () => {
const lines = fs.readFileSync(path.join(here, 'fixtures', 'amp-wingman-inferno.log'), 'utf8').split(/\r?\n/).filter(Boolean); const lines = fs.readFileSync(path.join(here, 'fixtures', 'echte-logs-wingman.log'), 'utf8').split(/\r?\n/).filter(Boolean);
const warmupEnd = lines.findIndex((l) => l.includes('command "mp_warmup_end"')); const warmupEnd = lines.findIndex((l) => l.includes('command "mp_warmup_end"'));
const amp = { teamNames: { A: 'MaxLAN Blau', B: 'MaxLAN Rot' }, maxRounds: 4, overtimeRounds: 6 }; const ctx = { teamNames: { A: 'MaxLAN Blau', B: 'MaxLAN Rot' }, maxRounds: 4, overtimeRounds: 6 };
const check = (s) => { const check = (s) => {
assert.equal(s.status, 'finished'); assert.equal(s.status, 'finished');
@@ -75,15 +75,15 @@ test('Echte Logzeilen eines AMP-Servers (Wingman, 4 Runden, Halbzeit nach 2)', (
// a) wie vom Server in Paketen geschickt // a) wie vom Server in Paketen geschickt
let s = initialLiveState({ map: 'de_inferno', ctTeam: 'A' }); let s = initialLiveState({ map: 'de_inferno', ctTeam: 'A' });
({ state: s } = applyLogLines(s, lines.slice(0, warmupEnd), amp)); ({ state: s } = applyLogLines(s, lines.slice(0, warmupEnd), ctx));
assert.equal(s.status, 'warmup'); assert.equal(s.status, 'warmup');
s.warmupEnded = true; // Organisator hat "Aufwärmphase beenden" geklickt s.warmupEnded = true; // Organisator hat "Aufwärmphase beenden" geklickt
({ state: s } = applyLogLines(s, lines.slice(warmupEnd), amp)); ({ state: s } = applyLogLines(s, lines.slice(warmupEnd), ctx));
check(s); check(s);
// b) jede Zeile einzeln (ungünstigste Paketgrenzen) // b) jede Zeile einzeln (ungünstigste Paketgrenzen)
let t = initialLiveState({ map: 'de_inferno', ctTeam: 'A', warmupEnded: true }); let t = initialLiveState({ map: 'de_inferno', ctTeam: 'A', warmupEnded: true });
for (const line of lines.slice(warmupEnd)) ({ state: t } = applyLogLines(t, [line], amp)); for (const line of lines.slice(warmupEnd)) ({ state: t } = applyLogLines(t, [line], ctx));
check(t); check(t);
}); });