diff --git a/core/provider/source2/provider_source2.cpp b/core/provider/source2/provider_source2.cpp index 34f176e..07c26c0 100644 --- a/core/provider/source2/provider_source2.cpp +++ b/core/provider/source2/provider_source2.cpp @@ -45,15 +45,13 @@ static ISource2ServerConfig* serverconfig = NULL; INetworkServerService* netservice = NULL; IEngineServiceMgr* enginesvcmgr = NULL; -// 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_HOOK3_void(INetworkServerService, StartupServer, SH_NOATTRIB, 0, const GameSessionConfiguration_t &, ISource2WorldSession *, const char *); -SH_DECL_HOOK5_void(IEngineServiceMgr, SwitchToLoop, SH_NOATTRIB, 0, const char *, KeyValues *, uint32, const char *, bool); -SH_DECL_HOOK2_void(INetworkGameServer, Init, SH_NOATTRIB, 0, const GameSessionConfiguration_t &, const char *); -SH_DECL_HOOK3(INetworkGameServer, StartChangeLevel, SH_NOATTRIB, 0, CUtlVector *, const char *, const char *, void *); SH_DECL_HOOK2_void(IServerGameClients, ClientCommand, SH_NOATTRIB, 0, CPlayerSlot, const CCommand&); +SH_DECL_HOOK3_void(IEngineServiceMgr, RegisterLoopMode, SH_NOATTRIB, 0, const char *, ILoopModeFactory *, void **); +SH_DECL_HOOK3_void(IEngineServiceMgr, UnregisterLoopMode, SH_NOATTRIB, 0, const char*, ILoopModeFactory*, void**); +SH_DECL_HOOK0(ILoopModeFactory, CreateLoopMode, SH_NOATTRIB, 0, ILoopMode *); +SH_DECL_HOOK1_void(ILoopModeFactory, DestroyLoopMode, SH_NOATTRIB, 0, ILoopMode *); +SH_DECL_HOOK2(ILoopMode, LoopInit, SH_NOATTRIB, 0, bool, KeyValues*, ILoopModePrerequisiteRegistry *); +SH_DECL_HOOK0_void(ILoopMode, LoopShutdown, SH_NOATTRIB, 0); #ifdef SHOULD_OVERRIDE_ALLOWDEDICATED_SERVER SH_DECL_HOOK1(ISource2ServerConfig, AllowDedicatedServers, const, 0, bool, EUniverse); @@ -147,14 +145,17 @@ void Source2Provider::Notify_DLLInit_Pre(CreateInterfaceFn engineFactory, SH_ADD_VPHOOK(ISource2ServerConfig, AllowDedicatedServers, serverconfig, SH_MEMBER(this, &Source2Provider::Hook_AllowDedicatedServers), false); #endif - SH_ADD_HOOK(INetworkServerService, StartupServer, netservice, SH_MEMBER(this, &Source2Provider::Hook_StartupServer_Post), true); - SH_ADD_HOOK(IEngineServiceMgr, SwitchToLoop, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_SwitchToLoop), false); + SH_ADD_HOOK(IEngineServiceMgr, RegisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_RegisterLoopMode), false); + SH_ADD_HOOK(IEngineServiceMgr, UnregisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_UnregisterLoopMode), false); } void Source2Provider::Notify_DLLShutdown_Pre() { ConVar_Unregister(); + SH_REMOVE_HOOK(IEngineServiceMgr, RegisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_RegisterLoopMode), false); + SH_REMOVE_HOOK(IEngineServiceMgr, UnregisterLoopMode, enginesvcmgr, SH_MEMBER(this, &Source2Provider::Hook_UnregisterLoopMode), false); + if (gameclients) { SH_REMOVE_HOOK(IServerGameClients, ClientCommand, gameclients, SH_MEMBER(this, &Source2Provider::Hook_ClientCommand), false); @@ -370,53 +371,71 @@ void LocalCommand_Meta(const CCommandContext &, const CCommand& args) } } -void Source2Provider::Hook_StartupServer_Post(const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *) +void Source2Provider::Hook_RegisterLoopMode(const char *pszLoopModeName, ILoopModeFactory *pLoopModeFactory, void **ppGlobalPointer) { - static bool bGameServerHooked = false; - if (!bGameServerHooked) + if (!strcmp(pszLoopModeName, "game")) { - INetworkGameServer* netserver = (META_IFACEPTR(INetworkServerService))->GetIGameServer(); + SH_ADD_HOOK(ILoopModeFactory, CreateLoopMode, pLoopModeFactory, SH_MEMBER(this, &Source2Provider::Hook_CreateLoopModePost), true); + SH_ADD_HOOK(ILoopModeFactory, DestroyLoopMode, pLoopModeFactory, SH_MEMBER(this, &Source2Provider::Hook_DestroyLoopMode), false); - SH_ADD_VPHOOK(INetworkGameServer, Init, netserver, SH_MEMBER(this, &Source2Provider::Hook_Init), false); - SH_ADD_VPHOOK(INetworkGameServer, StartChangeLevel, netserver, SH_MEMBER(this, &Source2Provider::Hook_StartChangeLevel), false); + if (nullptr != m_pCallbacks) + { + m_pCallbacks->OnGameInit(); + } + } +} - bGameServerHooked = true; +void Source2Provider::Hook_UnregisterLoopMode(const char* pszLoopModeName, ILoopModeFactory* pLoopModeFactory, void** ppGlobalPointer) +{ + if (!strcmp(pszLoopModeName, "game")) + { + SH_REMOVE_HOOK(ILoopModeFactory, CreateLoopMode, pLoopModeFactory, SH_MEMBER(this, &Source2Provider::Hook_CreateLoopModePost), true); + SH_REMOVE_HOOK(ILoopModeFactory, DestroyLoopMode, pLoopModeFactory, SH_MEMBER(this, &Source2Provider::Hook_DestroyLoopMode), false); } RETURN_META(MRES_IGNORED); } -void Source2Provider::Hook_Init(const GameSessionConfiguration_t &config, const char *pszMapName) +ILoopMode *Source2Provider::Hook_CreateLoopModePost() +{ + ILoopMode *pLoopMode = META_RESULT_ORIG_RET(ILoopMode *); + SH_ADD_HOOK(ILoopMode, LoopInit, pLoopMode, SH_MEMBER(this, &Source2Provider::Hook_LoopInitPost), true); + SH_ADD_HOOK(ILoopMode, LoopShutdown, pLoopMode, SH_MEMBER(this, &Source2Provider::Hook_LoopShutdownPost), true); + + // Post-hook. Ignored + return nullptr; +} + +void Source2Provider::Hook_DestroyLoopMode(ILoopMode* pLoopMode) +{ + SH_REMOVE_HOOK(ILoopMode, LoopInit, pLoopMode, SH_MEMBER(this, &Source2Provider::Hook_LoopInitPost), true); + SH_REMOVE_HOOK(ILoopMode, LoopShutdown, pLoopMode, SH_MEMBER(this, &Source2Provider::Hook_LoopShutdownPost), true); +} + +bool Source2Provider::Hook_LoopInitPost(KeyValues* pKeyValues, ILoopModePrerequisiteRegistry *pRegistry) { - static char szLastMap[260] = ""; if (nullptr != m_pCallbacks) { - m_pCallbacks->OnLevelInit(pszMapName, "", sLastMap.c_str(), "", false, false); + m_pCallbacks->OnLevelInit( + pKeyValues->GetString("levelname"), + "", + pKeyValues->GetString("previouslevel"), + pKeyValues->GetString("landmarkname"), + pKeyValues->GetBool("loadmap"), + false + ); } - - sLastMap = pszMapName; - - RETURN_META(MRES_IGNORED); + + // Post-hook. Ignored + return true; } -CUtlVector *Source2Provider::Hook_StartChangeLevel(const char *, const char *, void *) +void Source2Provider::Hook_LoopShutdownPost() { if (nullptr != m_pCallbacks) { m_pCallbacks->OnLevelShutdown(); } - - RETURN_META_VALUE(MRES_IGNORED, nullptr); -} - -void Source2Provider::Hook_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk) -{ - if (nullptr != m_pCallbacks && strcmp(pszLoopName, "levelload") == 0) - { - m_pCallbacks->OnGameInit(); - } - - RETURN_META(MRES_IGNORED); } void Source2Provider::Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& _cmd) diff --git a/core/provider/source2/provider_source2.h b/core/provider/source2/provider_source2.h index f2ca942..6f83311 100644 --- a/core/provider/source2/provider_source2.h +++ b/core/provider/source2/provider_source2.h @@ -30,6 +30,7 @@ #include "../provider_base.h" #include +#include #include // TODO: is this still needed for Dota or CS2 on any platform? @@ -67,14 +68,15 @@ public: #ifdef SHOULD_OVERRIDE_ALLOWDEDICATED_SERVER bool Hook_AllowDedicatedServers(EUniverse universe) const; #endif - void Hook_StartupServer_Post(const GameSessionConfiguration_t &config, ISource2WorldSession *, const char *); - void Hook_Init(const GameSessionConfiguration_t &config, const char* pszMapName); - CUtlVector *Hook_StartChangeLevel(const char*, const char*, void*); - void Hook_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk); + void Hook_RegisterLoopMode(const char* pszLoopModeName, ILoopModeFactory *pLoopModeFactory, void **ppGlobalPointer); + void Hook_UnregisterLoopMode(const char* pszLoopModeName, ILoopModeFactory* pLoopModeFactory, void** ppGlobalPointer); + ILoopMode *Hook_CreateLoopModePost(); + void Hook_DestroyLoopMode(ILoopMode*); + bool Hook_LoopInitPost(KeyValues* pKeyValues, ILoopModePrerequisiteRegistry *pRegistry); + void Hook_LoopShutdownPost(); void Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& args); private: IFileSystem* baseFs = nullptr; - std::string sLastMap; friend void LocalCommand_Meta(const CCommandContext& context, const CCommand& args); };