/* * CSB Demo Request * Copyright (C) 2026 counter-strike-boost.com * * At match start the plugin asks every client to record a demo with * client_cmd(id, "record ") using a prefix_map_date_player scheme, and * stops them at match end. Handy for anti-cheat review in mixes. Players whose * console is disabled are warned that recording may not have started. * * 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 Demo Request" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" new g_pEnabled, g_pPrefix new bool:g_bRecording public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_demo_enabled", "1") g_pPrefix = register_cvar("csb_demo_prefix", "csbmix") register_logevent("evGameCommencing", 2, "1=Game_Commencing") register_concmd("amx_demostart", "cmdStart", ADMIN_BAN, "- ask all clients to record a demo") register_concmd("amx_demostop", "cmdStop", ADMIN_BAN, "- stop client demos") } recordName(id, out[], len) { new prefix[16], mapname[32], stamp[24], name[32], safe[32] get_pcvar_string(g_pPrefix, prefix, charsmax(prefix)) get_mapname(mapname, charsmax(mapname)) get_time("%Y%m%d", stamp, charsmax(stamp)) get_user_name(id, name, charsmax(name)) /* keep only filename-safe characters from the player name */ new j = 0 for (new i = 0; name[i] && j < charsmax(safe); i++) { new c = name[i] if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) safe[j++] = c } safe[j] = 0 if (!safe[0]) copy(safe, charsmax(safe), "player") formatex(out, len, "%s_%s_%s_%s", prefix, mapname, stamp, safe) } requestOne(id) { if (!is_user_connected(id) || is_user_bot(id) || is_user_hltv(id)) return new demo[80] recordName(id, demo, charsmax(demo)) client_cmd(id, "record %s", demo) client_print(id, print_chat, "[CSB] Recording your demo as %s - do NOT type 'stop' or disconnect.", demo) } startAll() { new players[32], num get_players(players, num, "ch") for (new i = 0; i < num; i++) requestOne(players[i]) g_bRecording = true client_print(0, print_chat, "[CSB] Match demos are being recorded on every client. If your console is off, recording may not start.") } stopAll() { new players[32], num get_players(players, num, "ch") for (new i = 0; i < num; i++) client_cmd(players[i], "stop") g_bRecording = false client_print(0, print_chat, "[CSB] Client demo recording stopped.") } public evGameCommencing() { if (get_pcvar_num(g_pEnabled)) set_task(2.0, "taskStart") } public taskStart() { if (get_pcvar_num(g_pEnabled)) startAll() } public client_putinserver(id) { /* late joiner during an active recording session */ if (g_bRecording && !is_user_bot(id)) set_task(3.0, "taskLate", id) } public taskLate(id) { if (g_bRecording) requestOne(id) } public cmdStart(id, level, cid) { if (!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED startAll() console_print(id, "[CSB] Demo recording requested from all clients.") return PLUGIN_HANDLED } public cmdStop(id, level, cid) { if (!cmd_access(id, level, cid, 1)) return PLUGIN_HANDLED stopAll() console_print(id, "[CSB] Demo recording stopped on all clients.") return PLUGIN_HANDLED }