const express = require("express"); const router = express.Router(); const readline = require("readline"); const fs = require("fs"); const rcon = require("../modules/rcon"); const is_authenticated = require("../modules/middleware"); const ALLOWED_STEAM_IDS = ["76561198154367261"]; router.post("/api/setup-game", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const team1 = req.body.team1; const team2 = req.body.team2; var map = req.body.map; const game = req.body.game.toString(); switch (map) { case "cs_office_prophunt": map = 3644811896; break; case "de_assembly": map = 3071005299; break; case "de_brewery": map = 2870304806; break; case "de_dogtown": map = 3414036782; break; case "de_edin": map = 3328169568; break; case "de_grail": map = 3246527710; break; case "de_inferno_prophunt": map = 3608612434; break; case "de_mirage_prophunt": map = 3615968422; break; case "de_memento": map = 3165559377; break; case "de_maginot": map = 3195399109; break; case "de_mirage_bricks": map = 3464733042; break; case "de_palais": map = 3257582863; break; case "de_rainfall": map = 3265650949; break; case "de_rooftop": map = 3536622725; break; case "de_thera": map = 3121217565; break; case "de_transit": map = 3542662073; break; case "de_whistle": map = 3308613773; break; default: map = map; } if (team1.trim() != "") { await rcon.execute_command(server_id, `mp_teamname_1 "${team1}"`); } if (team2.trim() != "") { await rcon.execute_command(server_id, `mp_teamname_2 "${team2}"`); } if (game == "1") { // Competitive Short await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 1`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_competitive_16.cfg"); await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); } else if (game == "2") { // Competitive Long await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 1`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_competitive_24.cfg"); await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); } else if (game == "3") { // Casual Short await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 0`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_casual_16.cfg"); await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); } else if (game == "4") { // Casual Long await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 0`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_casual_24.cfg"); await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); } else if (game == "5") { // Wingman await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 2`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_wingman.cfg"); await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); } else if (game == "6") { // Arms race await rcon.execute_command(server_id, `game_type 1`); await rcon.execute_command(server_id, `game_mode 0`); await rcon.execute_command(server_id, `sv_skirmish_id 10`); execute_cfg_on_server(server_id, "./cfg/live_arms_race.cfg"); } else if (game == "7") { // Prophunt await rcon.execute_command(server_id, `game_type 0`); await rcon.execute_command(server_id, `game_mode 0`); await rcon.execute_command(server_id, `sv_skirmish_id 0`); execute_cfg_on_server(server_id, "./cfg/live_prophunt.cfg"); } if (isNaN(map)) { await rcon.execute_command(server_id, `changelevel ${map}`); } else { await rcon.execute_command(server_id, `host_workshop_map ${map}`); } // Adding 1 second delay in executing warmup.cfg to make it effective after map has been changed. if (game == "1" || game == "3" || game == "5") { setTimeout(() => { execute_cfg_on_server(server_id, "./cfg/warmup_16.cfg"); }, 1000); } else if (game == "2" || game == "4") { setTimeout(() => { execute_cfg_on_server(server_id, "./cfg/warmup_24.cfg"); }, 1000); } else if (game == "6") { setTimeout(() => { rcon.execute_command(server_id, `mp_restartgame 30`); }, 1000); } else if (game == "7") { setTimeout(() => { rcon.execute_command(server_id, "mp_restartgame 3"); }, 1000); } return res.status(200).json({ message: "Game Created!" }); } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/restart", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; await rcon.execute_command(server_id, `mp_restartgame 1`); return res.status(200).json({ message: "Game restarted" }); } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/start-warmup", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; execute_cfg_on_server(server_id, "./cfg/warmup.cfg"); execute_cfg_on_server(server_id, "./cfg/warmup_restart.cfg"); return res.status(200).json({ message: "Warmup started!" }); } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/swap-team", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; await rcon.execute_command(server_id, `mp_swapteams`); return res.status(200).json({ message: "Teams Swapped!" }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/go-live", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const res_mode = await rcon.execute_command(server_id, `game_mode`); const game_mode = res_mode.split("=")[1].trim().toString(); const res_type = await rcon.execute_command(server_id, `game_type`); const game_type = res_type.split("=")[1].trim().toString(); const res_rounds = await rcon.execute_command(server_id, `mp_maxrounds`); const maxrounds = res_rounds.split("=")[1].trim().toString(); if (game_mode == "1" && maxrounds == "16") { console.log("Executing live_competitive_16.cfg"); execute_cfg_on_server(server_id, "./cfg/live_competitive_16.cfg"); } else if (game_mode == "1" && maxrounds == "24") { console.log("Executing live_competitive_24.cfg"); execute_cfg_on_server(server_id, "./cfg/live_competitive_24.cfg"); } else if (game_mode == "0" && maxrounds == "16") { console.log("Executing live_casual_16.cfg"); execute_cfg_on_server(server_id, "./cfg/live_casual_16.cfg"); } else if (game_mode == "0" && maxrounds == "24") { console.log("Executing live_casual_24.cfg"); execute_cfg_on_server(server_id, "./cfg/live_casual_24.cfg"); } else if (game_mode == "2") { console.log("Executing live_wingman.cfg"); execute_cfg_on_server(server_id, "./cfg/live_wingman.cfg"); } execute_cfg_on_server(server_id, "./cfg/live_restart.cfg"); return res.status(200).json({ message: "Match is live!!" }); } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }); // List Round Backups API router.post("/api/list-backups", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.execute_command( server_id, "mp_backup_restore_list_files", ); console.log("Server response:", response); return res.status(200).json({ message: response }); } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }); // Restore Round API router.post("/api/restore-round", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; let round_number = req.body.round_number.toString(); if (round_number.length == 1) { round_number = "0" + round_number; } console.log( `SENDING mp_backup_restore_load_file backup_round${round_number}.txt`, ); await rcon.execute_command( server_id, `mp_backup_restore_load_file backup_round${round_number}.txt`, ); await rcon.execute_command(server_id, `mp_pause_match`); return res.status(200).json({ message: "Round Restored!" }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); router.post( "/api/restore-latest-backup", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.execute_command( server_id, `mp_backup_round_file_last`, ); const last_round_file = response.split("=")[1].trim().toString(); if (last_round_file.includes(".txt")) { await rcon.execute_command( server_id, `mp_backup_restore_load_file ${last_round_file}`, ); await rcon.execute_command(server_id, `mp_pause_match`); return res .status(200) .json({ message: `Latest Round Restored! (${last_round_file})` }); } else { return res.status(200).json({ message: "No latest backup found!" }); } } catch (error) { console.log(error); res.status(500).json({ error: "Internal server error" }); } }, ); // Pause Game API router.post("/api/pause", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.execute_command(server_id, "mp_pause_match"); return res.status(200).json({ message: "Game paused" }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); // Unpause Game API router.post("/api/unpause", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const response = await rcon.execute_command(server_id, "mp_unpause_match"); return res.status(200).json({ message: "Game unpaused" }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/rcon", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const command = req.body.command; const response = await rcon.execute_command(server_id, command); if (response == 200) { return res.status(200).json({ message: "Command sent!" }); } return res .status(200) .json({ message: "Command sent! Response received:\n" + response.toString(), }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); router.post("/api/say-admin", is_authenticated, async (req, res) => { try { const server_id = req.body.server_id; const message = req.body.message; const message_to_send = "say " + message; await rcon.execute_command(server_id, message_to_send); return res.status(200).json({ message: "Message sent!" }); } catch (error) { res.status(500).json({ error: "Internal server error" }); } }); function check_whitelisted_players() { rcon.rcons[server_id] .execute("status_json") .then((response) => { console.log(response); const server_status = JSON.parse(response); const players = server_status["server"]["clients"]; for (var i = 0; i < players.length; i++) { let player = players[i]; if ( !player.bot && player.steamid64.includes("7656") && !ALLOWED_STEAM_IDS.includes(player.steamid64) ) { console.log(`kick ${player.name}`); rcon.rcons[server_id].execute(`kick ${player.name}`); } } return; }) .catch(console.error); } function splitByByteLength(data, length) { const lines = data; const exportedLines = []; const lineEndChar = "; "; let index = 0; for (let item = 0; item < lines.length; item++) { if (typeof exportedLines[index] === "undefined") { exportedLines[index] = ""; } const lineFormatted = `${lines[item]}${lineEndChar}`; const lineBytes = Buffer.byteLength(lineFormatted, "utf8"); const bufferBytes = Buffer.byteLength(exportedLines[index], "utf8"); if (bufferBytes + lineBytes < length) { exportedLines[index] += lineFormatted; } else { index++; } } return exportedLines; } async function execute_cfg_on_server(server_id, cfg_path) { fs.readFile(cfg_path, "utf8", (err, data) => { if (err) { throw err; } data = data.replace(/^\/\/.*$/m, ""); data = data.split("\n"); const new_data = []; for (let i = 0; i < data.length; i += 1) { const line = data[i].trim(); const segments = line.split(" "); if (segments[0] === "say" || segments.length == 1) { new_data.push(line); } else if (segments[0] !== "" && segments[0] !== "//") { new_data.push(`${segments[0]} ${segments[1].split("\t")[0]}`); } } const exported_lines = splitByByteLength(data, 512); async function execute_next_item(item) { try { if (item < exported_lines.length) { console.log("Executing on server:", exported_lines[item]); await rcon.execute_command(server_id, exported_lines[item]); // Wait for 100ms before moving to the next iteration setTimeout(() => { execute_next_item(item + 1); }, 100); } } catch (error) { console.log("[execute_next_item] Error:", error); } } execute_next_item(0); }); } module.exports = { router, };