2016-01-19 23:58:55 +01:00
# pragma semicolon 1
# include <sourcemod>
2017-05-01 12:27:00 +02:00
# include <sdktools>
# include <cstrike>
2016-01-19 23:58:55 +01:00
# include <regex>
2017-05-01 12:27:00 +02:00
# include <dhooks>
2016-01-19 23:58:55 +01:00
# pragma newdecls required
2017-05-01 12:27:00 +02:00
# define COMMAND_SIZE 1024
// bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
Handle g_hAcceptInput ;
2016-01-19 23:58:55 +01:00
StringMap g_Rules ;
ArrayList g_aRules ;
ArrayList g_Regexes ;
ArrayList g_RegexRules ;
enum
{
MODE_NONE = 0 ,
MODE_ALL = 1 ,
MODE_STRVALUE = 2 ,
MODE_INTVALUE = 4 ,
MODE_FLOATVALUE = 8 ,
MODE_REGEXVALUE = 16 ,
MODE_MIN = 32 ,
MODE_MAX = 64 ,
MODE_ALLOW = 128 ,
MODE_DENY = 256 , // Reverse
MODE_CLAMP = 512 ,
STATE_NONE = 0 ,
STATE_ALLOW = 1 ,
STATE_DENY = 2 ,
STATE_CLAMPMIN = 4 ,
STATE_CLAMPMAX = 8
} ;
public Plugin myinfo =
{
name = " PointServerCommandFilter " ,
author = " BotoX " ,
description = " Filters point_servercommand->Command() using user-defined rules to restrict maps. " ,
2016-01-28 01:18:10 +01:00
version = " 1.0 " ,
2016-01-19 23:58:55 +01:00
url = " "
} ;
public void OnPluginStart ( )
{
2017-05-20 05:08:31 +02:00
Handle hGameConf = LoadGameConfigFile ( " sdktools.games " ) ;
2017-05-01 12:27:00 +02:00
if ( hGameConf = = INVALID_HANDLE )
{
2017-05-20 05:08:31 +02:00
SetFailState ( " Couldn't load sdktools game config! " ) ;
2017-05-01 12:27:00 +02:00
return ;
}
int Offset = GameConfGetOffset ( hGameConf , " AcceptInput " ) ;
g_hAcceptInput = DHookCreate ( Offset , HookType_Entity , ReturnType_Bool , ThisPointer_CBaseEntity , AcceptInput ) ;
DHookAddParam ( g_hAcceptInput , HookParamType_CharPtr ) ;
DHookAddParam ( g_hAcceptInput , HookParamType_CBaseEntity ) ;
DHookAddParam ( g_hAcceptInput , HookParamType_CBaseEntity ) ;
DHookAddParam ( g_hAcceptInput , HookParamType_Object , 20 , DHookPass_ByVal | DHookPass_ODTOR | DHookPass_OCTOR | DHookPass_OASSIGNOP ) ; //varaint_t is a union of 12 (float[3]) plus two int type params 12 + 8 = 20
DHookAddParam ( g_hAcceptInput , HookParamType_Int ) ;
CloseHandle ( hGameConf ) ;
/* Late Load */
int entity = INVALID_ENT_REFERENCE ;
while ( ( entity = FindEntityByClassname ( entity , " point_servercommand " ) ) ! = INVALID_ENT_REFERENCE )
{
OnEntityCreated ( entity , " point_servercommand " ) ;
}
2016-01-19 23:58:55 +01:00
LoadConfig ( ) ;
}
2017-05-01 12:27:00 +02:00
public void OnEntityCreated ( int entity , const char [ ] classname )
{
if ( StrEqual ( classname , " point_servercommand " ) )
{
DHookEntity ( g_hAcceptInput , false , entity ) ;
}
}
// bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
public MRESReturn AcceptInput ( int pThis , Handle hReturn , Handle hParams )
{
char szInputName [ 128 ] ;
DHookGetParamString ( hParams , 1 , szInputName , sizeof ( szInputName ) ) ;
if ( ! StrEqual ( szInputName , " Command " , true ) )
return MRES_Ignored ;
int client = 0 ;
if ( ! DHookIsNullParam ( hParams , 2 ) )
client = DHookGetParam ( hParams , 2 ) ;
char sCommand [ COMMAND_SIZE ] ;
DHookGetParamObjectPtrString ( hParams , 4 , 0 , ObjectValueType_String , sCommand , sizeof ( sCommand ) ) ;
int bReplaced = 0 ;
if ( client > 0 & & client < = MaxClients & & IsClientInGame ( client ) )
{
char sName [ MAX_NAME_LENGTH ] ;
GetClientName ( client , sName , sizeof ( sName ) ) ;
char sSteamId [ 32 ] ;
GetClientAuthId ( client , AuthId_Engine , sSteamId , sizeof ( sSteamId ) ) ;
char sUserID [ 32 ] ;
FormatEx ( sUserID , sizeof ( sUserID ) , " #%d " , GetClientUserId ( client ) ) ;
char sTeam [ 32 ] ;
if ( GetClientTeam ( client ) = = CS_TEAM_CT )
strcopy ( sTeam , sizeof ( sTeam ) , " @ct " ) ;
else if ( GetClientTeam ( client ) = = CS_TEAM_T )
strcopy ( sTeam , sizeof ( sTeam ) , " @t " ) ;
bReplaced + = ReplaceString ( sCommand , sizeof ( sCommand ) , " !activator.name " , sName , false ) ;
bReplaced + = ReplaceString ( sCommand , sizeof ( sCommand ) , " !activator.steamid " , sSteamId , false ) ;
bReplaced + = ReplaceString ( sCommand , sizeof ( sCommand ) , " !activator.team " , sTeam , false ) ;
bReplaced + = ReplaceString ( sCommand , sizeof ( sCommand ) , " !activator " , sUserID , false ) ;
}
Action iAction = PointServerCommandForward ( sCommand ) ;
if ( iAction = = Plugin_Stop )
{
DHookSetReturn ( hReturn , false ) ;
return MRES_Supercede ;
}
2018-07-19 13:52:43 +02:00
else if ( iAction = = Plugin_Changed | | GetEngineVersion ( ) = = Engine_CSGO | | bReplaced )
2017-05-01 12:27:00 +02:00
{
ServerCommand ( sCommand ) ;
DHookSetReturn ( hReturn , true ) ;
return MRES_Supercede ;
}
return MRES_Ignored ;
}
Action PointServerCommandForward ( char [ ] sOrigCommand )
2016-01-19 23:58:55 +01:00
{
static char sCommandRight [ 1024 ] ;
static char sCommandLeft [ 128 ] ;
strcopy ( sCommandRight , sizeof ( sCommandRight ) , sOrigCommand ) ;
TrimString ( sCommandRight ) ;
int Split = SplitString ( sCommandRight , " " , sCommandLeft , sizeof ( sCommandLeft ) ) ;
if ( Split = = - 1 )
2016-01-28 01:18:10 +01:00
{
2016-01-19 23:58:55 +01:00
strcopy ( sCommandLeft , sizeof ( sCommandLeft ) , sCommandRight ) ;
2016-01-28 01:18:10 +01:00
Split = 0 ;
}
2016-01-19 23:58:55 +01:00
TrimString ( sCommandLeft ) ;
strcopy ( sCommandRight , sizeof ( sCommandRight ) , sCommandRight [ Split ] ) ;
StringToLower ( sCommandLeft ) ;
StringToLower ( sCommandRight ) ;
ArrayList RuleList ;
if ( g_Rules . GetValue ( sCommandLeft , RuleList ) )
return MatchRuleList ( RuleList , sOrigCommand , sCommandLeft , sCommandRight ) ;
for ( int i = 0 ; i < g_Regexes . Length ; i + + )
{
Regex hRegex = g_Regexes . Get ( i ) ;
if ( MatchRegex ( hRegex , sCommandLeft ) > 0 )
{
RuleList = g_RegexRules . Get ( i ) ;
return MatchRuleList ( RuleList , sOrigCommand , sCommandLeft , sCommandRight ) ;
}
}
LogMessage ( " Blocked (No Rule): \" %s \" " , sOrigCommand ) ;
return Plugin_Stop ;
}
2017-05-01 12:27:00 +02:00
Action MatchRuleList ( ArrayList RuleList , char [ ] sOrigCommand , const char [ ] sCommandLeft , const char [ ] sCommandRight )
2016-01-19 23:58:55 +01:00
{
for ( int r = 0 ; r < RuleList . Length ; r + + )
{
int State = STATE_NONE ;
StringMap Rule = RuleList . Get ( r ) ;
int Mode ;
Rule . GetValue ( " mode " , Mode ) ;
2016-01-28 01:18:10 +01:00
bool IsNumeric = IsCharNumeric ( sCommandRight [ 0 ] ) | | ( sCommandRight [ 0 ] = = '-' & & IsCharNumeric ( sCommandRight [ 1 ] ) ) ;
2016-01-19 23:58:55 +01:00
if ( Mode & MODE_ALL )
State | = STATE_ALLOW ;
else if ( Mode & MODE_STRVALUE )
{
static char sValue [ 512 ] ;
Rule . GetString ( " value " , sValue , sizeof ( sValue ) ) ;
if ( strcmp ( sCommandRight , sValue ) = = 0 )
State | = STATE_ALLOW ;
}
else if ( Mode & MODE_INTVALUE )
{
int WantValue ;
int IsValue ;
Rule . GetValue ( " value " , WantValue ) ;
IsValue = StringToInt ( sCommandRight ) ;
2016-01-28 01:18:10 +01:00
if ( IsNumeric & & WantValue = = IsValue )
2016-01-19 23:58:55 +01:00
State | = STATE_ALLOW ;
}
else if ( Mode & MODE_FLOATVALUE )
{
float WantValue ;
float IsValue ;
Rule . GetValue ( " value " , WantValue ) ;
IsValue = StringToFloat ( sCommandRight ) ;
2016-01-28 01:18:10 +01:00
if ( IsNumeric & & FloatCompare ( IsValue , WantValue ) = = 0 )
2016-01-19 23:58:55 +01:00
State | = STATE_ALLOW ;
}
else if ( Mode & MODE_REGEXVALUE )
{
Regex hRegex ;
Rule . GetValue ( " value " , hRegex ) ;
if ( MatchRegex ( hRegex , sCommandRight ) > 0 )
State | = STATE_ALLOW ;
}
float MinValue ;
float MaxValue ;
float IsValue = StringToFloat ( sCommandRight ) ;
if ( ! IsNumeric & & ( Mode & MODE_MIN | | Mode & MODE_MAX ) )
continue ; // Ignore non-numerical
if ( Mode & MODE_MIN )
{
Rule . GetValue ( " minvalue " , MinValue ) ;
if ( IsValue > = MinValue )
State | = STATE_ALLOW ;
else
State | = STATE_DENY | STATE_CLAMPMIN ;
}
if ( Mode & MODE_MAX )
{
Rule . GetValue ( " maxvalue " , MaxValue ) ;
if ( IsValue < = MaxValue )
State | = STATE_ALLOW ;
else
State | = STATE_DENY | STATE_CLAMPMAX ;
}
// Reverse mode
if ( Mode & MODE_DENY & & State & STATE_ALLOW & & ! ( State & STATE_DENY ) )
{
LogMessage ( " Blocked (Deny): \" %s \" " , sOrigCommand ) ;
return Plugin_Stop ;
}
// Clamping?
// If there is no clamp rule (State == STATE_NONE) try to clamp to "clampvalue"
// aka. always clamp to "clampvalue" if there are no rules in clamp mode
if ( Mode & MODE_CLAMP & & ( State & STATE_DENY | | State = = STATE_NONE ) )
{
bool Clamp = false ;
float ClampValue ;
if ( Rule . GetValue ( " clampvalue " , ClampValue ) )
Clamp = true ;
else if ( State & STATE_CLAMPMIN )
{
ClampValue = MinValue ;
Clamp = true ;
}
else if ( State & STATE_CLAMPMAX )
{
ClampValue = MaxValue ;
Clamp = true ;
}
if ( Clamp )
{
LogMessage ( " Clamped (%f -> %f): \" %s \" " , IsValue , ClampValue , sOrigCommand ) ;
2017-05-01 12:27:00 +02:00
FormatEx ( sOrigCommand , COMMAND_SIZE , " %s %f " , sCommandLeft , ClampValue ) ;
return Plugin_Changed ;
2016-01-19 23:58:55 +01:00
}
else // Can this even happen? Yesh, dumb user. -> "clamp" {}
{
LogMessage ( " Blocked (!Clamp): \" %s \" " , sOrigCommand ) ;
return Plugin_Stop ;
}
}
else if ( Mode & MODE_CLAMP & & State & STATE_ALLOW )
{
LogMessage ( " Allowed (Clamp): \" %s \" " , sOrigCommand ) ;
return Plugin_Continue ;
}
if ( Mode & MODE_ALLOW & & State & STATE_ALLOW & & ! ( State & STATE_DENY ) )
{
LogMessage ( " Allowed (Allow): \" %s \" " , sOrigCommand ) ;
return Plugin_Continue ;
}
}
LogMessage ( " Blocked (No Match): \" %s \" " , sOrigCommand ) ;
return Plugin_Stop ;
}
void Cleanup ( )
{
if ( ! g_Rules )
return ;
for ( int i = 0 ; i < g_aRules . Length ; i + + )
{
ArrayList RuleList = g_aRules . Get ( i ) ;
CleanupRuleList ( RuleList ) ;
}
delete g_aRules ;
delete g_Rules ;
for ( int i = 0 ; i < g_Regexes . Length ; i + + )
{
Regex hRegex = g_Regexes . Get ( i ) ;
delete hRegex ;
ArrayList RuleList = g_RegexRules . Get ( i ) ;
CleanupRuleList ( RuleList ) ;
}
delete g_Regexes ;
delete g_RegexRules ;
}
void CleanupRuleList ( ArrayList RuleList )
{
for ( int j = 0 ; j < RuleList . Length ; j + + )
{
StringMap Rule = RuleList . Get ( j ) ;
int Mode ;
if ( Rule . GetValue ( " mode " , Mode ) )
{
if ( Mode & MODE_REGEXVALUE )
{
Regex hRegex ;
Rule . GetValue ( " value " , hRegex ) ;
delete hRegex ;
}
}
delete Rule ;
}
delete RuleList ;
}
void LoadConfig ( )
{
if ( g_Rules )
Cleanup ( ) ;
static char sConfigFile [ PLATFORM_MAX_PATH ] ;
2016-01-22 23:25:07 +01:00
BuildPath ( Path_SM , sConfigFile , sizeof ( sConfigFile ) , " configs/PointServerCommandFilter.cfg " ) ;
2016-01-19 23:58:55 +01:00
if ( ! FileExists ( sConfigFile ) )
SetFailState ( " Could not find config: \" %s \" " , sConfigFile ) ;
2016-01-22 23:25:07 +01:00
KeyValues Config = new KeyValues ( " PointServerCommandFilter " ) ;
2016-01-19 23:58:55 +01:00
if ( ! Config . ImportFromFile ( sConfigFile ) )
{
delete Config ;
SetFailState ( " ImportFromFile() failed! " ) ;
}
if ( ! Config . GotoFirstSubKey ( false ) )
{
delete Config ;
SetFailState ( " GotoFirstSubKey() failed! " ) ;
}
g_Rules = new StringMap ( ) ;
g_aRules = new ArrayList ( ) ;
g_Regexes = new ArrayList ( ) ;
g_RegexRules = new ArrayList ( ) ;
do
{
static char sLeft [ 128 ] ;
Config . GetSectionName ( sLeft , sizeof ( sLeft ) ) ;
StringToLower ( sLeft ) ;
int LeftLen = strlen ( sLeft ) ;
ArrayList RuleList ;
if ( sLeft [ 0 ] = = '/' & & sLeft [ LeftLen - 1 ] = = '/' )
{
sLeft [ LeftLen - 1 ] = 0 ;
Regex hRegex ;
static char sError [ 512 ] ;
hRegex = CompileRegex ( sLeft [ 1 ] , PCRE_CASELESS , sError , sizeof ( sError ) ) ;
if ( hRegex = = INVALID_HANDLE )
{
LogError ( " Regex error from %s " , sLeft ) ;
LogError ( sError ) ;
continue ;
}
else
{
RuleList = new ArrayList ( ) ;
g_Regexes . Push ( hRegex ) ;
g_RegexRules . Push ( RuleList ) ;
}
}
else if ( ! g_Rules . GetValue ( sLeft , RuleList ) )
{
RuleList = new ArrayList ( ) ;
g_Rules . SetValue ( sLeft , RuleList ) ;
g_aRules . Push ( RuleList ) ;
}
// Section
if ( Config . GotoFirstSubKey ( false ) )
{
do
{
static char sSection [ 128 ] ;
Config . GetSectionName ( sSection , sizeof ( sSection ) ) ;
int Mode = MODE_NONE ;
if ( strcmp ( sSection , " deny " , false ) = = 0 )
Mode | = MODE_DENY ;
else if ( strcmp ( sSection , " allow " , false ) = = 0 )
Mode | = MODE_ALLOW ;
else if ( strcmp ( sSection , " clamp " , false ) = = 0 )
Mode | = MODE_CLAMP ;
// Section
if ( Config . GotoFirstSubKey ( false ) )
{
StringMap Rule = new StringMap ( ) ;
int RuleMode = MODE_NONE ;
do
{
static char sKey [ 128 ] ;
Config . GetSectionName ( sKey , sizeof ( sKey ) ) ;
if ( strcmp ( sKey , " min " , false ) = = 0 )
{
float Value = Config . GetFloat ( NULL_STRING ) ;
Rule . SetValue ( " minvalue " , Value ) ;
RuleMode | = MODE_MIN ;
}
else if ( strcmp ( sKey , " max " , false ) = = 0 )
{
float Value = Config . GetFloat ( NULL_STRING ) ;
Rule . SetValue ( " maxvalue " , Value ) ;
RuleMode | = MODE_MAX ;
}
else if ( Mode & MODE_CLAMP )
{
float Value = Config . GetFloat ( NULL_STRING ) ;
Rule . SetValue ( " clampvalue " , Value ) ;
RuleMode | = MODE_CLAMP ;
}
else
{
StringMap Rule_ = new StringMap ( ) ;
if ( ParseRule ( Config , sLeft , Mode , Rule_ ) )
RuleList . Push ( Rule_ ) ;
else
delete Rule_ ;
}
} while ( Config . GotoNextKey ( false ) ) ;
Config . GoBack ( ) ;
if ( RuleMode ! = MODE_NONE )
{
Rule . SetValue ( " mode " , Mode | RuleMode ) ;
RuleList . Push ( Rule ) ;
}
else
delete Rule ;
}
else // Value
{
StringMap Rule = new StringMap ( ) ;
if ( ParseRule ( Config , sLeft , Mode , Rule ) )
RuleList . Push ( Rule ) ;
else
delete Rule ;
}
} while ( Config . GotoNextKey ( false ) ) ;
Config . GoBack ( ) ;
}
else // Value
{
StringMap Rule = new StringMap ( ) ;
if ( ParseRule ( Config , sLeft , MODE_ALLOW , Rule ) )
RuleList . Push ( Rule ) ;
else
delete Rule ;
}
} while ( Config . GotoNextKey ( false ) ) ;
delete Config ;
for ( int i = 0 ; i < g_aRules . Length ; i + + )
{
ArrayList RuleList = g_aRules . Get ( i ) ;
SortADTArrayCustom ( RuleList , SortRuleList ) ;
}
}
bool ParseRule ( KeyValues Config , const char [ ] sLeft , int Mode , StringMap Rule )
{
static char sValue [ 512 ] ;
if ( Config . GetDataType ( NULL_STRING ) = = KvData_String )
{
Config . GetString ( NULL_STRING , sValue , sizeof ( sValue ) ) ;
int ValueLen = strlen ( sValue ) ;
if ( sValue [ 0 ] = = '/' & & sValue [ ValueLen - 1 ] = = '/' )
{
sValue [ ValueLen - 1 ] = 0 ;
Regex hRegex ;
static char sError [ 512 ] ;
hRegex = CompileRegex ( sValue [ 1 ] , PCRE_CASELESS , sError , sizeof ( sError ) ) ;
if ( hRegex = = INVALID_HANDLE )
{
LogError ( " Regex error in %s from %s " , sLeft , sValue [ 1 ] ) ;
LogError ( sError ) ;
return false ;
}
else
{
Rule . SetValue ( " mode " , Mode | MODE_REGEXVALUE ) ;
Rule . SetValue ( " value " , hRegex ) ;
}
}
else
{
StringToLower ( sValue ) ;
Rule . SetValue ( " mode " , Mode | MODE_STRVALUE ) ;
Rule . SetString ( " value " , sValue ) ;
}
}
else if ( Config . GetDataType ( NULL_STRING ) = = KvData_Int )
{
int Value = Config . GetNum ( NULL_STRING ) ;
Rule . SetValue ( " mode " , Mode | MODE_INTVALUE ) ;
Rule . SetValue ( " value " , Value ) ;
}
else if ( Config . GetDataType ( NULL_STRING ) = = KvData_Float )
{
float Value = Config . GetFloat ( NULL_STRING ) ;
Rule . SetValue ( " mode " , Mode | MODE_FLOATVALUE ) ;
Rule . SetValue ( " value " , Value ) ;
}
else
Rule . SetValue ( " mode " , Mode | MODE_ALL ) ;
return true ;
}
public int SortRuleList ( int index1 , int index2 , Handle array , Handle hndl )
{
StringMap Rule1 = GetArrayCell ( array , index1 ) ;
StringMap Rule2 = GetArrayCell ( array , index2 ) ;
int Mode1 ;
int Mode2 ;
Rule1 . GetValue ( " mode " , Mode1 ) ;
Rule2 . GetValue ( " mode " , Mode2 ) ;
// Deny should be first
if ( Mode1 & MODE_DENY & & ! ( Mode2 & MODE_DENY ) )
return - 1 ;
if ( Mode2 & MODE_DENY & & ! ( Mode1 & MODE_DENY ) )
return 1 ;
// Clamp should be last
if ( Mode1 & MODE_CLAMP & & ! ( Mode2 & MODE_CLAMP ) )
return 1 ;
if ( Mode2 & MODE_CLAMP & & ! ( Mode1 & MODE_CLAMP ) )
return - 1 ;
return 0 ;
}
stock void StringToLower ( char [ ] Str )
{
for ( int i = 0 ; Str [ i ] ; i + + )
Str [ i ] = CharToLower ( Str [ i ] ) ;
}