added experimental extension interface for loading external extensions from mm:s
added experimental extension interface for loading external extensions from mm:s
hard-bumped the extension api
1.1 --- a/core/systems/ExtensionSys.cpp Sun Oct 28 05:51:10 2007 +0000
1.2 +++ b/core/systems/ExtensionSys.cpp Sun Oct 28 08:02:24 2007 +0000
1.3 @@ -41,14 +41,26 @@
1.4 CExtensionManager g_Extensions;
1.5 IdentityType_t g_ExtType;
1.6
1.7 -CExtension::CExtension(const char *filename, char *error, size_t maxlength)
1.8 +void CExtension::Initialize(const char *filename, const char *path)
1.9 {
1.10 - m_File.assign(filename);
1.11 m_pAPI = NULL;
1.12 m_pIdentToken = NULL;
1.13 + unload_code = 0;
1.14 + m_bFullyLoaded = false;
1.15 + m_File.assign(filename);
1.16 + m_Path.assign(path);
1.17 +}
1.18 +
1.19 +CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
1.20 +{
1.21 + m_pAPI = pAPI;
1.22 + Initialize(filename, path);
1.23 +}
1.24 +
1.25 +CLocalExtension::CLocalExtension(const char *filename)
1.26 +{
1.27 m_PlId = 0;
1.28 - unload_code = 0;
1.29 - m_FullyLoaded = false;
1.30 + m_pLib = NULL;
1.31
1.32 char path[PLATFORM_MAX_PATH];
1.33
1.34 @@ -73,12 +85,27 @@
1.35 g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
1.36 }
1.37
1.38 - m_Path.assign(path);
1.39 -
1.40 - m_pLib = NULL;
1.41 + Initialize(filename, path);
1.42 }
1.43
1.44 -bool CExtension::Load(char *error, size_t maxlength)
1.45 +bool CRemoteExtension::Load(char *error, size_t maxlength)
1.46 +{
1.47 + if (!PerformAPICheck(error, maxlength))
1.48 + {
1.49 + m_pAPI = NULL;
1.50 + return false;
1.51 + }
1.52 +
1.53 + if (!CExtension::Load(error, maxlength))
1.54 + {
1.55 + m_pAPI = NULL;
1.56 + return false;
1.57 + }
1.58 +
1.59 + return true;
1.60 +}
1.61 +
1.62 +bool CLocalExtension::Load(char *error, size_t maxlength)
1.63 {
1.64 m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
1.65
1.66 @@ -99,23 +126,24 @@
1.67 }
1.68
1.69 m_pAPI = pfnGetAPI();
1.70 - if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
1.71 +
1.72 + /* Check pointer and version */
1.73 + if (!PerformAPICheck(error, maxlength))
1.74 {
1.75 m_pLib->CloseLibrary();
1.76 m_pLib = NULL;
1.77 - snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
1.78 + m_pAPI = NULL;
1.79 return false;
1.80 }
1.81
1.82 + /* Load as MM:S */
1.83 if (m_pAPI->IsMetamodExtension())
1.84 {
1.85 bool already;
1.86 m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
1.87 }
1.88
1.89 - m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
1.90 -
1.91 - if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
1.92 + if (!CExtension::Load(error, maxlength))
1.93 {
1.94 if (m_pAPI->IsMetamodExtension())
1.95 {
1.96 @@ -126,13 +154,71 @@
1.97 m_PlId = 0;
1.98 }
1.99 }
1.100 + m_pLib->CloseLibrary();
1.101 + m_pLib = NULL;
1.102 m_pAPI = NULL;
1.103 + return false;
1.104 + }
1.105 +
1.106 + return true;
1.107 +}
1.108 +
1.109 +void CRemoteExtension::Unload()
1.110 +{
1.111 +}
1.112 +
1.113 +void CLocalExtension::Unload()
1.114 +{
1.115 + if (m_pAPI != NULL && m_PlId)
1.116 + {
1.117 + char temp_buffer[255];
1.118 + g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
1.119 + m_PlId = 0;
1.120 + }
1.121 +
1.122 + if (m_pLib != NULL)
1.123 + {
1.124 m_pLib->CloseLibrary();
1.125 m_pLib = NULL;
1.126 - g_ShareSys.DestroyIdentity(m_pIdentToken);
1.127 - m_pIdentToken = NULL;
1.128 + }
1.129 +}
1.130 +
1.131 +bool CRemoteExtension::IsExternal()
1.132 +{
1.133 + return true;
1.134 +}
1.135 +
1.136 +bool CLocalExtension::IsExternal()
1.137 +{
1.138 + return false;
1.139 +}
1.140 +
1.141 +CExtension::~CExtension()
1.142 +{
1.143 + DestroyIdentity();
1.144 +}
1.145 +
1.146 +bool CExtension::PerformAPICheck(char *error, size_t maxlength)
1.147 +{
1.148 + if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
1.149 + {
1.150 + snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
1.151 return false;
1.152 - } else {
1.153 + }
1.154 +
1.155 + return true;
1.156 +}
1.157 +
1.158 +bool CExtension::Load(char *error, size_t maxlength)
1.159 +{
1.160 + CreateIdentity();
1.161 + if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
1.162 + {
1.163 + DestroyIdentity();
1.164 + return false;
1.165 + }
1.166 + else
1.167 + {
1.168 /* Check if we're past load time */
1.169 if (!g_SourceMod.IsMapLoading())
1.170 {
1.171 @@ -143,35 +229,33 @@
1.172 return true;
1.173 }
1.174
1.175 -CExtension::~CExtension()
1.176 +void CExtension::CreateIdentity()
1.177 {
1.178 - char temp_buffer[255];
1.179 -
1.180 - if (m_pAPI)
1.181 + if (m_pIdentToken != NULL)
1.182 {
1.183 - if (m_PlId)
1.184 - {
1.185 - g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
1.186 - }
1.187 + return;
1.188 }
1.189
1.190 - if (m_pIdentToken)
1.191 + m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
1.192 +}
1.193 +
1.194 +void CExtension::DestroyIdentity()
1.195 +{
1.196 + if (m_pIdentToken == NULL)
1.197 {
1.198 - g_ShareSys.DestroyIdentity(m_pIdentToken);
1.199 + return;
1.200 }
1.201
1.202 - if (m_pLib)
1.203 - {
1.204 - m_pLib->CloseLibrary();
1.205 - }
1.206 + g_ShareSys.DestroyIdentity(m_pIdentToken);
1.207 + m_pIdentToken = NULL;
1.208 }
1.209
1.210 void CExtension::MarkAllLoaded()
1.211 {
1.212 - assert(m_FullyLoaded == false);
1.213 - if (!m_FullyLoaded)
1.214 + assert(m_bFullyLoaded == false);
1.215 + if (!m_bFullyLoaded)
1.216 {
1.217 - m_FullyLoaded = true;
1.218 + m_bFullyLoaded = true;
1.219 m_pAPI->OnExtensionsAllLoaded();
1.220 }
1.221 }
1.222 @@ -221,7 +305,12 @@
1.223 return m_pIdentToken;
1.224 }
1.225
1.226 -bool CExtension::IsLoaded()
1.227 +bool CRemoteExtension::IsLoaded()
1.228 +{
1.229 + return (m_pAPI != NULL);
1.230 +}
1.231 +
1.232 +bool CLocalExtension::IsLoaded()
1.233 {
1.234 return (m_pLib != NULL);
1.235 }
1.236 @@ -435,7 +524,7 @@
1.237 }
1.238
1.239 char error[256];
1.240 - CExtension *p = new CExtension(path, error, sizeof(error));
1.241 + CExtension *p = new CLocalExtension(path);
1.242
1.243 /* We put us in the list beforehand so extensions that check for each other
1.244 * won't recursively load each other.
1.245 @@ -456,13 +545,6 @@
1.246 List<CExtension *>::iterator iter;
1.247 CExtension *pExt;
1.248
1.249 - if (!strstr(file, "." PLATFORM_LIB_EXT))
1.250 - {
1.251 - char path[PLATFORM_MAX_PATH];
1.252 - UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
1.253 - return FindExtensionByFile(path);
1.254 - }
1.255 -
1.256 /* Chomp off the path */
1.257 char lookup[PLATFORM_MAX_PATH];
1.258 g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
1.259 @@ -478,6 +560,16 @@
1.260 }
1.261 }
1.262
1.263 + /* If we got no results, test if there was a platform extension.
1.264 + * If not, add one.
1.265 + */
1.266 + if (!strstr(file, "." PLATFORM_LIB_EXT))
1.267 + {
1.268 + char path[PLATFORM_MAX_PATH];
1.269 + UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
1.270 + return FindExtensionByFile(path);
1.271 + }
1.272 +
1.273 return NULL;
1.274 }
1.275
1.276 @@ -513,7 +605,7 @@
1.277 return NULL;
1.278 }
1.279
1.280 -IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t maxlength)
1.281 +IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
1.282 {
1.283 IExtension *pAlready;
1.284 if ((pAlready=FindExtensionByFile(file)) != NULL)
1.285 @@ -521,12 +613,11 @@
1.286 return pAlready;
1.287 }
1.288
1.289 - CExtension *pExt = new CExtension(file, error, maxlength);
1.290 -
1.291 - /* :NOTE: lifetime is currently ignored */
1.292 + CExtension *pExt = new CLocalExtension(file);
1.293
1.294 if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
1.295 {
1.296 + pExt->Unload();
1.297 delete pExt;
1.298 return NULL;
1.299 }
1.300 @@ -790,6 +881,7 @@
1.301 }
1.302 }
1.303
1.304 + pExt->Unload();
1.305 delete pExt;
1.306
1.307 List<CExtension *>::iterator iter;
1.308 @@ -833,7 +925,7 @@
1.309 {
1.310 continue;
1.311 }
1.312 - if (pExt->m_FullyLoaded)
1.313 + if (pExt->m_bFullyLoaded)
1.314 {
1.315 continue;
1.316 }
1.317 @@ -891,7 +983,9 @@
1.318 if (!pExt->IsRunning(error, sizeof(error)))
1.319 {
1.320 g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
1.321 - } else {
1.322 + }
1.323 + else
1.324 + {
1.325 IExtensionInterface *pAPI = pExt->GetAPI();
1.326 const char *name = pAPI->GetExtensionName();
1.327 const char *version = pAPI->GetExtensionVerString();
1.328 @@ -903,7 +997,9 @@
1.329 }
1.330 }
1.331 return;
1.332 - } else if (strcmp(cmd, "info") == 0) {
1.333 + }
1.334 + else if (strcmp(cmd, "info") == 0)
1.335 + {
1.336 if (argcount < 4)
1.337 {
1.338 g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
1.339 @@ -952,25 +1048,43 @@
1.340 {
1.341 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.342 g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
1.343 - } else {
1.344 + }
1.345 + else
1.346 + {
1.347 char error[255];
1.348 if (!pExt->IsRunning(error, sizeof(error)))
1.349 {
1.350 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.351 g_RootMenu.ConsolePrint(" Loaded: Yes");
1.352 g_RootMenu.ConsolePrint(" Running: No (%s)", error);
1.353 - } else {
1.354 + }
1.355 + else
1.356 + {
1.357 IExtensionInterface *pAPI = pExt->GetAPI();
1.358 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
1.359 g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
1.360 g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
1.361 g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
1.362 g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
1.363 - g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no");
1.364 +
1.365 + if (pExt->IsExternal())
1.366 + {
1.367 + g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
1.368 + }
1.369 + else if (pAPI->IsMetamodExtension())
1.370 + {
1.371 + g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
1.372 + }
1.373 + else
1.374 + {
1.375 + g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
1.376 + }
1.377 }
1.378 }
1.379 return;
1.380 - } else if (strcmp(cmd, "unload") == 0) {
1.381 + }
1.382 + else if (strcmp(cmd, "unload") == 0)
1.383 + {
1.384 if (argcount < 4)
1.385 {
1.386 g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
1.387 @@ -1141,3 +1255,29 @@
1.388
1.389 return false;
1.390 }
1.391 +
1.392 +IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
1.393 + const char *filepath,
1.394 + const char *filename,
1.395 + char *error,
1.396 + size_t maxlength)
1.397 +{
1.398 + IExtension *pAlready;
1.399 + if ((pAlready=FindExtensionByFile(filename)) != NULL)
1.400 + {
1.401 + return pAlready;
1.402 + }
1.403 +
1.404 + CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
1.405 +
1.406 + if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
1.407 + {
1.408 + pExt->Unload();
1.409 + delete pExt;
1.410 + return NULL;
1.411 + }
1.412 +
1.413 + m_Libs.push_back(pExt);
1.414 +
1.415 + return pExt;
1.416 +}
2.1 --- a/core/systems/ExtensionSys.h Sun Oct 28 05:51:10 2007 +0000
2.2 +++ b/core/systems/ExtensionSys.h Sun Oct 28 08:02:24 2007 +0000
2.3 @@ -59,13 +59,11 @@
2.4 {
2.5 friend class CExtensionManager;
2.6 public:
2.7 - CExtension(const char *filename, char *error, size_t maxlen);
2.8 - ~CExtension();
2.9 + virtual ~CExtension();
2.10 public: //IExtension
2.11 IExtensionInterface *GetAPI();
2.12 const char *GetFilename();
2.13 IdentityToken_t *GetIdentity();
2.14 - bool IsLoaded();
2.15 ITERATOR *FindFirstDependency(IExtension **pOwner, SMInterface **pInterface);
2.16 bool FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface);
2.17 void FreeDependencyIterator(ITERATOR *iter);
2.18 @@ -79,14 +77,20 @@
2.19 void RemovePlugin(IPlugin *pPlugin);
2.20 void MarkAllLoaded();
2.21 void AddLibrary(const char *library);
2.22 -private:
2.23 - bool Load(char *error, size_t maxlength);
2.24 -private:
2.25 +public:
2.26 + virtual bool Load(char *error, size_t maxlength);
2.27 + virtual bool IsLoaded() =0;
2.28 + virtual void Unload() =0;
2.29 +protected:
2.30 + void Initialize(const char *filename, const char *path);
2.31 + bool PerformAPICheck(char *error, size_t maxlength);
2.32 + void CreateIdentity();
2.33 + void DestroyIdentity();
2.34 +protected:
2.35 IdentityToken_t *m_pIdentToken;
2.36 IExtensionInterface *m_pAPI;
2.37 String m_File;
2.38 String m_Path;
2.39 - ILibrary *m_pLib;
2.40 String m_Error;
2.41 List<IfaceInfo> m_Deps; /** Dependencies */
2.42 List<IfaceInfo> m_ChildDeps; /** Children who might depend on us */
2.43 @@ -95,9 +99,33 @@
2.44 List<const sp_nativeinfo_t *> m_Natives;
2.45 List<WeakNative> m_WeakNatives;
2.46 List<String> m_Libraries;
2.47 + unsigned int unload_code;
2.48 + bool m_bFullyLoaded;
2.49 +};
2.50 +
2.51 +class CLocalExtension : public CExtension
2.52 +{
2.53 +public:
2.54 + CLocalExtension(const char *filename);
2.55 +public:
2.56 + bool Load(char *error, size_t maxlength);
2.57 + bool IsLoaded();
2.58 + void Unload();
2.59 + bool IsExternal();
2.60 +private:
2.61 PluginId m_PlId;
2.62 - unsigned int unload_code;
2.63 - bool m_FullyLoaded;
2.64 + ILibrary *m_pLib;
2.65 +};
2.66 +
2.67 +class CRemoteExtension : public CExtension
2.68 +{
2.69 +public:
2.70 + CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path);
2.71 +public:
2.72 + bool Load(char *error, size_t maxlength);
2.73 + bool IsLoaded();
2.74 + void Unload();
2.75 + bool IsExternal();
2.76 };
2.77
2.78 class CExtensionManager :
2.79 @@ -114,12 +142,16 @@
2.80 void OnSourceModShutdown();
2.81 public: //IExtensionManager
2.82 IExtension *LoadExtension(const char *path,
2.83 - ExtensionLifetime lifetime,
2.84 char *error,
2.85 size_t maxlength);
2.86 bool UnloadExtension(IExtension *pExt);
2.87 IExtension *FindExtensionByFile(const char *file);
2.88 IExtension *FindExtensionByName(const char *ext);
2.89 + IExtension *LoadExternal(IExtensionInterface *pInterface,
2.90 + const char *filepath,
2.91 + const char *filename,
2.92 + char *error,
2.93 + size_t maxlength);
2.94 public: //IPluginsListener
2.95 void OnPluginDestroyed(IPlugin *plugin);
2.96 public: //IRootConsoleCommand
3.1 --- a/public/IExtensionSys.h Sun Oct 28 05:51:10 2007 +0000
3.2 +++ b/public/IExtensionSys.h Sun Oct 28 08:02:24 2007 +0000
3.3 @@ -65,7 +65,9 @@
3.4
3.5 /**
3.6 * @brief Returns the filename of the extension, relative to the
3.7 - * extension folder.
3.8 + * extension folder. If the extension is an "external" extension,
3.9 + * the file path is specified by the extension itself, and may be
3.10 + * arbitrary (not real).
3.11 *
3.12 * @return A string containing the extension file name.
3.13 */
3.14 @@ -112,6 +114,15 @@
3.15 * @return True if extension is okay, false if not okay.
3.16 */
3.17 virtual bool IsRunning(char *error, size_t maxlength) =0;
3.18 +
3.19 + /**
3.20 + * @brief Returns whether the extension is local (from the extensions
3.21 + * folder), or is from an external source (such as Metamod:Source).
3.22 + *
3.23 + * @return True if from an external source,
3.24 + * false if local to SourceMod.
3.25 + */
3.26 + virtual bool IsExternal() =0;
3.27 };
3.28
3.29 /**
3.30 @@ -142,10 +153,10 @@
3.31 * @return True if load should continue, false otherwise.
3.32 */
3.33 virtual bool OnExtensionLoad(IExtension *me,
3.34 - IShareSys *sys,
3.35 - char *error,
3.36 - size_t maxlength,
3.37 - bool late) =0;
3.38 + IShareSys *sys,
3.39 + char *error,
3.40 + size_t maxlength,
3.41 + bool late) =0;
3.42
3.43 /**
3.44 * @brief Called when the extension is about to be unloaded.
3.45 @@ -166,8 +177,10 @@
3.46 virtual void OnExtensionPauseChange(bool pause) =0;
3.47
3.48 /**
3.49 - * @brief Asks the extension whether it's safe to remove an external interface it's using.
3.50 - * If it's not safe, return false, and the extension will be unloaded afterwards.
3.51 + * @brief Asks the extension whether it's safe to remove an external
3.52 + * interface it's using. If it's not safe, return false, and the
3.53 + * extension will be unloaded afterwards.
3.54 + *
3.55 * NOTE: It is important to also hook NotifyInterfaceDrop() in order to clean up resources.
3.56 *
3.57 * @param pInterface Pointer to interface being dropped.
3.58 @@ -199,27 +212,84 @@
3.59 return true;
3.60 }
3.61 public:
3.62 + /**
3.63 + * @brief For extensions loaded through SourceMod, this should return true
3.64 + * if the extension needs to attach to Metamod:Source. If the extension
3.65 + * is loaded through Metamod:Source, and uses SourceMod optionally, it must
3.66 + * return false.
3.67 + *
3.68 + * @return True if Metamod:Source is needed.
3.69 + */
3.70 virtual bool IsMetamodExtension() =0;
3.71 +
3.72 + /**
3.73 + * @brief Must return a string containing the extension's short name.
3.74 + *
3.75 + * @return String containing extension name.
3.76 + */
3.77 virtual const char *GetExtensionName() =0;
3.78 +
3.79 + /**
3.80 + * @brief Must return a string containing the extension's URL.
3.81 + *
3.82 + * @return String containing extension URL.
3.83 + */
3.84 virtual const char *GetExtensionURL() =0;
3.85 +
3.86 + /**
3.87 + * @brief Must return a string containing a short identifier tag.
3.88 + *
3.89 + * @return String containing extension tag.
3.90 + */
3.91 virtual const char *GetExtensionTag() =0;
3.92 +
3.93 + /**
3.94 + * @brief Must return a string containing a short author identifier.
3.95 + *
3.96 + * @return String containing extension author.
3.97 + */
3.98 virtual const char *GetExtensionAuthor() =0;
3.99 +
3.100 + /**
3.101 + * @brief Must return a string containing version information.
3.102 + *
3.103 + * Any version string format can be used, however, SourceMod
3.104 + * makes a special guarantee version numbers in the form of
3.105 + * A.B.C.D will always be fully displayed, where:
3.106 + *
3.107 + * A is a major version number of at most one digit.
3.108 + * B is a minor version number of at most two digits.
3.109 + * C is a minor version number of at most two digits.
3.110 + * D is a build number of at most 5 digits.
3.111 + *
3.112 + * Thus, thirteen characters of display is guaranteed.
3.113 + *
3.114 + * @return String containing extension version.
3.115 + */
3.116 virtual const char *GetExtensionVerString() =0;
3.117 +
3.118 + /**
3.119 + * @brief Must return a string containing description text.
3.120 + *
3.121 + * The description text may be longer than the other identifiers,
3.122 + * as it is only displayed when viewing one extension at a time.
3.123 + * However, it should not have newlines, or any other characters
3.124 + * which would otherwise disrupt the display pattern.
3.125 + *
3.126 + * @return String containing extension description.
3.127 + */
3.128 virtual const char *GetExtensionDescription() =0;
3.129 +
3.130 + /**
3.131 + * @brief Must return a string containing the compilation date.
3.132 + *
3.133 + * @return String containing the compilation date.
3.134 + */
3.135 virtual const char *GetExtensionDateString() =0;
3.136 };
3.137
3.138 #define SMINTERFACE_EXTENSIONMANAGER_NAME "IExtensionManager"
3.139 - #define SMINTERFACE_EXTENSIONMANAGER_VERSION 1
3.140 -
3.141 - /**
3.142 - * @brief Not currently used.
3.143 - */
3.144 - enum ExtensionLifetime
3.145 - {
3.146 - ExtLifetime_Forever, //Extension will never be unloaded automatically
3.147 - ExtLifetime_Map, //Extension will be unloaded at the end of the map
3.148 - };
3.149 + #define SMINTERFACE_EXTENSIONMANAGER_VERSION 2
3.150
3.151 /**
3.152 * @brief Manages the loading/unloading of extensions.
3.153 @@ -235,26 +305,66 @@
3.154 {
3.155 return SMINTERFACE_EXTENSIONMANAGER_VERSION;
3.156 }
3.157 + virtual bool IsVersionCompatible(unsigned int version)
3.158 + {
3.159 + if (version < 2)
3.160 + {
3.161 + return false;
3.162 + }
3.163 + return SMInterface::IsVersionCompatible(version);
3.164 + }
3.165 public:
3.166 /**
3.167 * @brief Loads a extension into the extension system.
3.168 *
3.169 - * @param path Path to extension file, relative to the extensions folder.
3.170 - * @param lifetime Lifetime of the extension (currently ignored).
3.171 - * @param error Error buffer.
3.172 - * @param maxlength Maximum error buffer length.
3.173 - * @return New IExtension on success, NULL on failure.
3.174 + * @param path Path to extension file, relative to the
3.175 + * extensions folder.
3.176 + * @param lifetime Lifetime of the extension (currently ignored).
3.177 + * @param error Error buffer.
3.178 + * @param maxlength Maximum error buffer length.
3.179 + * @return New IExtension on success, NULL on failure.
3.180 + * If NULL is returned, the error buffer will be
3.181 + * filled with a null-terminated string.
3.182 */
3.183 virtual IExtension *LoadExtension(const char *path,
3.184 - ExtensionLifetime lifetime,
3.185 - char *error,
3.186 - size_t maxlength) =0;
3.187 + char *error,
3.188 + size_t maxlength) =0;
3.189
3.190 /**
3.191 - * @brief Attempts to unload a module.
3.192 + * @brief Loads an extension into the extension system, directly,
3.193 + * as an external extension.
3.194 + *
3.195 + * The extension receives all normal callbacks. However, it is
3.196 + * never opened via LoadLibrary/dlopen or closed via FreeLibrary
3.197 + * or dlclose.
3.198 *
3.199 - * @param pExt IExtension pointer.
3.200 - * @return True if successful, false otherwise.
3.201 + * @param pInterface Pointer to an IExtensionInterface instance.
3.202 + * @param filepath Absolute path to the extension's file.
3.203 + * @param filename Name to use to uniquely identify the extension.
3.204 + * The name should be generic, without any
3.205 + * platform-specific suffices. For example,
3.206 + * sdktools.ext instead of sdktools.ext.so.
3.207 + * This filename is used to detect if the
3.208 + * extension is already loaded, and to verify
3.209 + * plugins that require the same extension.
3.210 + * @param error Buffer to store error message.
3.211 + * @param maxlength Maximum size of the error buffer.
3.212 + * @return IExtension pointer on success, NULL on failure.
3.213 + * If NULL is returned, the error buffer will be
3.214 + * filled with a null-terminated string.
3.215 + */
3.216 + virtual IExtension *LoadExternal(IExtensionInterface *pInterface,
3.217 + const char *filepath,
3.218 + const char *filename,
3.219 + char *error,
3.220 + size_t maxlength) =0;
3.221 +
3.222 + /**
3.223 + * @brief Attempts to unload an extension. External extensions must
3.224 + * call this before unloading.
3.225 + *
3.226 + * @param pExt IExtension pointer.
3.227 + * @return True if successful, false otherwise.
3.228 */
3.229 virtual bool UnloadExtension(IExtension *pExt) =0;
3.230 };