From a73b63cb5129c80e35d0fafe949d3e31bbeffb40 Mon Sep 17 00:00:00 2001 From: Nicholas Hastings Date: Sat, 11 Jul 2015 13:59:51 -0400 Subject: [PATCH] Initial version of GameInit, LevelInit, LevelShutdown hookup; removed cmds to manually trigger them. --- core/metamod.cpp | 238 ++++++++++++++++++++++++++------- core/metamod_provider.h | 8 ++ core/provider/provider_ep2.cpp | 48 +++++-- core/provider/provider_ep2.h | 6 + 4 files changed, 240 insertions(+), 60 deletions(-) diff --git a/core/metamod.cpp b/core/metamod.cpp index 09b7634..9b23434 100644 --- a/core/metamod.cpp +++ b/core/metamod.cpp @@ -37,6 +37,9 @@ #if defined __linux__ #include #endif +#if SOURCE_ENGINE == SE_SOURCE2 +#include +#endif using namespace SourceMM; using namespace SourceHook; @@ -47,6 +50,35 @@ using namespace SourceHook::Impl; * @file sourcemm.cpp */ +#if SOURCE_ENGINE == SE_SOURCE2 +// Hack to make hook decl compile when only having forward decl in header. +// (we have class structure but it requires protobuf which we don't want to include here) +class GameSessionConfiguration_t { }; + +SH_DECL_MANUALHOOK4_void(SGD_StartupServer, 0, 0, 0, const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); +SH_DECL_MANUALHOOK2_void(SGD_Init, 0, 0, 0, GameSessionConfiguration_t *, const char *); +SH_DECL_MANUALHOOK0(SGD_StartChangeLevel, 0, 0, 0, CUtlVector *); +SH_DECL_MANUALHOOK5_void(SGD_SwitchToLoop, 0, 0, 0, const char *, KeyValues *, uint32, const char *, bool); +SH_DECL_MANUALHOOK3(SGD_AllocateServer, 0, 0, 0, INetworkGameServer *, int, INetworkServerService *, ISource2WorldSession *); + +static INetworkGameServer * +Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *); + +static void +Handler_SwitchToLoop(const char *, KeyValues *, uint32, const char *, bool); + +static void +Handler_StartupServer(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); + +static void +Handler_StartupServer_Post(const GameSessionConfiguration_t &, INetworkGameServerFactory *, ISource2WorldSession *, const char *); + +static void +Handler_Init(GameSessionConfiguration_t *, const char *); + +static CUtlVector * +Handler_StartChangeLevel(); +#else SH_DECL_MANUALHOOK0(SGD_GameInit, 0, 0, 0, bool); SH_DECL_MANUALHOOK6(SGD_LevelInit, 0, 0, 0, bool, const char *, const char *, const char *, const char *, bool, bool); SH_DECL_MANUALHOOK0_void(SGD_LevelShutdown, 0, 0, 0); @@ -64,6 +96,7 @@ Handler_LevelInit(char const *pMapName, static bool Handler_GameInit(); +#endif static void InitializeVSP(); @@ -142,21 +175,6 @@ SourceMM::ISmmAPI *g_pMetamod = &g_Metamod; } \ } -#if SOURCE_ENGINE == SE_SOURCE2 -void meta_game_init(const CCommand &args) -{ - Handler_GameInit(); -} -void meta_level_init(const CCommand &args) -{ - Handler_LevelInit("dummy_level", "", "", "", false, false); -} -void meta_level_shutdown(const CCommand &args) -{ - Handler_LevelShutdown(); -} -#endif - /* Initialize everything here */ void mm_InitializeForLoad() @@ -171,7 +189,24 @@ mm_InitializeForLoad() */ in_first_level = true; -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE == SE_SOURCE2 + SourceHook::MemFuncInfo info; + + if (!provider->GetHookInfo(ProvidedHook_StartupServer, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkServerService::StartupServer"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_StartupServer, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer), false); + SH_ADD_MANUALHOOK(SGD_StartupServer, netservice, SH_STATIC(Handler_StartupServer_Post), true); + + if (!provider->GetHookInfo(ProvidedHook_SwitchToLoop, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for IEngineServiceMgr::SwitchToLoop"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_SwitchToLoop, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_SwitchToLoop, enginesvcmgr, SH_STATIC(Handler_SwitchToLoop), false); +#else SourceHook::MemFuncInfo info; if (!provider->GetHookInfo(ProvidedHook_GameInit, &info)) @@ -485,30 +520,6 @@ mm_InitializeGlobals(CreateInterfaceFn engineFactory, provider->Notify_DLLInit_Pre(engineFactory, gamedll_info.factory); } -static bool -Handler_GameInit() -{ - if (is_game_init) - return true; - - if (vsp_load_requested) - InitializeVSP(); - - if (g_bIsVspBridged && !were_plugins_loaded) - { - DoInitialPluginLoads(); - g_PluginMngr.SetAllLoaded(); - were_plugins_loaded = true; - } - - is_game_init = true; -#if SOURCE_ENGINE == SE_SOURCE2 - return true; -#else - RETURN_META_VALUE(MRES_IGNORED, true); -#endif -} - void mm_UnloadMetamod() { @@ -521,8 +532,35 @@ mm_UnloadMetamod() } static void -Handler_LevelShutdown(void) +mm_HandleGameInit() { + if (is_game_init) + return; + +#if SOURCE_ENGINE == SE_SOURCE2 + Msg("MMS: GameInit\n"); +#endif + + if (vsp_load_requested) + InitializeVSP(); + + if (g_bIsVspBridged && !were_plugins_loaded) + { + DoInitialPluginLoads(); + g_PluginMngr.SetAllLoaded(); + were_plugins_loaded = true; + } + + is_game_init = true; +} + +static void +mm_HandleLevelShutdown() +{ +#if SOURCE_ENGINE == SE_SOURCE2 + Msg("MMS: LevelShutdown\n"); +#endif + if (g_bIsVspBridged && !were_plugins_loaded) { DoInitialPluginLoads(); @@ -553,11 +591,120 @@ Handler_LevelShutdown(void) } ITER_EVENT(OnLevelShutdown, ()); +} +static void +mm_HandleLevelInit(char const *pMapName, +char const *pMapEntities, +char const *pOldLevel, +char const *pLandmarkName, +bool loadGame, +bool background) +{ #if SOURCE_ENGINE == SE_SOURCE2 -#else - RETURN_META(MRES_IGNORED); + Msg("MMS: LevelInit\n"); #endif + + ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); +} +#include +#if SOURCE_ENGINE == SE_SOURCE2 +static void +Handler_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk) +{ + if (strcmp(pszLoopName, "levelload") == 0) + { + mm_HandleGameInit(); + } + + RETURN_META(MRES_IGNORED); +} + +static void +Handler_StartupServer(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) +{ + SourceHook::MemFuncInfo info; + if (!provider->GetHookInfo(ProvidedHook_AllocateServer, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServerFactory::Allocate"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_AllocateServer, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); + + RETURN_META(MRES_IGNORED); +} + +static void +Handler_StartupServer_Post(const GameSessionConfiguration_t &config, INetworkGameServerFactory *pFactory, ISource2WorldSession *, const char *) +{ + SH_REMOVE_MANUALHOOK(SGD_AllocateServer, pFactory, SH_STATIC(Handler_AllocateServer), true); + + RETURN_META(MRES_IGNORED); +} + +static INetworkGameServer * +Handler_AllocateServer(int, INetworkServerService *, ISource2WorldSession *) +{ + static bool bGameServerHooked = false; + if (!bGameServerHooked) + { + INetworkGameServer *netserver = META_RESULT_ORIG_RET(INetworkGameServer *); + + SourceHook::MemFuncInfo info; + if (!provider->GetHookInfo(ProvidedHook_Init, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServer::Init"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_Init, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALVPHOOK(SGD_Init, netserver, SH_STATIC(Handler_Init), false); + + if (!provider->GetHookInfo(ProvidedHook_StartChangeLevel, &info)) + { + provider->DisplayError("Metamod:Source could not find a valid hook for INetworkGameServer::StartChangeLevel"); + } + SH_MANUALHOOK_RECONFIGURE(SGD_StartChangeLevel, info.vtblindex, info.vtbloffs, info.thisptroffs); + SH_ADD_MANUALVPHOOK(SGD_StartChangeLevel, netserver, SH_STATIC(Handler_StartChangeLevel), false); + + bGameServerHooked = true; + } + + RETURN_META_VALUE(MRES_IGNORED, nullptr); +} + +static void +Handler_Init(GameSessionConfiguration_t *pConfig, const char *pszMapName) +{ + static char szLastMap[260] = ""; + mm_HandleLevelInit(pszMapName, "", szLastMap, "", false, false); + UTIL_Format(szLastMap, sizeof(szLastMap), "%s", pszMapName); + + RETURN_META(MRES_IGNORED); +} + +static CUtlVector * +Handler_StartChangeLevel() +{ + mm_HandleLevelShutdown(); + + RETURN_META_VALUE(MRES_IGNORED, nullptr); +} + +#else + +static bool +Handler_GameInit() +{ + mm_HandleGameInit(); + + RETURN_META_VALUE(MRES_IGNORED, true); +} + +static void +Handler_LevelShutdown(void) +{ + mm_HandleLevelShutdown(); + + RETURN_META(MRES_IGNORED); } static bool @@ -570,12 +717,9 @@ Handler_LevelInit(char const *pMapName, { ITER_EVENT(OnLevelInit, (pMapName, pMapEntities, pOldLevel, pLandmarkName, loadGame, background)); -#if SOURCE_ENGINE == SE_SOURCE2 - return false; -#else RETURN_META_VALUE(MRES_IGNORED, false); -#endif } +#endif void MetamodSource::LogMsg(ISmmPlugin *pl, const char *msg, ...) { diff --git a/core/metamod_provider.h b/core/metamod_provider.h index 9cd71be..f16e76a 100644 --- a/core/metamod_provider.h +++ b/core/metamod_provider.h @@ -37,9 +37,17 @@ namespace SourceMM enum ProvidedHooks { +#if SOURCE_ENGINE == SE_SOURCE2 + ProvidedHook_StartChangeLevel = 0, + ProvidedHook_Init = 1, + ProvidedHook_StartupServer = 2, + ProvidedHook_SwitchToLoop = 3, + ProvidedHook_AllocateServer = 4, +#else ProvidedHook_LevelInit = 0, /**< IServerGameDLL::LevelInit */ ProvidedHook_LevelShutdown = 1, /**< IServerGameDLL::LevelShutdown */ ProvidedHook_GameInit = 4, /**< IServerGameDLL::GameInit */ +#endif }; /** diff --git a/core/provider/provider_ep2.cpp b/core/provider/provider_ep2.cpp index a7904dc..1f6b9c7 100644 --- a/core/provider/provider_ep2.cpp +++ b/core/provider/provider_ep2.cpp @@ -39,6 +39,9 @@ #include #include "metamod.h" #include +#if SOURCE_ENGINE == SE_SOURCE2 +#include +#endif #if SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); @@ -103,17 +106,14 @@ IFileSystem *baseFs = NULL; IServerGameDLL *server = NULL; #if SOURCE_ENGINE == SE_SOURCE2 static ISource2ServerConfig *serverconfig = NULL; +INetworkServerService *netservice = NULL; +IEngineServiceMgr *enginesvcmgr = NULL; #endif IVEngineServer *engine = NULL; IServerGameClients *gameclients = NULL; CGlobalVars *gpGlobals = NULL; IMetamodSourceProvider *provider = &g_Ep1Provider; ConCommand meta_local_cmd("meta", LocalCommand_Meta, "Metamod:Source control options"); -#if SOURCE_ENGINE == SE_SOURCE2 -ConCommand _meta_game_init("meta_game_init", meta_game_init); -ConCommand _meta_level_init("meta_level_init", meta_level_init); -ConCommand _meta_level_shutdown("meta_level_shutdown", meta_level_shutdown); -#endif #if SOURCE_ENGINE == SE_DOTA || SOURCE_ENGINE == SE_SOURCE2 SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CEntityIndex, const CCommand &); @@ -144,6 +144,8 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, #if SOURCE_ENGINE == SE_SOURCE2 gpGlobals = engine->GetServerGlobals(); serverconfig = (ISource2ServerConfig *) ((serverFactory) (INTERFACEVERSION_SERVERCONFIG, NULL)); + netservice = (INetworkServerService *) ((engineFactory) (NETWORKSERVERSERVICE_INTERFACE_VERSION, NULL)); + enginesvcmgr = (IEngineServiceMgr *) ((engineFactory) (ENGINESERVICEMGR_INTERFACE_VERSION, NULL)); #endif #if SOURCE_ENGINE >= SE_ORANGEBOX icvar = (ICvar *)((engineFactory)(CVAR_INTERFACE_VERSION, NULL)); @@ -177,11 +179,6 @@ void BaseProvider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, #endif g_SMConVarAccessor.RegisterConCommandBase(&meta_local_cmd); -#if SOURCE_ENGINE == SE_SOURCE2 - g_SMConVarAccessor.RegisterConCommandBase(&_meta_game_init); - g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_init); - g_SMConVarAccessor.RegisterConCommandBase(&_meta_level_shutdown); -#endif CacheUserMessages(); @@ -308,7 +305,34 @@ bool BaseProvider::LogMessage(const char *buffer) bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInfo) { -#if SOURCE_ENGINE != SE_SOURCE2 +#if SOURCE_ENGINE == SE_SOURCE2 + SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; + + switch (hook) + { + case ProvidedHook_StartupServer: + SourceHook::GetFuncInfo(&INetworkServerService::StartupServer, mfi); + break; + case ProvidedHook_StartChangeLevel: + SourceHook::GetFuncInfo(&INetworkGameServer::StartChangeLevel, mfi); + break; + case ProvidedHook_Init: + SourceHook::GetFuncInfo(&INetworkGameServer::Init, mfi); + break; + case ProvidedHook_SwitchToLoop: + SourceHook::GetFuncInfo(&IEngineServiceMgr::SwitchToLoop, mfi); + break; + case ProvidedHook_AllocateServer: + SourceHook::GetFuncInfo(&INetworkGameServerFactory::Allocate, mfi); + break; + default: + return false; + } + + *pInfo = mfi; + + return (mfi.thisptroffs >= 0); +#else SourceHook::MemFuncInfo mfi = {true, -1, 0, 0}; if (hook == ProvidedHook_LevelInit) @@ -327,8 +351,6 @@ bool BaseProvider::GetHookInfo(ProvidedHooks hook, SourceHook::MemFuncInfo *pInf *pInfo = mfi; return (mfi.thisptroffs >= 0); -#else - return false; #endif } diff --git a/core/provider/provider_ep2.h b/core/provider/provider_ep2.h index 26dfa89..db867dc 100644 --- a/core/provider/provider_ep2.h +++ b/core/provider/provider_ep2.h @@ -46,6 +46,8 @@ using namespace SourceMM; using namespace SourceHook; +class INetworkGameServer; + class BaseProvider : public IMetamodSourceProvider { public: @@ -89,6 +91,10 @@ extern IServerGameDLL *server; extern IServerGameClients *gameclients; extern ICvar *icvar; extern CGlobalVars *gpGlobals; +#if SOURCE_ENGINE == SE_SOURCE2 +extern INetworkServerService *netservice; +extern IEngineServiceMgr *enginesvcmgr; +#endif #endif //_INCLUDE_METAMOD_SOURCE_BASE_PROVIDER_H_