added experimental PointServerCommandFilter plugin
This commit is contained in:
parent
459815ce0e
commit
c532a321fa
74
PointServerCommandFilter/configs/PointDetour.cfg
Normal file
74
PointServerCommandFilter/configs/PointDetour.cfg
Normal file
@ -0,0 +1,74 @@
|
||||
// Example config to showcase features
|
||||
// This is a whitelist
|
||||
"PointDetour"
|
||||
{
|
||||
// Allow all
|
||||
"say" {}
|
||||
"exec" {}
|
||||
|
||||
// Allow "1"
|
||||
mp_restartgame "1"
|
||||
|
||||
// Regex: Allow all cvars/commands that start with mp_
|
||||
"/mp_.*/" {}
|
||||
|
||||
// Allow regex as paramter
|
||||
"echo" "/DEBUG:.*/"
|
||||
|
||||
// Allow anything but
|
||||
"sm"
|
||||
{
|
||||
"allow" {}
|
||||
"deny"
|
||||
{
|
||||
"value" "/plugins unload/"
|
||||
}
|
||||
}
|
||||
|
||||
// Allow the following
|
||||
"sm"
|
||||
{
|
||||
"allow"
|
||||
{
|
||||
"value" "/plugins unload/"
|
||||
"value" "/plugins load/"
|
||||
}
|
||||
}
|
||||
// also like this
|
||||
"sm"
|
||||
{
|
||||
"allow" "/plugins unload/"
|
||||
"allow" "/plugins load/"
|
||||
}
|
||||
|
||||
// Only allow values between (including) 100 and 1000
|
||||
"sv_gravity"
|
||||
{
|
||||
"allow"
|
||||
{
|
||||
"min" "100"
|
||||
"max" "1000"
|
||||
}
|
||||
}
|
||||
|
||||
// Only allow values between 0 and 6,
|
||||
// clamping if parmeter is outside of this range
|
||||
// Example: 10 becomes 6 | -1 becomes 0
|
||||
"mp_freezetime"
|
||||
{
|
||||
"clamp"
|
||||
{
|
||||
"min" "0"
|
||||
"max" "6"
|
||||
}
|
||||
}
|
||||
|
||||
// Override since clamp has no paramters
|
||||
"mp_restartgame"
|
||||
{
|
||||
"clamp"
|
||||
{
|
||||
"value" "1"
|
||||
}
|
||||
}
|
||||
}
|
493
PointServerCommandFilter/scripting/PointServerCommandFilter.sp
Normal file
493
PointServerCommandFilter/scripting/PointServerCommandFilter.sp
Normal file
@ -0,0 +1,493 @@
|
||||
#pragma semicolon 1
|
||||
#include <sourcemod>
|
||||
#include <regex>
|
||||
#include <pscd>
|
||||
#pragma newdecls required
|
||||
|
||||
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 = "0.1",
|
||||
url = ""
|
||||
};
|
||||
|
||||
public void OnPluginStart()
|
||||
{
|
||||
LoadConfig();
|
||||
}
|
||||
|
||||
public Action PointServerCommandForward(const 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);
|
||||
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, const 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);
|
||||
|
||||
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(IsCharNumeric(sCommandRight[0]) && WantValue == IsValue)
|
||||
State |= STATE_ALLOW;
|
||||
}
|
||||
else if(Mode & MODE_FLOATVALUE)
|
||||
{
|
||||
float WantValue;
|
||||
float IsValue;
|
||||
Rule.GetValue("value", WantValue);
|
||||
IsValue = StringToFloat(sCommandRight);
|
||||
|
||||
if(IsCharNumeric(sCommandRight[0]) && 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);
|
||||
bool IsNumeric = IsCharNumeric(sCommandRight[0]);
|
||||
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);
|
||||
ServerCommand("%s %f", sCommandLeft, ClampValue);
|
||||
return Plugin_Stop;
|
||||
}
|
||||
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/PointDetour.cfg");
|
||||
if(!FileExists(sConfigFile))
|
||||
SetFailState("Could not find config: \"%s\"", sConfigFile);
|
||||
|
||||
KeyValues Config = new KeyValues("PointDetour");
|
||||
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]);
|
||||
}
|
1
PointServerCommandFilter/scripting/include/pscd.inc
Symbolic link
1
PointServerCommandFilter/scripting/include/pscd.inc
Symbolic link
@ -0,0 +1 @@
|
||||
../../../includes/pscd.inc
|
67
includes/pscd.inc
Normal file
67
includes/pscd.inc
Normal file
@ -0,0 +1,67 @@
|
||||
/**
|
||||
* vim: set ts=4 :
|
||||
* =============================================================================
|
||||
* SourceMod (C)2004-2012 AlliedModders LLC. All rights reserved.
|
||||
* =============================================================================
|
||||
*
|
||||
* This file is part of the SourceMod/SourcePawn SDK.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License, version 3.0, as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||
* details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* As a special exception, AlliedModders LLC gives you permission to link the
|
||||
* code of this program (as well as its derivative works) to "Half-Life 2," the
|
||||
* "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
|
||||
* by the Valve Corporation. You must obey the GNU General Public License in
|
||||
* all respects for all other code used. Additionally, AlliedModders LLC grants
|
||||
* this exception to all derivative works. AlliedModders LLC defines further
|
||||
* exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
|
||||
* or <http://www.sourcemod.net/license.php>.
|
||||
*
|
||||
* Version: $Id$
|
||||
*/
|
||||
|
||||
#if defined _pscd_included
|
||||
#endinput
|
||||
#endif
|
||||
#define _pscd_included
|
||||
|
||||
/* Sets an objects vector variable value
|
||||
*
|
||||
* @param sCommand Command attempting to be run.
|
||||
* @return Return > Plugin_Continue to block, otherwise the command is executed.
|
||||
*
|
||||
*/
|
||||
|
||||
forward Action PointServerCommandForward(const char[] sCommand);
|
||||
|
||||
public Extension:__ext_PointDetour =
|
||||
{
|
||||
name = "PointDetour",
|
||||
file = "PointDetour.ext",
|
||||
#if defined AUTOLOAD_EXTENSIONS
|
||||
autoload = 1,
|
||||
#else
|
||||
autoload = 0,
|
||||
#endif
|
||||
#if defined REQUIRE_EXTENSIONS
|
||||
required = 1,
|
||||
#else
|
||||
required = 0,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if !defined REQUIRE_EXTENSIONS
|
||||
public __ext_dhooks_SetNTVOptional()
|
||||
{
|
||||
}
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user