/* * CSB Match Config Loader * Copyright (C) 2026 counter-strike-boost.com * * amx_mr15 / amx_mr12 exec the matching competitive config and then, a moment * later, verify the critical cvars (mp_freezetime, mp_roundtime, mp_startmoney, * sv_alltalk, mp_maxrounds). Any cvar that did not take the expected value is * printed as a diff, so a silently broken match config is caught immediately. * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. It is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See for details. */ #include #include new const PLUGIN[] = "CSB Match Config Loader" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pCfg15, g_pCfg12 new const g_szCheck[][] = { "mp_freezetime", "mp_roundtime", "mp_startmoney", "sv_alltalk", "mp_maxrounds" } new g_szExpected[sizeof(g_szCheck)][16] new g_iPendingMode public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pCfg15 = register_cvar("csb_cfg_mr15", "csb_mr15.cfg") g_pCfg12 = register_cvar("csb_cfg_mr12", "csb_mr12.cfg") register_concmd("amx_mr15", "cmdMr15", ADMIN_BAN, "- exec the MR15 config and validate cvars") register_concmd("amx_mr12", "cmdMr12", ADMIN_BAN, "- exec the MR12 config and validate cvars") } public cmdMr15(id, level, cid) { if (!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED loadConfig(id, 15) return PLUGIN_HANDLED } public cmdMr12(id, level, cid) { if (!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED loadConfig(id, 12) return PLUGIN_HANDLED } setExpected(const a[], const b[], const c[], const d[], const e[]) { copy(g_szExpected[0], charsmax(g_szExpected[]), a) copy(g_szExpected[1], charsmax(g_szExpected[]), b) copy(g_szExpected[2], charsmax(g_szExpected[]), c) copy(g_szExpected[3], charsmax(g_szExpected[]), d) copy(g_szExpected[4], charsmax(g_szExpected[]), e) } loadConfig(id, mode) { new cfg[64] if (mode == 15) { get_pcvar_string(g_pCfg15, cfg, charsmax(cfg)) setExpected("0", "1.75", "16000", "0", "30") } else { get_pcvar_string(g_pCfg12, cfg, charsmax(cfg)) setExpected("0", "1.75", "16000", "0", "24") } if (!cfg[0]) { console_print(id, "[CSB] No config filename is set.") return } server_cmd("exec %s", cfg) server_exec() client_print(0, print_chat, "[CSB] Executing match config %s (MR%d)...", cfg, mode) g_iPendingMode = mode new data[1] data[0] = id set_task(1.0, "taskVerify", 0, data, sizeof(data)) } bool:cvarMatches(const a[], const b[]) { new Float:fa = str_to_float(a) new Float:fb = str_to_float(b) new Float:diff = fa - fb if (diff < 0.0) diff = -diff return diff < 0.01 } public taskVerify(data[]) { new id = data[0] if (id && !is_user_connected(id)) id = 0 new mismatches = 0 for (new i = 0; i < sizeof(g_szCheck); i++) { new cur[16] get_cvar_string(g_szCheck[i], cur, charsmax(cur)) if (!cvarMatches(cur, g_szExpected[i])) { mismatches++ if (id) console_print(id, "[CSB] MISMATCH %s = %s (expected %s)", g_szCheck[i], cur, g_szExpected[i]) else log_amx("[CSB MR] mismatch %s = %s (expected %s)", g_szCheck[i], cur, g_szExpected[i]) client_print(0, print_chat, "[CSB] Config warning: %s is %s, expected %s.", g_szCheck[i], cur, g_szExpected[i]) } } if (!mismatches) { client_print(0, print_chat, "[CSB] MR%d config verified: all critical cvars are correct.", g_iPendingMode) if (id) console_print(id, "[CSB] All %d critical cvars match. Config is good.", sizeof(g_szCheck)) } else { client_print(0, print_chat, "[CSB] MR%d config has %d cvar(s) that did not take - check server console.", g_iPendingMode, mismatches) } }