core/systems/PluginSys.cpp
branchsourcemod-1.1.0
changeset 2283 03a67e41afbc
parent 1951 c7b4237fff50
child 2287 017a725c9d17
     1.1 --- a/core/systems/PluginSys.cpp	Fri Mar 28 06:21:34 2008 +0000
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,2722 +0,0 @@
     1.4 -/**
     1.5 - * vim: set ts=4 :
     1.6 - * =============================================================================
     1.7 - * SourceMod
     1.8 - * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     1.9 - * =============================================================================
    1.10 - *
    1.11 - * This program is free software; you can redistribute it and/or modify it under
    1.12 - * the terms of the GNU General Public License, version 3.0, as published by the
    1.13 - * Free Software Foundation.
    1.14 - * 
    1.15 - * This program is distributed in the hope that it will be useful, but WITHOUT
    1.16 - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    1.17 - * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    1.18 - * details.
    1.19 - *
    1.20 - * You should have received a copy of the GNU General Public License along with
    1.21 - * this program.  If not, see <http://www.gnu.org/licenses/>.
    1.22 - *
    1.23 - * As a special exception, AlliedModders LLC gives you permission to link the
    1.24 - * code of this program (as well as its derivative works) to "Half-Life 2," the
    1.25 - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    1.26 - * by the Valve Corporation.  You must obey the GNU General Public License in
    1.27 - * all respects for all other code used.  Additionally, AlliedModders LLC grants
    1.28 - * this exception to all derivative works.  AlliedModders LLC defines further
    1.29 - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    1.30 - * or <http://www.sourcemod.net/license.php>.
    1.31 - *
    1.32 - * Version: $Id$
    1.33 - */
    1.34 -
    1.35 -#include <stdio.h>
    1.36 -#include "PluginSys.h"
    1.37 -#include "ShareSys.h"
    1.38 -#include "LibrarySys.h"
    1.39 -#include "HandleSys.h"
    1.40 -#include "ForwardSys.h"
    1.41 -#include "sourcemm_api.h"
    1.42 -#include "sourcemod.h"
    1.43 -#include "TextParsers.h"
    1.44 -#include "Logger.h"
    1.45 -#include "ExtensionSys.h"
    1.46 -#include "sm_srvcmds.h"
    1.47 -#include "sm_stringutil.h"
    1.48 -#include "ConCmdManager.h"
    1.49 -#include "PlayerManager.h"
    1.50 -#include "CoreConfig.h"
    1.51 -#include "Translator.h"
    1.52 -
    1.53 -CPluginManager g_PluginSys;
    1.54 -HandleType_t g_PluginType = 0;
    1.55 -IdentityType_t g_PluginIdent = 0;
    1.56 -
    1.57 -CPlugin::CPlugin(const char *file)
    1.58 -{
    1.59 -	static int MySerial = 0;
    1.60 -
    1.61 -	m_type = PluginType_Private;
    1.62 -	m_status = Plugin_Uncompiled;
    1.63 -	m_serial = ++MySerial;
    1.64 -	m_plugin = NULL;
    1.65 -	m_errormsg[256] = '\0';
    1.66 -	snprintf(m_filename, sizeof(m_filename), "%s", file);
    1.67 -	m_handle = 0;
    1.68 -	m_ident = NULL;
    1.69 -	m_pProps = sm_trie_create();
    1.70 -	m_FakeNativesMissing = false;
    1.71 -	m_LibraryMissing = false;
    1.72 -	m_bGotAllLoaded = false;
    1.73 -}
    1.74 -
    1.75 -CPlugin::~CPlugin()
    1.76 -{
    1.77 -	if (m_handle)
    1.78 -	{
    1.79 -		HandleSecurity sec;
    1.80 -		sec.pOwner = g_PluginSys.GetIdentity();
    1.81 -		sec.pIdentity = sec.pOwner;
    1.82 -
    1.83 -		g_HandleSys.FreeHandle(m_handle, &sec);
    1.84 -		g_ShareSys.DestroyIdentity(m_ident);
    1.85 -	}
    1.86 -
    1.87 -	if (m_ctx.base)
    1.88 -	{
    1.89 -		delete m_ctx.base;
    1.90 -		m_ctx.base = NULL;
    1.91 -	}
    1.92 -	if (m_ctx.ctx)
    1.93 -	{
    1.94 -		m_ctx.vm->FreeContext(m_ctx.ctx);
    1.95 -		m_ctx.ctx = NULL;
    1.96 -	}
    1.97 -	if (m_ctx.co)
    1.98 -	{
    1.99 -		m_ctx.vm->AbortCompilation(m_ctx.co);
   1.100 -		m_ctx.co = NULL;
   1.101 -	}
   1.102 -
   1.103 -	if (m_plugin)
   1.104 -	{
   1.105 -		g_pSourcePawn->FreeFromMemory(m_plugin);
   1.106 -		m_plugin = NULL;
   1.107 -	}
   1.108 -	if (m_pProps)
   1.109 -	{
   1.110 -		sm_trie_destroy(m_pProps);
   1.111 -	}
   1.112 -	for (size_t i=0; i<m_configs.size(); i++)
   1.113 -	{
   1.114 -		delete m_configs[i];
   1.115 -	}
   1.116 -	m_configs.clear();
   1.117 -}
   1.118 -
   1.119 -void CPlugin::InitIdentity()
   1.120 -{
   1.121 -	if (!m_handle)
   1.122 -	{
   1.123 -		m_ident = g_ShareSys.CreateIdentity(g_PluginIdent, this);
   1.124 -		m_handle = g_HandleSys.CreateHandle(g_PluginType, this, g_PluginSys.GetIdentity(), g_PluginSys.GetIdentity(), NULL);
   1.125 -		m_ctx.base->SetIdentity(m_ident);
   1.126 -	}
   1.127 -}
   1.128 -
   1.129 -Handle_t CPlugin::GetMyHandle()
   1.130 -{
   1.131 -	return m_handle;
   1.132 -}
   1.133 -
   1.134 -CPlugin *CPlugin::CreatePlugin(const char *file, char *error, size_t maxlength)
   1.135 -{
   1.136 -	char fullpath[PLATFORM_MAX_PATH];
   1.137 -	g_SourceMod.BuildPath(Path_SM, fullpath, sizeof(fullpath), "plugins/%s", file);
   1.138 -	FILE *fp = fopen(fullpath, "rb");
   1.139 -
   1.140 -	CPlugin *pPlugin = new CPlugin(file);
   1.141 -
   1.142 -	if (!fp)
   1.143 -	{
   1.144 -		if (error)
   1.145 -		{
   1.146 -			snprintf(error, maxlength, "Unable to open file");
   1.147 -		}
   1.148 -		pPlugin->m_status = Plugin_BadLoad;
   1.149 -		return pPlugin;
   1.150 -	}
   1.151 -
   1.152 -	int err;
   1.153 -	sp_plugin_t *pl = g_pSourcePawn->LoadFromFilePointer(fp, &err);
   1.154 -	if (pl == NULL)
   1.155 -	{
   1.156 -		fclose(fp);
   1.157 -		if (error)
   1.158 -		{
   1.159 -			snprintf(error, maxlength, "Error %d while parsing plugin", err);
   1.160 -		}
   1.161 -		pPlugin->m_status = Plugin_BadLoad;
   1.162 -		return pPlugin;
   1.163 -	}
   1.164 -
   1.165 -	fclose(fp);
   1.166 -
   1.167 -	pPlugin->m_plugin = pl;
   1.168 -
   1.169 -	return pPlugin;
   1.170 -}
   1.171 -
   1.172 -bool CPlugin::GetProperty(const char *prop, void **ptr, bool remove/* =false */)
   1.173 -{
   1.174 -	bool exists = sm_trie_retrieve(m_pProps, prop, ptr);
   1.175 -
   1.176 -	if (exists && remove)
   1.177 -	{
   1.178 -		sm_trie_delete(m_pProps, prop);
   1.179 -	}
   1.180 -
   1.181 -	return exists;
   1.182 -}
   1.183 -
   1.184 -bool CPlugin::SetProperty(const char *prop, void *ptr)
   1.185 -{
   1.186 -	return sm_trie_insert(m_pProps, prop, ptr);
   1.187 -}
   1.188 -
   1.189 -ICompilation *CPlugin::StartMyCompile(IVirtualMachine *vm)
   1.190 -{
   1.191 -	if (!m_plugin)
   1.192 -	{
   1.193 -		return NULL;
   1.194 -	}
   1.195 -
   1.196 -	/* :NOTICE: We will eventually need to change these natives
   1.197 -	 * for swapping in new contexts
   1.198 -	 */
   1.199 -	if (m_ctx.co || m_ctx.ctx)
   1.200 -	{
   1.201 -		return NULL;
   1.202 -	}
   1.203 -
   1.204 -	m_status = Plugin_Uncompiled;
   1.205 -
   1.206 -	m_ctx.vm = vm;
   1.207 -	m_ctx.co = vm->StartCompilation(m_plugin);
   1.208 -
   1.209 -	return m_ctx.co;
   1.210 -}
   1.211 -
   1.212 -void CPlugin::CancelMyCompile()
   1.213 -{
   1.214 -	if (!m_ctx.co)
   1.215 -	{
   1.216 -		return;
   1.217 -	}
   1.218 -
   1.219 -	m_ctx.vm->AbortCompilation(m_ctx.co);
   1.220 -	m_ctx.co = NULL;
   1.221 -	m_ctx.vm = NULL;
   1.222 -}
   1.223 -
   1.224 -bool CPlugin::FinishMyCompile(char *error, size_t maxlength)
   1.225 -{
   1.226 -	if (!m_ctx.co)
   1.227 -	{
   1.228 -		return false;
   1.229 -	}
   1.230 -
   1.231 -	int err;
   1.232 -	m_ctx.ctx = m_ctx.vm->CompileToContext(m_ctx.co, &err);
   1.233 -	if (!m_ctx.ctx)
   1.234 -	{
   1.235 -		memset(&m_ctx, 0, sizeof(m_ctx));
   1.236 -		if (error)
   1.237 -		{
   1.238 -			snprintf(error, maxlength, "JIT failed to compile (error %d)", err);
   1.239 -		}
   1.240 -		return false;
   1.241 -	}
   1.242 -
   1.243 -	m_ctx.base = new BaseContext(m_ctx.ctx);
   1.244 -	m_ctx.ctx->user[SM_CONTEXTVAR_MYSELF] = (void *)this;
   1.245 -
   1.246 -	m_status = Plugin_Created;
   1.247 -	m_ctx.co = NULL;
   1.248 -
   1.249 -	UpdateInfo();
   1.250 -
   1.251 -	return true;
   1.252 -}
   1.253 -
   1.254 -void CPlugin::SetErrorState(PluginStatus status, const char *error_fmt, ...)
   1.255 -{
   1.256 -	PluginStatus old_status = m_status;
   1.257 -	m_status = status;
   1.258 -
   1.259 -	if (old_status == Plugin_Running)
   1.260 -	{
   1.261 -		/* Tell everyone we're now paused */
   1.262 -		g_PluginSys._SetPauseState(this, true);
   1.263 -	}
   1.264 -
   1.265 -	va_list ap;
   1.266 -	va_start(ap, error_fmt);
   1.267 -	vsnprintf(m_errormsg, sizeof(m_errormsg), error_fmt, ap);
   1.268 -	va_end(ap);
   1.269 -
   1.270 -	if (m_ctx.ctx)
   1.271 -	{
   1.272 -		m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED;
   1.273 -	}
   1.274 -}
   1.275 -
   1.276 -void CPlugin::UpdateInfo()
   1.277 -{
   1.278 -	/* Now grab the info */
   1.279 -	uint32_t idx;
   1.280 -	IPluginContext *base = GetBaseContext();
   1.281 -	int err = base->FindPubvarByName("myinfo", &idx);
   1.282 -
   1.283 -	memset(&m_info, 0, sizeof(m_info));
   1.284 -
   1.285 -	if (err == SP_ERROR_NONE)
   1.286 -	{
   1.287 -		struct sm_plugininfo_c_t
   1.288 -		{
   1.289 -			cell_t name;
   1.290 -			cell_t description;
   1.291 -			cell_t author;
   1.292 -			cell_t version;
   1.293 -			cell_t url;
   1.294 -		};
   1.295 -		sm_plugininfo_c_t *cinfo;
   1.296 -		cell_t local_addr;
   1.297 -
   1.298 -		base->GetPubvarAddrs(idx, &local_addr, (cell_t **)&cinfo);
   1.299 -		base->LocalToString(cinfo->name, (char **)&m_info.name);
   1.300 -		base->LocalToString(cinfo->description, (char **)&m_info.description);
   1.301 -		base->LocalToString(cinfo->author, (char **)&m_info.author);
   1.302 -		base->LocalToString(cinfo->url, (char **)&m_info.url);
   1.303 -		base->LocalToString(cinfo->version, (char **)&m_info.version);
   1.304 -	}
   1.305 -
   1.306 -	m_info.author = m_info.author ? m_info.author : "";
   1.307 -	m_info.description = m_info.description ? m_info.description : "";
   1.308 -	m_info.name = m_info.name ? m_info.name : "";
   1.309 -	m_info.url = m_info.url ? m_info.url : "";
   1.310 -	m_info.version = m_info.version ? m_info.version : "";
   1.311 -}
   1.312 -
   1.313 -void CPlugin::Call_OnPluginStart()
   1.314 -{
   1.315 -	if (m_status != Plugin_Loaded)
   1.316 -	{
   1.317 -		return;
   1.318 -	}
   1.319 -
   1.320 -	m_status = Plugin_Running;
   1.321 -
   1.322 -	cell_t result;
   1.323 -	IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginStart");
   1.324 -	if (!pFunction)
   1.325 -	{
   1.326 -		return;
   1.327 -	}
   1.328 -
   1.329 -	int err;
   1.330 -	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
   1.331 -	{
   1.332 -		SetErrorState(Plugin_Error, "Error detected in plugin startup (see error logs)");
   1.333 -	}
   1.334 -}
   1.335 -
   1.336 -void CPlugin::Call_OnPluginEnd()
   1.337 -{
   1.338 -	if (m_status > Plugin_Paused)
   1.339 -	{
   1.340 -		return;
   1.341 -	}
   1.342 -
   1.343 -	cell_t result;
   1.344 -	IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginEnd");
   1.345 -	if (!pFunction)
   1.346 -	{
   1.347 -		return;
   1.348 -	}
   1.349 -
   1.350 -	pFunction->Execute(&result);
   1.351 -}
   1.352 -
   1.353 -void CPlugin::Call_OnAllPluginsLoaded()
   1.354 -{
   1.355 -	if (m_status > Plugin_Paused)
   1.356 -	{
   1.357 -		return;
   1.358 -	}
   1.359 -
   1.360 -	if (m_bGotAllLoaded)
   1.361 -	{
   1.362 -		return;
   1.363 -	}
   1.364 -
   1.365 -	m_bGotAllLoaded = true;
   1.366 -
   1.367 -	cell_t result;
   1.368 -	IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnAllPluginsLoaded");
   1.369 -	if (pFunction != NULL)
   1.370 -	{
   1.371 -		pFunction->Execute(&result);
   1.372 -	}
   1.373 -
   1.374 -	if (g_OnMapStarted)
   1.375 -	{
   1.376 -		if ((pFunction = m_ctx.base->GetFunctionByName("OnMapStart")) != NULL)
   1.377 -		{
   1.378 -			pFunction->Execute(NULL);
   1.379 -		}
   1.380 -	}
   1.381 -
   1.382 -	if (SM_AreConfigsExecuted())
   1.383 -	{
   1.384 -		SM_ExecuteForPlugin(GetBaseContext());
   1.385 -	}
   1.386 -}
   1.387 -
   1.388 -bool CPlugin::Call_AskPluginLoad(char *error, size_t maxlength)
   1.389 -{
   1.390 -	if (m_status != Plugin_Created)
   1.391 -	{
   1.392 -		return false;
   1.393 -	}
   1.394 -
   1.395 -	m_status = Plugin_Loaded;
   1.396 -
   1.397 -	int err;
   1.398 -	cell_t result;
   1.399 -	IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("AskPluginLoad");
   1.400 -
   1.401 -	if (!pFunction)
   1.402 -	{
   1.403 -		return true;
   1.404 -	}
   1.405 -
   1.406 -	pFunction->PushCell(m_handle);
   1.407 -	pFunction->PushCell(g_PluginSys.IsLateLoadTime() ? 1 : 0);
   1.408 -	pFunction->PushStringEx(error, maxlength, 0, SM_PARAM_COPYBACK);
   1.409 -	pFunction->PushCell(maxlength);
   1.410 -	if ((err=pFunction->Execute(&result)) != SP_ERROR_NONE)
   1.411 -	{
   1.412 -		return false;
   1.413 -	}
   1.414 -
   1.415 -	if (!result || m_status != Plugin_Loaded)
   1.416 -	{
   1.417 -		return false;
   1.418 -	}
   1.419 -
   1.420 -	return true;
   1.421 -}
   1.422 -
   1.423 -const sp_plugin_t *CPlugin::GetPluginStructure()
   1.424 -{
   1.425 -	return m_plugin;
   1.426 -}
   1.427 -
   1.428 -IPluginContext *CPlugin::GetBaseContext()
   1.429 -{
   1.430 -	return m_ctx.base;
   1.431 -}
   1.432 -
   1.433 -sp_context_t *CPlugin::GetContext()
   1.434 -{
   1.435 -	return m_ctx.ctx;
   1.436 -}
   1.437 -
   1.438 -const char *CPlugin::GetFilename()
   1.439 -{
   1.440 -	return m_filename;
   1.441 -}
   1.442 -
   1.443 -PluginType CPlugin::GetType()
   1.444 -{
   1.445 -	return m_type;
   1.446 -}
   1.447 -
   1.448 -const sm_plugininfo_t *CPlugin::GetPublicInfo()
   1.449 -{
   1.450 -	return &m_info;
   1.451 -}
   1.452 -
   1.453 -unsigned int CPlugin::GetSerial()
   1.454 -{
   1.455 -	return m_serial;
   1.456 -}
   1.457 -
   1.458 -PluginStatus CPlugin::GetStatus()
   1.459 -{
   1.460 -	return m_status;
   1.461 -}
   1.462 -
   1.463 -bool CPlugin::IsDebugging()
   1.464 -{
   1.465 -	if (!m_ctx.ctx)
   1.466 -	{
   1.467 -		return false;
   1.468 -	}
   1.469 -
   1.470 -	return ((m_ctx.ctx->flags & SP_FLAG_DEBUG) == SP_FLAG_DEBUG);
   1.471 -}
   1.472 -
   1.473 -void CPlugin::LibraryActions(bool dropping)
   1.474 -{
   1.475 -	List<String>::iterator iter;
   1.476 -	for (iter = m_Libraries.begin();
   1.477 -		iter != m_Libraries.end();
   1.478 -		iter++)
   1.479 -	{
   1.480 -		g_PluginSys.OnLibraryAction((*iter).c_str(), true, dropping);
   1.481 -	}
   1.482 -}
   1.483 -
   1.484 -bool CPlugin::SetPauseState(bool paused)
   1.485 -{
   1.486 -	if (paused && GetStatus() != Plugin_Running)
   1.487 -	{
   1.488 -		return false;
   1.489 -	} else if (!paused && GetStatus() != Plugin_Paused) {
   1.490 -		return false;
   1.491 -	}
   1.492 -
   1.493 -	if (paused)
   1.494 -	{
   1.495 -		LibraryActions(true);
   1.496 -	}
   1.497 -
   1.498 -	IPluginFunction *pFunction = m_ctx.base->GetFunctionByName("OnPluginPauseChange");
   1.499 -	if (pFunction)
   1.500 -	{
   1.501 -		cell_t result;
   1.502 -		pFunction->PushCell(paused ? 1 : 0);
   1.503 -		pFunction->Execute(&result);
   1.504 -	}
   1.505 -
   1.506 -	if (paused)
   1.507 -	{
   1.508 -		m_status = Plugin_Paused;
   1.509 -		m_ctx.ctx->flags |= SPFLAG_PLUGIN_PAUSED;
   1.510 -	} else {
   1.511 -		m_status = Plugin_Running;
   1.512 -		m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED;
   1.513 -	}
   1.514 -
   1.515 -	g_PluginSys._SetPauseState(this, paused);
   1.516 -
   1.517 -	if (!paused)
   1.518 -	{
   1.519 -		LibraryActions(false);
   1.520 -	}
   1.521 -
   1.522 -	return true;
   1.523 -}
   1.524 -
   1.525 -IdentityToken_t *CPlugin::GetIdentity()
   1.526 -{
   1.527 -	return m_ident;
   1.528 -}
   1.529 -
   1.530 -bool CPlugin::ToggleDebugMode(bool debug, char *error, size_t maxlength)
   1.531 -{
   1.532 -	int err;
   1.533 -
   1.534 -	if (!IsRunnable())
   1.535 -	{
   1.536 -		if (error)
   1.537 -		{
   1.538 -			snprintf(error, maxlength, "Plugin is not runnable.");
   1.539 -		}
   1.540 -		return false;
   1.541 -	}
   1.542 -
   1.543 -	if (debug && IsDebugging())
   1.544 -	{
   1.545 -		if (error)
   1.546 -		{
   1.547 -			snprintf(error, maxlength, "Plugin is already in debug mode.");
   1.548 -		}
   1.549 -		return false;
   1.550 -	}
   1.551 -	else if (!debug && !IsDebugging())
   1.552 -	{
   1.553 -		if (error)
   1.554 -		{
   1.555 -			snprintf(error, maxlength, "Plugins is already in production mode.");
   1.556 -		}
   1.557 -		return false;
   1.558 -	}
   1.559 -
   1.560 -	ICompilation *co = g_pVM->StartCompilation(m_ctx.ctx->plugin);
   1.561 -	if (!g_pVM->SetCompilationOption(co, "debug", (debug) ? "1" : "0"))
   1.562 -	{
   1.563 -		if (error)
   1.564 -		{
   1.565 -			snprintf(error, maxlength, "Failed to change plugin mode (JIT failure).");
   1.566 -		}
   1.567 -		return false;
   1.568 -	}
   1.569 -
   1.570 -	sp_context_t *new_ctx = g_pVM->CompileToContext(co, &err);
   1.571 -
   1.572 -	if (new_ctx)
   1.573 -	{
   1.574 -		memcpy(new_ctx->memory, m_ctx.ctx->memory, m_ctx.ctx->mem_size);
   1.575 -		new_ctx->hp = m_ctx.ctx->hp;
   1.576 -		new_ctx->sp = m_ctx.ctx->sp;
   1.577 -		new_ctx->frm = m_ctx.ctx->frm;
   1.578 -		new_ctx->dbreak = m_ctx.ctx->dbreak;
   1.579 -		new_ctx->context = m_ctx.ctx->context;
   1.580 -		memcpy(new_ctx->user, m_ctx.ctx->user, sizeof(m_ctx.ctx->user));
   1.581 -
   1.582 -		uint32_t nativeCount = m_plugin->info.natives_num;
   1.583 -		for (uint32_t i=0; i<nativeCount; i++)
   1.584 -		{
   1.585 -			new_ctx->natives[i].pfn = m_ctx.ctx->natives[i].pfn;
   1.586 -			new_ctx->natives[i].status = m_ctx.ctx->natives[i].status;
   1.587 -		}
   1.588 -
   1.589 -		g_pVM->FreeContext(m_ctx.ctx);
   1.590 -		m_ctx.ctx = new_ctx;
   1.591 -		m_ctx.base->SetContext(new_ctx);
   1.592 -
   1.593 -		UpdateInfo();
   1.594 -	}
   1.595 -	else
   1.596 -	{
   1.597 -		if (error)
   1.598 -		{
   1.599 -			snprintf(error, maxlength, "Failed to recompile plugin (JIT error %d).", err);
   1.600 -		}
   1.601 -		return false;
   1.602 -	}
   1.603 -
   1.604 -	return true;
   1.605 -}
   1.606 -
   1.607 -bool CPlugin::IsRunnable()
   1.608 -{
   1.609 -	return (m_status <= Plugin_Paused) ? true : false;
   1.610 -}
   1.611 -
   1.612 -time_t CPlugin::GetFileTimeStamp()
   1.613 -{
   1.614 -	char path[PLATFORM_MAX_PATH];
   1.615 -	g_SourceMod.BuildPath(Path_SM, path, sizeof(path), "plugins/%s", m_filename);
   1.616 -#ifdef PLATFORM_WINDOWS
   1.617 -	struct _stat s;
   1.618 -	if (_stat(path, &s) != 0)
   1.619 -#elif defined PLATFORM_POSIX
   1.620 -	struct stat s;
   1.621 -	if (stat(path, &s) != 0)
   1.622 -#endif
   1.623 -	{
   1.624 -		return 0;
   1.625 -	}
   1.626 -	else
   1.627 -	{
   1.628 -		return s.st_mtime;
   1.629 -	}
   1.630 -}
   1.631 -
   1.632 -time_t CPlugin::GetTimeStamp()
   1.633 -{
   1.634 -	return m_LastAccess;
   1.635 -}
   1.636 -
   1.637 -void CPlugin::SetTimeStamp(time_t t)
   1.638 -{
   1.639 -	m_LastAccess = t;
   1.640 -}
   1.641 -
   1.642 -void CPlugin::AddLangFile(unsigned int index)
   1.643 -{
   1.644 -	m_PhraseFiles.push_back(index);
   1.645 -}
   1.646 -
   1.647 -size_t CPlugin::GetLangFileCount()
   1.648 -{
   1.649 -	return m_PhraseFiles.size();
   1.650 -}
   1.651 -
   1.652 -unsigned int CPlugin::GetLangFileByIndex(unsigned int index)
   1.653 -{
   1.654 -	return m_PhraseFiles.at(index);
   1.655 -}
   1.656 -
   1.657 -void CPlugin::DependencyDropped(CPlugin *pOwner)
   1.658 -{
   1.659 -	if (!m_ctx.ctx)
   1.660 -	{
   1.661 -		return;
   1.662 -	}
   1.663 -
   1.664 -	List<String>::iterator reqlib_iter;
   1.665 -	List<String>::iterator lib_iter;
   1.666 -	for (lib_iter=pOwner->m_Libraries.begin(); lib_iter!=pOwner->m_Libraries.end(); lib_iter++)
   1.667 -	{
   1.668 -		for (reqlib_iter=m_RequiredLibs.begin(); reqlib_iter!=m_RequiredLibs.end(); reqlib_iter++)
   1.669 -		{
   1.670 -			if ((*reqlib_iter) == (*lib_iter))
   1.671 -			{
   1.672 -				m_LibraryMissing = true;
   1.673 -			}
   1.674 -		}	
   1.675 -	}
   1.676 -
   1.677 -	List<FakeNative *>::iterator iter;
   1.678 -	FakeNative *pNative;
   1.679 -	sp_native_t *native;
   1.680 -	uint32_t idx;
   1.681 -	unsigned int unbound = 0;
   1.682 -
   1.683 -	for (iter = pOwner->m_fakeNatives.begin();
   1.684 -		 iter != pOwner->m_fakeNatives.end();
   1.685 -		 iter++)
   1.686 -	{
   1.687 -		pNative = (*iter);
   1.688 -		/* Find this native! */
   1.689 -		if (m_ctx.base->FindNativeByName(pNative->name.c_str(), &idx) != SP_ERROR_NONE)
   1.690 -		{
   1.691 -			continue;
   1.692 -		}
   1.693 -		/* Unbind it */
   1.694 -		m_ctx.base->GetNativeByIndex(idx, &native);
   1.695 -		native->pfn = NULL;
   1.696 -		native->status = SP_NATIVE_UNBOUND;
   1.697 -		unbound++;
   1.698 -	}
   1.699 -
   1.700 -	if (unbound)
   1.701 -	{
   1.702 -		m_FakeNativesMissing = true;
   1.703 -	}
   1.704 -
   1.705 -	/* :IDEA: in the future, add native trapping? */
   1.706 -	if (m_FakeNativesMissing || m_LibraryMissing)
   1.707 -	{
   1.708 -		SetErrorState(Plugin_Error, "Depends on plugin: %s", pOwner->GetFilename());
   1.709 -	}
   1.710 -
   1.711 -	m_dependsOn.remove(pOwner);
   1.712 -}
   1.713 -
   1.714 -unsigned int CPlugin::GetConfigCount()
   1.715 -{
   1.716 -	return (unsigned int)m_configs.size();
   1.717 -}
   1.718 -
   1.719 -AutoConfig *CPlugin::GetConfig(unsigned int i)
   1.720 -{
   1.721 -	if (i >= GetConfigCount())
   1.722 -	{
   1.723 -		return NULL;
   1.724 -	}
   1.725 -
   1.726 -	return m_configs[i];
   1.727 -}
   1.728 -
   1.729 -void CPlugin::AddConfig(bool autoCreate, const char *cfg, const char *folder)
   1.730 -{
   1.731 -	AutoConfig *c = new AutoConfig;
   1.732 -
   1.733 -	c->autocfg = cfg;
   1.734 -	c->folder = folder;
   1.735 -	c->create = autoCreate;
   1.736 -
   1.737 -	m_configs.push_back(c);
   1.738 -}
   1.739 -
   1.740 -/*******************
   1.741 - * PLUGIN ITERATOR *
   1.742 - *******************/
   1.743 -
   1.744 -CPluginManager::CPluginIterator::CPluginIterator(List<CPlugin *> *_mylist)
   1.745 -{
   1.746 -	mylist = _mylist;
   1.747 -	Reset();
   1.748 -}
   1.749 -
   1.750 -IPlugin *CPluginManager::CPluginIterator::GetPlugin()
   1.751 -{
   1.752 -	return (*current);
   1.753 -}
   1.754 -
   1.755 -bool CPluginManager::CPluginIterator::MorePlugins()
   1.756 -{
   1.757 -	return (current != mylist->end());
   1.758 -}
   1.759 -
   1.760 -void CPluginManager::CPluginIterator::NextPlugin()
   1.761 -{
   1.762 -	current++;
   1.763 -}
   1.764 -
   1.765 -void CPluginManager::CPluginIterator::Release()
   1.766 -{
   1.767 -	g_PluginSys.ReleaseIterator(this);
   1.768 -}
   1.769 -
   1.770 -CPluginManager::CPluginIterator::~CPluginIterator()
   1.771 -{
   1.772 -}
   1.773 -
   1.774 -void CPluginManager::CPluginIterator::Reset()
   1.775 -{
   1.776 -	current = mylist->begin();
   1.777 -}
   1.778 -
   1.779 -/******************
   1.780 - * PLUGIN MANAGER *
   1.781 - ******************/
   1.782 -
   1.783 -CPluginManager::CPluginManager()
   1.784 -{
   1.785 -	m_LoadLookup = sm_trie_create();
   1.786 -	m_AllPluginsLoaded = false;
   1.787 -	m_MyIdent = NULL;
   1.788 -	m_pNativeLookup = sm_trie_create();
   1.789 -	m_pCoreNatives = sm_trie_create();
   1.790 -	m_LoadingLocked = false;
   1.791 -}
   1.792 -
   1.793 -CPluginManager::~CPluginManager()
   1.794 -{
   1.795 -	/* :NOTICE: 
   1.796 -	 * Ignore the fact that there might be plugins in the cache.
   1.797 -	 * This usually means that Core is not being unloaded properly, and everything
   1.798 -	 * will crash anyway.  YAY
   1.799 -	 */
   1.800 -	sm_trie_destroy(m_LoadLookup);
   1.801 -	sm_trie_destroy(m_pNativeLookup);
   1.802 -	sm_trie_destroy(m_pCoreNatives);
   1.803 -
   1.804 -	CStack<CPluginManager::CPluginIterator *>::iterator iter;
   1.805 -	for (iter=m_iters.begin(); iter!=m_iters.end(); iter++)
   1.806 -	{
   1.807 -		delete (*iter);
   1.808 -	}
   1.809 -	m_iters.popall();
   1.810 -}
   1.811 -
   1.812 -void CPluginManager::Shutdown()
   1.813 -{
   1.814 -	List<CPlugin *>::iterator iter;
   1.815 -
   1.816 -	while ((iter = m_plugins.begin()) != m_plugins.end())
   1.817 -	{
   1.818 -		UnloadPlugin(*iter);
   1.819 -	}
   1.820 -}
   1.821 -
   1.822 -void CPluginManager::LoadAll_FirstPass(const char *config, const char *basedir)
   1.823 -{
   1.824 -	/* First read in the database of plugin settings */
   1.825 -	SMCError err;
   1.826 -	SMCStates states;
   1.827 -	m_AllPluginsLoaded = false;
   1.828 -	if ((err=textparsers->ParseFile_SMC(config, &m_PluginInfo, &states)) != SMCError_Okay)
   1.829 -	{
   1.830 -		g_Logger.LogError("[SM] Encountered fatal error parsing file \"%s\"", config);
   1.831 -		const char *err_msg = textparsers->GetSMCErrorString(err);
   1.832 -		if (err_msg)
   1.833 -		{
   1.834 -			g_Logger.LogError("[SM] Parse error encountered: \"%s\"", err_msg);
   1.835 -		}
   1.836 -	}
   1.837 -
   1.838 -	LoadPluginsFromDir(basedir, NULL);
   1.839 -}
   1.840 -
   1.841 -void CPluginManager::LoadPluginsFromDir(const char *basedir, const char *localpath)
   1.842 -{
   1.843 -	char base_path[PLATFORM_MAX_PATH];
   1.844 -
   1.845 -	/* Form the current path to start reading from */
   1.846 -	if (localpath == NULL)
   1.847 -	{
   1.848 -		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s", basedir);
   1.849 -	} else {
   1.850 -		g_LibSys.PathFormat(base_path, sizeof(base_path), "%s/%s", basedir, localpath);
   1.851 -	}
   1.852 -
   1.853 -	IDirectory *dir = g_LibSys.OpenDirectory(base_path);
   1.854 -
   1.855 -	if (!dir)
   1.856 -	{
   1.857 -		char error[256];
   1.858 -		g_LibSys.GetPlatformError(error, sizeof(error));
   1.859 -		g_Logger.LogError("[SM] Failure reading from plugins path: %s", localpath);
   1.860 -		g_Logger.LogError("[SM] Platform returned error: %s", error);
   1.861 -		return;
   1.862 -	}
   1.863 -
   1.864 -	while (dir->MoreFiles())
   1.865 -	{
   1.866 -		if (dir->IsEntryDirectory() 
   1.867 -			&& (strcmp(dir->GetEntryName(), ".") != 0)
   1.868 -			&& (strcmp(dir->GetEntryName(), "..") != 0)
   1.869 -			&& (strcmp(dir->GetEntryName(), "disabled") != 0)
   1.870 -			&& (strcmp(dir->GetEntryName(), "optional") != 0))
   1.871 -		{
   1.872 -			char new_local[PLATFORM_MAX_PATH];
   1.873 -			if (localpath == NULL)
   1.874 -			{
   1.875 -				/* If no path yet, don't add a former slash */
   1.876 -				snprintf(new_local, sizeof(new_local), "%s", dir->GetEntryName());
   1.877 -			} else {
   1.878 -				g_LibSys.PathFormat(new_local, sizeof(new_local), "%s/%s", localpath, dir->GetEntryName());
   1.879 -			}
   1.880 -			LoadPluginsFromDir(basedir, new_local);
   1.881 -		} else if (dir->IsEntryFile()) {
   1.882 -			const char *name = dir->GetEntryName();
   1.883 -			size_t len = strlen(name);
   1.884 -			if (len >= 4
   1.885 -				&& strcmp(&name[len-4], ".smx") == 0)
   1.886 -			{
   1.887 -				/* If the filename matches, load the plugin */
   1.888 -				char plugin[PLATFORM_MAX_PATH];
   1.889 -				if (localpath == NULL)
   1.890 -				{
   1.891 -					snprintf(plugin, sizeof(plugin), "%s", name);
   1.892 -				} else {
   1.893 -					g_LibSys.PathFormat(plugin, sizeof(plugin), "%s/%s", localpath, name);
   1.894 -				}
   1.895 -				LoadAutoPlugin(plugin);
   1.896 -			}
   1.897 -		}
   1.898 -		dir->NextEntry();
   1.899 -	}
   1.900 -	g_LibSys.CloseDirectory(dir);
   1.901 -}
   1.902 -
   1.903 -//well i have discovered that gabe newell is very fat, so i wrote this comment now
   1.904 -LoadRes CPluginManager::_LoadPlugin(CPlugin **_plugin, const char *path, bool debug, PluginType type, char error[], size_t maxlength)
   1.905 -{
   1.906 -	if (m_LoadingLocked)
   1.907 -	{
   1.908 -		return LoadRes_NeverLoad;
   1.909 -	}
   1.910 -
   1.911 -	bool no_load = false;
   1.912 -	PluginSettings *pset;
   1.913 -	unsigned int setcount = m_PluginInfo.GetSettingsNum();
   1.914 -	for (unsigned int i=0; i<setcount; i++)
   1.915 -	{
   1.916 -		if ((pset = m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
   1.917 -		{
   1.918 -			continue;
   1.919 -		}
   1.920 -		if (pset->blockload_val)
   1.921 -		{
   1.922 -			no_load = true;
   1.923 -			break;
   1.924 -		}
   1.925 -	}
   1.926 -
   1.927 -	/**
   1.928 -	 * Does this plugin already exist?
   1.929 -	 */
   1.930 -	CPlugin *pPlugin;
   1.931 -	if (sm_trie_retrieve(m_LoadLookup, path, (void **)&pPlugin))
   1.932 -	{
   1.933 -		/* Check to see if we should try reloading it */
   1.934 -		if (pPlugin->GetStatus() == Plugin_BadLoad
   1.935 -			|| pPlugin->GetStatus() == Plugin_Error
   1.936 -			|| pPlugin->GetStatus() == Plugin_Failed
   1.937 -			|| no_load)
   1.938 -		{
   1.939 -			UnloadPlugin(pPlugin);
   1.940 -		}
   1.941 -		else
   1.942 -		{
   1.943 -			if (_plugin)
   1.944 -			{
   1.945 -				*_plugin = pPlugin;
   1.946 -			}
   1.947 -			return LoadRes_AlreadyLoaded;
   1.948 -		}
   1.949 -	}
   1.950 -
   1.951 -	if (no_load)
   1.952 -	{
   1.953 -		return LoadRes_NeverLoad;
   1.954 -	}
   1.955 -
   1.956 -	pPlugin = CPlugin::CreatePlugin(path, error, maxlength);
   1.957 -
   1.958 -	assert(pPlugin != NULL);
   1.959 -
   1.960 -	pPlugin->m_type = PluginType_MapUpdated;
   1.961 -
   1.962 -	ICompilation *co = NULL;
   1.963 -
   1.964 -	if (pPlugin->m_status == Plugin_Uncompiled)
   1.965 -	{
   1.966 -		co = pPlugin->StartMyCompile(g_pVM);
   1.967 -	}
   1.968 -
   1.969 -	for (unsigned int i=0; i<setcount; i++)
   1.970 -	{
   1.971 -		if ((pset=m_PluginInfo.GetSettingsIfMatch(i, path)) == NULL)
   1.972 -		{
   1.973 -			continue;
   1.974 -		}
   1.975 -		pPlugin->m_type = pset->type_val;
   1.976 -		if (co)
   1.977 -		{
   1.978 -			for (unsigned int j=0; j<pset->opts_num; j++)
   1.979 -			{
   1.980 -				const char *key, *val;
   1.981 -				m_PluginInfo.GetOptionsForPlugin(pset, j, &key, &val);
   1.982 -				if (!key || !val)
   1.983 -				{
   1.984 -					continue;
   1.985 -				}
   1.986 -				if (!g_pVM->SetCompilationOption(co, key, val))
   1.987 -				{
   1.988 -					if (error)
   1.989 -					{
   1.990 -						snprintf(error, maxlength, "Unable to set JIT option (key \"%s\") (value \"%s\")", key, val);
   1.991 -					}
   1.992 -					pPlugin->CancelMyCompile();
   1.993 -					co = NULL;
   1.994 -					break;
   1.995 -				}
   1.996 -			}
   1.997 -		}
   1.998 -	}
   1.999 -
  1.1000 -	/* Do the actual compiling */
  1.1001 -	if (co)
  1.1002 -	{
  1.1003 -		pPlugin->FinishMyCompile(error, maxlength);
  1.1004 -		co = NULL;
  1.1005 -	}
  1.1006 -
  1.1007 -	/* Get the status */
  1.1008 -	if (pPlugin->GetStatus() == Plugin_Created)
  1.1009 -	{
  1.1010 -		AddCoreNativesToPlugin(pPlugin);
  1.1011 -		pPlugin->InitIdentity();
  1.1012 -		if (pPlugin->Call_AskPluginLoad(error, maxlength))
  1.1013 -		{
  1.1014 -			/* Autoload any modules */
  1.1015 -			LoadOrRequireExtensions(pPlugin, 1, error, maxlength);
  1.1016 -		}
  1.1017 -		else
  1.1018 -		{
  1.1019 -			pPlugin->SetErrorState(Plugin_Failed, "%s", error);
  1.1020 -		}
  1.1021 -	}
  1.1022 -
  1.1023 -	/* Save the time stamp */
  1.1024 -	time_t t = pPlugin->GetFileTimeStamp();
  1.1025 -	pPlugin->SetTimeStamp(t);
  1.1026 -
  1.1027 -	if (_plugin)
  1.1028 -	{
  1.1029 -		*_plugin = pPlugin;
  1.1030 -	}
  1.1031 -
  1.1032 -	return (pPlugin->GetStatus() == Plugin_Loaded) ? LoadRes_Successful : LoadRes_Failure;
  1.1033 -}
  1.1034 -
  1.1035 -IPlugin *CPluginManager::LoadPlugin(const char *path, bool debug, PluginType type, char error[], size_t maxlength, bool *wasloaded)
  1.1036 -{
  1.1037 -	CPlugin *pl;
  1.1038 -	LoadRes res;
  1.1039 -
  1.1040 -	*wasloaded = false;
  1.1041 -	if ((res=_LoadPlugin(&pl, path, debug, type, error, maxlength)) == LoadRes_Failure)
  1.1042 -	{
  1.1043 -		delete pl;
  1.1044 -		return NULL;
  1.1045 -	}
  1.1046 -
  1.1047 -	if (res == LoadRes_AlreadyLoaded)
  1.1048 -	{
  1.1049 -		*wasloaded = true;
  1.1050 -		return pl;
  1.1051 -	}
  1.1052 -
  1.1053 -	if (res == LoadRes_NeverLoad)
  1.1054 -	{
  1.1055 -		if (m_LoadingLocked)
  1.1056 -		{
  1.1057 -			UTIL_Format(error, maxlength, "There is a global plugin loading lock in effect.");
  1.1058 -		}
  1.1059 -		else
  1.1060 -		{
  1.1061 -			UTIL_Format(error, maxlength, "This plugin is blocked from loading (see plugin_settings.cfg)");
  1.1062 -		}
  1.1063 -		return NULL;
  1.1064 -	}
  1.1065 -
  1.1066 -	AddPlugin(pl);
  1.1067 -
  1.1068 -	/* Run second pass if we need to */
  1.1069 -	if (IsLateLoadTime() && pl->GetStatus() == Plugin_Loaded)
  1.1070 -	{
  1.1071 -		if (!RunSecondPass(pl, error, maxlength))
  1.1072 -		{
  1.1073 -			UnloadPlugin(pl);
  1.1074 -			return NULL;
  1.1075 -		}
  1.1076 -		pl->Call_OnAllPluginsLoaded();
  1.1077 -	}
  1.1078 -
  1.1079 -	return pl;
  1.1080 -}
  1.1081 -
  1.1082 -void CPluginManager::LoadAutoPlugin(const char *plugin)
  1.1083 -{
  1.1084 -	CPlugin *pl = NULL;
  1.1085 -	LoadRes res;
  1.1086 -	char error[255] = "Unknown error";
  1.1087 -
  1.1088 -	if ((res=_LoadPlugin(&pl, plugin, false, PluginType_MapUpdated, error, sizeof(error))) == LoadRes_Failure)
  1.1089 -	{
  1.1090 -		g_Logger.LogError("[SM] Failed to load plugin \"%s\": %s", plugin, error);
  1.1091 -		pl->SetErrorState(Plugin_Failed, "%s", error);
  1.1092 -	}
  1.1093 -
  1.1094 -	if (res == LoadRes_Successful)
  1.1095 -	{
  1.1096 -		AddPlugin(pl);
  1.1097 -	}
  1.1098 -}
  1.1099 -
  1.1100 -void CPluginManager::AddPlugin(CPlugin *pPlugin)
  1.1101 -{
  1.1102 -	List<IPluginsListener *>::iterator iter;
  1.1103 -	IPluginsListener *pListener;
  1.1104 -
  1.1105 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
  1.1106 -	{
  1.1107 -		pListener = (*iter);
  1.1108 -		pListener->OnPluginCreated(pPlugin);
  1.1109 -	}
  1.1110 -
  1.1111 -	m_plugins.push_back(pPlugin);
  1.1112 -	sm_trie_insert(m_LoadLookup, pPlugin->m_filename, pPlugin);
  1.1113 -}
  1.1114 -
  1.1115 -void CPluginManager::LoadAll_SecondPass()
  1.1116 -{
  1.1117 -	List<CPlugin *>::iterator iter;
  1.1118 -	CPlugin *pPlugin;
  1.1119 -
  1.1120 -	char error[256];
  1.1121 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
  1.1122 -	{
  1.1123 -		pPlugin = (*iter);
  1.1124 -		if (pPlugin->GetStatus() == Plugin_Loaded)
  1.1125 -		{
  1.1126 -			error[0] = '\0';
  1.1127 -			if (!RunSecondPass(pPlugin, error, sizeof(error)))
  1.1128 -			{
  1.1129 -				g_Logger.LogError("[SM] Unable to load plugin \"%s\": %s", pPlugin->GetFilename(), error);
  1.1130 -				pPlugin->SetErrorState(Plugin_Failed, "%s", error);
  1.1131 -			}
  1.1132 -		}
  1.1133 -	}
  1.1134 -
  1.1135 -	m_AllPluginsLoaded = true;
  1.1136 -}
  1.1137 -
  1.1138 -bool CPluginManager::FindOrRequirePluginDeps(CPlugin *pPlugin, char *error, size_t maxlength)
  1.1139 -{
  1.1140 -	struct _pl
  1.1141 -	{
  1.1142 -		cell_t name;
  1.1143 -		cell_t file;
  1.1144 -		cell_t required;
  1.1145 -	} *pl;
  1.1146 -
  1.1147 -	IPluginContext *pBase = pPlugin->GetBaseContext();
  1.1148 -	uint32_t num = pBase->GetPubVarsNum();
  1.1149 -	sp_pubvar_t *pubvar;
  1.1150 -	char *name, *file;
  1.1151 -	char pathfile[PLATFORM_MAX_PATH];
  1.1152 -
  1.1153 -	for (uint32_t i=0; i<num; i++)
  1.1154 -	{
  1.1155 -		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
  1.1156 -		{
  1.1157 -			continue;
  1.1158 -		}
  1.1159 -		if (strncmp(pubvar->name, "__pl_", 5) == 0)
  1.1160 -		{
  1.1161 -			pl = (_pl *)pubvar->offs;
  1.1162 -			if (pBase->LocalToString(pl->file, &file) != SP_ERROR_NONE)
  1.1163 -			{
  1.1164 -				continue;
  1.1165 -			}
  1.1166 -			if (pBase->LocalToString(pl->name, &name) != SP_ERROR_NONE)
  1.1167 -			{
  1.1168 -				continue;
  1.1169 -			}
  1.1170 -			g_LibSys.GetFileFromPath(pathfile, sizeof(pathfile), pPlugin->GetFilename());
  1.1171 -			if (strcmp(pathfile, file) == 0)
  1.1172 -			{
  1.1173 -				continue;
  1.1174 -			}
  1.1175 -			if (pl->required == false)
  1.1176 -			{
  1.1177 -				IPluginFunction *pFunc;
  1.1178 -				char buffer[64];
  1.1179 -				UTIL_Format(buffer, sizeof(buffer), "__pl_%s_SetNTVOptional", &pubvar->name[5]);
  1.1180 -				if ((pFunc=pBase->GetFunctionByName(buffer)))
  1.1181 -				{
  1.1182 -					cell_t res;
  1.1183 -					pFunc->Execute(&res);
  1.1184 -					if (pPlugin->GetContext()->n_err != SP_ERROR_NONE)
  1.1185 -					{
  1.1186 -						if (error)
  1.1187 -						{
  1.1188 -							snprintf(error, maxlength, "Fatal error during initializing plugin load");
  1.1189 -						}
  1.1190 -						return false;
  1.1191 -					}
  1.1192 -				}
  1.1193 -			}
  1.1194 -			else
  1.1195 -			{
  1.1196 -				/* Check that we aren't registering the same library twice */
  1.1197 -				if (pPlugin->m_RequiredLibs.find(name) == pPlugin->m_RequiredLibs.end())
  1.1198 -				{
  1.1199 -					pPlugin->m_RequiredLibs.push_back(name);
  1.1200 -				}
  1.1201 -				else
  1.1202 -				{
  1.1203 -					continue;
  1.1204 -				}
  1.1205 -				List<CPlugin *>::iterator iter;
  1.1206 -				CPlugin *pl;
  1.1207 -				bool found = false;
  1.1208 -				for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
  1.1209 -				{
  1.1210 -					pl = (*iter);
  1.1211 -					if (pl->m_Libraries.find(name) != pl->m_Libraries.end())
  1.1212 -					{
  1.1213 -						found = true;
  1.1214 -						break;
  1.1215 -					}
  1.1216 -				}
  1.1217 -				if (!found)
  1.1218 -				{
  1.1219 -					if (error)
  1.1220 -					{
  1.1221 -						snprintf(error, maxlength, "Could not find required plugin \"%s\"", name);
  1.1222 -					}
  1.1223 -					return false;
  1.1224 -				}
  1.1225 -			}
  1.1226 -		}
  1.1227 -	}
  1.1228 -
  1.1229 -	return true;
  1.1230 -}
  1.1231 -
  1.1232 -bool CPluginManager::LoadOrRequireExtensions(CPlugin *pPlugin, unsigned int pass, char *error, size_t maxlength)
  1.1233 -{
  1.1234 -	/* Find any extensions this plugin needs */
  1.1235 -	struct _ext
  1.1236 -	{
  1.1237 -		cell_t name;
  1.1238 -		cell_t file;
  1.1239 -		cell_t autoload;
  1.1240 -		cell_t required;
  1.1241 -	} *ext;
  1.1242 -
  1.1243 -	IPluginContext *pBase = pPlugin->GetBaseContext();
  1.1244 -	uint32_t num = pBase->GetPubVarsNum();
  1.1245 -	sp_pubvar_t *pubvar;
  1.1246 -	IExtension *pExt;
  1.1247 -	char path[PLATFORM_MAX_PATH];
  1.1248 -	char *file, *name;
  1.1249 -	for (uint32_t i=0; i<num; i++)
  1.1250 -	{
  1.1251 -		if (pBase->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
  1.1252 -		{
  1.1253 -			continue;
  1.1254 -		}
  1.1255 -		if (strncmp(pubvar->name, "__ext_", 6) == 0)
  1.1256 -		{
  1.1257 -			ext = (_ext *)pubvar->offs;
  1.1258 -			if (!ext->required && !ext->autoload)
  1.1259 -			{
  1.1260 -				continue;
  1.1261 -			}
  1.1262 -			if (pBase->LocalToString(ext->file, &file) != SP_ERROR_NONE)
  1.1263 -			{
  1.1264 -				continue;
  1.1265 -			}
  1.1266 -			if (pBase->LocalToString(ext->name, &name) != SP_ERROR_NONE)
  1.1267 -			{
  1.1268 -				continue;
  1.1269 -			}
  1.1270 -			if (pass == 1)
  1.1271 -			{
  1.1272 -				/* Attempt to auto-load if necessary */
  1.1273 -				if (ext->autoload)
  1.1274 -				{
  1.1275 -					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
  1.1276 -					g_Extensions.LoadAutoExtension(path);
  1.1277 -				}
  1.1278 -			}
  1.1279 -			else if (pass == 2)
  1.1280 -			{
  1.1281 -				/* Is this required? */
  1.1282 -				if (ext->required)
  1.1283 -				{
  1.1284 -					g_LibSys.PathFormat(path, PLATFORM_MAX_PATH, "%s", file);
  1.1285 -					if ((pExt = g_Extensions.FindExtensionByFile(path)) == NULL)
  1.1286 -					{
  1.1287 -						pExt = g_Extensions.FindExtensionByName(name);
  1.1288 -					}
  1.1289 -					/* :TODO: should we bind to unloaded extensions?
  1.1290 -					 * Currently the extension manager will ignore this.
  1.1291 -					 */
  1.1292 -					if (!pExt || !pExt->IsRunning(NULL, 0))
  1.1293 -					{
  1.1294 -						if (error)
  1.1295 -						{
  1.1296 -							snprintf(error, maxlength, "Required extension \"%s\" file(\"%s\") not running", name, file);
  1.1297 -						}
  1.1298 -						return false;
  1.1299 -					}
  1.1300 -					else
  1.1301 -					{
  1.1302 -						g_Extensions.BindChildPlugin(pExt, pPlugin);
  1.1303 -					}
  1.1304 -				}
  1.1305 -				else
  1.1306 -				{
  1.1307 -					IPluginFunction *pFunc;
  1.1308 -					char buffer[64];
  1.1309 -					UTIL_Format(buffer, sizeof(buffer), "__ext_%s_SetNTVOptional", &pubvar->name[6]);
  1.1310 -
  1.1311 -					if ((pFunc = pBase->GetFunctionByName(buffer)) != NULL)
  1.1312 -					{
  1.1313 -						cell_t res;
  1.1314 -						pFunc->Execute(&res);
  1.1315 -						if (pPlugin->GetContext()->n_err != SP_ERROR_NONE)
  1.1316 -						{
  1.1317 -							if (error)
  1.1318 -							{
  1.1319 -								UTIL_Format(error, maxlength, "Fatal error during plugin initialization (ext req)");
  1.1320 -							}
  1.1321 -							return false;
  1.1322 -						}
  1.1323 -					}
  1.1324 -				}
  1.1325 -			}
  1.1326 -		}
  1.1327 -	}
  1.1328 -
  1.1329 -	return true;
  1.1330 -}
  1.1331 -
  1.1332 -bool CPluginManager::RunSecondPass(CPlugin *pPlugin, char *error, size_t maxlength)
  1.1333 -{
  1.1334 -	/* Second pass for extension requirements */
  1.1335 -	if (!LoadOrRequireExtensions(pPlugin, 2, error, maxlength))
  1.1336 -	{
  1.1337 -		return false;
  1.1338 -	}
  1.1339 -
  1.1340 -	/* Bind all extra natives */
  1.1341 -	g_Extensions.BindAllNativesToPlugin(pPlugin);
  1.1342 -
  1.1343 -	if (!FindOrRequirePluginDeps(pPlugin, error, maxlength))
  1.1344 -	{
  1.1345 -		return false;
  1.1346 -	}
  1.1347 -
  1.1348 -	AddFakeNativesToPlugin(pPlugin);
  1.1349 -
  1.1350 -	/* Find any unbound natives
  1.1351 -	 * Right now, these are not allowed
  1.1352 -	 */
  1.1353 -	IPluginContext *pContext = pPlugin->GetBaseContext();
  1.1354 -	uint32_t num = pContext->GetNativesNum();
  1.1355 -	sp_native_t *native;
  1.1356 -	for (unsigned int i=0; i<num; i++)
  1.1357 -	{
  1.1358 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  1.1359 -		{
  1.1360 -			break;
  1.1361 -		}
  1.1362 -		if (native->status == SP_NATIVE_UNBOUND
  1.1363 -			&& native->name[0] != '@'
  1.1364 -			&& !(native->flags & SP_NTVFLAG_OPTIONAL))
  1.1365 -		{
  1.1366 -			if (error)
  1.1367 -			{
  1.1368 -				snprintf(error, maxlength, "Native \"%s\" was not found.", native->name);
  1.1369 -			}
  1.1370 -			return false;
  1.1371 -		}
  1.1372 -	}
  1.1373 -
  1.1374 -	/* Finish by telling all listeners */
  1.1375 -	List<IPluginsListener *>::iterator iter;
  1.1376 -	IPluginsListener *pListener;
  1.1377 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
  1.1378 -	{
  1.1379 -		pListener = (*iter);
  1.1380 -		pListener->OnPluginLoaded(pPlugin);
  1.1381 -	}
  1.1382 -	
  1.1383 -	/* Tell this plugin to finish initializing itself */
  1.1384 -	pPlugin->Call_OnPluginStart();
  1.1385 -
  1.1386 -	/* Now, if we have fake natives, go through all plugins that might need rebinding */
  1.1387 -	if (pPlugin->GetStatus() <= Plugin_Paused && pPlugin->m_fakeNatives.size())
  1.1388 -	{
  1.1389 -		List<CPlugin *>::iterator pl_iter;
  1.1390 -		CPlugin *pOther;
  1.1391 -		for (pl_iter = m_plugins.begin();
  1.1392 -			 pl_iter != m_plugins.end();
  1.1393 -			 pl_iter++)
  1.1394 -		{
  1.1395 -			pOther = (*pl_iter);
  1.1396 -			if ((pOther->GetStatus() == Plugin_Error
  1.1397 -				&& (pOther->m_FakeNativesMissing || pOther->m_LibraryMissing))
  1.1398 -				|| pOther->m_FakeNativesMissing)
  1.1399 -			{
  1.1400 -				TryRefreshDependencies(pOther);
  1.1401 -			}
  1.1402 -		}
  1.1403 -	}
  1.1404 -
  1.1405 -	/* Go through our libraries and tell other plugins they're added */
  1.1406 -	List<String>::iterator s_iter;
  1.1407 -	for (s_iter = pPlugin->m_Libraries.begin();
  1.1408 -		s_iter != pPlugin->m_Libraries.end();
  1.1409 -		s_iter++)
  1.1410 -	{
  1.1411 -		OnLibraryAction((*s_iter).c_str(), true, false);
  1.1412 -	}
  1.1413 -
  1.1414 -	/* Finally, add the core language file */
  1.1415 -	pPlugin->AddLangFile(g_pCorePhraseID);
  1.1416 -
  1.1417 -	return true;
  1.1418 -}
  1.1419 -
  1.1420 -void CPluginManager::AddCoreNativesToPlugin(CPlugin *pPlugin)
  1.1421 -{
  1.1422 -	IPluginContext *pContext = pPlugin->GetBaseContext();
  1.1423 -	
  1.1424 -
  1.1425 -	uint32_t natives = pContext->GetNativesNum();
  1.1426 -	sp_native_t *native;
  1.1427 -	SPVM_NATIVE_FUNC pfn;
  1.1428 -	for (uint32_t i=0; i<natives; i++)
  1.1429 -	{
  1.1430 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  1.1431 -		{
  1.1432 -			continue;
  1.1433 -		}
  1.1434 -		if (native->status == SP_NATIVE_BOUND)
  1.1435 -		{
  1.1436 -			continue;
  1.1437 -		}
  1.1438 -		if (!sm_trie_retrieve(m_pCoreNatives, native->name, (void **)&pfn))
  1.1439 -		{
  1.1440 -			continue;
  1.1441 -		}
  1.1442 -		pContext->BindNativeToIndex(i, pfn);
  1.1443 -	}
  1.1444 -}
  1.1445 -
  1.1446 -SPVM_NATIVE_FUNC CPluginManager::FindCoreNative(const char *name)
  1.1447 -{
  1.1448 -	SPVM_NATIVE_FUNC pfn;
  1.1449 -
  1.1450 -	if (!sm_trie_retrieve(m_pCoreNatives, name, (void **)&pfn))
  1.1451 -	{
  1.1452 -		return NULL;
  1.1453 -	}
  1.1454 -
  1.1455 -	return pfn;
  1.1456 -}
  1.1457 -
  1.1458 -void CPluginManager::TryRefreshDependencies(CPlugin *pPlugin)
  1.1459 -{
  1.1460 -	assert(pPlugin->GetBaseContext() != NULL);
  1.1461 -
  1.1462 -	AddFakeNativesToPlugin(pPlugin);
  1.1463 -
  1.1464 -	List<String>::iterator lib_iter;
  1.1465 -	List<String>::iterator req_iter;
  1.1466 -	List<CPlugin *>::iterator pl_iter;
  1.1467 -	CPlugin *pl;
  1.1468 -	for (req_iter=pPlugin->m_RequiredLibs.begin(); req_iter!=pPlugin->m_RequiredLibs.end(); req_iter++)
  1.1469 -	{
  1.1470 -		bool found = false;
  1.1471 -		for (pl_iter=m_plugins.begin(); pl_iter!=m_plugins.end(); pl_iter++)
  1.1472 -		{
  1.1473 -			pl = (*pl_iter);
  1.1474 -			for (lib_iter=pl->m_Libraries.begin(); lib_iter!=pl->m_Libraries.end(); lib_iter++)
  1.1475 -			{
  1.1476 -				if ((*req_iter) == (*lib_iter))
  1.1477 -				{
  1.1478 -					found = true;
  1.1479 -				}
  1.1480 -			}
  1.1481 -		}
  1.1482 -		if (!found)
  1.1483 -		{
  1.1484 -			pPlugin->SetErrorState(Plugin_Error, "Library not found: %s", (*req_iter).c_str());
  1.1485 -			return;
  1.1486 -		}
  1.1487 -	}
  1.1488 -
  1.1489 -	/* Find any unbound natives
  1.1490 -	 * Right now, these are not allowed
  1.1491 -	 */
  1.1492 -	IPluginContext *pContext = pPlugin->GetBaseContext();
  1.1493 -	uint32_t num = pContext->GetNativesNum();
  1.1494 -	sp_native_t *native;
  1.1495 -	for (unsigned int i=0; i<num; i++)
  1.1496 -	{
  1.1497 -		if (pContext->GetNativeByIndex(i, &native) != SP_ERROR_NONE)
  1.1498 -		{
  1.1499 -			break;
  1.1500 -		}
  1.1501 -		if (native->status == SP_NATIVE_UNBOUND && !(native->flags & SP_NTVFLAG_OPTIONAL))
  1.1502 -		{
  1.1503 -			pPlugin->SetErrorState(Plugin_Error, "Native not found: %s", native->name);
  1.1504 -			return;
  1.1505 -		}
  1.1506 -	}
  1.1507 -
  1.1508 -	if (pPlugin->GetStatus() == Plugin_Error)
  1.1509 -	{
  1.1510 -		/* If we got here, all natives are okay again! */
  1.1511 -		pPlugin->m_status = Plugin_Running;
  1.1512 -		if ((pPlugin->m_ctx.ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
  1.1513 -		{
  1.1514 -			pPlugin->m_ctx.ctx->flags &= ~SPFLAG_PLUGIN_PAUSED;
  1.1515 -			_SetPauseState(pPlugin, false);
  1.1516 -		}
  1.1517 -	}
  1.1518 -}
  1.1519 -
  1.1520 -void CPluginManager::AddFakeNativesToPlugin(CPlugin *pPlugin)
  1.1521 -{
  1.1522 -	IPluginContext *pContext = pPlugin->GetBaseContext();
  1.1523 -	sp_nativeinfo_t native;
  1.1524 -
  1.1525 -	List<FakeNative *>::iterator iter;
  1.1526 -	FakeNative *pNative;
  1.1527 -	sp_context_t *ctx;
  1.1528 -	for (iter = m_Natives.begin(); iter != m_Natives.end(); iter++)
  1.1529 -	{
  1.1530 -		pNative = (*iter);
  1.1531 -		ctx = pNative->ctx->GetContext();
  1.1532 -		if ((ctx->flags & SPFLAG_PLUGIN_PAUSED) == SPFLAG_PLUGIN_PAUSED)
  1.1533 -		{
  1.1534 -			/* Ignore natives in paused plugins */
  1.1535 -			continue;
  1.1536 -		}
  1.1537 -		native.name = pNative->name.c_str();
  1.1538 -		native.func = pNative->func;
  1.1539 -		if (pContext->BindNative(&native) == SP_ERROR_NONE)
  1.1540 -		{
  1.1541 -			uint32_t idx;
  1.1542 -			pContext->FindNativeByName(native.name, &idx);
  1.1543 -			if (pPlugin->GetContext()->natives[idx].flags & SP_NTVFLAG_OPTIONAL)
  1.1544 -			{
  1.1545 -				WeakNative wkn(pPlugin, idx);
  1.1546 -				GetPluginByCtx(ctx)->m_WeakNatives.push_back(wkn);
  1.1547 -				continue;
  1.1548 -			}
  1.1549 -			/* Add us as a dependency, but we're careful not to do this circularly! */
  1.1550 -			if (pNative->ctx != pContext)
  1.1551 -			{
  1.1552 -				CPlugin *pOther = GetPluginByCtx(ctx);
  1.1553 -				if (pOther->m_dependents.find(pPlugin) == pOther->m_dependents.end())
  1.1554 -				{
  1.1555 -					pOther->m_dependents.push_back(pPlugin);
  1.1556 -				}
  1.1557 -				if (pPlugin->m_dependsOn.find(pOther) == pPlugin->m_dependsOn.end())
  1.1558 -				{
  1.1559 -					pPlugin->m_dependsOn.push_back(pOther);
  1.1560 -				}
  1.1561 -			}
  1.1562 -		}
  1.1563 -	}
  1.1564 -}
  1.1565 -
  1.1566 -bool CPluginManager::UnloadPlugin(IPlugin *plugin)
  1.1567 -{
  1.1568 -	CPlugin *pPlugin = (CPlugin *)plugin;
  1.1569 -
  1.1570 -	/* This prevents removal during insertion or anything else weird */
  1.1571 -	if (m_plugins.find(pPlugin) == m_plugins.end())
  1.1572 -	{
  1.1573 -		return false;
  1.1574 -	}
  1.1575 -
  1.1576 -	IPluginContext *pContext = plugin->GetBaseContext();
  1.1577 -	if (pContext->IsInExec())
  1.1578 -	{
  1.1579 -		char buffer[255];
  1.1580 -		UTIL_Format(buffer, sizeof(buffer), "sm plugins unload %s\n", plugin->GetFilename());
  1.1581 -		engine->ServerCommand(buffer);
  1.1582 -		return false;
  1.1583 -	}
  1.1584 -
  1.1585 -	/* Remove us from the lookup table and linked list */
  1.1586 -	m_plugins.remove(pPlugin);
  1.1587 -	sm_trie_delete(m_LoadLookup, pPlugin->m_filename);
  1.1588 -
  1.1589 -	/* Go through our libraries and tell other plugins they're gone */
  1.1590 -	List<String>::iterator s_iter;
  1.1591 -	for (s_iter = pPlugin->m_Libraries.begin();
  1.1592 -		 s_iter != pPlugin->m_Libraries.end();
  1.1593 -		 s_iter++)
  1.1594 -	{
  1.1595 -		OnLibraryAction((*s_iter).c_str(), true, true);
  1.1596 -	}
  1.1597 -
  1.1598 -	/* Go through all dependent plugins and tell them this plugin is now gone */
  1.1599 -	List<CPlugin *>::iterator pl_iter;
  1.1600 -	CPlugin *pOther;
  1.1601 -	for (pl_iter = pPlugin->m_dependents.begin();
  1.1602 -		 pl_iter != pPlugin->m_dependents.end();
  1.1603 -		 pl_iter++)
  1.1604 -	{
  1.1605 -		pOther = (*pl_iter);
  1.1606 -		pOther->DependencyDropped(pPlugin);
  1.1607 -	}
  1.1608 -
  1.1609 -	/* Tell everyone we depend on that we no longer exist */
  1.1610 -	for (pl_iter = pPlugin->m_dependsOn.begin();
  1.1611 -		 pl_iter != pPlugin->m_dependsOn.end();
  1.1612 -		 pl_iter++)
  1.1613 -	{
  1.1614 -		pOther = (*pl_iter);
  1.1615 -		pOther->m_dependents.remove(pPlugin);
  1.1616 -	}
  1.1617 -
  1.1618 -	/* Remove weak references to us */
  1.1619 -	for (pl_iter = m_plugins.begin();
  1.1620 -		 pl_iter != m_plugins.end();
  1.1621 -		 pl_iter++)
  1.1622 -	{
  1.1623 -		pOther = (*pl_iter);
  1.1624 -		List<WeakNative>::iterator wk_iter = pOther->m_WeakNatives.begin();
  1.1625 -		while (wk_iter != pOther->m_WeakNatives.end())
  1.1626 -		{
  1.1627 -			if ((*wk_iter).pl == pPlugin)
  1.1628 -			{
  1.1629 -				wk_iter = pOther->m_WeakNatives.erase(wk_iter);
  1.1630 -			} else {
  1.1631 -				wk_iter++;
  1.1632 -			}
  1.1633 -		}
  1.1634 -	}
  1.1635 -
  1.1636 -	List<IPluginsListener *>::iterator iter;
  1.1637 -	IPluginsListener *pListener;
  1.1638 -
  1.1639 -	if (pPlugin->GetStatus() <= Plugin_Error)
  1.1640 -	{
  1.1641 -		/* Notify listeners of unloading */
  1.1642 -		for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
  1.1643 -		{
  1.1644 -			pListener = (*iter);
  1.1645 -			pListener->OnPluginUnloaded(pPlugin);
  1.1646 -		}
  1.1647 -		/* Notify plugin */
  1.1648 -		pPlugin->Call_OnPluginEnd();
  1.1649 -	}
  1.1650 -
  1.1651 -	/* Unbound weak natives */
  1.1652 -	List<WeakNative>::iterator wk_iter;
  1.1653 -	for (wk_iter=pPlugin->m_WeakNatives.begin(); wk_iter!=pPlugin->m_WeakNatives.end(); wk_iter++)
  1.1654 -	{
  1.1655 -		WeakNative & wkn = (*wk_iter);
  1.1656 -		sp_context_t *ctx = wkn.pl->GetContext();
  1.1657 -		ctx->natives[wkn.idx].status = SP_NATIVE_UNBOUND;
  1.1658 -		wkn.pl->m_FakeNativesMissing = true;
  1.1659 -	}
  1.1660 -
  1.1661 -	/* Remove all of our native functions */
  1.1662 -	List<FakeNative *>::iterator fn_iter;
  1.1663 -	FakeNative *pNative;
  1.1664 -	for (fn_iter = pPlugin->m_fakeNatives.begin();
  1.1665 -		fn_iter != pPlugin->m_fakeNatives.end();
  1.1666 -		fn_iter++)
  1.1667 -	{
  1.1668 -		pNative = (*fn_iter);
  1.1669 -		m_Natives.remove(pNative);
  1.1670 -		sm_trie_delete(m_pNativeLookup, pNative->name.c_str());
  1.1671 -		g_pVM->DestroyFakeNative(pNative->func);
  1.1672 -		delete pNative;
  1.1673 -	}
  1.1674 -
  1.1675 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
  1.1676 -	{
  1.1677 -		/* Notify listeners of destruction */
  1.1678 -		pListener = (*iter);
  1.1679 -		pListener->OnPluginDestroyed(pPlugin);
  1.1680 -	}
  1.1681 -	
  1.1682 -	/* Tell the plugin to delete itself */
  1.1683 -	delete pPlugin;
  1.1684 -
  1.1685 -	return true;
  1.1686 -}
  1.1687 -
  1.1688 -IPlugin *CPluginManager::FindPluginByContext(const sp_context_t *ctx)
  1.1689 -{
  1.1690 -	IPlugin *pl = (IPlugin *)ctx->user[SM_CONTEXTVAR_MYSELF];
  1.1691 -	return pl;
  1.1692 -}
  1.1693 -
  1.1694 -unsigned int CPluginManager::GetPluginCount()
  1.1695 -{
  1.1696 -	return m_plugins.size();
  1.1697 -}
  1.1698 -
  1.1699 -void CPluginManager::AddPluginsListener(IPluginsListener *listener)
  1.1700 -{
  1.1701 -	m_listeners.push_back(listener);
  1.1702 -}
  1.1703 -
  1.1704 -void CPluginManager::RemovePluginsListener(IPluginsListener *listener)
  1.1705 -{
  1.1706 -	m_listeners.remove(listener);
  1.1707 -}
  1.1708 -
  1.1709 -IPluginIterator *CPluginManager::GetPluginIterator()
  1.1710 -{
  1.1711 -	if (m_iters.empty())
  1.1712 -	{
  1.1713 -		return new CPluginIterator(&m_plugins);
  1.1714 -	} else {
  1.1715 -		CPluginIterator *iter = m_iters.front();
  1.1716 -		m_iters.pop();
  1.1717 -		iter->Reset();
  1.1718 -		return iter;
  1.1719 -	}
  1.1720 -}
  1.1721 -
  1.1722 -void CPluginManager::ReleaseIterator(CPluginIterator *iter)
  1.1723 -{
  1.1724 -	m_iters.push(iter);
  1.1725 -}
  1.1726 -
  1.1727 -bool CPluginManager::TestAliasMatch(const char *alias, const char *localpath)
  1.1728 -{
  1.1729 -	/* As an optimization, we do not call strlen, but compute the length in the first pass */
  1.1730 -	size_t alias_len = 0;
  1.1731 -	size_t local_len = 0;
  1.1732 -
  1.1733 -	const char *ptr = alias;
  1.1734 -	unsigned int alias_explicit_paths = 0;
  1.1735 -	unsigned int alias_path_end = 0;
  1.1736 -	while (*ptr != '\0')
  1.1737 -	{
  1.1738 -		if (*ptr == '\\' || *ptr == '/')
  1.1739 -		{
  1.1740 -			alias_explicit_paths++;
  1.1741 -			alias_path_end = alias_len;
  1.1742 -		}
  1.1743 -		alias_len++;
  1.1744 -		ptr++;
  1.1745 -	}
  1.1746 -
  1.1747 -	if (alias_explicit_paths && alias_path_end == alias_len - 1)
  1.1748 -	{
  1.1749 -		/* Trailing slash is totally invalid here */
  1.1750 -		return false;
  1.1751 -	}
  1.1752 -
  1.1753 -	ptr = localpath;
  1.1754 -	unsigned int local_explicit_paths = 0;
  1.1755 -	unsigned int local_path_end = 0;
  1.1756 -	while (*ptr != '\0')
  1.1757 -	{
  1.1758 -		if (*ptr == '\\' || *ptr == '/')
  1.1759 -		{
  1.1760 -			local_explicit_paths++;
  1.1761 -			local_path_end = local_len;
  1.1762 -		}
  1.1763 -		local_len++;
  1.1764 -		ptr++;
  1.1765 -	}
  1.1766 -
  1.1767 -	/* If the alias has more explicit paths than the real path,
  1.1768 -	 * no match will be possible.
  1.1769 -	 */
  1.1770 -	if (alias_explicit_paths > local_explicit_paths)
  1.1771 -	{
  1.1772 -		return false;
  1.1773 -	}
  1.1774 -
  1.1775 -	if (alias_explicit_paths)
  1.1776 -	{
  1.1777 -		/* We need to find if the paths match now.  For example, these should all match:
  1.1778 -		 * csdm     csdm
  1.1779 -		 * csdm     optional/csdm
  1.1780 -		 * csdm/ban optional/crab/csdm/ban
  1.1781 -		*/
  1.1782 -		const char *aliasptr = alias;
  1.1783 -		const char *localptr = localpath;
  1.1784 -		bool match = true;
  1.1785 -		do
  1.1786 -		{
  1.1787 -			if (*aliasptr != *localptr)
  1.1788 -			{
  1.1789 -				/* We have to knock one path off */
  1.1790 -				local_explicit_paths--;
  1.1791 -				if (alias_explicit_paths > local_explicit_paths)
  1.1792 -				{
  1.1793 -					/* Skip out if we're gonna have an impossible match */
  1.1794 -					return false;
  1.1795 -				}
  1.1796 -				/* Eat up localptr tokens until we get a result */
  1.1797 -				while (((localptr - localpath) < (int)local_path_end)
  1.1798 -					&& *localptr != '/'
  1.1799 -					&& *localptr != '\\')
  1.1800 -				{
  1.1801 -					localptr++;
  1.1802 -				}
  1.1803 -				/* Check if we hit the end of our searchable area.
  1.1804 -				 * This probably isn't possible because of the path 
  1.1805 -				 * count check, but it's a good idea anyway.
  1.1806 -				 */
  1.1807 -				if ((localptr - localpath) >= (int)local_path_end)
  1.1808 -				{
  1.1809 -					return false;
  1.1810 -				} else {
  1.1811 -					/* Consume the slash token */
  1.1812 -					localptr++;
  1.1813 -				}
  1.1814 -				/* Reset the alias pointer so we can continue consuming */
  1.1815 -				aliasptr = alias;
  1.1816 -				match = false;
  1.1817 -				continue;
  1.1818 -			}
  1.1819 -			/* Note:
  1.1820 -			 * This is safe because if localptr terminates early, aliasptr will too
  1.1821 -			 */
  1.1822 -			do
  1.1823 -			{
  1.1824 -				/* We should never reach the end of the string because of this check. */
  1.1825 -				bool aliasend = (aliasptr - alias) > (int)alias_path_end;
  1.1826 -				bool localend = (localptr - localpath) > (int)local_path_end;
  1.1827 -				if (aliasend || localend)
  1.1828 -				{
  1.1829 -					if (aliasend && localend)
  1.1830 -					{
  1.1831 -						/* we matched, and we can break out now */
  1.1832 -						match = true;
  1.1833 -						break;
  1.1834 -					}
  1.1835 -					/* Otherwise, we've hit the end somehow and rest won't match up.  Break out. */
  1.1836 -					match = false;
  1.1837 -					break;
  1.1838 -				}
  1.1839 -
  1.1840 -				/* If we got here, it's safe to compare the next two tokens */
  1.1841 -				if (*localptr != *aliasptr)
  1.1842 -				{
  1.1843 -					match = false;
  1.1844 -					break;
  1.1845 -				}
  1.1846 -				localptr++;
  1.1847 -				aliasptr++;
  1.1848 -			} while (true);
  1.1849 -		} while (!match);
  1.1850 -	}
  1.1851 -
  1.1852 -	/* If we got here, it's time to compare filenames */
  1.1853 -	const char *aliasptr = alias;
  1.1854 -	const char *localptr = localpath;
  1.1855 -
  1.1856 -	if (alias_explicit_paths)
  1.1857 -	{
  1.1858 -		aliasptr = &alias[alias_path_end + 1];
  1.1859 -	}
  1.1860 -
  1.1861 -	if (local_explicit_paths)
  1.1862 -	{
  1.1863 -		localptr = &localpath[local_path_end + 1];
  1.1864 -	}
  1.1865 -
  1.1866 -	while (true)
  1.1867 -	{
  1.1868 -		if (*aliasptr == '*')
  1.1869 -		{
  1.1870 -			/* First, see if this is the last character */
  1.1871 -			if ((unsigned)(aliasptr - alias) == alias_len - 1)
  1.1872 -			{
  1.1873 -				/* If so, there's no need to match anything else */
  1.1874 -				return true;
  1.1875 -			}
  1.1876 -			/* Otherwise, we need to search for an appropriate matching sequence in local.
  1.1877 -			 * Note that we only need to search up to the next asterisk.
  1.1878 -			 */
  1.1879 -			aliasptr++;
  1.1880 -			bool match = true;
  1.1881 -			const char *local_orig = localptr;
  1.1882 -			do
  1.1883 -			{
  1.1884 -				match = true;
  1.1885 -				while (*aliasptr != '\0' && *aliasptr != '*')
  1.1886 -				{
  1.1887 -					/* Since aliasptr is never '\0', localptr hitting the end will fail */
  1.1888 -					if (*aliasptr != *localptr)
  1.1889 -					{
  1.1890 -						match = false;
  1.1891 -						break;
  1.1892 -					}
  1.1893 -					aliasptr++;
  1.1894 -					localptr++;
  1.1895 -				}
  1.1896 -				if (!match)
  1.1897 -				{
  1.1898 -					/* If we didn't get a match, we need to advance the search stream.
  1.1899 -					 * This will let us skip tokens while still searching for another match.
  1.1900 -					 */
  1.1901 -					localptr = ++local_orig;
  1.1902 -					/* Make sure we don't go out of bounds */
  1.1903 -					if (*localptr == '\0')
  1.1904 -					{
  1.1905 -						break;
  1.1906 -					}
  1.1907 -				}
  1.1908 -			} while (!match);
  1.1909 -
  1.1910 -			if (!match)
  1.1911 -			{
  1.1912 -				return false;
  1.1913 -			} else {
  1.1914 -				/* If we got a match, move on to the next token */
  1.1915 -				continue;
  1.1916 -			}
  1.1917 -		} else if (*aliasptr == '\0') {
  1.1918 -			if (*localptr == '\0'
  1.1919 -				||
  1.1920 -				strcmp(localptr, ".smx") == 0)
  1.1921 -			{
  1.1922 -				return true;
  1.1923 -			} else {
  1.1924 -				return false;
  1.1925 -			}
  1.1926 -		} else if (*aliasptr != *localptr) {
  1.1927 -			return false;
  1.1928 -		}
  1.1929 -		aliasptr++;
  1.1930 -		localptr++;
  1.1931 -	}
  1.1932 -
  1.1933 -	return true;
  1.1934 -}
  1.1935 -
  1.1936 -bool CPluginManager::IsLateLoadTime() const
  1.1937 -{
  1.1938 -	return (m_AllPluginsLoaded || !g_SourceMod.IsMapLoading());
  1.1939 -}
  1.1940 -
  1.1941 -void CPluginManager::OnSourceModAllInitialized()
  1.1942 -{
  1.1943 -	m_MyIdent = g_ShareSys.CreateCoreIdentity();
  1.1944 -
  1.1945 -	HandleAccess sec;
  1.1946 -	g_HandleSys.InitAccessDefaults(NULL, &sec);
  1.1947 -
  1.1948 -	sec.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY;
  1.1949 -	sec.access[HandleAccess_Clone] = HANDLE_RESTRICT_IDENTITY;
  1.1950 -
  1.1951 -	g_PluginType = g_HandleSys.CreateType("Plugin", this, 0, NULL, &sec, m_MyIdent, NULL);
  1.1952 -	g_PluginIdent = g_ShareSys.CreateIdentType("PLUGIN");
  1.1953 -
  1.1954 -	g_RootMenu.AddRootConsoleCommand("plugins", "Manage Plugins", this);
  1.1955 -
  1.1956 -	g_ShareSys.AddInterface(NULL, this);
  1.1957 -}
  1.1958 -
  1.1959 -void CPluginManager::OnSourceModShutdown()
  1.1960 -{
  1.1961 -	g_RootMenu.RemoveRootConsoleCommand("plugins", this);
  1.1962 -
  1.1963 -	UnloadAll();
  1.1964 -
  1.1965 -	g_HandleSys.RemoveType(g_PluginType, m_MyIdent);
  1.1966 -	g_ShareSys.DestroyIdentType(g_PluginIdent);
  1.1967 -	g_ShareSys.DestroyIdentity(m_MyIdent);
  1.1968 -}
  1.1969 -
  1.1970 -void CPluginManager::OnHandleDestroy(HandleType_t type, void *object)
  1.1971 -{
  1.1972 -	/* We don't care about the internal object, actually */
  1.1973 -}
  1.1974 -
  1.1975 -void CPluginManager::RegisterNativesFromCore(sp_nativeinfo_t *natives)
  1.1976 -{
  1.1977 -	for (unsigned int i = 0; natives[i].func != NULL; i++)
  1.1978 -	{
  1.1979 -		sm_trie_insert(m_pCoreNatives, natives[i].name, (void *)natives[i].func);
  1.1980 -	}
  1.1981 -}
  1.1982 -
  1.1983 -IPlugin *CPluginManager::PluginFromHandle(Handle_t handle, HandleError *err)
  1.1984 -{
  1.1985 -	IPlugin *pPlugin;
  1.1986 -	HandleError _err;
  1.1987 -
  1.1988 -	HandleSecurity sec;
  1.1989 -
  1.1990 -	sec.pOwner = NULL;
  1.1991 -	sec.pIdentity = m_MyIdent;
  1.1992 -
  1.1993 -	if ((_err=g_HandleSys.ReadHandle(handle, g_PluginType, &sec, (void **)&pPlugin)) != HandleError_None)
  1.1994 -	{
  1.1995 -		pPlugin = NULL;
  1.1996 -	}
  1.1997 -
  1.1998 -	if (err)
  1.1999 -	{
  1.2000 -		*err = _err;
  1.2001 -	}
  1.2002 -
  1.2003 -	return pPlugin;
  1.2004 -}
  1.2005 -
  1.2006 -CPlugin *CPluginManager::GetPluginByOrder(int num)
  1.2007 -{
  1.2008 -	if (num < 1 || num > (int)GetPluginCount())
  1.2009 -	{
  1.2010 -		return NULL;
  1.2011 -	}
  1.2012 -
  1.2013 -	CPlugin *pl;
  1.2014 -	int id = 1;
  1.2015 -
  1.2016 -	IPluginIterator *iter = GetPluginIterator();
  1.2017 -	for (; iter->MorePlugins() && id<num; iter->NextPlugin(), id++) {}
  1.2018 -
  1.2019 -	pl = (CPlugin *)(iter->GetPlugin());
  1.2020 -	iter->Release();
  1.2021 -
  1.2022 -	return pl;
  1.2023 -}
  1.2024 -
  1.2025 -const char *CPluginManager::GetStatusText(PluginStatus st)
  1.2026 -{
  1.2027 -	switch (st)
  1.2028 -	{
  1.2029 -	case Plugin_Running:
  1.2030 -		return "Running";
  1.2031 -	case Plugin_Paused:
  1.2032 -		return "Paused";
  1.2033 -	case Plugin_Error:
  1.2034 -		return "Error";
  1.2035 -	case Plugin_Uncompiled:
  1.2036 -		return "Uncompiled";
  1.2037 -	case Plugin_BadLoad:
  1.2038 -		return "Bad Load";
  1.2039 -	case Plugin_Failed:
  1.2040 -		return "Failed";
  1.2041 -	default:
  1.2042 -		assert(false);
  1.2043 -		return "-";
  1.2044 -	}
  1.2045 -}
  1.2046 -
  1.2047 -void CPluginManager::OnRootConsoleCommand(const char *cmdname, const CCommand &command)
  1.2048 -{
  1.2049 -	int argcount = command.ArgC();
  1.2050 -	if (argcount >= 3)
  1.2051 -	{
  1.2052 -		const char *cmd = command.Arg(2);
  1.2053 -		if (strcmp(cmd, "list") == 0)
  1.2054 -		{
  1.2055 -			char buffer[256];
  1.2056 -			unsigned int id = 1;
  1.2057 -			int plnum = GetPluginCount();
  1.2058 -
  1.2059 -			if (!plnum)
  1.2060 -			{
  1.2061 -				g_RootMenu.ConsolePrint("[SM] No plugins loaded");
  1.2062 -				return;
  1.2063 -			}
  1.2064 -			else
  1.2065 -			{
  1.2066 -				g_RootMenu.ConsolePrint("[SM] Listing %d plugin%s:", GetPluginCount(), (plnum > 1) ? "s" : "");
  1.2067 -			}
  1.2068 -
  1.2069 -			IPluginIterator *iter = GetPluginIterator();
  1.2070 -			for (; iter->MorePlugins(); iter->NextPlugin(), id++)
  1.2071 -			{
  1.2072 -				IPlugin *pl = iter->GetPlugin();
  1.2073 -				assert(pl->GetStatus() != Plugin_Created);
  1.2074 -				int len = 0;
  1.2075 -				const sm_plugininfo_t *info = pl->GetPublicInfo();
  1.2076 -				if (pl->GetStatus() != Plugin_Running)
  1.2077 -				{
  1.2078 -					len += UTIL_Format(buffer, sizeof(buffer), "  %02d <%s>", id, GetStatusText(pl->GetStatus()));
  1.2079 -				}
  1.2080 -				else
  1.2081 -				{
  1.2082 -					len += UTIL_Format(buffer, sizeof(buffer), "  %02d", id);
  1.2083 -				}
  1.2084 -				len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " \"%s\"", (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
  1.2085 -				if (IS_STR_FILLED(info->version))
  1.2086 -				{
  1.2087 -					len += UTIL_Format(&buffer[len], sizeof(buffer)-len, " (%s)", info->version);
  1.2088 -				}
  1.2089 -				if (IS_STR_FILLED(info->author))
  1.2090 -				{
  1.2091 -					UTIL_Format(&buffer[len], sizeof(buffer)-len, " by %s", info->author);
  1.2092 -				}
  1.2093 -				g_RootMenu.ConsolePrint("%s", buffer);
  1.2094 -			}
  1.2095 -
  1.2096 -			iter->Release();
  1.2097 -			return;
  1.2098 -		}
  1.2099 -		else if (strcmp(cmd, "load") == 0)
  1.2100 -		{
  1.2101 -			if (argcount < 4)
  1.2102 -			{
  1.2103 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins load <file>");
  1.2104 -				return;
  1.2105 -			}
  1.2106 -
  1.2107 -			char error[128];
  1.2108 -			bool wasloaded;
  1.2109 -			const char *filename = command.Arg(3);
  1.2110 -
  1.2111 -			char pluginfile[256];
  1.2112 -			const char *ext = g_LibSys.GetFileExtension(filename) ? "" : ".smx";
  1.2113 -			UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", filename, ext);
  1.2114 -
  1.2115 -			IPlugin *pl = LoadPlugin(pluginfile, false, PluginType_MapUpdated, error, sizeof(error), &wasloaded);
  1.2116 -
  1.2117 -			if (wasloaded)
  1.2118 -			{
  1.2119 -				g_RootMenu.ConsolePrint("[SM] Plugin %s is already loaded.", pluginfile);
  1.2120 -				return;
  1.2121 -			}
  1.2122 -
  1.2123 -			if (pl)
  1.2124 -			{
  1.2125 -				g_RootMenu.ConsolePrint("[SM] Loaded plugin %s successfully.", pluginfile);
  1.2126 -			}
  1.2127 -			else
  1.2128 -			{
  1.2129 -				g_RootMenu.ConsolePrint("[SM] Plugin %s failed to load: %s.", pluginfile, error);
  1.2130 -			}
  1.2131 -
  1.2132 -			return;
  1.2133 -		}
  1.2134 -		else if (strcmp(cmd, "unload") == 0)
  1.2135 -		{
  1.2136 -			if (argcount < 4)
  1.2137 -			{
  1.2138 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins unload <#|file>");
  1.2139 -				return;
  1.2140 -			}
  1.2141 -
  1.2142 -			CPlugin *pl;
  1.2143 -			char *end;
  1.2144 -			const char *arg = command.Arg(3);
  1.2145 -			int id = strtol(arg, &end, 10);
  1.2146 -
  1.2147 -			if (*end == '\0')
  1.2148 -			{
  1.2149 -				pl = GetPluginByOrder(id);
  1.2150 -				if (!pl)
  1.2151 -				{
  1.2152 -					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
  1.2153 -					return;
  1.2154 -				}
  1.2155 -			}
  1.2156 -			else
  1.2157 -			{
  1.2158 -				char pluginfile[256];
  1.2159 -				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
  1.2160 -				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
  1.2161 -
  1.2162 -				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
  1.2163 -				{
  1.2164 -					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
  1.2165 -					return;
  1.2166 -				}
  1.2167 -			}
  1.2168 -
  1.2169 -			char name[PLATFORM_MAX_PATH];
  1.2170 -			const sm_plugininfo_t *info = pl->GetPublicInfo();
  1.2171 -			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
  1.2172 -
  1.2173 -			if (UnloadPlugin(pl))
  1.2174 -			{
  1.2175 -				g_RootMenu.ConsolePrint("[SM] Plugin %s unloaded successfully.", name);
  1.2176 -			}
  1.2177 -			else
  1.2178 -			{
  1.2179 -				g_RootMenu.ConsolePrint("[SM] Failed to unload plugin %s.", name);
  1.2180 -			}
  1.2181 -
  1.2182 -			return;
  1.2183 -		}
  1.2184 -		else if (strcmp(cmd, "unload_all") == 0)
  1.2185 -		{
  1.2186 -			g_PluginSys.UnloadAll();
  1.2187 -			g_RootMenu.ConsolePrint("[SM] All plugins have been unloaded.");
  1.2188 -			return;
  1.2189 -		}
  1.2190 -		else if (strcmp(cmd, "load_lock") == 0)
  1.2191 -		{
  1.2192 -			if (m_LoadingLocked)
  1.2193 -			{
  1.2194 -				g_RootMenu.ConsolePrint("[SM] There is already a loading lock in effect.");
  1.2195 -			}
  1.2196 -			else
  1.2197 -			{
  1.2198 -				m_LoadingLocked = true;
  1.2199 -				g_RootMenu.ConsolePrint("[SM] Loading is now locked; no plugins will be loaded or re-loaded.");
  1.2200 -			}
  1.2201 -			return;
  1.2202 -		}
  1.2203 -		else if (strcmp(cmd, "load_unlock") == 0)
  1.2204 -		{
  1.2205 -			if (m_LoadingLocked)
  1.2206 -			{
  1.2207 -				m_LoadingLocked = false;
  1.2208 -				g_RootMenu.ConsolePrint("[SM] The loading lock is no longer in effect.");
  1.2209 -			}
  1.2210 -			else
  1.2211 -			{
  1.2212 -				g_RootMenu.ConsolePrint("[SM] There was no loading lock in effect.");
  1.2213 -			}
  1.2214 -			return;
  1.2215 -		}
  1.2216 -		else if (strcmp(cmd, "info") == 0)
  1.2217 -		{
  1.2218 -			if (argcount < 4)
  1.2219 -			{
  1.2220 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins info <#>");
  1.2221 -				return;
  1.2222 -			}
  1.2223 -
  1.2224 -			int num = atoi(command.Arg(3));
  1.2225 -			if (num < 1 || num > (int)GetPluginCount())
  1.2226 -			{
  1.2227 -				g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
  1.2228 -				return;
  1.2229 -			}
  1.2230 -
  1.2231 -			CPlugin *pl = GetPluginByOrder(num);
  1.2232 -			const sm_plugininfo_t *info = pl->GetPublicInfo();
  1.2233 -
  1.2234 -			g_RootMenu.ConsolePrint("  Filename: %s", pl->GetFilename());
  1.2235 -			if (pl->GetStatus() <= Plugin_Error)
  1.2236 -			{
  1.2237 -				if (IS_STR_FILLED(info->name))
  1.2238 -				{
  1.2239 -					if (IS_STR_FILLED(info->description))
  1.2240 -					{
  1.2241 -						g_RootMenu.ConsolePrint("  Title: %s (%s)", info->name, info->description);
  1.2242 -					} else {
  1.2243 -						g_RootMenu.ConsolePrint("  Title: %s", info->name);
  1.2244 -					}
  1.2245 -				}
  1.2246 -				if (IS_STR_FILLED(info->author))
  1.2247 -				{
  1.2248 -					g_RootMenu.ConsolePrint("  Author: %s", info->author);
  1.2249 -				}
  1.2250 -				if (IS_STR_FILLED(info->version))
  1.2251 -				{
  1.2252 -					g_RootMenu.ConsolePrint("  Version: %s", info->version);
  1.2253 -				}
  1.2254 -				if (IS_STR_FILLED(info->url))
  1.2255 -				{
  1.2256 -					g_RootMenu.ConsolePrint("  URL: %s", info->url);
  1.2257 -				}
  1.2258 -				if (pl->GetStatus() == Plugin_Error)
  1.2259 -				{
  1.2260 -					g_RootMenu.ConsolePrint("  Error: %s", pl->m_errormsg);
  1.2261 -				}
  1.2262 -				else
  1.2263 -				{
  1.2264 -					g_RootMenu.ConsolePrint("  Debugging: %s", pl->IsDebugging() ? "Yes" : "No");
  1.2265 -					g_RootMenu.ConsolePrint("  Running: %s", pl->GetStatus() == Plugin_Running ? "Yes" : "No");
  1.2266 -
  1.2267 -					const char *typestr = "";
  1.2268 -					switch (pl->GetType())
  1.2269 -					{
  1.2270 -					case PluginType_MapUpdated:
  1.2271 -						typestr = "Map Change if Updated";
  1.2272 -						break;
  1.2273 -					case PluginType_MapOnly:
  1.2274 -						typestr = "Map Change";
  1.2275 -						break;
  1.2276 -					case PluginType_Private:
  1.2277 -					case PluginType_Global:
  1.2278 -						typestr = "Never";
  1.2279 -						break;
  1.2280 -					}
  1.2281 -
  1.2282 -					g_RootMenu.ConsolePrint("  Reloads: %s", typestr);
  1.2283 -				}
  1.2284 -			}
  1.2285 -			else
  1.2286 -			{
  1.2287 -				g_RootMenu.ConsolePrint("  Load error: %s", pl->m_errormsg);
  1.2288 -				g_RootMenu.ConsolePrint("  File info: (title \"%s\") (version \"%s\")", 
  1.2289 -										info->name ? info->name : "<none>",
  1.2290 -										info->version ? info->version : "<none>");
  1.2291 -				if (IS_STR_FILLED(info->url))
  1.2292 -				{
  1.2293 -					g_RootMenu.ConsolePrint("  File URL: %s", info->url);
  1.2294 -				}
  1.2295 -			}
  1.2296 -
  1.2297 -			return;
  1.2298 -		}
  1.2299 -		else if (strcmp(cmd, "debug") == 0)
  1.2300 -		{
  1.2301 -			if (argcount < 5)
  1.2302 -			{
  1.2303 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins debug <#> [on|off]");
  1.2304 -				return;
  1.2305 -			}
  1.2306 -
  1.2307 -			int num = atoi(command.Arg(3));
  1.2308 -			if (num < 1 || num > (int)GetPluginCount())
  1.2309 -			{
  1.2310 -				g_RootMenu.ConsolePrint("[SM] Plugin index not found.");
  1.2311 -				return;
  1.2312 -			}
  1.2313 -
  1.2314 -			int res;
  1.2315 -			const char *mode = command.Arg(4);
  1.2316 -			if ((res=strcmp("on", mode)) && strcmp("off", mode))
  1.2317 -			{
  1.2318 -				g_RootMenu.ConsolePrint("[SM] The only possible options are \"on\" and \"off.\"");
  1.2319 -				return;
  1.2320 -			}
  1.2321 -
  1.2322 -			bool debug;
  1.2323 -			if (!res)
  1.2324 -			{
  1.2325 -				debug = true;
  1.2326 -			}
  1.2327 -			else
  1.2328 -			{
  1.2329 -				debug = false;
  1.2330 -			}
  1.2331 -
  1.2332 -			CPlugin *pl = GetPluginByOrder(num);
  1.2333 -			if (debug && pl->IsDebugging())
  1.2334 -			{
  1.2335 -				g_RootMenu.ConsolePrint("[SM] This plugin is already in debug mode.");
  1.2336 -				return;
  1.2337 -			}
  1.2338 -			else if (!debug && !pl->IsDebugging())
  1.2339 -			{
  1.2340 -				g_RootMenu.ConsolePrint("[SM] Debug mode is already disabled in this plugin.");
  1.2341 -				return;
  1.2342 -			}
  1.2343 -
  1.2344 -			char error[256];
  1.2345 -			if (pl->ToggleDebugMode(debug, error, sizeof(error)))
  1.2346 -			{
  1.2347 -				g_RootMenu.ConsolePrint("[SM] Successfully toggled debug mode on plugin %s.", pl->GetFilename());
  1.2348 -				return;
  1.2349 -			}
  1.2350 -			else
  1.2351 -			{
  1.2352 -				g_RootMenu.ConsolePrint("[SM] Could not toggle debug mode on plugin %s.", pl->GetFilename());
  1.2353 -				g_RootMenu.ConsolePrint("[SM] Plugin returned error: %s", error);
  1.2354 -				return;
  1.2355 -			}
  1.2356 -		}
  1.2357 -		else if (strcmp(cmd, "refresh") == 0)
  1.2358 -		{
  1.2359 -			g_SourceMod.DoGlobalPluginLoads();
  1.2360 -			g_RootMenu.ConsolePrint("[SM] The plugin list has been refreshed and reloaded.");
  1.2361 -			return;
  1.2362 -		}
  1.2363 -		else if (strcmp(cmd, "reload") == 0)
  1.2364 -		{
  1.2365 -			if (argcount < 4)
  1.2366 -			{
  1.2367 -				g_RootMenu.ConsolePrint("[SM] Usage: sm plugins reload <#|file>");
  1.2368 -				return;
  1.2369 -			}
  1.2370 -
  1.2371 -			CPlugin *pl;
  1.2372 -			char *end;
  1.2373 -			const char *arg = command.Arg(3);
  1.2374 -			int id = strtol(arg, &end, 10);
  1.2375 -
  1.2376 -			if (*end == '\0')
  1.2377 -			{
  1.2378 -				pl = GetPluginByOrder(id);
  1.2379 -				if (!pl)
  1.2380 -				{
  1.2381 -					g_RootMenu.ConsolePrint("[SM] Plugin index %d not found.", id);
  1.2382 -					return;
  1.2383 -				}
  1.2384 -			}
  1.2385 -			else
  1.2386 -			{
  1.2387 -				char pluginfile[256];
  1.2388 -				const char *ext = g_LibSys.GetFileExtension(arg) ? "" : ".smx";
  1.2389 -				UTIL_Format(pluginfile, sizeof(pluginfile), "%s%s", arg, ext);
  1.2390 -
  1.2391 -				if (!sm_trie_retrieve(m_LoadLookup, pluginfile, (void **)&pl))
  1.2392 -				{
  1.2393 -					g_RootMenu.ConsolePrint("[SM] Plugin %s is not loaded.", pluginfile);
  1.2394 -					return;
  1.2395 -				}
  1.2396 -			}
  1.2397 -
  1.2398 -			char name[PLATFORM_MAX_PATH];
  1.2399 -			const sm_plugininfo_t *info = pl->GetPublicInfo();
  1.2400 -			strcpy(name, (IS_STR_FILLED(info->name)) ? info->name : pl->GetFilename());
  1.2401 -
  1.2402 -			if (ReloadPlugin(pl))
  1.2403 -			{
  1.2404 -				g_RootMenu.ConsolePrint("[SM] Plugin %s reloaded successfully.", name);
  1.2405 -			}
  1.2406 -			else
  1.2407 -			{
  1.2408 -				g_RootMenu.ConsolePrint("[SM] Failed to reload plugin %s.", name);
  1.2409 -			}
  1.2410 -
  1.2411 -			return;
  1.2412 -		}
  1.2413 -	}
  1.2414 -
  1.2415 -	/* Draw the main menu */
  1.2416 -	g_RootMenu.ConsolePrint("SourceMod Plugins Menu:");
  1.2417 -	g_RootMenu.DrawGenericOption("debug", "Toggle debug mode on a plugin");
  1.2418 -	g_RootMenu.DrawGenericOption("info", "Information about a plugin");
  1.2419 -	g_RootMenu.DrawGenericOption("list", "Show loaded plugins");
  1.2420 -	g_RootMenu.DrawGenericOption("load", "Load a plugin");
  1.2421 -	g_RootMenu.DrawGenericOption("load_lock", "Prevents any more plugins from being loaded");
  1.2422 -	g_RootMenu.DrawGenericOption("load_unlock", "Re-enables plugin loading");
  1.2423 -	g_RootMenu.DrawGenericOption("refresh", "Reloads/refreshes all plugins in the plugins folder");
  1.2424 -	g_RootMenu.DrawGenericOption("reload", "Reloads a plugin");
  1.2425 -	g_RootMenu.DrawGenericOption("unload", "Unload a plugin");
  1.2426 -	g_RootMenu.DrawGenericOption("unload_all", "Unloads all plugins");
  1.2427 -}
  1.2428 -
  1.2429 -bool CPluginManager::ReloadPlugin(CPlugin *pl)
  1.2430 -{
  1.2431 -	List<CPlugin *>::iterator iter;
  1.2432 -	char filename[PLATFORM_MAX_PATH];
  1.2433 -	bool debug, wasloaded;
  1.2434 -	PluginType ptype;
  1.2435 -	IPlugin *newpl;
  1.2436 -	int id = 1;
  1.2437 -
  1.2438 -	strcpy(filename, pl->m_filename);
  1.2439 -	debug = pl->IsDebugging();
  1.2440 -	ptype = pl->GetType();
  1.2441 -
  1.2442 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++, id++)
  1.2443 -	{
  1.2444 -		if ((*iter) == pl)
  1.2445 -		{
  1.2446 -			break;
  1.2447 -		}
  1.2448 -	}
  1.2449 -
  1.2450 -	if (!UnloadPlugin(pl))
  1.2451 -	{
  1.2452 -		return false;
  1.2453 -	}
  1.2454 -	if (!(newpl=LoadPlugin(filename, debug, ptype, NULL, 0, &wasloaded)))
  1.2455 -	{
  1.2456 -		return false;
  1.2457 -	}
  1.2458 -
  1.2459 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
  1.2460 -	{
  1.2461 -		if ((*iter) == (CPlugin *)newpl)
  1.2462 -		{
  1.2463 -			m_plugins.erase(iter);
  1.2464 -			break;
  1.2465 -		}
  1.2466 -	}
  1.2467 -
  1.2468 -	int i;
  1.2469 -	for (i=1, iter=m_plugins.begin(); iter!=m_plugins.end() && i<id; iter++, i++)
  1.2470 -	{
  1.2471 -	}
  1.2472 -	m_plugins.insert(iter, (CPlugin *)newpl);
  1.2473 -
  1.2474 -	return true;
  1.2475 -}
  1.2476 -
  1.2477 -void CPluginManager::ReloadOrUnloadPlugins()
  1.2478 -{
  1.2479 -	/* If we're in a load lock, just skip this whole bit. */
  1.2480 -	if (m_LoadingLocked)
  1.2481 -	{
  1.2482 -		return;
  1.2483 -	}
  1.2484 -
  1.2485 -	List<CPlugin *>::iterator iter;
  1.2486 -	List<CPlugin *> tmp_list = m_plugins;
  1.2487 -	CPlugin *pl;
  1.2488 -	time_t t;
  1.2489 -
  1.2490 -	for (iter=tmp_list.begin(); iter!=tmp_list.end(); iter++)
  1.2491 -	{
  1.2492 -		pl = (*iter);
  1.2493 -		if (pl->GetType() ==  PluginType_MapOnly)
  1.2494 -		{
  1.2495 -			UnloadPlugin((IPlugin *)pl);
  1.2496 -		}
  1.2497 -		else if (pl->GetType() == PluginType_MapUpdated)
  1.2498 -		{
  1.2499 -			t = pl->GetFileTimeStamp();
  1.2500 -			if (!t || t > pl->GetTimeStamp())
  1.2501 -			{
  1.2502 -				pl->SetTimeStamp(t);
  1.2503 -				UnloadPlugin((IPlugin *)pl);
  1.2504 -			}
  1.2505 -		}
  1.2506 -	}
  1.2507 -}
  1.2508 -
  1.2509 -void CPluginManager::_SetPauseState(CPlugin *pl, bool paused)
  1.2510 -{
  1.2511 -	List<IPluginsListener *>::iterator iter;
  1.2512 -	IPluginsListener *pListener;
  1.2513 -	for (iter=m_listeners.begin(); iter!=m_listeners.end(); iter++)
  1.2514 -	{
  1.2515 -		pListener = (*iter);
  1.2516 -		pListener->OnPluginPauseChange(pl, paused);
  1.2517 -	}	
  1.2518 -}
  1.2519 -
  1.2520 -bool CPluginManager::AddFakeNative(IPluginFunction *pFunction, const char *name, SPVM_FAKENATIVE_FUNC func)
  1.2521 -{
  1.2522 -	if (sm_trie_retrieve(m_pNativeLookup, name, NULL))
  1.2523 -	{
  1.2524 -		return false;
  1.2525 -	}
  1.2526 -
  1.2527 -	FakeNative *pNative = new FakeNative;
  1.2528 -
  1.2529 -	pNative->func = g_pVM->CreateFakeNative(func, pNative);
  1.2530 -	if (!pNative->func)
  1.2531 -	{
  1.2532 -		delete pNative;
  1.2533 -		return false;
  1.2534 -	}
  1.2535 -
  1.2536 -	pNative->call = pFunction;
  1.2537 -	pNative->name.assign(name);
  1.2538 -	pNative->ctx = pFunction->GetParentContext();
  1.2539 -
  1.2540 -	m_Natives.push_back(pNative);
  1.2541 -	sm_trie_insert(m_pNativeLookup, name,pNative);
  1.2542 -
  1.2543 -	CPlugin *pPlugin = GetPluginByCtx(pNative->ctx->GetContext());
  1.2544 -	pPlugin->m_fakeNatives.push_back(pNative);
  1.2545 -
  1.2546 -	return true;
  1.2547 -}
  1.2548 -
  1.2549 -void CPluginManager::AddFunctionsToForward(const char *name, IChangeableForward *pForward)
  1.2550 -{
  1.2551 -	List<CPlugin *>::iterator iter;
  1.2552 -	CPlugin *pPlugin;
  1.2553 -	IPluginFunction *pFunction;
  1.2554 -
  1.2555 -	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++)
  1.2556 -	{
  1.2557 -		pPlugin = (*iter);
  1.2558 -
  1.2559 -		if (pPlugin->GetStatus() <= Plugin_Paused)
  1.2560 -		{
  1.2561 -			pFunction = pPlugin->GetBaseContext()->GetFunctionByName(name);
  1.2562 -
  1.2563 -			if (pFunction)
  1.2564 -			{
  1.2565 -				pForward->AddFunction(pFunction);
  1.2566 -			}
  1.2567 -		}
  1.2568 -	}
  1.2569 -}
  1.2570 -
  1.2571 -CPlugin *CPluginManager::GetPluginFromIdentity(IdentityToken_t *pToken)
  1.2572 -{
  1.2573 -	if (pToken->type != g_PluginIdent)
  1.2574 -	{
  1.2575 -		return NULL;
  1.2576 -	}
  1.2577 -
  1.2578 -	return (CPlugin *)(pToken->ptr);
  1.2579 -}
  1.2580 -
  1.2581 -void CPluginManager::OnLibraryAction(const char *lib, bool is_a_plugin, bool drop)
  1.2582 -{
  1.2583 -	List<CPlugin *>::iterator iter;
  1.2584 -
  1.2585 -	struct _pl
  1.2586 -	{
  1.2587 -		cell_t name;
  1.2588 -		cell_t file;
  1.2589 -		cell_t required;
  1.2590 -	} *plc;
  1.2591 -
  1.2592 -	struct _ext
  1.2593 -	{
  1.2594 -		cell_t name;
  1.2595 -		cell_t file;
  1.2596 -		cell_t autoload;
  1.2597 -		cell_t required;
  1.2598 -	} *ext;
  1.2599 -
  1.2600 -	const char *name = drop ? "OnLibraryRemoved" : "OnLibraryAdded";
  1.2601 -
  1.2602 -	for (iter=m_plugins.begin();
  1.2603 -		 iter!=m_plugins.end();
  1.2604 -		 iter++)
  1.2605 -	{
  1.2606 -		CPlugin *pl = (*iter);
  1.2607 -		if (pl->GetStatus() != Plugin_Running)
  1.2608 -		{
  1.2609 -			continue;
  1.2610 -		}
  1.2611 -		IPluginContext *pContext = pl->GetBaseContext();
  1.2612 -		IPluginFunction *pf = pContext->GetFunctionByName(name);
  1.2613 -		if (!pf)
  1.2614 -		{
  1.2615 -			continue;
  1.2616 -		}
  1.2617 -		uint32_t num_vars = pContext->GetPubVarsNum();
  1.2618 -		for (uint32_t i=0; i<num_vars; i++)
  1.2619 -		{
  1.2620 -			sp_pubvar_t *pubvar;
  1.2621 -			if (pContext->GetPubvarByIndex(i, &pubvar) != SP_ERROR_NONE)
  1.2622 -			{
  1.2623 -				continue;
  1.2624 -			}
  1.2625 -			if (is_a_plugin && strncmp(pubvar->name, "__pl_", 5) == 0)
  1.2626 -			{
  1.2627 -				plc = (_pl *)pubvar->offs;
  1.2628 -				if (plc->required)
  1.2629 -				{
  1.2630 -					continue;
  1.2631 -				}
  1.2632 -				char *str;
  1.2633 -				pContext->LocalToString(plc->name, &str);
  1.2634 -				if (strcmp(str, lib) != 0)
  1.2635 -				{
  1.2636 -					continue;
  1.2637 -				}
  1.2638 -				pf->PushString(lib);
  1.2639 -				pf->Execute(NULL);
  1.2640 -			}
  1.2641 -			else if (!is_a_plugin && strncmp(pubvar->name, "__ext_", 6) == 0)
  1.2642 -			{
  1.2643 -				ext = (_ext *)pubvar->offs;
  1.2644 -				if (ext->required)
  1.2645 -				{
  1.2646 -					continue;
  1.2647 -				}
  1.2648 -				char *str;
  1.2649 -				pContext->LocalToString(ext->name, &str);
  1.2650 -				if (strcmp(str, lib) != 0)
  1.2651 -				{
  1.2652 -					continue;
  1.2653 -				}
  1.2654 -				pf->PushString(lib);
  1.2655 -				pf->Execute(NULL);
  1.2656 -			}
  1.2657 -		}
  1.2658 -	}
  1.2659 -}
  1.2660 -
  1.2661 -bool CPluginManager::LibraryExists(const char *lib)
  1.2662 -{
  1.2663 -	List<CPlugin *>::iterator iter;
  1.2664 -
  1.2665 -	for (iter=m_plugins.begin();
  1.2666 -		 iter!=m_plugins.end();
  1.2667 -		 iter++)
  1.2668 -	{
  1.2669 -		CPlugin *pl = (*iter);
  1.2670 -		if (pl->GetStatus() != Plugin_Running)
  1.2671 -		{
  1.2672 -			continue;
  1.2673 -		}
  1.2674 -		List<String>::iterator s_iter;
  1.2675 -		for (s_iter = pl->m_Libraries.begin();
  1.2676 -			 s_iter != pl->m_Libraries.end();
  1.2677 -			 s_iter++)
  1.2678 -		{
  1.2679 -			if ((*s_iter).compare(lib) == 0)
  1.2680 -			{
  1.2681 -				return true;
  1.2682 -			}
  1.2683 -		}
  1.2684 -	}
  1.2685 -
  1.2686 -	return false;
  1.2687 -}
  1.2688 -
  1.2689 -void CPluginManager::AllPluginsLoaded()
  1.2690 -{
  1.2691 -	List<CPlugin *>::iterator iter;
  1.2692 -	CPlugin *pl;
  1.2693 -
  1.2694 -	for (iter=m_plugins.begin(); iter!=m_plugins.end(); iter++)
  1.2695 -	{
  1.2696 -		pl = (*iter);
  1.2697 -		pl->Call_OnAllPluginsLoaded();
  1.2698 -	}
  1.2699 -}
  1.2700 -
  1.2701 -void CPluginManager::UnloadAll()
  1.2702 -{
  1.2703 -	List<CPlugin *>::iterator iter;
  1.2704 -	while ( (iter = m_plugins.begin()) != m_plugins.end() )
  1.2705 -	{
  1.2706 -		UnloadPlugin((*iter));
  1.2707 -	}
  1.2708 -}
  1.2709 -
  1.2710 -int CPluginManager::GetOrderOfPlugin(IPlugin *pl)
  1.2711 -{
  1.2712 -	int id = 1;
  1.2713 -	List<CPlugin *>::iterator iter;
  1.2714 -
  1.2715 -	for (iter = m_plugins.begin(); iter != m_plugins.end(); iter++, id++)
  1.2716 -	{
  1.2717 -		if ((*iter) == pl)
  1.2718 -		{
  1.2719 -			return id;
  1.2720 -		}
  1.2721 -	}
  1.2722 -
  1.2723 -	return -1;
  1.2724 -}
  1.2725 -