core/systems/ExtensionSys.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1380 eeb8d3b56155
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
dvander@370
     1
/**
ds@653
     2
 * vim: set ts=4 :
ds@1330
     3
 * =============================================================================
dvander@1231
     4
 * SourceMod
dvander@1231
     5
 * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
ds@1330
     6
 * =============================================================================
dvander@370
     7
 *
ds@1330
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1330
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330
    10
 * Free Software Foundation.
dvander@1231
    11
 * 
ds@1330
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1330
    15
 * details.
dvander@1231
    16
 *
ds@1330
    17
 * You should have received a copy of the GNU General Public License along with
ds@1330
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
dvander@1231
    19
 *
ds@1330
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1330
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1330
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1330
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330
    27
 * or <http://www.sourcemod.net/license.php>.
dvander@370
    28
 *
dvander@370
    29
 * Version: $Id$
dvander@370
    30
 */
dvander@370
    31
dvander@397
    32
#include <stdlib.h>
dvander@298
    33
#include "ExtensionSys.h"
dvander@298
    34
#include "LibrarySys.h"
dvander@298
    35
#include "ShareSys.h"
dvander@592
    36
#include "Logger.h"
dvander@304
    37
#include "sourcemm_api.h"
dvander@310
    38
#include "sm_srvcmds.h"
dvander@397
    39
#include "sm_stringutil.h"
dvander@298
    40
dvander@298
    41
CExtensionManager g_Extensions;
dvander@298
    42
IdentityType_t g_ExtType;
dvander@298
    43
ds@755
    44
CExtension::CExtension(const char *filename, char *error, size_t maxlength)
dvander@298
    45
{
dvander@298
    46
	m_File.assign(filename);
dvander@298
    47
	m_pAPI = NULL;
dvander@298
    48
	m_pIdentToken = NULL;
dvander@304
    49
	m_PlId = 0;
dvander@311
    50
	unload_code = 0;
dvander@315
    51
	m_FullyLoaded = false;
dvander@298
    52
ds@652
    53
	char path[PLATFORM_MAX_PATH];
dvander@317
    54
	g_SourceMod.BuildPath(Path_SM, path, PLATFORM_MAX_PATH, "extensions/%s", filename);
dvander@941
    55
	m_Path.assign(path);
dvander@298
    56
dvander@941
    57
	m_pLib = NULL;
dvander@941
    58
}
dvander@941
    59
dvander@941
    60
bool CExtension::Load(char *error, size_t maxlength)
dvander@941
    61
{
dvander@941
    62
	m_pLib = g_LibSys.OpenLibrary(m_Path.c_str(), error, maxlength);
dvander@298
    63
dvander@298
    64
	if (m_pLib == NULL)
dvander@298
    65
	{
dvander@941
    66
		return false;
dvander@298
    67
	}
dvander@298
    68
dvander@298
    69
	typedef IExtensionInterface *(*GETAPI)();
dvander@298
    70
	GETAPI pfnGetAPI = NULL;
dvander@298
    71
dvander@298
    72
	if ((pfnGetAPI=(GETAPI)m_pLib->GetSymbolAddress("GetSMExtAPI")) == NULL)
dvander@298
    73
	{
dvander@298
    74
		m_pLib->CloseLibrary();
dvander@298
    75
		m_pLib = NULL;
ds@755
    76
		snprintf(error, maxlength, "Unable to find extension entry point");
dvander@941
    77
		return false;
dvander@298
    78
	}
dvander@298
    79
dvander@298
    80
	m_pAPI = pfnGetAPI();
dvander@298
    81
	if (!m_pAPI || m_pAPI->GetExtensionVersion() > SMINTERFACE_EXTENSIONAPI_VERSION)
dvander@298
    82
	{
dvander@298
    83
		m_pLib->CloseLibrary();
dvander@298
    84
		m_pLib = NULL;
ds@755
    85
		snprintf(error, maxlength, "Extension version is too new to load (%d, max is %d)", m_pAPI->GetExtensionVersion(), SMINTERFACE_EXTENSIONAPI_VERSION);
dvander@941
    86
		return false;
dvander@298
    87
	}
dvander@298
    88
dvander@298
    89
	if (m_pAPI->IsMetamodExtension())
dvander@298
    90
	{
dvander@304
    91
		bool already;
dvander@941
    92
		m_PlId = g_pMMPlugins->Load(m_Path.c_str(), g_PLID, already, error, maxlength);
dvander@298
    93
	}
dvander@298
    94
dvander@868
    95
	m_pIdentToken = g_ShareSys.CreateIdentity(g_ExtType, this);
dvander@298
    96
ds@755
    97
	if (!m_pAPI->OnExtensionLoad(this, &g_ShareSys, error, maxlength, !g_SourceMod.IsMapLoading()))
dvander@298
    98
	{
dvander@298
    99
		if (m_pAPI->IsMetamodExtension())
dvander@298
   100
		{
dvander@304
   101
			if (m_PlId)
dvander@304
   102
			{
dvander@304
   103
				char dummy[255];
dvander@304
   104
				g_pMMPlugins->Unload(m_PlId, true, dummy, sizeof(dummy));
dvander@304
   105
				m_PlId = 0;
dvander@304
   106
			}
dvander@298
   107
		}
dvander@298
   108
		m_pAPI = NULL;
dvander@298
   109
		m_pLib->CloseLibrary();
dvander@298
   110
		m_pLib = NULL;
dvander@298
   111
		g_ShareSys.DestroyIdentity(m_pIdentToken);
dvander@298
   112
		m_pIdentToken = NULL;
dvander@941
   113
		return false;
dvander@315
   114
	} else {
dvander@315
   115
		/* Check if we're past load time */
dvander@315
   116
		if (!g_SourceMod.IsMapLoading())
dvander@315
   117
		{
dvander@315
   118
			m_pAPI->OnExtensionsAllLoaded();
dvander@315
   119
		}
dvander@298
   120
	}
dvander@941
   121
dvander@941
   122
	return true;
dvander@298
   123
}
dvander@298
   124
dvander@298
   125
CExtension::~CExtension()
dvander@298
   126
{
dvander@298
   127
	if (m_pAPI)
dvander@298
   128
	{
dvander@304
   129
		if (m_PlId)
dvander@304
   130
		{
dvander@304
   131
			g_pMMPlugins->Unload(m_PlId, true, NULL, 0);
dvander@304
   132
		}
dvander@298
   133
	}
dvander@298
   134
dvander@298
   135
	if (m_pIdentToken)
dvander@298
   136
	{
dvander@298
   137
		g_ShareSys.DestroyIdentity(m_pIdentToken);
dvander@298
   138
	}
dvander@298
   139
dvander@298
   140
	if (m_pLib)
dvander@298
   141
	{
dvander@298
   142
		m_pLib->CloseLibrary();
dvander@298
   143
	}
dvander@298
   144
}
dvander@298
   145
dvander@315
   146
void CExtension::MarkAllLoaded()
dvander@315
   147
{
dvander@315
   148
	assert(m_FullyLoaded == false);
dvander@315
   149
	if (!m_FullyLoaded)
dvander@315
   150
	{
dvander@315
   151
		m_FullyLoaded = true;
dvander@315
   152
		m_pAPI->OnExtensionsAllLoaded();
dvander@315
   153
	}
dvander@315
   154
}
dvander@315
   155
dvander@305
   156
void CExtension::AddPlugin(IPlugin *pPlugin)
dvander@305
   157
{
dvander@868
   158
	/* Unfortunately we have to do this :( */
dvander@868
   159
	if (m_Plugins.find(pPlugin) != m_Plugins.end())
dvander@868
   160
	{
dvander@868
   161
		m_Plugins.push_back(pPlugin);
dvander@868
   162
	}
dvander@305
   163
}
dvander@305
   164
dvander@305
   165
void CExtension::RemovePlugin(IPlugin *pPlugin)
dvander@305
   166
{
dvander@305
   167
	m_Plugins.remove(pPlugin);
dvander@1121
   168
dvander@1121
   169
	List<WeakNative>::iterator iter = m_WeakNatives.begin();
dvander@1121
   170
	while (iter != m_WeakNatives.end())
dvander@1121
   171
	{
dvander@1121
   172
		if ((*iter).pl == pPlugin)
dvander@1121
   173
		{
dvander@1121
   174
			iter = m_WeakNatives.erase(iter);
dvander@1121
   175
		} else {
dvander@1121
   176
			iter++;
dvander@1121
   177
		}
dvander@1121
   178
	}
dvander@305
   179
}
dvander@305
   180
dvander@298
   181
void CExtension::SetError(const char *error)
dvander@298
   182
{
dvander@298
   183
	m_Error.assign(error);
dvander@298
   184
}
dvander@298
   185
dvander@298
   186
IExtensionInterface *CExtension::GetAPI()
dvander@298
   187
{
dvander@298
   188
	return m_pAPI;
dvander@298
   189
}
dvander@298
   190
dvander@298
   191
const char *CExtension::GetFilename()
dvander@298
   192
{
dvander@298
   193
	return m_File.c_str();
dvander@298
   194
}
dvander@298
   195
dvander@298
   196
IdentityToken_t *CExtension::GetIdentity()
dvander@298
   197
{
dvander@298
   198
	return m_pIdentToken;
dvander@298
   199
}
dvander@298
   200
dvander@298
   201
bool CExtension::IsLoaded()
dvander@298
   202
{
dvander@298
   203
	return (m_pLib != NULL);
dvander@298
   204
}
dvander@298
   205
dvander@304
   206
void CExtension::AddDependency(IfaceInfo *pInfo)
dvander@304
   207
{
dvander@304
   208
	m_Deps.push_back(*pInfo);
dvander@304
   209
}
dvander@304
   210
dvander@1150
   211
bool operator ==(const IfaceInfo &i1, const IfaceInfo &i2)
dvander@1150
   212
{
dvander@1150
   213
	return (i1.iface == i2.iface) && (i1.owner == i2.owner);
dvander@1150
   214
}
dvander@1150
   215
dvander@1150
   216
void CExtension::AddChildDependent(CExtension *pOther, SMInterface *iface)
dvander@1150
   217
{
dvander@1150
   218
	IfaceInfo info;
dvander@1150
   219
	info.iface = iface;
dvander@1150
   220
	info.owner = pOther;
dvander@1150
   221
dvander@1150
   222
	List<IfaceInfo>::iterator iter;
dvander@1150
   223
	for (iter = m_ChildDeps.begin();
dvander@1150
   224
		 iter != m_ChildDeps.end();
dvander@1150
   225
		 iter++)
dvander@1150
   226
	{
dvander@1150
   227
		IfaceInfo &other = (*iter);
dvander@1150
   228
		if (other == info)
dvander@1150
   229
		{
dvander@1150
   230
			return;
dvander@1150
   231
		}
dvander@1150
   232
	}
dvander@1150
   233
dvander@1150
   234
	m_ChildDeps.push_back(info);
dvander@1150
   235
}
dvander@1150
   236
dvander@304
   237
ITERATOR *CExtension::FindFirstDependency(IExtension **pOwner, SMInterface **pInterface)
dvander@304
   238
{
dvander@304
   239
	List<IfaceInfo>::iterator iter = m_Deps.begin();
dvander@304
   240
dvander@304
   241
	if (iter == m_Deps.end())
dvander@304
   242
	{
dvander@304
   243
		return NULL;
dvander@304
   244
	}
dvander@304
   245
dvander@304
   246
	if (pOwner)
dvander@304
   247
	{
dvander@304
   248
		*pOwner = (*iter).owner;
dvander@304
   249
	}
dvander@304
   250
	if (pInterface)
dvander@304
   251
	{
dvander@304
   252
		*pInterface = (*iter).iface;
dvander@304
   253
	}
dvander@304
   254
dvander@304
   255
	List<IfaceInfo>::iterator *pIter = new List<IfaceInfo>::iterator(iter);
dvander@304
   256
dvander@304
   257
	return (ITERATOR *)pIter;
dvander@304
   258
}
dvander@304
   259
dvander@304
   260
bool CExtension::FindNextDependency(ITERATOR *iter, IExtension **pOwner, SMInterface **pInterface)
dvander@304
   261
{
dvander@304
   262
	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
dvander@304
   263
	List<IfaceInfo>::iterator _iter;
dvander@304
   264
dvander@304
   265
	if (_iter == m_Deps.end())
dvander@304
   266
	{
dvander@304
   267
		return false;
dvander@304
   268
	}
dvander@304
   269
dvander@304
   270
	_iter++;
dvander@304
   271
dvander@304
   272
	if (pOwner)
dvander@304
   273
	{
dvander@304
   274
		*pOwner = (*_iter).owner;
dvander@304
   275
	}
dvander@304
   276
	if (pInterface)
dvander@304
   277
	{
dvander@304
   278
		*pInterface = (*_iter).iface;
dvander@304
   279
	}
dvander@304
   280
dvander@304
   281
	*pIter = _iter;
dvander@304
   282
dvander@304
   283
	if (_iter == m_Deps.end())
dvander@304
   284
	{
dvander@304
   285
		return false;
dvander@304
   286
	}
dvander@304
   287
dvander@304
   288
	return true;
dvander@304
   289
}
dvander@304
   290
dvander@304
   291
void CExtension::FreeDependencyIterator(ITERATOR *iter)
dvander@304
   292
{
dvander@304
   293
	List<IfaceInfo>::iterator *pIter = (List<IfaceInfo>::iterator *)iter;
dvander@304
   294
dvander@304
   295
	delete pIter;
dvander@304
   296
}
dvander@304
   297
dvander@304
   298
void CExtension::AddInterface(SMInterface *pInterface)
dvander@304
   299
{
dvander@304
   300
	m_Interfaces.push_back(pInterface);
dvander@304
   301
}
dvander@304
   302
dvander@315
   303
bool CExtension::IsRunning(char *error, size_t maxlength)
dvander@315
   304
{
dvander@315
   305
	if (!IsLoaded())
dvander@315
   306
	{
dvander@315
   307
		if (error)
dvander@315
   308
		{
dvander@315
   309
			snprintf(error, maxlength, "%s", m_Error.c_str());
dvander@315
   310
		}
dvander@315
   311
		return false;
dvander@315
   312
	}
dvander@315
   313
dvander@315
   314
	return m_pAPI->QueryRunning(error, maxlength);
dvander@315
   315
}
dvander@315
   316
dvander@304
   317
/*********************
dvander@304
   318
 * EXTENSION MANAGER *
dvander@304
   319
 *********************/
dvander@304
   320
dvander@298
   321
void CExtensionManager::OnSourceModAllInitialized()
dvander@298
   322
{
dvander@298
   323
	g_ExtType = g_ShareSys.CreateIdentType("EXTENSION");
dvander@305
   324
	g_PluginSys.AddPluginsListener(this);
dvander@310
   325
	g_RootMenu.AddRootConsoleCommand("exts", "Manage extensions", this);
dvander@336
   326
	g_ShareSys.AddInterface(NULL, this);
dvander@298
   327
}
dvander@298
   328
dvander@298
   329
void CExtensionManager::OnSourceModShutdown()
dvander@298
   330
{
dvander@310
   331
	g_RootMenu.RemoveRootConsoleCommand("exts", this);
dvander@298
   332
	g_ShareSys.DestroyIdentType(g_ExtType);
dvander@298
   333
}
dvander@298
   334
dvander@1018
   335
void CExtensionManager::Shutdown()
dvander@1018
   336
{
dvander@1018
   337
	List<CExtension *>::iterator iter;
dvander@1018
   338
dvander@1018
   339
	while ((iter = m_Libs.begin()) != m_Libs.end())
dvander@1018
   340
	{
dvander@1018
   341
		UnloadExtension((*iter));
dvander@1018
   342
	}
dvander@1018
   343
}
dvander@1018
   344
dvander@397
   345
void CExtensionManager::TryAutoload()
dvander@397
   346
{
dvander@397
   347
	char path[PLATFORM_MAX_PATH];
dvander@397
   348
dvander@397
   349
	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "extensions");
dvander@397
   350
dvander@397
   351
	IDirectory *pDir = g_LibSys.OpenDirectory(path);
dvander@397
   352
	if (!pDir)
dvander@397
   353
	{
dvander@397
   354
		return;
dvander@397
   355
	}
dvander@397
   356
dvander@397
   357
	const char *lfile;
dvander@397
   358
	size_t len;
dvander@397
   359
	while (pDir->MoreFiles())
dvander@397
   360
	{
dvander@397
   361
		if (pDir->IsEntryDirectory())
dvander@397
   362
		{
dvander@397
   363
			pDir->NextEntry();
dvander@397
   364
			continue;
dvander@397
   365
		}
dvander@397
   366
dvander@397
   367
		lfile = pDir->GetEntryName();
dvander@397
   368
		len = strlen(lfile);
dvander@397
   369
		if (len <= 9) /* size of ".autoload" */
dvander@397
   370
		{
dvander@397
   371
			pDir->NextEntry();
dvander@397
   372
			continue;
dvander@397
   373
		}
dvander@397
   374
dvander@397
   375
		if (strcmp(&lfile[len - 9], ".autoload") != 0)
dvander@397
   376
		{
dvander@397
   377
			pDir->NextEntry();
dvander@397
   378
			continue;
dvander@397
   379
		}
dvander@397
   380
dvander@397
   381
		char file[PLATFORM_MAX_PATH];
dvander@397
   382
		len = UTIL_Format(file, sizeof(file), "%s", lfile);
dvander@397
   383
		strcpy(&file[len - 9], ".ext." PLATFORM_LIB_EXT);
dvander@397
   384
dvander@397
   385
		LoadAutoExtension(file);
dvander@397
   386
		
dvander@397
   387
		pDir->NextEntry();
dvander@397
   388
	}
dvander@397
   389
}
dvander@397
   390
dvander@298
   391
IExtension *CExtensionManager::LoadAutoExtension(const char *path)
dvander@298
   392
{
dvander@315
   393
	if (!strstr(path, "." PLATFORM_LIB_EXT))
dvander@315
   394
	{
ds@652
   395
		char newpath[PLATFORM_MAX_PATH];
dvander@315
   396
		snprintf(newpath, PLATFORM_MAX_PATH, "%s.%s", path, PLATFORM_LIB_EXT);
dvander@315
   397
		return LoadAutoExtension(newpath);
dvander@315
   398
	}
dvander@315
   399
dvander@304
   400
	IExtension *pAlready;
dvander@304
   401
	if ((pAlready=FindExtensionByFile(path)) != NULL)
dvander@304
   402
	{
dvander@304
   403
		return pAlready;
dvander@304
   404
	}
dvander@304
   405
dvander@298
   406
	char error[256];
dvander@298
   407
	CExtension *p = new CExtension(path, error, sizeof(error));
dvander@298
   408
dvander@941
   409
	/* We put us in the list beforehand so extensions that check for each other
dvander@941
   410
	 * won't recursively load each other.
dvander@941
   411
	 */
dvander@941
   412
	m_Libs.push_back(p);
dvander@941
   413
dvander@941
   414
	if (!p->Load(error, sizeof(error)) || !p->IsLoaded())
dvander@298
   415
	{
dvander@305
   416
		g_Logger.LogError("[SM] Unable to load extension \"%s\": %s", path, error);
dvander@298
   417
		p->SetError(error);
dvander@298
   418
	}
dvander@298
   419
dvander@298
   420
	return p;
dvander@298
   421
}
dvander@298
   422
dvander@298
   423
IExtension *CExtensionManager::FindExtensionByFile(const char *file)
dvander@298
   424
{
dvander@298
   425
	List<CExtension *>::iterator iter;
dvander@298
   426
	CExtension *pExt;
dvander@298
   427
dvander@315
   428
	if (!strstr(file, "." PLATFORM_LIB_EXT))
dvander@315
   429
	{
dvander@315
   430
		char path[PLATFORM_MAX_PATH];
dvander@315
   431
		snprintf(path, PLATFORM_MAX_PATH, "%s.%s", file, PLATFORM_LIB_EXT);
dvander@315
   432
		return FindExtensionByFile(path);
dvander@315
   433
	}
dvander@315
   434
dvander@298
   435
	/* Make sure the file direction is right */
ds@652
   436
	char path[PLATFORM_MAX_PATH];
dvander@298
   437
	g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
dvander@298
   438
dvander@298
   439
	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@298
   440
	{
dvander@298
   441
		pExt = (*iter);
dvander@298
   442
		if (strcmp(pExt->GetFilename(), path) == 0)
dvander@298
   443
		{
dvander@298
   444
			return pExt;
dvander@298
   445
		}
dvander@298
   446
	}
dvander@298
   447
dvander@298
   448
	return NULL;
dvander@298
   449
}
dvander@298
   450
dvander@298
   451
IExtension *CExtensionManager::FindExtensionByName(const char *ext)
dvander@298
   452
{
dvander@298
   453
	List<CExtension *>::iterator iter;
dvander@298
   454
	CExtension *pExt;
dvander@298
   455
	IExtensionInterface *pAPI;
dvander@298
   456
	const char *name;
dvander@298
   457
dvander@298
   458
	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@298
   459
	{
dvander@298
   460
		pExt = (*iter);
dvander@298
   461
		if (!pExt->IsLoaded())
dvander@298
   462
		{
dvander@298
   463
			continue;
dvander@298
   464
		}
dvander@298
   465
		if ((pAPI = pExt->GetAPI()) == NULL)
dvander@298
   466
		{
dvander@298
   467
			continue;
dvander@298
   468
		}
dvander@298
   469
		name = pAPI->GetExtensionName();
dvander@298
   470
		if (!name)
dvander@298
   471
		{
dvander@298
   472
			continue;
dvander@298
   473
		}
dvander@298
   474
		if (strcmp(name, ext) == 0)
dvander@298
   475
		{
dvander@298
   476
			return pExt;
dvander@298
   477
		}
dvander@298
   478
	}
dvander@298
   479
dvander@298
   480
	return NULL;
dvander@298
   481
}
dvander@298
   482
ds@755
   483
IExtension *CExtensionManager::LoadExtension(const char *file, ExtensionLifetime lifetime, char *error, size_t maxlength)
dvander@298
   484
{
dvander@304
   485
	IExtension *pAlready;
dvander@304
   486
	if ((pAlready=FindExtensionByFile(file)) != NULL)
dvander@304
   487
	{
dvander@304
   488
		return pAlready;
dvander@304
   489
	}
dvander@304
   490
ds@755
   491
	CExtension *pExt = new CExtension(file, error, maxlength);
dvander@298
   492
dvander@298
   493
	/* :NOTE: lifetime is currently ignored */
dvander@298
   494
dvander@941
   495
	if (!pExt->Load(error, maxlength) || !pExt->IsLoaded())
dvander@298
   496
	{
dvander@298
   497
		delete pExt;
dvander@298
   498
		return NULL;
dvander@298
   499
	}
dvander@298
   500
dvander@315
   501
	/* :TODO: do QueryRunning check if the map is loaded */
dvander@315
   502
dvander@298
   503
	m_Libs.push_back(pExt);
dvander@298
   504
dvander@298
   505
	return pExt;
dvander@298
   506
}
dvander@298
   507
dvander@1150
   508
void CExtensionManager::BindDependency(IExtension *pRequester, IfaceInfo *pInfo)
dvander@298
   509
{
dvander@1150
   510
	CExtension *pExt = (CExtension *)pRequester;
dvander@1150
   511
	CExtension *pOwner = (CExtension *)pInfo->owner;
dvander@304
   512
dvander@304
   513
	pExt->AddDependency(pInfo);
dvander@1150
   514
dvander@1150
   515
	IExtensionInterface *pAPI = pExt->GetAPI();
dvander@1150
   516
	if (pAPI && !pAPI->QueryInterfaceDrop(pInfo->iface))
dvander@1150
   517
	{
dvander@1150
   518
		pOwner->AddChildDependent(pExt, pInfo->iface);
dvander@1150
   519
	}
dvander@304
   520
}
dvander@304
   521
dvander@304
   522
void CExtensionManager::AddInterface(IExtension *pOwner, SMInterface *pInterface)
dvander@304
   523
{
dvander@304
   524
	CExtension *pExt = (CExtension *)pOwner;
dvander@304
   525
dvander@304
   526
	pExt->AddInterface(pInterface);
dvander@298
   527
}
dvander@298
   528
dvander@305
   529
void CExtensionManager::BindChildPlugin(IExtension *pParent, IPlugin *pPlugin)
dvander@305
   530
{
dvander@305
   531
	CExtension *pExt = (CExtension *)pParent;
dvander@305
   532
dvander@305
   533
	pExt->AddPlugin(pPlugin);
dvander@305
   534
}
dvander@305
   535
dvander@305
   536
void CExtensionManager::OnPluginDestroyed(IPlugin *plugin)
dvander@305
   537
{
dvander@305
   538
	List<CExtension *>::iterator iter;
dvander@305
   539
dvander@305
   540
	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@305
   541
	{
dvander@305
   542
		(*iter)->RemovePlugin(plugin);
dvander@305
   543
	}
dvander@305
   544
}
dvander@305
   545
dvander@311
   546
CExtension *CExtensionManager::FindByOrder(unsigned int num)
dvander@311
   547
{
dvander@311
   548
	if (num < 1 || num > m_Libs.size())
dvander@311
   549
	{
dvander@311
   550
		return NULL;
dvander@311
   551
	}
dvander@311
   552
dvander@311
   553
	List<CExtension *>::iterator iter = m_Libs.begin();
dvander@311
   554
dvander@311
   555
	while (iter != m_Libs.end())
dvander@311
   556
	{
dvander@311
   557
		if (--num == 0)
dvander@311
   558
		{
dvander@311
   559
			return (*iter);
dvander@311
   560
		}
dvander@311
   561
		iter++;
dvander@311
   562
	}
dvander@311
   563
dvander@311
   564
	return NULL;
dvander@311
   565
}
dvander@311
   566
dvander@315
   567
void CExtensionManager::BindAllNativesToPlugin(IPlugin *pPlugin)
dvander@315
   568
{
dvander@315
   569
	List<CExtension *>::iterator iter;
dvander@315
   570
	CExtension *pExt;
dvander@315
   571
	IPluginContext *pContext = pPlugin->GetBaseContext();
dvander@315
   572
	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@315
   573
	{
dvander@315
   574
		pExt = (*iter);
dvander@315
   575
		if (!pExt->IsLoaded())
dvander@315
   576
		{
dvander@315
   577
			continue;
dvander@315
   578
		}
dvander@315
   579
		if (!pExt->m_Natives.size())
dvander@315
   580
		{
dvander@315
   581
			continue;
dvander@315
   582
		}
dvander@315
   583
		bool set = false;
dvander@315
   584
		List<const sp_nativeinfo_t *>::iterator n_iter;
dvander@315
   585
		const sp_nativeinfo_t *natives;
dvander@315
   586
		for (n_iter = pExt->m_Natives.begin();
dvander@315
   587
			 n_iter != pExt->m_Natives.end();
dvander@315
   588
			 n_iter++)
dvander@315
   589
		{
dvander@315
   590
			natives = (*n_iter);
faluco@1089
   591
			uint32_t idx;
dvander@315
   592
			unsigned int i=0;
dvander@315
   593
			while (natives[i].func != NULL && natives[i].name != NULL)
dvander@315
   594
			{
faluco@1089
   595
				if (pContext->BindNative(&natives[i]) == SP_ERROR_NONE)
dvander@315
   596
				{
faluco@1089
   597
					pContext->FindNativeByName(natives[i].name, &idx);
faluco@1089
   598
					if (!(pContext->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL))
faluco@1089
   599
					{
faluco@1089
   600
						set = true;
faluco@1112
   601
					} else {
dvander@1121
   602
						WeakNative wkn = WeakNative((CPlugin *)pPlugin, idx);
faluco@1112
   603
						pExt->m_WeakNatives.push_back(wkn);
faluco@1089
   604
					}
dvander@315
   605
				}
faluco@1089
   606
				i++;
dvander@315
   607
			}
dvander@315
   608
		}
dvander@315
   609
		if (set && (pExt->m_Plugins.find(pPlugin) == pExt->m_Plugins.end()))
dvander@315
   610
		{
dvander@315
   611
			/* For now, mark this plugin as a requirement.  Later we'll introduce native filtering. */
dvander@315
   612
			pExt->m_Plugins.push_back(pPlugin);
dvander@315
   613
		}
dvander@315
   614
	}
dvander@315
   615
}
dvander@315
   616
dvander@304
   617
bool CExtensionManager::UnloadExtension(IExtension *_pExt)
dvander@298
   618
{
dvander@304
   619
	if (!_pExt)
dvander@304
   620
	{
dvander@304
   621
		return false;
dvander@304
   622
	}
dvander@304
   623
dvander@304
   624
	CExtension *pExt = (CExtension *)_pExt;
dvander@304
   625
dvander@304
   626
	if (m_Libs.find(pExt) == m_Libs.end())
dvander@304
   627
	{
dvander@304
   628
		return false;
dvander@304
   629
	}
dvander@304
   630
dvander@304
   631
	/* First remove us from internal lists */
dvander@304
   632
	g_ShareSys.RemoveInterfaces(_pExt);
dvander@304
   633
	m_Libs.remove(pExt);
dvander@304
   634
dvander@304
   635
	List<CExtension *> UnloadQueue;
dvander@298
   636
dvander@304
   637
	/* Handle dependencies */
dvander@304
   638
	if (pExt->IsLoaded())
dvander@304
   639
	{
dvander@305
   640
		/* Unload any dependent plugins */
dvander@305
   641
		List<IPlugin *>::iterator p_iter = pExt->m_Plugins.begin();
dvander@305
   642
		while (p_iter != pExt->m_Plugins.end())
dvander@305
   643
		{
dvander@311
   644
			/* We have to manually unlink ourselves here, since we're no longer being managed */
dvander@305
   645
			g_PluginSys.UnloadPlugin((*p_iter));
dvander@311
   646
			p_iter = pExt->m_Plugins.erase(p_iter);
dvander@305
   647
		}
dvander@305
   648
faluco@1112
   649
		/* Unbound weak natives */
dvander@1121
   650
		List<WeakNative>::iterator wkn_iter;
faluco@1112
   651
		for (wkn_iter=pExt->m_WeakNatives.begin(); wkn_iter!=pExt->m_WeakNatives.end(); wkn_iter++)
faluco@1112
   652
		{
dvander@1121
   653
			WeakNative & wkn = (*wkn_iter);
dvander@1121
   654
			sp_context_t *ctx = wkn.pl->GetContext();
dvander@1121
   655
			ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
faluco@1112
   656
		}
faluco@1112
   657
dvander@304
   658
		/* Notify and/or unload all dependencies */
dvander@304
   659
		List<CExtension *>::iterator c_iter;
dvander@304
   660
		CExtension *pDep;
dvander@304
   661
		IExtensionInterface *pAPI;
dvander@304
   662
		for (c_iter = m_Libs.begin(); c_iter != m_Libs.end(); c_iter++)
dvander@304
   663
		{
dvander@304
   664
			pDep = (*c_iter);
dvander@304
   665
			if ((pAPI=pDep->GetAPI()) == NULL)
dvander@304
   666
			{
dvander@304
   667
				continue;
dvander@304
   668
			}
dvander@311
   669
			if (pDep == pExt)
dvander@311
   670
			{
dvander@311
   671
				continue;
dvander@311
   672
			}
dvander@304
   673
			/* Now, get its dependency list */
dvander@304
   674
			bool dropped = false;
dvander@304
   675
			List<IfaceInfo>::iterator i_iter = pDep->m_Deps.begin();
dvander@304
   676
			while (i_iter != pDep->m_Deps.end())
dvander@304
   677
			{
dvander@304
   678
				if ((*i_iter).owner == _pExt)
dvander@304
   679
				{
dvander@1150
   680
					if (!pAPI->QueryInterfaceDrop((*i_iter).iface))
dvander@304
   681
					{
dvander@1150
   682
						if (!dropped)
dvander@1150
   683
						{
dvander@1150
   684
							dropped = true;
dvander@1150
   685
							UnloadQueue.push_back(pDep);
dvander@1150
   686
						}
dvander@304
   687
					}
dvander@304
   688
					pAPI->NotifyInterfaceDrop((*i_iter).iface);
dvander@304
   689
					i_iter = pDep->m_Deps.erase(i_iter);
dvander@304
   690
				} else {
dvander@304
   691
					i_iter++;
dvander@304
   692
				}
dvander@304
   693
			}
dvander@1150
   694
			/* Flush out any back references to this plugin */
dvander@1150
   695
			i_iter = pDep->m_ChildDeps.begin();
dvander@1150
   696
			while (i_iter != pDep->m_ChildDeps.end())
dvander@1150
   697
			{
dvander@1150
   698
				if ((*i_iter).owner == pExt)
dvander@1150
   699
				{
dvander@1150
   700
					i_iter = pDep->m_ChildDeps.erase(i_iter);
dvander@1150
   701
				} else {
dvander@1150
   702
					i_iter++;
dvander@1150
   703
				}
dvander@1150
   704
			}
dvander@304
   705
		}
dvander@1202
   706
dvander@1202
   707
		/* Tell it to unload */
dvander@1202
   708
		pAPI = pExt->GetAPI();
dvander@1202
   709
		pAPI->OnExtensionUnload();
dvander@304
   710
	}
dvander@304
   711
dvander@1157
   712
	IdentityToken_t *pIdentity;
dvander@1157
   713
	if ((pIdentity = pExt->GetIdentity()) != NULL)
dvander@1157
   714
	{
dvander@1157
   715
		SMGlobalClass *glob = SMGlobalClass::head;
dvander@1157
   716
		while (glob)
dvander@1157
   717
		{
dvander@1157
   718
			glob->OnSourceModIdentityDropped(pIdentity);
dvander@1157
   719
			glob = glob->m_pGlobalClassNext;
dvander@1157
   720
		}
dvander@1157
   721
	}
dvander@1157
   722
dvander@1018
   723
	delete pExt;
dvander@1018
   724
dvander@304
   725
	List<CExtension *>::iterator iter;
dvander@304
   726
	for (iter=UnloadQueue.begin(); iter!=UnloadQueue.end(); iter++)
dvander@304
   727
	{
dvander@304
   728
		/* NOTE: This is safe because the unload function backs out of anything not present */
dvander@304
   729
		UnloadExtension((*iter));
dvander@304
   730
	}
dvander@304
   731
dvander@298
   732
	return true;
dvander@298
   733
}
dvander@310
   734
dvander@315
   735
void CExtensionManager::AddNatives(IExtension *pOwner, const sp_nativeinfo_t *natives)
dvander@315
   736
{
dvander@315
   737
	CExtension *pExt = (CExtension *)pOwner;
dvander@315
   738
dvander@315
   739
	pExt->m_Natives.push_back(natives);
dvander@315
   740
}
dvander@315
   741
dvander@315
   742
void CExtensionManager::MarkAllLoaded()
dvander@315
   743
{
dvander@315
   744
	List<CExtension *>::iterator iter;
dvander@315
   745
	CExtension *pExt;
dvander@315
   746
dvander@315
   747
	for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@315
   748
	{
dvander@315
   749
		pExt = (*iter);
dvander@315
   750
		if (!pExt->IsLoaded())
dvander@315
   751
		{
dvander@315
   752
			continue;
dvander@315
   753
		}
dvander@315
   754
		if (pExt->m_FullyLoaded)
dvander@315
   755
		{
dvander@315
   756
			continue;
dvander@315
   757
		}
dvander@315
   758
		pExt->MarkAllLoaded();
dvander@315
   759
	}
dvander@315
   760
}
dvander@315
   761
dvander@324
   762
void CExtensionManager::AddDependency(IExtension *pSource, const char *file, bool required, bool autoload)
dvander@324
   763
{
dvander@941
   764
	/* This function doesn't really need to do anything now.  We make sure the 
dvander@941
   765
	 * other extension is loaded, but handling of dependencies is really done 
dvander@941
   766
	 * by the interface fetcher.
dvander@941
   767
	 */
dvander@941
   768
	if (required || autoload)
dvander@941
   769
	{
dvander@941
   770
		LoadAutoExtension(file);
dvander@941
   771
	}
dvander@324
   772
}
dvander@324
   773
dvander@310
   774
void CExtensionManager::OnRootConsoleCommand(const char *cmd, unsigned int argcount)
dvander@310
   775
{
dvander@310
   776
	if (argcount >= 3)
dvander@310
   777
	{
dvander@310
   778
		const char *cmd = g_RootMenu.GetArgument(2);
dvander@310
   779
		if (strcmp(cmd, "list") == 0)
dvander@310
   780
		{
dvander@310
   781
			List<CExtension *>::iterator iter;
dvander@310
   782
			CExtension *pExt;
dvander@310
   783
			unsigned int num = 1;
dvander@310
   784
			switch (m_Libs.size())
dvander@310
   785
			{
dvander@310
   786
			case 1:
dvander@310
   787
				{
dvander@310
   788
					g_RootMenu.ConsolePrint("[SM] Displaying 1 extension:");
dvander@310
   789
					break;
dvander@310
   790
				}
dvander@310
   791
			case 0:
dvander@310
   792
				{
dvander@310
   793
					g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
dvander@310
   794
					break;
dvander@310
   795
				}
dvander@310
   796
			default:
dvander@310
   797
				{
dvander@310
   798
					g_RootMenu.ConsolePrint("[SM] Displaying %d extensions:", m_Libs.size());
dvander@310
   799
					break;
dvander@310
   800
				}
dvander@310
   801
			}
dvander@310
   802
			for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++,num++)
dvander@310
   803
			{
dvander@310
   804
				pExt = (*iter);
dvander@310
   805
				if (pExt->IsLoaded())
dvander@310
   806
				{
dvander@315
   807
					char error[255];
dvander@315
   808
					if (!pExt->IsRunning(error, sizeof(error)))
dvander@315
   809
					{
dvander@315
   810
						g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), error);
dvander@315
   811
					} else {
dvander@315
   812
						IExtensionInterface *pAPI = pExt->GetAPI();
dvander@315
   813
						const char *name = pAPI->GetExtensionName();
dvander@315
   814
						const char *version = pAPI->GetExtensionVerString();
dvander@315
   815
						const char *descr = pAPI->GetExtensionDescription();
dvander@315
   816
						g_RootMenu.ConsolePrint("[%02d] %s (%s): %s", num, name, version, descr);
dvander@315
   817
					}
dvander@310
   818
				} else {
dvander@310
   819
					g_RootMenu.ConsolePrint("[%02d] <FAILED> file \"%s\": %s", num, pExt->GetFilename(), pExt->m_Error.c_str());
dvander@310
   820
				}
dvander@310
   821
			}
dvander@310
   822
			return;
dvander@310
   823
		} else if (strcmp(cmd, "info") == 0) {
dvander@310
   824
			if (argcount < 4)
dvander@310
   825
			{
dvander@310
   826
				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
dvander@310
   827
				return;
dvander@310
   828
			}
dvander@310
   829
dvander@310
   830
			const char *sId = g_RootMenu.GetArgument(3);
dvander@310
   831
			unsigned int id = atoi(sId);
dvander@310
   832
			if (id <= 0)
dvander@310
   833
			{
dvander@310
   834
				g_RootMenu.ConsolePrint("[SM] Usage: sm info <#>");
dvander@310
   835
				return;
dvander@310
   836
			}
dvander@310
   837
dvander@310
   838
			if (m_Libs.size() == 0)
dvander@310
   839
			{
dvander@310
   840
				g_RootMenu.ConsolePrint("[SM] No extensions are loaded.");
dvander@310
   841
				return;
dvander@310
   842
			}
dvander@310
   843
dvander@310
   844
			if (id > m_Libs.size())
dvander@310
   845
			{
dvander@310
   846
				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
dvander@310
   847
				return;
dvander@310
   848
			}
dvander@310
   849
dvander@310
   850
			List<CExtension *>::iterator iter = m_Libs.begin();
dvander@310
   851
			CExtension *pExt = NULL;
dvander@310
   852
			while (iter != m_Libs.end())
dvander@310
   853
			{
dvander@310
   854
				if (--id == 0)
dvander@310
   855
				{
dvander@310
   856
					pExt = (*iter);
dvander@310
   857
					break;
dvander@310
   858
				}
dvander@310
   859
				iter++;
dvander@310
   860
			}
dvander@310
   861
			/* This should never happen */
dvander@310
   862
			if (!pExt)
dvander@310
   863
			{
dvander@310
   864
				g_RootMenu.ConsolePrint("[SM] No extension was found with id %d.", id);
dvander@310
   865
				return;
dvander@310
   866
			}
dvander@310
   867
dvander@310
   868
			if (!pExt->IsLoaded())
dvander@310
   869
			{
dvander@310
   870
				g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
dvander@310
   871
				g_RootMenu.ConsolePrint(" Loaded: No (%s)", pExt->m_Error.c_str());
dvander@310
   872
			} else {
dvander@315
   873
				char error[255];
dvander@315
   874
				if (!pExt->IsRunning(error, sizeof(error)))
dvander@315
   875
				{
dvander@315
   876
					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
dvander@315
   877
					g_RootMenu.ConsolePrint(" Loaded: Yes");
dvander@315
   878
					g_RootMenu.ConsolePrint(" Running: No (%s)", error);
dvander@315
   879
				} else {
dvander@315
   880
					IExtensionInterface *pAPI = pExt->GetAPI();
dvander@315
   881
					g_RootMenu.ConsolePrint(" File: %s", pExt->GetFilename());
dvander@315
   882
					g_RootMenu.ConsolePrint(" Loaded: Yes (version %s)", pAPI->GetExtensionVerString());
dvander@315
   883
					g_RootMenu.ConsolePrint(" Name: %s (%s)", pAPI->GetExtensionName(), pAPI->GetExtensionDescription());
dvander@315
   884
					g_RootMenu.ConsolePrint(" Author: %s (%s)", pAPI->GetExtensionAuthor(), pAPI->GetExtensionURL());
dvander@315
   885
					g_RootMenu.ConsolePrint(" Binary info: API version %d (compiled %s)", pAPI->GetExtensionVersion(), pAPI->GetExtensionDateString());
dvander@315
   886
					g_RootMenu.ConsolePrint(" Metamod enabled: %s", pAPI->IsMetamodExtension() ? "yes" : "no");
dvander@315
   887
				}
dvander@310
   888
			}
dvander@310
   889
			return;
dvander@311
   890
		} else if (strcmp(cmd, "unload") == 0) {
dvander@311
   891
			if (argcount < 4)
dvander@311
   892
			{
dvander@311
   893
				g_RootMenu.ConsolePrint("[SM] Usage: sm unload <#> [code]");
dvander@311
   894
				return;
dvander@311
   895
			}
dvander@311
   896
dvander@311
   897
			const char *arg = g_RootMenu.GetArgument(3);
dvander@311
   898
			unsigned int num = atoi(arg);
dvander@311
   899
			CExtension *pExt = FindByOrder(num);
dvander@311
   900
dvander@311
   901
			if (!pExt)
dvander@311
   902
			{
dvander@311
   903
				g_RootMenu.ConsolePrint("[SM] Extension number %d was not found.", num);
dvander@311
   904
				return;
dvander@311
   905
			}
dvander@311
   906
dvander@311
   907
			if (argcount > 4 && pExt->unload_code)
dvander@311
   908
			{
dvander@311
   909
				const char *unload = g_RootMenu.GetArgument(4);
dvander@351
   910
				if (pExt->unload_code == (unsigned)atoi(unload))
dvander@311
   911
				{
ds@652
   912
					char filename[PLATFORM_MAX_PATH];
dvander@311
   913
					snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
dvander@311
   914
					UnloadExtension(pExt);
dvander@311
   915
					g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
dvander@311
   916
				} else {
dvander@311
   917
					g_RootMenu.ConsolePrint("[SM] Please try again, the correct unload code is \"%d\"", pExt->unload_code);
dvander@311
   918
				}
dvander@311
   919
				return;
dvander@311
   920
			}
dvander@311
   921
dvander@311
   922
			if (!pExt->IsLoaded() 
dvander@1150
   923
				|| (!pExt->m_ChildDeps.size() && !pExt->m_Plugins.size()))
dvander@311
   924
			{
ds@652
   925
				char filename[PLATFORM_MAX_PATH];
dvander@311
   926
				snprintf(filename, PLATFORM_MAX_PATH, "%s", pExt->GetFilename());
dvander@311
   927
				UnloadExtension(pExt);
dvander@311
   928
				g_RootMenu.ConsolePrint("[SM] Extension %s is now unloaded.", filename);
dvander@311
   929
				return;
dvander@311
   930
			} else {
dvander@311
   931
				List<IPlugin *> plugins;
dvander@1150
   932
				if (pExt->m_ChildDeps.size())
dvander@311
   933
				{
dvander@311
   934
					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following extensions: ", pExt->GetFilename());
dvander@311
   935
					List<CExtension *>::iterator iter;
dvander@311
   936
					CExtension *pOther;
dvander@311
   937
					/* Get list of all extensions */
dvander@311
   938
					for (iter=m_Libs.begin(); iter!=m_Libs.end(); iter++)
dvander@311
   939
					{
dvander@311
   940
						List<IfaceInfo>::iterator i_iter;
dvander@311
   941
						pOther = (*iter);
dvander@311
   942
						if (!pOther->IsLoaded() || pOther == pExt)
dvander@311
   943
						{
dvander@311
   944
							continue;
dvander@311
   945
						}
dvander@311
   946
						/* Get their dependencies */
dvander@311
   947
						for (i_iter=pOther->m_Deps.begin();
dvander@311
   948
							 i_iter!=pOther->m_Deps.end();
dvander@311
   949
							 i_iter++)
dvander@311
   950
						{
dvander@311
   951
							/* Is this dependency to us? */
dvander@311
   952
							if ((*i_iter).owner != pExt)
dvander@311
   953
							{
dvander@311
   954
								continue;
dvander@311
   955
							}
dvander@311
   956
							/* Will our dependent care? */
dvander@311
   957
							if (!pExt->GetAPI()->QueryInterfaceDrop((*i_iter).iface))
dvander@311
   958
							{
dvander@311
   959
								g_RootMenu.ConsolePrint(" -> %s", pExt->GetFilename());
dvander@311
   960
								/* Add to plugin unload list */
dvander@311
   961
								List<IPlugin *>::iterator p_iter;
dvander@311
   962
								for (p_iter=pOther->m_Plugins.begin();
dvander@311
   963
									 p_iter!=pOther->m_Plugins.end();
dvander@311
   964
									 p_iter++)
dvander@311
   965
								{
dvander@311
   966
									if (plugins.find((*p_iter)) == plugins.end())
dvander@311
   967
									{
dvander@311
   968
										plugins.push_back((*p_iter));
dvander@311
   969
									}
dvander@311
   970
								}
dvander@311
   971
							}
dvander@311
   972
						}
dvander@311
   973
					}
dvander@311
   974
				}
dvander@311
   975
				if (pExt->m_Plugins.size())
dvander@311
   976
				{
dvander@311
   977
					g_RootMenu.ConsolePrint("[SM] Unloading %s will unload the following plugins: ", pExt->GetFilename());
dvander@311
   978
					List<IPlugin *>::iterator iter;
dvander@311
   979
					IPlugin *pPlugin;
dvander@311
   980
					for (iter = pExt->m_Plugins.begin(); iter != pExt->m_Plugins.end(); iter++)
dvander@311
   981
					{
dvander@311
   982
						pPlugin = (*iter);
dvander@311
   983
						if (plugins.find(pPlugin) == plugins.end())
dvander@311
   984
						{
dvander@311
   985
							plugins.push_back(pPlugin);
dvander@311
   986
						}
dvander@311
   987
					}
dvander@311
   988
					for (iter = plugins.begin(); iter != plugins.end(); iter++)
dvander@311
   989
					{
dvander@311
   990
						pPlugin = (*iter);
dvander@311
   991
						g_RootMenu.ConsolePrint(" -> %s", pPlugin->GetFilename());
dvander@311
   992
					}
dvander@311
   993
				}
dvander@311
   994
				srand(static_cast<int>(time(NULL)));
dvander@311
   995
				pExt->unload_code = (rand() % 877) + 123;	//123 to 999
dvander@311
   996
				g_RootMenu.ConsolePrint("[SM] To verify unloading %s, please use the following: ", pExt->GetFilename());
dvander@311
   997
				g_RootMenu.ConsolePrint("[SM] sm exts unload %d %d", num, pExt->unload_code);
dvander@311
   998
dvander@311
   999
				return;
dvander@311
  1000
			}
dvander@310
  1001
		}
dvander@310
  1002
	}
dvander@310
  1003
dvander@310
  1004
	g_RootMenu.ConsolePrint("SourceMod Extensions Menu:");
dvander@310
  1005
	g_RootMenu.DrawGenericOption("info", "Extra extension information");
dvander@310
  1006
	g_RootMenu.DrawGenericOption("list", "List extensions");
dvander@311
  1007
	g_RootMenu.DrawGenericOption("unload", "Unload an extension");
dvander@310
  1008
}
dvander@868
  1009
dvander@868
  1010
CExtension *CExtensionManager::GetExtensionFromIdent(IdentityToken_t *ptr)
dvander@868
  1011
{
dvander@868
  1012
	if (ptr->type == g_ExtType)
dvander@868
  1013
	{
dvander@868
  1014
		return (CExtension *)(ptr->ptr);
dvander@868
  1015
	}
dvander@868
  1016
dvander@868
  1017
	return NULL;
dvander@868
  1018
}