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;
|
CExtensionManager g_Extensions;
|
||||||
IdentityType_t g_ExtType;
|
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_pAPI = NULL;
|
||||||
m_pIdentToken = NULL;
|
m_pIdentToken = NULL;
|
||||||
m_PlId = 0;
|
|
||||||
unload_code = 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];
|
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);
|
g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_Path.assign(path);
|
Initialize(filename, path);
|
||||||
|
|
||||||
m_pLib = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
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();
|
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->CloseLibrary();
|
||||||
m_pLib = NULL;
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load as MM:S */
|
||||||
if (m_pAPI->IsMetamodExtension())
|
if (m_pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
bool already;
|
bool already;
|
||||||
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
|
m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
|
if (!CExtension::Load(error, maxlength))
|
||||||
|
|
||||||
if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
|
|
||||||
{
|
{
|
||||||
if (m_pAPI->IsMetamodExtension())
|
if (m_pAPI->IsMetamodExtension())
|
||||||
{
|
{
|
||||||
@ -126,13 +154,71 @@ bool CExtension::Load(char *error, size_t maxlength)
|
|||||||
m_PlId = 0;
|
m_PlId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
m_pAPI = NULL;
|
|
||||||
m_pLib->CloseLibrary();
|
m_pLib->CloseLibrary();
|
||||||
m_pLib = NULL;
|
m_pLib = NULL;
|
||||||
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
m_pAPI = NULL;
|
||||||
m_pIdentToken = NULL;
|
|
||||||
return false;
|
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 */
|
/* Check if we're past load time */
|
||||||
if (!g_SourceMod.IsMapLoading())
|
if (!g_SourceMod.IsMapLoading())
|
||||||
{
|
{
|
||||||
@ -143,35 +229,33 @@ bool CExtension::Load(char *error, size_t maxlength)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CExtension::~CExtension()
|
void CExtension::CreateIdentity()
|
||||||
{
|
{
|
||||||
char temp_buffer[255];
|
if (m_pIdentToken != NULL)
|
||||||
|
|
||||||
if (m_pAPI)
|
|
||||||
{
|
{
|
||||||
if (m_PlId)
|
return;
|
||||||
{
|
|
||||||
g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_pIdentToken)
|
m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CExtension::DestroyIdentity()
|
||||||
{
|
{
|
||||||
|
if (m_pIdentToken == NULL)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
g_ShareSys.DestroyIdentity(m_pIdentToken);
|
||||||
}
|
m_pIdentToken = NULL;
|
||||||
|
|
||||||
if (m_pLib)
|
|
||||||
{
|
|
||||||
m_pLib->CloseLibrary();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CExtension::MarkAllLoaded()
|
void CExtension::MarkAllLoaded()
|
||||||
{
|
{
|
||||||
assert(m_FullyLoaded == false);
|
assert(m_bFullyLoaded == false);
|
||||||
if (!m_FullyLoaded)
|
if (!m_bFullyLoaded)
|
||||||
{
|
{
|
||||||
m_FullyLoaded = true;
|
m_bFullyLoaded = true;
|
||||||
m_pAPI->OnExtensionsAllLoaded();
|
m_pAPI->OnExtensionsAllLoaded();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -221,7 +305,12 @@ IdentityToken_t *CExtension::GetIdentity()
|
|||||||
return m_pIdentToken;
|
return m_pIdentToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CExtension::IsLoaded()
|
bool CRemoteExtension::IsLoaded()
|
||||||
|
{
|
||||||
|
return (m_pAPI != NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CLocalExtension::IsLoaded()
|
||||||
{
|
{
|
||||||
return (m_pLib != NULL);
|
return (m_pLib != NULL);
|
||||||
}
|
}
|
||||||
@ -435,7 +524,7 @@ IExtension *CExtensionManager::LoadAutoExtension(const char *path)
|
|||||||
}
|
}
|
||||||
|
|
||||||
char error[256];
|
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
|
/* We put us in the list beforehand so extensions that check for each other
|
||||||
* won't recursively load each other.
|
* won't recursively load each other.
|
||||||
@ -456,13 +545,6 @@ IExtension *CExtensionManager::FindExtensionByFile(const char *file)
|
|||||||
List<CExtension *>::iterator iter;
|
List<CExtension *>::iterator iter;
|
||||||
CExtension *pExt;
|
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 */
|
/* Chomp off the path */
|
||||||
char lookup[PLATFORM_MAX_PATH];
|
char lookup[PLATFORM_MAX_PATH];
|
||||||
g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,7 +605,7 @@ IExtension *CExtensionManager::FindExtensionByName(const char *ext)
|
|||||||
return NULL;
|
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;
|
IExtension *pAlready;
|
||||||
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
if ((pAlready=FindExtensionByFile(file)) != NULL)
|
||||||
@ -521,12 +613,11 @@ IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime
|
|||||||
return pAlready;
|
return pAlready;
|
||||||
}
|
}
|
||||||
|
|
||||||
CExtension *pExt = new CExtension(file, error, maxlength);
|
CExtension *pExt = new CLocalExtension(file);
|
||||||
|
|
||||||
/* :NOTE: lifetime is currently ignored */
|
|
||||||
|
|
||||||
if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
|
if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
|
||||||
{
|
{
|
||||||
|
pExt->Unload();
|
||||||
delete pExt;
|
delete pExt;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -790,6 +881,7 @@ bool CExtensionManager::UnloadExtension(IExtension *_pExt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pExt->Unload();
|
||||||
delete pExt;
|
delete pExt;
|
||||||
|
|
||||||
List<CExtension *>::iterator iter;
|
List<CExtension *>::iterator iter;
|
||||||
@ -833,7 +925,7 @@ void CExtensionManager::MarkAllLoaded()
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pExt->m_FullyLoaded)
|
if (pExt->m_bFullyLoaded)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -891,7 +983,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
if (!pExt->IsRunning(error, sizeof(error)))
|
if (!pExt->IsRunning(error, sizeof(error)))
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
|
g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||||
const char *name = pAPI->GetExtensionName();
|
const char *name = pAPI->GetExtensionName();
|
||||||
const char *version = pAPI->GetExtensionVerString();
|
const char *version = pAPI->GetExtensionVerString();
|
||||||
@ -903,7 +997,9 @@ void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (strcmp(cmd, "info") == 0) {
|
}
|
||||||
|
else if (strcmp(cmd, "info") == 0)
|
||||||
|
{
|
||||||
if (argcount < 4)
|
if (argcount < 4)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
|
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(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
|
g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
char error[255];
|
char error[255];
|
||||||
if (!pExt->IsRunning(error, sizeof(error)))
|
if (!pExt->IsRunning(error, sizeof(error)))
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: Yes");
|
g_RootMenu.ConsolePrint(" Loaded: Yes");
|
||||||
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
|
g_RootMenu.ConsolePrint(" Running: No (%s)", error);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
IExtensionInterface *pAPI = pExt->GetAPI();
|
IExtensionInterface *pAPI = pExt->GetAPI();
|
||||||
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
|
||||||
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
|
g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
|
||||||
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
|
g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
|
||||||
g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
|
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(" 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;
|
return;
|
||||||
} else if (strcmp(cmd, "unload") == 0) {
|
}
|
||||||
|
else if (strcmp(cmd, "unload") == 0)
|
||||||
|
{
|
||||||
if (argcount < 4)
|
if (argcount < 4)
|
||||||
{
|
{
|
||||||
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
|
g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
|
||||||
@ -1141,3 +1255,29 @@ bool CExtensionManager::LibraryExists(const char *library)
|
|||||||
|
|
||||||
return false;
|
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;
|
friend class CExtensionManager;
|
||||||
public:
|
public:
|
||||||
CExtension(const char *filename, char *error, size_t maxlen);
|
virtual ~CExtension();
|
||||||
~CExtension();
|
|
||||||
public: //IExtension
|
public: //IExtension
|
||||||
IExtensionInterface *GetAPI();
|
IExtensionInterface *GetAPI();
|
||||||
const char *GetFilename();
|
const char *GetFilename();
|
||||||
IdentityToken_t *GetIdentity();
|
IdentityToken_t *GetIdentity();
|
||||||
bool IsLoaded();
|
|
||||||
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
|
||||||
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
|
||||||
void FreeDependencyIterator(ITERATOR *iter);
|
void FreeDependencyIterator(ITERATOR *iter);
|
||||||
@ -79,14 +77,20 @@ public:
|
|||||||
void RemovePlugin(IPlugin *pPlugin);
|
void RemovePlugin(IPlugin *pPlugin);
|
||||||
void MarkAllLoaded();
|
void MarkAllLoaded();
|
||||||
void AddLibrary(const char *library);
|
void AddLibrary(const char *library);
|
||||||
private:
|
public:
|
||||||
bool Load(char *error, size_t maxlength);
|
virtual bool Load(char *error, size_t maxlength);
|
||||||
private:
|
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;
|
IdentityToken_t *m_pIdentToken;
|
||||||
IExtensionInterface *m_pAPI;
|
IExtensionInterface *m_pAPI;
|
||||||
String m_File;
|
String m_File;
|
||||||
String m_Path;
|
String m_Path;
|
||||||
ILibrary *m_pLib;
|
|
||||||
String m_Error;
|
String m_Error;
|
||||||
List<IfaceInfo> m_Deps; /** Dependencies */
|
List<IfaceInfo> m_Deps; /** Dependencies */
|
||||||
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
|
||||||
@ -95,9 +99,33 @@ private:
|
|||||||
List<const sp_nativeinfo_t *> m_Natives;
|
List<const sp_nativeinfo_t *> m_Natives;
|
||||||
List<WeakNative> m_WeakNatives;
|
List<WeakNative> m_WeakNatives;
|
||||||
List<String> m_Libraries;
|
List<String> m_Libraries;
|
||||||
PluginId m_PlId;
|
|
||||||
unsigned int unload_code;
|
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 :
|
class CExtensionManager :
|
||||||
@ -114,12 +142,16 @@ public: //SMGlobalClass
|
|||||||
void OnSourceModShutdown();
|
void OnSourceModShutdown();
|
||||||
public: //IExtensionManager
|
public: //IExtensionManager
|
||||||
IExtension *LoadExtension(const char *path,
|
IExtension *LoadExtension(const char *path,
|
||||||
ExtensionLifetime lifetime,
|
|
||||||
char *error,
|
char *error,
|
||||||
size_t maxlength);
|
size_t maxlength);
|
||||||
bool UnloadExtension(IExtension *pExt);
|
bool UnloadExtension(IExtension *pExt);
|
||||||
IExtension *FindExtensionByFile(const char *file);
|
IExtension *FindExtensionByFile(const char *file);
|
||||||
IExtension *FindExtensionByName(const char *ext);
|
IExtension *FindExtensionByName(const char *ext);
|
||||||
|
IExtension *LoadExternal(IExtensionInterface *pInterface,
|
||||||
|
const char *filepath,
|
||||||
|
const char *filename,
|
||||||
|
char *error,
|
||||||
|
size_t maxlength);
|
||||||
public: //IPluginsListener
|
public: //IPluginsListener
|
||||||
void OnPluginDestroyed(IPlugin *plugin);
|
void OnPluginDestroyed(IPlugin *plugin);
|
||||||
public: //IRootConsoleCommand
|
public: //IRootConsoleCommand
|
||||||
|
@ -65,7 +65,9 @@ namespace SourceMod
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the filename of the extension, relative to the
|
* @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.
|
* @return A string containing the extension file name.
|
||||||
*/
|
*/
|
||||||
@ -112,6 +114,15 @@ namespace SourceMod
|
|||||||
* @return True if extension is okay, false if not okay.
|
* @return True if extension is okay, false if not okay.
|
||||||
*/
|
*/
|
||||||
virtual bool IsRunning(char *error, size_t maxlength) =0;
|
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;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -166,8 +177,10 @@ namespace SourceMod
|
|||||||
virtual void OnExtensionPauseChange(bool pause) =0;
|
virtual void OnExtensionPauseChange(bool pause) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Asks the extension whether it's safe to remove an external interface it's using.
|
* @brief Asks the extension whether it's safe to remove an external
|
||||||
* If it's not safe, return false, and the extension will be unloaded afterwards.
|
* 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.
|
* NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources.
|
||||||
*
|
*
|
||||||
* @param pInterface Pointer to interface being dropped.
|
* @param pInterface Pointer to interface being dropped.
|
||||||
@ -199,27 +212,84 @@ namespace SourceMod
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
public:
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
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;
|
virtual const char *GetExtensionDateString() =0;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager"
|
#define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager"
|
||||||
#define SMINTERFACE_EXTENSIONMANAGER_VERSION 1
|
#define SMINTERFACE_EXTENSIONMANAGER_VERSION 2
|
||||||
|
|
||||||
/**
|
|
||||||
* @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
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Manages the loading/unloading of extensions.
|
* @brief Manages the loading/unloading of extensions.
|
||||||
@ -235,23 +305,63 @@ namespace SourceMod
|
|||||||
{
|
{
|
||||||
return SMINTERFACE_EXTENSIONMANAGER_VERSION;
|
return SMINTERFACE_EXTENSIONMANAGER_VERSION;
|
||||||
}
|
}
|
||||||
|
virtual bool IsVersionCompatible(unsigned int version)
|
||||||
|
{
|
||||||
|
if (version < 2)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return SMInterface::IsVersionCompatible(version);
|
||||||
|
}
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief Loads a extension into the extension system.
|
* @brief Loads a extension into the extension system.
|
||||||
*
|
*
|
||||||
* @param path Path to extension file, relative to the extensions folder.
|
* @param path Path to extension file, relative to the
|
||||||
|
* extensions folder.
|
||||||
* @param lifetime Lifetime of the extension (currently ignored).
|
* @param lifetime Lifetime of the extension (currently ignored).
|
||||||
* @param error Error buffer.
|
* @param error Error buffer.
|
||||||
* @param maxlength Maximum error buffer length.
|
* @param maxlength Maximum error buffer length.
|
||||||
* @return New IExtension on success, NULL on failure.
|
* @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,
|
virtual IExtension *LoadExtension(const char *path,
|
||||||
ExtensionLifetime lifetime,
|
|
||||||
char *error,
|
char *error,
|
||||||
size_t maxlength) =0;
|
size_t maxlength) =0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Attempts to unload a module.
|
* @brief Loads an extension into the extension system, directly,
|
||||||
|
* as an external extension.
|
||||||
|
*
|
||||||
|
* 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.
|
* @param pExt IExtension pointer.
|
||||||
* @return True if successful, false otherwise.
|
* @return True if successful, false otherwise.
|
||||||
|
Loading…
Reference in New Issue
Block a user