Added feature testing functionality (bug 4021, r=pred).
This commit is contained in:
parent
084dd1c8dd
commit
2698ff1a04
@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* On SourceHook v4.3 or lower, there are no DVP hooks. Very sad, right?
|
* On SourceHook v4.3 or lower, there are no DVP hooks. Very sad, right?
|
||||||
* Only do this on newer version. For the older code, we'll do an incredibly
|
* Only do this on newer versions. For the older code, we'll do an incredibly
|
||||||
* hacky detour.
|
* hacky detour.
|
||||||
*
|
*
|
||||||
* The idea of the "non-hacky" (yeah... no) code is that every unique
|
* The idea of the "non-hacky" (yeah... no) code is that every unique
|
||||||
@ -49,6 +49,7 @@
|
|||||||
#include "ConCmdManager.h"
|
#include "ConCmdManager.h"
|
||||||
#include "HalfLife2.h"
|
#include "HalfLife2.h"
|
||||||
#include "ConCommandBaseIterator.h"
|
#include "ConCommandBaseIterator.h"
|
||||||
|
#include "ShareSys.h"
|
||||||
|
|
||||||
#if defined PLATFORM_LINUX
|
#if defined PLATFORM_LINUX
|
||||||
# include <dlfcn.h>
|
# include <dlfcn.h>
|
||||||
@ -531,10 +532,12 @@ void DummyHook()
|
|||||||
* BEGIN THE ACTUALLY GENERIC CODE.
|
* BEGIN THE ACTUALLY GENERIC CODE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define FEATURECAP_COMMANDLISTENER "command listener"
|
||||||
|
|
||||||
static GenericCommandHooker s_GenericHooker;
|
static GenericCommandHooker s_GenericHooker;
|
||||||
ConsoleDetours g_ConsoleDetours;
|
ConsoleDetours g_ConsoleDetours;
|
||||||
|
|
||||||
ConsoleDetours::ConsoleDetours() : triedToEnable(false), isEnabled(false)
|
ConsoleDetours::ConsoleDetours() : status(FeatureStatus_Unknown)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -542,6 +545,7 @@ void ConsoleDetours::OnSourceModAllInitialized()
|
|||||||
{
|
{
|
||||||
m_pForward = g_Forwards.CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
|
m_pForward = g_Forwards.CreateForwardEx("OnAnyCommand", ET_Hook, 3, NULL, Param_Cell,
|
||||||
Param_String, Param_Cell);
|
Param_String, Param_Cell);
|
||||||
|
g_ShareSys.AddCapabilityProvider(NULL, this, FEATURECAP_COMMANDLISTENER);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleDetours::OnSourceModShutdown()
|
void ConsoleDetours::OnSourceModShutdown()
|
||||||
@ -559,18 +563,23 @@ void ConsoleDetours::OnSourceModShutdown()
|
|||||||
s_GenericHooker.Disable();
|
s_GenericHooker.Disable();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleDetours::IsAvailable()
|
FeatureStatus ConsoleDetours::GetFeatureStatus(FeatureType type, const char *name)
|
||||||
{
|
{
|
||||||
if (triedToEnable)
|
return GetStatus();
|
||||||
return isEnabled;
|
}
|
||||||
isEnabled = s_GenericHooker.Enable();
|
|
||||||
triedToEnable = true;
|
FeatureStatus ConsoleDetours::GetStatus()
|
||||||
return isEnabled;
|
{
|
||||||
|
if (status == FeatureStatus_Unknown)
|
||||||
|
{
|
||||||
|
status = s_GenericHooker.Enable() ? FeatureStatus_Available : FeatureStatus_Unavailable;
|
||||||
|
}
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
bool ConsoleDetours::AddListener(IPluginFunction *fun, const char *command)
|
||||||
{
|
{
|
||||||
if (!IsAvailable())
|
if (GetStatus() != FeatureStatus_Available)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (command == NULL)
|
if (command == NULL)
|
||||||
|
@ -36,7 +36,9 @@
|
|||||||
#include "ForwardSys.h"
|
#include "ForwardSys.h"
|
||||||
#include <sm_trie_tpl.h>
|
#include <sm_trie_tpl.h>
|
||||||
|
|
||||||
class ConsoleDetours : public SMGlobalClass
|
class ConsoleDetours :
|
||||||
|
public SMGlobalClass,
|
||||||
|
public IFeatureProvider
|
||||||
{
|
{
|
||||||
friend class PlayerManager;
|
friend class PlayerManager;
|
||||||
friend class GenericCommandHooker;
|
friend class GenericCommandHooker;
|
||||||
@ -50,6 +52,8 @@ public:
|
|||||||
public: //SMGlobalClass
|
public: //SMGlobalClass
|
||||||
void OnSourceModAllInitialized();
|
void OnSourceModAllInitialized();
|
||||||
void OnSourceModShutdown();
|
void OnSourceModShutdown();
|
||||||
|
public: //IFeatureProvider
|
||||||
|
FeatureStatus GetFeatureStatus(FeatureType type, const char *name);
|
||||||
public:
|
public:
|
||||||
bool AddListener(IPluginFunction *fun, const char *command);
|
bool AddListener(IPluginFunction *fun, const char *command);
|
||||||
bool RemoveListener(IPluginFunction *fun, const char *command);
|
bool RemoveListener(IPluginFunction *fun, const char *command);
|
||||||
@ -60,15 +64,14 @@ private:
|
|||||||
#else
|
#else
|
||||||
static cell_t Dispatch(ConCommand *pBase);
|
static cell_t Dispatch(ConCommand *pBase);
|
||||||
#endif
|
#endif
|
||||||
bool IsAvailable();
|
|
||||||
public:
|
public:
|
||||||
inline bool IsEnabled()
|
FeatureStatus GetStatus();
|
||||||
|
bool IsEnabled()
|
||||||
{
|
{
|
||||||
return isEnabled;
|
return status == FeatureStatus_Available;
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
bool triedToEnable;
|
FeatureStatus status;
|
||||||
bool isEnabled;
|
|
||||||
IChangeableForward *m_pForward;
|
IChangeableForward *m_pForward;
|
||||||
KTrie<Listener*> m_CmdLookup;
|
KTrie<Listener*> m_CmdLookup;
|
||||||
List<Listener*> m_Listeners;
|
List<Listener*> m_Listeners;
|
||||||
|
@ -527,3 +527,85 @@ NativeEntry *ShareSystem::AddFakeNative(IPluginFunction *pFunc, const char *name
|
|||||||
|
|
||||||
return pEntry;
|
return pEntry;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ShareSystem::AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
if (m_caps.retrieve(name) != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Capability cap;
|
||||||
|
cap.ext = myself;
|
||||||
|
cap.provider = provider;
|
||||||
|
|
||||||
|
m_caps.insert(name, cap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShareSystem::DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
Capability *pCap = m_caps.retrieve(name);
|
||||||
|
if (pCap == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pCap->ext != myself || pCap->provider != provider)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_caps.remove(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureStatus ShareSystem::TestFeature(IPluginRuntime *pRuntime, FeatureType feature,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
switch (feature)
|
||||||
|
{
|
||||||
|
case FeatureType_Native:
|
||||||
|
return TestNative(pRuntime, name);
|
||||||
|
case FeatureType_Capability:
|
||||||
|
return TestCap(name);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FeatureStatus_Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureStatus ShareSystem::TestNative(IPluginRuntime *pRuntime, const char *name)
|
||||||
|
{
|
||||||
|
uint32_t index;
|
||||||
|
|
||||||
|
if (pRuntime->FindNativeByName(name, &index) == SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
sp_native_t *native;
|
||||||
|
if (pRuntime->GetNativeByIndex(index, &native) == SP_ERROR_NONE)
|
||||||
|
{
|
||||||
|
if (native->status == SP_NATIVE_BOUND)
|
||||||
|
return FeatureStatus_Available;
|
||||||
|
else
|
||||||
|
return FeatureStatus_Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeEntry *entry = FindNative(name);
|
||||||
|
if (entry == NULL)
|
||||||
|
return FeatureStatus_Unknown;
|
||||||
|
|
||||||
|
if ((entry->replacement.owner != NULL || entry->owner != NULL) &&
|
||||||
|
(entry->replacement.func != NULL || entry->func != NULL))
|
||||||
|
{
|
||||||
|
return FeatureStatus_Available;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return FeatureStatus_Unavailable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FeatureStatus ShareSystem::TestCap(const char *name)
|
||||||
|
{
|
||||||
|
Capability *cap = m_caps.retrieve(name);
|
||||||
|
if (cap == NULL)
|
||||||
|
return FeatureStatus_Unknown;
|
||||||
|
|
||||||
|
return cap->provider->GetFeatureStatus(FeatureType_Capability, name);
|
||||||
|
}
|
||||||
|
@ -87,7 +87,13 @@ struct NativeEntry
|
|||||||
FakeNative *fake;
|
FakeNative *fake;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ShareSystem :
|
struct Capability
|
||||||
|
{
|
||||||
|
IExtension *ext;
|
||||||
|
IFeatureProvider *provider;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ShareSystem :
|
||||||
public IShareSys,
|
public IShareSys,
|
||||||
public SMGlobalClass,
|
public SMGlobalClass,
|
||||||
public IHandleTypeDispatch
|
public IHandleTypeDispatch
|
||||||
@ -110,6 +116,10 @@ public: //IShareSys
|
|||||||
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
void AddDependency(IExtension *myself, const char *filename, bool require, bool autoload);
|
||||||
void RegisterLibrary(IExtension *myself, const char *name);
|
void RegisterLibrary(IExtension *myself, const char *name);
|
||||||
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives);
|
||||||
|
void AddCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||||
|
const char *name);
|
||||||
|
void DropCapabilityProvider(IExtension *myself, IFeatureProvider *provider,
|
||||||
|
const char *name);
|
||||||
public: //SMGlobalClass
|
public: //SMGlobalClass
|
||||||
/* Pre-empt in case anything tries to register idents early */
|
/* Pre-empt in case anything tries to register idents early */
|
||||||
void Initialize();
|
void Initialize();
|
||||||
@ -119,6 +129,9 @@ public: //IHandleTypeDispatch
|
|||||||
public:
|
public:
|
||||||
IdentityToken_t *CreateCoreIdentity();
|
IdentityToken_t *CreateCoreIdentity();
|
||||||
void RemoveInterfaces(IExtension *pExtension);
|
void RemoveInterfaces(IExtension *pExtension);
|
||||||
|
FeatureStatus TestFeature(IPluginRuntime *pRuntime, FeatureType feature, const char *name);
|
||||||
|
FeatureStatus TestNative(IPluginRuntime *pRuntime, const char *name);
|
||||||
|
FeatureStatus TestCap(const char *name);
|
||||||
public:
|
public:
|
||||||
inline IdentityToken_t *GetIdentRoot()
|
inline IdentityToken_t *GetIdentRoot()
|
||||||
{
|
{
|
||||||
@ -143,6 +156,7 @@ private:
|
|||||||
HandleType_t m_IfaceType;
|
HandleType_t m_IfaceType;
|
||||||
IdentityType_t m_CoreType;
|
IdentityType_t m_CoreType;
|
||||||
KTrie<NativeEntry *> m_NtvCache;
|
KTrie<NativeEntry *> m_NtvCache;
|
||||||
|
KTrie<Capability> m_caps;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern ShareSystem g_ShareSys;
|
extern ShareSystem g_ShareSys;
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include "ForwardSys.h"
|
#include "ForwardSys.h"
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "ExtensionSys.h"
|
#include "ExtensionSys.h"
|
||||||
|
#include <sm_trie_tpl.h>
|
||||||
|
|
||||||
#if defined PLATFORM_WINDOWS
|
#if defined PLATFORM_WINDOWS
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -491,6 +492,11 @@ static cell_t LibraryExists(IPluginContext *pContext, const cell_t *params)
|
|||||||
char *str;
|
char *str;
|
||||||
pContext->LocalToString(params[1], &str);
|
pContext->LocalToString(params[1], &str);
|
||||||
|
|
||||||
|
if (strcmp(str, "__CanTestFeatures__") == 0)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (g_PluginSys.LibraryExists(str))
|
if (g_PluginSys.LibraryExists(str))
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
@ -630,6 +636,43 @@ static cell_t VerifyCoreVersion(IPluginContext *pContext, const cell_t *params)
|
|||||||
return 4;
|
return 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static cell_t GetFeatureStatus(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
FeatureType type = (FeatureType)params[1];
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
pContext->LocalToString(params[2], &name);
|
||||||
|
|
||||||
|
return g_ShareSys.TestFeature(pContext->GetRuntime(),type, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static cell_t RequireFeature(IPluginContext *pContext, const cell_t *params)
|
||||||
|
{
|
||||||
|
FeatureType type = (FeatureType)params[1];
|
||||||
|
char *name;
|
||||||
|
|
||||||
|
pContext->LocalToString(params[2], &name);
|
||||||
|
|
||||||
|
if (g_ShareSys.TestFeature(pContext->GetRuntime(),type, name) != FeatureStatus_Available)
|
||||||
|
{
|
||||||
|
char buffer[255];
|
||||||
|
char *msg = buffer;
|
||||||
|
char default_message[255];
|
||||||
|
CPlugin *pPlugin = g_PluginSys.GetPluginByCtx(pContext->GetContext());
|
||||||
|
|
||||||
|
g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 3);
|
||||||
|
if (pContext->GetLastNativeError() != SP_ERROR_NONE || buffer[0] == '\0')
|
||||||
|
{
|
||||||
|
UTIL_Format(default_message, sizeof(default_message), "Feature \"%s\" not available", name);
|
||||||
|
msg = default_message;
|
||||||
|
}
|
||||||
|
pPlugin->SetErrorState(Plugin_Error, "%s", msg);
|
||||||
|
return pContext->ThrowNativeErrorEx(SP_ERROR_ABORTED, "%s", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
REGISTER_NATIVES(coreNatives)
|
REGISTER_NATIVES(coreNatives)
|
||||||
{
|
{
|
||||||
{"AutoExecConfig", AutoExecConfig},
|
{"AutoExecConfig", AutoExecConfig},
|
||||||
@ -654,6 +697,8 @@ REGISTER_NATIVES(coreNatives)
|
|||||||
{"GetExtensionFileStatus", GetExtensionFileStatus},
|
{"GetExtensionFileStatus", GetExtensionFileStatus},
|
||||||
{"FindPluginByNumber", FindPluginByNumber},
|
{"FindPluginByNumber", FindPluginByNumber},
|
||||||
{"VerifyCoreVersion", VerifyCoreVersion},
|
{"VerifyCoreVersion", VerifyCoreVersion},
|
||||||
|
{"GetFeatureStatus", GetFeatureStatus},
|
||||||
|
{"RequireFeature", RequireFeature},
|
||||||
{NULL, NULL},
|
{NULL, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -858,6 +858,8 @@ native RemoveServerTag(const String:tag[]);
|
|||||||
*/
|
*/
|
||||||
functag public Action:CommandListener(client, const String:command[], argc);
|
functag public Action:CommandListener(client, const String:command[], argc);
|
||||||
|
|
||||||
|
#define FEATURECAP_COMMANDLISTENER "command listener"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a callback that will fire when a command is sent to the server.
|
* Adds a callback that will fire when a command is sent to the server.
|
||||||
*
|
*
|
||||||
@ -866,6 +868,9 @@ functag public Action:CommandListener(client, const String:command[], argc);
|
|||||||
* Using Reg*Cmd to intercept is in poor practice, as it physically creates a
|
* Using Reg*Cmd to intercept is in poor practice, as it physically creates a
|
||||||
* new command and can slow down dispatch in general.
|
* new command and can slow down dispatch in general.
|
||||||
*
|
*
|
||||||
|
* To see if this feature is available, use FeatureType_Capability and
|
||||||
|
* FEATURECAP_COMMANDLISTENER.
|
||||||
|
*
|
||||||
* @param callback Callback.
|
* @param callback Callback.
|
||||||
* @param command Command, or if not specified, a global listener.
|
* @param command Command, or if not specified, a global listener.
|
||||||
* The command is case insensitive.
|
* The command is case insensitive.
|
||||||
|
@ -151,8 +151,22 @@ public Extension:__ext_core =
|
|||||||
|
|
||||||
native VerifyCoreVersion();
|
native VerifyCoreVersion();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a native as optional, such that if it is unloaded, removed,
|
||||||
|
* or otherwise non-existent, the plugin will still work. Calling
|
||||||
|
* removed natives results in a run-time error.
|
||||||
|
*
|
||||||
|
* @param name Native name.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
native MarkNativeAsOptional(const String:name[]);
|
||||||
|
|
||||||
public __ext_core_SetNTVOptional()
|
public __ext_core_SetNTVOptional()
|
||||||
{
|
{
|
||||||
|
MarkNativeAsOptional("GetFeatureStatus");
|
||||||
|
MarkNativeAsOptional("RequireFeature");
|
||||||
|
MarkNativeAsOptional("AddCommandListener");
|
||||||
|
MarkNativeAsOptional("RemoveCommandListener");
|
||||||
VerifyCoreVersion();
|
VerifyCoreVersion();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,16 +410,6 @@ native GetSysTickCount();
|
|||||||
*/
|
*/
|
||||||
native AutoExecConfig(bool:autoCreate=true, const String:name[]="", const String:folder[]="sourcemod");
|
native AutoExecConfig(bool:autoCreate=true, const String:name[]="", const String:folder[]="sourcemod");
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets a native as optional, such that if it is unloaded, removed,
|
|
||||||
* or otherwise non-existent, the plugin will still work. Calling
|
|
||||||
* removed natives results in a run-time error.
|
|
||||||
*
|
|
||||||
* @param name Native name.
|
|
||||||
* @noreturn
|
|
||||||
*/
|
|
||||||
native MarkNativeAsOptional(const String:name[]);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a library name for identifying as a dependency to
|
* Registers a library name for identifying as a dependency to
|
||||||
* other plugins.
|
* other plugins.
|
||||||
@ -565,6 +555,81 @@ forward bool:OnClientFloodCheck(client);
|
|||||||
*/
|
*/
|
||||||
forward OnClientFloodResult(client, bool:blocked);
|
forward OnClientFloodResult(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 String: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.
|
||||||
|
* @noreturn
|
||||||
|
*/
|
||||||
|
native RequireFeature(FeatureType:type, const String:name[],
|
||||||
|
const String:fmt[]="", any:...);
|
||||||
|
|
||||||
#include <helpers>
|
#include <helpers>
|
||||||
#include <entity>
|
#include <entity>
|
||||||
#include <entity_prop_stocks>
|
#include <entity_prop_stocks>
|
||||||
|
33
plugins/testsuite/capstest.sp
Normal file
33
plugins/testsuite/capstest.sp
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
|
||||||
|
public OnPluginStart()
|
||||||
|
{
|
||||||
|
RegServerCmd("sm_test_caps1", Test_Caps1);
|
||||||
|
RegServerCmd("sm_test_caps2", Test_Caps2);
|
||||||
|
RegServerCmd("sm_test_caps3", Test_Caps3);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Caps1(args)
|
||||||
|
{
|
||||||
|
PrintToServer("CanTestFeatures: %d", CanTestFeatures());
|
||||||
|
PrintToServer("Status PTS: %d", GetFeatureStatus(FeatureType_Native, "PrintToServer"));
|
||||||
|
PrintToServer("Status ???: %d", GetFeatureStatus(FeatureType_Native, "???"));
|
||||||
|
PrintToServer("Status CL: %d", GetFeatureStatus(FeatureType_Capability, FEATURECAP_COMMANDLISTENER));
|
||||||
|
|
||||||
|
return Plugin_Handled
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Caps2(args)
|
||||||
|
{
|
||||||
|
RequireFeature(FeatureType_Native, "VerifyCoreVersion");
|
||||||
|
RequireFeature(FeatureType_Native, "Sally ate a worm");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Action:Test_Caps3(args)
|
||||||
|
{
|
||||||
|
RequireFeature(FeatureType_Native, "Sally ate a worm", "oh %s %d no", "yam", 23);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ namespace SourceMod
|
|||||||
* Note: This is bumped when IShareSys is changed, because IShareSys
|
* Note: This is bumped when IShareSys is changed, because IShareSys
|
||||||
* itself is not versioned.
|
* itself is not versioned.
|
||||||
*/
|
*/
|
||||||
#define SMINTERFACE_EXTENSIONAPI_VERSION 4
|
#define SMINTERFACE_EXTENSIONAPI_VERSION 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The interface an extension must expose.
|
* @brief The interface an extension must expose.
|
||||||
|
@ -35,9 +35,6 @@
|
|||||||
/**
|
/**
|
||||||
* @file IShareSys.h
|
* @file IShareSys.h
|
||||||
* @brief Defines the Share System, responsible for shared resources and dependencies.
|
* @brief Defines the Share System, responsible for shared resources and dependencies.
|
||||||
*
|
|
||||||
* The Share System also manages the Identity_t data type, although this is internally
|
|
||||||
* implemented with the Handle System.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <sp_vm_types.h>
|
#include <sp_vm_types.h>
|
||||||
@ -54,6 +51,41 @@ namespace SourceMod
|
|||||||
/** Forward declaration from IHandleSys.h */
|
/** Forward declaration from IHandleSys.h */
|
||||||
typedef HandleType_t IdentityType_t;
|
typedef HandleType_t IdentityType_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Types of features.
|
||||||
|
*/
|
||||||
|
enum FeatureType
|
||||||
|
{
|
||||||
|
FeatureType_Native, /**< Native functions for plugins. */
|
||||||
|
FeatureType_Capability /**< Named capabilities. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Feature presence status codes.
|
||||||
|
*/
|
||||||
|
enum FeatureStatus
|
||||||
|
{
|
||||||
|
FeatureStatus_Available = 0, /**< Feature is available for use. */
|
||||||
|
FeatureStatus_Unavailable, /**< Feature is unavailable, but known. */
|
||||||
|
FeatureStatus_Unknown /**< Feature is not known. */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Provides a capability feature.
|
||||||
|
*/
|
||||||
|
class IFeatureProvider
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Must return whether a capability is present.
|
||||||
|
*
|
||||||
|
* @param type Feature type (FeatureType_Capability right now).
|
||||||
|
* @param name Feature name.
|
||||||
|
* @return Feature status code.
|
||||||
|
*/
|
||||||
|
virtual FeatureStatus GetFeatureStatus(FeatureType type, const char *name) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Defines the base functionality required by a shared interface.
|
* @brief Defines the base functionality required by a shared interface.
|
||||||
*/
|
*/
|
||||||
@ -221,6 +253,31 @@ namespace SourceMod
|
|||||||
* lifetime of the extension.
|
* lifetime of the extension.
|
||||||
*/
|
*/
|
||||||
virtual void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
|
virtual void OverrideNatives(IExtension *myself, const sp_nativeinfo_t *natives) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds a capability provider. Feature providers are used by
|
||||||
|
* plugins to determine if a feature exists at runtime. This is
|
||||||
|
* distinctly different from checking for a native, because natives
|
||||||
|
* may be backed by underlying functionality which is not available.
|
||||||
|
*
|
||||||
|
* @param myself Extension.
|
||||||
|
* @param provider Feature provider implementation.
|
||||||
|
* @param name Capibility name.
|
||||||
|
*/
|
||||||
|
virtual void AddCapabilityProvider(IExtension *myself,
|
||||||
|
IFeatureProvider *provider,
|
||||||
|
const char *name) =0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Drops a previously added cap provider.
|
||||||
|
*
|
||||||
|
* @param myself Extension.
|
||||||
|
* @param provider Feature provider implementation.
|
||||||
|
* @param name Capibility name.
|
||||||
|
*/
|
||||||
|
virtual void DropCapabilityProvider(IExtension *myself,
|
||||||
|
IFeatureProvider *provider,
|
||||||
|
const char *name) =0;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user