diff --git a/docs/portainer-cs2.md b/docs/portainer-cs2.md index dbc8b15..d9c7cc4 100644 --- a/docs/portainer-cs2.md +++ b/docs/portainer-cs2.md @@ -257,6 +257,9 @@ 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. - **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. +- **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. +- **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. Für eine LAN-Party mit festen Servern ist der **Static-Adapter mit Stack aus Schritt 1** die einfachere und robustere Wahl. diff --git a/server/src/matchService.js b/server/src/matchService.js index 2cd41f6..5d65f8c 100644 --- a/server/src/matchService.js +++ b/server/src/matchService.js @@ -483,7 +483,11 @@ export class MatchService extends EventEmitter { maxRounds: match.mode === 'wingman' ? this.config.match.maxRoundsWingman : this.config.match.maxRoundsCompetitive, overtimeRounds: 6, }); - if (!events.length && JSON.stringify(before) === JSON.stringify(state)) return; + if (!events.length && JSON.stringify(before) === JSON.stringify(state)) { + // Nichts Relevantes dabei, aber der Server liefert: Empfang trotzdem vermerken (Anzeige "Live-Daten empfangen") + this.db.prepare('UPDATE series_maps SET live_updated_at = ? WHERE match_id = ? AND number = ?').run(this.now(), matchId, row.number); + return; + } const finished = events.find((e) => e.type === 'map_end'); this.db .prepare( @@ -706,10 +710,11 @@ export class MatchService extends EventEmitter { status: s.status, score: { A: s.score_a, B: s.score_b }, winner: s.winner, - live: live && { - status: live.status, - sides: live.sides, - rounds: live.rounds, + // Auch ohne Spielstand (Aufwärmphase) mitschicken, sobald der Server Logs liefert + live: (live || s.live_updated_at) && { + status: live?.status ?? 'warmup', + sides: live?.sides ?? null, + rounds: live?.rounds ?? [], updatedAt: s.live_updated_at, }, }; diff --git a/server/src/servers/dockerAdapter.js b/server/src/servers/dockerAdapter.js index 4255a19..50861e3 100644 --- a/server/src/servers/dockerAdapter.js +++ b/server/src/servers/dockerAdapter.js @@ -92,7 +92,8 @@ export class DockerServerAdapter { CS2_PORT: String(port), CS2_RCONPW: secrets.rconPassword, CS2_PW: secrets.serverPassword, - CS2_MAXPLAYERS: mode === 'wingman' ? '4' : '10', + // Spielerplätze + 1 für CSTV (belegt selbst einen Platz) + 1 Reserve (Admin, Ersatz) + CS2_MAXPLAYERS: mode === 'wingman' ? '6' : '12', CS2_GAMETYPE: '0', CS2_GAMEMODE: mode === 'wingman' ? '2' : '1', CS2_SERVER_HIBERNATE: '0', diff --git a/server/test/dockerAdapter.test.js b/server/test/dockerAdapter.test.js index f39d557..28e6a9b 100644 --- a/server/test/dockerAdapter.test.js +++ b/server/test/dockerAdapter.test.js @@ -35,6 +35,7 @@ test('Ohne GSLT startet der Container im LAN-Modus, mit GSLT mit Token', async ( assert.equal(env.CS2_LAN, '1'); assert.equal(env.SRCDS_TOKEN, undefined); assert.equal(env.CS2_GAMEMODE, '2'); + assert.equal(env.CS2_MAXPLAYERS, '6', '4 Spieler + CSTV + Reserve'); assert.equal(env.CS2_PORT, '27100'); assert.equal(env.TV_PORT, '27101'); assert.ok(runArgs.includes('cs2-mapveto-gamefiles:/home/steam/cs2-dedicated'));