rewrite of the native and dependency binding/interaction code. this will ease the transition for native overrides, and greatly simplifies most of the logic. all native binding code now takes place almost entirely in ShareSys, and PluginSys supplements this logic where appropriate. extensionsys has been cleaned up
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
8 * This program is free software; you can redistribute it and/or modify it under
9 * the terms of the GNU General Public License, version 3.0, as published by the
10 * Free Software Foundation.
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
20 * As a special exception, AlliedModders LLC gives you permission to link the
21 * code of this program (as well as its derivative works) to "Half-Life 2," the
22 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
23 * by the Valve Corporation. You must obey the GNU General Public License in
24 * all respects for all other code used. Additionally, AlliedModders LLC grants
25 * this exception to all derivative works. AlliedModders LLC defines further
26 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
27 * or <http://www.sourcemod.net/license.php>.
33 #include "ExtensionSys.h"
34 #include "LibrarySys.h"
37 #include "sourcemm_api.h"
38 #include "sm_srvcmds.h"
39 #include "sm_stringutil.h"
41 CExtensionManager g_Extensions;
42 IdentityType_t g_ExtType;
44 void CExtension::Initialize(const char *filename, const char *path)
49 m_bFullyLoaded = false;
50 m_File.assign(filename);
54 CRemoteExtension::CRemoteExtension(IExtensionInterface *pAPI, const char *filename, const char *path)
56 Initialize(filename, path);
60 CLocalExtension::CLocalExtension(const char *filename)
65 char path[PLATFORM_MAX_PATH];
67 /* First see if there is an engine specific build! */
68 g_SourceMod.BuildPath(Path_SM,
71 #if defined METAMOD_PLAPI_VERSION
72 #if defined ORANGEBOX_BUILD
73 "extensions/auto.2.ep2/%s",
75 "extensions/auto.2.ep1/%s",
76 #endif //ORANGEBOX_BUILD
77 #else //METAMOD_PLAPI_VERSION
78 "extensions/auto.1.ep1/%s",
79 #endif //METAMOD_PLAPI_VERSION
82 /* Try the "normal" version */
83 if (!g_LibSys.IsPathFile(path))
85 g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
88 Initialize(filename, path);
91 bool CRemoteExtension::Load(char *error, size_t maxlength)
93 if (!PerformAPICheck(error, maxlength))
99 if (!CExtension::Load(error, maxlength))
108 bool CLocalExtension::Load(char *error, size_t maxlength)
110 m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
117 typedef IExtensionInterface *(*GETAPI)();
118 GETAPI pfnGetAPI = NULL;
120 if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
122 m_pLib->CloseLibrary();
124 snprintf(error, maxlength, "Unable to find extension entry point");
128 m_pAPI = pfnGetAPI();
130 /* Check pointer and version */
131 if (!PerformAPICheck(error, maxlength))
133 m_pLib->CloseLibrary();
140 if (m_pAPI->IsMetamodExtension())
143 m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
146 if (!CExtension::Load(error, maxlength))
148 if (m_pAPI->IsMetamodExtension())
153 g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
157 m_pLib->CloseLibrary();
166 void CRemoteExtension::Unload()
170 void CLocalExtension::Unload()
172 if (m_pAPI != NULL && m_PlId)
174 char temp_buffer[255];
175 g_pMMPlugins->Unload(m_PlId, true, temp_buffer, sizeof(temp_buffer));
181 m_pLib->CloseLibrary();
186 bool CRemoteExtension::IsExternal()
191 bool CLocalExtension::IsExternal()
196 CExtension::~CExtension()
201 bool CExtension::PerformAPICheck(char *error, size_t maxlength)
205 snprintf(error, maxlength, "No IExtensionInterface instance provided");
209 if (m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
211 snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
218 bool CExtension::Load(char *error, size_t maxlength)
221 if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
228 /* Check if we're past load time */
229 if (!g_SourceMod.IsMapLoading())
231 m_pAPI->OnExtensionsAllLoaded();
238 void CExtension::CreateIdentity()
240 if (m_pIdentToken != NULL)
245 m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
248 void CExtension::DestroyIdentity()
250 if (m_pIdentToken == NULL)
255 g_ShareSys.DestroyIdentity(m_pIdentToken);
256 m_pIdentToken = NULL;
259 void CExtension::MarkAllLoaded()
261 assert(m_bFullyLoaded == false);
264 m_bFullyLoaded = true;
265 m_pAPI->OnExtensionsAllLoaded();
269 void CExtension::AddPlugin(CPlugin *pPlugin)
271 /* Unfortunately we have to do this :( */
272 if (m_Dependents.find(pPlugin) != m_Dependents.end())
274 m_Dependents.push_back(pPlugin);
278 void CExtension::SetError(const char *error)
280 m_Error.assign(error);
283 IExtensionInterface *CExtension::GetAPI()
288 const char *CExtension::GetFilename()
290 return m_File.c_str();
293 IdentityToken_t *CExtension::GetIdentity()
295 return m_pIdentToken;
298 bool CRemoteExtension::IsLoaded()
300 return (m_pAPI != NULL);
303 bool CLocalExtension::IsLoaded()
305 return (m_pLib != NULL);
308 void CExtension::AddDependency(IfaceInfo *pInfo)
310 if (m_Deps.find(*pInfo) == m_Deps.end())
312 m_Deps.push_back(*pInfo);
316 bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
318 return (i1.iface == i2.iface) && (i1.owner == i2.owner);
321 void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
327 List<IfaceInfo>::iterator iter;
328 for (iter = m_ChildDeps.begin();
329 iter != m_ChildDeps.end();
332 IfaceInfo &other = (*iter);
339 m_ChildDeps.push_back(info);
342 ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
344 List<IfaceInfo>::iterator iter = m_Deps.begin();
346 if (iter == m_Deps.end())
353 *pOwner = (*iter).owner;
357 *pInterface = (*iter).iface;
360 List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
362 return (ITERATOR *)pIter;
365 bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
367 List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
368 List<IfaceInfo>::iterator _iter;
370 if (_iter == m_Deps.end())
379 *pOwner = (*_iter).owner;
383 *pInterface = (*_iter).iface;
388 if (_iter == m_Deps.end())
396 void CExtension::FreeDependencyIterator(ITERATOR *iter)
398 List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
403 void CExtension::AddInterface(SMInterface *pInterface)
405 m_Interfaces.push_back(pInterface);
408 bool CExtension::IsRunning(char *error, size_t maxlength)
414 snprintf(error, maxlength, "%s", m_Error.c_str());
419 return m_pAPI->QueryRunning(error, maxlength);
422 void CExtension::AddLibrary(const char *library)
424 m_Libraries.push_back(library);
427 /*********************
428 * EXTENSION MANAGER *
429 *********************/
431 void CExtensionManager::OnSourceModAllInitialized()
433 g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
434 g_PluginSys.AddPluginsListener(this);
435 g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
436 g_ShareSys.AddInterface(NULL, this);
439 void CExtensionManager::OnSourceModShutdown()
441 g_RootMenu.RemoveRootConsoleCommand("exts", this);
442 g_ShareSys.DestroyIdentType(g_ExtType);
445 void CExtensionManager::Shutdown()
447 List<CExtension *>::iterator iter;
449 while ((iter = m_Libs.begin()) != m_Libs.end())
451 UnloadExtension((*iter));
455 void CExtensionManager::TryAutoload()
457 char path[PLATFORM_MAX_PATH];
459 g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
461 IDirectory *pDir = g_LibSys.OpenDirectory(path);
469 while (pDir->MoreFiles())
471 if (pDir->IsEntryDirectory())
477 lfile = pDir->GetEntryName();
479 if (len <= 9) /* size of ".autoload" */
485 if (strcmp(&lfile[len - 9], ".autoload") != 0)
491 char file[PLATFORM_MAX_PATH];
492 len = UTIL_Format(file, sizeof(file), "%s", lfile);
493 strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
495 LoadAutoExtension(file);
501 IExtension *CExtensionManager::LoadAutoExtension(const char *path)
503 if (!strstr(path, "." PLATFORM_LIB_EXT))
505 char newpath[PLATFORM_MAX_PATH];
506 g_LibSys.PathFormat(newpath, sizeof(newpath), "%s.%s", path, PLATFORM_LIB_EXT);
507 return LoadAutoExtension(newpath);
510 IExtension *pAlready;
511 if ((pAlready=FindExtensionByFile(path)) != NULL)
517 CExtension *p = new CLocalExtension(path);
519 /* We put us in the list beforehand so extensions that check for each other
520 * won't recursively load each other.
524 if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
526 g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
533 IExtension *CExtensionManager::FindExtensionByFile(const char *file)
535 List<CExtension *>::iterator iter;
538 /* Chomp off the path */
539 char lookup[PLATFORM_MAX_PATH];
540 g_LibSys.GetFileFromPath(lookup, sizeof(lookup), file);
542 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
545 char short_file[PLATFORM_MAX_PATH];
546 g_LibSys.GetFileFromPath(short_file, sizeof(short_file), pExt->GetFilename());
547 if (strcmp(lookup, short_file) == 0)
553 /* If we got no results, test if there was a platform extension.
556 if (!strstr(file, "." PLATFORM_LIB_EXT))
558 char path[PLATFORM_MAX_PATH];
559 UTIL_Format(path, sizeof(path), "%s.%s", file, PLATFORM_LIB_EXT);
560 return FindExtensionByFile(path);
566 IExtension *CExtensionManager::FindExtensionByName(const char *ext)
568 List<CExtension *>::iterator iter;
570 IExtensionInterface *pAPI;
573 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
576 if (!pExt->IsLoaded())
580 if ((pAPI = pExt->GetAPI()) == NULL)
584 name = pAPI->GetExtensionName();
589 if (strcmp(name, ext) == 0)
598 IExtension *CExtensionManager::LoadExtension(const char *file, char *error, size_t maxlength)
600 IExtension *pAlready;
601 if ((pAlready=FindExtensionByFile(file)) != NULL)
606 CExtension *pExt = new CLocalExtension(file);
608 if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
615 /* :TODO: do QueryRunning check if the map is loaded */
617 m_Libs.push_back(pExt);
622 void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
624 CExtension *pExt = (CExtension *)pRequester;
625 CExtension *pOwner = (CExtension *)pInfo->owner;
627 pExt->AddDependency(pInfo);
629 IExtensionInterface *pAPI = pExt->GetAPI();
630 if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
632 pOwner->AddChildDependent(pExt, pInfo->iface);
636 void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
638 CExtension *pExt = (CExtension *)pOwner;
640 pExt->AddInterface(pInterface);
643 void CExtensionManager::BindChildPlugin( IExtension *pParent, CPlugin *pPlugin )
645 CExtension *pExt = (CExtension *)pParent;
647 pExt->AddPlugin(pPlugin);
650 void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
652 List<CExtension *>::iterator iter;
654 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
656 (*iter)->DropRefsTo((CPlugin *)plugin);
660 CExtension *CExtensionManager::FindByOrder(unsigned int num)
662 if (num < 1 || num > m_Libs.size())
667 List<CExtension *>::iterator iter = m_Libs.begin();
669 while (iter != m_Libs.end())
681 bool CExtensionManager::UnloadExtension(IExtension *_pExt)
688 CExtension *pExt = (CExtension *)_pExt;
690 if (m_Libs.find(pExt) == m_Libs.end())
695 /* First remove us from internal lists */
696 g_ShareSys.RemoveInterfaces(_pExt);
699 List<CExtension *> UnloadQueue;
701 /* Handle dependencies */
702 if (pExt->IsLoaded())
704 /* Unload any dependent plugins */
705 List<CPlugin *>::iterator p_iter = pExt->m_Dependents.begin();
706 while (p_iter != pExt->m_Dependents.end())
708 /* We have to manually unlink ourselves here, since we're no longer being managed */
709 g_PluginSys.UnloadPlugin((*p_iter));
710 p_iter = pExt->m_Dependents.erase(p_iter);
713 List<String>::iterator s_iter;
714 for (s_iter = pExt->m_Libraries.begin();
715 s_iter != pExt->m_Libraries.end();
718 g_PluginSys.OnLibraryAction((*s_iter).c_str(), false, true);
721 /* Notify and/or unload all dependencies */
722 List<CExtension *>::iterator c_iter;
724 IExtensionInterface *pAPI;
725 for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
728 if ((pAPI=pDep->GetAPI()) == NULL)
736 /* Now, get its dependency list */
737 bool dropped = false;
738 List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
739 while (i_iter != pDep->m_Deps.end())
741 if ((*i_iter).owner == _pExt)
743 if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
748 UnloadQueue.push_back(pDep);
751 pAPI->NotifyInterfaceDrop((*i_iter).iface);
752 i_iter = pDep->m_Deps.erase(i_iter);
759 /* Flush out any back references to this plugin */
760 i_iter = pDep->m_ChildDeps.begin();
761 while (i_iter != pDep->m_ChildDeps.end())
763 if ((*i_iter).owner == pExt)
765 i_iter = pDep->m_ChildDeps.erase(i_iter);
774 /* Unbind our natives from Core */
775 pExt->DropEverything();
777 /* Tell it to unload */
778 pAPI = pExt->GetAPI();
779 pAPI->OnExtensionUnload();
782 IdentityToken_t *pIdentity;
783 if ((pIdentity = pExt->GetIdentity()) != NULL)
785 SMGlobalClass *glob = SMGlobalClass::head;
788 glob->OnSourceModIdentityDropped(pIdentity);
789 glob = glob->m_pGlobalClassNext;
796 List<CExtension *>::iterator iter;
797 for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
799 /* NOTE: This is safe because the unload function backs out of anything not present */
800 UnloadExtension((*iter));
806 void CExtensionManager::MarkAllLoaded()
808 List<CExtension *>::iterator iter;
811 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
814 if (!pExt->IsLoaded())
818 if (pExt->m_bFullyLoaded)
822 pExt->MarkAllLoaded();
826 void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
828 /* This function doesn't really need to do anything now. We make sure the
829 * other extension is loaded, but handling of dependencies is really done
830 * by the interface fetcher.
832 if (required || autoload)
834 LoadAutoExtension(file);
838 void CExtensionManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
840 int argcount = command.ArgC();
843 const char *cmd = command.Arg(2);
844 if (strcmp(cmd, "list") == 0)
846 List<CExtension *>::iterator iter;
848 unsigned int num = 1;
849 switch (m_Libs.size())
853 g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
858 g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
863 g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
867 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
870 if (pExt->IsLoaded())
873 if (!pExt->IsRunning(error, sizeof(error)))
875 g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
879 IExtensionInterface *pAPI = pExt->GetAPI();
880 const char *name = pAPI->GetExtensionName();
881 const char *version = pAPI->GetExtensionVerString();
882 const char *descr = pAPI->GetExtensionDescription();
883 g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
886 g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
891 else if (strcmp(cmd, "info") == 0)
895 g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
899 const char *sId = command.Arg(3);
900 unsigned int id = atoi(sId);
903 g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
907 if (m_Libs.size() == 0)
909 g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
913 if (id > m_Libs.size())
915 g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
919 List<CExtension *>::iterator iter = m_Libs.begin();
920 CExtension *pExt = NULL;
921 while (iter != m_Libs.end())
930 /* This should never happen */
933 g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
937 if (!pExt->IsLoaded())
939 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
940 g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
945 if (!pExt->IsRunning(error, sizeof(error)))
947 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
948 g_RootMenu.ConsolePrint(" Loaded: Yes");
949 g_RootMenu.ConsolePrint(" Running: No (%s)", error);
953 IExtensionInterface *pAPI = pExt->GetAPI();
954 g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
955 g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
956 g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
957 g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
958 g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
960 if (pExt->IsExternal())
962 g_RootMenu.ConsolePrint(" Method: Loaded by Metamod:Source, attached to SourceMod");
964 else if (pAPI->IsMetamodExtension())
966 g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod, attached to Metamod:Source");
970 g_RootMenu.ConsolePrint(" Method: Loaded by SourceMod");
976 else if (strcmp(cmd, "unload") == 0)
980 g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
984 const char *arg = command.Arg(3);
985 unsigned int num = atoi(arg);
986 CExtension *pExt = FindByOrder(num);
990 g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
994 if (argcount > 4 && pExt->unload_code)
996 const char *unload = command.Arg(4);
997 if (pExt->unload_code == (unsigned)atoi(unload))
999 char filename[PLATFORM_MAX_PATH];
1000 snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
1001 UnloadExtension(pExt);
1002 g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
1006 g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
1011 if (!pExt->IsLoaded()
1012 || (!pExt->m_ChildDeps.size() && !pExt->m_Dependents.size()))
1014 char filename[PLATFORM_MAX_PATH];
1015 snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
1016 UnloadExtension(pExt);
1017 g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
1022 List<CPlugin *> plugins;
1023 if (pExt->m_ChildDeps.size())
1025 g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
1026 List<CExtension *>::iterator iter;
1028 /* Get list of all extensions */
1029 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1031 List<IfaceInfo>::iterator i_iter;
1033 if (!pOther->IsLoaded() || pOther == pExt)
1037 /* Get their dependencies */
1038 for (i_iter=pOther->m_Deps.begin();
1039 i_iter!=pOther->m_Deps.end();
1042 /* Is this dependency to us? */
1043 if ((*i_iter).owner != pExt)
1047 /* Will our dependent care? */
1048 if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
1050 g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
1051 /* Add to plugin unload list */
1052 List<CPlugin *>::iterator p_iter;
1053 for (p_iter=pOther->m_Dependents.begin();
1054 p_iter!=pOther->m_Dependents.end();
1057 if (plugins.find((*p_iter)) == plugins.end())
1059 plugins.push_back((*p_iter));
1066 if (pExt->m_Dependents.size())
1068 g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
1069 List<CPlugin *>::iterator iter;
1071 for (iter = pExt->m_Dependents.begin(); iter != pExt->m_Dependents.end(); iter++)
1074 if (plugins.find(pPlugin) == plugins.end())
1076 plugins.push_back(pPlugin);
1079 for (iter = plugins.begin(); iter != plugins.end(); iter++)
1082 g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
1085 srand(static_cast<int>(time(NULL)));
1086 pExt->unload_code = (rand() % 877) + 123; //123 to 999
1087 g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
1088 g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
1095 g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
1096 g_RootMenu.DrawGenericOption("info", "Extra extension information");
1097 g_RootMenu.DrawGenericOption("list", "List extensions");
1098 g_RootMenu.DrawGenericOption("unload", "Unload an extension");
1101 CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
1103 if (ptr->type == g_ExtType)
1105 return (CExtension *)(ptr->ptr);
1111 CExtensionManager::CExtensionManager()
1115 CExtensionManager::~CExtensionManager()
1119 void CExtensionManager::AddLibrary(IExtension *pSource, const char *library)
1121 CExtension *pExt = (CExtension *)pSource;
1122 pExt->AddLibrary(library);
1123 g_PluginSys.OnLibraryAction(library, false, false);
1126 bool CExtensionManager::LibraryExists(const char *library)
1130 for (List<CExtension *>::iterator iter = m_Libs.begin();
1131 iter != m_Libs.end();
1135 for (List<String>::iterator s_iter = pExt->m_Libraries.begin();
1136 s_iter != pExt->m_Libraries.end();
1139 if ((*s_iter).compare(library) == 0)
1149 IExtension *CExtensionManager::LoadExternal(IExtensionInterface *pInterface,
1150 const char *filepath,
1151 const char *filename,
1155 IExtension *pAlready;
1156 if ((pAlready=FindExtensionByFile(filename)) != NULL)
1161 CExtension *pExt = new CRemoteExtension(pInterface, filename, filepath);
1163 if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
1170 m_Libs.push_back(pExt);
1175 void CExtensionManager::CallOnCoreMapStart(edict_t *pEdictList, int edictCount, int clientMax)
1177 IExtensionInterface *pAPI;
1178 List<CExtension *>::iterator iter;
1180 for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
1182 if ((pAPI = (*iter)->GetAPI()) == NULL)
1186 if (pAPI->GetExtensionVersion() > 3)
1188 pAPI->OnCoreMapStart(pEdictList, edictCount, clientMax);