Загрузка данных
/* Modified from the original: https://amx-x.ru/viewtopic.php?f=8&t=34883 */
#include <amxmodx>
#define PLUGIN "Anti-Reconnect"
#define VERSION "1.3"
#define AUTHOR "RevCrew & prnl0"
#define DICTIONARY "anti-rc.txt"
#define SET_BIT(%1,%2) (%1 |= (1 << (%2 & 31)))
#define CLEAR_BIT(%1,%2) (%1 &= ~(1 << (%2 & 31)))
#define CHECK_BIT(%1,%2) (%1 & (1 << (%2 & 31)))
enum DetectType
{
dt_authid = 0,
dt_ip
}
enum _:PlayerData
{
pd_rc_count,
pd_entry_permit_time
}
new Trie:g_user_map;
new g_in_rc;
new g_pcvar_admin_immunity;
new g_pcvar_admin_flag;
new g_pcvar_rc_time;
new g_pcvar_detect_type;
new g_pcvar_chat_show_n_rc_attemps;
new g_pcvar_chat_show;
new g_pcvar_prefix;
public plugin_init()
{
register_plugin(PLUGIN, VERSION, AUTHOR);
register_dictionary(DICTIONARY);
/* CVars */
g_pcvar_admin_immunity = register_cvar("ar_admin_immunity", "0");
g_pcvar_admin_flag = register_cvar("ar_admin_flag", "g");
g_pcvar_rc_time = register_cvar("ar_reconnect_time", "120");
g_pcvar_detect_type = register_cvar("ar_detect_type", "ip");
g_pcvar_chat_show = register_cvar("ar_show_in_chat", "1");
g_pcvar_chat_show_n_rc_attemps = register_cvar("ar_rc_attempts_to_show_in_chat", "3");
g_pcvar_prefix = register_cvar("ar_prefix", "^3[AR]^1");
/* Miscellaneous */
g_user_map = TrieCreate();
}
public plugin_end()
{
TrieDestroy(g_user_map)
}
public client_connect(pid)
{
CLEAR_BIT(g_in_rc, pid);
if (should_bypass_ar(pid)) {
return PLUGIN_CONTINUE;
}
new id[MAX_AUTHID_LENGTH + 1];
get_detect_id(pid, id, charsmax(id));
new player[PlayerData];
/* TODO: checking if `TrieGetArray` succeeded is really not necessary if you
* trust the logic in `client_disconnected`. */
if (TrieGetArray(g_user_map, id, player, 2)) {
new time_left = player[pd_entry_permit_time] - get_systime(0);
if (time_left > 0) {
SET_BIT(g_in_rc, pid);
++player[pd_rc_count];
TrieSetArray(g_user_map, id, player, 2);
server_cmd("kick #%d ^"%L^"", get_user_userid(pid), pid, "CONSOLE_KICK", time_left);
if (
get_pcvar_bool(g_pcvar_chat_show)
&& player[pd_rc_count] <= get_pcvar_num(g_pcvar_chat_show_n_rc_attemps)
) {
/* TODO: eventually replace with a global stock that formats messages. */
new name[MAX_NAME_LENGTH + 1];
new msg[MAX_FMT_LENGTH + 1];
get_user_name(pid, name, charsmax(name));
get_pcvar_string(g_pcvar_prefix, msg, charsmax(msg));
formatex(
msg, charsmax(msg),
"%L", LANG_PLAYER, "CHAT_PLAYER_KICKED", msg, name, get_pcvar_num(g_pcvar_rc_time)
);
client_print_color(0, print_team_default, msg);
}
return PLUGIN_CONTINUE;
}
TrieDeleteKey(g_user_map, id);
}
return PLUGIN_CONTINUE;
}
public client_disconnected(pid)
{
if (should_bypass_ar(pid) || CHECK_BIT(g_in_rc, pid)) {
return PLUGIN_CONTINUE;
}
new id[MAX_AUTHID_LENGTH + 1];
get_detect_id(pid, id, charsmax(id));
new player[PlayerData];
TrieGetArray(g_user_map, id, player, 2);
player[pd_rc_count] = 0;
player[pd_entry_permit_time] = get_systime(0) + get_pcvar_num(g_pcvar_rc_time);
TrieSetArray(g_user_map, id, player, 2);
return PLUGIN_CONTINUE;
}
/* Utilities */
bool:should_bypass_ar(pid)
{
if (get_pcvar_bool(g_pcvar_admin_immunity)) {
new flag[16];
get_pcvar_string(g_pcvar_admin_flag, flag, charsmax(flag));
if (get_user_flags(pid) & read_flags(flag)) {
return true;
}
}
return false;
}
get_detect_id(pid, id[], maxlen)
{
if (get_detect_type() == DetectType:dt_ip) {
get_user_ip(pid, id, maxlen, 1);
} else {
get_user_authid(pid, id, maxlen);
}
}
DetectType:get_detect_type()
{
new detect_type[7];
get_pcvar_string(g_pcvar_detect_type, detect_type, charsmax(detect_type));
if (!strncmp(detect_type, "authid", 6, true)) {
return DetectType:dt_authid;
} else {
return DetectType:dt_ip;
}
}