Код:
/* UFPS Slots Reservation
* -[4.07.14] Доработка проверки на STEAM игрока.
*
* Переменные:
*
* amx_reservation (default: 0) - Количество резервных слотов.
*
* amx_hideslots (default: 0) - Метод скрытия резервных слотов.
* -1 - Не скрывать резервные слоты, отобразить количество слотов равным sv_visiblemaxplayers
* 0 - Не скрывать резервные слоты, отобразить количество слотов равным maxplayers
* 1 - Скрывать резервные слоты (стандартный режим скрытия adminslots)
* 2 - Полностью скрыть резевные слоты (войти на резервный слот можно будет только командой connect из консоли)
*
* amx_remove_mode (default: 0) - Режим выбора игрока для удаления с сервера, при входе админа на последний резервный слот.
* 0 - Удаляются только боты
* 1 - Удаляются боты или игроки с наиболее высоким пингом
* 2 - Удаляются боты или игроки с наименьшим временем игры на сервере
* 3 - Удаляются боты или игроки с наибольшим временем игры на сервере
*
* amx_remove_hltv (default: 0) - Удалять с сервера HLTV, при входе админа на последний резервный слот.
* 0 - Не удалять HLTV
* 1 - Удалять HLTV, как обычного игрока.
*
* amx_remove_redirect (default: 0) - Метод удаления игрока с сервера
* 0 - Кикать игрока.
* 1 - Перенаправлять игрока на указанный в adminslots.ini сервер.
*
* amx_remove_showmotd (default: 0) - При удалении игрока показывать ему MOTD с сообщением о причине удаления.
* 0 - Не показывать MOTD
* 1 - Показывать MOTD
*
* amx_remove_endround (default: 0) - Удалять игрока только по окончании раунда.
* 0 - Сразу
* 1 - Ожидать окончания раунда
*
*/
#include <amxmodx>
#include <amxmisc>
#define PLUGIN_NAME "UFPS Slots Reservation"
#define PLUGIN_VERSION "4.3 +fix"
#define PLUGIN_AUTHOR "UFPS.Team"
#define ADMIN_IMMUNE ADMIN_RESERVATION
#define MOTD_TIME 5.0
#define LEN_STRING 32
#define MAX_PLAYERS 32
#define MAX_SUBNET 64
/* PRIVATE MODULE
*
* Можно пускать на сервер определенную группу игроков,
* которая будет иметь приоритет перед остальными простыми игроками, удаляя их с сервера.
* Создавать группы, вы можете самостоятельно, дописав в функцию is_user_private
*
* Группы, которые можно подключить через PRIVATE_MODE:
* 0 - Функция отключена
* 1 - Игроки с локальных сетей
* 2 - Игроки с клиентом MYAC
* 3 - Игроки с клиентом STEAM
* 4 - Игроки со специальным флагом (по-умолчанию "r": ADMIN_LEVEL_F)
*
*/
#define PRIVATE_MODE 3
#define PRIVATE_FLAG ADMIN_LEVEL_F
new g_maxplayers
new pcv_mode
new pcv_hltv
new pcv_endround
new pcv_showmotd
new pcv_redirect
new pcv_hideslots
new pcv_reservation
new pcv_vismaxplayers
new bool:g_remove_user [MAX_PLAYERS + 1]
new bool:steamUser [33]
new subnet_count
new subnet_ip [MAX_SUBNET]
new subnet_mask [MAX_SUBNET]
new subnet_redirect [MAX_SUBNET] [LEN_STRING + 1]
new subnet_password [MAX_SUBNET] [LEN_STRING + 1]
public plugin_init()
{
register_plugin ( PLUGIN_NAME, PLUGIN_VERSION, PLUGIN_AUTHOR )
register_dictionary ( "adminslots.txt" )
register_dictionary ( "adminslots_motd.txt" )
register_logevent ( "event_end_round", 2, "1=Round_End" )
pcv_hideslots = register_cvar( "amx_hideslots", "0" )
pcv_reservation = register_cvar( "amx_reservation", "0" )
pcv_mode = register_cvar( "amx_remove_mode", "0" )
pcv_hltv = register_cvar( "amx_remove_hltv", "0" )
pcv_endround = register_cvar( "amx_remove_endround", "0" )
pcv_showmotd = register_cvar( "amx_remove_showmotd", "0" )
pcv_redirect = register_cvar( "amx_remove_redirect", "0" )
pcv_vismaxplayers = get_cvar_pointer( "sv_visiblemaxplayers" )
g_maxplayers = get_maxplayers()
}
public plugin_cfg( )
{
set_task( 0.5, "load_subnets" )
}
public load_subnets( )
{
new configsdir[64], filename[64], file
get_configsdir( configsdir, charsmax( configsdir ) )
formatex( filename, charsmax( filename ), "%s/adminslots.ini", configsdir )
file = fopen( filename, "r" )
if( file )
{
new string[256], subnet[LEN_STRING], ip[16], mask[4], _ip
subnet_count = 0
while(( subnet_count <( MAX_SUBNET ) ) && !feof( file ) )
{
fgets( file, string, charsmax( string ) )
if(( string[0] != ';' ) &&( string[0] != '/' ) &&
parse( string, subnet, charsmax( string ), subnet_redirect[subnet_count], LEN_STRING, subnet_password[subnet_count], LEN_STRING ) &&
strtok( subnet, ip, charsmax( ip ), mask, charsmax( mask ), '/', 1 ) )
{
_ip = get_num_ip( ip )
if( _ip != -1 )
{
subnet_ip[subnet_count] = get_mask_ip( _ip, str_to_num( mask ) )
subnet_mask[subnet_count] = str_to_num( mask )
subnet_count++
}
}
}
fclose( file )
}
else
{
log_amx( "File ^"%s^" not found", filename )
}
set_visibleslots( get_playersnum( 1 ), g_maxplayers - clamp( get_pcvar_num( pcv_reservation ), 0 , g_maxplayers ) )
}
public client_disconnect( id )
{
g_remove_user[id] = false
set_visibleslots( get_playersnum( 1 ) - 1, g_maxplayers - clamp( get_pcvar_num( pcv_reservation ), 0 , g_maxplayers ) )
if( task_exists( id ) ) remove_task( id )
return PLUGIN_CONTINUE
}
public client_authorized( id )
{
new players = get_playersnum( 1 )
new reserv = clamp( get_pcvar_num( pcv_reservation ), 0 , g_maxplayers )
new limit = g_maxplayers - reserv
// if( ( is_user_steam( id ) ) ? "steamUser[id] = true" : "steamUser[id] = false" )
if ( is_user_steam( id ) ) steamUser[id] = true
set_visibleslots( players, limit )
if( players > limit )
{
new who
if( access( id, ADMIN_IMMUNE ) )
{
if( players < g_maxplayers ) return PLUGIN_CONTINUE
who = cmd_find_player( id )
if( who )
cmd_remove_delay( who )
}
else if( is_user_private( id ) )
{
who = cmd_find_player( id )
if( who )
cmd_remove_delay( who )
else
{
cmd_remove_player( id )
return PLUGIN_HANDLED
}
}
else
{
cmd_remove_player( id )
return PLUGIN_HANDLED
}
}
return PLUGIN_CONTINUE
}
public event_end_round( )
{
if( get_pcvar_num( pcv_endround ) )
for( new i = 1; i <= MAX_PLAYERS ; ++i )
if( g_remove_user[i] ) cmd_remove_motd( i )
return PLUGIN_CONTINUE
}
public cmd_remove_delay( id )
{
if( is_user_bot( id ) || is_user_hltv( id ) )
{
cmd_remove_player( id )
}
else
{
if( get_pcvar_num( pcv_endround ) )
g_remove_user[id] = true
else
cmd_remove_motd( id )
}
}
public cmd_remove_motd( id )
{
if( is_user_connected( id ) && !check_freeslots() )
{
if( !get_pcvar_num( pcv_showmotd ) )
{
cmd_remove_player( id )
}
else
{
new buffer[1024], title[64]
format( title, sizeof( title ) - 1, "%L", id, "AEHTM_TITLE" )
new pos = format( buffer, sizeof( buffer ) - 1, "%L", id, "AEHTM_META" )
if( pos < sizeof( buffer ) )
pos += format( buffer[pos], sizeof( buffer ) - 1, "%L", id, "AEHTM_STYLE" )
if( get_pcvar_num( pcv_redirect ) )
{
if( pos < sizeof( buffer ) )
pos += format( buffer[pos], sizeof( buffer ) - 1, "%L", id, "AEHTM_RDIR" )
}
else
{
if( pos < sizeof( buffer ) )
pos += format( buffer[pos], sizeof( buffer ) - 1, "%L", id, "AEHTM_KICK" )
}
show_motd( id, buffer, title )
if( task_exists( id ) ) remove_task( id )
set_task( MOTD_TIME, "cmd_remove_player", id )
}
}
}
public cmd_remove_player( id )
{
if( is_user_connected( id ) || is_user_connecting( id ) )
{
if( is_user_bot( id ) || is_user_hltv( id ) )
{
server_cmd( "kick #%d", get_user_userid( id ) )
}
else if( get_pcvar_num( pcv_redirect ) )
{
new ip[16]
get_user_ip( id, ip, charsmax( ip ), 1 )
new subnet_index = get_subnet_id( ip )
if( subnet_index != -1 )
{
if( subnet_password[subnet_index][0] )
client_cmd( id, ";Password ^"%s^"", subnet_password[subnet_index] )
client_cmd( id, ";Echo ^"* Server is full, redirect to free server.^";Disconnect;Wait;Wait;Wait;Connect %s", subnet_redirect[subnet_index] )
}
}
else
{
new reason[128], name[LEN_STRING]
get_user_name( id, name, sizeof( name ) - 1 )
format( reason, sizeof( reason ) - 1, "%L", id, "DROPPED_RES" )
cmd_remove_user( id, reason )
}
}
}
stock cmd_find_player( caller )
{
new players[MAX_PLAYERS], num
get_players( players, num, "" )
new id, player, ping, loss, time, time_find, ping_find = -1
new action = get_pcvar_num( pcv_mode )
if( num ) time_find = get_user_time( players[0] )
for( new i; i < num ; ++i )
{
player = players[i]
if( is_user_bot( player ) ) return player
if( !get_pcvar_num( pcv_hltv ) && is_user_hltv( player ) ) continue
if( access( player, ADMIN_IMMUNE ) ) continue
if( !access( caller, ADMIN_IMMUNE ) && is_user_private( player ) ) continue
switch( action )
{
case 1:
{
get_user_ping( player, ping, loss )
if( ping > ping_find )
{
ping_find = ping
id = player
}
}
case 2:
{
time = get_user_time( player )
if( time <= time_find )
{
time_find = time
id = player
}
}
case 3:
{
time = get_user_time( player )
if( time >= time_find )
{
time_find = time
id = player
}
}
}
}
return id
}
stock subnet_to_ip( ip_safe[16], mask_safe )
{
new mask = mask_safe
if( mask > 32 || mask < 0 ) mask = 32
new byte[4], bits = 8
new ip[16], ip_int[4], ip_str[16]
new invmask[9] = {0,128,192,224,240,248,252,254,255}
copy( ip_str, charsmax( ip_str ), ip_safe )
for( new i=0; i < 4; i++ )
{
strtok( ip_str, byte, charsmax( byte ), ip_str, charsmax( ip_str ), '.', 1 )
ip_int[i] = str_to_num( byte )
}
for( new i=0; i < 4; i++ )
{
if( mask < bits ) bits = mask
num_to_str(( ip_int[i] & invmask[bits] ), byte, charsmax( byte ) )
add( ip, charsmax( ip ), byte )
if( i < 3 ) add( ip, charsmax( ip ), "." )
mask -= bits
}
return ip
}
stock set_visibleslots( const players, const limit )
{
switch( get_pcvar_num( pcv_hideslots ) )
{
case 0:
set_pcvar_num( pcv_vismaxplayers, g_maxplayers );
case 1:
{
new slots = players + 1
if( players == g_maxplayers )
slots = g_maxplayers
else if( players < limit )
slots = limit
set_pcvar_num( pcv_vismaxplayers, slots )
}
case 2:
set_pcvar_num( pcv_vismaxplayers, limit );
}
}
stock check_freeslots( )
{
return( get_playersnum( 1 ) <= ( g_maxplayers - clamp( get_pcvar_num( pcv_reservation ), 0 , g_maxplayers ) ) )
}
stock get_num_ip( const ip[] )
{
static string[16], byte_0[4], byte_A[4], byte_B[4], byte_C[4], _ip
copy( string, charsmax( string ), ip )
replace_all( string, charsmax( string ), ".", " ")
if( parse( string, byte_0, charsmax( byte_0 ), byte_A, charsmax( byte_A ), byte_B, charsmax( byte_B ), byte_C, charsmax( byte_C ) ) != 4 ) return -1
_ip = ( str_to_num( byte_0 ) & 255 ) << 24
_ip += ( str_to_num( byte_A ) & 255 ) << 16
_ip += ( str_to_num( byte_B ) & 255 ) << 8
_ip += str_to_num( byte_C ) & 255
return _ip
}
stock get_mask_ip( const _ip, const _mask )
{
if( !_mask ) return 0
new shift = 32 - clamp( _mask, 0 , 32 )
return( _ip >> shift ) << shift
}
stock get_subnet_id( const ip[] )
{
new _ip = get_num_ip( ip )
for( new i; i < subnet_count; ++i ) if( subnet_ip[i] == get_mask_ip( _ip, subnet_mask[i] ) ) return i
return -1
}
#define SVC_DISCONNECT 2
stock cmd_remove_user( const id, const reason[128] )
{
if( is_user_connected( id ) )
{
message_begin ( MSG_ONE_UNRELIABLE, SVC_DISCONNECT, _, id )
write_string ( reason )
message_end ( )
server_exec ( )
}
else if( is_user_connecting( id ) )
{
server_cmd( "kick #%d %s", get_user_userid( id ), reason )
}
}
/* PRIVATE PLAYERS MODULE */
#define LAN_NUM 4
new subnet_lan_ip [LAN_NUM] =
{
2130706432, // 127.0.0.0
-1062731776, // 192.168.0.0
-1408237568, // 172.16.0.0
167772160 // 10.0.0.0
}
new subnet_lan_mask [LAN_NUM] =
{
8,
16,
12,
8
}
stock get_users_private( players[32], &num )
{
num = 0
for( new id = 1; id < ( MAX_PLAYERS + 1 ); id++ )
if( is_user_connected( id ) && is_user_private( id ) ) players[num++] = id
}
stock bool:is_user_private( id )
{
switch( PRIVATE_MODE )
{
case 1:
{
new ip[16]
get_user_ip ( id, ip, 15, 1 )
new _ip = get_num_ip( ip )
for( new i; i < LAN_NUM; ++i ) if( subnet_lan_ip[i] == get_mask_ip( _ip, subnet_lan_mask[i] ) ) return true
}
case 2:
{
new myAC[32]
get_user_info( id, "*myAC", myAC, charsmax( myAC ) )
if( str_to_num( myAC ) > 0 ) return true
}
case 3:
{
if (steamUser[id]) return true
}
case 4:
{
if( get_user_flags( id ) & PRIVATE_FLAG ) return true
}
}
return false
}
stock bool:is_user_steam( id )
{
static dp_pointer
if(dp_pointer || (dp_pointer = get_cvar_pointer("dp_r_id_provider")))
{
server_cmd("dp_clientinfo %d", id)
server_exec()
return (get_pcvar_num(dp_pointer) == 2) ? true : false
}
return false
}