// ========================================================
set sv_clientcommand_antispam_time 1 "Amount of seconds after a command before another command can be called again without being considered spam. (Use -1 for no antispam limit)"
set sv_clientcommand_antispam_count 8 "Amount of commands considered spam before commands are rejected."
+set sv_clientcommand_antispam_percommand 1 "Apply separate antispam timers for each command"
seta sv_status_privacy 1 "hide IP addresses from \"status\" and \"who\" replies shown to clients"
seta cl_autoswitch 1 "automatically switch to newly picked up weapons if they are better than what you are carrying"
FOREACH(CLIENT_COMMANDS, true, { CMD_Write_Alias("qc_cmd_cmd", it.m_name, it.m_description); });
}
+bool ClientCommand_antispam(int argc, entity caller, string command)
+{
+ entity store = IS_CLIENT(caller) ? CS(caller) : caller; // unfortunately, we need to store these on the client initially
+ .float floodtime = cmd_floodtime;
+
+ if(autocvar_sv_clientcommand_antispam_percommand)
+ {
+ string c = strtolower(argv(0));
+ FOREACH(CLIENT_COMMANDS, it.m_name == c, {
+ floodtime = cmd_floodtime_forcommand[it.m_id];
+ break;
+ });
+ }
+
+ if(time < store.(floodtime))
+ {
+ sprint(caller, strcat("^3CMD FLOOD CONTROL: wait ^1", ftos(store.(floodtime) - time), "^3 seconds, command was: ", command, "\n"));
+ return true;
+ }
+ else
+ {
+ float spamtime = autocvar_sv_clientcommand_antispam_time;
+ int spamcount = autocvar_sv_clientcommand_antispam_count;
+ store.(floodtime) = max(time - spamcount * spamtime, store.(floodtime)) + spamtime;
+ }
+
+ return false;
+}
+
// ======================================
// Main Function Called By Engine (cmd)
// ======================================
LABEL(flood_control)
if (!timeout_status) // not while paused
{
- entity store = IS_CLIENT(this) ? CS(this) : this; // unfortunately, we need to store these on the client initially
- // this is basically the same as the chat flood control
- if (time < store.cmd_floodtime)
- {
- sprint(this, strcat("^3CMD FLOOD CONTROL: wait ^1", ftos(store.cmd_floodtime - time), "^3 seconds, command was: ", command, "\n"));
- return; // too much spam, halt
- }
- else
- store.cmd_floodtime = max(time - autocvar_sv_clientcommand_antispam_count * autocvar_sv_clientcommand_antispam_time, store.cmd_floodtime) + autocvar_sv_clientcommand_antispam_time;
+ if(ClientCommand_antispam(argc, this, command))
+ return; // too much spam, halt
}
break; // continue, as we're not flooding yet
}
ENDCLASS(clientcommand_##id) \
REGISTER(CLIENT_COMMANDS, CMD_SVCL, id, m_id, NEW(clientcommand_##id)); \
METHOD(clientcommand_##id, m_invokecmd, void(clientcommand_##id this, int request, entity caller, int arguments, string command))
+
+.float cmd_floodtime_forcommand[REGISTRY_MAX(CLIENT_COMMANDS)];