added experimental extension interface for loading external extensions from mm:s
hard-bumped the extension api --HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401654
This commit is contained in:
parent
0cf6a24414
commit
f60369a005
@ -41,14 +41,26 @@
|
||||
CExtensionManager g_Extensions;
|
||||
IdentityType_t g_ExtType;
|
||||
|
||||
CExtension::CExtension(const char *filename, char *error, size_t maxlength)
|
||||
void CExtension::Initialize(const char *filename, const char *path)
|
||||
{
|
||||
m_File.assign(filename);
|
||||
m_pAPI = NULL;
|
||||
m_pIdentToken = NULL;
|
||||
m_PlId = 0;
|
||||
unload_code = 0;
|
||||
m_FullyLoaded = false;
|
||||
m_bFullyLoaded = false;
|
||||
m_File.assign(filename);
|
||||
m_Path.assign(path);
|
||||
}
|
||||
|
||||
CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
|
||||
{
|
||||
m_pAPI = pAPI;
|
||||
Initialize(filename, path);
|
||||
}
|
||||
|
||||
CLocalExtension::CLocalExtension(const char *filename)
|
||||
{
|
||||
m_PlId = 0;
|
||||
m_pLib = NULL;
|
||||
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
|
||||
@ -73,12 +85,27 @@ CExtension::CExtension(const char *filename, char *error, size_t maxlength)
|
||||
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
|
||||
}
|
||||
|
||||
m_Path.assign(path);
|
||||
|
||||
m_pLib = NULL;
|
||||
Initialize(filename, path);
|
||||
}
|
||||
|
||||
bool CExtension::Load(char *error, size_t maxlength)
|
||||
bool CRemoteExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
if (!PerformAPICheck(error, maxlength))
|
||||
{
|
||||
m_pAPI = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!CExtension::Load(error, maxlength))
|
||||
{
|
||||
m_pAPI = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLocalExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
|
||||
|
||||
@ -99,23 +126,24 @@ bool CExtension::Load(char *error, size_t maxlength)
|
||||
}
|
||||
|
||||
m_pAPI = pfnGetAPI();
|
||||
if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
|
||||
|
||||
/* Check pointer and version */
|
||||
if (!PerformAPICheck(error, maxlength))
|
||||
{
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
|
||||
m_pAPI = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Load as MM:S */
|
||||
if (m_pAPI->IsMetamodExtension())
|
||||
{
|
||||
bool already;
|
||||
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
|
||||
}
|
||||
|
||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
|
||||
|
||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
|
||||
if (!CExtension::Load(error, maxlength))
|
||||
{
|
||||
if (m_pAPI->IsMetamodExtension())
|
||||
{
|
||||
@ -126,13 +154,71 @@ bool CExtension::Load(char *error, size_t maxlength)
|
||||
m_PlId = 0;
|
||||
}
|
||||
}
|
||||
m_pAPI = NULL;
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
||||
m_pIdentToken = NULL;
|
||||
m_pAPI = NULL;
|
||||
return false;
|
||||
} else {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CRemoteExtension::Unload()
|
||||
{
|
||||
}
|
||||
|
||||
void CLocalExtension::Unload()
|
||||
{
|
||||
if (m_pAPI != NULL && m_PlId)
|
||||
{
|
||||
char temp_buffer[255];
|
||||
g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
|
||||
m_PlId = 0;
|
||||
}
|
||||
|
||||
if (m_pLib != NULL)
|
||||
{
|
||||
m_pLib->CloseLibrary();
|
||||
m_pLib = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool CRemoteExtension::IsExternal()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CLocalExtension::IsExternal()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CExtension::~CExtension()
|
||||
{
|
||||
DestroyIdentity();
|
||||
}
|
||||
|
||||
bool CExtension::PerformAPICheck(char *error, size_t maxlength)
|
||||
{
|
||||
if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
|
||||
{
|
||||
snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CExtension::Load(char *error, size_t maxlength)
|
||||
{
|
||||
CreateIdentity();
|
||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
|
||||
{
|
||||
DestroyIdentity();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check if we're past load time */
|
||||
if (!g_SourceMod.IsMapLoading())
|
||||
{
|
||||
@ -143,35 +229,33 @@ bool CExtension::Load(char *error, size_t maxlength)
|
||||
return true;
|
||||
}
|
||||
|
||||
CExtension::~CExtension()
|
||||
void CExtension::CreateIdentity()
|
||||
{
|
||||
char temp_buffer[255];
|
||||
|
||||
if (m_pAPI)
|
||||
if (m_pIdentToken != NULL)
|
||||
{
|
||||
if (m_PlId)
|
||||
{
|
||||
g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pIdentToken)
|
||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
|
||||
}
|
||||
|
||||
void CExtension::DestroyIdentity()
|
||||
{
|
||||
if (m_pIdentToken == NULL)
|
||||
{
|
||||
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pLib)
|
||||
{
|
||||
m_pLib->CloseLibrary();
|
||||
}
|
||||
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
||||
m_pIdentToken = NULL;
|
||||
}
|
||||
|
||||
void CExtension::MarkAllLoaded()
|
||||
{
|
||||
assert(m_FullyLoaded == false);
|
||||
if (!m_FullyLoaded)
|
||||
assert(m_bFullyLoaded == false);
|
||||
if (!m_bFullyLoaded)
|
||||
{
|
||||
m_FullyLoaded = true;
|
||||
m_bFullyLoaded = true;
|
||||
m_pAPI->OnExtensionsAllLoaded();
|
||||
}
|
||||
}
|
||||
@ -221,7 +305,12 @@ IdentityToken_t *CExtension::GetIdentity()
|
||||
return m_pIdentToken;
|
||||
}
|
||||
|
||||
bool CExtension::IsLoaded()
|
||||
bool CRemoteExtension::IsLoaded()
|
||||
{
|
||||
return (m_pAPI != NULL);
|
||||
}
|
||||
|
||||
bool CLocalExtension::IsLoaded()
|
||||
{
|
||||
return (m_pLib != NULL);
|
||||
}
|
||||
@ -435,7 +524,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
||||
}
|
||||
|
||||
char error[256];
|
||||
CExtension *p = new CExtension(path, error, sizeof(error));
|
||||
CExtension *p = new CLocalExtension(path);
|
||||
|
||||
/* We put us in the list beforehand so extensions that check for each other
|
||||
* won't recursively load each other.
|
||||
@ -456,13 +545,6 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
|
||||
List<CExtension *>::iterator iter;
|
||||
CExtension *pExt;
|
||||
|
||||
if (!strstr(file, "." PLATFORM_LIB_EXT))
|
||||
{
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
|
||||
return FindExtensionByFile(path);
|
||||
}
|
||||
|
||||
/* Chomp off the path */
|
||||
char lookup[PLATFORM_MAX_PATH];
|
||||
g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
|
||||
@ -478,6 +560,16 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
|
||||
}
|
||||
}
|
||||
|
||||
/* If we got no results, test if there was a platform extension.
|
||||
* If not, add one.
|
||||
*/
|
||||
if (!strstr(file, "." PLATFORM_LIB_EXT))
|
||||
{
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
|
||||
return FindExtensionByFile(path);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -513,7 +605,7 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t maxlength)
|
||||
IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
|
||||
{
|
||||
IExtension *pAlready;
|
||||
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
||||
@ -521,12 +613,11 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
|
||||
return pAlready;
|
||||
}
|
||||
|
||||
CExtension *pExt = new CExtension(file, error, maxlength);
|
||||
|
||||
/* :NOTE: lifetime is currently ignored */
|
||||
CExtension *pExt = new CLocalExtension(file);
|
||||
|
||||
if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
|
||||
{
|
||||
pExt->Unload();
|
||||
delete pExt;
|
||||
return NULL;
|
||||
}
|
||||
@ -790,6 +881,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
||||
}
|
||||
}
|
||||
|
||||
pExt->Unload();
|
||||
delete pExt;
|
||||
|
||||
List<CExtension *>::iterator iter;
|
||||
@ -833,7 +925,7 @@ void CExtensionManager::MarkAllLoaded()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (pExt->m_FullyLoaded)
|
||||
if (pExt->m_bFullyLoaded)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@ -891,7 +983,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
if (!pExt->IsRunning(error, sizeof(error)))
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||
const char *name = pAPI->GetExtensionName();
|
||||
const char *version = pAPI->GetExtensionVerString();
|
||||
@ -903,7 +997,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (strcmp(cmd, "info") == 0) {
|
||||
}
|
||||
else if (strcmp(cmd, "info") == 0)
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
||||
@ -952,25 +1048,43 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
||||
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
char error[255];
|
||||
if (!pExt->IsRunning(error, sizeof(error)))
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
||||
g_RootMenu.ConsolePrint(" Loaded: Yes");
|
||||
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
||||
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
|
||||
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
|
||||
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
|
||||
g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
|
||||
g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no");
|
||||
|
||||
if (pExt->IsExternal())
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
|
||||
}
|
||||
else if (pAPI->IsMetamodExtension())
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
|
||||
}
|
||||
else
|
||||
{
|
||||
g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (strcmp(cmd, "unload") == 0) {
|
||||
}
|
||||
else if (strcmp(cmd, "unload") == 0)
|
||||
{
|
||||
if (argcount < 4)
|
||||
{
|
||||
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
|
||||
@ -1141,3 +1255,29 @@ bool CExtensionManager::LibraryExists(const char *library)
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
|
||||
const char *filepath,
|
||||
const char *filename,
|
||||
char *error,
|
||||
size_t maxlength)
|
||||
{
|
||||
IExtension *pAlready;
|
||||
if ((pAlready=FindExtensionByFile(filename)) != NULL)
|
||||
{
|
||||
return pAlready;
|
||||
}
|
||||
|
||||
CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
|
||||
|
||||
if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
|
||||
{
|
||||
pExt->Unload();
|
||||
delete pExt;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
m_Libs.push_back(pExt);
|
||||
|
||||
return pExt;
|
||||
}
|
||||
|
@ -59,13 +59,11 @@ class CExtension : public IExtension
|
||||
{
|
||||
friend class CExtensionManager;
|
||||
public:
|
||||
CExtension(const char *filename, char *error, size_t maxlen);
|
||||
~CExtension();
|
||||
virtual ~CExtension();
|
||||
public: //IExtension
|
||||
IExtensionInterface *GetAPI();
|
||||
const char *GetFilename();
|
||||
IdentityToken_t *GetIdentity();
|
||||
bool IsLoaded();
|
||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||
void FreeDependencyIterator(ITERATOR *iter);
|
||||
@ -79,14 +77,20 @@ public:
|
||||
void RemovePlugin(IPlugin *pPlugin);
|
||||
void MarkAllLoaded();
|
||||
void AddLibrary(const char *library);
|
||||
private:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
private:
|
||||
public:
|
||||
virtual bool Load(char *error, size_t maxlength);
|
||||
virtual bool IsLoaded() =0;
|
||||
virtual void Unload() =0;
|
||||
protected:
|
||||
void Initialize(const char *filename, const char *path);
|
||||
bool PerformAPICheck(char *error, size_t maxlength);
|
||||
void CreateIdentity();
|
||||
void DestroyIdentity();
|
||||
protected:
|
||||
IdentityToken_t *m_pIdentToken;
|
||||
IExtensionInterface *m_pAPI;
|
||||
String m_File;
|
||||
String m_Path;
|
||||
ILibrary *m_pLib;
|
||||
String m_Error;
|
||||
List<IfaceInfo> m_Deps; /** Dependencies */
|
||||
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
||||
@ -95,9 +99,33 @@ private:
|
||||
List<const sp_nativeinfo_t *> m_Natives;
|
||||
List<WeakNative> m_WeakNatives;
|
||||
List<String> m_Libraries;
|
||||
PluginId m_PlId;
|
||||
unsigned int unload_code;
|
||||
bool m_FullyLoaded;
|
||||
bool m_bFullyLoaded;
|
||||
};
|
||||
|
||||
class CLocalExtension : public CExtension
|
||||
{
|
||||
public:
|
||||
CLocalExtension(const char *filename);
|
||||
public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool IsExternal();
|
||||
private:
|
||||
PluginId m_PlId;
|
||||
ILibrary *m_pLib;
|
||||
};
|
||||
|
||||
class CRemoteExtension : public CExtension
|
||||
{
|
||||
public:
|
||||
CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path);
|
||||
public:
|
||||
bool Load(char *error, size_t maxlength);
|
||||
bool IsLoaded();
|
||||
void Unload();
|
||||
bool IsExternal();
|
||||
};
|
||||
|
||||
class CExtensionManager :
|
||||
@ -114,12 +142,16 @@ public: //SMGlobalClass
|
||||
void OnSourceModShutdown();
|
||||
public: //IExtensionManager
|
||||
IExtension *LoadExtension(const char *path,
|
||||
ExtensionLifetime lifetime,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
bool UnloadExtension(IExtension *pExt);
|
||||
IExtension *FindExtensionByFile(const char *file);
|
||||
IExtension *FindExtensionByName(const char *ext);
|
||||
IExtension *LoadExternal(IExtensionInterface *pInterface,
|
||||
const char *filepath,
|
||||
const char *filename,
|
||||
char *error,
|
||||
size_t maxlength);
|
||||
public: //IPluginsListener
|
||||
void OnPluginDestroyed(IPlugin *plugin);
|
||||
public: //IRootConsoleCommand
|
||||
|
@ -65,7 +65,9 @@ namespace SourceMod
|
||||
|
||||
/**
|
||||
* @brief Returns the filename of the extension, relative to the
|
||||
* extension folder.
|
||||
* extension folder. If the extension is an "external" extension,
|
||||
* the file path is specified by the extension itself, and may be
|
||||
* arbitrary (not real).
|
||||
*
|
||||
* @return A string containing the extension file name.
|
||||
*/
|
||||
@ -112,6 +114,15 @@ namespace SourceMod
|
||||
* @return True if extension is okay, false if not okay.
|
||||
*/
|
||||
virtual bool IsRunning(char *error, size_t maxlength) =0;
|
||||
|
||||
/**
|
||||
* @brief Returns whether the extension is local (from the extensions
|
||||
* folder), or is from an external source (such as Metamod:Source).
|
||||
*
|
||||
* @return True if from an external source,
|
||||
* false if local to SourceMod.
|
||||
*/
|
||||
virtual bool IsExternal() =0;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -142,10 +153,10 @@ namespace SourceMod
|
||||
* @return True if load should continue, false otherwise.
|
||||
*/
|
||||
virtual bool OnExtensionLoad(IExtension *me,
|
||||
IShareSys *sys,
|
||||
char *error,
|
||||
size_t maxlength,
|
||||
bool late) =0;
|
||||
IShareSys *sys,
|
||||
char *error,
|
||||
size_t maxlength,
|
||||
bool late) =0;
|
||||
|
||||
/**
|
||||
* @brief Called when the extension is about to be unloaded.
|
||||
@ -166,8 +177,10 @@ namespace SourceMod
|
||||
virtual void OnExtensionPauseChange(bool pause) =0;
|
||||
|
||||
/**
|
||||
* @brief Asks the extension whether it's safe to remove an external interface it's using.
|
||||
* If it's not safe, return false, and the extension will be unloaded afterwards.
|
||||
* @brief Asks the extension whether it's safe to remove an external
|
||||
* interface it's using. If it's not safe, return false, and the
|
||||
* extension will be unloaded afterwards.
|
||||
*
|
||||
* NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources.
|
||||
*
|
||||
* @param pInterface Pointer to interface being dropped.
|
||||
@ -199,27 +212,84 @@ namespace SourceMod
|
||||
return true;
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* @brief For extensions loaded through SourceMod, this should return true
|
||||
* if the extension needs to attach to Metamod:Source. If the extension
|
||||
* is loaded through Metamod:Source, and uses SourceMod optionally, it must
|
||||
* return false.
|
||||
*
|
||||
* @return True if Metamod:Source is needed.
|
||||
*/
|
||||
virtual bool IsMetamodExtension() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing the extension's short name.
|
||||
*
|
||||
* @return String containing extension name.
|
||||
*/
|
||||
virtual const char *GetExtensionName() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing the extension's URL.
|
||||
*
|
||||
* @return String containing extension URL.
|
||||
*/
|
||||
virtual const char *GetExtensionURL() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing a short identifier tag.
|
||||
*
|
||||
* @return String containing extension tag.
|
||||
*/
|
||||
virtual const char *GetExtensionTag() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing a short author identifier.
|
||||
*
|
||||
* @return String containing extension author.
|
||||
*/
|
||||
virtual const char *GetExtensionAuthor() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing version information.
|
||||
*
|
||||
* Any version string format can be used, however, SourceMod
|
||||
* makes a special guarantee version numbers in the form of
|
||||
* A.B.C.D will always be fully displayed, where:
|
||||
*
|
||||
* A is a major version number of at most one digit.
|
||||
* B is a minor version number of at most two digits.
|
||||
* C is a minor version number of at most two digits.
|
||||
* D is a build number of at most 5 digits.
|
||||
*
|
||||
* Thus, thirteen characters of display is guaranteed.
|
||||
*
|
||||
* @return String containing extension version.
|
||||
*/
|
||||
virtual const char *GetExtensionVerString() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing description text.
|
||||
*
|
||||
* The description text may be longer than the other identifiers,
|
||||
* as it is only displayed when viewing one extension at a time.
|
||||
* However, it should not have newlines, or any other characters
|
||||
* which would otherwise disrupt the display pattern.
|
||||
*
|
||||
* @return String containing extension description.
|
||||
*/
|
||||
virtual const char *GetExtensionDescription() =0;
|
||||
|
||||
/**
|
||||
* @brief Must return a string containing the compilation date.
|
||||
*
|
||||
* @return String containing the compilation date.
|
||||
*/
|
||||
virtual const char *GetExtensionDateString() =0;
|
||||
};
|
||||
|
||||
#define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager"
|
||||
#define SMINTERFACE_EXTENSIONMANAGER_VERSION 1
|
||||
|
||||
/**
|
||||
* @brief Not currently used.
|
||||
*/
|
||||
enum ExtensionLifetime
|
||||
{
|
||||
ExtLifetime_Forever, //Extension will never be unloaded automatically
|
||||
ExtLifetime_Map, //Extension will be unloaded at the end of the map
|
||||
};
|
||||
#define SMINTERFACE_EXTENSIONMANAGER_VERSION 2
|
||||
|
||||
/**
|
||||
* @brief Manages the loading/unloading of extensions.
|
||||
@ -235,26 +305,66 @@ namespace SourceMod
|
||||
{
|
||||
return SMINTERFACE_EXTENSIONMANAGER_VERSION;
|
||||
}
|
||||
virtual bool IsVersionCompatible(unsigned int version)
|
||||
{
|
||||
if (version < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return SMInterface::IsVersionCompatible(version);
|
||||
}
|
||||
public:
|
||||
/**
|
||||
* @brief Loads a extension into the extension system.
|
||||
*
|
||||
* @param path Path to extension file, relative to the extensions folder.
|
||||
* @param lifetime Lifetime of the extension (currently ignored).
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum error buffer length.
|
||||
* @return New IExtension on success, NULL on failure.
|
||||
* @param path Path to extension file, relative to the
|
||||
* extensions folder.
|
||||
* @param lifetime Lifetime of the extension (currently ignored).
|
||||
* @param error Error buffer.
|
||||
* @param maxlength Maximum error buffer length.
|
||||
* @return New IExtension on success, NULL on failure.
|
||||
* If NULL is returned, the error buffer will be
|
||||
* filled with a null-terminated string.
|
||||
*/
|
||||
virtual IExtension *LoadExtension(const char *path,
|
||||
ExtensionLifetime lifetime,
|
||||
char *error,
|
||||
size_t maxlength) =0;
|
||||
char *error,
|
||||
size_t maxlength) =0;
|
||||
|
||||
/**
|
||||
* @brief Attempts to unload a module.
|
||||
* @brief Loads an extension into the extension system, directly,
|
||||
* as an external extension.
|
||||
*
|
||||
* @param pExt IExtension pointer.
|
||||
* @return True if successful, false otherwise.
|
||||
* The extension receives all normal callbacks. However, it is
|
||||
* never opened via LoadLibrary/dlopen or closed via FreeLibrary
|
||||
* or dlclose.
|
||||
*
|
||||
* @param pInterface Pointer to an IExtensionInterface instance.
|
||||
* @param filepath Absolute path to the extension's file.
|
||||
* @param filename Name to use to uniquely identify the extension.
|
||||
* The name should be generic, without any
|
||||
* platform-specific suffices. For example,
|
||||
* sdktools.ext instead of sdktools.ext.so.
|
||||
* This filename is used to detect if the
|
||||
* extension is already loaded, and to verify
|
||||
* plugins that require the same extension.
|
||||
* @param error Buffer to store error message.
|
||||
* @param maxlength Maximum size of the error buffer.
|
||||
* @return IExtension pointer on success, NULL on failure.
|
||||
* If NULL is returned, the error buffer will be
|
||||
* filled with a null-terminated string.
|
||||
*/
|
||||
virtual IExtension *LoadExternal(IExtensionInterface *pInterface,
|
||||
const char *filepath,
|
||||
const char *filename,
|
||||
char *error,
|
||||
size_t maxlength) =0;
|
||||
|
||||
/**
|
||||
* @brief Attempts to unload an extension. External extensions must
|
||||
* call this before unloading.
|
||||
*
|
||||
* @param pExt IExtension pointer.
|
||||
* @return True if successful, false otherwise.
|
||||
*/
|
||||
virtual bool UnloadExtension(IExtension *pExt) =0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user