diff options
author | Kawe Mazidjatari <48657826+Mauler125@users.noreply.github.com> | 2022-02-23 22:27:08 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-23 18:27:08 -0300 |
commit | 4f28a07d0562ca905bbcdb010b69604c330194bb (patch) | |
tree | 32ce0e8b0eff10cba6944a561e3538931a6033b6 | |
parent | 8c9f34283f8670dda98959d0785d682e6f652a93 (diff) | |
download | NorthstarLauncher-4f28a07d0562ca905bbcdb010b69604c330194bb.tar.gz NorthstarLauncher-4f28a07d0562ca905bbcdb010b69604c330194bb.zip |
ConVar class rebuild (#90)
* Implement CCvar class with mapped out vtable funcs
* Rebuilded ConVar class + code overhaul to use new system
* ConVar class is now properly mapped out for r2 (0x80 in size).
* Reimplemented and exposed all frequently used ConVar class methods to the SDK.
* Implement frequently used CCvar class methods.
* Implement all CCVarIteratorInternal class methods.
* Performed additional cleanup over the SDK to use new system instead.
* ConVar class improvements + rebuilded ConCommand struct
* Fix actual struct size for ConCommand
25 files changed, 1028 insertions, 188 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index 5235dfc9..6da5f2b7 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -110,16 +110,19 @@ <ClInclude Include="audio.h" /> <ClInclude Include="bansystem.h" /> <ClInclude Include="bitbuf.h" /> + <ClInclude Include="bits.h" /> <ClInclude Include="buildainfile.h" /> <ClInclude Include="chatcommand.h" /> <ClInclude Include="clientchathooks.h" /> <ClInclude Include="localchatwriter.h" /> <ClInclude Include="serverchathooks.h" /> <ClInclude Include="clientauthhooks.h" /> + <ClInclude Include="color.h" /> <ClInclude Include="concommand.h" /> <ClInclude Include="configurables.h" /> <ClInclude Include="context.h" /> <ClInclude Include="convar.h" /> + <ClInclude Include="cvar.h" /> <ClInclude Include="dedicated.h" /> <ClInclude Include="dedicatedmaterialsystem.h" /> <ClInclude Include="filesystem.h" /> @@ -556,6 +559,7 @@ <ItemGroup> <ClCompile Include="audio.cpp" /> <ClCompile Include="bansystem.cpp" /> + <ClCompile Include="bits.cpp" /> <ClCompile Include="buildainfile.cpp" /> <ClCompile Include="chatcommand.cpp" /> <ClCompile Include="clientauthhooks.cpp" /> @@ -564,6 +568,7 @@ <ClCompile Include="configurables.cpp" /> <ClCompile Include="context.cpp" /> <ClCompile Include="convar.cpp" /> + <ClCompile Include="cvar.cpp" /> <ClCompile Include="dedicated.cpp" /> <ClCompile Include="dedicatedmaterialsystem.cpp" /> <ClCompile Include="dllmain.cpp" /> diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 11205541..f0c8c380 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -121,6 +121,12 @@ <Filter Include="Header Files\include\libcurl"> <UniqueIdentifier>{ea1e17a6-40b7-4e1b-8edb-e9ae704ce604}</UniqueIdentifier> </Filter> + <Filter Include="Source Files\Shared\Math"> + <UniqueIdentifier>{59b0f68f-daa7-4641-b6fa-8464b56da2bb}</UniqueIdentifier> + </Filter> + <Filter Include="Header Files\Shared\Math"> + <UniqueIdentifier>{44a83740-9d70-480d-9a7a-43b81f8eab9e}</UniqueIdentifier> + </Filter> </ItemGroup> <ItemGroup> <ClInclude Include="pch.h"> @@ -1449,6 +1455,15 @@ <ClInclude Include="configurables.h"> <Filter>Header Files\Client</Filter> </ClInclude> + <ClInclude Include="cvar.h"> + <Filter>Header Files\Shared\Convar</Filter> + </ClInclude> + <ClInclude Include="color.h"> + <Filter>Header Files\Shared\Math</Filter> + </ClInclude> + <ClInclude Include="bits.h"> + <Filter>Header Files\Shared\Math</Filter> + </ClInclude> <ClInclude Include="serverchathooks.h"> <Filter>Header Files\Server</Filter> </ClInclude> @@ -1592,6 +1607,12 @@ <ClCompile Include="configurables.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> + <ClCompile Include="cvar.cpp"> + <Filter>Source Files\Shared\Convar</Filter> + </ClCompile> + <ClCompile Include="bits.cpp"> + <Filter>Source Files\Shared\Math</Filter> + </ClCompile> <ClCompile Include="serverchathooks.cpp"> <Filter>Source Files\Server</Filter> </ClCompile> diff --git a/NorthstarDedicatedTest/audio.cpp b/NorthstarDedicatedTest/audio.cpp index d6f70255..d3201b89 100644 --- a/NorthstarDedicatedTest/audio.cpp +++ b/NorthstarDedicatedTest/audio.cpp @@ -345,7 +345,7 @@ bool __declspec(noinline) __fastcall LoadSampleMetadata_Internal( { char* eventName = (char*)parentEvent + 0x110; - if (Cvar_ns_print_played_sounds->m_nValue > 0) + if (Cvar_ns_print_played_sounds->GetInt() > 0) spdlog::info("[AUDIO] Playing event {}", eventName); auto iter = g_CustomAudioManager.m_loadedAudioOverrides.find(eventName); @@ -462,7 +462,7 @@ void __fastcall MilesLog_Hook(int level, const char* string) { spdlog::info("[MS void InitialiseMilesAudioHooks(HMODULE baseAddress) { - Cvar_ns_print_played_sounds = RegisterConVar("ns_print_played_sounds", "0", FCVAR_NONE, ""); + Cvar_ns_print_played_sounds = new ConVar("ns_print_played_sounds", "0", FCVAR_NONE, ""); if (IsDedicated()) return; diff --git a/NorthstarDedicatedTest/bits.cpp b/NorthstarDedicatedTest/bits.cpp new file mode 100644 index 00000000..45375b18 --- /dev/null +++ b/NorthstarDedicatedTest/bits.cpp @@ -0,0 +1,28 @@ +//=============================================================================// +// +// Purpose: look for NANs, infinities, and underflows. +// +//=============================================================================// + +#include "pch.h" +#include "bits.h" + +//----------------------------------------------------------------------------- +// This follows the ANSI/IEEE 754-1985 standard +//----------------------------------------------------------------------------- +unsigned long& FloatBits(float& f) { return *reinterpret_cast<unsigned long*>(&f); } + +unsigned long const& FloatBits(float const& f) { return *reinterpret_cast<unsigned long const*>(&f); } + +float BitsToFloat(unsigned long i) { return *reinterpret_cast<float*>(&i); } + +bool IsFinite(float f) { return ((FloatBits(f) & 0x7F800000) != 0x7F800000); } + +unsigned long FloatAbsBits(float f) { return FloatBits(f) & 0x7FFFFFFF; } + +float FloatMakePositive(float f) { return fabsf(f); } + +float FloatNegate(float f) +{ + return -f; // BitsToFloat( FloatBits(f) ^ 0x80000000 ); +} diff --git a/NorthstarDedicatedTest/bits.h b/NorthstarDedicatedTest/bits.h new file mode 100644 index 00000000..0532a9bd --- /dev/null +++ b/NorthstarDedicatedTest/bits.h @@ -0,0 +1,10 @@ +#pragma once + +unsigned long& FloatBits(float& f); +unsigned long const& FloatBits(float const& f); +float BitsToFloat(unsigned long i); +bool IsFinite(float f); +unsigned long FloatAbsBits(float f); + +#define FLOAT32_NAN_BITS (std::uint32_t)0x7FC00000 // NaN! +#define FLOAT32_NAN BitsToFloat(FLOAT32_NAN_BITS) diff --git a/NorthstarDedicatedTest/buildainfile.cpp b/NorthstarDedicatedTest/buildainfile.cpp index 1d37c0a9..3adb8324 100644 --- a/NorthstarDedicatedTest/buildainfile.cpp +++ b/NorthstarDedicatedTest/buildainfile.cpp @@ -231,7 +231,7 @@ void DumpAINInfo(CAI_Network* aiNetwork) spdlog::info("calculated total linkcount: {}", calculatedLinkcount); calculatedLinkcount /= 2; - if (Cvar_ns_ai_dumpAINfileFromLoad->m_nValue) + if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) { if (aiNetwork->linkcount == calculatedLinkcount) spdlog::info("caculated linkcount is normal!"); @@ -365,7 +365,7 @@ void LoadAINFileHook(void* aimanager, void* buf, const char* filename) { LoadAINFile(aimanager, buf, filename); - if (Cvar_ns_ai_dumpAINfileFromLoad->m_nValue) + if (Cvar_ns_ai_dumpAINfileFromLoad->GetBool()) { spdlog::info("running DumpAINInfo for loaded file {}", filename); DumpAINInfo(*(CAI_Network**)((char*)aimanager + 2536)); @@ -374,7 +374,7 @@ void LoadAINFileHook(void* aimanager, void* buf, const char* filename) void InitialiseBuildAINFileHooks(HMODULE baseAddress) { - Cvar_ns_ai_dumpAINfileFromLoad = RegisterConVar( + Cvar_ns_ai_dumpAINfileFromLoad = new ConVar( "ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk"); HookEnabler hook; diff --git a/NorthstarDedicatedTest/chatcommand.cpp b/NorthstarDedicatedTest/chatcommand.cpp index cd6a998c..ac41014a 100644 --- a/NorthstarDedicatedTest/chatcommand.cpp +++ b/NorthstarDedicatedTest/chatcommand.cpp @@ -1,6 +1,7 @@ #include "pch.h" -#include "chatcommand.h" +#include "convar.h" #include "concommand.h" +#include "chatcommand.h" #include "dedicated.h" #include "localchatwriter.h" diff --git a/NorthstarDedicatedTest/clientauthhooks.cpp b/NorthstarDedicatedTest/clientauthhooks.cpp index 41f0fd32..3b98e84a 100644 --- a/NorthstarDedicatedTest/clientauthhooks.cpp +++ b/NorthstarDedicatedTest/clientauthhooks.cpp @@ -20,10 +20,10 @@ void AuthWithStryderHook(void* a1) { // game will call this forever, until it gets a valid auth key // so, we need to manually invalidate our key until we're authed with northstar, then we'll allow game to auth with stryder - if (!g_MasterServerManager->m_bOriginAuthWithMasterServerDone && Cvar_ns_has_agreed_to_send_token->m_nValue != DISAGREED_TO_SEND_TOKEN) + if (!g_MasterServerManager->m_bOriginAuthWithMasterServerDone && Cvar_ns_has_agreed_to_send_token->GetInt() != DISAGREED_TO_SEND_TOKEN) { // if player has agreed to send token and we aren't already authing, try to auth - if (Cvar_ns_has_agreed_to_send_token->m_nValue == AGREED_TO_SEND_TOKEN && + if (Cvar_ns_has_agreed_to_send_token->GetInt() == AGREED_TO_SEND_TOKEN && !g_MasterServerManager->m_bOriginAuthWithMasterServerInProgress) g_MasterServerManager->AuthenticateOriginWithMasterServer(g_LocalPlayerUserID, g_LocalPlayerOriginToken); @@ -40,7 +40,7 @@ void InitialiseClientAuthHooks(HMODULE baseAddress) return; // this cvar will save to cfg once initially agreed with - Cvar_ns_has_agreed_to_send_token = RegisterConVar( + Cvar_ns_has_agreed_to_send_token = new ConVar( "ns_has_agreed_to_send_token", "0", FCVAR_ARCHIVE_PLAYERPROFILE, "whether the user has agreed to send their origin token to the northstar masterserver"); diff --git a/NorthstarDedicatedTest/color.h b/NorthstarDedicatedTest/color.h new file mode 100644 index 00000000..b2d02d1e --- /dev/null +++ b/NorthstarDedicatedTest/color.h @@ -0,0 +1,90 @@ +#pragma once + +struct color24 +{ + uint8_t r, g, b; +}; + +typedef struct color32_s +{ + bool operator!=(const struct color32_s& other) const { return r != other.r || g != other.g || b != other.b || a != other.a; } + inline unsigned* asInt(void) { return reinterpret_cast<unsigned*>(this); } + inline const unsigned* asInt(void) const { return reinterpret_cast<const unsigned*>(this); } + inline void Copy(const color32_s& rhs) { *asInt() = *rhs.asInt(); } + + uint8_t r, g, b, a; +} color32; + +//----------------------------------------------------------------------------- +// Purpose: Basic handler for an rgb set of colors +// This class is fully inline +//----------------------------------------------------------------------------- +class Color +{ + public: + Color(int r, int g, int b, int a) + { + _color[0] = (unsigned char)r; + _color[1] = (unsigned char)g; + _color[2] = (unsigned char)b; + _color[3] = (unsigned char)a; + } + void SetColor(int _r, int _g, int _b, int _a = 0) + { + _color[0] = (unsigned char)_r; + _color[1] = (unsigned char)_g; + _color[2] = (unsigned char)_b; + _color[3] = (unsigned char)_a; + } + void GetColor(int& _r, int& _g, int& _b, int& _a) const + { + _r = _color[0]; + _g = _color[1]; + _b = _color[2]; + _a = _color[3]; + } + int GetValue(int index) const { return _color[index]; } + void SetRawColor(int color32) { *((int*)this) = color32; } + int GetRawColor(void) const { return *((int*)this); } + + inline int r() const { return _color[0]; } + inline int g() const { return _color[1]; } + inline int b() const { return _color[2]; } + inline int a() const { return _color[3]; } + + unsigned char& operator[](int index) { return _color[index]; } + + const unsigned char& operator[](int index) const { return _color[index]; } + + bool operator==(const Color& rhs) const { return (*((int*)this) == *((int*)&rhs)); } + + bool operator!=(const Color& rhs) const { return !(operator==(rhs)); } + + Color& operator=(const Color& rhs) + { + SetRawColor(rhs.GetRawColor()); + return *this; + } + + Color& operator=(const color32& rhs) + { + _color[0] = rhs.r; + _color[1] = rhs.g; + _color[2] = rhs.b; + _color[3] = rhs.a; + return *this; + } + + color32 ToColor32(void) const + { + color32 newColor{}; + newColor.r = _color[0]; + newColor.g = _color[1]; + newColor.b = _color[2]; + newColor.a = _color[3]; + return newColor; + } + + private: + unsigned char _color[4]; +}; diff --git a/NorthstarDedicatedTest/concommand.cpp b/NorthstarDedicatedTest/concommand.cpp index b876a05c..b455100f 100644 --- a/NorthstarDedicatedTest/concommand.cpp +++ b/NorthstarDedicatedTest/concommand.cpp @@ -17,17 +17,97 @@ void RegisterConCommand(const char* name, void (*callback)(const CCommand&), con conCommandConstructor(newCommand, name, callback, helpString, flags, nullptr); } -ConCommand* FindConCommand(const char* name) -{ - ICvar* icvar = - *g_pCvar; // hellish call because i couldn't get icvar vtable stuff in convar.h to get the right offset for whatever reason - typedef ConCommand* (*FindCommandBaseType)(ICvar * self, const char* varName); - FindCommandBaseType FindCommandBase = *(FindCommandBaseType*)((*(char**)icvar) + 112); - return FindCommandBase(icvar, name); -} - void InitialiseConCommands(HMODULE baseAddress) { conCommandConstructor = (ConCommandConstructorType)((char*)baseAddress + 0x415F60); AddMiscConCommands(); -}
\ No newline at end of file +} + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +// Output : bool +//----------------------------------------------------------------------------- +bool ConCommand::IsCommand(void) const { return true; } + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +// Output : bool +//----------------------------------------------------------------------------- +bool ConCommandBase::IsCommand(void) const { return true; } + +//----------------------------------------------------------------------------- +// Purpose: Has this cvar been registered +// Output : Returns true on success, false on failure. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsRegistered(void) const { return m_bRegistered; } + +//----------------------------------------------------------------------------- +// Purpose: Test each ConCommand query before execution. +// Input : *pCommandBase - nFlags +// Output : False if execution is permitted, true if not. +//----------------------------------------------------------------------------- +bool ConCommandBase::IsFlagSet(int nFlags) const +{ + return false; // !TODO: Returning false on every query? (original implementation in Northstar before ConCommandBase refactor) +} + +//----------------------------------------------------------------------------- +// Purpose: Checks if ConCommand has requested flags. +// Input : nFlags - +// Output : True if ConCommand has nFlags. +//----------------------------------------------------------------------------- +bool ConCommandBase::HasFlags(int nFlags) { return m_nFlags & nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: Add's flags to ConCommand. +// Input : nFlags - +//----------------------------------------------------------------------------- +void ConCommandBase::AddFlags(int nFlags) { m_nFlags |= nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: Removes flags from ConCommand. +// Input : nFlags - +//----------------------------------------------------------------------------- +void ConCommandBase::RemoveFlags(int nFlags) { m_nFlags &= ~nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: Returns current flags. +// Output : int +//----------------------------------------------------------------------------- +int ConCommandBase::GetFlags(void) const { return m_nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: +// Output : const ConCommandBase +//----------------------------------------------------------------------------- +ConCommandBase* ConCommandBase::GetNext(void) const { return m_pNext; } + +//----------------------------------------------------------------------------- +// Purpose: Returns the ConCommandBase help text. +// Output : const char* +//----------------------------------------------------------------------------- +const char* ConCommandBase::GetHelpText(void) const { return m_pszHelpString; } + +//----------------------------------------------------------------------------- +// Purpose: Copies string using local new/delete operators +// Input : *szFrom - +// Output : char +//----------------------------------------------------------------------------- +char* ConCommandBase::CopyString(const char* szFrom) const +{ + size_t nLen; + char* szTo; + + nLen = strlen(szFrom); + if (nLen <= 0) + { + szTo = new char[1]; + szTo[0] = 0; + } + else + { + szTo = new char[nLen + 1]; + memmove(szTo, szFrom, nLen + 1); + } + return szTo; +} diff --git a/NorthstarDedicatedTest/concommand.h b/NorthstarDedicatedTest/concommand.h index c7458794..b1342163 100644 --- a/NorthstarDedicatedTest/concommand.h +++ b/NorthstarDedicatedTest/concommand.h @@ -1,26 +1,15 @@ #pragma once -#include "convar.h" -// taken from ttf2sdk -class ConCommand +// From Source SDK +class ConCommandBase; +class IConCommandBaseAccessor { - unsigned char unknown[0x68]; - public: - virtual void EngineDestructor(void) {} - virtual bool IsCommand(void) const { return false; } - virtual bool IsFlagSet(int flag) { return false; } - virtual void AddFlags(int flags) {} - virtual void RemoveFlags(int flags) {} - virtual int GetFlags() const { return 0; } - virtual const char* GetName(void) const { return nullptr; } - virtual const char* GetHelpText(void) const { return nullptr; } - virtual bool IsRegistered(void) const { return false; } - // NOTE: there are more virtual methods here - // NOTE: Not using the engine's destructor here because it doesn't do anything useful for us + // Flags is a combination of FCVAR flags in cvar.h. + // hOut is filled in with a handle to the variable. + virtual bool RegisterConCommandBase(ConCommandBase* pVar) = 0; }; -// From Source SDK class CCommand { public: @@ -50,15 +39,10 @@ class CCommand }; inline int CCommand::MaxCommandLength() { return COMMAND_MAX_LENGTH - 1; } - inline int64_t CCommand::ArgC() const { return m_nArgc; } - inline const char** CCommand::ArgV() const { return m_nArgc ? (const char**)m_ppArgv : NULL; } - inline const char* CCommand::ArgS() const { return m_nArgv0Size ? &m_pArgSBuffer[m_nArgv0Size] : ""; } - inline const char* CCommand::GetCommandString() const { return m_nArgc ? m_pArgSBuffer : ""; } - inline const char* CCommand::Arg(int nIndex) const { // FIXME: Many command handlers appear to not be particularly careful @@ -68,9 +52,56 @@ inline const char* CCommand::Arg(int nIndex) const return ""; return m_ppArgv[nIndex]; } - inline const char* CCommand::operator[](int nIndex) const { return Arg(nIndex); } +// From r5reloaded +class ConCommandBase +{ + public: + bool HasFlags(int nFlags); + void AddFlags(int nFlags); + void RemoveFlags(int nFlags); + + bool IsCommand(void) const; + bool IsRegistered(void) const; + bool IsFlagSet(int nFlags) const; + static bool IsFlagSet(ConCommandBase* pCommandBase, int nFlags); // For hooking to engine's implementation. + + int GetFlags(void) const; + ConCommandBase* GetNext(void) const; + const char* GetHelpText(void) const; + + char* CopyString(const char* szFrom) const; + + void* m_pConCommandBaseVTable; // 0x0000 + ConCommandBase* m_pNext; // 0x0008 + bool m_bRegistered; // 0x0010 + char pad_0011[7]; // 0x0011 <- 3 bytes padding + unk int32. + const char* m_pszName; // 0x0018 + const char* m_pszHelpString; // 0x0020 + int m_nFlags; // 0x0028 + ConCommandBase* s_pConCommandBases; // 0x002C + IConCommandBaseAccessor* s_pAccessor; // 0x0034 +}; // Size: 0x0040 + +// taken from ttf2sdk +class ConCommand : public ConCommandBase +{ + friend class CCVar; + + public: + ConCommand(void){}; // !TODO: Rebuild engine constructor in SDK instead. + ConCommand(const char* szName, const char* szHelpString, int nFlags, void* pCallback, void* pCommandCompletionCallback); + void Init(void); + bool IsCommand(void) const; + + void* m_pCommandCallback{}; // 0x0040 <- starts from 0x40 since we inherit ConCommandBase. + void* m_pCompletionCallback{}; // 0x0048 <- defaults to sub_180417410 ('xor eax, eax'). + int m_nCallbackFlags{}; // 0x0050 + char pad_0054[4]; // 0x0054 + int unk0; // 0x0058 + int unk1; // 0x005C +}; // Size: 0x0060 + void RegisterConCommand(const char* name, void (*callback)(const CCommand&), const char* helpString, int flags); -ConCommand* FindConCommand(const char* name); void InitialiseConCommands(HMODULE baseAddress);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/convar.cpp b/NorthstarDedicatedTest/convar.cpp index 4157b42f..0f4eeba7 100644 --- a/NorthstarDedicatedTest/convar.cpp +++ b/NorthstarDedicatedTest/convar.cpp @@ -1,56 +1,478 @@ #include "pch.h" +#include "bits.h" +#include "cvar.h" #include "convar.h" #include "hookutils.h" #include "gameutils.h" #include "sourceinterface.h" -#include <set> // should this be in modmanager? std::unordered_map<std::string, ConVar*> g_CustomConvars; // this is used in modloading code to determine whether we've registered a mod convar already -SourceInterface<ICvar>* g_pCvar; -typedef void (*ConVarConstructorType)(ConVar* newVar, const char* name, const char* defaultValue, int flags, const char* helpString); -ConVarConstructorType conVarConstructor; +typedef void (*ConVarRegisterType)( + ConVar* pConVar, const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, bool bMin, float fMin, + bool bMax, float fMax, void* pCallback); +ConVarRegisterType conVarRegister; + +typedef void (*ConVarMallocType)(void* pConVarMaloc, int a2, int a3); +ConVarMallocType conVarMalloc; + +void* g_pConVar_Vtable = nullptr; +void* g_pIConVar_Vtable = nullptr; + typedef bool (*CvarIsFlagSetType)(ConVar* self, int flags); CvarIsFlagSetType CvarIsFlagSet; -ConVar* RegisterConVar(const char* name, const char* defaultValue, int flags, const char* helpString) +//----------------------------------------------------------------------------- +// Purpose: ConVar interface initialization +//----------------------------------------------------------------------------- +void InitialiseConVars(HMODULE baseAddress) +{ + conVarMalloc = (ConVarMallocType)((char*)baseAddress + 0x415C20); + conVarRegister = (ConVarRegisterType)((char*)baseAddress + 0x417230); + + g_pConVar_Vtable = (char*)baseAddress + 0x67FD28; + g_pIConVar_Vtable = (char*)baseAddress + 0x67FDC8; + + g_pCVarInterface = new SourceInterface<CCvar>("vstdlib.dll", "VEngineCvar007"); + g_pCVar = *g_pCVarInterface; + + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417FA0, &ConVar::IsFlagSet, reinterpret_cast<LPVOID*>(&CvarIsFlagSet)); +} + +//----------------------------------------------------------------------------- +// Purpose: constructor +//----------------------------------------------------------------------------- +ConVar::ConVar(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString) +{ + spdlog::info("Registering Convar {}", pszName); + + this->m_ConCommandBase.m_pConCommandBaseVTable = g_pConVar_Vtable; + this->m_ConCommandBase.s_pConCommandBases = (ConCommandBase*)g_pIConVar_Vtable; + + conVarMalloc(&this->m_pMalloc, 0, 0); // Allocate new memory for ConVar. + conVarRegister(this, pszName, pszDefaultValue, nFlags, pszHelpString, 0, 0, 0, 0, 0); + + g_CustomConvars.emplace(pszName, this); +} + +//----------------------------------------------------------------------------- +// Purpose: constructor +//----------------------------------------------------------------------------- +ConVar::ConVar( + const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, float fMax, + void* pCallback) +{ + spdlog::info("Registering Convar {}", pszName); + + this->m_ConCommandBase.m_pConCommandBaseVTable = g_pConVar_Vtable; + this->m_ConCommandBase.s_pConCommandBases = (ConCommandBase*)g_pIConVar_Vtable; + + conVarMalloc(&this->m_pMalloc, 0, 0); // Allocate new memory for ConVar. + conVarRegister(this, pszName, pszDefaultValue, nFlags, pszHelpString, bMin, fMin, bMax, fMax, pCallback); + + g_CustomConvars.emplace(pszName, this); +} + +//----------------------------------------------------------------------------- +// Purpose: destructor +//----------------------------------------------------------------------------- +ConVar::~ConVar(void) +{ + if (m_Value.m_pszString) + { + delete[] m_Value.m_pszString; + m_Value.m_pszString = NULL; + } +} + +//----------------------------------------------------------------------------- +// Purpose: Returns the base ConVar name. +// Output : const char* +//----------------------------------------------------------------------------- +const char* ConVar::GetBaseName(void) const { return m_ConCommandBase.m_pszName; } + +//----------------------------------------------------------------------------- +// Purpose: Returns the ConVar help text. +// Output : const char* +//----------------------------------------------------------------------------- +const char* ConVar::GetHelpText(void) const { return m_ConCommandBase.m_pszHelpString; } + +//----------------------------------------------------------------------------- +// Purpose: Add's flags to ConVar. +// Input : nFlags - +//----------------------------------------------------------------------------- +void ConVar::AddFlags(int nFlags) { m_ConCommandBase.m_nFlags |= nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: Removes flags from ConVar. +// Input : nFlags - +//----------------------------------------------------------------------------- +void ConVar::RemoveFlags(int nFlags) { m_ConCommandBase.m_nFlags &= ~nFlags; } + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a boolean. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::GetBool(void) const { return !!GetInt(); } + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a float. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetFloat(void) const { return m_Value.m_fValue; } + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as an integer. +// Output : int +//----------------------------------------------------------------------------- +int ConVar::GetInt(void) const { return m_Value.m_nValue; } + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a color. +// Output : Color +//----------------------------------------------------------------------------- +Color ConVar::GetColor(void) const +{ + unsigned char* pColorElement = ((unsigned char*)&m_Value.m_nValue); + return Color(pColorElement[0], pColorElement[1], pColorElement[2], pColorElement[3]); +} + +//----------------------------------------------------------------------------- +// Purpose: Return ConVar value as a string. +// Output : const char * +//----------------------------------------------------------------------------- +const char* ConVar::GetString(void) const +{ + if (m_ConCommandBase.m_nFlags & FCVAR_NEVER_AS_STRING) + { + return "FCVAR_NEVER_AS_STRING"; + } + + char const* str = m_Value.m_pszString; + return str ? str : ""; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMinVal - +// Output : true if there is a min set. +//----------------------------------------------------------------------------- +bool ConVar::GetMin(float& flMinVal) const +{ + flMinVal = m_fMinVal; + return m_bHasMin; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : flMaxVal - +// Output : true if there is a max set. +//----------------------------------------------------------------------------- +bool ConVar::GetMax(float& flMaxVal) const +{ + flMaxVal = m_fMaxVal; + return m_bHasMax; +} + +//----------------------------------------------------------------------------- +// Purpose: returns the min value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMinValue(void) const { return m_fMinVal; } + +//----------------------------------------------------------------------------- +// Purpose: returns the max value. +// Output : float +//----------------------------------------------------------------------------- +float ConVar::GetMaxValue(void) const +{ + return m_fMaxVal; + ; +} + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has min value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMin(void) const { return m_bHasMin; } + +//----------------------------------------------------------------------------- +// Purpose: checks if ConVar has max value. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::HasMax(void) const { return m_bHasMax; } + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar int value. +// Input : nValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(int nValue) { - spdlog::info("Registering Convar {}", name); + if (nValue == m_Value.m_nValue) + { + return; + } + + // Only valid for root ConVars. + assert(m_pParent == this); - // no need to free this ever really, it should exist as long as game does - ConVar* newVar = new ConVar; - conVarConstructor(newVar, name, defaultValue, flags, helpString); + float flValue = (float)nValue; - g_CustomConvars.emplace(name, newVar); + // Check bounds. + if (ClampValue(flValue)) + { + nValue = (int)(flValue); + } - return newVar; + // Redetermine value. + float flOldValue = m_Value.m_fValue; + m_Value.m_fValue = flValue; + m_Value.m_nValue = nValue; + + if (!(m_ConCommandBase.m_nFlags & FCVAR_NEVER_AS_STRING)) + { + char szTempValue[32]; + snprintf(szTempValue, sizeof(szTempValue), "%d", m_Value.m_nValue); + ChangeStringValue(szTempValue, flOldValue); + } } -ConVar* FindConVar(const char* name) +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar float value. +// Input : flValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(float flValue) { - ICvar* icvar = - *g_pCvar; // hellish call because i couldn't get icvar vtable stuff in convar.h to get the right offset for whatever reason - typedef ConVar* (*FindConVarType)(ICvar * self, const char* varName); - FindConVarType FindConVarInternal = *(FindConVarType*)((*(char**)icvar) + 128); - return FindConVarInternal(icvar, name); + if (flValue == m_Value.m_fValue) + { + return; + } + + // Only valid for root ConVars. + assert(m_pParent == this); + + // Check bounds. + ClampValue(flValue); + + // Redetermine value. + float flOldValue = m_Value.m_fValue; + m_Value.m_fValue = flValue; + m_Value.m_nValue = (int)m_Value.m_fValue; + + if (!(m_ConCommandBase.m_nFlags & FCVAR_NEVER_AS_STRING)) + { + char szTempValue[32]; + snprintf(szTempValue, sizeof(szTempValue), "%f", m_Value.m_fValue); + ChangeStringValue(szTempValue, flOldValue); + } } -bool CvarIsFlagSetHook(ConVar* self, int flags) +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar string value. +// Input : *szValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(const char* pszValue) +{ + if (strcmp(this->m_Value.m_pszString, pszValue) == 0) + { + return; + } + this->m_Value.m_pszString = pszValue; + + char szTempValue[32]{}; + const char* pszNewValue{}; + + // Only valid for root convars. + assert(m_pParent == this); + + float flOldValue = m_Value.m_fValue; + pszNewValue = (char*)pszValue; + if (!pszNewValue) + { + pszNewValue = ""; + } + + if (!SetColorFromString(pszValue)) + { + // Not a color, do the standard thing + float flNewValue = (float)atof(pszValue); + if (!IsFinite(flNewValue)) + { + spdlog::warn("Warning: ConVar '{}' = '{}' is infinite, clamping value.\n", GetBaseName(), pszValue); + flNewValue = FLT_MAX; + } + + if (ClampValue(flNewValue)) + { + snprintf(szTempValue, sizeof(szTempValue), "%f", flNewValue); + pszNewValue = szTempValue; + } + + // Redetermine value + m_Value.m_fValue = flNewValue; + m_Value.m_nValue = (int)(m_Value.m_fValue); + } + + if (!(m_ConCommandBase.m_nFlags & FCVAR_NEVER_AS_STRING)) + { + ChangeStringValue(pszNewValue, flOldValue); + } +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value. +// Input : clValue - +//----------------------------------------------------------------------------- +void ConVar::SetValue(Color clValue) +{ + std::string svResult = ""; + + for (int i = 0; i < 4; i++) + { + if (!(clValue.GetValue(i) == 0 && svResult.size() == 0)) + { + svResult += std::to_string(clValue.GetValue(i)); + svResult.append(" "); + } + } + + this->m_Value.m_pszString = svResult.c_str(); +} + +//----------------------------------------------------------------------------- +// Purpose: changes the ConVar string value. +// Input : *pszTempVal - flOldValue +//----------------------------------------------------------------------------- +void ConVar::ChangeStringValue(const char* pszTempVal, float flOldValue) +{ + assert(!(m_ConCommandBase.m_nFlags & FCVAR_NEVER_AS_STRING)); + + char* pszOldValue = (char*)_malloca(m_Value.m_iStringLength); + if (pszOldValue != NULL) + { + memcpy(pszOldValue, m_Value.m_pszString, m_Value.m_iStringLength); + } + + if (pszTempVal) + { + int len = strlen(pszTempVal) + 1; + + if (len > m_Value.m_iStringLength) + { + if (m_Value.m_pszString) + { + // !TODO: Causes issues in tier0.dll, but doesn't in apex. + // Not a big issue since we are creating a new string below + // anyways to prevent buffer overflow if string is longer + // then the old string. + // delete[] m_Value.m_pszString; + } + + m_Value.m_pszString = new char[len]; + m_Value.m_iStringLength = len; + } + + memcpy((char*)m_Value.m_pszString, pszTempVal, len); + } + else + { + m_Value.m_pszString = NULL; + } + + pszOldValue = 0; +} + +//----------------------------------------------------------------------------- +// Purpose: sets the ConVar color value from string. +// Input : *pszValue - +//----------------------------------------------------------------------------- +bool ConVar::SetColorFromString(const char* pszValue) +{ + bool bColor = false; + + // Try pulling RGBA color values out of the string. + int nRGBA[4]{}; + int nParamsRead = sscanf_s(pszValue, "%i %i %i %i", &(nRGBA[0]), &(nRGBA[1]), &(nRGBA[2]), &(nRGBA[3])); + + if (nParamsRead >= 3) + { + // This is probably a color! + if (nParamsRead == 3) + { + // Assume they wanted full alpha. + nRGBA[3] = 255; + } + + if (nRGBA[0] >= 0 && nRGBA[0] <= 255 && nRGBA[1] >= 0 && nRGBA[1] <= 255 && nRGBA[2] >= 0 && nRGBA[2] <= 255 && nRGBA[3] >= 0 && + nRGBA[3] <= 255) + { + // printf("*** WOW! Found a color!! ***\n"); + + // This is definitely a color! + bColor = true; + + // Stuff all the values into each byte of our int. + unsigned char* pColorElement = ((unsigned char*)&m_Value.m_nValue); + pColorElement[0] = nRGBA[0]; + pColorElement[1] = nRGBA[1]; + pColorElement[2] = nRGBA[2]; + pColorElement[3] = nRGBA[3]; + + // Copy that value into our float. + m_Value.m_fValue = (float)(m_Value.m_nValue); + } + } + + return bColor; +} + +//----------------------------------------------------------------------------- +// Purpose: Checks if ConVar is registered. +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::IsRegistered(void) const { return m_ConCommandBase.m_bRegistered; } + +//----------------------------------------------------------------------------- +// Purpose: Returns true if this is a command +// Output : bool +//----------------------------------------------------------------------------- +bool ConVar::IsCommand(void) const { return false; } + +//----------------------------------------------------------------------------- +// Purpose: Test each ConVar query before setting the value. +// Input : *pConVar - nFlags +// Output : False if change is permitted, true if not. +//----------------------------------------------------------------------------- +bool ConVar::IsFlagSet(ConVar* pConVar, int nFlags) { // unrestrict FCVAR_DEVELOPMENTONLY and FCVAR_HIDDEN - if (self && (flags == FCVAR_DEVELOPMENTONLY || flags == FCVAR_HIDDEN)) + if (pConVar && (nFlags == FCVAR_DEVELOPMENTONLY || nFlags == FCVAR_HIDDEN)) return false; - return CvarIsFlagSet(self, flags); + return CvarIsFlagSet(pConVar, nFlags); } -void InitialiseConVars(HMODULE baseAddress) +//----------------------------------------------------------------------------- +// Purpose: Check whether to clamp and then perform clamp. +// Input : flValue - +// Output : Returns true if value changed. +//----------------------------------------------------------------------------- +bool ConVar::ClampValue(float& flValue) { - conVarConstructor = (ConVarConstructorType)((char*)baseAddress + 0x416200); - g_pCvar = new SourceInterface<ICvar>("vstdlib.dll", "VEngineCvar007"); + if (m_bHasMin && (flValue < m_fMinVal)) + { + flValue = m_fMinVal; + return true; + } - HookEnabler hook; - ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417FA0, &CvarIsFlagSetHook, reinterpret_cast<LPVOID*>(&CvarIsFlagSet)); -}
\ No newline at end of file + if (m_bHasMax && (flValue > m_fMaxVal)) + { + flValue = m_fMaxVal; + return true; + } + + return false; +} diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h index 30ab702b..a00c7f0e 100644 --- a/NorthstarDedicatedTest/convar.h +++ b/NorthstarDedicatedTest/convar.h @@ -1,6 +1,9 @@ #pragma once #include "sourceinterface.h" -#include <set> +#include "color.h" +#include "cvar.h" +#include "concommand.h" + // taken directly from iconvar.h // The default, no flags at all @@ -17,14 +20,13 @@ // ConVar only #define FCVAR_PROTECTED \ (1 << 5) // It's a server cvar, but we don't send the data since it's a password, etc. Sends 1 if it's not bland/zero, 0 otherwise as - // value + // value. #define FCVAR_SPONLY (1 << 6) // This cvar cannot be changed by clients connected to a multiplayer server. #define FCVAR_ARCHIVE (1 << 7) // set to cause it to be saved to vars.rc #define FCVAR_NOTIFY (1 << 8) // notifies players when changed #define FCVAR_USERINFO (1 << 9) // changes the client's info string #define FCVAR_PRINTABLEONLY (1 << 10) // This cvar's string cannot contain unprintable characters ( e.g., used for player name etc ). - #define FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS \ (1 << 10) // When on concommands this allows remote clients to execute this cmd on the server. // We are changing the default behavior of concommands to disallow execution by remote clients without @@ -34,8 +36,7 @@ #define FCVAR_NEVER_AS_STRING (1 << 12) // never try to print that cvar // It's a ConVar that's shared between the client and the server. -// At signon, the values of all such ConVars are sent from the server to the client (skipped for local -// client, of course ) +// At signon, the values of all such ConVars are sent from the server to the client (skipped for local client, of course ) // If a change is requested it must come from the console (i.e., no remote client changes) // If a value is changed while a server is active, it's replicated to all connected clients #define FCVAR_REPLICATED (1 << 13) // server setting enforced on clients, TODO rename to FCAR_SERVER at some time @@ -66,52 +67,77 @@ // #define FCVAR_AVAILABLE (1<<27) // #define FCVAR_AVAILABLE (1<<31) +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; class ConCommand; +class ConVar; -// still need to map out functions and that for this, would be nice to be able to get actual values out of these in native -// also i sure do hope this size is right because there's a fairly decent chance it isn't +//----------------------------------------------------------------------------- +// Purpose: A console variable +//----------------------------------------------------------------------------- class ConVar { public: - // if there are ever crashes caused by modifying custom cvars, check this - unsigned char unknown[0x40]; - char* m_pszString; - size_t m_StringLength; - float m_fValue; - int32_t m_nValue; - unsigned char unknown2[0x28]; - - public: - virtual void EngineDestructor(void) {} - virtual bool IsCommand(void) const { return false; } - virtual bool IsFlagSet(int flag) { return false; } - virtual void AddFlags(int flags) {} - virtual void RemoveFlags(int flags) {} - virtual int GetFlags() const { return 0; } - virtual const char* GetName(void) const { return nullptr; } - virtual const char* GetHelpText(void) const { return nullptr; } - virtual bool IsRegistered(void) const { return false; } -}; - -class ICvar -{ - public: - struct VTable + ConVar(void){}; + ConVar(const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString); + ConVar( + const char* pszName, const char* pszDefaultValue, int nFlags, const char* pszHelpString, bool bMin, float fMin, bool bMax, + float fMax, void* pCallback); + ~ConVar(void); + + const char* GetBaseName(void) const; + const char* GetHelpText(void) const; + + void AddFlags(int nFlags); + void RemoveFlags(int nFlags); + + bool GetBool(void) const; + float GetFloat(void) const; + int GetInt(void) const; + Color GetColor(void) const; + const char* GetString(void) const; + + bool GetMin(float& flMinValue) const; + bool GetMax(float& flMaxValue) const; + float GetMinValue(void) const; + float GetMaxValue(void) const; + + bool HasMin(void) const; + bool HasMax(void) const; + + void SetValue(int nValue); + void SetValue(float flValue); + void SetValue(const char* pszValue); + void SetValue(Color clValue); + + void ChangeStringValue(const char* pszTempValue, float flOldValue); + bool SetColorFromString(const char* pszValue); + bool ClampValue(float& value); + + bool IsRegistered(void) const; + bool IsCommand(void) const; + static bool IsFlagSet(ConVar* pConVar, int nFlags); + + struct CVValue_t { - // void* unknown[10]; - // void(*UnregisterConCommand) (ICvar* cvar, ConCommand* pCommandBase); - // void* unknown2[28]; - // ConVar*(*FindVar)(const char* var_name); // offset for this is currently very wrong - char* unknown[112]; - ConCommand* (*FindCommandBase)(ICvar* self, const char* varName); // this offset is also wrong for some reason + const char* m_pszString; + int64_t m_iStringLength; + float m_fValue; + int m_nValue; }; - VTable* m_vtable; -}; + ConCommandBase m_ConCommandBase{}; // 0x0000 + ConVar* m_pParent{}; // 0x0040 + CVValue_t m_Value{}; // 0x0048 + bool m_bHasMin{}; // 0x005C + float m_fMinVal{}; // 0x0060 + bool m_bHasMax{}; // 0x0064 + float m_fMaxVal{}; // 0x0068 + void* m_pMalloc{}; // 0x0070 + char m_pPad80[10]{}; // 0x0080 +}; // Size: 0x0080 -ConVar* RegisterConVar(const char* name, const char* defaultValue, int flags, const char* helpString); -ConVar* FindConVar(const char* name); void InitialiseConVars(HMODULE baseAddress); - -extern std::unordered_map<std::string, ConVar*> g_CustomConvars; -extern SourceInterface<ICvar>* g_pCvar;
\ No newline at end of file +extern std::unordered_map<std::string, ConVar*> g_CustomConvars;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/cvar.cpp b/NorthstarDedicatedTest/cvar.cpp new file mode 100644 index 00000000..7f8c35d7 --- /dev/null +++ b/NorthstarDedicatedTest/cvar.cpp @@ -0,0 +1,65 @@ +#include "pch.h" +#include "cvar.h" +#include "convar.h" +#include "concommand.h" + +//----------------------------------------------------------------------------- +// Purpose: finds base commands. +// Input : *pszCommandName - +//----------------------------------------------------------------------------- +ConCommandBase* CCvar::FindCommandBase(const char* pszCommandName) +{ + static int index = 14; + return CallVFunc<ConCommandBase*>(index, this, pszCommandName); +} + +//----------------------------------------------------------------------------- +// Purpose: finds ConVars. +// Input : *pszVarName - +//----------------------------------------------------------------------------- +ConVar* CCvar::FindVar(const char* pszVarName) +{ + static int index = 16; + return CallVFunc<ConVar*>(index, this, pszVarName); +} + +//----------------------------------------------------------------------------- +// Purpose: finds ConCommands. +// Input : *pszCommandName - +//----------------------------------------------------------------------------- +ConCommand* CCvar::FindCommand(const char* pszCommandName) +{ + static int index = 18; + return CallVFunc<ConCommand*>(index, this, pszCommandName); +} + +//----------------------------------------------------------------------------- +// Purpose: iterates over all ConVars +//----------------------------------------------------------------------------- +CCVarIteratorInternal* CCvar::FactoryInternalIterator() +{ + static int index = 41; + return CallVFunc<CCVarIteratorInternal*>(index, this); +} + +//----------------------------------------------------------------------------- +// Purpose: returns all ConVars +//----------------------------------------------------------------------------- +std::unordered_map<std::string, ConCommandBase*> CCvar::DumpToMap() +{ + std::stringstream ss; + CCVarIteratorInternal* itint = FactoryInternalIterator(); // Allocate new InternalIterator. + + std::unordered_map<std::string, ConCommandBase*> allConVars; + + for (itint->SetFirst(); itint->IsValid(); itint->Next()) // Loop through all instances. + { + ConCommandBase* pCommand = itint->Get(); + const char* pszCommandName = pCommand->m_pszName; + allConVars[pszCommandName] = pCommand; + } + + return allConVars; +} +SourceInterface<CCvar>* g_pCVarInterface; +CCvar* g_pCVar;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/cvar.h b/NorthstarDedicatedTest/cvar.h new file mode 100644 index 00000000..43b13bfb --- /dev/null +++ b/NorthstarDedicatedTest/cvar.h @@ -0,0 +1,37 @@ +#pragma once +#include "convar.h" + +//----------------------------------------------------------------------------- +// Forward declarations +//----------------------------------------------------------------------------- +class ConCommandBase; +class ConCommand; +class ConVar; + +//----------------------------------------------------------------------------- +// Internals for ICVarIterator +//----------------------------------------------------------------------------- +class CCVarIteratorInternal // Fully reversed table, just look at the virtual function table and rename the function. +{ + public: + virtual void SetFirst(void) = 0; // 0 + virtual void Next(void) = 0; // 1 + virtual bool IsValid(void) = 0; // 2 + virtual ConCommandBase* Get(void) = 0; // 3 +}; + +//----------------------------------------------------------------------------- +// Default implementation +//----------------------------------------------------------------------------- +class CCvar +{ + public: + ConCommandBase* FindCommandBase(const char* pszCommandName); + ConVar* FindVar(const char* pszVarName); + ConCommand* FindCommand(const char* pszCommandName); + CCVarIteratorInternal* FactoryInternalIterator(); + std::unordered_map<std::string, ConCommandBase*> DumpToMap(); +}; + +extern SourceInterface<CCvar>* g_pCVarInterface; +extern CCvar* g_pCVar;
\ No newline at end of file diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 39f683e6..35d45800 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -42,7 +42,7 @@ void RunServer(CDedicatedExports* dedicated) // add +map if not present // don't manually execute this from cbuf as users may have it in their startup args anyway, easier just to run from stuffcmds if present if (!CommandLine()->CheckParm("+map")) - CommandLine()->AppendParm("+map", Cvar_match_defaultMap->m_pszString); + CommandLine()->AppendParm("+map", Cvar_match_defaultMap->GetString()); // run server autoexec and re-run commandline Cbuf_AddText(Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", cmd_source_t::kCommandSrcCode); @@ -78,8 +78,8 @@ void RunServer(CDedicatedExports* dedicated) .c_str()); } - std::this_thread::sleep_for( - std::chrono::duration<double, std::ratio<1>>(Cvar_base_tickinterval_mp->m_fValue - fmin(Plat_FloatTime() - frameStart, 0.25))); + std::this_thread::sleep_for(std::chrono::duration<double, std::ratio<1>>( + Cvar_base_tickinterval_mp->GetFloat() - fmin(Plat_FloatTime() - frameStart, 0.25))); } } diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp index f9fd4d95..b8194397 100644 --- a/NorthstarDedicatedTest/gameutils.cpp +++ b/NorthstarDedicatedTest/gameutils.cpp @@ -60,9 +60,6 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) g_pEngine = *(CEngine**)((char*)baseAddress + 0x7D70C8); sv_m_State = (server_state_t*)((char*)baseAddress + 0x12A53D48); - Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); - Cvar_net_datablock_enabled = (ConVar*)((char*)baseAddress + 0x12A4F6D0); - GetCurrentPlaylistName = (GetCurrentPlaylistType)((char*)baseAddress + 0x18C640); SetCurrentPlaylist = (SetCurrentPlaylistType)((char*)baseAddress + 0x18EB20); SetPlaylistVarOverride = (SetPlaylistVarOverrideType)((char*)baseAddress + 0x18ED00); @@ -71,10 +68,26 @@ void InitialiseEngineGameUtilFunctions(HMODULE baseAddress) g_LocalPlayerUserID = (char*)baseAddress + 0x13F8E688; g_LocalPlayerOriginToken = (char*)baseAddress + 0x13979C80; + GetBaseLocalClient = (GetBaseLocalClientType)((char*)baseAddress + 0x78200); + + /* NOTE: + g_pCVar->FindVar("convar_name") now works. These are no longer needed. + You can also itterate over every ConVar using CCVarIteratorInternal + dump the pointers to a vector and access them from there. + Example: + std::vector<ConVar*> g_pAllConVars; + for (auto& map : g_pCVar->DumpToMap()) + { + ConVar* pConVar = g_pCVar->FindVar(map.first.c_str()); + if (pConVar) + { + g_pAllConVars.push_back(pConVar); + } + }*/ + Cvar_hostport = (ConVar*)((char*)baseAddress + 0x13FA6070); + Cvar_net_datablock_enabled = (ConVar*)((char*)baseAddress + 0x12A4F6D0); Cvar_match_defaultMap = (ConVar*)((char*)baseAddress + 0x8AB530); Cvar_communities_hostname = (ConVar*)((char*)baseAddress + 0x13157E50); - - GetBaseLocalClient = (GetBaseLocalClientType)((char*)baseAddress + 0x78200); } void InitialiseServerGameUtilFunctions(HMODULE baseAddress) diff --git a/NorthstarDedicatedTest/latencyflex.cpp b/NorthstarDedicatedTest/latencyflex.cpp index 4772b78a..a677b6d2 100644 --- a/NorthstarDedicatedTest/latencyflex.cpp +++ b/NorthstarDedicatedTest/latencyflex.cpp @@ -15,7 +15,7 @@ PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame{}; void OnRenderStartHook() { - if (Cvar_r_latencyflex->m_nValue) + if (Cvar_r_latencyflex->GetInt()) m_winelfx_WaitAndBeginFrame(); OnRenderStart(); @@ -41,7 +41,7 @@ void InitialiseLatencyFleX(HMODULE baseAddress) reinterpret_cast<PFN_winelfx_WaitAndBeginFrame>(reinterpret_cast<void*>(GetProcAddress(m_lfxModule, "winelfx_WaitAndBeginFrame"))); spdlog::info("LatencyFleX initialized."); - Cvar_r_latencyflex = RegisterConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction."); + Cvar_r_latencyflex = new ConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction."); HookEnabler hook; ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1952C0, &OnRenderStartHook, reinterpret_cast<LPVOID*>(&OnRenderStart)); diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index ec46bedc..4d31981e 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -230,7 +230,7 @@ EngineSpewFuncType EngineSpewFunc; void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format, va_list args) { - if (!Cvar_spewlog_enable->m_nValue) + if (!Cvar_spewlog_enable->GetBool()) return; const char* typeStr; @@ -390,8 +390,7 @@ void InitialiseEngineSpewFuncHooks(HMODULE baseAddress) hook, (char*)baseAddress + 0x1A1530, CClientState_ProcessPrint_Hook, reinterpret_cast<LPVOID*>(&CClientState_ProcessPrint_Original)); - Cvar_spewlog_enable = - RegisterConVar("spewlog_enable", "1", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged"); + Cvar_spewlog_enable = new ConVar("spewlog_enable", "1", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged"); } #include "bitbuf.h" @@ -422,7 +421,7 @@ void TextMsgHook(BFRead* msg) char text[256]; msg->ReadString(text, sizeof(text)); - if (!Cvar_cl_showtextmsg->m_nValue) + if (!Cvar_cl_showtextmsg->GetBool()) return; switch (msg_dest) @@ -451,5 +450,5 @@ void InitialiseClientPrintHooks(HMODULE baseAddress) // "TextMsg" usermessage ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x198710, TextMsgHook, reinterpret_cast<LPVOID*>(&TextMsg_Original)); - Cvar_cl_showtextmsg = RegisterConVar("cl_showtextmsg", "1", FCVAR_NONE, "Enable/disable text messages printing on the screen."); + Cvar_cl_showtextmsg = new ConVar("cl_showtextmsg", "1", FCVAR_NONE, "Enable/disable text messages printing on the screen."); }
\ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index cfb92409..b08ebb90 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -105,8 +105,8 @@ std::string unescape_unicode(const std::string& str) void UpdateServerInfoFromUnicodeToUTF8() { - g_MasterServerManager->ns_auth_srvName = unescape_unicode(Cvar_ns_server_name->m_pszString); - g_MasterServerManager->ns_auth_srvDesc = unescape_unicode(Cvar_ns_server_desc->m_pszString); + g_MasterServerManager->ns_auth_srvName = unescape_unicode(Cvar_ns_server_name->GetString()); + g_MasterServerManager->ns_auth_srvDesc = unescape_unicode(Cvar_ns_server_desc->GetString()); } const char* HttplibErrorToString(httplib::Error error) @@ -214,7 +214,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or std::string readBuffer; curl_easy_setopt( curl, CURLOPT_URL, - fmt::format("{}/client/origin_auth?id={}&token={}", Cvar_ns_masterserver_hostname->m_pszString, uidStr, tokenStr).c_str()); + fmt::format("{}/client/origin_auth?id={}&token={}", Cvar_ns_masterserver_hostname->GetString(), uidStr, tokenStr).c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); @@ -283,13 +283,13 @@ void MasterServerManager::RequestServerList() m_requestingServerList = true; m_scriptRequestingServerList = true; - spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->m_pszString); + spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->GetString()); CURL* curl = curl_easy_init(); SetCommonHttpClientOptions(curl); std::string readBuffer; - curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/servers", Cvar_ns_masterserver_hostname->m_pszString).c_str()); + curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/servers", Cvar_ns_masterserver_hostname->GetString()).c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); @@ -437,7 +437,7 @@ void MasterServerManager::RequestMainMenuPromos() std::string readBuffer; curl_easy_setopt( - curl, CURLOPT_URL, fmt::format("{}/client/mainmenupromos", Cvar_ns_masterserver_hostname->m_pszString).c_str()); + curl, CURLOPT_URL, fmt::format("{}/client/mainmenupromos", Cvar_ns_masterserver_hostname->GetString()).c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); @@ -555,7 +555,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken std::string readBuffer; curl_easy_setopt( curl, CURLOPT_URL, - fmt::format("{}/client/auth_with_self?id={}&playerToken={}", Cvar_ns_masterserver_hostname->m_pszString, uidStr, tokenStr) + fmt::format("{}/client/auth_with_self?id={}&playerToken={}", Cvar_ns_masterserver_hostname->GetString(), uidStr, tokenStr) .c_str()); curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback); @@ -696,7 +696,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c curl_easy_setopt( curl, CURLOPT_URL, fmt::format( - "{}/client/auth_with_server?id={}&playerToken={}&server={}&password={}", Cvar_ns_masterserver_hostname->m_pszString, + "{}/client/auth_with_server?id={}&playerToken={}&server={}&password={}", Cvar_ns_masterserver_hostname->GetString(), uidStr, tokenStr, serverIdStr, escapedPassword) .c_str()); @@ -777,10 +777,10 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c void MasterServerManager::AddSelfToServerList( int port, int authPort, char* name, char* description, char* map, char* playlist, int maxPlayers, char* password) { - if (!Cvar_ns_report_server_to_masterserver->m_nValue) + if (!Cvar_ns_report_server_to_masterserver->GetBool()) return; - if (!Cvar_ns_report_sp_server_to_masterserver->m_nValue && !strncmp(map, "sp_", 3)) + if (!Cvar_ns_report_sp_server_to_masterserver->GetBool() && !strncmp(map, "sp_", 3)) { m_bRequireClientAuth = false; return; @@ -830,7 +830,7 @@ void MasterServerManager::AddSelfToServerList( curl, CURLOPT_URL, fmt::format( "{}/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}", - Cvar_ns_masterserver_hostname->m_pszString, port, authPort, nameEscaped, descEscaped, mapEscaped, playlistEscaped, + Cvar_ns_masterserver_hostname->GetString(), port, authPort, nameEscaped, descEscaped, mapEscaped, playlistEscaped, maxPlayers, passwordEscaped) .c_str()); @@ -915,7 +915,7 @@ void MasterServerManager::AddSelfToServerList( char* escapedDescNew = curl_easy_escape(curl, g_MasterServerManager->ns_auth_srvDesc.c_str(), NULL); char* escapedMapNew = curl_easy_escape(curl, g_pHostState->m_levelName, NULL); char* escapedPlaylistNew = curl_easy_escape(curl, GetCurrentPlaylistName(), NULL); - char* escapedPasswordNew = curl_easy_escape(curl, Cvar_ns_server_password->m_pszString, NULL); + char* escapedPasswordNew = curl_easy_escape(curl, Cvar_ns_server_password->GetString(), NULL); int maxPlayers = 6; char* maxPlayersVar = GetCurrentPlaylistVar("max_players", false); @@ -928,8 +928,8 @@ void MasterServerManager::AddSelfToServerList( "{}/server/" "update_values?id={}&port={}&authPort={}&name={}&description={}&map={}&playlist={}&playerCount={}&" "maxPlayers={}&password={}", - Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, Cvar_hostport->m_nValue, - Cvar_ns_player_auth_port->m_nValue, escapedNameNew, escapedDescNew, escapedMapNew, + Cvar_ns_masterserver_hostname->GetString(), m_ownServerId, Cvar_hostport->GetInt(), + Cvar_ns_player_auth_port->GetInt(), escapedNameNew, escapedDescNew, escapedMapNew, escapedPlaylistNew, g_ServerAuthenticationManager->m_additionalPlayerData.size(), maxPlayers, escapedPasswordNew) .c_str()); @@ -1026,7 +1026,7 @@ void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist, curl_easy_setopt( curl, CURLOPT_URL, fmt::format( - "{}/server/update_values?id={}&map={}&playlist={}&maxPlayers={}", Cvar_ns_masterserver_hostname->m_pszString, + "{}/server/update_values?id={}&map={}&playlist={}&maxPlayers={}", Cvar_ns_masterserver_hostname->GetString(), m_ownServerId, mapEscaped, playlistEscaped, maxPlayers) .c_str()); @@ -1066,7 +1066,7 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount) curl_easy_setopt( curl, CURLOPT_URL, fmt::format( - "{}/server/update_values?id={}&playerCount={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, playerCount) + "{}/server/update_values?id={}&playerCount={}", Cvar_ns_masterserver_hostname->GetString(), m_ownServerId, playerCount) .c_str()); CURLcode result = curl_easy_perform(curl); @@ -1105,7 +1105,7 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata, curl_easy_setopt( curl, CURLOPT_URL, fmt::format( - "{}/accounts/write_persistence?id={}&serverId={}", Cvar_ns_masterserver_hostname->m_pszString, strPlayerId, + "{}/accounts/write_persistence?id={}&serverId={}", Cvar_ns_masterserver_hostname->GetString(), strPlayerId, m_ownServerId) .c_str()); curl_easy_setopt(curl, CURLOPT_POST, 1L); @@ -1140,7 +1140,7 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata, void MasterServerManager::RemoveSelfFromServerList() { // dont call this if we don't have a server id - if (!*m_ownServerId || !Cvar_ns_report_server_to_masterserver->m_nValue) + if (!*m_ownServerId || !Cvar_ns_report_server_to_masterserver->GetBool()) return; std::thread requestThread( @@ -1155,7 +1155,7 @@ void MasterServerManager::RemoveSelfFromServerList() curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer); curl_easy_setopt( curl, CURLOPT_URL, - fmt::format("{}/server/remove_server?id={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId).c_str()); + fmt::format("{}/server/remove_server?id={}", Cvar_ns_masterserver_hostname->GetString(), m_ownServerId).c_str()); CURLcode result = curl_easy_perform(curl); @@ -1197,14 +1197,14 @@ void CHostState__State_NewGameHook(CHostState* hostState) maxPlayers = std::stoi(maxPlayersVar); // Copy new server name cvar to source - Cvar_hostname->m_pszString = Cvar_ns_server_name->m_pszString; - Cvar_hostname->m_StringLength = Cvar_ns_server_name->m_StringLength; + Cvar_hostname->SetValue(Cvar_ns_server_name->GetString()); // This calls the function that converts unicode strings from servername and serverdesc to UTF-8 UpdateServerInfoFromUnicodeToUTF8(); g_MasterServerManager->AddSelfToServerList( - Cvar_hostport->m_nValue, Cvar_ns_player_auth_port->m_nValue, Cvar_ns_server_name->m_pszString, Cvar_ns_server_desc->m_pszString, - hostState->m_levelName, (char*)GetCurrentPlaylistName(), maxPlayers, Cvar_ns_server_password->m_pszString); + Cvar_hostport->GetInt(), Cvar_ns_player_auth_port->GetInt(), (char*)Cvar_ns_server_name->GetString(), + (char*)Cvar_ns_server_desc->GetString(), hostState->m_levelName, (char*)GetCurrentPlaylistName(), maxPlayers, + (char*)Cvar_ns_server_password->GetString()); g_ServerAuthenticationManager->StartPlayerAuthServer(); g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = false; } @@ -1255,15 +1255,15 @@ MasterServerManager::MasterServerManager() : m_pendingConnectionInfo{}, m_ownSer void InitialiseSharedMasterServer(HMODULE baseAddress) { - Cvar_ns_masterserver_hostname = RegisterConVar("ns_masterserver_hostname", "127.0.0.1", FCVAR_NONE, ""); + Cvar_ns_masterserver_hostname = new ConVar("ns_masterserver_hostname", "127.0.0.1", FCVAR_NONE, ""); // unfortunately lib doesn't let us specify a port and still have https work - // Cvar_ns_masterserver_port = RegisterConVar("ns_masterserver_port", "8080", FCVAR_NONE, ""); + // Cvar_ns_masterserver_port = new ConVar("ns_masterserver_port", "8080", FCVAR_NONE, ""); - Cvar_ns_server_name = RegisterConVar("ns_server_name", "Unnamed Northstar Server", FCVAR_GAMEDLL, ""); - Cvar_ns_server_desc = RegisterConVar("ns_server_desc", "Default server description", FCVAR_GAMEDLL, ""); - Cvar_ns_server_password = RegisterConVar("ns_server_password", "", FCVAR_GAMEDLL, ""); - Cvar_ns_report_server_to_masterserver = RegisterConVar("ns_report_server_to_masterserver", "1", FCVAR_GAMEDLL, ""); - Cvar_ns_report_sp_server_to_masterserver = RegisterConVar("ns_report_sp_server_to_masterserver", "0", FCVAR_GAMEDLL, ""); + Cvar_ns_server_name = new ConVar("ns_server_name", "Unnamed Northstar Server", FCVAR_GAMEDLL, ""); + Cvar_ns_server_desc = new ConVar("ns_server_desc", "Default server description", FCVAR_GAMEDLL, ""); + Cvar_ns_server_password = new ConVar("ns_server_password", "", FCVAR_GAMEDLL, ""); + Cvar_ns_report_server_to_masterserver = new ConVar("ns_report_server_to_masterserver", "1", FCVAR_GAMEDLL, ""); + Cvar_ns_report_sp_server_to_masterserver = new ConVar("ns_report_sp_server_to_masterserver", "0", FCVAR_GAMEDLL, ""); Cvar_hostname = *(ConVar**)((char*)baseAddress + 0x1315bae8); diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp index 7e6322cb..4f2bb416 100644 --- a/NorthstarDedicatedTest/modmanager.cpp +++ b/NorthstarDedicatedTest/modmanager.cpp @@ -284,7 +284,7 @@ void ModManager::LoadMods() if (g_CustomConvars.find(convar->Name) == g_CustomConvars.end()) // make sure convar isn't registered yet, unsure if necessary but idk what behaviour is for defining // same convar multiple times - RegisterConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str()); + new ConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str()); // read vpk paths if (fs::exists(mod.ModDirectory / "vpk")) diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h index 653776ce..29d1fe8d 100644 --- a/NorthstarDedicatedTest/pch.h +++ b/NorthstarDedicatedTest/pch.h @@ -12,11 +12,22 @@ // add headers that you want to pre-compile here #include "memalloc.h" + #include <Windows.h> +#include <Psapi.h> +#include <set> +#include <filesystem> +#include <sstream> + #include "logging.h" #include "include/MinHook.h" #include "spdlog/spdlog.h" #include "libcurl/include/curl/curl.h" #include "hookutils.h" +template <typename ReturnType, typename... Args> ReturnType CallVFunc(int index, void* thisPtr, Args... args) +{ + return (*reinterpret_cast<ReturnType(__fastcall***)(void*, Args...)>(thisPtr))[index](thisPtr, args...); +} + #endif
\ No newline at end of file diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp index d885d6f0..249230c8 100644 --- a/NorthstarDedicatedTest/playlist.cpp +++ b/NorthstarDedicatedTest/playlist.cpp @@ -40,7 +40,7 @@ char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2) { // 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->m_nValue || strcmp(GetCurrentPlaylistName(), "private_match")) + if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(GetCurrentPlaylistName(), "private_match")) return 1; return Onclc_SetPlaylistVarOverride(a1, a2); @@ -80,7 +80,7 @@ void InitialisePlaylistHooks(HMODULE baseAddress) // 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 = RegisterConVar( + Cvar_ns_use_clc_SetPlaylistVarOverride = new ConVar( "ns_use_clc_SetPlaylistVarOverride", "0", FCVAR_GAMEDLL, "Whether the server should accept clc_SetPlaylistVarOverride messages"); HookEnabler hook; diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp index 57646218..8bbca125 100644 --- a/NorthstarDedicatedTest/serverauthentication.cpp +++ b/NorthstarDedicatedTest/serverauthentication.cpp @@ -87,11 +87,11 @@ void ServerAuthenticationManager::StartPlayerAuthServer() "/authenticate_incoming_player", [this](const httplib::Request& request, httplib::Response& response) { - // can't just do request.remote_addr == Cvar_ns_masterserver_hostname->m_pszString because the cvar can be a url, gotta + // can't just do request.remote_addr == Cvar_ns_masterserver_hostname->GetString() because the cvar can be a url, gotta // resolve an ip from it for comparisons // unsigned long remoteAddr = inet_addr(request.remote_addr.c_str()); // - // char* addrPtr = Cvar_ns_masterserver_hostname->m_pszString; + // char* addrPtr = Cvar_ns_masterserver_hostname->GetString(); // char* typeStart = strstr(addrPtr, "://"); // if (typeStart) // addrPtr = typeStart + 3; @@ -123,7 +123,7 @@ void ServerAuthenticationManager::StartPlayerAuthServer() response.set_content("{\"success\":true}", "application/json"); }); - m_playerAuthServer.listen("0.0.0.0", Cvar_ns_player_auth_port->m_nValue); + m_playerAuthServer.listen("0.0.0.0", Cvar_ns_player_auth_port->GetInt()); }); serverThread.detach(); @@ -191,7 +191,7 @@ bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid, // set persistent data as ready, we use 0x3 internally to mark the client as using local persistence *((char*)player + 0x4a0) = (char)0x3; - if (!CVar_ns_auth_allow_insecure->m_nValue) // no auth data and insecure connections aren't allowed, so dc the client + if (!CVar_ns_auth_allow_insecure->GetBool()) // no auth data and insecure connections aren't allowed, so dc the client return false; // insecure connections are allowed, try reading from disk @@ -223,7 +223,7 @@ bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid, bool ServerAuthenticationManager::RemovePlayerAuthData(void* player) { - if (!Cvar_ns_erase_auth_info->m_nValue) + if (!Cvar_ns_erase_auth_info->GetBool()) return false; // hack for special case where we're on a local server, so we erase our own newly created auth data on disconnect @@ -256,7 +256,7 @@ void ServerAuthenticationManager::WritePersistentData(void* player) g_MasterServerManager->WritePlayerPersistentData( (char*)player + 0xF500, (char*)player + 0x4FA, m_additionalPlayerData[player].pdataSize); } - else if (CVar_ns_auth_allow_insecure_write->m_nValue) + else if (CVar_ns_auth_allow_insecure_write->GetBool()) { // todo: write pdata to disk here } @@ -270,7 +270,7 @@ bool ServerAuthenticationManager::CheckPlayerChatRatelimit(void* player) m_additionalPlayerData[player].sayTextLimitCount = 0; } - if (m_additionalPlayerData[player].sayTextLimitCount >= Cvar_sv_max_chat_messages_per_sec->m_nValue) + if (m_additionalPlayerData[player].sayTextLimitCount >= Cvar_sv_max_chat_messages_per_sec->GetInt()) return false; m_additionalPlayerData[player].sayTextLimitCount++; @@ -380,7 +380,7 @@ CCommand__TokenizeType CCommand__Tokenize; char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const char* pCommandString) { - if (CVar_sv_quota_stringcmdspersecond->m_nValue != -1) + if (CVar_sv_quota_stringcmdspersecond->GetInt() != -1) { // note: this isn't super perfect, legit clients can trigger it in lobby, mostly good enough tho imo // https://github.com/perilouswithadollarsign/cstrike15_src/blob/f82112a2388b841d72cb62ca48ab1846dfcc11c8/engine/sv_client.cpp#L1513 @@ -393,7 +393,7 @@ char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const c g_ServerAuthenticationManager->m_additionalPlayerData[self].numClientCommandsInQuota++; if (g_ServerAuthenticationManager->m_additionalPlayerData[self].numClientCommandsInQuota > - CVar_sv_quota_stringcmdspersecond->m_nValue) + CVar_sv_quota_stringcmdspersecond->GetInt()) { // too many stringcmds, dc player CBaseClient__Disconnect(self, 1, "Sent too many stringcmd commands"); @@ -409,7 +409,7 @@ char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const c if (!CCommand__Tokenize(tempCommand, pCommandString, cmd_source_t::kCommandSrcCode) || !tempCommand.ArgC()) return false; - ConCommand* command = FindConCommand(tempCommand.Arg(0)); + ConCommand* command = g_pCVar->FindCommand(tempCommand.Arg(0)); // if the command doesn't exist pass it on to ExecuteStringCommand for script clientcommands and stuff if (command && !command->IsFlagSet(FCVAR_CLIENTCMD_CAN_EXECUTE)) @@ -422,7 +422,7 @@ char CGameClient__ExecuteStringCommandHook(void* self, uint32_t unknown, const c return false; } - // todo later, basically just limit to CVar_sv_quota_stringcmdspersecond->m_nValue stringcmds per client per second + // todo later, basically just limit to CVar_sv_quota_stringcmdspersecond->GetInt() stringcmds per client per second return CGameClient__ExecuteStringCommand(self, unknown, pCommandString); } @@ -453,15 +453,15 @@ char __fastcall CNetChan___ProcessMessagesHook(void* self, void* buf) (Plat_FloatTime() * 1000) - (startTime * 1000); if (g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime >= - Cvar_net_chan_limit_msec_per_sec->m_nValue) + Cvar_net_chan_limit_msec_per_sec->GetInt()) { spdlog::warn( "Client {} hit netchan processing limit with {}ms of processing time this second (max is {})", (char*)sender + 0x16, g_ServerAuthenticationManager->m_additionalPlayerData[sender].netChanProcessingLimitTime, - Cvar_net_chan_limit_msec_per_sec->m_nValue); + Cvar_net_chan_limit_msec_per_sec->GetInt()); // nonzero = kick, 0 = warn - if (Cvar_net_chan_limit_mode->m_nValue) + if (Cvar_net_chan_limit_mode->GetInt()) { CBaseClient__Disconnect(sender, 1, "Exceeded net channel processing limit"); return false; @@ -486,7 +486,7 @@ void CBaseClient__SendServerInfoHook(void* self) bool ProcessConnectionlessPacketHook(void* a1, netpacket_t* packet) { if (packet->adr.type == NA_IP && - (!(packet->data[4] == 'N' && Cvar_net_datablock_enabled->m_nValue) || !Cvar_net_datablock_enabled->m_nValue)) + (!(packet->data[4] == 'N' && Cvar_net_datablock_enabled->GetBool()) || !Cvar_net_datablock_enabled->GetBool())) { // bad lookup: optimise later tm UnconnectedPlayerSendData* sendData = nullptr; @@ -516,10 +516,10 @@ bool ProcessConnectionlessPacketHook(void* a1, netpacket_t* packet) sendData->packetCount++; - if (sendData->packetCount >= Cvar_sv_querylimit_per_sec->m_nValue) + if (sendData->packetCount >= Cvar_sv_querylimit_per_sec->GetInt()) { spdlog::warn( - "Client went over connectionless ratelimit of {} per sec with packet of type {}", Cvar_sv_querylimit_per_sec->m_nValue, + "Client went over connectionless ratelimit of {} per sec with packet of type {}", Cvar_sv_querylimit_per_sec->GetInt(), packet->data[4]); // timeout for a minute @@ -547,26 +547,26 @@ void InitialiseServerAuthentication(HMODULE baseAddress) { g_ServerAuthenticationManager = new ServerAuthenticationManager; - Cvar_ns_erase_auth_info = RegisterConVar( - "ns_erase_auth_info", "1", FCVAR_GAMEDLL, "Whether auth info should be erased from this server on disconnect or crash"); + Cvar_ns_erase_auth_info = + new ConVar("ns_erase_auth_info", "1", FCVAR_GAMEDLL, "Whether auth info should be erased from this server on disconnect or crash"); CVar_ns_auth_allow_insecure = - RegisterConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect"); - CVar_ns_auth_allow_insecure_write = RegisterConVar( + new ConVar("ns_auth_allow_insecure", "0", FCVAR_GAMEDLL, "Whether this server will allow unauthenicated players to connect"); + CVar_ns_auth_allow_insecure_write = new ConVar( "ns_auth_allow_insecure_write", "0", FCVAR_GAMEDLL, "Whether the pdata of unauthenticated clients will be written to disk when changed"); // literally just stolen from a fix valve used in csgo - CVar_sv_quota_stringcmdspersecond = RegisterConVar( + CVar_sv_quota_stringcmdspersecond = new ConVar( "sv_quota_stringcmdspersecond", "60", FCVAR_GAMEDLL, "How many string commands per second clients are allowed to submit, 0 to disallow all string commands"); // https://blog.counter-strike.net/index.php/2019/07/24922/ but different because idk how to check what current tick number is Cvar_net_chan_limit_mode = - RegisterConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = log, 1 = kick"); - Cvar_net_chan_limit_msec_per_sec = RegisterConVar( + new ConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = log, 1 = kick"); + Cvar_net_chan_limit_msec_per_sec = new ConVar( "net_chan_limit_msec_per_sec", "0", FCVAR_GAMEDLL, "Netchannel processing is limited to so many milliseconds, abort connection if exceeding budget"); - Cvar_ns_player_auth_port = RegisterConVar("ns_player_auth_port", "8081", FCVAR_GAMEDLL, ""); - Cvar_sv_querylimit_per_sec = RegisterConVar("sv_querylimit_per_sec", "15", FCVAR_GAMEDLL, ""); - Cvar_sv_max_chat_messages_per_sec = RegisterConVar("sv_max_chat_messages_per_sec", "5", FCVAR_GAMEDLL, ""); + Cvar_ns_player_auth_port = new ConVar("ns_player_auth_port", "8081", FCVAR_GAMEDLL, ""); + Cvar_sv_querylimit_per_sec = new ConVar("sv_querylimit_per_sec", "15", FCVAR_GAMEDLL, ""); + Cvar_sv_max_chat_messages_per_sec = new ConVar("sv_max_chat_messages_per_sec", "5", FCVAR_GAMEDLL, ""); RegisterConCommand("ns_resetpersistence", ResetPdataCommand, "resets your pdata when you next enter the lobby", FCVAR_NONE); diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp index e6f46c13..2ce45baa 100644 --- a/NorthstarDedicatedTest/sourceconsole.cpp +++ b/NorthstarDedicatedTest/sourceconsole.cpp @@ -1,4 +1,5 @@ #include "pch.h" +#include "convar.h" #include "sourceconsole.h" #include "sourceinterface.h" #include "concommand.h" |