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