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; const map = req.body.map; const game = req.body.game.toString(); 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") { await rcon.execute_command(server_id, `game_mode 1`); execute_cfg_on_server(server_id, './cfg/live_competitive_16.cfg'); } else if (game == "2") { await rcon.execute_command(server_id, `game_mode 1`); execute_cfg_on_server(server_id, './cfg/live_competitive_24.cfg'); } else if (game == "3") { await rcon.execute_command(server_id, `game_mode 0`); execute_cfg_on_server(server_id, './cfg/live_casual_16.cfg'); } else if (game == "4") { await rcon.execute_command(server_id, `game_mode 0`); execute_cfg_on_server(server_id, './cfg/live_casual_24.cfg'); } else if (game == "5") { await rcon.execute_command(server_id, `game_mode 2`); execute_cfg_on_server(server_id, './cfg/live_wingman.cfg'); } await rcon.execute_command(server_id, `mp_warmup_pausetimer 1`); await rcon.execute_command(server_id, `changelevel ${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) } 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 };