core/sourcemod.cpp
author Scott Ehlert <ds@alliedmods.net>
Wed Aug 15 06:19:30 2007 +0000 (2007-08-15)
changeset 1330 ab94316bb52b
parent 1231 17badaf66ce4
child 1338 1ba17552b7b1
permissions -rw-r--r--
Updated license headers on virtually all files with extremely minor changes in the name of some sort of strange consistency.
All plugin and include file headers also have been changed to say about GPL3 instead of GPL2.

(This day shall henceforth be known as the Eighty Column Massacre of '07)
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2007 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <stdio.h>
    33 #include "sourcemod.h"
    34 #include "sourcemm_api.h"
    35 #include "systems/LibrarySys.h"
    36 #include "vm/sp_vm_engine.h"
    37 #include <sh_string.h>
    38 #include "PluginSys.h"
    39 #include "ShareSys.h"
    40 #include "CoreConfig.h"
    41 #include "Logger.h"
    42 #include "ExtensionSys.h"
    43 #include "AdminCache.h"
    44 #include "sm_stringutil.h"
    45 #include "PlayerManager.h"
    46 #include "Translator.h"
    47 #include "ForwardSys.h"
    48 #include "TimerSys.h"
    49 #include "MenuStyle_Valve.h"
    50 #include "MenuStyle_Radio.h"
    51 #include "Database.h"
    52 
    53 SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool);
    54 SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false);
    55 SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool);
    56 SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *);
    57 
    58 SourcePawnEngine g_SourcePawn;
    59 SourceModBase g_SourceMod;
    60 
    61 ILibrary *g_pJIT = NULL;
    62 SourceHook::String g_BaseDir;
    63 ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn;
    64 IVirtualMachine *g_pVM;
    65 IdentityToken_t *g_pCoreIdent = NULL;
    66 float g_LastTime = 0.0f;
    67 float g_LastMenuTime = 0.0f;
    68 float g_LastAuthCheck = 0.0f;
    69 IForward *g_pOnGameFrame = NULL;
    70 IForward *g_pOnMapEnd = NULL;
    71 bool g_Loaded = false;
    72 int g_StillFrames = 0;
    73 float g_StillTime = 0.0f;
    74 
    75 typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *);
    76 typedef int (*GIVEENGINEPOINTER2)(ISourcePawnEngine *, unsigned int api_version);
    77 typedef unsigned int (*GETEXPORTCOUNT)();
    78 typedef IVirtualMachine *(*GETEXPORT)(unsigned int);
    79 typedef void (*NOTIFYSHUTDOWN)();
    80 
    81 void ShutdownJIT()
    82 {
    83 	NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown");
    84 	if (notify)
    85 	{
    86 		notify();
    87 	}
    88 
    89 	g_pJIT->CloseLibrary();
    90 }
    91 
    92 SourceModBase::SourceModBase()
    93 {
    94 	m_IsMapLoading = false;
    95 	m_ExecPluginReload = false;
    96 	m_ExecOnMapEnd = false;
    97 	m_GotBasePath = false;
    98 }
    99 
   100 ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, 
   101 									  const char *value, 
   102 									  ConfigSource source, 
   103 									  char *error, 
   104 									  size_t maxlength)
   105 {
   106 	if (strcasecmp(key, "BasePath") == 0)
   107 	{
   108 		if (source == ConfigSource_Console)
   109 		{
   110 			UTIL_Format(error, maxlength, "Cannot be set at runtime");
   111 			return ConfigResult_Reject;
   112 		}
   113 
   114 		if (!m_GotBasePath)
   115 		{
   116 			g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), value);
   117 			g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), value);
   118 
   119 			m_GotBasePath = true;
   120 		}
   121 
   122 		return ConfigResult_Accept;
   123 	}
   124 
   125 	return ConfigResult_Ignore;
   126 }
   127 
   128 bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late)
   129 {
   130 	const char *gamepath = g_SMAPI->GetBaseDir();
   131 
   132 	/* Store full path to game */
   133 	g_BaseDir.assign(gamepath);
   134 
   135 	/* Store name of game directory by itself */
   136 	size_t len = strlen(gamepath);
   137 	for (size_t i = len - 1; i >= 0; i--)
   138 	{
   139 		if (gamepath[i] == PLATFORM_SEP_CHAR)
   140 		{
   141 			strncopy(m_ModDir, &gamepath[++i], sizeof(m_ModDir));
   142 			break;
   143 		}
   144 	}
   145 
   146 	/* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */
   147 	g_CoreConfig.Initialize();
   148 
   149 	/* This shouldn't happen, but can't hurt to be safe */
   150 	if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath)
   151 	{
   152 		g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str());
   153 		g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod");
   154 		m_GotBasePath = true;
   155 	}
   156 
   157 	/* Attempt to load the JIT! */
   158 	char file[PLATFORM_MAX_PATH];
   159 	char myerror[255];
   160 	g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s",
   161 		GetSourceModPath(),
   162 		PLATFORM_LIB_EXT
   163 		);
   164 
   165 	g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror));
   166 	if (!g_pJIT)
   167 	{
   168 		if (error && maxlength)
   169 		{
   170 			snprintf(error, maxlength, "%s (failed to load bin/sourcepawn.jit.x86.%s)", 
   171 				myerror,
   172 				PLATFORM_LIB_EXT);
   173 		}
   174 		return false;
   175 	}
   176 
   177 	int err;
   178 	
   179 	GIVEENGINEPOINTER2 jit_init2 = (GIVEENGINEPOINTER2)g_pJIT->GetSymbolAddress("GiveEnginePointer2");
   180 	if (!jit_init2)
   181 	{
   182 		GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer");
   183 		if (!jit_init)
   184 		{
   185 			ShutdownJIT();
   186 			if (error && maxlength)
   187 			{
   188 				snprintf(error, maxlength, "Failed to find GiveEnginePointer in JIT!");
   189 			}
   190 			return false;
   191 		}
   192 
   193 		if ((err=jit_init(g_pSourcePawn)) != 0)
   194 		{
   195 			ShutdownJIT();
   196 			if (error && maxlength)
   197 			{
   198 				snprintf(error, maxlength, "GiveEnginePointer returned %d in the JIT", err);
   199 			}
   200 			return false;
   201 		}
   202 	} else {
   203 		/* On version bumps, we should check for older versions as well, if the new version fails.
   204 		 * We can then check the exports to see if any VM versions will be sufficient.
   205 		 */
   206 		if ((err=jit_init2(g_pSourcePawn, SOURCEPAWN_ENGINE_API_VERSION)) != SP_ERROR_NONE)
   207 		{
   208 			ShutdownJIT();
   209 			if (error && maxlength)
   210 			{
   211 				snprintf(error, maxlength, "JIT incompatible with SourceMod version");
   212 			}
   213 			return false;
   214 		}
   215 	}
   216 
   217 	GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount");
   218 	GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport");
   219 	if (!jit_get)
   220 	{
   221 		ShutdownJIT();
   222 		if (error && maxlength)
   223 		{
   224 			snprintf(error, maxlength, "JIT is missing a necessary export!");
   225 		}
   226 		return false;
   227 	}
   228 
   229 	unsigned int num = jit_getnum();
   230 	if (!num)
   231 	{
   232 		ShutdownJIT();
   233 		if (error && maxlength)
   234 		{
   235 			snprintf(error, maxlength, "JIT did not export any virtual machines!");
   236 		}
   237 		return false;
   238 	}
   239 
   240 	unsigned int api_version;
   241 	for (unsigned int i=0; i<num; i++)
   242 	{
   243 		 if ((g_pVM=jit_get(i)) == NULL)
   244 		 {
   245 			 if (error && maxlength)
   246 			 {
   247 				 snprintf(error, maxlength, "JIT did not export any virtual machines!");
   248 			 }
   249 			 continue;
   250 		 }
   251 		/* Refuse any API that we might not be able to deal with.
   252 		 * Also refuse anything < 3 because we need fake natives.
   253 		 */
   254 		 api_version = g_pVM->GetAPIVersion();
   255 		 if (api_version < 3 || api_version > SOURCEPAWN_VM_API_VERSION)
   256 		 {
   257 			 if (error && maxlength)
   258 			 {
   259 				 snprintf(error, maxlength, "JIT is not a compatible version");
   260 			 }
   261 			 g_pVM = NULL;
   262 			 continue;
   263 		 }
   264 		 break;
   265 	}
   266 
   267 	if (!g_pVM)
   268 	{
   269 		ShutdownJIT();
   270 		return false;
   271 	}
   272 
   273 	/* Hook this now so we can detect startup without calling StartSourceMod() */
   274 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
   275 
   276 	/* Only load if we're not late */
   277 	if (!late)
   278 	{
   279 		StartSourceMod(false);
   280 	}
   281 
   282 	return true;
   283 }
   284 
   285 void SourceModBase::StartSourceMod(bool late)
   286 {
   287 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
   288 	SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false);
   289 
   290 	enginePatch = SH_GET_CALLCLASS(engine);
   291 	gamedllPatch = SH_GET_CALLCLASS(gamedll);
   292 
   293 	/* Notify! */
   294 	SMGlobalClass *pBase = SMGlobalClass::head;
   295 	while (pBase)
   296 	{
   297 		pBase->OnSourceModStartup(false);
   298 		pBase = pBase->m_pGlobalClassNext;
   299 	}
   300 
   301 	/* Make the global core identity */
   302 	g_pCoreIdent = g_ShareSys.CreateCoreIdentity();
   303 
   304 	/* Notify! */
   305 	pBase = SMGlobalClass::head;
   306 	while (pBase)
   307 	{
   308 		pBase->OnSourceModAllInitialized();
   309 		pBase = pBase->m_pGlobalClassNext;
   310 	}
   311 
   312 	/* Add us now... */
   313 	g_ShareSys.AddInterface(NULL, this);
   314 
   315 	/* We're loaded! */
   316 	g_Loaded = true;
   317 }
   318 
   319 static bool g_LevelEndBarrier = false;
   320 bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background)
   321 {
   322 	/* If we're not loaded... */
   323 	if (!g_Loaded)
   324 	{
   325 		/* Do all global initialization now */
   326 		StartSourceMod(true);
   327 	}
   328 
   329 	m_IsMapLoading = true;
   330 	m_ExecPluginReload = true;
   331 	m_ExecOnMapEnd = true;
   332 	g_LastTime = 0.0f;
   333 	g_LastMenuTime = 0.0f;
   334 	g_LastAuthCheck = 0.0f;
   335 	g_SimTicks.ticking = true;
   336 	g_SimTicks.tickcount = 0;
   337 	g_StillTime = 0.0f;
   338 	g_StillFrames = 0;
   339 
   340 	/* Notify! */
   341 	SMGlobalClass *pBase = SMGlobalClass::head;
   342 	while (pBase)
   343 	{
   344 		pBase->OnSourceModLevelChange(pMapName);
   345 		pBase = pBase->m_pGlobalClassNext;
   346 	}
   347 
   348 	DoGlobalPluginLoads();
   349 
   350 	m_IsMapLoading = false;
   351 
   352 	/* Notify! */
   353 	pBase = SMGlobalClass::head;
   354 	while (pBase)
   355 	{
   356 		pBase->OnSourceModPluginsLoaded();
   357 		pBase = pBase->m_pGlobalClassNext;
   358 	}
   359 
   360 	if (!g_pOnGameFrame)
   361 	{
   362 		g_pOnGameFrame = g_Forwards.CreateForward("OnGameFrame", ET_Ignore, 0, NULL);
   363 	}
   364 
   365 	if (!g_pOnMapEnd)
   366 	{
   367 		g_pOnMapEnd = g_Forwards.CreateForward("OnMapEnd", ET_Ignore, 0, NULL);
   368 	}
   369 
   370 	g_LevelEndBarrier = true;
   371 
   372 	RETURN_META_VALUE(MRES_IGNORED, true);
   373 }
   374 
   375 void StartTickSimulation()
   376 {
   377 	g_SimTicks.ticking = false;
   378 	g_SimTicks.tickcount = 0;
   379 	g_SimTicks.ticktime = gpGlobals->curtime;
   380 }
   381 
   382 void StopTickSimulation()
   383 {
   384 	g_SimTicks.ticking = true;
   385 	g_Timers.MapChange(false);
   386 	g_StillFrames = 0;
   387 	g_LastTime = gpGlobals->curtime;
   388 }
   389 
   390 void SimulateTick()
   391 {
   392 	g_SimTicks.tickcount++;
   393 	g_SimTicks.ticktime = g_StillTime + (g_SimTicks.tickcount * gpGlobals->interval_per_tick);
   394 }
   395 
   396 void SourceModBase::GameFrame(bool simulating)
   397 {
   398 	g_DBMan.RunFrame();
   399 
   400 	/**
   401 	 * Note: This is all hardcoded rather than delegated to save
   402 	 * precious CPU cycles.
   403 	 */
   404 	float curtime = gpGlobals->curtime;
   405 	int framecount = gpGlobals->framecount;
   406 
   407 	/* Verify that we're still ticking */
   408 	if (g_SimTicks.ticking)
   409 	{
   410 		if (g_StillFrames == 0)
   411 		{
   412 			g_StillFrames = framecount;
   413 			g_StillTime = curtime;
   414 		} else {
   415 			/* Try to detect when we've stopped ticking.
   416 			 * We do this once 10 frames pass and there have been no ticks.
   417 			 */
   418 			if (g_StillTime == curtime)
   419 			{
   420 				if (framecount - g_StillFrames >= 5)
   421 				{
   422 					StartTickSimulation();
   423 					return;
   424 				}
   425 			} else {
   426 				/* We're definitely ticking we get here, 
   427 				 * but update everything as a precaution */
   428 				g_StillFrames = framecount;
   429 				g_StillTime = curtime;
   430 			}
   431 		}
   432 	} else {
   433 		/* We need to make sure we should still be simulating. */
   434 		if (g_StillTime != curtime)
   435 		{
   436 			/* Wow, we're ticking again! It's time to revert. */
   437 			StopTickSimulation();
   438 			return;
   439 		}
   440 		/* Nope, not ticking.  Simulate! */
   441 		SimulateTick();
   442 		curtime = g_SimTicks.ticktime;
   443 	}
   444 
   445 	if (curtime - g_LastTime >= 0.1f)
   446 	{
   447 		if (m_CheckingAuth
   448 			&& (gpGlobals->curtime - g_LastAuthCheck > 0.7f))
   449 		{
   450 			g_LastAuthCheck = gpGlobals->curtime;
   451 			g_Players.RunAuthChecks();
   452 		}
   453 
   454 		g_Timers.RunFrame();
   455 		g_LastTime = curtime;
   456 	}
   457 
   458 	if (g_SimTicks.ticking && curtime - g_LastMenuTime >= 1.0f)
   459 	{
   460 		g_ValveMenuStyle.ProcessWatchList();
   461 		g_RadioMenuStyle.ProcessWatchList();
   462 		g_LastMenuTime = curtime;
   463 	}
   464 
   465 	if (g_pOnGameFrame && g_pOnGameFrame->GetFunctionCount())
   466 	{
   467 		g_pOnGameFrame->Execute(NULL);
   468 	}
   469 }
   470 
   471 void SourceModBase::LevelShutdown()
   472 {
   473 	if (g_LevelEndBarrier)
   474 	{
   475 		SMGlobalClass *next = SMGlobalClass::head;
   476 		while (next)
   477 		{
   478 			next->OnSourceModLevelEnd();
   479 			next = next->m_pGlobalClassNext;
   480 		}
   481 		g_LevelEndBarrier = false;
   482 	}
   483 
   484 	if (g_pOnMapEnd && m_ExecOnMapEnd)
   485 	{
   486 		g_pOnMapEnd->Execute(NULL);
   487 		m_ExecOnMapEnd = false;
   488 	}
   489 
   490 	g_OnMapStarted = false;
   491 
   492 	if (m_ExecPluginReload)
   493 	{
   494 		g_PluginSys.ReloadOrUnloadPlugins();
   495 		m_ExecPluginReload = false;
   496 	}
   497 }
   498 
   499 bool SourceModBase::IsMapLoading() const
   500 {
   501 	return m_IsMapLoading;
   502 }
   503 
   504 void SourceModBase::DoGlobalPluginLoads()
   505 {
   506 	char config_path[PLATFORM_MAX_PATH];
   507 	char plugins_path[PLATFORM_MAX_PATH];
   508 
   509 	BuildPath(Path_SM, config_path, 
   510 		sizeof(config_path),
   511 		"configs/plugin_settings.cfg");
   512 	BuildPath(Path_SM, plugins_path,
   513 		sizeof(plugins_path),
   514 		"plugins");
   515 
   516 	/* Load any auto extensions */
   517 	g_Extensions.TryAutoload();
   518 
   519 	/* Run the first pass */
   520 	g_PluginSys.LoadAll_FirstPass(config_path, plugins_path);
   521 
   522 	/* Mark any extensions as loaded */
   523 	g_Extensions.MarkAllLoaded();
   524 
   525 	/* No modules yet, it's safe to call this from here */
   526 	g_PluginSys.LoadAll_SecondPass();
   527 
   528 	/* Re-mark any extensions as loaded */
   529 	g_Extensions.MarkAllLoaded();
   530 
   531 	/* Call OnAllPluginsLoaded */
   532 	g_PluginSys.AllPluginsLoaded();
   533 }
   534 
   535 size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, char *format, ...)
   536 {
   537 	char _buffer[PLATFORM_MAX_PATH];
   538 	va_list ap;
   539 
   540 	va_start(ap, format);
   541 	vsnprintf(_buffer, PLATFORM_MAX_PATH, format, ap);
   542 	va_end(ap);
   543 
   544 	const char *base = NULL;
   545 	if (type == Path_Game)
   546 	{
   547 		base = GetGamePath();
   548 	} else if (type == Path_SM) {
   549 		base = GetSourceModPath();
   550 	} else if (type == Path_SM_Rel) {
   551 		base = m_SMRelDir;
   552 	}
   553 
   554 	if (base)
   555 	{
   556 		return g_LibSys.PathFormat(buffer, maxlength, "%s/%s", base, _buffer);
   557 	} else {
   558 		return g_LibSys.PathFormat(buffer, maxlength, "%s", _buffer);
   559 	}
   560 }
   561 
   562 void SourceModBase::CloseSourceMod()
   563 {
   564 	/* Force a level end */
   565 	LevelShutdown();
   566 
   567 	/* Unload plugins */
   568 	g_PluginSys.Shutdown();
   569 
   570 	/* Unload extensions */
   571 	g_Extensions.Shutdown();
   572 
   573 	SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false);
   574 
   575 	if (g_Loaded)
   576 	{
   577 		if (g_pOnGameFrame)
   578 		{
   579 			g_Forwards.ReleaseForward(g_pOnGameFrame);
   580 		}
   581 
   582 		if (g_pOnMapEnd)
   583 		{
   584 			g_Forwards.ReleaseForward(g_pOnMapEnd);
   585 		}
   586 	
   587 		/* Notify! */
   588 		SMGlobalClass *pBase = SMGlobalClass::head;
   589 		while (pBase)
   590 		{
   591 			pBase->OnSourceModShutdown();
   592 			pBase = pBase->m_pGlobalClassNext;
   593 		}
   594 	
   595 		/* Delete all data packs */
   596 		CStack<CDataPack *>::iterator iter;
   597 		CDataPack *pd;
   598 		for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++)
   599 		{
   600 			pd = (*iter);
   601 			delete pd;
   602 		}
   603 		m_freepacks.popall();
   604 	
   605 		/* Notify! */
   606 		pBase = SMGlobalClass::head;
   607 		while (pBase)
   608 		{
   609 			pBase->OnSourceModAllShutdown();
   610 			pBase = pBase->m_pGlobalClassNext;
   611 		}
   612 	
   613 		if (enginePatch)
   614 		{
   615 			SH_RELEASE_CALLCLASS(enginePatch);
   616 			enginePatch = NULL;
   617 		}
   618 	
   619 		if (gamedllPatch)
   620 		{
   621 			SH_RELEASE_CALLCLASS(gamedllPatch);
   622 			gamedllPatch = NULL;
   623 		}
   624 
   625 		SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false);
   626 		SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, this, &SourceModBase::GameFrame, false);
   627 	}
   628 
   629 	/* Rest In Peace */
   630 	ShutdownJIT();
   631 }
   632 
   633 void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...)
   634 {
   635 	IExtensionInterface *pAPI = pExt->GetAPI();
   636 	const char *tag = pAPI->GetExtensionTag();
   637 	char buffer[2048];
   638 	va_list ap;
   639 
   640 	va_start(ap, format);
   641 	vsnprintf(buffer, sizeof(buffer), format, ap);
   642 	va_end(ap);
   643 
   644 	if (tag)
   645 	{
   646 		g_Logger.LogMessage("[%s] %s", tag, buffer);
   647 	} else {
   648 		g_Logger.LogMessage("%s", buffer);
   649 	}
   650 }
   651 
   652 void SourceModBase::LogError(IExtension *pExt, const char *format, ...)
   653 {
   654 	IExtensionInterface *pAPI = pExt->GetAPI();
   655 	const char *tag = pAPI->GetExtensionTag();
   656 	char buffer[2048];
   657 	va_list ap;
   658 
   659 	va_start(ap, format);
   660 	vsnprintf(buffer, sizeof(buffer), format, ap);
   661 	va_end(ap);
   662 
   663 	if (tag)
   664 	{
   665 		g_Logger.LogError("[%s] %s", tag, buffer);
   666 	} else {
   667 		g_Logger.LogError("%s", buffer);
   668 	}
   669 }
   670 
   671 size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param)
   672 {
   673 	char *fmt;
   674 
   675 	pContext->LocalToString(params[param], &fmt);
   676 
   677 	int lparam = ++param;
   678 
   679 	return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam);
   680 }
   681 
   682 const char *SourceModBase::GetSourceModPath() const
   683 {
   684 	return m_SMBaseDir;
   685 }
   686 
   687 const char *SourceModBase::GetGamePath() const
   688 {
   689 	return g_BaseDir.c_str();
   690 }
   691 
   692 void SourceModBase::SetGlobalTarget(unsigned int index)
   693 {
   694 	m_target = index;
   695 }
   696 
   697 void SourceModBase::SetAuthChecking(bool set)
   698 {
   699 	m_CheckingAuth = set;
   700 }
   701 
   702 unsigned int SourceModBase::GetGlobalTarget() const
   703 {
   704 	return m_target;
   705 }
   706 
   707 IDataPack *SourceModBase::CreateDataPack()
   708 {
   709 	CDataPack *pack;
   710 	if (m_freepacks.empty())
   711 	{
   712 		pack = new CDataPack;
   713 	} else {
   714 		pack = m_freepacks.front();
   715 		m_freepacks.pop();
   716 		pack->Initialize();
   717 	}
   718 	return pack;
   719 }
   720 
   721 void SourceModBase::FreeDataPack(IDataPack *pack)
   722 {
   723 	m_freepacks.push(static_cast<CDataPack *>(pack));
   724 }
   725 
   726 Handle_t SourceModBase::GetDataPackHandleType(bool readonly)
   727 {
   728 	//:TODO:
   729 	return 0;
   730 }
   731 
   732 const char *SourceModBase::GetGameFolderName() const
   733 {
   734 	return m_ModDir;
   735 }
   736 
   737 ISourcePawnEngine *SourceModBase::GetScriptingEngine()
   738 {
   739 	return g_pSourcePawn;
   740 }
   741 
   742 IVirtualMachine *SourceModBase::GetScriptingVM()
   743 {
   744 	return g_pVM;
   745 }
   746 
   747 void SourceModBase::AllPluginsLoaded()
   748 {
   749 	SMGlobalClass *base = SMGlobalClass::head;
   750 	while (base)
   751 	{
   752 		base->OnSourceModGameInitialized();
   753 		base = base->m_pGlobalClassNext;
   754 	}
   755 }
   756 
   757 SMGlobalClass *SMGlobalClass::head = NULL;
   758 
   759 SMGlobalClass::SMGlobalClass()
   760 {
   761 	m_pGlobalClassNext = SMGlobalClass::head;
   762 	SMGlobalClass::head = this;
   763 }