/* * CSB Name Filter * Copyright (C) 2026 counter-strike-boost.com * * Blocks unwanted player names on connect and on rename. Names are checked * against a case-insensitive substring blacklist loaded from an ini file * (advertising URLs, IP addresses, slurs, admin impersonation). A matching * player is either auto-renamed to a generated name or kicked, and a per-player * cooldown stops name-change spam. * * This is an independent GPL implementation; it is not based on any other * plugin's source. * * 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 the GNU General * Public License for more details: . */ #include new const PLUGIN[] = "CSB Name Filter" new const VERSION[] = "1.0.0" new const AUTHOR[] = "counter-strike-boost.com" #define MAX_PATTERNS 128 #define COOLDOWN 3.0 new g_pEnabled, g_pAction, g_pMinLen, g_pBlockIp new g_szBad[MAX_PATTERNS][32] new g_iBadCount = 0 new g_szLastName[33][32] new Float:g_flLastChange[33] public plugin_init() { register_plugin(PLUGIN, VERSION, AUTHOR) g_pEnabled = register_cvar("csb_namefilter_enabled", "1") g_pAction = register_cvar("csb_namefilter_action", "0") /* 0 = rename, 1 = kick */ g_pMinLen = register_cvar("csb_namefilter_minlen", "2") g_pBlockIp = register_cvar("csb_namefilter_blockip", "1") } public plugin_cfg() { loadPatterns() } loadPatterns() { g_iBadCount = 0 new path[128] get_localinfo("amxx_configsdir", path, charsmax(path)) if (!path[0]) copy(path, charsmax(path), "addons/amxmodx/configs") add(path, charsmax(path), "/csb_namefilter.ini") if (!file_exists(path)) { log_amx("[CSB Name Filter] %s not found - using a small built-in list.", path) seedDefaults() return } new line[64], len for (new i = 0; i < 4096; i++) { if (!read_file(path, i, line, charsmax(line), len)) break trim(line) if (!line[0] || line[0] == ';' || line[0] == '#') continue if (g_iBadCount >= MAX_PATTERNS) break strtolower(line) copy(g_szBad[g_iBadCount], charsmax(g_szBad[]), line) g_iBadCount++ } if (!g_iBadCount) seedDefaults() log_amx("[CSB Name Filter] loaded %d name patterns.", g_iBadCount) } seedDefaults() { new const defaults[][] = { "http://", "https://", "www.", ".com", ".net", ".ru", ".org", "admin", "owner", "console", "[csb]" } for (new i = 0; i < sizeof(defaults) && g_iBadCount < MAX_PATTERNS; i++) { copy(g_szBad[g_iBadCount], charsmax(g_szBad[]), defaults[i]) g_iBadCount++ } } public client_putinserver(id) { g_szLastName[id][0] = 0 g_flLastChange[id] = 0.0 if (!is_user_bot(id) && !is_user_hltv(id)) checkName(id) } public client_infochanged(id) { if (!is_user_connected(id) || is_user_bot(id) || is_user_hltv(id)) return new newname[32] get_user_info(id, "name", newname, charsmax(newname)) if (!newname[0] || equal(newname, g_szLastName[id])) return checkName(id) } checkName(id) { if (!get_pcvar_num(g_pEnabled)) return new name[32] get_user_name(id, name, charsmax(name)) copy(g_szLastName[id], charsmax(g_szLastName[]), name) new reason[32] reason[0] = 0 if (isBad(name, reason, charsmax(reason))) { punish(id, name, reason) return } /* rate-limit legitimate but rapid renames */ new Float:now = get_gametime() if (g_flLastChange[id] > 0.0 && (now - g_flLastChange[id]) < COOLDOWN) { client_print_color(id, print_team_default, "^x04[CSB]^x01 Please stop changing your name so fast.") } g_flLastChange[id] = now } bool:isBad(const name[], reason[], rlen) { new lname[32] copy(lname, charsmax(lname), name) strtolower(lname) trim(lname) if (strlen(lname) < get_pcvar_num(g_pMinLen)) { copy(reason, rlen, "name too short") return true } if (get_pcvar_num(g_pBlockIp) && looksLikeIp(lname)) { copy(reason, rlen, "looks like an IP") return true } for (new i = 0; i < g_iBadCount; i++) { if (contain(lname, g_szBad[i]) != -1) { formatex(reason, rlen, "matched '%s'", g_szBad[i]) return true } } return false } bool:looksLikeIp(const s[]) { new dots = 0, digits = 0 for (new i = 0; s[i]; i++) { if (s[i] == '.') dots++ else if (s[i] >= '0' && s[i] <= '9') digits++ } return (dots >= 3 && digits >= 4) } punish(id, const name[], const reason[]) { if (get_pcvar_num(g_pAction) == 1) { log_amx("[CSB Name Filter] kicked '%s' (%s)", name, reason) server_cmd("kick #%d ^"Your name is not allowed on this server^"", get_user_userid(id)) return } new newname[32] formatex(newname, charsmax(newname), "Player_%d", get_user_userid(id)) set_user_info(id, "name", newname) copy(g_szLastName[id], charsmax(g_szLastName[]), newname) client_print_color(id, print_team_default, "^x04[CSB]^x01 Your name was rejected (%s) and changed to^x04 %s^x01.", reason, newname) log_amx("[CSB Name Filter] renamed '%s' -> '%s' (%s)", name, newname, reason) } public client_disconnected(id) { g_szLastName[id][0] = 0 g_flLastChange[id] = 0.0 }