diff -r c7b4237fff50 -r 03a67e41afbc core/sourcemod.cpp --- a/core/sourcemod.cpp Fri Mar 28 06:21:34 2008 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,662 +0,0 @@ -/** - * vim: set ts=4 : - * ============================================================================= - * SourceMod - * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved. - * ============================================================================= - * - * This program is free software; you can redistribute it and/or modify it under - * the terms of the GNU General Public License, version 3.0, as published by the - * Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - * details. - * - * You should have received a copy of the GNU General Public License along with - * this program. If not, see . - * - * As a special exception, AlliedModders LLC gives you permission to link the - * code of this program (as well as its derivative works) to "Half-Life 2," the - * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software - * by the Valve Corporation. You must obey the GNU General Public License in - * all respects for all other code used. Additionally, AlliedModders LLC grants - * this exception to all derivative works. AlliedModders LLC defines further - * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007), - * or . - * - * Version: $Id$ - */ - -#include -#include "sourcemod.h" -#include "sourcemm_api.h" -#include "systems/LibrarySys.h" -#include "vm/sp_vm_engine.h" -#include -#include "PluginSys.h" -#include "ShareSys.h" -#include "CoreConfig.h" -#include "Logger.h" -#include "ExtensionSys.h" -#include "AdminCache.h" -#include "sm_stringutil.h" -#include "PlayerManager.h" -#include "Translator.h" -#include "ForwardSys.h" -#include "TimerSys.h" -#include "GameConfigs.h" - -SH_DECL_HOOK6(IServerGameDLL, LevelInit, SH_NOATTRIB, false, bool, const char *, const char *, const char *, const char *, bool, bool); -SH_DECL_HOOK0_void(IServerGameDLL, LevelShutdown, SH_NOATTRIB, false); -SH_DECL_HOOK1_void(IServerGameDLL, GameFrame, SH_NOATTRIB, false, bool); -SH_DECL_HOOK1_void(IVEngineServer, ServerCommand, SH_NOATTRIB, false, const char *); - -SourcePawnEngine g_SourcePawn; -SourceModBase g_SourceMod; - -ILibrary *g_pJIT = NULL; -SourceHook::String g_BaseDir; -ISourcePawnEngine *g_pSourcePawn = &g_SourcePawn; -IVirtualMachine *g_pVM; -IdentityToken_t *g_pCoreIdent = NULL; -IForward *g_pOnMapEnd = NULL; -bool g_Loaded = false; - -typedef int (*GIVEENGINEPOINTER)(ISourcePawnEngine *); -typedef int (*GIVEENGINEPOINTER2)(ISourcePawnEngine *, unsigned int api_version); -typedef unsigned int (*GETEXPORTCOUNT)(); -typedef IVirtualMachine *(*GETEXPORT)(unsigned int); -typedef void (*NOTIFYSHUTDOWN)(); - -void ShutdownJIT() -{ - NOTIFYSHUTDOWN notify = (NOTIFYSHUTDOWN)g_pJIT->GetSymbolAddress("NotifyShutdown"); - if (notify) - { - notify(); - } - - g_pJIT->CloseLibrary(); -} - -SourceModBase::SourceModBase() -{ - m_IsMapLoading = false; - m_ExecPluginReload = false; - m_ExecOnMapEnd = false; - m_GotBasePath = false; -} - -ConfigResult SourceModBase::OnSourceModConfigChanged(const char *key, - const char *value, - ConfigSource source, - char *error, - size_t maxlength) -{ - if (strcasecmp(key, "BasePath") == 0) - { - if (source == ConfigSource_Console) - { - UTIL_Format(error, maxlength, "Cannot be set at runtime"); - return ConfigResult_Reject; - } - - if (!m_GotBasePath) - { - g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/%s", g_BaseDir.c_str(), value); - g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), value); - - m_GotBasePath = true; - } - - return ConfigResult_Accept; - } - - return ConfigResult_Ignore; -} - -bool SourceModBase::InitializeSourceMod(char *error, size_t maxlength, bool late) -{ - const char *gamepath = g_SMAPI->GetBaseDir(); - - /* Store full path to game */ - g_BaseDir.assign(gamepath); - - /* Store name of game directory by itself */ - size_t len = strlen(gamepath); - for (size_t i = len - 1; i >= 0; i--) - { - if (gamepath[i] == PLATFORM_SEP_CHAR) - { - strncopy(m_ModDir, &gamepath[++i], sizeof(m_ModDir)); - break; - } - } - - /* Initialize CoreConfig so we can get SourceMod base path properly - this basically parses core.cfg */ - g_CoreConfig.Initialize(); - - /* This shouldn't happen, but can't hurt to be safe */ - if (!g_LibSys.PathExists(m_SMBaseDir) || !m_GotBasePath) - { - g_LibSys.PathFormat(m_SMBaseDir, sizeof(m_SMBaseDir), "%s/addons/sourcemod", g_BaseDir.c_str()); - g_LibSys.PathFormat(m_SMRelDir, sizeof(m_SMRelDir), "addons/sourcemod"); - m_GotBasePath = true; - } - - /* Attempt to load the JIT! */ - char file[PLATFORM_MAX_PATH]; - char myerror[255]; - g_SMAPI->PathFormat(file, sizeof(file), "%s/bin/sourcepawn.jit.x86.%s", - GetSourceModPath(), - PLATFORM_LIB_EXT - ); - - g_pJIT = g_LibSys.OpenLibrary(file, myerror, sizeof(myerror)); - if (!g_pJIT) - { - if (error && maxlength) - { - snprintf(error, maxlength, "%s (failed to load bin/sourcepawn.jit.x86.%s)", - myerror, - PLATFORM_LIB_EXT); - } - return false; - } - - int err; - - GIVEENGINEPOINTER2 jit_init2 = (GIVEENGINEPOINTER2)g_pJIT->GetSymbolAddress("GiveEnginePointer2"); - if (!jit_init2) - { - GIVEENGINEPOINTER jit_init = (GIVEENGINEPOINTER)g_pJIT->GetSymbolAddress("GiveEnginePointer"); - if (!jit_init) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "Failed to find GiveEnginePointer in JIT!"); - } - return false; - } - - if ((err=jit_init(g_pSourcePawn)) != 0) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "GiveEnginePointer returned %d in the JIT", err); - } - return false; - } - } else { - /* On version bumps, we should check for older versions as well, if the new version fails. - * We can then check the exports to see if any VM versions will be sufficient. - */ - if ((err=jit_init2(g_pSourcePawn, SOURCEPAWN_ENGINE_API_VERSION)) != SP_ERROR_NONE) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "JIT incompatible with SourceMod version"); - } - return false; - } - } - - GETEXPORTCOUNT jit_getnum = (GETEXPORTCOUNT)g_pJIT->GetSymbolAddress("GetExportCount"); - GETEXPORT jit_get = (GETEXPORT)g_pJIT->GetSymbolAddress("GetExport"); - if (!jit_get) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "JIT is missing a necessary export!"); - } - return false; - } - - unsigned int num = jit_getnum(); - if (!num) - { - ShutdownJIT(); - if (error && maxlength) - { - snprintf(error, maxlength, "JIT did not export any virtual machines!"); - } - return false; - } - - unsigned int api_version; - for (unsigned int i=0; iGetAPIVersion(); - if (api_version < 3 || api_version > SOURCEPAWN_VM_API_VERSION) - { - if (error && maxlength) - { - snprintf(error, maxlength, "JIT is not a compatible version"); - } - g_pVM = NULL; - continue; - } - break; - } - - if (!g_pVM) - { - ShutdownJIT(); - return false; - } - - /* Hook this now so we can detect startup without calling StartSourceMod() */ - SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); - - /* Only load if we're not late */ - if (!late) - { - StartSourceMod(false); - } - - return true; -} - -void SourceModBase::StartSourceMod(bool late) -{ - SH_ADD_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); - SH_ADD_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, &g_Timers, &TimerSystem::GameFrame, false); - - enginePatch = SH_GET_CALLCLASS(engine); - gamedllPatch = SH_GET_CALLCLASS(gamedll); - - /* Notify! */ - SMGlobalClass *pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModStartup(false); - pBase = pBase->m_pGlobalClassNext; - } - - /* Make the global core identity */ - g_pCoreIdent = g_ShareSys.CreateCoreIdentity(); - - /* Notify! */ - pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModAllInitialized(); - pBase = pBase->m_pGlobalClassNext; - } - - /* Add us now... */ - g_ShareSys.AddInterface(NULL, this); - - /* We're loaded! */ - g_Loaded = true; - - /* Initialize VSP stuff */ - if (vsp_interface != NULL) - { - g_SourceMod_Core.OnVSPListening(vsp_interface); - } -} - -static bool g_LevelEndBarrier = false; -bool SourceModBase::LevelInit(char const *pMapName, char const *pMapEntities, char const *pOldLevel, char const *pLandmarkName, bool loadGame, bool background) -{ - /* If we're not loaded... */ - if (!g_Loaded) - { - /* Do all global initialization now */ - StartSourceMod(true); - } - - m_IsMapLoading = true; - m_ExecPluginReload = true; - m_ExecOnMapEnd = true; - - /* Notify! */ - SMGlobalClass *pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModLevelChange(pMapName); - pBase = pBase->m_pGlobalClassNext; - } - - DoGlobalPluginLoads(); - - m_IsMapLoading = false; - - /* Notify! */ - pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModPluginsLoaded(); - pBase = pBase->m_pGlobalClassNext; - } - - if (!g_pOnMapEnd) - { - g_pOnMapEnd = g_Forwards.CreateForward("OnMapEnd", ET_Ignore, 0, NULL); - } - - g_LevelEndBarrier = true; - - RETURN_META_VALUE(MRES_IGNORED, true); -} - -void SourceModBase::LevelShutdown() -{ - if (g_LevelEndBarrier) - { - SMGlobalClass *next = SMGlobalClass::head; - while (next) - { - next->OnSourceModLevelEnd(); - next = next->m_pGlobalClassNext; - } - g_LevelEndBarrier = false; - } - - if (g_pOnMapEnd && m_ExecOnMapEnd) - { - g_pOnMapEnd->Execute(NULL); - m_ExecOnMapEnd = false; - } - - g_OnMapStarted = false; - - if (m_ExecPluginReload) - { - g_PluginSys.ReloadOrUnloadPlugins(); - m_ExecPluginReload = false; - } -} - -bool SourceModBase::IsMapLoading() const -{ - return m_IsMapLoading; -} - -void SourceModBase::DoGlobalPluginLoads() -{ - char config_path[PLATFORM_MAX_PATH]; - char plugins_path[PLATFORM_MAX_PATH]; - - BuildPath(Path_SM, config_path, - sizeof(config_path), - "configs/plugin_settings.cfg"); - BuildPath(Path_SM, plugins_path, - sizeof(plugins_path), - "plugins"); - - /* Load any auto extensions */ - g_Extensions.TryAutoload(); - - /* Fire the extensions ready message */ - g_SMAPI->MetaFactory(SOURCEMOD_NOTICE_EXTENSIONS, NULL, NULL); - - /* Load any game extension */ - const char *game_ext; - if ((game_ext = g_pGameConf->GetKeyValue("GameExtension")) != NULL) - { - char path[PLATFORM_MAX_PATH]; - UTIL_Format(path, sizeof(path), "%s.ext." PLATFORM_LIB_EXT, game_ext); - g_Extensions.LoadAutoExtension(path); - } - - /* Run the first pass */ - g_PluginSys.LoadAll_FirstPass(config_path, plugins_path); - - /* Mark any extensions as loaded */ - g_Extensions.MarkAllLoaded(); - - /* No modules yet, it's safe to call this from here */ - g_PluginSys.LoadAll_SecondPass(); - - /* Re-mark any extensions as loaded */ - g_Extensions.MarkAllLoaded(); - - /* Call OnAllPluginsLoaded */ - g_PluginSys.AllPluginsLoaded(); -} - -size_t SourceModBase::BuildPath(PathType type, char *buffer, size_t maxlength, const char *format, ...) -{ - char _buffer[PLATFORM_MAX_PATH]; - va_list ap; - - va_start(ap, format); - vsnprintf(_buffer, PLATFORM_MAX_PATH, format, ap); - va_end(ap); - - const char *base = NULL; - if (type == Path_Game) - { - base = GetGamePath(); - } else if (type == Path_SM) { - base = GetSourceModPath(); - } else if (type == Path_SM_Rel) { - base = m_SMRelDir; - } - - if (base) - { - return g_LibSys.PathFormat(buffer, maxlength, "%s/%s", base, _buffer); - } else { - return g_LibSys.PathFormat(buffer, maxlength, "%s", _buffer); - } -} - -void SourceModBase::CloseSourceMod() -{ - /* Force a level end */ - LevelShutdown(); - - /* Unload plugins */ - g_PluginSys.Shutdown(); - - /* Unload extensions */ - g_Extensions.Shutdown(); - - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelInit, gamedll, this, &SourceModBase::LevelInit, false); - - if (g_Loaded) - { - if (g_pOnMapEnd) - { - g_Forwards.ReleaseForward(g_pOnMapEnd); - } - - /* Notify! */ - SMGlobalClass *pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - /* Delete all data packs */ - CStack::iterator iter; - CDataPack *pd; - for (iter=m_freepacks.begin(); iter!=m_freepacks.end(); iter++) - { - pd = (*iter); - delete pd; - } - m_freepacks.popall(); - - /* Notify! */ - pBase = SMGlobalClass::head; - while (pBase) - { - pBase->OnSourceModAllShutdown(); - pBase = pBase->m_pGlobalClassNext; - } - - if (enginePatch) - { - SH_RELEASE_CALLCLASS(enginePatch); - enginePatch = NULL; - } - - if (gamedllPatch) - { - SH_RELEASE_CALLCLASS(gamedllPatch); - gamedllPatch = NULL; - } - - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, LevelShutdown, gamedll, this, &SourceModBase::LevelShutdown, false); - SH_REMOVE_HOOK_MEMFUNC(IServerGameDLL, GameFrame, gamedll, &g_Timers, &TimerSystem::GameFrame, false); - } - - /* Rest In Peace */ - ShutdownJIT(); -} - -void SourceModBase::LogMessage(IExtension *pExt, const char *format, ...) -{ - IExtensionInterface *pAPI = pExt->GetAPI(); - const char *tag = pAPI->GetExtensionTag(); - char buffer[2048]; - va_list ap; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - if (tag) - { - g_Logger.LogMessage("[%s] %s", tag, buffer); - } else { - g_Logger.LogMessage("%s", buffer); - } -} - -void SourceModBase::LogError(IExtension *pExt, const char *format, ...) -{ - IExtensionInterface *pAPI = pExt->GetAPI(); - const char *tag = pAPI->GetExtensionTag(); - char buffer[2048]; - va_list ap; - - va_start(ap, format); - vsnprintf(buffer, sizeof(buffer), format, ap); - va_end(ap); - - if (tag) - { - g_Logger.LogError("[%s] %s", tag, buffer); - } else { - g_Logger.LogError("%s", buffer); - } -} - -size_t SourceModBase::FormatString(char *buffer, size_t maxlength, IPluginContext *pContext, const cell_t *params, unsigned int param) -{ - char *fmt; - - pContext->LocalToString(params[param], &fmt); - - int lparam = ++param; - - return atcprintf(buffer, maxlength, fmt, pContext, params, &lparam); -} - -const char *SourceModBase::GetSourceModPath() const -{ - return m_SMBaseDir; -} - -const char *SourceModBase::GetGamePath() const -{ - return g_BaseDir.c_str(); -} - -unsigned int SourceModBase::SetGlobalTarget(unsigned int index) -{ - unsigned int old = m_target; - m_target = index; - return old; -} - -unsigned int SourceModBase::GetGlobalTarget() const -{ - return m_target; -} - -IDataPack *SourceModBase::CreateDataPack() -{ - CDataPack *pack; - if (m_freepacks.empty()) - { - pack = new CDataPack; - } else { - pack = m_freepacks.front(); - m_freepacks.pop(); - pack->Initialize(); - } - return pack; -} - -void SourceModBase::FreeDataPack(IDataPack *pack) -{ - m_freepacks.push(static_cast(pack)); -} - -Handle_t SourceModBase::GetDataPackHandleType(bool readonly) -{ - //:TODO: - return 0; -} - -const char *SourceModBase::GetGameFolderName() const -{ - return m_ModDir; -} - -ISourcePawnEngine *SourceModBase::GetScriptingEngine() -{ - return g_pSourcePawn; -} - -IVirtualMachine *SourceModBase::GetScriptingVM() -{ - return g_pVM; -} - -void SourceModBase::AllPluginsLoaded() -{ - SMGlobalClass *base = SMGlobalClass::head; - while (base) - { - base->OnSourceModGameInitialized(); - base = base->m_pGlobalClassNext; - } -} - -time_t SourceModBase::GetAdjustedTime() -{ - return GetAdjustedTime(); -} - -SMGlobalClass *SMGlobalClass::head = NULL; - -SMGlobalClass::SMGlobalClass() -{ - m_pGlobalClassNext = SMGlobalClass::head; - SMGlobalClass::head = this; -}