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