core/systems/PluginSys.cpp
author David Anderson <dvander@alliedmods.net>
Fri Aug 15 05:22:26 2008 +0000 (2008-08-15)
changeset 2226 d10b38524be3
parent 2219 5ddd93671335
child 2289 44045ead61cd
permissions -rw-r--r--
Landed sourcepawn-1.2. The big changes:

1) JIT compilation/optimization now occurs per-function, and only when functions are first used. We're now officially a whole-method JIT rather than an AOT compiler (albiet, still a simple JIT). This has two implications: Functions are now much better abstracted internally, and loading a plugin is now much less expensive. If a function contains calls to other functions, THOSE functions are only compiled when they're invoked as well.

2) I've removed debug mode. We always show full backtraces now, as there was a very cheap way to implement this which really cleaned up everything. This is great for a number of reasons -- there's less code, the JIT is better designed, we don't need to relocate debug tables, and best of all we no longer have to tell users to enable debug mode at their own expense.
ds@1952
     1
/**
ds@1952
     2
 * vim: set ts=4 :
ds@1952
     3
 * =============================================================================
ds@1952
     4
 * SourceMod
ds@1952
     5
 * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
ds@1952
     6
 * =============================================================================
ds@1952
     7
 *
ds@1952
     8
 * This program is free software; you can redistribute it and/or modify it under
ds@1952
     9
 * the terms of the GNU General Public License, version 3.0, as published by the
ds@1952
    10
 * Free Software Foundation.
ds@1952
    11
 * 
ds@1952
    12
 * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1952
    13
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1952
    14
 * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
ds@1952
    15
 * details.
ds@1952
    16
 *
ds@1952
    17
 * You should have received a copy of the GNU General Public License along with
ds@1952
    18
 * this program.  If not, see <http://www.gnu.org/licenses/>.
ds@1952
    19
 *
ds@1952
    20
 * As a special exception, AlliedModders LLC gives you permission to link the
ds@1952
    21
 * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1952
    22
 * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1952
    23
 * by the Valve Corporation.  You must obey the GNU General Public License in
ds@1952
    24
 * all respects for all other code used.  Additionally, AlliedModders LLC grants
ds@1952
    25
 * this exception to all derivative works.  AlliedModders LLC defines further
ds@1952
    26
 * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1952
    27
 * or <http://www.sourcemod.net/license.php>.
ds@1952
    28
 *
ds@1952
    29
 * Version: $Id$
ds@1952
    30
 */
ds@1952
    31
ds@1952
    32
#include <stdio.h>
ds@1952
    33
#include "PluginSys.h"
ds@1952
    34
#include "ShareSys.h"
ds@1952
    35
#include "LibrarySys.h"
ds@1952
    36
#include "HandleSys.h"
ds@1952
    37
#include "ForwardSys.h"
ds@1952
    38
#include "sourcemm_api.h"
ds@1952
    39
#include "sourcemod.h"
ds@1952
    40
#include "TextParsers.h"
ds@1952
    41
#include "Logger.h"
ds@1952
    42
#include "ExtensionSys.h"
ds@1952
    43
#include "sm_srvcmds.h"
ds@1952
    44
#include "sm_stringutil.h"
ds@1952
    45
#include "ConCmdManager.h"
ds@1952
    46
#include "PlayerManager.h"
ds@1952
    47
#include "CoreConfig.h"
ds@1952
    48
#include "Translator.h"
ds@1952
    49
ds@1952
    50
CPluginManager g_PluginSys;
ds@1952
    51
HandleType_t g_PluginType = 0;
ds@1952
    52
IdentityType_t g_PluginIdent = 0;
ds@1952
    53
ds@1952
    54
CPlugin::CPlugin(const char *file)
ds@1952
    55
{
ds@1952
    56
	static int MySerial = 0;
ds@1952
    57
ds@1952
    58
	m_type = PluginType_Private;
ds@1952
    59
	m_status = Plugin_Uncompiled;
ds@1952
    60
	m_serial = ++MySerial;
dvander@2193
    61
	m_pRuntime = NULL;
ds@1952
    62
	m_errormsg[256] = '\0';
ds@1952
    63
	snprintf(m_filename, sizeof(m_filename), "%s", file);
ds@1952
    64
	m_handle = 0;
ds@1952
    65
	m_ident = NULL;
ds@1952
    66
	m_pProps = sm_trie_create();
ds@1952
    67
	m_FakeNativesMissing = false;
ds@1952
    68
	m_LibraryMissing = false;
ds@1952
    69
	m_bGotAllLoaded = false;
dvander@2042
    70
	m_pPhrases = g_Translator.CreatePhraseCollection();
ds@1952
    71
}
ds@1952
    72
ds@1952
    73
CPlugin::~CPlugin()
ds@1952
    74
{
ds@1952
    75
	if (m_handle)
ds@1952
    76
	{
ds@1952
    77
		HandleSecurity sec;
ds@1952
    78
		sec.pOwner = g_PluginSys.GetIdentity();
ds@1952
    79
		sec.pIdentity = sec.pOwner;
ds@1952
    80
ds@1952
    81
		g_HandleSys.FreeHandle(m_handle, &sec);
ds@1952
    82
		g_ShareSys.DestroyIdentity(m_ident);
ds@1952
    83
	}
ds@1952
    84
dvander@2193
    85
	if (m_pRuntime != NULL)
ds@1952
    86
	{
dvander@2193
    87
		delete m_pRuntime;
dvander@2193
    88
		m_pRuntime = NULL;
ds@1952
    89
	}
ds@1952
    90
ds@1952
    91
	if (m_pProps)
ds@1952
    92
	{
ds@1952
    93
		sm_trie_destroy(m_pProps);
ds@1952
    94
	}
ds@1952
    95
	for (size_t i=0; i<m_configs.size(); i++)
ds@1952
    96
	{
ds@1952
    97
		delete m_configs[i];
ds@1952
    98
	}
ds@1952
    99
	m_configs.clear();
dvander@2042
   100
	if (m_pPhrases != NULL)
dvander@2042
   101
	{
dvander@2042
   102
		m_pPhrases->Destroy();
dvander@2042
   103
		m_pPhrases = NULL;
dvander@2042
   104
	}
ds@1952
   105
}
ds@1952
   106
ds@1952
   107
void CPlugin::InitIdentity()
ds@1952
   108
{
ds@1952
   109
	if (!m_handle)
ds@1952
   110
	{
ds@1952
   111
		m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
ds@1952
   112
		m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
dvander@2193
   113
		m_pRuntime->GetDefaultContext()->SetKey(1, m_ident);
dvander@2193
   114
		m_pRuntime->GetDefaultContext()->SetKey(2, (IPlugin *)this);
ds@1952
   115
	}
ds@1952
   116
}
ds@1952
   117
ds@1952
   118
unsigned int CPlugin::CalcMemUsage()
ds@1952
   119
{
ds@1952
   120
	unsigned int base_size = 
ds@1952
   121
		sizeof(CPlugin) 
ds@1952
   122
		+ sizeof(IdentityToken_t)
ds@1952
   123
		+ (m_configs.size() * (sizeof(AutoConfig *) + sizeof(AutoConfig)))
ds@1952
   124
		+ sm_trie_mem_usage(m_pProps);
ds@1952
   125
ds@1952
   126
	for (unsigned int i = 0; i < m_configs.size(); i++)
ds@1952
   127
	{
ds@1952
   128
		base_size += m_configs[i]->autocfg.size();
ds@1952
   129
		base_size += m_configs[i]->folder.size();
ds@1952
   130
	}
ds@1952
   131
ds@1952
   132
	for (List<String>::iterator i = m_Libraries.begin();
ds@1952
   133
		 i != m_Libraries.end();
ds@1952
   134
		 i++)
ds@1952
   135
	{
ds@1952
   136
		base_size += (*i).size();
ds@1952
   137
	}
ds@1952
   138
ds@1952
   139
	for (List<String>::iterator i = m_RequiredLibs.begin();
ds@1952
   140
		 i != m_RequiredLibs.end();
ds@1952
   141
		 i++)
ds@1952
   142
	{
ds@1952
   143
		base_size += (*i).size();
ds@1952
   144
	}
ds@1952
   145
ds@1952
   146
	return base_size;
ds@1952
   147
}
ds@1952
   148
ds@1952
   149
Handle_t CPlugin::GetMyHandle()
ds@1952
   150
{
ds@1952
   151
	return m_handle;
ds@1952
   152
}
ds@1952
   153
ds@1952
   154
CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
ds@1952
   155
{
ds@1952
   156
	char fullpath[PLATFORM_MAX_PATH];
ds@1952
   157
	g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file);
ds@1952
   158
	FILE *fp = fopen(fullpath, "rb");
ds@1952
   159
ds@1952
   160
	CPlugin *pPlugin = new CPlugin(file);
ds@1952
   161
ds@1952
   162
	if (!fp)
ds@1952
   163
	{
ds@1952
   164
		if (error)
ds@1952
   165
		{
ds@1952
   166
			snprintf(error, maxlength, "Unable to open file");
ds@1952
   167
		}
ds@1952
   168
		pPlugin->m_status = Plugin_BadLoad;
ds@1952
   169
		return pPlugin;
ds@1952
   170
	}
ds@1952
   171
pred@2219
   172
	fclose(fp);
pred@2219
   173
ds@1952
   174
	return pPlugin;
ds@1952
   175
}
ds@1952
   176
ds@1952
   177
bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */)
ds@1952
   178
{
ds@1952
   179
	bool exists = sm_trie_retrieve(m_pProps, prop, ptr);
ds@1952
   180
ds@1952
   181
	if (exists && remove)
ds@1952
   182
	{
ds@1952
   183
		sm_trie_delete(m_pProps, prop);
ds@1952
   184
	}
ds@1952
   185
ds@1952
   186
	return exists;
ds@1952
   187
}
ds@1952
   188
ds@1952
   189
bool CPlugin::SetProperty(const char *prop, void *ptr)
ds@1952
   190
{
ds@1952
   191
	return sm_trie_insert(m_pProps, prop, ptr);
ds@1952
   192
}
ds@1952
   193
dvander@2193
   194
IPluginRuntime *CPlugin::GetRuntime()
ds@1952
   195
{
dvander@2193
   196
	return m_pRuntime;
ds@1952
   197
}
ds@1952
   198
ds@1952
   199
void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
ds@1952
   200
{
ds@1952
   201
	PluginStatus old_status = m_status;
ds@1952
   202
	m_status = status;
ds@1952
   203
ds@1952
   204
	if (old_status == Plugin_Running)
ds@1952
   205
	{
ds@1952
   206
		/* Tell everyone we're now paused */
ds@1952
   207
		g_PluginSys._SetPauseState(this, true);
ds@1952
   208
	}
ds@1952
   209
ds@1952
   210
	va_list ap;
ds@1952
   211
	va_start(ap, error_fmt);
ds@1952
   212
	vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
ds@1952
   213
	va_end(ap);
ds@1952
   214
dvander@2193
   215
	if (m_pRuntime != NULL)
ds@1952
   216
	{
dvander@2193
   217
		m_pRuntime->SetPauseState(true);
ds@1952
   218
	}
ds@1952
   219
}
ds@1952
   220
ds@1952
   221
void CPlugin::UpdateInfo()
ds@1952
   222
{
ds@1952
   223
	/* Now grab the info */
ds@1952
   224
	uint32_t idx;
ds@1952
   225
	IPluginContext *base = GetBaseContext();
ds@1952
   226
	int err = base->FindPubvarByName("myinfo", &idx);
ds@1952
   227
ds@1952
   228
	memset(&m_info, 0, sizeof(m_info));
ds@1952
   229
ds@1952
   230
	if (err == SP_ERROR_NONE)
ds@1952
   231
	{
ds@1952
   232
		struct sm_plugininfo_c_t
ds@1952
   233
		{
ds@1952
   234
			cell_t name;
ds@1952
   235
			cell_t description;
ds@1952
   236
			cell_t author;
ds@1952
   237
			cell_t version;
ds@1952
   238
			cell_t url;
ds@1952
   239
		};
ds@1952
   240
		sm_plugininfo_c_t *cinfo;
ds@1952
   241
		cell_t local_addr;
ds@1952
   242
ds@1952
   243
		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
ds@1952
   244
		base->LocalToString(cinfo->name, (char **)&m_info.name);
ds@1952
   245
		base->LocalToString(cinfo->description, (char **)&m_info.description);
ds@1952
   246
		base->LocalToString(cinfo->author, (char **)&m_info.author);
ds@1952
   247
		base->LocalToString(cinfo->url, (char **)&m_info.url);
ds@1952
   248
		base->LocalToString(cinfo->version, (char **)&m_info.version);
ds@1952
   249
	}
ds@1952
   250
ds@1952
   251
	m_info.author = m_info.author ? m_info.author : "";
ds@1952
   252
	m_info.description = m_info.description ? m_info.description : "";
ds@1952
   253
	m_info.name = m_info.name ? m_info.name : "";
ds@1952
   254
	m_info.url = m_info.url ? m_info.url : "";
ds@1952
   255
	m_info.version = m_info.version ? m_info.version : "";
dvander@2105
   256
dvander@2105
   257
	if ((err = base->FindPubvarByName("__version", &idx)) == SP_ERROR_NONE)
dvander@2105
   258
	{
dvander@2105
   259
		struct __version_info
dvander@2105
   260
		{
dvander@2105
   261
			cell_t version;
dvander@2105
   262
			cell_t filevers;
dvander@2105
   263
			cell_t date;
dvander@2105
   264
			cell_t time;
dvander@2105
   265
		};
dvander@2105
   266
		__version_info *info;
dvander@2105
   267
		cell_t local_addr;
dvander@2105
   268
		const char *pDate, *pTime;
dvander@2105
   269
dvander@2105
   270
		pDate = "";
dvander@2105
   271
		pTime = "";
dvander@2105
   272
dvander@2105
   273
		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&info);
dvander@2105
   274
		m_FileVersion = info->version;
dvander@2105
   275
		if (m_FileVersion >= 3)
dvander@2105
   276
		{
dvander@2105
   277
			base->LocalToString(info->date, (char **)&pDate);
dvander@2105
   278
			base->LocalToString(info->time, (char **)&pTime);
dvander@2105
   279
			UTIL_Format(m_DateTime, sizeof(m_DateTime), "%s %s", pDate, pTime);
dvander@2105
   280
		}
dvander@2105
   281
	}
dvander@2105
   282
	else
dvander@2105
   283
	{
dvander@2105
   284
		m_FileVersion = 0;
dvander@2105
   285
	}
ds@1952
   286
}
ds@1952
   287
ds@1952
   288
void CPlugin::Call_OnPluginStart()
ds@1952
   289
{
ds@1952
   290
	if (m_status != Plugin_Loaded)
ds@1952
   291
	{
ds@1952
   292
		return;
ds@1952
   293
	}
ds@1952
   294
ds@1952
   295
	m_status = Plugin_Running;
ds@1952
   296
ds@1952
   297
	cell_t result;
dvander@2193
   298
	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginStart");
ds@1952
   299
	if (!pFunction)
ds@1952
   300
	{
ds@1952
   301
		return;
ds@1952
   302
	}
ds@1952
   303
ds@1952
   304
	int err;
ds@1952
   305
	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
ds@1952
   306
	{
ds@1952
   307
		SetErrorState(Plugin_Error, "Error detected in plugin startup (see error logs)");
ds@1952
   308
	}
ds@1952
   309
}
ds@1952
   310
ds@1952
   311
void CPlugin::Call_OnPluginEnd()
ds@1952
   312
{
ds@1952
   313
	if (m_status > Plugin_Paused)
ds@1952
   314
	{
ds@1952
   315
		return;
ds@1952
   316
	}
ds@1952
   317
ds@1952
   318
	cell_t result;
dvander@2193
   319
	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginEnd");
ds@1952
   320
	if (!pFunction)
ds@1952
   321
	{
ds@1952
   322
		return;
ds@1952
   323
	}
ds@1952
   324
ds@1952
   325
	pFunction->Execute(&result);
ds@1952
   326
}
ds@1952
   327
ds@1952
   328
void CPlugin::Call_OnAllPluginsLoaded()
ds@1952
   329
{
ds@1952
   330
	if (m_status > Plugin_Paused)
ds@1952
   331
	{
ds@1952
   332
		return;
ds@1952
   333
	}
ds@1952
   334
ds@1952
   335
	if (m_bGotAllLoaded)
ds@1952
   336
	{
ds@1952
   337
		return;
ds@1952
   338
	}
ds@1952
   339
ds@1952
   340
	m_bGotAllLoaded = true;
ds@1952
   341
ds@1952
   342
	cell_t result;
dvander@2193
   343
	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnAllPluginsLoaded");
ds@1952
   344
	if (pFunction != NULL)
ds@1952
   345
	{
ds@1952
   346
		pFunction->Execute(&result);
ds@1952
   347
	}
ds@1952
   348
ds@1952
   349
	if (g_OnMapStarted)
ds@1952
   350
	{
dvander@2193
   351
		if ((pFunction = m_pRuntime->GetFunctionByName("OnMapStart")) != NULL)
ds@1952
   352
		{
ds@1952
   353
			pFunction->Execute(NULL);
ds@1952
   354
		}
ds@1952
   355
	}
ds@1952
   356
ds@1952
   357
	if (SM_AreConfigsExecuted())
ds@1952
   358
	{
ds@1952
   359
		SM_ExecuteForPlugin(GetBaseContext());
ds@1952
   360
	}
ds@1952
   361
}
ds@1952
   362
ds@1952
   363
bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
ds@1952
   364
{
ds@1952
   365
	if (m_status != Plugin_Created)
ds@1952
   366
	{
ds@1952
   367
		return false;
ds@1952
   368
	}
ds@1952
   369
ds@1952
   370
	m_status = Plugin_Loaded;
ds@1952
   371
ds@1952
   372
	int err;
ds@1952
   373
	cell_t result;
dvander@2193
   374
	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("AskPluginLoad");
ds@1952
   375
ds@1952
   376
	if (!pFunction)
ds@1952
   377
	{
ds@1952
   378
		return true;
ds@1952
   379
	}
ds@1952
   380
ds@1952
   381
	pFunction->PushCell(m_handle);
ds@1952
   382
	pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
ds@1952
   383
	pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
ds@1952
   384
	pFunction->PushCell(maxlength);
ds@1952
   385
	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
ds@1952
   386
	{
ds@1952
   387
		return false;
ds@1952
   388
	}
ds@1952
   389
ds@1952
   390
	if (!result || m_status != Plugin_Loaded)
ds@1952
   391
	{
ds@1952
   392
		return false;
ds@1952
   393
	}
ds@1952
   394
ds@1952
   395
	return true;
ds@1952
   396
}
ds@1952
   397
dvander@2193
   398
void *CPlugin::GetPluginStructure()
ds@1952
   399
{
dvander@2193
   400
	return NULL;
ds@1952
   401
}
ds@1952
   402
ds@1952
   403
IPluginContext *CPlugin::GetBaseContext()
ds@1952
   404
{
dvander@2193
   405
	if (m_pRuntime == NULL)
dvander@2193
   406
	{
dvander@2193
   407
		return NULL;
dvander@2193
   408
	}
dvander@2193
   409
dvander@2193
   410
	return m_pRuntime->GetDefaultContext();
ds@1952
   411
}
ds@1952
   412
ds@1952
   413
sp_context_t *CPlugin::GetContext()
ds@1952
   414
{
dvander@2193
   415
	return NULL;
ds@1952
   416
}
ds@1952
   417
ds@1952
   418
const char *CPlugin::GetFilename()
ds@1952
   419
{
ds@1952
   420
	return m_filename;
ds@1952
   421
}
ds@1952
   422
ds@1952
   423
PluginType CPlugin::GetType()
ds@1952
   424
{
ds@1952
   425
	return m_type;
ds@1952
   426
}
ds@1952
   427
ds@1952
   428
const sm_plugininfo_t *CPlugin::GetPublicInfo()
ds@1952
   429
{
ds@1952
   430
	return &m_info;
ds@1952
   431
}
ds@1952
   432
ds@1952
   433
unsigned int CPlugin::GetSerial()
ds@1952
   434
{
ds@1952
   435
	return m_serial;
ds@1952
   436
}
ds@1952
   437
ds@1952
   438
PluginStatus CPlugin::GetStatus()
ds@1952
   439
{
ds@1952
   440
	return m_status;
ds@1952
   441
}
ds@1952
   442
ds@1952
   443
bool CPlugin::IsDebugging()
ds@1952
   444
{
dvander@2193
   445
	if (m_pRuntime == NULL)
ds@1952
   446
	{
ds@1952
   447
		return false;
ds@1952
   448
	}
ds@1952
   449
dvander@2226
   450
	return true;
ds@1952
   451
}
ds@1952
   452
ds@1952
   453
void CPlugin::LibraryActions(bool dropping)
ds@1952
   454
{
ds@1952
   455
	List<String>::iterator iter;
ds@1952
   456
	for (iter = m_Libraries.begin();
ds@1952
   457
		iter != m_Libraries.end();
ds@1952
   458
		iter++)
ds@1952
   459
	{
ds@1952
   460
		g_PluginSys.OnLibraryAction((*iter).c_str(), true, dropping);
ds@1952
   461
	}
ds@1952
   462
}
ds@1952
   463
ds@1952
   464
bool CPlugin::SetPauseState(bool paused)
ds@1952
   465
{
ds@1952
   466
	if (paused && GetStatus() != Plugin_Running)
ds@1952
   467
	{
ds@1952
   468
		return false;
ds@1952
   469
	} else if (!paused && GetStatus() != Plugin_Paused) {
ds@1952
   470
		return false;
ds@1952
   471
	}
ds@1952
   472
ds@1952
   473
	if (paused)
ds@1952
   474
	{
ds@1952
   475
		LibraryActions(true);
ds@1952
   476
	}
ds@1952
   477
dvander@2193
   478
	IPluginFunction *pFunction = m_pRuntime->GetFunctionByName("OnPluginPauseChange");
ds@1952
   479
	if (pFunction)
ds@1952
   480
	{
ds@1952
   481
		cell_t result;
ds@1952
   482
		pFunction->PushCell(paused ? 1 : 0);
ds@1952
   483
		pFunction->Execute(&result);
ds@1952
   484
	}
ds@1952
   485
ds@1952
   486
	if (paused)
ds@1952
   487
	{
ds@1952
   488
		m_status = Plugin_Paused;
dvander@2193
   489
		m_pRuntime->SetPauseState(true);
ds@1952
   490
	} else {
ds@1952
   491
		m_status = Plugin_Running;
dvander@2193
   492
		m_pRuntime->SetPauseState(false);
ds@1952
   493
	}
ds@1952
   494
ds@1952
   495
	g_PluginSys._SetPauseState(this, paused);
ds@1952
   496
ds@1952
   497
	if (!paused)
ds@1952
   498
	{
ds@1952
   499
		LibraryActions(false);
ds@1952
   500
	}
ds@1952
   501
ds@1952
   502
	return true;
ds@1952
   503
}
ds@1952
   504
ds@1952
   505
IdentityToken_t *CPlugin::GetIdentity()
ds@1952
   506
{
ds@1952
   507
	return m_ident;
ds@1952
   508
}
ds@1952
   509
ds@1952
   510
bool CPlugin::IsRunnable()
ds@1952
   511
{
ds@1952
   512
	return (m_status <= Plugin_Paused) ? true : false;
ds@1952
   513
}
ds@1952
   514
ds@1952
   515
time_t CPlugin::GetFileTimeStamp()
ds@1952
   516
{
ds@1952
   517
	char path[PLATFORM_MAX_PATH];
ds@1952
   518
	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename);
ds@1952
   519
#ifdef PLATFORM_WINDOWS
ds@1952
   520
	struct _stat s;
ds@1952
   521
	if (_stat(path, &s) != 0)
ds@1952
   522
#elif defined PLATFORM_POSIX
ds@1952
   523
	struct stat s;
ds@1952
   524
	if (stat(path, &s) != 0)
ds@1952
   525
#endif
ds@1952
   526
	{
ds@1952
   527
		return 0;
ds@1952
   528
	}
ds@1952
   529
	else
ds@1952
   530
	{
ds@1952
   531
		return s.st_mtime;
ds@1952
   532
	}
ds@1952
   533
}
ds@1952
   534
ds@1952
   535
time_t CPlugin::GetTimeStamp()
ds@1952
   536
{
ds@1952
   537
	return m_LastAccess;
ds@1952
   538
}
ds@1952
   539
ds@1952
   540
void CPlugin::SetTimeStamp(time_t t)
ds@1952
   541
{
ds@1952
   542
	m_LastAccess = t;
ds@1952
   543
}
ds@1952
   544
dvander@2042
   545
IPhraseCollection *CPlugin::GetPhrases()
ds@1952
   546
{
dvander@2042
   547
	return m_pPhrases;
ds@1952
   548
}
ds@1952
   549
ds@1952
   550
void CPlugin::DependencyDropped(CPlugin *pOwner)
ds@1952
   551
{
dvander@2193
   552
	if (!m_pRuntime)
ds@1952
   553
	{
ds@1952
   554
		return;
ds@1952
   555
	}
ds@1952
   556
ds@1952
   557
	List<String>::iterator reqlib_iter;
ds@1952
   558
	List<String>::iterator lib_iter;
ds@1952
   559
	for (lib_iter=pOwner->m_Libraries.begin(); lib_iter!=pOwner->m_Libraries.end(); lib_iter++)
ds@1952
   560
	{
ds@1952
   561
		for (reqlib_iter=m_RequiredLibs.begin(); reqlib_iter!=m_RequiredLibs.end(); reqlib_iter++)
ds@1952
   562
		{
ds@1952
   563
			if ((*reqlib_iter) == (*lib_iter))
ds@1952
   564
			{
ds@1952
   565
				m_LibraryMissing = true;
ds@1952
   566
			}
ds@1952
   567
		}	
ds@1952
   568
	}
ds@1952
   569
dvander@2086
   570
	List<NativeEntry *>::iterator iter;
dvander@2086
   571
	NativeEntry *pNative;
ds@1952
   572
	sp_native_t *native;
ds@1952
   573
	uint32_t idx;
ds@1952
   574
	unsigned int unbound = 0;
ds@1952
   575
dvander@2086
   576
	for (iter = pOwner->m_Natives.begin();
dvander@2086
   577
		 iter != pOwner->m_Natives.end();
ds@1952
   578
		 iter++)
ds@1952
   579
	{
ds@1952
   580
		pNative = (*iter);
ds@1952
   581
		/* Find this native! */
dvander@2193
   582
		if (m_pRuntime->FindNativeByName(pNative->name, &idx) != SP_ERROR_NONE)
ds@1952
   583
		{
ds@1952
   584
			continue;
ds@1952
   585
		}
ds@1952
   586
		/* Unbind it */
dvander@2193
   587
		m_pRuntime->GetNativeByIndex(idx, &native);
ds@1952
   588
		native->pfn = NULL;
ds@1952
   589
		native->status = SP_NATIVE_UNBOUND;
ds@1952
   590
		unbound++;
ds@1952
   591
	}
ds@1952
   592
ds@1952
   593
	if (unbound)
ds@1952
   594
	{
ds@1952
   595
		m_FakeNativesMissing = true;
ds@1952
   596
	}
ds@1952
   597
ds@1952
   598
	/* :IDEA: in the future, add native trapping? */
ds@1952
   599
	if (m_FakeNativesMissing || m_LibraryMissing)
ds@1952
   600
	{
ds@1952
   601
		SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
ds@1952
   602
	}
ds@1952
   603
}
ds@1952
   604
ds@1952
   605
unsigned int CPlugin::GetConfigCount()
ds@1952
   606
{
ds@1952
   607
	return (unsigned int)m_configs.size();
ds@1952
   608
}
ds@1952
   609
ds@1952
   610
AutoConfig *CPlugin::GetConfig(unsigned int i)
ds@1952
   611
{
ds@1952
   612
	if (i >= GetConfigCount())
ds@1952
   613
	{
ds@1952
   614
		return NULL;
ds@1952
   615
	}
ds@1952
   616
ds@1952
   617
	return m_configs[i];
ds@1952
   618
}
ds@1952
   619
ds@1952
   620
void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder)
ds@1952
   621
{
ds@1952
   622
	/* Do a check for duplicates to prevent double-execution */
ds@1952
   623
	for (size_t i = 0; i < m_configs.size(); i++)
ds@1952
   624
	{
ds@1952
   625
		if (m_configs[i]->autocfg.compare(cfg) == 0
ds@1952
   626
			&& m_configs[i]->folder.compare(folder) == 0
ds@1952
   627
			&& m_configs[i]->create == autoCreate)
ds@1952
   628
		{
ds@1952
   629
			return;
ds@1952
   630
		}
ds@1952
   631
	}
ds@1952
   632
ds@1952
   633
	AutoConfig *c = new AutoConfig;
ds@1952
   634
ds@1952
   635
	c->autocfg = cfg;
ds@1952
   636
	c->folder = folder;
ds@1952
   637
	c->create = autoCreate;
ds@1952
   638
ds@1952
   639
	m_configs.push_back(c);
ds@1952
   640
}
ds@1952
   641
dvander@2086
   642
void CPlugin::DropEverything()
dvander@2086
   643
{
dvander@2086
   644
	CPlugin *pOther;
dvander@2086
   645
	List<CPlugin *>::iterator iter;
dvander@2086
   646
	List<WeakNative>::iterator wk_iter;
dvander@2086
   647
dvander@2086
   648
	/* Tell everyone that depends on us that we're about to drop */
dvander@2086
   649
	for (iter = m_Dependents.begin();
dvander@2086
   650
		 iter != m_Dependents.end(); 
dvander@2086
   651
		 iter++)
dvander@2086
   652
	{
dvander@2086
   653
		pOther = (*iter);
dvander@2086
   654
		pOther->DependencyDropped(this);
dvander@2086
   655
	}
dvander@2086
   656
dvander@2086
   657
	/* Note: we don't care about things we depend on. 
dvander@2086
   658
	 * The reason is that extensions have their own cleanup 
dvander@2086
   659
	 * code for plugins.  Although the "right" design would be 
dvander@2086
   660
	 * to centralize that here, i'm omitting it for now.  Thus, 
dvander@2086
   661
	 * the code below to walk the plugins list will suffice.
dvander@2086
   662
	 */
dvander@2086
   663
	
dvander@2086
   664
	/* Other plugins could be holding weak references that were 
dvander@2086
   665
	 * added by us.  We need to clean all of those up now.
dvander@2086
   666
	 */
dvander@2086
   667
	for (iter = g_PluginSys.m_plugins.begin();
dvander@2086
   668
		 iter != g_PluginSys.m_plugins.end();
dvander@2086
   669
		 iter++)
dvander@2086
   670
	{
dvander@2086
   671
		(*iter)->DropRefsTo(this);
dvander@2086
   672
	}
dvander@2086
   673
dvander@2086
   674
	/* Proceed with the rest of the necessities. */
dvander@2086
   675
	CNativeOwner::DropEverything();
dvander@2086
   676
}
dvander@2086
   677
dvander@2086
   678
bool CPlugin::AddFakeNative(IPluginFunction *pFunc, const char *name, SPVM_FAKENATIVE_FUNC func)
dvander@2086
   679
{
dvander@2086
   680
	NativeEntry *pEntry;
dvander@2086
   681
dvander@2086
   682
	if ((pEntry = g_ShareSys.AddFakeNative(pFunc, name, func)) == NULL)
dvander@2086
   683
	{
dvander@2086
   684
		return false;
dvander@2086
   685
	}
dvander@2086
   686
dvander@2086
   687
	m_Natives.push_back(pEntry);
dvander@2086
   688
dvander@2086
   689
	return true;
dvander@2086
   690
}
dvander@2086
   691
ds@1952
   692
/*******************
ds@1952
   693
 * PLUGIN ITERATOR *
ds@1952
   694
 *******************/
ds@1952
   695
ds@1952
   696
CPluginManager::CPluginIterator::CPluginIterator(List<CPlugin *> *_mylist)
ds@1952
   697
{
ds@1952
   698
	mylist = _mylist;
ds@1952
   699
	Reset();
ds@1952
   700
}
ds@1952
   701
ds@1952
   702
IPlugin *CPluginManager::CPluginIterator::GetPlugin()
ds@1952
   703
{
ds@1952
   704
	return (*current);
ds@1952
   705
}
ds@1952
   706
ds@1952
   707
bool CPluginManager::CPluginIterator::MorePlugins()
ds@1952
   708
{
ds@1952
   709
	return (current != mylist->end());
ds@1952
   710
}
ds@1952
   711
ds@1952
   712
void CPluginManager::CPluginIterator::NextPlugin()
ds@1952
   713
{
ds@1952
   714
	current++;
ds@1952
   715
}
ds@1952
   716
ds@1952
   717
void CPluginManager::CPluginIterator::Release()
ds@1952
   718
{
ds@1952
   719
	g_PluginSys.ReleaseIterator(this);
ds@1952
   720
}
ds@1952
   721
ds@1952
   722
CPluginManager::CPluginIterator::~CPluginIterator()
ds@1952
   723
{
ds@1952
   724
}
ds@1952
   725
ds@1952
   726
void CPluginManager::CPluginIterator::Reset()
ds@1952
   727
{
ds@1952
   728
	current = mylist->begin();
ds@1952
   729
}
ds@1952
   730
ds@1952
   731
/******************
ds@1952
   732
 * PLUGIN MANAGER *
ds@1952
   733
 ******************/
ds@1952
   734
ds@1952
   735
CPluginManager::CPluginManager()
ds@1952
   736
{
ds@1952
   737
	m_LoadLookup = sm_trie_create();
ds@1952
   738
	m_AllPluginsLoaded = false;
ds@1952
   739
	m_MyIdent = NULL;
ds@1952
   740
	m_LoadingLocked = false;
ds@1952
   741
}
ds@1952
   742
ds@1952
   743
CPluginManager::~CPluginManager()
ds@1952
   744
{
ds@1952
   745
	/* :NOTICE: 
ds@1952
   746
	 * Ignore the fact that there might be plugins in the cache.
ds@1952
   747
	 * This usually means that Core is not being unloaded properly, and everything
ds@1952
   748
	 * will crash anyway.  YAY
ds@1952
   749
	 */
ds@1952
   750
	sm_trie_destroy(m_LoadLookup);
ds@1952
   751
ds@1952
   752
	CStack<CPluginManager::CPluginIterator *>::iterator iter;
ds@1952
   753
	for (iter=m_iters.begin(); iter!=m_iters.end(); iter++)
ds@1952
   754
	{
ds@1952
   755
		delete (*iter);
ds@1952
   756
	}
ds@1952
   757
	m_iters.popall();
ds@1952
   758
}
ds@1952
   759
ds@1952
   760
void CPluginManager::Shutdown()
ds@1952
   761
{
ds@1952
   762
	List<CPlugin *>::iterator iter;
ds@1952
   763
ds@1952
   764
	while ((iter = m_plugins.begin()) != m_plugins.end())
ds@1952
   765
	{
ds@1952
   766
		UnloadPlugin(*iter);
ds@1952
   767
	}
ds@1952
   768
}
ds@1952
   769
ds@1952
   770
void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
ds@1952
   771
{
ds@1952
   772
	/* First read in the database of plugin settings */
ds@1952
   773
	SMCError err;
ds@1952
   774
	SMCStates states;
ds@1952
   775
	m_AllPluginsLoaded = false;
ds@1952
   776
	if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &states)) != SMCError_Okay)
ds@1952
   777
	{
ds@1952
   778
		g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
ds@1952
   779
		const char *err_msg = textparsers->GetSMCErrorString(err);
ds@1952
   780
		if (err_msg)
ds@1952
   781
		{
ds@1952
   782
			g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
ds@1952
   783
		}
ds@1952
   784
	}
ds@1952
   785
ds@1952
   786
	LoadPluginsFromDir(basedir, NULL);
ds@1952
   787
}
ds@1952
   788
ds@1952
   789
void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
ds@1952
   790
{
ds@1952
   791
	char base_path[PLATFORM_MAX_PATH];
ds@1952
   792
ds@1952
   793
	/* Form the current path to start reading from */
ds@1952
   794
	if (localpath == NULL)
ds@1952
   795
	{
ds@1952
   796
		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
ds@1952
   797
	} else {
ds@1952
   798
		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
ds@1952
   799
	}
ds@1952
   800
ds@1952
   801
	IDirectory *dir = g_LibSys.OpenDirectory(base_path);
ds@1952
   802
ds@1952
   803
	if (!dir)
ds@1952
   804
	{
ds@1952
   805
		char error[256];
ds@1952
   806
		g_LibSys.GetPlatformError(error, sizeof(error));
ds@1952
   807
		g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
ds@1952
   808
		g_Logger.LogError("[SM] Platform returned error: %s", error);
ds@1952
   809
		return;
ds@1952
   810
	}
ds@1952
   811
ds@1952
   812
	while (dir->MoreFiles())
ds@1952
   813
	{
ds@1952
   814
		if (dir->IsEntryDirectory() 
ds@1952
   815
			&& (strcmp(dir->GetEntryName(), ".") != 0)
ds@1952
   816
			&& (strcmp(dir->GetEntryName(), "..") != 0)
ds@1952
   817
			&& (strcmp(dir->GetEntryName(), "disabled") != 0)
ds@1952
   818
			&& (strcmp(dir->GetEntryName(), "optional") != 0))
ds@1952
   819
		{
ds@1952
   820
			char new_local[PLATFORM_MAX_PATH];
ds@1952
   821
			if (localpath == NULL)
ds@1952
   822
			{
ds@1952
   823
				/* If no path yet, don't add a former slash */
ds@1952
   824
				snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
ds@1952
   825
			} else {
ds@1952
   826
				g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
ds@1952
   827
			}
ds@1952
   828
			LoadPluginsFromDir(basedir, new_local);
ds@1952
   829
		} else if (dir->IsEntryFile()) {
ds@1952
   830
			const char *name = dir->GetEntryName();
ds@1952
   831
			size_t len = strlen(name);
ds@1952
   832
			if (len >= 4
ds@1952
   833
				&& strcmp(&name[len-4], ".smx") == 0)
ds@1952
   834
			{
ds@1952
   835
				/* If the filename matches, load the plugin */
ds@1952
   836
				char plugin[PLATFORM_MAX_PATH];
ds@1952
   837
				if (localpath == NULL)
ds@1952
   838
				{
ds@1952
   839
					snprintf(plugin, sizeof(plugin), "%s", name);
ds@1952
   840
				} else {
ds@1952
   841
					g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
ds@1952
   842
				}
ds@1952
   843
				LoadAutoPlugin(plugin);
ds@1952
   844
			}
ds@1952
   845
		}
ds@1952
   846
		dir->NextEntry();
ds@1952
   847
	}
ds@1952
   848
	g_LibSys.CloseDirectory(dir);
ds@1952
   849
}
ds@1952
   850
ds@1952
   851
LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
ds@1952
   852
{
ds@1952
   853
	if (m_LoadingLocked)
ds@1952
   854
	{
ds@1952
   855
		return LoadRes_NeverLoad;
ds@1952
   856
	}
ds@1952
   857
dvander@2193
   858
	int err;
ds@1952
   859
	bool no_load = false;
ds@1952
   860
	PluginSettings *pset;
ds@1952
   861
	unsigned int setcount = m_PluginInfo.GetSettingsNum();
ds@1952
   862
	for (unsigned int i=0; i<setcount; i++)
ds@1952
   863
	{
ds@1952
   864
		if ((pset = m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
ds@1952
   865
		{
ds@1952
   866
			continue;
ds@1952
   867
		}
ds@1952
   868
		if (pset->blockload_val)
ds@1952
   869
		{
ds@1952
   870
			no_load = true;
ds@1952
   871
			break;
ds@1952
   872
		}
ds@1952
   873
	}
ds@1952
   874
ds@1952
   875
	/**
ds@1952
   876
	 * Does this plugin already exist?
ds@1952
   877
	 */
ds@1952
   878
	CPlugin *pPlugin;
ds@1952
   879
	if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
ds@1952
   880
	{
ds@1952
   881
		/* Check to see if we should try reloading it */
ds@1952
   882
		if (pPlugin->GetStatus() == Plugin_BadLoad
ds@1952
   883
			|| pPlugin->GetStatus() == Plugin_Error
ds@1952
   884
			|| pPlugin->GetStatus() == Plugin_Failed
ds@1952
   885
			|| no_load)
ds@1952
   886
		{
ds@1952
   887
			UnloadPlugin(pPlugin);
ds@1952
   888
		}
ds@1952
   889
		else
ds@1952
   890
		{
ds@1952
   891
			if (_plugin)
ds@1952
   892
			{
ds@1952
   893
				*_plugin = pPlugin;
ds@1952
   894
			}
ds@1952
   895
			return LoadRes_AlreadyLoaded;
ds@1952
   896
		}
ds@1952
   897
	}
ds@1952
   898
ds@1952
   899
	if (no_load)
ds@1952
   900
	{
ds@1952
   901
		return LoadRes_NeverLoad;
ds@1952
   902
	}
ds@1952
   903
ds@1952
   904
	pPlugin = CPlugin::CreatePlugin(path, error, maxlength);
ds@1952
   905
ds@1952
   906
	assert(pPlugin != NULL);
ds@1952
   907
ds@1952
   908
	pPlugin->m_type = PluginType_MapUpdated;
ds@1952
   909
ds@1952
   910
	ICompilation *co = NULL;
ds@1952
   911
ds@1952
   912
	if (pPlugin->m_status == Plugin_Uncompiled)
ds@1952
   913
	{
dvander@2193
   914
		co = g_pSourcePawn2->StartCompilation();
ds@1952
   915
	}
ds@1952
   916
ds@1952
   917
	for (unsigned int i=0; i<setcount; i++)
ds@1952
   918
	{
ds@1952
   919
		if ((pset=m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
ds@1952
   920
		{
ds@1952
   921
			continue;
ds@1952
   922
		}
ds@1952
   923
		pPlugin->m_type = pset->type_val;
ds@1952
   924
		if (co)
ds@1952
   925
		{
ds@1952
   926
			for (unsigned int j=0; j<pset->opts_num; j++)
ds@1952
   927
			{
ds@1952
   928
				const char *key, *val;
ds@1952
   929
				m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
ds@1952
   930
				if (!key || !val)
ds@1952
   931
				{
ds@1952
   932
					continue;
ds@1952
   933
				}
dvander@2193
   934
				if ((err = co->SetOption(key, val)) == SP_ERROR_NONE)
ds@1952
   935
				{
ds@1952
   936
					if (error)
ds@1952
   937
					{
ds@1952
   938
						snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
ds@1952
   939
					}
dvander@2193
   940
					co->Abort();
ds@1952
   941
					co = NULL;
ds@1952
   942
					break;
ds@1952
   943
				}
ds@1952
   944
			}
ds@1952
   945
		}
ds@1952
   946
	}
ds@1952
   947
ds@1952
   948
	/* Do the actual compiling */
dvander@2193
   949
	if (co != NULL)
ds@1952
   950
	{
dvander@2193
   951
		char fullpath[PLATFORM_MAX_PATH];
dvander@2193
   952
		g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", pPlugin->m_filename);
dvander@2193
   953
dvander@2193
   954
		pPlugin->m_pRuntime = g_pSourcePawn2->LoadPlugin(co, fullpath, &err);
dvander@2193
   955
		if (pPlugin->m_pRuntime == NULL)
dvander@2193
   956
		{
dvander@2193
   957
			snprintf(error, 
dvander@2193
   958
				maxlength, 
dvander@2193
   959
				"Unable to load plugin (error %d: %s)", 
dvander@2193
   960
				err, 
dvander@2193
   961
				g_pSourcePawn2->GetErrorString(err));
dvander@2193
   962
		}
dvander@2193
   963
		else
dvander@2193
   964
		{
dvander@2193
   965
			pPlugin->UpdateInfo();
dvander@2193
   966
			pPlugin->m_status = Plugin_Created;
dvander@2193
   967
		}
ds@1952
   968
	}
ds@1952
   969
ds@1952
   970
	/* Get the status */
ds@1952
   971
	if (pPlugin->GetStatus() == Plugin_Created)
ds@1952
   972
	{
dvander@2086
   973
		/* First native pass - add anything from Core */
dvander@2086
   974
		g_ShareSys.BindNativesToPlugin(pPlugin, true);
ds@1952
   975
		pPlugin->InitIdentity();
ds@1952
   976
		if (pPlugin->Call_AskPluginLoad(error, maxlength))
ds@1952
   977
		{
ds@1952
   978
			/* Autoload any modules */
ds@1952
   979
			LoadOrRequireExtensions(pPlugin, 1, error, maxlength);
ds@1952
   980
		}
ds@1952
   981
		else
ds@1952
   982
		{
ds@1952
   983
			pPlugin->SetErrorState(Plugin_Failed, "%s", error);
ds@1952
   984
		}
ds@1952
   985
	}
ds@1952
   986
ds@1952
   987
	/* Save the time stamp */
ds@1952
   988
	time_t t = pPlugin->GetFileTimeStamp();
ds@1952
   989
	pPlugin->SetTimeStamp(t);
ds@1952
   990
ds@1952
   991
	if (_plugin)
ds@1952
   992
	{
ds@1952
   993
		*_plugin = pPlugin;
ds@1952
   994
	}
ds@1952
   995
ds@1952
   996
	return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure;
ds@1952
   997
}
ds@1952
   998
ds@1952
   999
IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded)
ds@1952
  1000
{
ds@1952
  1001
	CPlugin *pl;
ds@1952
  1002
	LoadRes res;
ds@1952
  1003
ds@1952
  1004
	*wasloaded = false;
dvander@2226
  1005
	if ((res=_LoadPlugin(&pl, path, true, type, error, maxlength)) == LoadRes_Failure)
ds@1952
  1006
	{
ds@1952
  1007
		delete pl;
ds@1952
  1008
		return NULL;
ds@1952
  1009
	}
ds@1952
  1010
ds@1952
  1011
	if (res == LoadRes_AlreadyLoaded)
ds@1952
  1012
	{
ds@1952
  1013
		*wasloaded = true;
ds@1952
  1014
		return pl;
ds@1952
  1015
	}
ds@1952
  1016
ds@1952
  1017
	if (res == LoadRes_NeverLoad)
ds@1952
  1018
	{
ds@1952
  1019
		if (m_LoadingLocked)
ds@1952
  1020
		{
ds@1952
  1021
			UTIL_Format(error, maxlength, "There is a global plugin loading lock in effect");
ds@1952
  1022
		}
ds@1952
  1023
		else
ds@1952
  1024
		{
ds@1952
  1025
			UTIL_Format(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
ds@1952
  1026
		}
ds@1952
  1027
		return NULL;
ds@1952
  1028
	}
ds@1952
  1029
ds@1952
  1030
	AddPlugin(pl);
ds@1952
  1031
ds@1952
  1032
	/* Run second pass if we need to */
ds@1952
  1033
	if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
ds@1952
  1034
	{
ds@1952
  1035
		if (!RunSecondPass(pl, error, maxlength))
ds@1952
  1036
		{
ds@1952
  1037
			UnloadPlugin(pl);
ds@1952
  1038
			return NULL;
ds@1952
  1039
		}
ds@1952
  1040
		pl->Call_OnAllPluginsLoaded();
ds@1952
  1041
	}
ds@1952
  1042
ds@1952
  1043
	return pl;
ds@1952
  1044
}
ds@1952
  1045
ds@1952
  1046
void CPluginManager::LoadAutoPlugin(const char *plugin)
ds@1952
  1047
{
ds@1952
  1048
	CPlugin *pl = NULL;
ds@1952
  1049
	LoadRes res;
ds@1952
  1050
	char error[255] = "Unknown error";
ds@1952
  1051
ds@1952
  1052
	if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
ds@1952
  1053
	{
ds@1952
  1054
		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
ds@1952
  1055
		pl->SetErrorState(Plugin_Failed, "%s", error);
ds@1952
  1056
	}
ds@1952
  1057
ds@1952
  1058
	if (res == LoadRes_Successful)
ds@1952
  1059
	{
ds@1952
  1060
		AddPlugin(pl);
ds@1952
  1061
	}
ds@1952
  1062
}
ds@1952
  1063
ds@1952
  1064
void CPluginManager::AddPlugin(CPlugin *pPlugin)
ds@1952
  1065
{
ds@1952
  1066
	List<IPluginsListener *>::iterator iter;
ds@1952
  1067
	IPluginsListener *pListener;
ds@1952
  1068
ds@1952
  1069
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
ds@1952
  1070
	{
ds@1952
  1071
		pListener = (*iter);
ds@1952
  1072
		pListener->OnPluginCreated(pPlugin);
ds@1952
  1073
	}
ds@1952
  1074
ds@1952
  1075
	m_plugins.push_back(pPlugin);
ds@1952
  1076
	sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
ds@1952
  1077
}
ds@1952
  1078
ds@1952
  1079
void CPluginManager::LoadAll_SecondPass()
ds@1952
  1080
{
ds@1952
  1081
	List<CPlugin *>::iterator iter;
ds@1952
  1082
	CPlugin *pPlugin;
ds@1952
  1083
ds@1952
  1084
	char error[256];
ds@1952
  1085
	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
ds@1952
  1086
	{
ds@1952
  1087
		pPlugin = (*iter);
ds@1952
  1088
		if (pPlugin->GetStatus() == Plugin_Loaded)
ds@1952
  1089
		{
ds@1952
  1090
			error[0] = '\0';
ds@1952
  1091
			if (!RunSecondPass(pPlugin, error, sizeof(error)))
ds@1952
  1092
			{
ds@1952
  1093
				g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
ds@1952
  1094
				pPlugin->SetErrorState(Plugin_Failed, "%s", error);
ds@1952
  1095
			}
ds@1952
  1096
		}
ds@1952
  1097
	}
ds@1952
  1098
ds@1952
  1099
	m_AllPluginsLoaded = true;
ds@1952
  1100
}
ds@1952
  1101
ds@1952
  1102
bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength)
ds@1952
  1103
{
ds@1952
  1104
	struct _pl
ds@1952
  1105
	{
ds@1952
  1106
		cell_t name;
ds@1952
  1107
		cell_t file;
ds@1952
  1108
		cell_t required;
ds@1952
  1109
	} *pl;
ds@1952
  1110
ds@1952
  1111
	IPluginContext *pBase = pPlugin->GetBaseContext();
ds@1952
  1112
	uint32_t num = pBase->GetPubVarsNum();
ds@1952
  1113
	sp_pubvar_t *pubvar;
ds@1952
  1114
	char *name, *file;
ds@1952
  1115
	char pathfile[PLATFORM_MAX_PATH];
ds@1952
  1116
ds@1952
  1117
	for (uint32_t i=0; i<num; i++)
ds@1952
  1118
	{
ds@1952
  1119
		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
ds@1952
  1120
		{
ds@1952
  1121
			continue;
ds@1952
  1122
		}
ds@1952
  1123
		if (strncmp(pubvar->name, "__pl_", 5) == 0)
ds@1952
  1124
		{
ds@1952
  1125
			pl = (_pl *)pubvar->offs;
ds@1952
  1126
			if (pBase->LocalToString(pl->file, &file) != SP_ERROR_NONE)
ds@1952
  1127
			{
ds@1952
  1128
				continue;
ds@1952
  1129
			}
ds@1952
  1130
			if (pBase->LocalToString(pl->name, &name) != SP_ERROR_NONE)
ds@1952
  1131
			{
ds@1952
  1132
				continue;
ds@1952
  1133
			}
ds@1952
  1134
			g_LibSys.GetFileFromPath(pathfile, sizeof(pathfile), pPlugin->GetFilename());
ds@1952
  1135
			if (strcmp(pathfile, file) == 0)
ds@1952
  1136
			{
ds@1952
  1137
				continue;
ds@1952
  1138
			}
ds@1952
  1139
			if (pl->required == false)
ds@1952
  1140
			{
ds@1952
  1141
				IPluginFunction *pFunc;
ds@1952
  1142
				char buffer[64];
ds@1952
  1143
				UTIL_Format(buffer, sizeof(buffer), "__pl_%s_SetNTVOptional", &pubvar->name[5]);
ds@1952
  1144
				if ((pFunc=pBase->GetFunctionByName(buffer)))
ds@1952
  1145
				{
ds@1952
  1146
					cell_t res;
ds@1952
  1147
					pFunc->Execute(&res);
dvander@2193
  1148
					if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
ds@1952
  1149
					{
ds@1952
  1150
						if (error)
ds@1952
  1151
						{
ds@1952
  1152
							snprintf(error, maxlength, "Fatal error during initializing plugin load");
ds@1952
  1153
						}
ds@1952
  1154
						return false;
ds@1952
  1155
					}
ds@1952
  1156
				}
ds@1952
  1157
			}
ds@1952
  1158
			else
ds@1952
  1159
			{
ds@1952
  1160
				/* Check that we aren't registering the same library twice */
ds@1952
  1161
				if (pPlugin->m_RequiredLibs.find(name) == pPlugin->m_RequiredLibs.end())
ds@1952
  1162
				{
ds@1952
  1163
					pPlugin->m_RequiredLibs.push_back(name);
ds@1952
  1164
				}
ds@1952
  1165
				else
ds@1952
  1166
				{
ds@1952
  1167
					continue;
ds@1952
  1168
				}
ds@1952
  1169
				List<CPlugin *>::iterator iter;
ds@1952
  1170
				CPlugin *pl;
ds@1952
  1171
				bool found = false;
ds@1952
  1172
				for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
ds@1952
  1173
				{
ds@1952
  1174
					pl = (*iter);
ds@1952
  1175
					if (pl->m_Libraries.find(name) != pl->m_Libraries.end())
ds@1952
  1176
					{
ds@1952
  1177
						found = true;
ds@1952
  1178
						break;
ds@1952
  1179
					}
ds@1952
  1180
				}
ds@1952
  1181
				if (!found)
ds@1952
  1182
				{
ds@1952
  1183
					if (error)
ds@1952
  1184
					{
ds@1952
  1185
						snprintf(error, maxlength, "Could not find required plugin \"%s\"", name);
ds@1952
  1186
					}
ds@1952
  1187
					return false;
ds@1952
  1188
				}
ds@1952
  1189
			}
ds@1952
  1190
		}
ds@1952
  1191
	}
ds@1952
  1192
ds@1952
  1193
	return true;
ds@1952
  1194
}
ds@1952
  1195
ds@1952
  1196
bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
ds@1952
  1197
{
ds@1952
  1198
	/* Find any extensions this plugin needs */
ds@1952
  1199
	struct _ext
ds@1952
  1200
	{
ds@1952
  1201
		cell_t name;
ds@1952
  1202
		cell_t file;
ds@1952
  1203
		cell_t autoload;
ds@1952
  1204
		cell_t required;
ds@1952
  1205
	} *ext;
ds@1952
  1206
ds@1952
  1207
	IPluginContext *pBase = pPlugin->GetBaseContext();
ds@1952
  1208
	uint32_t num = pBase->GetPubVarsNum();
ds@1952
  1209
	sp_pubvar_t *pubvar;
ds@1952
  1210
	IExtension *pExt;
ds@1952
  1211
	char path[PLATFORM_MAX_PATH];
ds@1952
  1212
	char *file, *name;
ds@1952
  1213
	for (uint32_t i=0; i<num; i++)
ds@1952
  1214
	{
ds@1952
  1215
		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
ds@1952
  1216
		{
ds@1952
  1217
			continue;
ds@1952
  1218
		}
ds@1952
  1219
		if (strncmp(pubvar->name, "__ext_", 6) == 0)
ds@1952
  1220
		{
ds@1952
  1221
			ext = (_ext *)pubvar->offs;
ds@1952
  1222
			if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
ds@1952
  1223
			{
ds@1952
  1224
				continue;
ds@1952
  1225
			}
ds@1952
  1226
			if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
ds@1952
  1227
			{
ds@1952
  1228
				continue;
ds@1952
  1229
			}
ds@1952
  1230
			if (pass == 1)
ds@1952
  1231
			{
ds@1952
  1232
				/* Attempt to auto-load if necessary */
ds@1952
  1233
				if (ext->autoload)
ds@1952
  1234
				{
ds@1952
  1235
					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
ds@1952
  1236
					g_Extensions.LoadAutoExtension(path);
ds@1952
  1237
				}
ds@1952
  1238
			}
ds@1952
  1239
			else if (pass == 2)
ds@1952
  1240
			{
ds@1952
  1241
				/* Is this required? */
ds@1952
  1242
				if (ext->required)
ds@1952
  1243
				{
ds@1952
  1244
					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
ds@1952
  1245
					if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
ds@1952
  1246
					{
ds@1952
  1247
						pExt = g_Extensions.FindExtensionByName(name);
ds@1952
  1248
					}
ds@1952
  1249
					/* :TODO: should we bind to unloaded extensions?
ds@1952
  1250
					 * Currently the extension manager will ignore this.
ds@1952
  1251
					 */
ds@1952
  1252
					if (!pExt || !pExt->IsRunning(NULL, 0))
ds@1952
  1253
					{
ds@1952
  1254
						if (error)
ds@1952
  1255
						{
ds@1952
  1256
							snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
ds@1952
  1257
						}
ds@1952
  1258
						return false;
ds@1952
  1259
					}
ds@1952
  1260
					else
ds@1952
  1261
					{
ds@1952
  1262
						g_Extensions.BindChildPlugin(pExt, pPlugin);
ds@1952
  1263
					}
ds@1952
  1264
				}
ds@1952
  1265
				else
ds@1952
  1266
				{
ds@1952
  1267
					IPluginFunction *pFunc;
ds@1952
  1268
					char buffer[64];
ds@1952
  1269
					UTIL_Format(buffer, sizeof(buffer), "__ext_%s_SetNTVOptional", &pubvar->name[6]);
ds@1952
  1270
ds@1952
  1271
					if ((pFunc = pBase->GetFunctionByName(buffer)) != NULL)
ds@1952
  1272
					{
ds@1952
  1273
						cell_t res;
ds@1952
  1274
						pFunc->Execute(&res);
dvander@2193
  1275
						if (pPlugin->GetBaseContext()->GetLastNativeError() != SP_ERROR_NONE)
ds@1952
  1276
						{
ds@1952
  1277
							if (error)
ds@1952
  1278
							{
ds@1952
  1279
								UTIL_Format(error, maxlength, "Fatal error during plugin initialization (ext req)");
ds@1952
  1280
							}
ds@1952
  1281
							return false;
ds@1952
  1282
						}
ds@1952
  1283
					}
ds@1952
  1284
				}
ds@1952
  1285
			}
ds@1952
  1286
		}
ds@1952
  1287
	}
ds@1952
  1288
ds@1952
  1289
	return true;
ds@1952
  1290
}
ds@1952
  1291
ds@1952
  1292
bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
ds@1952
  1293
{
ds@1952
  1294
	/* Second pass for extension requirements */
ds@1952
  1295
	if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
ds@1952
  1296
	{
ds@1952
  1297
		return false;
ds@1952
  1298
	}
ds@1952
  1299
ds@1952
  1300
	if (!FindOrRequirePluginDeps(pPlugin, error, maxlength))
ds@1952
  1301
	{
ds@1952
  1302
		return false;
ds@1952
  1303
	}
ds@1952
  1304
dvander@2086
  1305
	/* Run another binding pass */
dvander@2086
  1306
	g_ShareSys.BindNativesToPlugin(pPlugin, false);
ds@1952
  1307
dvander@2086
  1308
	/* Find any unbound natives. Right now, these are not allowed. */
ds@1952
  1309
	IPluginContext *pContext = pPlugin->GetBaseContext();
ds@1952
  1310
	uint32_t num = pContext->GetNativesNum();
ds@1952
  1311
	sp_native_t *native;
ds@1952
  1312
	for (unsigned int i=0; i<num; i++)
ds@1952
  1313
	{
ds@1952
  1314
		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
ds@1952
  1315
		{
ds@1952
  1316
			break;
ds@1952
  1317
		}
ds@1952
  1318
		if (native->status == SP_NATIVE_UNBOUND
ds@1952
  1319
			&& native->name[0] != '@'
ds@1952
  1320
			&& !(native->flags & SP_NTVFLAG_OPTIONAL))
ds@1952
  1321
		{
ds@1952
  1322
			if (error)
ds@1952
  1323
			{
dvander@2210
  1324
				snprintf(error, maxlength, "Native \"%s\" was not found", native->name);
ds@1952
  1325
			}
ds@1952
  1326
			return false;
ds@1952
  1327
		}
ds@1952
  1328
	}
ds@1952
  1329
ds@1952
  1330
	/* Finish by telling all listeners */
ds@1952
  1331
	List<IPluginsListener *>::iterator iter;
ds@1952
  1332
	IPluginsListener *pListener;
ds@1952
  1333
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
ds@1952
  1334
	{
ds@1952
  1335
		pListener = (*iter);
ds@1952
  1336
		pListener->OnPluginLoaded(pPlugin);
ds@1952
  1337
	}
ds@1952
  1338
	
ds@1952
  1339
	/* Tell this plugin to finish initializing itself */
ds@1952
  1340
	pPlugin->Call_OnPluginStart();
ds@1952
  1341
ds@1952
  1342
	/* Now, if we have fake natives, go through all plugins that might need rebinding */
dvander@2086
  1343
	if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_Natives.size())
ds@1952
  1344
	{
ds@1952
  1345
		List<CPlugin *>::iterator pl_iter;
ds@1952
  1346
		CPlugin *pOther;
ds@1952
  1347
		for (pl_iter = m_plugins.begin();
ds@1952
  1348
			 pl_iter != m_plugins.end();
ds@1952
  1349
			 pl_iter++)
ds@1952
  1350
		{
ds@1952
  1351
			pOther = (*pl_iter);
ds@1952
  1352
			if ((pOther->GetStatus() == Plugin_Error
ds@1952
  1353
				&& (pOther->m_FakeNativesMissing || pOther->m_LibraryMissing))
ds@1952
  1354
				|| pOther->m_FakeNativesMissing)
ds@1952
  1355
			{
ds@1952
  1356
				TryRefreshDependencies(pOther);
ds@1952
  1357
			}
dvander@2086
  1358
			else if ((pOther->GetStatus() == Plugin_Running
dvander@2086
  1359
					  || pOther->GetStatus() == Plugin_Paused)
dvander@2086
  1360
					 && pOther != pPlugin)
dvander@2086
  1361
			{
dvander@2086
  1362
				List<NativeEntry *>::iterator nv_iter;
dvander@2086
  1363
				for (nv_iter = pPlugin->m_Natives.begin();
dvander@2086
  1364
					 nv_iter != pPlugin->m_Natives.end();
dvander@2086
  1365
					 nv_iter++)
dvander@2086
  1366
				{
dvander@2086
  1367
					g_ShareSys.BindNativeToPlugin(pOther, (*nv_iter));
dvander@2086
  1368
				}
dvander@2086
  1369
			}
ds@1952
  1370
		}
ds@1952
  1371
	}
ds@1952
  1372
ds@1952
  1373
	/* Go through our libraries and tell other plugins they're added */
ds@1952
  1374
	List<String>::iterator s_iter;
ds@1952
  1375
	for (s_iter = pPlugin->m_Libraries.begin();
ds@1952
  1376
		s_iter != pPlugin->m_Libraries.end();
ds@1952
  1377
		s_iter++)
ds@1952
  1378
	{
ds@1952
  1379
		OnLibraryAction((*s_iter).c_str(), true, false);
ds@1952
  1380
	}
ds@1952
  1381
dvander@2042
  1382
	/* :TODO: optimize? does this even matter? */
dvander@2042
  1383
	pPlugin->GetPhrases()->AddPhraseFile("core.phrases");
ds@1952
  1384
ds@1952
  1385
	return true;
ds@1952
  1386
}
ds@1952
  1387
ds@1952
  1388
void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
ds@1952
  1389
{
ds@1952
  1390
	assert(pPlugin->GetBaseContext() != NULL);
ds@1952
  1391
dvander@2086
  1392
	g_ShareSys.BindNativesToPlugin(pPlugin, false);
ds@1952
  1393
ds@1952
  1394
	List<String>::iterator lib_iter;
ds@1952
  1395
	List<String>::iterator req_iter;
ds@1952
  1396
	List<CPlugin *>::iterator pl_iter;
ds@1952
  1397
	CPlugin *pl;
ds@1952
  1398
	for (req_iter=pPlugin->m_RequiredLibs.begin(); req_iter!=pPlugin->m_RequiredLibs.end(); req_iter++)
ds@1952
  1399
	{
ds@1952
  1400
		bool found = false;
ds@1952
  1401
		for (pl_iter=m_plugins.begin(); pl_iter!=m_plugins.end(); pl_iter++)
ds@1952
  1402
		{
ds@1952
  1403
			pl = (*pl_iter);
ds@1952
  1404
			for (lib_iter=pl->m_Libraries.begin(); lib_iter!=pl->m_Libraries.end(); lib_iter++)
ds@1952
  1405
			{
ds@1952
  1406
				if ((*req_iter) == (*lib_iter))
ds@1952
  1407
				{
ds@1952
  1408
					found = true;
ds@1952
  1409
				}
ds@1952
  1410
			}
ds@1952
  1411
		}
ds@1952
  1412
		if (!found)
ds@1952
  1413
		{
ds@1952
  1414
			pPlugin->SetErrorState(Plugin_Error, "Library not found: %s", (*req_iter).c_str());
ds@1952
  1415
			return;
ds@1952
  1416
		}
ds@1952
  1417
	}
ds@1952
  1418
ds@1952
  1419
	/* Find any unbound natives
ds@1952
  1420
	 * Right now, these are not allowed
ds@1952
  1421
	 */
ds@1952
  1422
	IPluginContext *pContext = pPlugin->GetBaseContext();
ds@1952
  1423
	uint32_t num = pContext->GetNativesNum();
ds@1952
  1424
	sp_native_t *native;
ds@1952
  1425
	for (unsigned int i=0; i<num; i++)
ds@1952
  1426
	{
ds@1952
  1427
		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
ds@1952
  1428
		{
ds@1952
  1429
			break;
ds@1952
  1430
		}
ds@1952
  1431
		if (native->status == SP_NATIVE_UNBOUND && !(native->flags & SP_NTVFLAG_OPTIONAL))
ds@1952
  1432
		{
ds@1952
  1433
			pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
ds@1952
  1434
			return;
ds@1952
  1435
		}
ds@1952
  1436
	}
ds@1952
  1437
ds@1952
  1438
	if (pPlugin->GetStatus() == Plugin_Error)
ds@1952
  1439
	{
ds@1952
  1440
		/* If we got here, all natives are okay again! */
ds@1952
  1441
		pPlugin->m_status = Plugin_Running;
dvander@2193
  1442
		if (pPlugin->m_pRuntime->IsPaused())
ds@1952
  1443
		{
dvander@2193
  1444
			pPlugin->m_pRuntime->SetPauseState(false);
ds@1952
  1445
			_SetPauseState(pPlugin, false);
ds@1952
  1446
		}
ds@1952
  1447
	}
ds@1952
  1448
}
ds@1952
  1449
ds@1952
  1450
bool CPluginManager::UnloadPlugin(IPlugin *plugin)
ds@1952
  1451
{
ds@1952
  1452
	CPlugin *pPlugin = (CPlugin *)plugin;
ds@1952
  1453
ds@1952
  1454
	/* This prevents removal during insertion or anything else weird */
ds@1952
  1455
	if (m_plugins.find(pPlugin) == m_plugins.end())
ds@1952
  1456
	{
ds@1952
  1457
		return false;
ds@1952
  1458
	}
ds@1952
  1459
ds@1952
  1460
	IPluginContext *pContext = plugin->GetBaseContext();
ds@1952
  1461
	if (pContext->IsInExec())
ds@1952
  1462
	{
ds@1952
  1463
		char buffer[255];
ds@1952
  1464
		UTIL_Format(buffer, sizeof(buffer), "sm plugins unload %s\n", plugin->GetFilename());
ds@1952
  1465
		engine->ServerCommand(buffer);
ds@1952
  1466
		return false;
ds@1952
  1467
	}
ds@1952
  1468
ds@1952
  1469
	/* Remove us from the lookup table and linked list */
ds@1952
  1470
	m_plugins.remove(pPlugin);
ds@1952
  1471
	sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
ds@1952
  1472
ds@1952
  1473
	/* Go through our libraries and tell other plugins they're gone */
ds@1952
  1474
	List<String>::iterator s_iter;
ds@1952
  1475
	for (s_iter = pPlugin->m_Libraries.begin();
ds@1952
  1476
		 s_iter != pPlugin->m_Libraries.end();
ds@1952
  1477
		 s_iter++)
ds@1952
  1478
	{
ds@1952
  1479
		OnLibraryAction((*s_iter).c_str(), true, true);
ds@1952
  1480
	}
ds@1952
  1481
ds@1952
  1482
	List<IPluginsListener *>::iterator iter;
ds@1952
  1483
	IPluginsListener *pListener;
ds@1952
  1484
ds@1952
  1485
	if (pPlugin->GetStatus() <= Plugin_Error)
ds@1952
  1486
	{
ds@1952
  1487
		/* Notify listeners of unloading */
ds@1952
  1488
		for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
ds@1952
  1489
		{
ds@1952
  1490
			pListener = (*iter);
ds@1952
  1491
			pListener->OnPluginUnloaded(pPlugin);
ds@1952
  1492
		}
ds@1952
  1493
		/* Notify plugin */
ds@1952
  1494
		pPlugin->Call_OnPluginEnd();
ds@1952
  1495
	}
ds@1952
  1496
dvander@2086
  1497
	pPlugin->DropEverything();
ds@1952
  1498
ds@1952
  1499
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
ds@1952
  1500
	{
ds@1952
  1501
		/* Notify listeners of destruction */
ds@1952
  1502
		pListener = (*iter);
ds@1952
  1503
		pListener->OnPluginDestroyed(pPlugin);
ds@1952
  1504
	}
ds@1952
  1505
	
ds@1952
  1506
	/* Tell the plugin to delete itself */
ds@1952
  1507
	delete pPlugin;
ds@1952
  1508
ds@1952
  1509
	return true;
ds@1952
  1510
}
ds@1952
  1511
ds@1952
  1512
IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
ds@1952
  1513
{
dvander@2193
  1514
	IPlugin *pPlugin;
dvander@2193
  1515
	IPluginContext *pContext;
dvander@2193
  1516
dvander@2193
  1517
	pContext = reinterpret_cast<IPluginContext *>(const_cast<sp_context_t *>(ctx));
dvander@2193
  1518
dvander@2193
  1519
	if (pContext->GetKey(2, (void **)&pPlugin))
dvander@2193
  1520
	{
dvander@2193
  1521
		return pPlugin;
dvander@2193
  1522
	}
dvander@2193
  1523
dvander@2193
  1524
	return NULL;
dvander@2193
  1525
}
dvander@2193
  1526
dvander@2193
  1527
CPlugin *CPluginManager::GetPluginByCtx(const sp_context_t *ctx)
dvander@2193
  1528
{
dvander@2193
  1529
	return (CPlugin *)FindPluginByContext(ctx);
ds@1952
  1530
}
ds@1952
  1531
ds@1952
  1532
unsigned int CPluginManager::GetPluginCount()
ds@1952
  1533
{
ds@1952
  1534
	return m_plugins.size();
ds@1952
  1535
}
ds@1952
  1536
ds@1952
  1537
void CPluginManager::AddPluginsListener(IPluginsListener *listener)
ds@1952
  1538
{
ds@1952
  1539
	m_listeners.push_back(listener);
ds@1952
  1540
}
ds@1952
  1541
ds@1952
  1542
void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
ds@1952
  1543
{
ds@1952
  1544
	m_listeners.remove(listener);
ds@1952
  1545
}
ds@1952
  1546
ds@1952
  1547
IPluginIterator *CPluginManager::GetPluginIterator()
ds@1952
  1548
{
ds@1952
  1549
	if (m_iters.empty())
ds@1952
  1550
	{
ds@1952
  1551
		return new CPluginIterator(&m_plugins);
ds@1952
  1552
	} else {
ds@1952
  1553
		CPluginIterator *iter = m_iters.front();
ds@1952
  1554
		m_iters.pop();
ds@1952
  1555
		iter->Reset();
ds@1952
  1556
		return iter;
ds@1952
  1557
	}
ds@1952
  1558
}
ds@1952
  1559
ds@1952
  1560
void CPluginManager::ReleaseIterator(CPluginIterator *iter)
ds@1952
  1561
{
ds@1952
  1562
	m_iters.push(iter);
ds@1952
  1563
}
ds@1952
  1564
ds@1952
  1565
bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
ds@1952
  1566
{
ds@1952
  1567
	/* As an optimization, we do not call strlen, but compute the length in the first pass */
ds@1952
  1568
	size_t alias_len = 0;
ds@1952
  1569
	size_t local_len = 0;
ds@1952
  1570
ds@1952
  1571
	const char *ptr = alias;
ds@1952
  1572
	unsigned int alias_explicit_paths = 0;
ds@1952
  1573
	unsigned int alias_path_end = 0;
ds@1952
  1574
	while (*ptr != '\0')
ds@1952
  1575
	{
ds@1952
  1576
		if (*ptr == '\\' || *ptr == '/')
ds@1952
  1577
		{
ds@1952
  1578
			alias_explicit_paths++;
ds@1952
  1579
			alias_path_end = alias_len;
ds@1952
  1580
		}
ds@1952
  1581
		alias_len++;
ds@1952
  1582
		ptr++;
ds@1952
  1583
	}
ds@1952
  1584
ds@1952
  1585
	if (alias_explicit_paths && alias_path_end == alias_len - 1)
ds@1952
  1586
	{
ds@1952
  1587
		/* Trailing slash is totally invalid here */
ds@1952
  1588
		return false;
ds@1952
  1589
	}
ds@1952
  1590
ds@1952
  1591
	ptr = localpath;
ds@1952
  1592
	unsigned int local_explicit_paths = 0;
ds@1952
  1593
	unsigned int local_path_end = 0;
ds@1952
  1594
	while (*ptr != '\0')
ds@1952
  1595
	{
ds@1952
  1596
		if (*ptr == '\\' || *ptr == '/')
ds@1952
  1597
		{
ds@1952
  1598
			local_explicit_paths++;
ds@1952
  1599
			local_path_end = local_len;
ds@1952
  1600
		}
ds@1952
  1601
		local_len++;
ds@1952
  1602
		ptr++;
ds@1952
  1603
	}
ds@1952
  1604
ds@1952
  1605
	/* If the alias has more explicit paths than the real path,
ds@1952
  1606
	 * no match will be possible.
ds@1952
  1607
	 */
ds@1952
  1608
	if (alias_explicit_paths > local_explicit_paths)
ds@1952
  1609
	{
ds@1952
  1610
		return false;
ds@1952
  1611
	}
ds@1952
  1612
ds@1952
  1613
	if (alias_explicit_paths)
ds@1952
  1614
	{
ds@1952
  1615
		/* We need to find if the paths match now.  For example, these should all match:
ds@1952
  1616
		 * csdm     csdm
ds@1952
  1617
		 * csdm     optional/csdm
ds@1952
  1618
		 * csdm/ban optional/crab/csdm/ban
ds@1952
  1619
		*/
ds@1952
  1620
		const char *aliasptr = alias;
ds@1952
  1621
		const char *localptr = localpath;
ds@1952
  1622
		bool match = true;
ds@1952
  1623
		do
ds@1952
  1624
		{
ds@1952
  1625
			if (*aliasptr != *localptr)
ds@1952
  1626
			{
ds@1952
  1627
				/* We have to knock one path off */
ds@1952
  1628
				local_explicit_paths--;
ds@1952
  1629
				if (alias_explicit_paths > local_explicit_paths)
ds@1952
  1630
				{
ds@1952
  1631
					/* Skip out if we're gonna have an impossible match */
ds@1952
  1632
					return false;
ds@1952
  1633
				}
ds@1952
  1634
				/* Eat up localptr tokens until we get a result */
ds@1952
  1635
				while (((localptr - localpath) < (int)local_path_end)
ds@1952
  1636
					&& *localptr != '/'
ds@1952
  1637
					&& *localptr != '\\')
ds@1952
  1638
				{
ds@1952
  1639
					localptr++;
ds@1952
  1640
				}
ds@1952
  1641
				/* Check if we hit the end of our searchable area.
ds@1952
  1642
				 * This probably isn't possible because of the path 
ds@1952
  1643
				 * count check, but it's a good idea anyway.
ds@1952
  1644
				 */
ds@1952
  1645
				if ((localptr - localpath) >= (int)local_path_end)
ds@1952
  1646
				{
ds@1952
  1647
					return false;
ds@1952
  1648
				} else {
ds@1952
  1649
					/* Consume the slash token */
ds@1952
  1650
					localptr++;
ds@1952
  1651
				}
ds@1952
  1652
				/* Reset the alias pointer so we can continue consuming */
ds@1952
  1653
				aliasptr = alias;
ds@1952
  1654
				match = false;
ds@1952
  1655
				continue;
ds@1952
  1656
			}
ds@1952
  1657
			/* Note:
ds@1952
  1658
			 * This is safe because if localptr terminates early, aliasptr will too
ds@1952
  1659
			 */
ds@1952
  1660
			do
ds@1952
  1661
			{
ds@1952
  1662
				/* We should never reach the end of the string because of this check. */
ds@1952
  1663
				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
ds@1952
  1664
				bool localend = (localptr - localpath) > (int)local_path_end;
ds@1952
  1665
				if (aliasend || localend)
ds@1952
  1666
				{
ds@1952
  1667
					if (aliasend && localend)
ds@1952
  1668
					{
ds@1952
  1669
						/* we matched, and we can break out now */
ds@1952
  1670
						match = true;
ds@1952
  1671
						break;
ds@1952
  1672
					}
ds@1952
  1673
					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
ds@1952
  1674
					match = false;
ds@1952
  1675
					break;
ds@1952
  1676
				}
ds@1952
  1677
ds@1952
  1678
				/* If we got here, it's safe to compare the next two tokens */
ds@1952
  1679
				if (*localptr != *aliasptr)
ds@1952
  1680
				{
ds@1952
  1681
					match = false;
ds@1952
  1682
					break;
ds@1952
  1683
				}
ds@1952
  1684
				localptr++;
ds@1952
  1685
				aliasptr++;
ds@1952
  1686
			} while (true);
ds@1952
  1687
		} while (!match);
ds@1952
  1688
	}
ds@1952
  1689
ds@1952
  1690
	/* If we got here, it's time to compare filenames */
ds@1952
  1691
	const char *aliasptr = alias;
ds@1952
  1692
	const char *localptr = localpath;
ds@1952
  1693
ds@1952
  1694
	if (alias_explicit_paths)
ds@1952
  1695
	{
ds@1952
  1696
		aliasptr = &alias[alias_path_end + 1];
ds@1952
  1697
	}
ds@1952
  1698
ds@1952
  1699
	if (local_explicit_paths)
ds@1952
  1700
	{
ds@1952
  1701
		localptr = &localpath[local_path_end + 1];
ds@1952
  1702
	}
ds@1952
  1703
ds@1952
  1704
	while (true)
ds@1952
  1705
	{
ds@1952
  1706
		if (*aliasptr == '*')
ds@1952
  1707
		{
ds@1952
  1708
			/* First, see if this is the last character */
ds@1952
  1709
			if ((unsigned)(aliasptr - alias) == alias_len - 1)
ds@1952
  1710
			{
ds@1952
  1711
				/* If so, there's no need to match anything else */
ds@1952
  1712
				return true;
ds@1952
  1713
			}
ds@1952
  1714
			/* Otherwise, we need to search for an appropriate matching sequence in local.
ds@1952
  1715
			 * Note that we only need to search up to the next asterisk.
ds@1952
  1716
			 */
ds@1952
  1717
			aliasptr++;
ds@1952
  1718
			bool match = true;
ds@1952
  1719
			const char *local_orig = localptr;
ds@1952
  1720
			do
ds@1952
  1721
			{
ds@1952
  1722
				match = true;
ds@1952
  1723
				while (*aliasptr != '\0' && *aliasptr != '*')
ds@1952
  1724
				{
ds@1952
  1725
					/* Since aliasptr is never '\0', localptr hitting the end will fail */
ds@1952
  1726
					if (*aliasptr != *localptr)
ds@1952
  1727
					{
ds@1952
  1728
						match = false;
ds@1952
  1729
						break;
ds@1952
  1730
					}
ds@1952
  1731
					aliasptr++;
ds@1952
  1732
					localptr++;
ds@1952
  1733
				}
ds@1952
  1734
				if (!match)
ds@1952
  1735
				{
ds@1952
  1736
					/* If we didn't get a match, we need to advance the search stream.
ds@1952
  1737
					 * This will let us skip tokens while still searching for another match.
ds@1952
  1738
					 */
ds@1952
  1739
					localptr = ++local_orig;
ds@1952
  1740
					/* Make sure we don't go out of bounds */
ds@1952
  1741
					if (*localptr == '\0')
ds@1952
  1742
					{
ds@1952
  1743
						break;
ds@1952
  1744
					}
ds@1952
  1745
				}
ds@1952
  1746
			} while (!match);
ds@1952
  1747
ds@1952
  1748
			if (!match)
ds@1952
  1749
			{
ds@1952
  1750
				return false;
ds@1952
  1751
			} else {
ds@1952
  1752
				/* If we got a match, move on to the next token */
ds@1952
  1753
				continue;
ds@1952
  1754
			}
ds@1952
  1755
		} else if (*aliasptr == '\0') {
ds@1952
  1756
			if (*localptr == '\0'
ds@1952
  1757
				||
ds@1952
  1758
				strcmp(localptr, ".smx") == 0)
ds@1952
  1759
			{
ds@1952
  1760
				return true;
ds@1952
  1761
			} else {
ds@1952
  1762
				return false;
ds@1952
  1763
			}
ds@1952
  1764
		} else if (*aliasptr != *localptr) {
ds@1952
  1765
			return false;
ds@1952
  1766
		}
ds@1952
  1767
		aliasptr++;
ds@1952
  1768
		localptr++;
ds@1952
  1769
	}
ds@1952
  1770
ds@1952
  1771
	return true;
ds@1952
  1772
}
ds@1952
  1773
ds@1952
  1774
bool CPluginManager::IsLateLoadTime() const
ds@1952
  1775
{
ds@1952
  1776
	return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
ds@1952
  1777
}
ds@1952
  1778
ds@1952
  1779
void CPluginManager::OnSourceModAllInitialized()
ds@1952
  1780
{
ds@1952
  1781
	m_MyIdent = g_ShareSys.CreateCoreIdentity();
ds@1952
  1782
ds@1952
  1783
	HandleAccess sec;
ds@1952
  1784
	g_HandleSys.InitAccessDefaults(NULL, &sec);
ds@1952
  1785
ds@1952
  1786
	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
ds@1952
  1787
	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
ds@1952
  1788
ds@1952
  1789
	g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
ds@1952
  1790
	g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
ds@1952
  1791
ds@1952
  1792
	g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
ds@1952
  1793
ds@1952
  1794
	g_ShareSys.AddInterface(NULL, this);
ds@1952
  1795
}
ds@1952
  1796
ds@1952
  1797
void CPluginManager::OnSourceModShutdown()
ds@1952
  1798
{
ds@1952
  1799
	g_RootMenu.RemoveRootConsoleCommand("plugins", this);
ds@1952
  1800
ds@1952
  1801
	UnloadAll();
ds@1952
  1802
ds@1952
  1803
	g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
ds@1952
  1804
	g_ShareSys.DestroyIdentType(g_PluginIdent);
ds@1952
  1805
	g_ShareSys.DestroyIdentity(m_MyIdent);
ds@1952
  1806
}
ds@1952
  1807
ds@1952
  1808
void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
ds@1952
  1809
{
ds@1952
  1810
	/* We don't care about the internal object, actually */
ds@1952
  1811
}
ds@1952
  1812
ds@1952
  1813
bool CPluginManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
ds@1952
  1814
{
ds@1952
  1815
	*pSize = ((CPlugin *)object)->CalcMemUsage();
ds@1952
  1816
	return true;
ds@1952
  1817
}
ds@1952
  1818
ds@1952
  1819
IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
ds@1952
  1820
{
ds@1952
  1821
	IPlugin *pPlugin;
ds@1952
  1822
	HandleError _err;
ds@1952
  1823
ds@1952
  1824
	HandleSecurity sec;
ds@1952
  1825
ds@1952
  1826
	sec.pOwner = NULL;
ds@1952
  1827
	sec.pIdentity = m_MyIdent;
ds@1952
  1828
ds@1952
  1829
	if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
ds@1952
  1830
	{
ds@1952
  1831
		pPlugin = NULL;
ds@1952
  1832
	}
ds@1952
  1833
ds@1952
  1834
	if (err)
ds@1952
  1835
	{
ds@1952
  1836
		*err = _err;
ds@1952
  1837
	}
ds@1952
  1838
ds@1952
  1839
	return pPlugin;
ds@1952
  1840
}
ds@1952
  1841
ds@1952
  1842
CPlugin *CPluginManager::GetPluginByOrder(int num)
ds@1952
  1843
{
ds@1952
  1844
	if (num < 1 || num > (int)GetPluginCount())
ds@1952
  1845
	{
ds@1952
  1846
		return NULL;
ds@1952
  1847
	}
ds@1952
  1848
ds@1952
  1849
	CPlugin *pl;
ds@1952
  1850
	int id = 1;
ds@1952
  1851
ds@2113
  1852
	SourceHook::List<CPlugin *>::iterator iter;
ds@2113
  1853
	for (iter = m_plugins.begin(); iter != m_plugins.end() && id < num; iter++, id++) {}
ds@1952
  1854
ds@2113
  1855
	pl = *iter;
ds@1952
  1856
ds@1952
  1857
	return pl;
ds@1952
  1858
}
ds@1952
  1859
ds@1952
  1860
const char *CPluginManager::GetStatusText(PluginStatus st)
ds@1952
  1861
{
ds@1952
  1862
	switch (st)
ds@1952
  1863
	{
ds@1952
  1864
	case Plugin_Running:
ds@1952
  1865
		return "Running";
ds@1952
  1866
	case Plugin_Paused:
ds@1952
  1867
		return "Paused";
ds@1952
  1868
	case Plugin_Error:
ds@1952
  1869
		return "Error";
ds@1952
  1870
	case Plugin_Uncompiled:
ds@1952
  1871
		return "Uncompiled";
ds@1952
  1872
	case Plugin_BadLoad:
ds@1952
  1873
		return "Bad Load";
ds@1952
  1874
	case Plugin_Failed:
ds@1952
  1875
		return "Failed";
ds@1952
  1876
	default:
ds@1952
  1877
		assert(false);
ds@1952
  1878
		return "-";
ds@1952
  1879
	}
ds@1952
  1880
}
ds@1952
  1881
ds@1952
  1882
void CPluginManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
ds@1952
  1883
{
ds@1952
  1884
	int argcount = command.ArgC();
ds@1952
  1885
	if (argcount >= 3)
ds@1952
  1886
	{
ds@1952
  1887
		const char *cmd = command.Arg(2);
ds@1952
  1888
		if (strcmp(cmd, "list") == 0)
ds@1952
  1889
		{
ds@1952
  1890
			char buffer[256];
ds@1952
  1891
			unsigned int id = 1;
ds@1952
  1892
			int plnum = GetPluginCount();
ds@1952
  1893
ds@1952
  1894
			if (!plnum)
ds@1952
  1895
			{
ds@1952
  1896
				g_RootMenu.ConsolePrint("[SM] No plugins loaded");
ds@1952
  1897
				return;
ds@1952
  1898
			}
ds@1952
  1899
			else
ds@1952
  1900
			{
ds@1952
  1901
				g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
ds@1952
  1902
			}
ds@1952
  1903
dvander@2105
  1904
			CPlugin *pl;
dvander@2105
  1905
			SourceHook::List<CPlugin *>::iterator iter;
dvander@2105
  1906
			SourceHook::List<CPlugin *> m_FailList;
ds@1952
  1907
ds@2113
  1908
			for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
ds@1952
  1909
			{
dvander@2105
  1910
				pl = (*iter);
ds@1952
  1911
				assert(pl->GetStatus() != Plugin_Created);
ds@1952
  1912
				int len = 0;
ds@1952
  1913
				const sm_plugininfo_t *info = pl->GetPublicInfo();
ds@1952
  1914
				if (pl->GetStatus() != Plugin_Running)
ds@1952
  1915
				{
ds@1952
  1916
					len += UTIL_Format(buffer, sizeof(buffer), "  %02d <%s>", id, GetStatusText(pl->GetStatus()));
ds@1952
  1917
ds@1952
  1918
					if (pl->GetStatus() <= Plugin_Error)
ds@1952
  1919
					{
ds@1952
  1920
						/* Plugin has failed to load. */
ds@1952
  1921
						m_FailList.push_back(pl);
ds@1952
  1922
					}
ds@1952
  1923
				}
ds@1952
  1924
				else
ds@1952
  1925
				{
ds@1952
  1926
					len += UTIL_Format(buffer, sizeof(buffer), "  %02d", id);
ds@1952
  1927
				}
ds@1952
  1928
				len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
ds@1952
  1929
				if (IS_STR_FILLED(info->version))
ds@1952
  1930
				{
ds@1952
  1931
					len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
ds@1952
  1932
				}
ds@1952
  1933
				if (IS_STR_FILLED(info->author))
ds@1952
  1934
				{
ds@1952
  1935
					UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
ds@1952
  1936
				}
ds@1952
  1937
				g_RootMenu.ConsolePrint("%s", buffer);
ds@1952
  1938
			}
ds@1952
  1939
ds@1952
  1940
			if (!m_FailList.empty())
ds@1952
  1941
			{
ds@1952
  1942
				g_RootMenu.ConsolePrint("Load Errors:");
ds@1952
  1943
dvander@2105
  1944
				SourceHook::List<CPlugin *>::iterator _iter;
ds@1952
  1945
ds@1952
  1946
				CPlugin *pl;
ds@1952
  1947
ds@1952
  1948
				for (_iter=m_FailList.begin(); _iter!=m_FailList.end(); _iter++)
ds@1952
  1949
				{
ds@1952
  1950
					pl = (CPlugin *)*_iter;
ds@1952
  1951
					g_RootMenu.ConsolePrint("%s: %s",(IS_STR_FILLED(pl->GetPublicInfo()->name)) ? pl->GetPublicInfo()->name : pl->GetFilename(), pl->m_errormsg);
ds@1952
  1952
				}
ds@1952
  1953
			}
ds@1952
  1954
ds@1952
  1955
			return;
ds@1952
  1956
		}
ds@1952
  1957
		else if (strcmp(cmd, "load") == 0)
ds@1952
  1958
		{
ds@1952
  1959
			if (argcount < 4)
ds@1952
  1960
			{
ds@1952
  1961
				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load <file>");
ds@1952
  1962
				return;
ds@1952
  1963
			}
ds@1952
  1964
ds@1952
  1965
			char error[128];
ds@1952
  1966
			bool wasloaded;
ds@1952
  1967
			const char *filename = command.Arg(3);
ds@1952
  1968
ds@1952
  1969
			char pluginfile[256];
ds@1952
  1970
			const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx";
ds@1952
  1971
			UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext);
ds@1952
  1972
ds@1952
  1973
			IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded);
ds@1952
  1974
ds@1952
  1975
			if (wasloaded)
ds@1952
  1976
			{
ds@1952
  1977
				g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile);
ds@1952
  1978
				return;
ds@1952
  1979
			}
ds@1952
  1980
ds@1952
  1981
			if (pl)
ds@1952
  1982
			{
ds@1952
  1983
				g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile);
ds@1952
  1984
			}
ds@1952
  1985
			else
ds@1952
  1986
			{
ds@1952
  1987
				g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error);
ds@1952
  1988
			}
ds@1952
  1989
ds@1952
  1990
			return;
ds@1952
  1991
		}
ds@1952
  1992
		else if (strcmp(cmd, "unload") == 0)
ds@1952
  1993
		{
ds@1952
  1994
			if (argcount < 4)
ds@1952
  1995
			{
ds@1952
  1996
				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#|file>");
ds@1952
  1997
				return;
ds@1952
  1998
			}
ds@1952
  1999
ds@1952
  2000
			CPlugin *pl;
ds@1952
  2001
			char *end;
ds@1952
  2002
			const char *arg = command.Arg(3);
ds@1952
  2003
			int id = strtol(arg, &end, 10);
ds@1952
  2004
ds@1952
  2005
			if (*end == '\0')
ds@1952
  2006
			{
ds@1952
  2007
				pl = GetPluginByOrder(id);
ds@1952
  2008
				if (!pl)
ds@1952
  2009
				{
ds@1952
  2010
					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
ds@1952
  2011
					return;
ds@1952
  2012
				}
ds@1952
  2013
			}
ds@1952
  2014
			else
ds@1952
  2015
			{
ds@1952
  2016
				char pluginfile[256];
ds@1952
  2017
				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
ds@1952
  2018
				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
ds@1952
  2019
ds@1952
  2020
				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
ds@1952
  2021
				{
ds@1952
  2022
					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
ds@1952
  2023
					return;
ds@1952
  2024
				}
ds@1952
  2025
			}
ds@1952
  2026
ds@1952
  2027
			char name[PLATFORM_MAX_PATH];
ds@1952
  2028
			const sm_plugininfo_t *info = pl->GetPublicInfo();
ds@1952
  2029
			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
ds@1952
  2030
ds@1952
  2031
			if (UnloadPlugin(pl))
ds@1952
  2032
			{
ds@1952
  2033
				g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name);
ds@1952
  2034
			}
ds@1952
  2035
			else
ds@1952
  2036
			{
ds@1952
  2037
				g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name);
ds@1952
  2038
			}
ds@1952
  2039
ds@1952
  2040
			return;
ds@1952
  2041
		}
ds@1952
  2042
		else if (strcmp(cmd, "unload_all") == 0)
ds@1952
  2043
		{
ds@1952
  2044
			g_PluginSys.UnloadAll();
ds@1952
  2045
			g_RootMenu.ConsolePrint("[SM] All plugins have been unloaded.");
ds@1952
  2046
			return;
ds@1952
  2047
		}
ds@1952
  2048
		else if (strcmp(cmd, "load_lock") == 0)
ds@1952
  2049
		{
ds@1952
  2050
			if (m_LoadingLocked)
ds@1952
  2051
			{
ds@1952
  2052
				g_RootMenu.ConsolePrint("[SM] There is already a loading lock in effect.");
ds@1952
  2053
			}
ds@1952
  2054
			else
ds@1952
  2055
			{
ds@1952
  2056
				m_LoadingLocked = true;
ds@1952
  2057
				g_RootMenu.ConsolePrint("[SM] Loading is now locked; no plugins will be loaded or re-loaded.");
ds@1952
  2058
			}
ds@1952
  2059
			return;
ds@1952
  2060
		}
ds@1952
  2061
		else if (strcmp(cmd, "load_unlock") == 0)
ds@1952
  2062
		{
ds@1952
  2063
			if (m_LoadingLocked)
ds@1952
  2064
			{
ds@1952
  2065
				m_LoadingLocked = false;
ds@1952
  2066
				g_RootMenu.ConsolePrint("[SM] The loading lock is no longer in effect.");
ds@1952
  2067
			}
ds@1952
  2068
			else
ds@1952
  2069
			{
ds@1952
  2070
				g_RootMenu.ConsolePrint("[SM] There was no loading lock in effect.");
ds@1952
  2071
			}
ds@1952
  2072
			return;
ds@1952
  2073
		}
ds@1952
  2074
		else if (strcmp(cmd, "info") == 0)
ds@1952
  2075
		{
ds@1952
  2076
			if (argcount < 4)
ds@1952
  2077
			{
ds@1952
  2078
				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>");
ds@1952
  2079
				return;
ds@1952
  2080
			}
ds@1952
  2081
ds@1952
  2082
			CPlugin *pl;
ds@1952
  2083
			char *end;
ds@1952
  2084
			const char *arg = command.Arg(3);
ds@1952
  2085
			int id = strtol(arg, &end, 10);
ds@1952
  2086
ds@1952
  2087
			if (*end == '\0')
ds@1952
  2088
			{
ds@1952
  2089
				pl = GetPluginByOrder(id);
ds@1952
  2090
				if (!pl)
ds@1952
  2091
				{
ds@1952
  2092
					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
ds@1952
  2093
					return;
ds@1952
  2094
				}
ds@1952
  2095
			}
ds@1952
  2096
			else
ds@1952
  2097
			{
ds@1952
  2098
				char pluginfile[256];
ds@1952
  2099
				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
ds@1952
  2100
				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
ds@1952
  2101
ds@1952
  2102
				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
ds@1952
  2103
				{
ds@1952
  2104
					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
ds@1952
  2105
					return;
ds@1952
  2106
				}
ds@1952
  2107
			}
ds@1952
  2108
ds@1952
  2109
			const sm_plugininfo_t *info = pl->GetPublicInfo();
ds@1952
  2110
ds@1952
  2111
			g_RootMenu.ConsolePrint("  Filename: %s", pl->GetFilename());
ds@1952
  2112
			if (pl->GetStatus() <= Plugin_Error)
ds@1952
  2113
			{
ds@1952
  2114
				if (IS_STR_FILLED(info->name))
ds@1952
  2115
				{
ds@1952
  2116
					if (IS_STR_FILLED(info->description))
ds@1952
  2117
					{
ds@1952
  2118
						g_RootMenu.ConsolePrint("  Title: %s (%s)", info->name, info->description);
ds@1952
  2119
					} else {
ds@1952
  2120
						g_RootMenu.ConsolePrint("  Title: %s", info->name);
ds@1952
  2121
					}
ds@1952
  2122
				}
ds@1952
  2123
				if (IS_STR_FILLED(info->author))
ds@1952
  2124
				{
ds@1952
  2125
					g_RootMenu.ConsolePrint("  Author: %s", info->author);
ds@1952
  2126
				}
ds@1952
  2127
				if (IS_STR_FILLED(info->version))
ds@1952
  2128
				{
ds@1952
  2129
					g_RootMenu.ConsolePrint("  Version: %s", info->version);
ds@1952
  2130
				}
ds@1952
  2131
				if (IS_STR_FILLED(info->url))
ds@1952
  2132
				{
ds@1952
  2133
					g_RootMenu.ConsolePrint("  URL: %s", info->url);
ds@1952
  2134
				}
ds@1952
  2135
				if (pl->GetStatus() == Plugin_Error)
ds@1952
  2136
				{
ds@1952
  2137
					g_RootMenu.ConsolePrint("  Error: %s", pl->m_errormsg);
ds@1952
  2138
				}
ds@1952
  2139
				else
ds@1952
  2140
				{
dvander@2105
  2141
					if (pl->GetStatus() == Plugin_Running)
dvander@2105
  2142
					{
dvander@2226
  2143
						g_RootMenu.ConsolePrint("  Status: running");
dvander@2105
  2144
					}
dvander@2105
  2145
					else
dvander@2105
  2146
					{
dvander@2105
  2147
						g_RootMenu.ConsolePrint("  Status: not running");
dvander@2105
  2148
					}
ds@1952
  2149
ds@1952
  2150
					const char *typestr = "";
ds@1952
  2151
					switch (pl->GetType())
ds@1952
  2152
					{
ds@1952
  2153
					case PluginType_MapUpdated:
ds@1952
  2154
						typestr = "Map Change if Updated";
ds@1952
  2155
						break;
ds@1952
  2156
					case PluginType_MapOnly:
ds@1952
  2157
						typestr = "Map Change";
ds@1952
  2158
						break;
ds@1952
  2159
					case PluginType_Private:
ds@1952
  2160
					case PluginType_Global:
ds@1952
  2161
						typestr = "Never";
ds@1952
  2162
						break;
ds@1952
  2163
					}
ds@1952
  2164
ds@1952
  2165
					g_RootMenu.ConsolePrint("  Reloads: %s", typestr);
ds@1952
  2166
				}
dvander@2105
  2167
				if (pl->m_FileVersion >= 3)
dvander@2105
  2168
				{
dvander@2105
  2169
					g_RootMenu.ConsolePrint("  Timestamp: %s", pl->m_DateTime);
dvander@2105
  2170
				}
ds@1952
  2171
			}
ds@1952
  2172
			else
ds@1952
  2173
			{
ds@1952
  2174
				g_RootMenu.ConsolePrint("  Load error: %s", pl->m_errormsg);
ds@1952
  2175
				g_RootMenu.ConsolePrint("  File info: (title \"%s\") (version \"%s\")", 
ds@1952
  2176
										info->name ? info->name : "<none>",
ds@1952
  2177
										info->version ? info->version : "<none>");
ds@1952
  2178
				if (IS_STR_FILLED(info->url))
ds@1952
  2179
				{
ds@1952
  2180
					g_RootMenu.ConsolePrint("  File URL: %s", info->url);
ds@1952
  2181
				}
ds@1952
  2182
			}
ds@1952
  2183
ds@1952
  2184
			return;
ds@1952
  2185
		}
ds@1952
  2186
		else if (strcmp(cmd, "refresh") == 0)
ds@1952
  2187
		{
ds@1952
  2188
			g_SourceMod.DoGlobalPluginLoads();
ds@1952
  2189
			g_RootMenu.ConsolePrint("[SM] The plugin list has been refreshed and reloaded.");
ds@1952
  2190
			return;
ds@1952
  2191
		}
ds@1952
  2192
		else if (strcmp(cmd, "reload") == 0)
ds@1952
  2193
		{
ds@1952
  2194
			if (argcount < 4)
ds@1952
  2195
			{
ds@1952
  2196
				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins reload <#|file>");
ds@1952
  2197
				return;
ds@1952
  2198
			}
ds@1952
  2199
ds@1952
  2200
			CPlugin *pl;
ds@1952
  2201
			char *end;
ds@1952
  2202
			const char *arg = command.Arg(3);
ds@1952
  2203
			int id = strtol(arg, &end, 10);
ds@1952
  2204
ds@1952
  2205
			if (*end == '\0')
ds@1952
  2206
			{
ds@1952
  2207
				pl = GetPluginByOrder(id);
ds@1952
  2208
				if (!pl)
ds@1952
  2209
				{
ds@1952
  2210
					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
ds@1952
  2211
					return;
ds@1952
  2212
				}
ds@1952
  2213
			}
ds@1952
  2214
			else
ds@1952
  2215
			{
ds@1952
  2216
				char pluginfile[256];
ds@1952
  2217
				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
ds@1952
  2218
				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
ds@1952
  2219
ds@1952
  2220
				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
ds@1952
  2221
				{
ds@1952
  2222
					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
ds@1952
  2223
					return;
ds@1952
  2224
				}
ds@1952
  2225
			}
ds@1952
  2226
ds@1952
  2227
			char name[PLATFORM_MAX_PATH];
ds@1952
  2228
			const sm_plugininfo_t *info = pl->GetPublicInfo();
ds@1952
  2229
			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
ds@1952
  2230
ds@1952
  2231
			if (ReloadPlugin(pl))
ds@1952
  2232
			{
ds@1952
  2233
				g_RootMenu.ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
ds@1952
  2234
			}
ds@1952
  2235
			else
ds@1952
  2236
			{
ds@1952
  2237
				g_RootMenu.ConsolePrint("[SM] Failed to reload plugin %s.", name);
ds@1952
  2238
			}
ds@1952
  2239
ds@1952
  2240
			return;
ds@1952
  2241
		}
ds@1952
  2242
	}
ds@1952
  2243
ds@1952
  2244
	/* Draw the main menu */
ds@1952
  2245
	g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
ds@1952
  2246
	g_RootMenu.DrawGenericOption("info", "Information about a plugin");
ds@1952
  2247
	g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
ds@1952
  2248
	g_RootMenu.DrawGenericOption("load", "Load a plugin");
ds@1952
  2249
	g_RootMenu.DrawGenericOption("load_lock", "Prevents any more plugins from being loaded");
ds@1952
  2250
	g_RootMenu.DrawGenericOption("load_unlock", "Re-enables plugin loading");
ds@1952
  2251
	g_RootMenu.DrawGenericOption("refresh", "Reloads/refreshes all plugins in the plugins folder");
ds@1952
  2252
	g_RootMenu.DrawGenericOption("reload", "Reloads a plugin");
ds@1952
  2253
	g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
ds@1952
  2254
	g_RootMenu.DrawGenericOption("unload_all", "Unloads all plugins");
ds@1952
  2255
}
ds@1952
  2256
ds@1952
  2257
bool CPluginManager::ReloadPlugin(CPlugin *pl)
ds@1952
  2258
{
ds@1952
  2259
	List<CPlugin *>::iterator iter;
ds@1952
  2260
	char filename[PLATFORM_MAX_PATH];
dvander@2226
  2261
	bool wasloaded;
ds@1952
  2262
	PluginType ptype;
ds@1952
  2263
	IPlugin *newpl;
ds@1952
  2264
	int id = 1;
ds@1952
  2265
ds@1952
  2266
	strcpy(filename, pl->m_filename);
ds@1952
  2267
	ptype = pl->GetType();
ds@1952
  2268
ds@1952
  2269
	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++, id++)
ds@1952
  2270
	{
ds@1952
  2271
		if ((*iter) == pl)
ds@1952
  2272
		{
ds@1952
  2273
			break;
ds@1952
  2274
		}
ds@1952
  2275
	}
ds@1952
  2276
ds@1952
  2277
	if (!UnloadPlugin(pl))
ds@1952
  2278
	{
ds@1952
  2279
		return false;
ds@1952
  2280
	}
dvander@2226
  2281
	if (!(newpl=LoadPlugin(filename, true, ptype, NULL, 0, &wasloaded)))
ds@1952
  2282
	{
ds@1952
  2283
		return false;
ds@1952
  2284
	}
ds@1952
  2285
ds@1952
  2286
	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
ds@1952
  2287
	{
ds@1952
  2288
		if ((*iter) == (CPlugin *)newpl)
ds@1952
  2289
		{
ds@1952
  2290
			m_plugins.erase(iter);
ds@1952
  2291
			break;
ds@1952
  2292
		}
ds@1952
  2293
	}
ds@1952
  2294
ds@1952
  2295
	int i;
ds@1952
  2296
	for (i=1, iter=m_plugins.begin(); iter!=m_plugins.end() && i<id; iter++, i++)
ds@1952
  2297
	{
ds@1952
  2298
	}
ds@1952
  2299
	m_plugins.insert(iter, (CPlugin *)newpl);
ds@1952
  2300
ds@1952
  2301
	return true;
ds@1952
  2302
}
ds@1952
  2303
ds@1952
  2304
void CPluginManager::ReloadOrUnloadPlugins()
ds@1952
  2305
{
ds@1952
  2306
	/* If we're in a load lock, just skip this whole bit. */
ds@1952
  2307
	if (m_LoadingLocked)
ds@1952
  2308
	{
ds@1952
  2309
		return;
ds@1952
  2310
	}
ds@1952
  2311
ds@1952
  2312
	List<CPlugin *>::iterator iter;
ds@1952
  2313
	List<CPlugin *> tmp_list = m_plugins;
ds@1952
  2314
	CPlugin *pl;
ds@1952
  2315
	time_t t;
ds@1952
  2316
ds@1952
  2317
	for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++)
ds@1952
  2318
	{
ds@1952
  2319
		pl = (*iter);
ds@1952
  2320
		if (pl->GetType() ==  PluginType_MapOnly)
ds@1952
  2321
		{
ds@1952
  2322
			UnloadPlugin((IPlugin *)pl);
ds@1952
  2323
		}
ds@1952
  2324
		else if (pl->GetType() == PluginType_MapUpdated)
ds@1952
  2325
		{
ds@1952
  2326
			t = pl->GetFileTimeStamp();
ds@1952
  2327
			if (!t || t > pl->GetTimeStamp())
ds@1952
  2328
			{
ds@1952
  2329
				pl->SetTimeStamp(t);
ds@1952
  2330
				UnloadPlugin((IPlugin *)pl);
ds@1952
  2331
			}
ds@1952
  2332
		}
ds@1952
  2333
	}
ds@1952
  2334
}
ds@1952
  2335
ds@1952
  2336
void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
ds@1952
  2337
{
ds@1952
  2338
	List<IPluginsListener *>::iterator iter;
ds@1952
  2339
	IPluginsListener *pListener;
ds@1952
  2340
	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
ds@1952
  2341
	{
ds@1952
  2342
		pListener = (*iter);
ds@1952
  2343
		pListener->OnPluginPauseChange(pl, paused);
ds@1952
  2344
	}	
ds@1952
  2345
}
ds@1952
  2346
ds@1952
  2347
void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward)
ds@1952
  2348
{
ds@1952
  2349
	List<CPlugin *>::iterator iter;
ds@1952
  2350
	CPlugin *pPlugin;
ds@1952
  2351
	IPluginFunction *pFunction;
ds@1952
  2352
ds@1952
  2353
	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
ds@1952
  2354
	{
ds@1952
  2355
		pPlugin = (*iter);
ds@1952
  2356
ds@1952
  2357
		if (pPlugin->GetStatus() <= Plugin_Paused)
ds@1952
  2358
		{
ds@1952
  2359
			pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name);
ds@1952
  2360
ds@1952
  2361
			if (pFunction)
ds@1952
  2362
			{
ds@1952
  2363
				pForward->AddFunction(pFunction);
ds@1952
  2364
			}
ds@1952
  2365
		}
ds@1952
  2366
	}
ds@1952
  2367
}
ds@1952
  2368
ds@1952
  2369
CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken)
ds@1952
  2370
{
ds@1952
  2371
	if (pToken->type != g_PluginIdent)
ds@1952
  2372
	{
ds@1952
  2373
		return NULL;
ds@1952
  2374
	}
ds@1952
  2375
ds@1952
  2376
	return (CPlugin *)(pToken->ptr);
ds@1952
  2377
}
ds@1952
  2378
ds@1952
  2379
void CPluginManager::OnLibraryAction(const char *lib, bool is_a_plugin, bool drop)
ds@1952
  2380
{
ds@1952
  2381
	List<CPlugin *>::iterator iter;
ds@1952
  2382
ds@1952
  2383
	struct _pl
ds@1952
  2384
	{
ds@1952
  2385
		cell_t name;
ds@1952
  2386
		cell_t file;
ds@1952
  2387
		cell_t required;
ds@1952
  2388
	} *plc;
ds@1952
  2389
ds@1952
  2390
	struct _ext
ds@1952
  2391
	{
ds@1952
  2392
		cell_t name;
ds@1952
  2393
		cell_t file;
ds@1952
  2394
		cell_t autoload;
ds@1952
  2395
		cell_t required;
ds@1952
  2396
	} *ext;
ds@1952
  2397
ds@1952
  2398
	const char *name = drop ? "OnLibraryRemoved" : "OnLibraryAdded";
ds@1952
  2399
ds@1952
  2400
	for (iter=m_plugins.begin();
ds@1952
  2401
		 iter!=m_plugins.end();
ds@1952
  2402
		 iter++)
ds@1952
  2403
	{
ds@1952
  2404
		CPlugin *pl = (*iter);
ds@1952
  2405
		if (pl->GetStatus() != Plugin_Running)
ds@1952
  2406
		{
ds@1952
  2407
			continue;
ds@1952
  2408
		}
ds@1952
  2409
		IPluginContext *pContext = pl->GetBaseContext();
ds@1952
  2410
		IPluginFunction *pf = pContext->GetFunctionByName(name);
ds@1952
  2411
		if (!pf)
ds@1952
  2412
		{
ds@1952
  2413
			continue;
ds@1952
  2414
		}
ds@1952
  2415
		uint32_t num_vars = pContext->GetPubVarsNum();
ds@1952
  2416
		for (uint32_t i=0; i<num_vars; i++)
ds@1952
  2417
		{
ds@1952
  2418
			sp_pubvar_t *pubvar;
ds@1952
  2419
			if (pContext->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
ds@1952
  2420
			{
ds@1952
  2421
				continue;
ds@1952
  2422
			}
ds@1952
  2423
			if (is_a_plugin && strncmp(pubvar->name, "__pl_", 5) == 0)
ds@1952
  2424
			{
ds@1952
  2425
				plc = (_pl *)pubvar->offs;
ds@1952
  2426
				if (plc->required)
ds@1952
  2427
				{
ds@1952
  2428
					continue;
ds@1952
  2429
				}
ds@1952
  2430
				char *str;
ds@1952
  2431
				pContext->LocalToString(plc->name, &str);
ds@1952
  2432
				if (strcmp(str, lib) != 0)
ds@1952
  2433
				{
ds@1952
  2434
					continue;
ds@1952
  2435
				}
ds@1952
  2436
				pf->PushString(lib);
ds@1952
  2437
				pf->Execute(NULL);
ds@1952
  2438
			}
ds@1952
  2439
			else if (!is_a_plugin && strncmp(pubvar->name, "__ext_", 6) == 0)
ds@1952
  2440
			{
ds@1952
  2441
				ext = (_ext *)pubvar->offs;
ds@1952
  2442
				if (ext->required)
ds@1952
  2443
				{
ds@1952
  2444
					continue;
ds@1952
  2445
				}
ds@1952
  2446
				char *str;
ds@1952
  2447
				pContext->LocalToString(ext->name, &str);
ds@1952
  2448
				if (strcmp(str, lib) != 0)
ds@1952
  2449
				{
ds@1952
  2450
					continue;
ds@1952
  2451
				}
ds@1952
  2452
				pf->PushString(lib);
ds@1952
  2453
				pf->Execute(NULL);
ds@1952
  2454
			}
ds@1952
  2455
		}
ds@1952
  2456
	}
ds@1952
  2457
}
ds@1952
  2458
ds@1952
  2459
bool CPluginManager::LibraryExists(const char *lib)
ds@1952
  2460
{
ds@1952
  2461
	List<CPlugin *>::iterator iter;
ds@1952
  2462
ds@1952
  2463
	for (iter=m_plugins.begin();
ds@1952
  2464
		 iter!=m_plugins.end();
ds@1952
  2465
		 iter++)
ds@1952
  2466
	{
ds@1952
  2467
		CPlugin *pl = (*iter);
ds@1952
  2468
		if (pl->GetStatus() != Plugin_Running)
ds@1952
  2469
		{
ds@1952
  2470
			continue;
ds@1952
  2471
		}
ds@1952
  2472
		List<String>::iterator s_iter;
ds@1952
  2473
		for (s_iter = pl->m_Libraries.begin();
ds@1952
  2474
			 s_iter != pl->m_Libraries.end();
ds@1952
  2475
			 s_iter++)
ds@1952
  2476
		{
ds@1952
  2477
			if ((*s_iter).compare(lib) == 0)
ds@1952
  2478
			{
ds@1952
  2479
				return true;
ds@1952
  2480
			}
ds@1952
  2481
		}
ds@1952
  2482
	}
ds@1952
  2483
ds@1952
  2484
	return false;
ds@1952
  2485
}
ds@1952
  2486
ds@1952
  2487
void CPluginManager::AllPluginsLoaded()
ds@1952
  2488
{
ds@1952
  2489
	List<CPlugin *>::iterator iter;
ds@1952
  2490
	CPlugin *pl;
ds@1952
  2491
ds@1952
  2492
	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
ds@1952
  2493
	{
ds@1952
  2494
		pl = (*iter);
ds@1952
  2495
		pl->Call_OnAllPluginsLoaded();
ds@1952
  2496
	}
ds@1952
  2497
}
ds@1952
  2498
ds@1952
  2499
void CPluginManager::UnloadAll()
ds@1952
  2500
{
ds@1952
  2501
	List<CPlugin *>::iterator iter;
ds@1952
  2502
	while ( (iter = m_plugins.begin()) != m_plugins.end() )
ds@1952
  2503
	{
ds@1952
  2504
		UnloadPlugin((*iter));
ds@1952
  2505
	}
ds@1952
  2506
}
ds@1952
  2507
ds@1952
  2508
int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
ds@1952
  2509
{
ds@1952
  2510
	int id = 1;
ds@1952
  2511
	List<CPlugin *>::iterator iter;
ds@1952
  2512
ds@1952
  2513
	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
ds@1952
  2514
	{
ds@1952
  2515
		if ((*iter) == pl)
ds@1952
  2516
		{
ds@1952
  2517
			return id;
ds@1952
  2518
		}
ds@1952
  2519
	}
ds@1952
  2520
ds@1952
  2521
	return -1;
ds@1952
  2522
}
ds@1952
  2523
ds@1952
  2524
CPlugin *CPluginManager::FindPluginByConsoleArg(const char *arg)
ds@1952
  2525
{
ds@1952
  2526
	int id;
ds@1952
  2527
	char *end;
ds@1952
  2528
	CPlugin *pl;
ds@1952
  2529
	
ds@1952
  2530
	id = strtol(arg, &end, 10);
ds@1952
  2531
ds@1952
  2532
	if (*end == '\0')
ds@1952
  2533
	{
ds@1952
  2534
		pl = GetPluginByOrder(id);
ds@1952
  2535
		if (!pl)
ds@1952
  2536
		{
ds@1952
  2537
			return NULL;
ds@1952
  2538
		}
ds@1952
  2539
	}
ds@1952
  2540
	else
ds@1952
  2541
	{
ds@1952
  2542
		char pluginfile[256];
ds@1952
  2543
		const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
ds@1952
  2544
		UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
ds@1952
  2545
ds@1952
  2546
		if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
ds@1952
  2547
		{
ds@1952
  2548
			return NULL;
ds@1952
  2549
		}
ds@1952
  2550
	}
ds@1952
  2551
ds@1952
  2552
	return pl;
ds@1952
  2553
}