Compare commits

..
Author SHA1 Message Date
BotoX 01989d3851 Add GetClientIClient native. 2019-09-02 19:46:15 +02:00
17 changed files with 135 additions and 506 deletions
-8
View File
@@ -36,11 +36,7 @@
#if SOURCE_ENGINE >= SE_ORANGEBOX
SH_DECL_HOOK1_void(ICvar, UnregisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
#if SOURCE_ENGINE == SE_CSGO
SH_DECL_HOOK2_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *, bool);
#else
SH_DECL_HOOK1_void(ICvar, RegisterConCommand, SH_NOATTRIB, 0, ConCommandBase *);
#endif
#else
SH_DECL_HOOK1_void(ICvar, RegisterConCommandBase, SH_NOATTRIB, 0, ConCommandBase *);
#endif
@@ -82,11 +78,7 @@ public:
#endif
}
#if SOURCE_ENGINE == SE_CSGO
void LinkConCommandBase(ConCommandBase *pBase, bool unknown)
#else
void LinkConCommandBase(ConCommandBase *pBase)
#endif
{
IConCommandLinkListener *listener = IConCommandLinkListener::head;
while (listener)
+14 -28
View File
@@ -1458,23 +1458,24 @@ static cell_t IsClientInKickQueue(IPluginContext *pContext, const cell_t *params
return pPlayer->IsInKickQueue() ? 1 : 0;
}
cmd_target_info_t g_ProcessTargetString_info;
static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params)
{
pContext->LocalToString(params[1], (char **) &g_ProcessTargetString_info.pattern);
g_ProcessTargetString_info.admin = params[2];
pContext->LocalToPhysAddr(params[3], &g_ProcessTargetString_info.targets);
g_ProcessTargetString_info.max_targets = params[4];
g_ProcessTargetString_info.flags = params[5];
pContext->LocalToString(params[6], &g_ProcessTargetString_info.target_name);
g_ProcessTargetString_info.target_name_maxlength = params[7];
cmd_target_info_t info;
pContext->LocalToString(params[1], (char **) &info.pattern);
info.admin = params[2];
pContext->LocalToPhysAddr(params[3], &info.targets);
info.max_targets = params[4];
info.flags = params[5];
pContext->LocalToString(params[6], &info.target_name);
info.target_name_maxlength = params[7];
cell_t *tn_is_ml;
pContext->LocalToPhysAddr(params[8], &tn_is_ml);
playerhelpers->ProcessCommandTarget(&g_ProcessTargetString_info);
playerhelpers->ProcessCommandTarget(&info);
if (g_ProcessTargetString_info.target_name_style == COMMAND_TARGETNAME_ML)
if (info.target_name_style == COMMAND_TARGETNAME_ML)
{
*tn_is_ml = 1;
}
@@ -1483,30 +1484,16 @@ static cell_t ProcessTargetString(IPluginContext *pContext, const cell_t *params
*tn_is_ml = 0;
}
if (g_ProcessTargetString_info.num_targets == 0)
if (info.num_targets == 0)
{
return g_ProcessTargetString_info.reason;
return info.reason;
}
else
{
return g_ProcessTargetString_info.num_targets;
return info.num_targets;
}
}
static cell_t GetLastProcessTargetString(IPluginContext *pContext, const cell_t *params)
{
cell_t *admin, *flags;
pContext->StringToLocalUTF8(params[1], params[2], g_ProcessTargetString_info.pattern, NULL);
pContext->LocalToPhysAddr(params[3], &admin);
pContext->LocalToPhysAddr(params[4], &flags);
*admin = g_ProcessTargetString_info.admin;
*flags = g_ProcessTargetString_info.flags;
return 0;
}
static cell_t FormatActivitySource(IPluginContext *pContext, const cell_t *params)
{
int value;
@@ -1658,7 +1645,6 @@ REGISTER_NATIVES(playernatives)
{ "NotifyPostAdminCheck", NotifyPostAdminCheck },
{ "IsClientInKickQueue", IsClientInKickQueue },
{ "ProcessTargetString", ProcessTargetString },
{ "GetLastProcessTargetString", GetLastProcessTargetString },
{ "FormatActivitySource", FormatActivitySource },
{ "GetClientSerial", sm_GetClientSerial },
{ "GetClientFromSerial", sm_GetClientFromSerial },
-11
View File
@@ -789,16 +789,6 @@ static cell_t sm_RegAdminCmd(IPluginContext *pContext, const cell_t *params)
return 1;
}
static cell_t sm_IsCommandCallback(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
if (!pCmd)
return 0;
return 1;
}
static cell_t sm_GetCmdArgs(IPluginContext *pContext, const cell_t *params)
{
const ICommandArgs *pCmd = g_HL2.PeekCommandStack();
@@ -1477,7 +1467,6 @@ REGISTER_NATIVES(consoleNatives)
{"GetConVarDefault", GetConVarDefault},
{"RegServerCmd", sm_RegServerCmd},
{"RegConsoleCmd", sm_RegConsoleCmd},
{"IsCommandCallback", sm_IsCommandCallback},
{"GetCmdArgString", sm_GetCmdArgString},
{"GetCmdArgs", sm_GetCmdArgs},
{"GetCmdArg", sm_GetCmdArg},
+22
View File
@@ -356,6 +356,27 @@ static cell_t GetAvgPackets(IPluginContext *pContext, const cell_t *params)
return sp_ftoc(value);
}
static cell_t sm_GetClientIClient(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
if (!pPlayer)
{
return pContext->ThrowNativeError("Client index %d is invalid", client);
}
else if (!pPlayer->IsConnected())
{
return pContext->ThrowNativeError("Client %d is not connected", client);
}
else if (pPlayer->IsFakeClient())
{
return pContext->ThrowNativeError("Client %d is a bot", client);
}
return (cell_t)pPlayer->GetIClient();
}
static cell_t RunAdminCacheChecks(IPluginContext *pContext, const cell_t *params)
{
int client = params[1];
@@ -392,6 +413,7 @@ REGISTER_NATIVES(playernatives)
{"GetClientAvgChoke", GetAvgChoke},
{"GetClientAvgData", GetAvgData},
{"GetClientAvgPackets", GetAvgPackets},
{"GetClientIClient", sm_GetClientIClient },
{"RunAdminCacheChecks", RunAdminCacheChecks},
{NULL, NULL}
};
-2
View File
@@ -51,7 +51,6 @@ IGameConfig *g_pGameConf = NULL;
IGameEventManager2 *gameevents = NULL;
bool hooked_everything = false;
int g_msgHintText = -1;
CGlobalVars *gpGlobals;
SMEXT_LINK(&g_CStrike);
@@ -108,7 +107,6 @@ bool CStrike::SDK_OnMetamodLoad(ISmmAPI *ismm, char *error, size_t maxlen, bool
{
GET_V_IFACE_CURRENT(GetEngineFactory, gameevents, IGameEventManager2, INTERFACEVERSION_GAMEEVENTSMANAGER2);
GET_V_IFACE_CURRENT(GetEngineFactory, engine, IVEngineServer, INTERFACEVERSION_VENGINESERVER);
gpGlobals = ismm->GetCGlobals();
return true;
}
-1
View File
@@ -166,7 +166,6 @@ private:
extern IBinTools *g_pBinTools;
extern IGameConfig *g_pGameConf;
extern ISDKTools *g_pSDKTools;
extern CGlobalVars *gpGlobals;
extern int g_msgHintText;
extern bool g_pIgnoreTerminateDetour;
extern bool g_pIgnoreCSWeaponDropDetour;
+1 -13
View File
@@ -58,19 +58,7 @@ void TimeLeftEvents::FireGameEvent(IGameEvent *event)
if (get_new_timeleft_offset || !round_end_found)
{
get_new_timeleft_offset = false;
float flGameStartTime = gpGlobals->curtime;
uintptr_t gamerules = (uintptr_t)g_pSDKTools->GetGameRules();
if (gamerules)
{
sm_sendprop_info_t info;
if (gamehelpers->FindSendPropInfo("CCSGameRulesProxy", "m_flGameStartTime", &info))
{
flGameStartTime = *(float *)(gamerules + info.actual_offset);
}
}
timersys->NotifyOfGameStart(flGameStartTime - gpGlobals->curtime);
timersys->NotifyOfGameStart();
timersys->MapTimeLeftChanged();
}
round_end_found = false;
+1 -2
View File
@@ -24,8 +24,7 @@ files = [
'basecommands.sp',
'mapchooser.sp',
'randomcycle.sp',
'sql-admin-manager.sp',
'DynamicTargeting.sp'
'sql-admin-manager.sp'
]
spcomp_argv = [
-266
View File
@@ -1,266 +0,0 @@
#pragma semicolon 1
#define PLUGIN_VERSION "1.0"
#include <sourcemod>
#include <DynamicTargeting>
#pragma newdecls required
public Plugin myinfo =
{
name = "Dynamic Targeting",
author = "BotoX",
description = "",
version = PLUGIN_VERSION,
url = ""
}
char g_PlayerNames[MAXPLAYERS + 1][MAX_NAME_LENGTH];
Handle g_PlayerData[MAXPLAYERS + 1];
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("AmbiguousMenu", Native_AmbiguousMenu);
RegPluginLibrary("DynamicTargeting");
return APLRes_Success;
}
public void OnClientDisconnect(int client)
{
if(g_PlayerData[client] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[client]);
g_PlayerData[client] = INVALID_HANDLE;
}
}
int CreateAmbiguousMenu(int client, const char[] sCommand, const char[] sArgString, const char[] sPattern, int FilterFlags)
{
Menu menu = new Menu(MenuHandler_AmbiguousMenu, MenuAction_Select|MenuAction_Cancel|MenuAction_End|MenuAction_DrawItem|MenuAction_DisplayItem);
menu.ExitButton = true;
char sTitle[32 + MAX_TARGET_LENGTH];
FormatEx(sTitle, sizeof(sTitle), "Target \"%s\" is ambiguous.", sPattern);
menu.SetTitle(sTitle);
int Players = 0;
int[] aClients = new int[MaxClients + 1];
for(int i = 1; i <= MaxClients; i++)
{
if(!IsClientConnected(i) || i == client)
continue;
if(FilterFlags & COMMAND_FILTER_NO_BOTS && IsFakeClient(i))
continue;
if(!(FilterFlags & COMMAND_FILTER_CONNECTED) && !IsClientInGame(i))
continue;
if(FilterFlags & COMMAND_FILTER_ALIVE && !IsPlayerAlive(i))
continue;
if(FilterFlags & COMMAND_FILTER_DEAD && IsPlayerAlive(i))
continue;
// insert player names into g_PlayerNames array
GetClientName(i, g_PlayerNames[i], sizeof(g_PlayerNames[]));
if(StrContains(g_PlayerNames[i], sPattern, false) != -1)
aClients[Players++] = i;
}
// sort aClients array by player name
SortCustom1D(aClients, Players, SortByPlayerName);
// insert players sorted
char sUserId[12];
char sDisp[MAX_NAME_LENGTH + 16];
for(int i = 0; i < Players; i++)
{
IntToString(GetClientUserId(aClients[i]), sUserId, sizeof(sUserId));
FormatEx(sDisp, sizeof(sDisp), "%s (%s)", g_PlayerNames[aClients[i]], sUserId);
menu.AddItem(sUserId, sDisp);
}
DataPack pack = new DataPack();
pack.WriteString(sCommand);
pack.WriteString(sArgString);
pack.WriteString(sPattern);
pack.WriteCell(FilterFlags);
if(g_PlayerData[client] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[client]);
g_PlayerData[client] = INVALID_HANDLE;
}
CancelClientMenu(client);
g_PlayerData[client] = pack;
menu.Display(client, MENU_TIME_FOREVER);
return 0;
}
public int MenuHandler_AmbiguousMenu(Menu menu, MenuAction action, int param1, int param2)
{
switch(action)
{
case MenuAction_End:
{
CloseHandle(menu);
}
case MenuAction_Cancel:
{
if(g_PlayerData[param1] != INVALID_HANDLE)
{
CloseHandle(g_PlayerData[param1]);
g_PlayerData[param1] = INVALID_HANDLE;
}
}
case MenuAction_Select:
{
int Style;
char sItem[32];
char sDisp[MAX_NAME_LENGTH + 16];
menu.GetItem(param2, sItem, sizeof(sItem), Style, sDisp, sizeof(sDisp));
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client)
{
PrintToChat(param1, "\x04[DynamicTargeting]\x01 Player no longer available.");
menu.DisplayAt(param1, GetMenuSelectionPosition(), MENU_TIME_FOREVER);
return 0;
}
DataPack pack = view_as<DataPack>(g_PlayerData[param1]);
pack.Reset();
char sCommand[128];
pack.ReadString(sCommand, sizeof(sCommand));
char sArgString[256];
pack.ReadString(sArgString, sizeof(sArgString));
char sPattern[MAX_TARGET_LENGTH];
pack.ReadString(sPattern, sizeof(sPattern));
int Result = ReCallAmbiguous(param1, client, sCommand, sArgString, sPattern);
return Result;
}
case MenuAction_DrawItem:
{
int Style;
char sItem[32];
menu.GetItem(param2, sItem, sizeof(sItem), Style);
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client) // Player disconnected
return ITEMDRAW_DISABLED;
return Style;
}
case MenuAction_DisplayItem:
{
int Style;
char sItem[32];
char sDisp[MAX_NAME_LENGTH + 16];
menu.GetItem(param2, sItem, sizeof(sItem), Style, sDisp, sizeof(sDisp));
if(!sItem[0])
return 0;
char sBuffer[MAX_NAME_LENGTH + 16];
int UserId = StringToInt(sItem);
int client = GetClientOfUserId(UserId);
if(!client) // Player disconnected
return 0;
GetClientName(client, g_PlayerNames[client], sizeof(g_PlayerNames[]));
FormatEx(sBuffer, sizeof(sBuffer), "%s (%d)", g_PlayerNames[client], UserId);
if(!StrEqual(sDisp, sBuffer))
return RedrawMenuItem(sBuffer);
return 0;
}
}
return 0;
}
int ReCallAmbiguous(int client, int newClient, const char[] sCommand, const char[] sArgString, const char[] sPattern)
{
char sTarget[16];
FormatEx(sTarget, sizeof(sTarget), "#%d", GetClientUserId(newClient));
char sNewArgString[256];
strcopy(sNewArgString, sizeof(sNewArgString), sArgString);
char sPart[256];
int CurrentIndex = 0;
int NextIndex = 0;
while(NextIndex != -1 && CurrentIndex < sizeof(sNewArgString))
{
NextIndex = BreakString(sNewArgString[CurrentIndex], sPart, sizeof(sPart));
if(StrEqual(sPart, sPattern))
{
ReplaceStringEx(sNewArgString[CurrentIndex], sizeof(sNewArgString) - CurrentIndex, sPart, sTarget);
break;
}
CurrentIndex += NextIndex;
}
FakeClientCommandEx(client, "%s %s", sCommand, sNewArgString);
return 0;
}
public int Native_AmbiguousMenu(Handle plugin, int numParams)
{
int client = GetNativeCell(1);
if(client > MaxClients || client <= 0)
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is not valid.");
return -1;
}
if(!IsClientInGame(client))
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is not in-game.");
return -1;
}
if(IsFakeClient(client))
{
ThrowNativeError(SP_ERROR_NATIVE, "Client is fake-client.");
return -1;
}
char sCommand[128];
GetNativeString(2, sCommand, sizeof(sCommand));
char sArgString[256];
GetNativeString(3, sArgString, sizeof(sArgString));
char sPattern[MAX_TARGET_LENGTH];
GetNativeString(4, sPattern, sizeof(sPattern));
int FilterFlags = GetNativeCell(5);
return CreateAmbiguousMenu(client, sCommand, sArgString, sPattern, FilterFlags);
}
public int SortByPlayerName(int elem1, int elem2, const int[] array, Handle hndl)
{
return strcmp(g_PlayerNames[elem1], g_PlayerNames[elem2], false);
}
-24
View File
@@ -1,24 +0,0 @@
#if defined _DynamicTargeting_Included
#endinput
#endif
#define _DynamicTargeting_Included
native int AmbiguousMenu(int client, char[] sCommand, char[] sArgString, char[] sPattern, int FilterFlags);
public SharedPlugin __pl_DynamicTargeting =
{
name = "DynamicTargeting",
file = "DynamicTargeting.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public __pl_DynamicTargeting_SetNTVOptional()
{
MarkNativeAsOptional("AmbiguousMenu");
}
#endif
+9
View File
@@ -741,6 +741,15 @@ native float GetClientAvgData(int client, NetFlow flow);
*/
native float GetClientAvgPackets(int client, NetFlow flow);
/**
* Returns the client's baseserver IClient pointer.
*
* @param client Player's index.
* @return IClient address.
* @error Invalid client index, client not connected, or fake client.
*/
native Address GetClientIClient(int client);
/**
* Translates an userid index to the real player index.
*
+1 -48
View File
@@ -84,25 +84,6 @@ native int ProcessTargetString(const char[] pattern,
int tn_maxlength,
bool &tn_is_ml);
/**
* Retrieves arguments that were passed to the last ProcessTargetString call.
*
* @param pattern Buffer to store the pattern.
* @param p_maxlen Maximum length of the pattern buffer.
* @param admin OUTPUT: Admin performing the action, or 0 if the server.
* @param filter_flags OUTPUT: Filter flags.
* @noreturn
*/
native void GetLastProcessTargetString(char[] pattern,
int p_maxlen,
int &admin,
int &filter_flags);
#undef REQUIRE_PLUGIN
#include <DynamicTargeting>
#define REQUIRE_PLUGIN
/**
* Replies to a client with a given message describing a targetting
* failure reason.
@@ -112,7 +93,7 @@ native void GetLastProcessTargetString(char[] pattern,
* @param client Client index, or 0 for server.
* @param reason COMMAND_TARGET reason.
*/
stock void ReplyToTargetError(int client, int reason, bool dynamic=true)
stock void ReplyToTargetError(int client, int reason)
{
switch (reason)
{
@@ -147,34 +128,6 @@ stock void ReplyToTargetError(int client, int reason, bool dynamic=true)
case COMMAND_TARGET_AMBIGUOUS:
{
ReplyToCommand(client, "[SM] %t", "More than one client matched");
if(dynamic &&
GetFeatureStatus(FeatureType_Native, "GetLastProcessTargetString") == FeatureStatus_Available &&
LibraryExists("DynamicTargeting"))
{
if(GetFeatureStatus(FeatureType_Native, "IsCommandCallback") == FeatureStatus_Available &&
!IsCommandCallback())
{
return;
}
char sCommand[128];
GetCmdArg(0, sCommand, sizeof(sCommand));
char sArgString[256];
GetCmdArgString(sArgString, sizeof(sArgString));
char pattern[MAX_TARGET_LENGTH];
int admin;
int filter_flags;
GetLastProcessTargetString(pattern, sizeof(pattern), admin, filter_flags);
if(!admin || !IsClientInGame(admin) || IsFakeClient(admin))
return;
AmbiguousMenu(admin, sCommand, sArgString, pattern, filter_flags);
}
}
}
}
+1 -8
View File
@@ -402,14 +402,7 @@ native void RegAdminCmd(const char[] cmd,
const char[] description="",
const char[] group="",
int flags=0);
/**
* Returns whether there is a command callback available.
*
* @return True if called from inside a command callback.
*/
native bool IsCommandCallback();
/**
* Returns the number of arguments from the current console or server command.
* @note Unlike the HL2 engine call, this does not include the command itself.
-3
View File
@@ -311,9 +311,6 @@ public void __ext_core_SetNTVOptional()
MarkNativeAsOptional("Protobuf.ReadRepeatedMessage");
MarkNativeAsOptional("Protobuf.AddMessage");
MarkNativeAsOptional("IsCommandCallback");
MarkNativeAsOptional("GetLastProcessTargetString");
VerifyCoreVersion();
}
+1 -4
View File
@@ -615,10 +615,7 @@ native int FormatNativeString(int out_param,
*
* @param data Data passed to the RequestFrame native.
*/
typeset RequestFrameCallback {
function void ();
function void (any data);
}
typedef RequestFrameCallback = function void (any data);
/**
* Creates a single use Next Frame hook.
+85 -86
View File
@@ -47,92 +47,6 @@ struct Plugin
public const char[] url; /**< Plugin URL */
};
/**
* Returns whether a library exists. This function should be considered
* expensive; it should only be called on plugin to determine availability
* of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes
* in optional resources.
*
* @param name Library name of a plugin or extension.
* @return True if exists, false otherwise.
*/
native bool LibraryExists(const char[] name);
/**
* Feature types.
*/
enum FeatureType
{
/**
* A native function call.
*/
FeatureType_Native,
/**
* A named capability. This is distinctly different from checking for a
* native, because the underlying functionality could be enabled on-demand
* to improve loading time. Thus a native may appear to exist, but it might
* be part of a set of features that are not compatible with the current game
* or version of SourceMod.
*/
FeatureType_Capability
};
/**
* Feature statuses.
*/
enum FeatureStatus
{
/**
* Feature is available for use.
*/
FeatureStatus_Available,
/**
* Feature is not available.
*/
FeatureStatus_Unavailable,
/**
* Feature is not known at all.
*/
FeatureStatus_Unknown
};
/**
* Returns whether "GetFeatureStatus" will work. Using this native
* or this function will not cause SourceMod to fail loading on older versions,
* however, GetFeatureStatus will only work if this function returns true.
*
* @return True if GetFeatureStatus will work, false otherwise.
*/
stock bool CanTestFeatures()
{
return LibraryExists("__CanTestFeatures__");
}
/**
* Returns whether a feature exists, and if so, whether it is usable.
*
* @param type Feature type.
* @param name Feature name.
* @return Feature status.
*/
native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name);
/**
* Requires that a given feature is available. If it is not, SetFailState()
* is called with the given message.
*
* @param type Feature type.
* @param name Feature name.
* @param fmt Message format string, or empty to use default.
* @param ... Message format parameters, if any.
*/
native void RequireFeature(FeatureType type, const char[] name,
const char[] fmt="", any ...);
#include <core>
#include <float>
#include <vector>
@@ -534,6 +448,17 @@ native void AutoExecConfig(bool autoCreate=true, const char[] name="", const cha
*/
native void RegPluginLibrary(const char[] name);
/**
* Returns whether a library exists. This function should be considered
* expensive; it should only be called on plugin to determine availability
* of resources. Use OnLibraryAdded()/OnLibraryRemoved() to detect changes
* in optional resources.
*
* @param name Library name of a plugin or extension.
* @return True if exists, false otherwise.
*/
native bool LibraryExists(const char[] name);
/**
* Returns the status of an extension, by filename.
*
@@ -657,6 +582,80 @@ forward bool OnClientFloodCheck(int client);
*/
forward void OnClientFloodResult(int client, bool blocked);
/**
* Feature types.
*/
enum FeatureType
{
/**
* A native function call.
*/
FeatureType_Native,
/**
* A named capability. This is distinctly different from checking for a
* native, because the underlying functionality could be enabled on-demand
* to improve loading time. Thus a native may appear to exist, but it might
* be part of a set of features that are not compatible with the current game
* or version of SourceMod.
*/
FeatureType_Capability
};
/**
* Feature statuses.
*/
enum FeatureStatus
{
/**
* Feature is available for use.
*/
FeatureStatus_Available,
/**
* Feature is not available.
*/
FeatureStatus_Unavailable,
/**
* Feature is not known at all.
*/
FeatureStatus_Unknown
};
/**
* Returns whether "GetFeatureStatus" will work. Using this native
* or this function will not cause SourceMod to fail loading on older versions,
* however, GetFeatureStatus will only work if this function returns true.
*
* @return True if GetFeatureStatus will work, false otherwise.
*/
stock bool CanTestFeatures()
{
return LibraryExists("__CanTestFeatures__");
}
/**
* Returns whether a feature exists, and if so, whether it is usable.
*
* @param type Feature type.
* @param name Feature name.
* @return Feature status.
*/
native FeatureStatus GetFeatureStatus(FeatureType type, const char[] name);
/**
* Requires that a given feature is available. If it is not, SetFailState()
* is called with the given message.
*
* @param type Feature type.
* @param name Feature name.
* @param fmt Message format string, or empty to use default.
* @param ... Message format parameters, if any.
*/
native void RequireFeature(FeatureType type, const char[] name,
const char[] fmt="", any ...);
/**
* Represents how many bytes we can read from an address with one load
*/
-2
View File
@@ -324,7 +324,6 @@ CopyFiles('plugins', 'addons/sourcemod/scripting',
'rockthevote.sp',
'sounds.sp',
'sql-admin-manager.sp',
'DynamicTargeting.sp',
]
)
CopyFiles('plugins/include', 'addons/sourcemod/scripting/include',
@@ -395,7 +394,6 @@ CopyFiles('plugins/include', 'addons/sourcemod/scripting/include',
'usermessages.inc',
'vector.inc',
'version.inc',
'DynamicTargeting.inc',
]
)
CopyFiles('translations', 'addons/sourcemod/translations',