From 41d6c2c37e16a9fc0b81f725e773bd8886615396 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 29 Nov 2007 00:13:08 +0000 Subject: [PATCH] experimental commit of a new feature --HG-- branch : sourcemm-1.4.3 extra : convert_revision : svn%3Ac2935e3e-5518-0410-8daf-afa5dab7d4e3/branches/sourcemm-1.4.3%40586 --- sourcemm/CSmmAPI.cpp | 2 +- sourcemm/sourcemm.cpp | 123 +++++++++++++++++++++++++++++++++----- sourcemm/sourcemm.h | 4 ++ sourcemm/vsp_listener.cpp | 33 +++++----- sourcemm/vsp_listener.h | 2 + 5 files changed, 133 insertions(+), 31 deletions(-) diff --git a/sourcemm/CSmmAPI.cpp b/sourcemm/CSmmAPI.cpp index 29963a9..317d31a 100644 --- a/sourcemm/CSmmAPI.cpp +++ b/sourcemm/CSmmAPI.cpp @@ -487,7 +487,7 @@ void CSmmAPI::LoadAsVSP() void CSmmAPI::EnableVSPListener() { /* If GameInit already passed and we're not already enabled or loaded, go ahead and LoadAsVSP load */ - if (bGameInit && !m_VSP && !g_VspListener.IsLoaded()) + if (bGameInit && !m_VSP && !g_VspListener.IsLoaded() && !g_VspListener.IsRootLoadMethod()) { LoadAsVSP(); } diff --git a/sourcemm/sourcemm.cpp b/sourcemm/sourcemm.cpp index 67afe74..4c1680c 100644 --- a/sourcemm/sourcemm.cpp +++ b/sourcemm/sourcemm.cpp @@ -19,6 +19,7 @@ #include "CPlugin.h" #include "util.h" #include "vsp_listener.h" +#include "iplayerinfo.h" #include using namespace SourceMM; @@ -63,7 +64,7 @@ int g_GameDllVersion = 0; const char VSPIFACE_001[] = "ISERVERPLUGINCALLBACKS001"; const char VSPIFACE_002[] = "ISERVERPLUGINCALLBACKS002"; const char GAMEINFO_PATH[] = "|gameinfo_path|"; -IBaseFileSystem *baseFs = NULL; +IFileSystem *baseFs = NULL; void ClearGamedllList(); @@ -125,14 +126,10 @@ void InitMainStates() SH_ADD_HOOK_STATICFUNC(IServerGameDLL, GameInit, g_GameDll.pGameDLL, GameInit_handler, false); } -bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals) +bool StartupMetamod(CreateInterfaceFn engineFactory) { - g_Engine.engineFactory = engineFactory; - g_Engine.fileSystemFactory = filesystemFactory; - g_Engine.physicsFactory = physicsFactory; - g_Engine.pGlobals = pGlobals; - g_Engine.engine = (IVEngineServer *)((engineFactory)(INTERFACEVERSION_VENGINESERVER, NULL)); + if (!g_Engine.engine) { Error("Could not find IVEngineServer! Metamod cannot load."); @@ -147,7 +144,6 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, g_Engine.loaded = true; - /* Initialize our console hooks */ ConCommandBaseMgr::OneTimeInit(static_cast(&g_SMConVarAccessor)); g_GameDllPatch = SH_GET_CALLCLASS(g_GameDll.pGameDLL); @@ -155,7 +151,9 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, if (g_GameDll.pGameClients) { SH_ADD_HOOK_STATICFUNC(IServerGameClients, ClientCommand, g_GameDll.pGameClients, ClientCommand_handler, false); - } else { + } + else + { /* If IServerGameClients isn't found, this really isn't a fatal error so... */ LogMessage("[META] Warning: Could not find IServerGameClients!"); LogMessage("[META] Warning: The 'meta' command will not be available to clients."); @@ -170,13 +168,13 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, if (!g_SmmAPI.CacheUserMessages()) { /* Don't know of a mod that has stripped out user messages completely, - * but perhaps should do something different here? - */ + * but perhaps should do something different here? + */ LogMessage("[META] Warning: Failed to get list of user messages."); LogMessage("[META] Warning: The 'meta game' command will not display user messages."); } - baseFs = (IBaseFileSystem *)((filesystemFactory)(BASEFILESYSTEM_INTERFACE_VERSION, NULL)); + baseFs = (IFileSystem *)((engineFactory)(FILESYSTEM_INTERFACE_VERSION, NULL)); if (baseFs == NULL) { LogMessage("[META] Failed to find filesystem interface, .vdf files will not be parsed."); @@ -202,9 +200,90 @@ bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, bInFirstLevel = true; + return true; +} + +bool DLLInit(CreateInterfaceFn engineFactory, CreateInterfaceFn physicsFactory, CreateInterfaceFn filesystemFactory, CGlobalVars *pGlobals) +{ + g_Engine.engineFactory = engineFactory; + g_Engine.fileSystemFactory = filesystemFactory; + g_Engine.physicsFactory = physicsFactory; + g_Engine.pGlobals = pGlobals; + + StartupMetamod(engineFactory); + RETURN_META_VALUE(MRES_IGNORED, true); } +bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory) +{ + g_Engine.engineFactory = ifaceFactory; + g_Engine.fileSystemFactory = ifaceFactory; + g_Engine.physicsFactory = ifaceFactory; + + IPlayerInfoManager *playerInfoManager = (IPlayerInfoManager *)serverFactory("PlayerInfoManager002", NULL); + if (playerInfoManager == NULL) + { + Error("Metamod:Source requires gameinfo.txt modification to load on this game."); + return false; + } + + g_Engine.pGlobals = playerInfoManager->GetGlobalVars(); + + /* Now find the server */ + g_GameDll.factory = serverFactory; + g_GameDll.lib = NULL; + + char gamedll_iface[] = "ServerGameDLL000"; + for (unsigned int i = 3; i <= 50; i++) + { + gamedll_iface[15] = '0' + i; + g_GameDll.pGameDLL = (IServerGameDLL *)serverFactory(gamedll_iface, NULL); + if (g_GameDll.pGameDLL != NULL) + { + g_GameDllVersion = i; + break; + } + } + + if (g_GameDll.pGameDLL == NULL) + { + Error("Metamod:Source requires gameinfo.txt modification to load on this game."); + return false; + } + + char gameclients_iface[] = "ServerGameClients000"; + for (unsigned int i = 3; i <= 4; i++) + { + gameclients_iface[19] = '0' + i; + g_GameDll.pGameClients = (IServerGameClients *)serverFactory(gameclients_iface, NULL); + if (g_GameDll.pGameClients != NULL) + { + break; + } + } + + char smm_path[PATH_SIZE]; + const char *game_dir; + GetFileOfAddress((void *)AlternatelyLoadMetamod, smm_path, sizeof(smm_path)); + g_SmmPath.assign(smm_path); + + game_dir = CommandLine()->ParmValue("-game", "hl2"); + abspath(smm_path, game_dir); + g_ModPath.assign(smm_path); + + InitMainStates(); + + if (!StartupMetamod(ifaceFactory)) + { + return false; + } + + g_PluginMngr.SetAllLoaded(); + + return true; +} + bool GameInit_handler() { if (bGameInit) @@ -212,7 +291,7 @@ bool GameInit_handler() return true; } - if (g_SmmAPI.VSPEnabled()) + if (g_SmmAPI.VSPEnabled() && !g_VspListener.IsRootLoadMethod()) { g_SmmAPI.LoadAsVSP(); } @@ -234,7 +313,7 @@ SMM_API void *CreateInterface(const char *iface, int *ret) /* Prevent loading of self as a SourceMM plugin or Valve server plugin :x */ if (strcmp(iface, PLAPI_NAME) == 0) { - Warning("Do not try loading Metamod:Source as a SourceMM or Valve server plugin.\n"); + Warning("Do not try loading Metamod:Source as a Metamod:Source plugin"); if (ret) { @@ -257,6 +336,12 @@ SMM_API void *CreateInterface(const char *iface, int *ret) return &g_VspListener; } + /* If we're a VSP, bypass this by default */ + if (g_VspListener.IsRootLoadMethod()) + { + IFACE_MACRO(g_GameDll.factory, GameDLL); + } + if (!gParsedGameInfo) { gParsedGameInfo = true; @@ -490,7 +575,7 @@ void ClearGamedllList() gamedll_list.clear(); } -void DLLShutdown_handler() +void UnloadMetamod() { /* Unload plugins */ g_PluginMngr.UnloadAll(); @@ -507,9 +592,15 @@ void DLLShutdown_handler() g_SourceHook.CompleteShutdown(); if (g_GameDll.lib && g_GameDll.loaded) + { dlclose(g_GameDll.lib); + } memset(&g_GameDll, 0, sizeof(GameDllInfo)); +} +void DLLShutdown_handler() +{ + UnloadMetamod(); RETURN_META(MRES_SUPERCEDE); } @@ -586,7 +677,7 @@ void LookForVDFs(const char *dir) if ((hFind = FindFirstFile(path, &fd)) == INVALID_HANDLE_VALUE) { DWORD dw = GetLastError(); - FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), diff --git a/sourcemm/sourcemm.h b/sourcemm/sourcemm.h index b61f9eb..bfc7386 100644 --- a/sourcemm/sourcemm.h +++ b/sourcemm/sourcemm.h @@ -87,6 +87,8 @@ struct EngineInfo IVEngineServer *engine; }; +bool AlternatelyLoadMetamod(CreateInterfaceFn ifaceFactory, CreateInterfaceFn serverFactory); + /** @brief Global variable for GameDLL info */ extern GameDllInfo g_GameDll; @@ -116,6 +118,8 @@ extern int g_GameDllVersion; extern bool bGameInit; +void UnloadMetamod(); + /** @brief Global CallClass for IServerGameDLL */ extern SourceHook::CallClass *g_GameDllPatch; diff --git a/sourcemm/vsp_listener.cpp b/sourcemm/vsp_listener.cpp index c02a230..33e0b7e 100644 --- a/sourcemm/vsp_listener.cpp +++ b/sourcemm/vsp_listener.cpp @@ -19,6 +19,7 @@ VSPListener::VSPListener() { m_Loaded = false; m_Loadable = false; + m_bIsRootLoadMethod = false; } void VSPListener::ClientActive(edict_t *pEntity) @@ -92,6 +93,7 @@ void VSPListener::ServerActivate(edict_t *pEdictList, int edictCount, int client void VSPListener::Unload() { + UnloadMetamod(); } void VSPListener::SetLoadable(bool set) @@ -99,27 +101,30 @@ void VSPListener::SetLoadable(bool set) m_Loadable = set; } +bool VSPListener::IsRootLoadMethod() +{ + return m_bIsRootLoadMethod; +} + bool VSPListener::Load(CreateInterfaceFn interfaceFactory, CreateInterfaceFn gameServerFactory) { - if (!g_GameDll.loaded) - { - Error("Metamod:Source is not a Valve Server Plugin\n"); - - return false; - } - - if (!m_Loadable) - { - Warning("Do not manually load Metamod:Source as a Valve Server Plugin\n"); - - return false; - } - if (m_Loaded) { return false; } + if (!m_Loadable && !g_GameDll.loaded) + { + /* New loading mechanism, do a bunch o' stuff! */ + m_bIsRootLoadMethod = true; + m_Loaded = true; + SetLoadable(false); + if (!AlternatelyLoadMetamod(interfaceFactory, gameServerFactory)) + { + return false; + } + } + m_Loaded = true; SetLoadable(false); diff --git a/sourcemm/vsp_listener.h b/sourcemm/vsp_listener.h index 44b7b60..f907855 100644 --- a/sourcemm/vsp_listener.h +++ b/sourcemm/vsp_listener.h @@ -39,9 +39,11 @@ public: public: bool IsLoaded(); void SetLoadable(bool loadable); + bool IsRootLoadMethod(); private: bool m_Loaded; bool m_Loadable; + bool m_bIsRootLoadMethod; }; extern VSPListener g_VspListener;