Skip to content

Commit

Permalink
S2: rework GameInit/LevelInit/LevelShutdown flow to better match S1
Browse files Browse the repository at this point in the history
  • Loading branch information
psychonic committed Oct 16, 2023
1 parent 2f0d9fc commit b2b9f3d
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 39 deletions.
87 changes: 53 additions & 34 deletions core/provider/source2/provider_source2.cpp
Expand Up @@ -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<INetworkGameClient *> *, 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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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()
{
static char szLastMap[260] = "";
if (nullptr != m_pCallbacks)
{
m_pCallbacks->OnLevelInit(pszMapName, "", sLastMap.c_str(), "", false, false);
}
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);

sLastMap = pszMapName;
// Post-hook. Ignored
return nullptr;
}

RETURN_META(MRES_IGNORED);
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);
}

CUtlVector<INetworkGameClient *> *Source2Provider::Hook_StartChangeLevel(const char *, const char *, void *)
bool Source2Provider::Hook_LoopInitPost(KeyValues* pKeyValues, ILoopModePrerequisiteRegistry *pRegistry)
{
if (nullptr != m_pCallbacks)
{
m_pCallbacks->OnLevelShutdown();
m_pCallbacks->OnLevelInit(
pKeyValues->GetString("levelname"),
"",
pKeyValues->GetString("previouslevel"),
pKeyValues->GetString("landmarkname"),
pKeyValues->GetBool("loadmap"),
false
);
}

RETURN_META_VALUE(MRES_IGNORED, nullptr);

// Post-hook. Ignored
return true;
}

void Source2Provider::Hook_SwitchToLoop(const char *pszLoopName, KeyValues *pKV, uint32 nId, const char *pszUnk, bool bUnk)
void Source2Provider::Hook_LoopShutdownPost()
{
if (nullptr != m_pCallbacks && strcmp(pszLoopName, "levelload") == 0)
if (nullptr != m_pCallbacks)
{
m_pCallbacks->OnGameInit();
m_pCallbacks->OnLevelShutdown();
}

RETURN_META(MRES_IGNORED);
}

void Source2Provider::Hook_ClientCommand(CPlayerSlot nSlot, const CCommand& _cmd)
Expand Down
12 changes: 7 additions & 5 deletions core/provider/source2/provider_source2.h
Expand Up @@ -30,6 +30,7 @@

#include "../provider_base.h"
#include <tier1/utlvector.h>
#include <IEngineService.h>
#include <string>

// TODO: is this still needed for Dota or CS2 on any platform?
Expand Down Expand Up @@ -67,14 +68,15 @@ class Source2Provider : public BaseProvider
#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<INetworkGameClient *> *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);
};
Expand Down

0 comments on commit b2b9f3d

Please sign in to comment.