diff options
Diffstat (limited to 'NorthstarDLL/playlist.cpp')
-rw-r--r-- | NorthstarDLL/playlist.cpp | 138 |
1 files changed, 81 insertions, 57 deletions
diff --git a/NorthstarDLL/playlist.cpp b/NorthstarDLL/playlist.cpp index f3e17a32..4f34dbb1 100644 --- a/NorthstarDLL/playlist.cpp +++ b/NorthstarDLL/playlist.cpp @@ -1,106 +1,130 @@ #include "pch.h" #include "playlist.h" -#include "nsmem.h" #include "concommand.h" #include "convar.h" -#include "gameutils.h" -#include "hookutils.h" #include "squirrel.h" +#include "hoststate.h" +#include "serverpresence.h" -typedef char (*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2); -Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride; +AUTOHOOK_INIT() -typedef int (*GetCurrentGamemodeMaxPlayersType)(); -GetCurrentGamemodeMaxPlayersType GetCurrentGamemodeMaxPlayers; - -// function type defined in gameutils.h -SetPlaylistVarOverrideType SetPlaylistVarOverrideOriginal; -GetCurrentPlaylistVarType GetCurrentPlaylistVarOriginal; +// use the R2 namespace for game funcs +namespace R2 +{ + const char* (*GetCurrentPlaylistName)(); + void (*SetCurrentPlaylist)(const char* pPlaylistName); + void (*SetPlaylistVarOverride)(const char* pVarName, const char* pValue); + const char* (*GetCurrentPlaylistVar)(const char* pVarName, bool bUseOverrides); +} // namespace R2 ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride; -void ConCommand_playlist(const CCommand& args) +// clang-format off +AUTOHOOK(clc_SetPlaylistVarOverride__Process, engine.dll + 0x222180, +char, __fastcall, (void* a1, void* a2)) +// clang-format on { - if (args.ArgC() < 2) - return; + // the private_match playlist on mp_lobby is the only situation where there should be any legitimate sending of this netmessage + if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(R2::GetCurrentPlaylistName(), "private_match") || + strcmp(R2::g_pHostState->m_levelName, "mp_lobby")) + return 1; - SetCurrentPlaylist(args.Arg(1)); + return clc_SetPlaylistVarOverride__Process(a1, a2); } -void ConCommand_setplaylistvaroverride(const CCommand& args) +// clang-format off +AUTOHOOK(SetCurrentPlaylist, engine.dll + 0x18EB20, +bool, __fastcall, (const char* pPlaylistName)) +// clang-format on { - if (args.ArgC() < 3) + bool bSuccess = SetCurrentPlaylist(pPlaylistName); + + if (bSuccess) + { + spdlog::info("Set playlist to {}", R2::GetCurrentPlaylistName()); + g_pServerPresence->SetPlaylist(R2::GetCurrentPlaylistName()); + } + + return bSuccess; +} + +// clang-format off +AUTOHOOK(SetPlaylistVarOverride, engine.dll + 0x18ED00, +void, __fastcall, (const char* pVarName, const char* pValue)) +// clang-format on +{ + if (strlen(pValue) >= 64) return; - for (int i = 1; i < args.ArgC(); i += 2) - SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1)); + SetPlaylistVarOverride(pVarName, pValue); } -char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2) +// clang-format off +AUTOHOOK(GetCurrentPlaylistVar, engine.dll + 0x18C680, +const char*, __fastcall, (const char* pVarName, bool bUseOverrides)) +// clang-format on { - // the private_match playlist is the only situation where there should be any legitimate sending of this netmessage - // todo: check mp_lobby here too - if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(GetCurrentPlaylistName(), "private_match")) - return 1; + if (!bUseOverrides && !strcmp(pVarName, "max_players")) + bUseOverrides = true; - return Onclc_SetPlaylistVarOverride(a1, a2); + return GetCurrentPlaylistVar(pVarName, bUseOverrides); } -void SetPlaylistVarOverrideHook(const char* varName, const char* value) +// clang-format off +AUTOHOOK(GetCurrentGamemodeMaxPlayers, engine.dll + 0x18C430, +int, __fastcall, ()) +// clang-format on { - if (strlen(value) >= 64) - return; + const char* pMaxPlayers = R2::GetCurrentPlaylistVar("max_players", 0); + if (!pMaxPlayers) + return GetCurrentGamemodeMaxPlayers(); - SetPlaylistVarOverrideOriginal(varName, value); + int iMaxPlayers = atoi(pMaxPlayers); + return iMaxPlayers; } -char* GetCurrentPlaylistVarHook(const char* varName, bool useOverrides) +void ConCommand_playlist(const CCommand& args) { - if (!useOverrides && !strcmp(varName, "max_players")) - useOverrides = true; + if (args.ArgC() < 2) + return; - return GetCurrentPlaylistVarOriginal(varName, useOverrides); + R2::SetCurrentPlaylist(args.Arg(1)); } -int GetCurrentGamemodeMaxPlayersHook() +void ConCommand_setplaylistvaroverride(const CCommand& args) { - char* maxPlayersStr = GetCurrentPlaylistVar("max_players", 0); - if (!maxPlayersStr) - return GetCurrentGamemodeMaxPlayers(); + if (args.ArgC() < 3) + return; - int maxPlayers = atoi(maxPlayersStr); - return maxPlayers; + for (int i = 1; i < args.ArgC(); i += 2) + R2::SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1)); } -void InitialisePlaylistHooks(HMODULE baseAddress) +ON_DLL_LOAD_RELIESON("engine.dll", PlaylistHooks, (ConCommand, ConVar), (CModule module)) { + AUTOHOOK_DISPATCH() + + R2::GetCurrentPlaylistName = module.Offset(0x18C640).As<const char* (*)()>(); + R2::SetCurrentPlaylist = module.Offset(0x18EB20).As<void (*)(const char*)>(); + R2::SetPlaylistVarOverride = module.Offset(0x18ED00).As<void (*)(const char*, const char*)>(); + R2::GetCurrentPlaylistVar = module.Offset(0x18C680).As<const char* (*)(const char*, bool)>(); + + // playlist is the name of the command on respawn servers, but we already use setplaylist so can't get rid of it + RegisterConCommand("playlist", ConCommand_playlist, "Sets the current playlist", FCVAR_NONE); RegisterConCommand("setplaylist", ConCommand_playlist, "Sets the current playlist", FCVAR_NONE); RegisterConCommand("setplaylistvaroverrides", ConCommand_setplaylistvaroverride, "sets a playlist var override", FCVAR_NONE); + // note: clc_SetPlaylistVarOverride is pretty insecure, since it allows for entirely arbitrary playlist var overrides to be sent to the - // server this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be + // server, this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be // disabled altogether, since the custom menus won't use it anyway this should only really be accepted if you want vanilla client // compatibility Cvar_ns_use_clc_SetPlaylistVarOverride = new ConVar( "ns_use_clc_SetPlaylistVarOverride", "0", FCVAR_GAMEDLL, "Whether the server should accept clc_SetPlaylistVarOverride messages"); - HookEnabler hook; - ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x222180, &Onclc_SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&Onclc_SetPlaylistVarOverride)); - ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18ED00, &SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&SetPlaylistVarOverrideOriginal)); - ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18C680, &GetCurrentPlaylistVarHook, reinterpret_cast<LPVOID*>(&GetCurrentPlaylistVarOriginal)); - ENABLER_CREATEHOOK( - hook, (char*)baseAddress + 0x18C430, &GetCurrentGamemodeMaxPlayersHook, reinterpret_cast<LPVOID*>(&GetCurrentGamemodeMaxPlayers)); - - uintptr_t ba = (uintptr_t)baseAddress; - // patch to prevent clc_SetPlaylistVarOverride from being able to crash servers if we reach max overrides due to a call to Error (why is // this possible respawn, wtf) todo: add a warning for this - { - NSMem::BytePatch(ba + 0x18ED8D, "C3"); - } + module.Offset(0x18ED8D).Patch("C3"); // patch to allow setplaylistvaroverride to be called before map init on dedicated and private match launched through the game - NSMem::NOP(ba + 0x18ED17, 6); + module.Offset(0x18ED17).NOP(6); } |