593 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
			
		
		
	
	
			593 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			SourcePawn
		
	
	
	
	
	
| #pragma semicolon 1
 | |
| #include <sourcemod>
 | |
| #include <sdktools>
 | |
| #include <cstrike>
 | |
| #include <regex>
 | |
| #include <dhooks>
 | |
| #pragma newdecls required
 | |
| 
 | |
| #define COMMAND_SIZE 1024
 | |
| 
 | |
| // bool CBaseEntity::AcceptInput( const char *szInputName, CBaseEntity *pActivator, CBaseEntity *pCaller, variant_t Value, int outputID )
 | |
| Handle g_hAcceptInput;
 | |
| 
 | |
| 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.",
 | |
| 	version = "1.0",
 | |
| 	url = ""
 | |
| };
 | |
| 
 | |
| public void OnPluginStart()
 | |
| {
 | |
| 	Handle hGameConf = LoadGameConfigFile("sdktools.games");
 | |
| 	if(hGameConf == INVALID_HANDLE)
 | |
| 	{
 | |
| 		SetFailState("Couldn't load sdktools game config!");
 | |
| 		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");
 | |
| 	}
 | |
| 
 | |
| 	LoadConfig();
 | |
| }
 | |
| 
 | |
| 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", false))
 | |
| 		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;
 | |
| 	}
 | |
| 	else if(iAction == Plugin_Changed || GetEngineVersion() == Engine_CSGO || bReplaced)
 | |
| 	{
 | |
| 		ServerCommand(sCommand);
 | |
| 		DHookSetReturn(hReturn, true);
 | |
| 		return MRES_Supercede;
 | |
| 	}
 | |
| 
 | |
| 	return MRES_Ignored;
 | |
| }
 | |
| 
 | |
| Action PointServerCommandForward(char[] sOrigCommand)
 | |
| {
 | |
| 	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)
 | |
| 	{
 | |
| 		strcopy(sCommandLeft, sizeof(sCommandLeft), sCommandRight);
 | |
| 		Split = 0;
 | |
| 	}
 | |
| 	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;
 | |
| }
 | |
| 
 | |
| Action MatchRuleList(ArrayList RuleList, char[] sOrigCommand, const char[] sCommandLeft, const char[] sCommandRight)
 | |
| {
 | |
| 	for(int r = 0; r < RuleList.Length; r++)
 | |
| 	{
 | |
| 		int State = STATE_NONE;
 | |
| 		StringMap Rule = RuleList.Get(r);
 | |
| 		int Mode;
 | |
| 		Rule.GetValue("mode", Mode);
 | |
| 		bool IsNumeric = IsCharNumeric(sCommandRight[0]) || (sCommandRight[0] == '-' && IsCharNumeric(sCommandRight[1]));
 | |
| 
 | |
| 		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);
 | |
| 
 | |
| 			if(IsNumeric && WantValue == IsValue)
 | |
| 				State |= STATE_ALLOW;
 | |
| 		}
 | |
| 		else if(Mode & MODE_FLOATVALUE)
 | |
| 		{
 | |
| 			float WantValue;
 | |
| 			float IsValue;
 | |
| 			Rule.GetValue("value", WantValue);
 | |
| 			IsValue = StringToFloat(sCommandRight);
 | |
| 
 | |
| 			if(IsNumeric && FloatCompare(IsValue, WantValue) == 0)
 | |
| 				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);
 | |
| 				FormatEx(sOrigCommand, COMMAND_SIZE, "%s %f", sCommandLeft, ClampValue);
 | |
| 				return Plugin_Changed;
 | |
| 			}
 | |
| 			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];
 | |
| 	BuildPath(Path_SM, sConfigFile, sizeof(sConfigFile), "configs/PointServerCommandFilter.cfg");
 | |
| 	if(!FileExists(sConfigFile))
 | |
| 		SetFailState("Could not find config: \"%s\"", sConfigFile);
 | |
| 
 | |
| 	KeyValues Config = new KeyValues("PointServerCommandFilter");
 | |
| 	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]);
 | |
| }
 |