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