Backend: Match-Lobbys, Map-Veto, Echtzeit und CS2-Serveradapter
Express + Socket.IO + SQLite. Veto-Engine mit konfigurierbaren Map-Pools und validierten Abläufen, rollenbasierte Berechtigungen, Server-Lebenszyklus mit Demo-, Docker- und Static-Pool-Adapter (RCON), automatisches Herunterfahren. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
104aa1a67b
27 files changed
+6355
No files matched your search
@@ -0,0 +1,58 @@
|
||||
// Erzeugt die Konsolenbefehle, mit denen ein laufender CS2-Server für eine Map der Serie konfiguriert wird.
|
||||
// Alle Werte werden so bereinigt, dass sie keine weiteren Befehle einschleusen können.
|
||||
|
||||
export function sanitizeConsoleText(value, maxLength = 32) {
|
||||
return String(value ?? '')
|
||||
.replace(/["';\\\r\n\t]/g, '')
|
||||
.replace(/[^\p{L}\p{N} ._\-+#!?()[\]|]/gu, '')
|
||||
.trim()
|
||||
.slice(0, maxLength) || 'Team';
|
||||
}
|
||||
|
||||
/**
|
||||
* Liefert zwei Befehlsgruppen:
|
||||
* - beforeMapChange: Spielmodus, Passwörter, CSTV und der Mapwechsel selbst.
|
||||
* game_type/game_mode und tv_enable greifen erst beim Laden einer Map.
|
||||
* - afterMapChange: Match-Einstellungen. Diese werden erst nach dem Laden gesetzt,
|
||||
* weil die gamemode_*.cfg des Spiels sie beim Mapwechsel sonst überschreibt.
|
||||
*
|
||||
* @param {object} p
|
||||
* @param {object} p.match Match-Datensatz (Teamnamen)
|
||||
* @param {object} p.pool Map-Pool (mode/gameType/gameMode)
|
||||
* @param {object} p.seriesMap { map, ctTeam: 'A'|'B'|null }
|
||||
* @param {object} p.secrets { serverPassword, tvPassword }
|
||||
* @param {object} p.settings config.match
|
||||
*/
|
||||
export function buildMapCommands({ match, pool, seriesMap, secrets, settings }) {
|
||||
const isWingman = pool.mode === 'wingman';
|
||||
const ctTeam = seriesMap.ctTeam ?? 'A';
|
||||
const tTeam = ctTeam === 'A' ? 'B' : 'A';
|
||||
const names = { A: sanitizeConsoleText(match.team_a_name), B: sanitizeConsoleText(match.team_b_name) };
|
||||
|
||||
const beforeMapChange = [
|
||||
`game_type ${Number(pool.gameType)}`,
|
||||
`game_mode ${Number(pool.gameMode)}`,
|
||||
`sv_password "${secrets.serverPassword}"`,
|
||||
`tv_enable ${settings.tvEnabled ? 1 : 0}`,
|
||||
`tv_delay ${Number(settings.tvDelaySeconds)}`,
|
||||
`tv_password "${secrets.tvPassword}"`,
|
||||
`changelevel ${seriesMap.map}`,
|
||||
];
|
||||
|
||||
const afterMapChange = [
|
||||
// mp_teamname_1 = Team, das auf CT startet; mp_teamname_2 = Team, das auf T startet
|
||||
`mp_teamname_1 "${names[ctTeam]}"`,
|
||||
`mp_teamname_2 "${names[tTeam]}"`,
|
||||
`mp_maxrounds ${isWingman ? settings.maxRoundsWingman : settings.maxRoundsCompetitive}`,
|
||||
`mp_overtime_enable ${settings.overtime ? 1 : 0}`,
|
||||
'mp_match_can_clinch 1',
|
||||
'mp_autoteambalance 0',
|
||||
'mp_limitteams 0',
|
||||
// Aufwärmphase läuft, bis der Organisator das Match startet (mp_warmup_end)
|
||||
'mp_warmup_pausetimer 1',
|
||||
...settings.extraCommands,
|
||||
];
|
||||
|
||||
return { beforeMapChange, afterMapChange };
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user