aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDLL/shared
diff options
context:
space:
mode:
authorJack <66967891+ASpoonPlaysGames@users.noreply.github.com>2023-12-27 00:32:01 +0000
committerGitHub <noreply@github.com>2023-12-27 01:32:01 +0100
commitf5ab6fb5e8be7b73e6003d4145081d5e0c0ce287 (patch)
tree90f2c6a4885dbd181799e2325cf33588697674e1 /NorthstarDLL/shared
parentbb8ed59f6891b1196c5f5bbe7346cd171c8215fa (diff)
downloadNorthstarLauncher-f5ab6fb5e8be7b73e6003d4145081d5e0c0ce287.tar.gz
NorthstarLauncher-f5ab6fb5e8be7b73e6003d4145081d5e0c0ce287.zip
Folder restructuring from primedev (#624)v1.21.2-rc3v1.21.2
Copies of over the primedev folder structure for easier cherry-picking of further changes Co-authored-by: F1F7Y <filip.bartos07@proton.me>
Diffstat (limited to 'NorthstarDLL/shared')
-rw-r--r--NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp461
-rw-r--r--NorthstarDLL/shared/exploit_fixes/exploitfixes_lzss.cpp78
-rw-r--r--NorthstarDLL/shared/exploit_fixes/exploitfixes_utf8parser.cpp199
-rw-r--r--NorthstarDLL/shared/exploit_fixes/ns_limits.cpp298
-rw-r--r--NorthstarDLL/shared/exploit_fixes/ns_limits.h52
-rw-r--r--NorthstarDLL/shared/keyvalues.cpp1322
-rw-r--r--NorthstarDLL/shared/keyvalues.h134
-rw-r--r--NorthstarDLL/shared/maxplayers.cpp640
-rw-r--r--NorthstarDLL/shared/maxplayers.h3
-rw-r--r--NorthstarDLL/shared/misccommands.cpp391
-rw-r--r--NorthstarDLL/shared/misccommands.h3
-rw-r--r--NorthstarDLL/shared/playlist.cpp125
-rw-r--r--NorthstarDLL/shared/playlist.h10
13 files changed, 0 insertions, 3716 deletions
diff --git a/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp b/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp
deleted file mode 100644
index 8064d5ac..00000000
--- a/NorthstarDLL/shared/exploit_fixes/exploitfixes.cpp
+++ /dev/null
@@ -1,461 +0,0 @@
-#include "core/convar/cvar.h"
-#include "ns_limits.h"
-#include "dedicated/dedicated.h"
-#include "core/tier0.h"
-#include "engine/r2engine.h"
-#include "client/r2client.h"
-#include "core/math/vector.h"
-#include "core/vanilla.h"
-
-AUTOHOOK_INIT()
-
-ConVar* Cvar_ns_exploitfixes_log;
-ConVar* Cvar_ns_should_log_all_clientcommands;
-
-ConVar* Cvar_sv_cheats;
-
-#define BLOCKED_INFO(s) \
- ( \
- [=]() -> bool \
- { \
- if (Cvar_ns_exploitfixes_log->GetBool()) \
- { \
- std::stringstream stream; \
- stream << "ExploitFixes.cpp: " << BLOCK_PREFIX << s; \
- spdlog::error(stream.str()); \
- } \
- return false; \
- }())
-
-// block bad netmessages
-// Servers can literally request a screenshot from any client, yeah no
-// clang-format off
-AUTOHOOK(CLC_Screenshot_WriteToBuffer, engine.dll + 0x22AF20,
-bool, __fastcall, (void* thisptr, void* buffer)) // 48 89 5C 24 ? 57 48 83 EC 20 8B 42 10
-// clang-format on
-{
- if (g_pVanillaCompatibility->GetVanillaCompatibility())
- return CLC_Screenshot_WriteToBuffer(thisptr, buffer);
- return false;
-}
-
-// clang-format off
-AUTOHOOK(CLC_Screenshot_ReadFromBuffer, engine.dll + 0x221F00,
-bool, __fastcall, (void* thisptr, void* buffer)) // 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 48 83 EC 20 48 8B DA 48 8B 52 38
-// clang-format on
-{
- if (g_pVanillaCompatibility->GetVanillaCompatibility())
- return CLC_Screenshot_ReadFromBuffer(thisptr, buffer);
- return false;
-}
-
-// This is unused ingame and a big client=>server=>client exploit vector
-// clang-format off
-AUTOHOOK(Base_CmdKeyValues_ReadFromBuffer, engine.dll + 0x220040,
-bool, __fastcall, (void* thisptr, void* buffer)) // 40 55 48 81 EC ? ? ? ? 48 8D 6C 24 ? 48 89 5D 70
-// clang-format on
-{
- return false;
-}
-
-// clang-format off
-AUTOHOOK(CClient_ProcessSetConVar, engine.dll + 0x75CF0,
-bool, __fastcall, (void* pMsg)) // 48 8B D1 48 8B 49 18 48 8B 01 48 FF 60 10
-// clang-format on
-{
-
- constexpr int ENTRY_STR_LEN = 260;
- struct SetConVarEntry
- {
- char name[ENTRY_STR_LEN];
- char val[ENTRY_STR_LEN];
- };
-
- struct NET_SetConVar
- {
- void* vtable;
- void* unk1;
- void* unk2;
- void* m_pMessageHandler;
- SetConVarEntry* m_ConVars; // convar entry array
- void* unk5; // these 2 unks are just vector capacity or whatever
- void* unk6;
- int m_ConVars_count; // amount of cvar entries in array (this will not be out of bounds)
- };
-
- auto msg = (NET_SetConVar*)pMsg;
- bool bIsServerFrame = ThreadInServerFrameThread();
-
- std::string BLOCK_PREFIX =
- std::string {"NET_SetConVar ("} + (bIsServerFrame ? "server" : "client") + "): Blocked dangerous/invalid msg: ";
-
- if (bIsServerFrame)
- {
- constexpr int SETCONVAR_SANITY_AMOUNT_LIMIT = 69;
- if (msg->m_ConVars_count < 1 || msg->m_ConVars_count > SETCONVAR_SANITY_AMOUNT_LIMIT)
- {
- return BLOCKED_INFO("Invalid m_ConVars_count (" << msg->m_ConVars_count << ")");
- }
- }
-
- for (int i = 0; i < msg->m_ConVars_count; i++)
- {
- auto entry = msg->m_ConVars + i;
-
- // Safety check for memory access
- if (CMemoryAddress(entry).IsMemoryReadable(sizeof(*entry)))
- {
- // Find null terminators
- bool nameValid = false, valValid = false;
- for (int i = 0; i < ENTRY_STR_LEN; i++)
- {
- if (!entry->name[i])
- nameValid = true;
- if (!entry->val[i])
- valValid = true;
- }
-
- if (!nameValid || !valValid)
- return BLOCKED_INFO("Missing null terminators");
-
- ConVar* pVar = g_pCVar->FindVar(entry->name);
-
- if (pVar)
- {
- memcpy(
- entry->name,
- pVar->m_ConCommandBase.m_pszName,
- strlen(pVar->m_ConCommandBase.m_pszName) + 1); // Force name to match case
-
- int iFlags = bIsServerFrame ? FCVAR_USERINFO : FCVAR_REPLICATED;
- if (!pVar->IsFlagSet(iFlags))
- return BLOCKED_INFO(
- "Invalid flags (" << std::hex << "0x" << pVar->m_ConCommandBase.m_nFlags << "), var is " << entry->name);
- }
- }
- else
- {
- return BLOCKED_INFO("Unreadable memory at " << (void*)entry); // Not risking that one, they all gotta be readable
- }
- }
-
- return CClient_ProcessSetConVar(msg);
-}
-
-// prevent invalid user CMDs
-// clang-format off
-AUTOHOOK(CClient_ProcessUsercmds, engine.dll + 0x1040F0,
-bool, __fastcall, (void* thisptr, void* pMsg)) // 40 55 56 48 83 EC 58
-// clang-format on
-{
- struct CLC_Move
- {
- BYTE gap0[24];
- void* m_pMessageHandler;
- int m_nBackupCommands;
- int m_nNewCommands;
- int m_nLength;
- // bf_read m_DataIn;
- // bf_write m_DataOut;
- };
-
- auto msg = (CLC_Move*)pMsg;
-
- const char* BLOCK_PREFIX = "ProcessUserCmds: ";
-
- if (msg->m_nBackupCommands < 0)
- {
- return BLOCKED_INFO("Invalid m_nBackupCommands (" << msg->m_nBackupCommands << ")");
- }
-
- if (msg->m_nNewCommands < 0)
- {
- return BLOCKED_INFO("Invalid m_nNewCommands (" << msg->m_nNewCommands << ")");
- }
-
- if (msg->m_nLength <= 0)
- return BLOCKED_INFO("Invalid message length (" << msg->m_nLength << ")");
-
- return CClient_ProcessUsercmds(thisptr, pMsg);
-}
-
-// clang-format off
-AUTOHOOK(ReadUsercmd, server.dll + 0x2603F0,
-void, __fastcall, (void* buf, void* pCmd_move, void* pCmd_from)) // 4C 89 44 24 ? 53 55 56 57
-// clang-format on
-{
- // Let normal usercmd read happen first, it's safe
- ReadUsercmd(buf, pCmd_move, pCmd_from);
-
- // Now let's make sure the CMD we read isnt messed up to prevent numerous exploits (including server crashing)
- struct alignas(4) SV_CUserCmd
- {
- DWORD command_number;
- DWORD tick_count;
- float command_time;
- Vector3 worldViewAngles;
- BYTE gap18[4];
- Vector3 localViewAngles;
- Vector3 attackangles;
- Vector3 move;
- DWORD buttons;
- BYTE impulse;
- short weaponselect;
- DWORD meleetarget;
- BYTE gap4C[24];
- char headoffset;
- BYTE gap65[11];
- Vector3 cameraPos;
- Vector3 cameraAngles;
- BYTE gap88[4];
- int tickSomething;
- DWORD dword90;
- DWORD predictedServerEventAck;
- DWORD dword98;
- float frameTime;
- };
-
- auto cmd = (SV_CUserCmd*)pCmd_move;
- auto fromCmd = (SV_CUserCmd*)pCmd_from;
-
- std::string BLOCK_PREFIX =
- "ReadUsercmd (command_number delta: " + std::to_string(cmd->command_number - fromCmd->command_number) + "): ";
-
- // fix invalid player angles
- cmd->worldViewAngles.MakeValid();
- cmd->attackangles.MakeValid();
- cmd->localViewAngles.MakeValid();
-
- // Fix invalid camera angles
- cmd->cameraPos.MakeValid();
- cmd->cameraAngles.MakeValid();
-
- // Fix invaid movement vector
- cmd->move.MakeValid();
-
- if (cmd->frameTime <= 0 || cmd->tick_count == 0 || cmd->command_time <= 0)
- {
- BLOCKED_INFO(
- "Bogus cmd timing (tick_count: " << cmd->tick_count << ", frameTime: " << cmd->frameTime
- << ", commandTime : " << cmd->command_time << ")");
- goto INVALID_CMD; // No simulation of bogus-timed cmds
- }
-
- return;
-
-INVALID_CMD:
-
- // Fix any gameplay-affecting cmd properties
- // NOTE: Currently tickcount/frametime is set to 0, this ~shouldn't~ cause any problems
- cmd->worldViewAngles = cmd->localViewAngles = cmd->attackangles = cmd->cameraAngles = {0, 0, 0};
- cmd->tick_count = cmd->frameTime = 0;
- cmd->move = cmd->cameraPos = {0, 0, 0};
- cmd->buttons = 0;
- cmd->meleetarget = 0;
-}
-
-// ensure that GetLocalBaseClient().m_bRestrictServerCommands is set correctly, which the return value of this function controls
-// this is IsValveMod in source, but we're making it IsRespawnMod now since valve didn't make this one
-// clang-format off
-AUTOHOOK(IsRespawnMod, engine.dll + 0x1C6360,
-bool, __fastcall, (const char* pModName)) // 48 83 EC 28 48 8B 0D ? ? ? ? 48 8D 15 ? ? ? ? E8 ? ? ? ? 85 C0 74 63
-// clang-format on
-{
- // somewhat temp, store the modname here, since we don't have a proper ptr in engine to it rn
- int iSize = strlen(pModName);
- g_pModName = new char[iSize + 1];
- strcpy(g_pModName, pModName);
-
- if (g_pVanillaCompatibility->GetVanillaCompatibility())
- return false;
-
- return (!strcmp("r2", pModName) || !strcmp("r1", pModName)) && !CommandLine()->CheckParm("-norestrictservercommands");
-}
-
-// ratelimit stringcmds, and prevent remote clients from calling commands that they shouldn't
-// clang-format off
-AUTOHOOK(CGameClient__ExecuteStringCommand, engine.dll + 0x1022E0,
-bool, __fastcall, (CBaseClient* self, uint32_t unknown, const char* pCommandString))
-// clang-format on
-{
- if (Cvar_ns_should_log_all_clientcommands->GetBool())
- spdlog::info("player {} (UID: {}) sent command: \"{}\"", self->m_Name, self->m_UID, pCommandString);
-
- if (!g_pServerLimits->CheckStringCommandLimits(self))
- {
- CBaseClient__Disconnect(self, 1, "Sent too many stringcmd commands");
- return false;
- }
-
- // verify the command we're trying to execute is FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS, if it's a concommand
- char* commandBuf[1040]; // assumedly this is the size of CCommand since we don't have an actual constructor
- memset(commandBuf, 0, sizeof(commandBuf));
- CCommand tempCommand = *(CCommand*)&commandBuf;
-
- if (!CCommand__Tokenize(tempCommand, pCommandString, cmd_source_t::kCommandSrcCode) || !tempCommand.ArgC())
- return false;
-
- 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_GAMEDLL_FOR_REMOTE_CLIENTS))
- {
- // ensure FCVAR_GAMEDLL concommands without FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS can't be executed by remote clients
- if (IsDedicatedServer())
- return false;
-
- if (strcmp(self->m_UID, g_pLocalPlayerUserID))
- return false;
- }
-
- // check for and block abusable legacy portal 2 commands
- // these aren't actually concommands weirdly enough, they seem to just be hardcoded
- if (!Cvar_sv_cheats->GetBool())
- {
- constexpr const char* blockedCommands[] = {
- "emit", // Sound-playing exploit (likely for Portal 2 coop devs testing splitscreen sound or something)
-
- // These both execute a command for every single entity for some reason, nice one valve
- "pre_go_to_hub",
- "pre_go_to_calibration",
-
- "end_movie", // Calls "__MovieFinished" script function, not sure exactly what this does but it certainly isn't needed
- "load_recent_checkpoint" // This is the instant-respawn exploit, literally just calls RespawnPlayer()
- };
-
- int iCmdLength = strlen(tempCommand.Arg(0));
-
- bool bIsBadCommand = false;
- for (auto& blockedCommand : blockedCommands)
- {
- if (iCmdLength != strlen(blockedCommand))
- continue;
-
- for (int i = 0; tempCommand.Arg(0)[i]; i++)
- if (tolower(tempCommand.Arg(0)[i]) != blockedCommand[i])
- goto NEXT_COMMAND; // break out of this loop, then go to next command
-
- // this is a command we need to block
- return false;
- NEXT_COMMAND:;
- }
- }
-
- return CGameClient__ExecuteStringCommand(self, unknown, pCommandString);
-}
-
-// prevent clients from crashing servers through overflowing CNetworkStringTableContainer::WriteBaselines
-bool bWasWritingStringTableSuccessful;
-
-// clang-format off
-AUTOHOOK(CBaseClient__SendServerInfo, engine.dll + 0x104FB0,
-void, __fastcall, (void* self))
-// clang-format on
-{
- bWasWritingStringTableSuccessful = true;
- CBaseClient__SendServerInfo(self);
- if (!bWasWritingStringTableSuccessful)
- CBaseClient__Disconnect(
- self, 1, "Overflowed CNetworkStringTableContainer::WriteBaselines, try restarting your client and reconnecting");
-}
-
-// return null when GetEntByIndex is passed an index >= 0x4000
-// this is called from exactly 1 script clientcommand that can be given an arbitrary index, and going above 0x4000 crashes
-// clang-format off
-AUTOHOOK(GetEntByIndex, server.dll + 0x2A8A50,
-void*, __fastcall, (int i))
-// clang-format on
-{
- const int MAX_ENT_IDX = 0x4000;
-
- if (i >= MAX_ENT_IDX)
- {
- spdlog::warn("GetEntByIndex {} is out of bounds (max {})", i, MAX_ENT_IDX);
- return nullptr;
- }
-
- return GetEntByIndex(i);
-}
-// clang-format off
-AUTOHOOK(CL_CopyExistingEntity, engine.dll + 0x6F940,
-bool, __fastcall, (void* a1))
-// clang-format on
-{
- struct CEntityReadInfo
- {
- BYTE gap[40];
- int nNewEntity;
- };
-
- CEntityReadInfo* pReadInfo = (CEntityReadInfo*)a1;
- if (pReadInfo->nNewEntity >= 0x1000 || pReadInfo->nNewEntity < 0)
- {
- // Value isn't sanitized in release builds for
- // every game powered by the Source Engine 1
- // causing read/write outside of array bounds.
- // This defect has let to the achievement of a
- // full-chain RCE exploit. We hook and perform
- // sanity checks for the value of m_nNewEntity
- // here to prevent this behavior from happening.
- return false;
- }
-
- return CL_CopyExistingEntity(a1);
-}
-
-ON_DLL_LOAD("engine.dll", EngineExploitFixes, (CModule module))
-{
- AUTOHOOK_DISPATCH_MODULE(engine.dll)
-
- // allow client/ui to run clientcommands despite restricting servercommands
- module.Offset(0x4FB65).Patch("EB 11");
- module.Offset(0x4FBAC).Patch("EB 16");
-
- // patch to set bWasWritingStringTableSuccessful in CNetworkStringTableContainer::WriteBaselines if it fails
- {
- CMemoryAddress writeAddress(&bWasWritingStringTableSuccessful - module.Offset(0x234EDC).m_nAddress);
-
- CMemoryAddress addr = module.Offset(0x234ED2);
- addr.Patch("C7 05");
- addr.Offset(2).Patch((BYTE*)&writeAddress, sizeof(writeAddress));
-
- addr.Offset(6).Patch("00 00 00 00");
-
- addr.Offset(10).NOP(5);
- }
-}
-
-ON_DLL_LOAD_RELIESON("server.dll", ServerExploitFixes, ConVar, (CModule module))
-{
- AUTOHOOK_DISPATCH_MODULE(server.dll)
-
- // ret at the start of CServerGameClients::ClientCommandKeyValues as it has no benefit and is forwarded to client (i.e. security issue)
- // this prevents the attack vector of client=>server=>client, however server=>client also has clientside patches
- module.Offset(0x153920).Patch("C3");
-
- // Dumb ANTITAMPER patches (they negatively impact performance and security)
- constexpr const char* ANTITAMPER_EXPORTS[] = {
- "ANTITAMPER_SPOTCHECK_CODEMARKER",
- "ANTITAMPER_TESTVALUE_CODEMARKER",
- "ANTITAMPER_TRIGGER_CODEMARKER",
- };
-
- // Prevent these from actually doing anything
- for (auto exportName : ANTITAMPER_EXPORTS)
- {
- CMemoryAddress exportAddr = module.GetExport(exportName);
- if (exportAddr)
- {
- // Just return, none of them have any args or are userpurge
- exportAddr.Patch("C3");
- spdlog::info("Patched AntiTamper function export \"{}\"", exportName);
- }
- }
-
- Cvar_ns_exploitfixes_log =
- new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something");
- Cvar_ns_should_log_all_clientcommands =
- new ConVar("ns_should_log_all_clientcommands", "0", FCVAR_NONE, "Whether to log all clientcommands");
-
- Cvar_sv_cheats = g_pCVar->FindVar("sv_cheats");
-}
diff --git a/NorthstarDLL/shared/exploit_fixes/exploitfixes_lzss.cpp b/NorthstarDLL/shared/exploit_fixes/exploitfixes_lzss.cpp
deleted file mode 100644
index ccb6ac18..00000000
--- a/NorthstarDLL/shared/exploit_fixes/exploitfixes_lzss.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-
-AUTOHOOK_INIT()
-
-static constexpr int LZSS_LOOKSHIFT = 4;
-
-struct lzss_header_t
-{
- unsigned int id;
- unsigned int actualSize;
-};
-
-// Rewrite of CLZSS::SafeUncompress to fix a vulnerability where malicious compressed payloads could cause the decompressor to try to read
-// out of the bounds of the output buffer.
-// clang-format off
-AUTOHOOK(CLZSS__SafeDecompress, engine.dll + 0x432A10,
-unsigned int, __fastcall, (void* self, const unsigned char* pInput, unsigned char* pOutput, unsigned int unBufSize))
-// clang-format on
-{
- unsigned int totalBytes = 0;
- int getCmdByte = 0;
- int cmdByte = 0;
-
- lzss_header_t header = *(lzss_header_t*)pInput;
-
- if (!pInput || !header.actualSize || header.id != 0x53535A4C || header.actualSize > unBufSize)
- return 0;
-
- pInput += sizeof(lzss_header_t);
-
- for (;;)
- {
- if (!getCmdByte)
- cmdByte = *pInput++;
-
- getCmdByte = (getCmdByte + 1) & 0x07;
-
- if (cmdByte & 0x01)
- {
- int position = *pInput++ << LZSS_LOOKSHIFT;
- position |= (*pInput >> LZSS_LOOKSHIFT);
- position += 1;
- int count = (*pInput++ & 0x0F) + 1;
- if (count == 1)
- break;
-
- // Ensure reference chunk exists entirely within our buffer
- if (position > totalBytes)
- return 0;
-
- totalBytes += count;
- if (totalBytes > unBufSize)
- return 0;
-
- unsigned char* pSource = pOutput - position;
- for (int i = 0; i < count; i++)
- *pOutput++ = *pSource++;
- }
- else
- {
- totalBytes++;
- if (totalBytes > unBufSize)
- return 0;
-
- *pOutput++ = *pInput++;
- }
- cmdByte = cmdByte >> 1;
- }
-
- if (totalBytes != header.actualSize)
- return 0;
-
- return totalBytes;
-}
-
-ON_DLL_LOAD("engine.dll", ExploitFixes_LZSS, (CModule module))
-{
- AUTOHOOK_DISPATCH()
-}
diff --git a/NorthstarDLL/shared/exploit_fixes/exploitfixes_utf8parser.cpp b/NorthstarDLL/shared/exploit_fixes/exploitfixes_utf8parser.cpp
deleted file mode 100644
index 3d97f750..00000000
--- a/NorthstarDLL/shared/exploit_fixes/exploitfixes_utf8parser.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-
-AUTOHOOK_INIT()
-
-INT64(__fastcall* sub_F1320)(DWORD a1, char* a2);
-
-// Reimplementation of an exploitable UTF decoding function in titanfall
-bool __fastcall CheckUTF8Valid(INT64* a1, DWORD* a2, char* strData)
-{
- DWORD v3; // eax
- char* v4; // rbx
- char v5; // si
- char* _strData; // rdi
- char* v7; // rbp
- char v11; // al
- DWORD v12; // er9
- DWORD v13; // ecx
- DWORD v14; // edx
- DWORD v15; // er8
- int v16; // eax
- DWORD v17; // er9
- int v18; // eax
- DWORD v19; // er9
- DWORD v20; // ecx
- int v21; // eax
- int v22; // er9
- DWORD v23; // edx
- int v24; // eax
- int v25; // er9
- DWORD v26; // er9
- DWORD v27; // er10
- DWORD v28; // ecx
- DWORD v29; // edx
- DWORD v30; // er8
- int v31; // eax
- DWORD v32; // er10
- int v33; // eax
- DWORD v34; // er10
- DWORD v35; // ecx
- int v36; // eax
- int v37; // er10
- DWORD v38; // edx
- int v39; // eax
- int v40; // er10
- DWORD v41; // er10
- INT64 v43; // r8
- INT64 v44; // rdx
- INT64 v45; // rcx
- INT64 v46; // rax
- INT64 v47; // rax
- char v48; // al
- INT64 v49; // r8
- INT64 v50; // rdx
- INT64 v51; // rcx
- INT64 v52; // rax
- INT64 v53; // rax
-
- v3 = a2[2];
- v4 = (char*)(a1[1] + *a2);
- v5 = 0;
- _strData = strData;
- v7 = &v4[*((UINT16*)a2 + 2)];
- if (v3 >= 2)
- {
- ++v4;
- --v7;
- if (v3 != 2)
- {
- while (1)
- {
- if (!CMemoryAddress(v4).IsMemoryReadable(1))
- return false; // INVALID
-
- v11 = *v4++; // crash potential
- if (v11 != 92)
- goto LABEL_6;
- v11 = *v4++;
- if (v11 == 110)
- break;
- switch (v11)
- {
- case 't':
- v11 = 9;
- goto LABEL_6;
- case 'r':
- v11 = 13;
- goto LABEL_6;
- case 'b':
- v11 = 8;
- goto LABEL_6;
- case 'f':
- v11 = 12;
- goto LABEL_6;
- }
- if (v11 != 117)
- goto LABEL_6;
- v12 = *v4 | 0x20;
- v13 = v4[1] | 0x20;
- v14 = v4[2] | 0x20;
- v15 = v4[3] | 0x20;
- v16 = 87;
- if (v12 <= 0x39)
- v16 = 48;
- v17 = v12 - v16;
- v18 = 87;
- v19 = v17 << 12;
- if (v13 <= 0x39)
- v18 = 48;
- v20 = v13 - v18;
- v21 = 87;
- v22 = (v20 << 8) | v19;
- if (v14 <= 0x39)
- v21 = 48;
- v23 = v14 - v21;
- v24 = 87;
- v25 = (16 * v23) | v22;
- if (v15 <= 0x39)
- v24 = 48;
- v4 += 4;
- v26 = (v15 - v24) | v25;
- if (v26 - 55296 <= 0x7FF)
- {
- if (v26 >= 0xDC00)
- return true;
- if (*v4 != 92 || v4[1] != 117)
- return true;
-
- v27 = v4[2] | 0x20;
- v28 = v4[3] | 0x20;
- v29 = v4[4] | 0x20;
- v30 = v4[5] | 0x20;
- v31 = 87;
- if (v27 <= 0x39)
- v31 = 48;
- v32 = v27 - v31;
- v33 = 87;
- v34 = v32 << 12;
- if (v28 <= 0x39)
- v33 = 48;
- v35 = v28 - v33;
- v36 = 87;
- v37 = (v35 << 8) | v34;
- if (v29 <= 0x39)
- v36 = 48;
- v38 = v29 - v36;
- v39 = 87;
- v40 = (16 * v38) | v37;
- if (v30 <= 0x39)
- v39 = 48;
- v4 += 6;
- v41 = ((v30 - v39) | v40) - 56320;
- if (v41 > 0x3FF)
- return true;
- v26 = v41 | ((v26 - 55296) << 10);
- }
- _strData += (DWORD)sub_F1320(v26, _strData);
- LABEL_7:
- if (v4 == v7)
- goto LABEL_48;
- }
- v11 = 10;
- LABEL_6:
- v5 |= v11;
- *_strData++ = v11;
- goto LABEL_7;
- }
- }
-LABEL_48:
- return true;
-}
-
-// prevent utf8 parser from crashing when provided bad data, which can be sent through user-controlled openinvites
-// clang-format off
-AUTOHOOK(Rson_ParseUTF8, engine.dll + 0xEF670,
-bool, __fastcall, (INT64* a1, DWORD* a2, char* strData)) // 48 89 5C 24 ? 48 89 6C 24 ? 48 89 74 24 ? 57 41 54 41 55 41 56 41 57 48 83 EC 20 8B 1A
-// clang-format on
-{
- static void* targetRetAddr = CModule("engine.dll").FindPattern("84 C0 75 2C 49 8B 16");
-
- // only call if we're parsing utf8 data from the network (i.e. communities), otherwise we get perf issues
- void* pReturnAddress =
-#ifdef _MSC_VER
- _ReturnAddress()
-#else
- __builtin_return_address(0)
-#endif
- ;
-
- if (pReturnAddress == targetRetAddr && !CheckUTF8Valid(a1, a2, strData))
- return false;
-
- return Rson_ParseUTF8(a1, a2, strData);
-}
-
-ON_DLL_LOAD("engine.dll", EngineExploitFixes_UTF8Parser, (CModule module))
-{
- AUTOHOOK_DISPATCH()
-
- sub_F1320 = module.FindPattern("83 F9 7F 77 08 88 0A").RCast<INT64(__fastcall*)(DWORD, char*)>();
-}
diff --git a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp b/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp
deleted file mode 100644
index bd855ee4..00000000
--- a/NorthstarDLL/shared/exploit_fixes/ns_limits.cpp
+++ /dev/null
@@ -1,298 +0,0 @@
-#include "ns_limits.h"
-#include "engine/hoststate.h"
-#include "client/r2client.h"
-#include "engine/r2engine.h"
-#include "server/r2server.h"
-#include "core/tier0.h"
-#include "core/math/vector.h"
-#include "server/auth/serverauthentication.h"
-
-AUTOHOOK_INIT()
-
-ServerLimitsManager* g_pServerLimits;
-
-float (*CEngineServer__GetTimescale)();
-
-// todo: make this work on higher timescales, also possibly disable when sv_cheats is set
-void ServerLimitsManager::RunFrame(double flCurrentTime, float flFrameTime)
-{
- if (Cvar_sv_antispeedhack_enable->GetBool())
- {
- // for each player, set their usercmd processing budget for the frame to the last frametime for the server
- for (int i = 0; i < g_pGlobals->m_nMaxClients; i++)
- {
- CBaseClient* player = &g_pClientArray[i];
-
- if (m_PlayerLimitData.find(player) != m_PlayerLimitData.end())
- {
- PlayerLimitData* pLimitData = &g_pServerLimits->m_PlayerLimitData[player];
- if (pLimitData->flFrameUserCmdBudget < g_pGlobals->m_flTickInterval * Cvar_sv_antispeedhack_maxtickbudget->GetFloat())
- {
- pLimitData->flFrameUserCmdBudget += g_pServerLimits->Cvar_sv_antispeedhack_budgetincreasemultiplier->GetFloat() *
- fmax(flFrameTime, g_pGlobals->m_flFrameTime * CEngineServer__GetTimescale());
- }
- }
- }
- }
-}
-
-void ServerLimitsManager::AddPlayer(CBaseClient* player)
-{
- PlayerLimitData limitData;
- limitData.flFrameUserCmdBudget =
- g_pGlobals->m_flTickInterval * CEngineServer__GetTimescale() * Cvar_sv_antispeedhack_maxtickbudget->GetFloat();
-
- m_PlayerLimitData.insert(std::make_pair(player, limitData));
-}
-
-void ServerLimitsManager::RemovePlayer(CBaseClient* player)
-{
- if (m_PlayerLimitData.find(player) != m_PlayerLimitData.end())
- m_PlayerLimitData.erase(player);
-}
-
-bool ServerLimitsManager::CheckStringCommandLimits(CBaseClient* player)
-{
- if (CVar_sv_quota_stringcmdspersecond->GetInt() != -1)
- {
- // note: this isn't super perfect, legit clients can trigger it in lobby if they try, mostly good enough tho imo
- if (Plat_FloatTime() - m_PlayerLimitData[player].lastClientCommandQuotaStart >= 1.0)
- {
- // reset quota
- m_PlayerLimitData[player].lastClientCommandQuotaStart = Plat_FloatTime();
- m_PlayerLimitData[player].numClientCommandsInQuota = 0;
- }
-
- m_PlayerLimitData[player].numClientCommandsInQuota++;
- if (m_PlayerLimitData[player].numClientCommandsInQuota > CVar_sv_quota_stringcmdspersecond->GetInt())
- {
- // too many stringcmds, dc player
- return false;
- }
- }
-
- return true;
-}
-
-bool ServerLimitsManager::CheckChatLimits(CBaseClient* player)
-{
- if (Plat_FloatTime() - m_PlayerLimitData[player].lastSayTextLimitStart >= 1.0)
- {
- m_PlayerLimitData[player].lastSayTextLimitStart = Plat_FloatTime();
- m_PlayerLimitData[player].sayTextLimitCount = 0;
- }
-
- if (m_PlayerLimitData[player].sayTextLimitCount >= Cvar_sv_max_chat_messages_per_sec->GetInt())
- return false;
-
- m_PlayerLimitData[player].sayTextLimitCount++;
- return true;
-}
-
-// clang-format off
-AUTOHOOK(CNetChan__ProcessMessages, engine.dll + 0x2140A0,
-char, __fastcall, (void* self, void* buf))
-// clang-format on
-{
- enum eNetChanLimitMode
- {
- NETCHANLIMIT_WARN,
- NETCHANLIMIT_KICK
- };
-
- double startTime = Plat_FloatTime();
- char ret = CNetChan__ProcessMessages(self, buf);
-
- // check processing limits, unless we're in a level transition
- if (g_pHostState->m_iCurrentState == HostState_t::HS_RUN && ThreadInServerFrameThread())
- {
- // player that sent the message
- CBaseClient* sender = *(CBaseClient**)((char*)self + 368);
-
- // if no sender, return
- // relatively certain this is fine?
- if (!sender || !g_pServerLimits->m_PlayerLimitData.count(sender))
- return ret;
-
- // reset every second
- if (startTime - g_pServerLimits->m_PlayerLimitData[sender].lastNetChanProcessingLimitStart >= 1.0 ||
- g_pServerLimits->m_PlayerLimitData[sender].lastNetChanProcessingLimitStart == -1.0)
- {
- g_pServerLimits->m_PlayerLimitData[sender].lastNetChanProcessingLimitStart = startTime;
- g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime = 0.0;
- }
- g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime += (Plat_FloatTime() * 1000) - (startTime * 1000);
-
- if (g_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime >=
- g_pServerLimits->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_pServerLimits->m_PlayerLimitData[sender].netChanProcessingLimitTime,
- g_pServerLimits->Cvar_net_chan_limit_msec_per_sec->GetInt());
-
- // never kick local player
- if (g_pServerLimits->Cvar_net_chan_limit_mode->GetInt() != NETCHANLIMIT_WARN && strcmp(g_pLocalPlayerUserID, sender->m_UID))
- {
- CBaseClient__Disconnect(sender, 1, "Exceeded net channel processing limit");
- return false;
- }
- }
- }
-
- return ret;
-}
-
-bool ServerLimitsManager::CheckConnectionlessPacketLimits(netpacket_t* packet)
-{
- static const ConVar* Cvar_net_data_block_enabled = g_pCVar->FindVar("net_data_block_enabled");
-
- // don't ratelimit datablock packets as long as datablock is enabled
- if (packet->adr.type == NA_IP &&
- (!(packet->data[4] == 'N' && Cvar_net_data_block_enabled->GetBool()) || !Cvar_net_data_block_enabled->GetBool()))
- {
- // bad lookup: optimise later tm
- UnconnectedPlayerLimitData* sendData = nullptr;
- for (UnconnectedPlayerLimitData& foundSendData : g_pServerLimits->m_UnconnectedPlayerLimitData)
- {
- if (!memcmp(packet->adr.ip, foundSendData.ip, 16))
- {
- sendData = &foundSendData;
- break;
- }
- }
-
- if (!sendData)
- {
- sendData = &g_pServerLimits->m_UnconnectedPlayerLimitData.emplace_back();
- memcpy(sendData->ip, packet->adr.ip, 16);
- }
-
- if (Plat_FloatTime() < sendData->timeoutEnd)
- return false;
-
- if (Plat_FloatTime() - sendData->lastQuotaStart >= 1.0)
- {
- sendData->lastQuotaStart = Plat_FloatTime();
- sendData->packetCount = 0;
- }
-
- sendData->packetCount++;
-
- if (sendData->packetCount >= g_pServerLimits->Cvar_sv_querylimit_per_sec->GetInt())
- {
- spdlog::warn(
- "Client went over connectionless ratelimit of {} per sec with packet of type {}",
- g_pServerLimits->Cvar_sv_querylimit_per_sec->GetInt(),
- packet->data[4]);
-
- // timeout for a minute
- sendData->timeoutEnd = Plat_FloatTime() + 60.0;
- return false;
- }
- }
-
- return true;
-}
-
-// this is weird and i'm not sure if it's correct, so not using for now
-/*AUTOHOOK(CBasePlayer__PhysicsSimulate, server.dll + 0x5A6E50, bool, __fastcall, (void* self, int a2, char a3))
-{
- spdlog::info("CBasePlayer::PhysicsSimulate");
- return CBasePlayer__PhysicsSimulate(self, a2, a3);
-}*/
-
-struct alignas(4) SV_CUserCmd
-{
- DWORD command_number;
- DWORD tick_count;
- float command_time;
- Vector3 worldViewAngles;
- BYTE gap18[4];
- Vector3 localViewAngles;
- Vector3 attackangles;
- Vector3 move;
- DWORD buttons;
- BYTE impulse;
- short weaponselect;
- DWORD meleetarget;
- BYTE gap4C[24];
- char headoffset;
- BYTE gap65[11];
- Vector3 cameraPos;
- Vector3 cameraAngles;
- BYTE gap88[4];
- int tickSomething;
- DWORD dword90;
- DWORD predictedServerEventAck;
- DWORD dword98;
- float frameTime;
-};
-
-// clang-format off
-AUTOHOOK(CPlayerMove__RunCommand, server.dll + 0x5B8100,
-void, __fastcall, (void* self, CBasePlayer* player, SV_CUserCmd* pUserCmd, uint64_t a4))
-// clang-format on
-{
- if (g_pServerLimits->Cvar_sv_antispeedhack_enable->GetBool())
- {
- CBaseClient* pClient = &g_pClientArray[player->m_nPlayerIndex - 1];
-
- if (g_pServerLimits->m_PlayerLimitData.find(pClient) != g_pServerLimits->m_PlayerLimitData.end())
- {
- PlayerLimitData* pLimitData = &g_pServerLimits->m_PlayerLimitData[pClient];
-
- pLimitData->flFrameUserCmdBudget = fmax(0.0, pLimitData->flFrameUserCmdBudget - pUserCmd->frameTime);
-
- if (pLimitData->flFrameUserCmdBudget <= 0.0)
- {
- spdlog::warn("player {} went over usercmd budget ({})", pClient->m_Name, pLimitData->flFrameUserCmdBudget);
- return;
- }
- }
- }
-
- CPlayerMove__RunCommand(self, player, pUserCmd, a4);
-}
-
-ON_DLL_LOAD_RELIESON("engine.dll", ServerLimits, ConVar, (CModule module))
-{
- AUTOHOOK_DISPATCH_MODULE(engine.dll)
-
- g_pServerLimits = new ServerLimitsManager;
-
- g_pServerLimits->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, -1 to disable");
- g_pServerLimits->Cvar_net_chan_limit_mode =
- new ConVar("net_chan_limit_mode", "0", FCVAR_GAMEDLL, "The mode for netchan processing limits: 0 = warn, 1 = kick");
- g_pServerLimits->Cvar_net_chan_limit_msec_per_sec = new ConVar(
- "net_chan_limit_msec_per_sec",
- "100",
- FCVAR_GAMEDLL,
- "Netchannel processing is limited to so many milliseconds, abort connection if exceeding budget");
- g_pServerLimits->Cvar_sv_querylimit_per_sec = new ConVar("sv_querylimit_per_sec", "15", FCVAR_GAMEDLL, "");
- g_pServerLimits->Cvar_sv_max_chat_messages_per_sec = new ConVar("sv_max_chat_messages_per_sec", "5", FCVAR_GAMEDLL, "");
- g_pServerLimits->Cvar_sv_antispeedhack_enable =
- new ConVar("sv_antispeedhack_enable", "0", FCVAR_NONE, "whether to enable antispeedhack protections");
- g_pServerLimits->Cvar_sv_antispeedhack_maxtickbudget = new ConVar(
- "sv_antispeedhack_maxtickbudget",
- "64",
- FCVAR_GAMEDLL,
- "Maximum number of client-issued usercmd ticks that can be replayed in packet loss conditions");
- g_pServerLimits->Cvar_sv_antispeedhack_budgetincreasemultiplier = new ConVar(
- "sv_antispeedhack_budgetincreasemultiplier",
- "1",
- FCVAR_GAMEDLL,
- "Increase usercmd processing budget by tickinterval * value per tick");
-
- CEngineServer__GetTimescale = module.Offset(0x240840).RCast<float (*)()>();
-}
-
-ON_DLL_LOAD("server.dll", ServerLimitsServer, (CModule module))
-{
- AUTOHOOK_DISPATCH_MODULE(server.dll)
-}
diff --git a/NorthstarDLL/shared/exploit_fixes/ns_limits.h b/NorthstarDLL/shared/exploit_fixes/ns_limits.h
deleted file mode 100644
index 546fec6f..00000000
--- a/NorthstarDLL/shared/exploit_fixes/ns_limits.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-#include "engine/r2engine.h"
-#include "core/convar/convar.h"
-#include <unordered_map>
-
-struct PlayerLimitData
-{
- double lastClientCommandQuotaStart = -1.0;
- int numClientCommandsInQuota = 0;
-
- double lastNetChanProcessingLimitStart = -1.0;
- double netChanProcessingLimitTime = 0.0;
-
- double lastSayTextLimitStart = -1.0;
- int sayTextLimitCount = 0;
-
- float flFrameUserCmdBudget = 0.0;
-};
-
-struct UnconnectedPlayerLimitData
-{
- char ip[16];
- double lastQuotaStart = 0.0;
- int packetCount = 0;
- double timeoutEnd = -1.0;
-};
-
-class ServerLimitsManager
-{
-public:
- ConVar* CVar_sv_quota_stringcmdspersecond;
- ConVar* Cvar_net_chan_limit_mode;
- ConVar* Cvar_net_chan_limit_msec_per_sec;
- ConVar* Cvar_sv_querylimit_per_sec;
- ConVar* Cvar_sv_max_chat_messages_per_sec;
- ConVar* Cvar_sv_antispeedhack_enable;
- ConVar* Cvar_sv_antispeedhack_maxtickbudget;
- ConVar* Cvar_sv_antispeedhack_budgetincreasemultiplier;
-
- std::unordered_map<CBaseClient*, PlayerLimitData> m_PlayerLimitData;
- std::vector<UnconnectedPlayerLimitData> m_UnconnectedPlayerLimitData;
-
-public:
- void RunFrame(double flCurrentTime, float flFrameTime);
- void AddPlayer(CBaseClient* player);
- void RemovePlayer(CBaseClient* player);
- bool CheckStringCommandLimits(CBaseClient* player);
- bool CheckChatLimits(CBaseClient* player);
- bool CheckConnectionlessPacketLimits(netpacket_t* packet);
-};
-
-extern ServerLimitsManager* g_pServerLimits;
diff --git a/NorthstarDLL/shared/keyvalues.cpp b/NorthstarDLL/shared/keyvalues.cpp
deleted file mode 100644
index 88753723..00000000
--- a/NorthstarDLL/shared/keyvalues.cpp
+++ /dev/null
@@ -1,1322 +0,0 @@
-#include "keyvalues.h"
-#include <winnt.h>
-
-// implementation of the ConVar class
-// heavily based on https://github.com/Mauler125/r5sdk/blob/master/r5dev/vpc/keyvalues.cpp
-
-typedef int HKeySymbol;
-#define INVALID_KEY_SYMBOL (-1)
-
-#define MAKE_3_BYTES_FROM_1_AND_2(x1, x2) ((((uint16_t)x2) << 8) | (uint8_t)(x1))
-#define SPLIT_3_BYTES_INTO_1_AND_2(x1, x2, x3) \
- do \
- { \
- x1 = (uint8_t)(x3); \
- x2 = (uint16_t)((x3) >> 8); \
- } while (0)
-
-struct CKeyValuesSystem
-{
-public:
- struct __VTable
- {
- char pad0[8 * 3]; // 2 methods
- HKeySymbol (*GetSymbolForString)(CKeyValuesSystem* self, const char* name, bool bCreate);
- const char* (*GetStringForSymbol)(CKeyValuesSystem* self, HKeySymbol symbol);
- char pad1[8 * 5];
- HKeySymbol (*GetSymbolForStringCaseSensitive)(
- CKeyValuesSystem* self, HKeySymbol& hCaseInsensitiveSymbol, const char* name, bool bCreate);
- };
-
- const __VTable* m_pVtable;
-};
-
-int (*V_UTF8ToUnicode)(const char* pUTF8, wchar_t* pwchDest, int cubDestSizeInBytes);
-int (*V_UnicodeToUTF8)(const wchar_t* pUnicode, char* pUTF8, int cubDestSizeInBytes);
-CKeyValuesSystem* (*KeyValuesSystem)();
-
-KeyValues::KeyValues() {} // default constructor for copying and such
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(const char* pszSetName)
-{
- Init();
- SetName(pszSetName);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-// *pszFirstKey -
-// *pszFirstValue -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(const char* pszSsetName, const char* pszFirstKey, const char* pszFirstValue)
-{
- Init();
- SetName(pszSsetName);
- SetString(pszFirstKey, pszFirstValue);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-// *pszFirstKey -
-// *pwszFirstValue -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, const wchar_t* pwszFirstValue)
-{
- Init();
- SetName(pszSetName);
- SetWString(pszFirstKey, pwszFirstValue);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-// *pszFirstKey -
-// iFirstValue -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue)
-{
- Init();
- SetName(pszSetName);
- SetInt(pszFirstKey, iFirstValue);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-// *pszFirstKey -
-// *pszFirstValue -
-// *pszSecondKey -
-// *pszSecondValue -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(
- const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue, const char* pszSecondKey, const char* pszSecondValue)
-{
- Init();
- SetName(pszSetName);
- SetString(pszFirstKey, pszFirstValue);
- SetString(pszSecondKey, pszSecondValue);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Constructor
-// Input : *pszSetName -
-// *pszFirstKey -
-// iFirstValue -
-// *pszSecondKey -
-// iSecondValue -
-//-----------------------------------------------------------------------------
-KeyValues::KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue, const char* pszSecondKey, int iSecondValue)
-{
- Init();
- SetName(pszSetName);
- SetInt(pszFirstKey, iFirstValue);
- SetInt(pszSecondKey, iSecondValue);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Destructor
-//-----------------------------------------------------------------------------
-KeyValues::~KeyValues(void)
-{
- RemoveEverything();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Initialize member variables
-//-----------------------------------------------------------------------------
-void KeyValues::Init(void)
-{
- m_iKeyName = 0;
- m_iKeyNameCaseSensitive1 = 0;
- m_iKeyNameCaseSensitive2 = 0;
- m_iDataType = TYPE_NONE;
-
- m_pSub = nullptr;
- m_pPeer = nullptr;
- m_pChain = nullptr;
-
- m_sValue = nullptr;
- m_wsValue = nullptr;
- m_pValue = nullptr;
-
- m_bHasEscapeSequences = 0;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Clear out all subkeys, and the current value
-//-----------------------------------------------------------------------------
-void KeyValues::Clear(void)
-{
- delete m_pSub;
- m_pSub = nullptr;
- m_iDataType = TYPE_NONE;
-}
-
-//-----------------------------------------------------------------------------
-// for backwards compat - we used to need this to force the free to run from the same DLL
-// as the alloc
-//-----------------------------------------------------------------------------
-void KeyValues::DeleteThis(void)
-{
- delete this;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: remove everything
-//-----------------------------------------------------------------------------
-void KeyValues::RemoveEverything(void)
-{
- KeyValues* dat;
- KeyValues* datNext = nullptr;
- for (dat = m_pSub; dat != nullptr; dat = datNext)
- {
- datNext = dat->m_pPeer;
- dat->m_pPeer = nullptr;
- delete dat;
- }
-
- for (dat = m_pPeer; dat && dat != this; dat = datNext)
- {
- datNext = dat->m_pPeer;
- dat->m_pPeer = nullptr;
- delete dat;
- }
-
- delete[] m_sValue;
- m_sValue = nullptr;
- delete[] m_wsValue;
- m_wsValue = nullptr;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Find a keyValue, create it if it is not found.
-// Set bCreate to true to create the key if it doesn't already exist
-// (which ensures a valid pointer will be returned)
-// Input : *pszKeyName -
-// bCreate -
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::FindKey(const char* pszKeyName, bool bCreate)
-{
- assert_msg(this, "Member function called on NULL KeyValues");
-
- if (!pszKeyName || !*pszKeyName)
- return this;
-
- const char* pSubStr = strchr(pszKeyName, '/');
- const char* pSearchStr = pszKeyName;
- if (pSubStr && !*(pSubStr + 1))
- {
- // if key name is just '/', then use it as a key directly
- pSearchStr = pSubStr;
- pSubStr = nullptr;
- }
-
- HKeySymbol iSearchStr = KeyValuesSystem()->m_pVtable->GetSymbolForString(KeyValuesSystem(), pSearchStr, bCreate);
- if (iSearchStr == INVALID_KEY_SYMBOL)
- {
- // not found, couldn't possibly be in key value list
- return nullptr;
- }
-
- KeyValues* pLastKVs = nullptr;
- KeyValues* pCurrentKVs;
- // find the searchStr in the current peer list
- for (pCurrentKVs = m_pSub; pCurrentKVs != nullptr; pCurrentKVs = pCurrentKVs->m_pPeer)
- {
- pLastKVs = pCurrentKVs; // record the last item looked at (for if we need to append to the end of the list)
-
- // symbol compare
- if (pLastKVs->m_iKeyName == (uint32_t)iSearchStr)
- break;
- }
-
- if (!pCurrentKVs && m_pChain)
- pCurrentKVs = m_pChain->FindKey(pSearchStr, false);
-
- // make sure a key was found
- if (!pCurrentKVs)
- {
- if (bCreate)
- {
- // we need to create a new key
- pCurrentKVs = new KeyValues(pSearchStr);
- // Assert(dat != NULL);
-
- // insert new key at end of list
- if (pLastKVs)
- pLastKVs->m_pPeer = pCurrentKVs;
- else
- m_pSub = pCurrentKVs;
-
- pCurrentKVs->m_pPeer = nullptr;
-
- // a key graduates to be a submsg as soon as it's m_pSub is set
- // this should be the only place m_pSub is set
- m_iDataType = TYPE_NONE;
- }
- else
- {
- return nullptr;
- }
- }
-
- // if we've still got a subStr we need to keep looking deeper in the tree
- if (pSubStr)
- {
- // recursively chain down through the paths in the string
- return pCurrentKVs->FindKey(pSubStr + 1, bCreate);
- }
-
- return pCurrentKVs;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Locate last child. Returns NULL if we have no children
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::FindLastSubKey(void) const
-{
- // No children?
- if (m_pSub == nullptr)
- return nullptr;
-
- // Scan for the last one
- KeyValues* pLastChild = m_pSub;
- while (pLastChild->m_pPeer)
- pLastChild = pLastChild->m_pPeer;
- return pLastChild;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Adds a subkey. Make sure the subkey isn't a child of some other keyvalues
-// Input : *pSubKey -
-//-----------------------------------------------------------------------------
-void KeyValues::AddSubKey(KeyValues* pSubkey)
-{
- // Make sure the subkey isn't a child of some other keyvalues
- assert(pSubkey != nullptr);
- assert(pSubkey->m_pPeer == nullptr);
-
- // add into subkey list
- if (m_pSub == nullptr)
- {
- m_pSub = pSubkey;
- }
- else
- {
- KeyValues* pTempDat = m_pSub;
- while (pTempDat->GetNextKey() != nullptr)
- {
- pTempDat = pTempDat->GetNextKey();
- }
-
- pTempDat->SetNextKey(pSubkey);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Remove a subkey from the list
-// Input : *pSubKey -
-//-----------------------------------------------------------------------------
-void KeyValues::RemoveSubKey(KeyValues* pSubKey)
-{
- if (!pSubKey)
- return;
-
- // check the list pointer
- if (m_pSub == pSubKey)
- {
- m_pSub = pSubKey->m_pPeer;
- }
- else
- {
- // look through the list
- KeyValues* kv = m_pSub;
- while (kv->m_pPeer)
- {
- if (kv->m_pPeer == pSubKey)
- {
- kv->m_pPeer = pSubKey->m_pPeer;
- break;
- }
-
- kv = kv->m_pPeer;
- }
- }
-
- pSubKey->m_pPeer = nullptr;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Insert a subkey at index
-// Input : nIndex -
-// *pSubKey -
-//-----------------------------------------------------------------------------
-void KeyValues::InsertSubKey(int nIndex, KeyValues* pSubKey)
-{
- // Sub key must be valid and not part of another chain
- assert(pSubKey && pSubKey->m_pPeer == nullptr);
-
- if (nIndex == 0)
- {
- pSubKey->m_pPeer = m_pSub;
- m_pSub = pSubKey;
- return;
- }
- else
- {
- int nCurrentIndex = 0;
- for (KeyValues* pIter = GetFirstSubKey(); pIter != nullptr; pIter = pIter->GetNextKey())
- {
- ++nCurrentIndex;
- if (nCurrentIndex == nIndex)
- {
- pSubKey->m_pPeer = pIter->m_pPeer;
- pIter->m_pPeer = pSubKey;
- return;
- }
- }
- // Index is out of range if we get here
- assert(0);
- return;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Checks if key contains a subkey
-// Input : *pSubKey -
-// Output : true if contains, false otherwise
-//-----------------------------------------------------------------------------
-bool KeyValues::ContainsSubKey(KeyValues* pSubKey)
-{
- for (KeyValues* pIter = GetFirstSubKey(); pIter != nullptr; pIter = pIter->GetNextKey())
- {
- if (pSubKey == pIter)
- {
- return true;
- }
- }
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Swaps existing subkey with another
-// Input : *pExistingSubkey -
-// *pNewSubKey -
-//-----------------------------------------------------------------------------
-void KeyValues::SwapSubKey(KeyValues* pExistingSubkey, KeyValues* pNewSubKey)
-{
- assert(pExistingSubkey != nullptr && pNewSubKey != nullptr);
-
- // Make sure the new sub key isn't a child of some other keyvalues
- assert(pNewSubKey->m_pPeer == nullptr);
-
- // Check the list pointer
- if (m_pSub == pExistingSubkey)
- {
- pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
- pExistingSubkey->m_pPeer = nullptr;
- m_pSub = pNewSubKey;
- }
- else
- {
- // Look through the list
- KeyValues* kv = m_pSub;
- while (kv->m_pPeer)
- {
- if (kv->m_pPeer == pExistingSubkey)
- {
- pNewSubKey->m_pPeer = pExistingSubkey->m_pPeer;
- pExistingSubkey->m_pPeer = nullptr;
- kv->m_pPeer = pNewSubKey;
- break;
- }
-
- kv = kv->m_pPeer;
- }
- // Existing sub key should always be found, otherwise it's a bug in the calling code.
- assert(kv->m_pPeer != nullptr);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Elides subkey
-// Input : *pSubKey -
-//-----------------------------------------------------------------------------
-void KeyValues::ElideSubKey(KeyValues* pSubKey)
-{
- // This pointer's "next" pointer needs to be fixed up when we elide the key
- KeyValues** ppPointerToFix = &m_pSub;
- for (KeyValues* pKeyIter = m_pSub; pKeyIter != nullptr; ppPointerToFix = &pKeyIter->m_pPeer, pKeyIter = pKeyIter->GetNextKey())
- {
- if (pKeyIter == pSubKey)
- {
- if (pSubKey->m_pSub == nullptr)
- {
- // No children, simply remove the key
- *ppPointerToFix = pSubKey->m_pPeer;
- delete pSubKey;
- }
- else
- {
- *ppPointerToFix = pSubKey->m_pSub;
- // Attach the remainder of this chain to the last child of pSubKey
- KeyValues* pChildIter = pSubKey->m_pSub;
- while (pChildIter->m_pPeer != nullptr)
- {
- pChildIter = pChildIter->m_pPeer;
- }
- // Now points to the last child of pSubKey
- pChildIter->m_pPeer = pSubKey->m_pPeer;
- // Detach the node to be elided
- pSubKey->m_pSub = nullptr;
- pSubKey->m_pPeer = nullptr;
- delete pSubKey;
- }
- return;
- }
- }
- // Key not found; that's caller error.
- assert(0);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Check if a keyName has no value assigned to it.
-// Input : *pszKeyName -
-// Output : true on success, false otherwise
-//-----------------------------------------------------------------------------
-bool KeyValues::IsEmpty(const char* pszKeyName)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (!pKey)
- return true;
-
- if (pKey->m_iDataType == TYPE_NONE && pKey->m_pSub == nullptr)
- return true;
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: gets the first true sub key
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetFirstTrueSubKey(void) const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- KeyValues* pRet = this ? m_pSub : nullptr;
- while (pRet && pRet->m_iDataType != TYPE_NONE)
- pRet = pRet->m_pPeer;
-
- return pRet;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: gets the next true sub key
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetNextTrueSubKey(void) const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- KeyValues* pRet = this ? m_pPeer : nullptr;
- while (pRet && pRet->m_iDataType != TYPE_NONE)
- pRet = pRet->m_pPeer;
-
- return pRet;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: gets the first value
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetFirstValue(void) const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- KeyValues* pRet = this ? m_pSub : nullptr;
- while (pRet && pRet->m_iDataType == TYPE_NONE)
- pRet = pRet->m_pPeer;
-
- return pRet;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: gets the next value
-// Output : *KeyValues
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetNextValue(void) const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- KeyValues* pRet = this ? m_pPeer : nullptr;
- while (pRet && pRet->m_iDataType == TYPE_NONE)
- pRet = pRet->m_pPeer;
-
- return pRet;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Return the first subkey in the list
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetFirstSubKey() const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- return this ? m_pSub : nullptr;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Return the next subkey
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::GetNextKey() const
-{
- assert_msg(this, "Member function called on NULL KeyValues");
- return this ? m_pPeer : nullptr;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the name of the current key section
-// Output : const char*
-//-----------------------------------------------------------------------------
-const char* KeyValues::GetName(void) const
-{
- return KeyValuesSystem()->m_pVtable->GetStringForSymbol(
- KeyValuesSystem(), MAKE_3_BYTES_FROM_1_AND_2(m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2));
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the integer value of a keyName. Default value is returned
-// if the keyName can't be found.
-// Input : *pszKeyName -
-// nDefaultValue -
-// Output : int
-//-----------------------------------------------------------------------------
-int KeyValues::GetInt(const char* pszKeyName, int iDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- switch (pKey->m_iDataType)
- {
- case TYPE_STRING:
- return atoi(pKey->m_sValue);
- case TYPE_WSTRING:
- return _wtoi(pKey->m_wsValue);
- case TYPE_FLOAT:
- return static_cast<int>(pKey->m_flValue);
- case TYPE_UINT64:
- // can't convert, since it would lose data
- assert(0);
- return 0;
- case TYPE_INT:
- case TYPE_PTR:
- default:
- return pKey->m_iValue;
- };
- }
- return iDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the integer value of a keyName. Default value is returned
-// if the keyName can't be found.
-// Input : *pszKeyName -
-// nDefaultValue -
-// Output : uint64_t
-//-----------------------------------------------------------------------------
-uint64_t KeyValues::GetUint64(const char* pszKeyName, uint64_t nDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- switch (pKey->m_iDataType)
- {
- case TYPE_STRING:
- {
- uint64_t uiResult = 0ull;
- sscanf(pKey->m_sValue, "%lld", &uiResult);
- return uiResult;
- }
- case TYPE_WSTRING:
- {
- uint64_t uiResult = 0ull;
- swscanf(pKey->m_wsValue, L"%lld", &uiResult);
- return uiResult;
- }
- case TYPE_FLOAT:
- return static_cast<int>(pKey->m_flValue);
- case TYPE_UINT64:
- return *reinterpret_cast<uint64_t*>(pKey->m_sValue);
- case TYPE_PTR:
- return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(pKey->m_pValue));
- case TYPE_INT:
- default:
- return pKey->m_iValue;
- };
- }
- return nDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the pointer value of a keyName. Default value is returned
-// if the keyName can't be found.
-// Input : *pszKeyName -
-// pDefaultValue -
-// Output : void*
-//-----------------------------------------------------------------------------
-void* KeyValues::GetPtr(const char* pszKeyName, void* pDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- switch (pKey->m_iDataType)
- {
- case TYPE_PTR:
- return pKey->m_pValue;
-
- case TYPE_WSTRING:
- case TYPE_STRING:
- case TYPE_FLOAT:
- case TYPE_INT:
- case TYPE_UINT64:
- default:
- return nullptr;
- };
- }
- return pDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the float value of a keyName. Default value is returned
-// if the keyName can't be found.
-// Input : *pszKeyName -
-// flDefaultValue -
-// Output : float
-//-----------------------------------------------------------------------------
-float KeyValues::GetFloat(const char* pszKeyName, float flDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- switch (pKey->m_iDataType)
- {
- case TYPE_STRING:
- return static_cast<float>(atof(pKey->m_sValue));
- case TYPE_WSTRING:
- return static_cast<float>(_wtof(pKey->m_wsValue)); // no wtof
- case TYPE_FLOAT:
- return pKey->m_flValue;
- case TYPE_INT:
- return static_cast<float>(pKey->m_iValue);
- case TYPE_UINT64:
- return static_cast<float>((*(reinterpret_cast<uint64_t*>(pKey->m_sValue))));
- case TYPE_PTR:
- default:
- return 0.0f;
- };
- }
- return flDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the string pointer of a keyName. Default value is returned
-// if the keyName can't be found.
-// // Input : *pszKeyName -
-// pszDefaultValue -
-// Output : const char*
-//-----------------------------------------------------------------------------
-const char* KeyValues::GetString(const char* pszKeyName, const char* pszDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- // convert the data to string form then return it
- char buf[64];
- switch (pKey->m_iDataType)
- {
- case TYPE_FLOAT:
- snprintf(buf, sizeof(buf), "%f", pKey->m_flValue);
- SetString(pszKeyName, buf);
- break;
- case TYPE_PTR:
- snprintf(buf, sizeof(buf), "%lld", reinterpret_cast<uint64_t>(pKey->m_pValue));
- SetString(pszKeyName, buf);
- break;
- case TYPE_INT:
- snprintf(buf, sizeof(buf), "%d", pKey->m_iValue);
- SetString(pszKeyName, buf);
- break;
- case TYPE_UINT64:
- snprintf(buf, sizeof(buf), "%lld", *(reinterpret_cast<uint64_t*>(pKey->m_sValue)));
- SetString(pszKeyName, buf);
- break;
- case TYPE_COLOR:
- snprintf(buf, sizeof(buf), "%d %d %d %d", pKey->m_Color[0], pKey->m_Color[1], pKey->m_Color[2], pKey->m_Color[3]);
- SetString(pszKeyName, buf);
- break;
-
- case TYPE_WSTRING:
- {
- // convert the string to char *, set it for future use, and return it
- char wideBuf[512];
- int result = V_UnicodeToUTF8(pKey->m_wsValue, wideBuf, 512);
- if (result)
- {
- // note: this will copy wideBuf
- SetString(pszKeyName, wideBuf);
- }
- else
- {
- return pszDefaultValue;
- }
- break;
- }
- case TYPE_STRING:
- break;
- default:
- return pszDefaultValue;
- };
-
- return pKey->m_sValue;
- }
- return pszDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the wide string pointer of a keyName. Default value is returned
-// if the keyName can't be found.
-// // Input : *pszKeyName -
-// pwszDefaultValue -
-// Output : const wchar_t*
-//-----------------------------------------------------------------------------
-const wchar_t* KeyValues::GetWString(const char* pszKeyName, const wchar_t* pwszDefaultValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- wchar_t wbuf[64];
- switch (pKey->m_iDataType)
- {
- case TYPE_FLOAT:
- swprintf(wbuf, ARRAYSIZE(wbuf), L"%f", pKey->m_flValue);
- SetWString(pszKeyName, wbuf);
- break;
- case TYPE_PTR:
- swprintf(wbuf, ARRAYSIZE(wbuf), L"%lld", static_cast<int64_t>(reinterpret_cast<size_t>(pKey->m_pValue)));
- SetWString(pszKeyName, wbuf);
- break;
- case TYPE_INT:
- swprintf(wbuf, ARRAYSIZE(wbuf), L"%d", pKey->m_iValue);
- SetWString(pszKeyName, wbuf);
- break;
- case TYPE_UINT64:
- {
- swprintf(wbuf, ARRAYSIZE(wbuf), L"%lld", *(reinterpret_cast<uint64_t*>(pKey->m_sValue)));
- SetWString(pszKeyName, wbuf);
- }
- break;
- case TYPE_COLOR:
- swprintf(wbuf, ARRAYSIZE(wbuf), L"%d %d %d %d", pKey->m_Color[0], pKey->m_Color[1], pKey->m_Color[2], pKey->m_Color[3]);
- SetWString(pszKeyName, wbuf);
- break;
-
- case TYPE_WSTRING:
- break;
- case TYPE_STRING:
- {
- size_t bufSize = strlen(pKey->m_sValue) + 1;
- wchar_t* pWBuf = new wchar_t[bufSize];
- int result = V_UTF8ToUnicode(pKey->m_sValue, pWBuf, static_cast<int>(bufSize * sizeof(wchar_t)));
- if (result >= 0) // may be a zero length string
- {
- SetWString(pszKeyName, pWBuf);
- delete[] pWBuf;
- }
- else
- {
- delete[] pWBuf;
- return pwszDefaultValue;
- }
-
- break;
- }
- default:
- return pwszDefaultValue;
- };
-
- return reinterpret_cast<const wchar_t*>(pKey->m_wsValue);
- }
- return pwszDefaultValue;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Gets a color
-// Input : *pszKeyName -
-// &defaultColor -
-// Output : Color
-//-----------------------------------------------------------------------------
-Color KeyValues::GetColor(const char* pszKeyName, const Color& defaultColor)
-{
- Color color = defaultColor;
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- {
- if (pKey->m_iDataType == TYPE_COLOR)
- {
- color[0] = pKey->m_Color[0];
- color[1] = pKey->m_Color[1];
- color[2] = pKey->m_Color[2];
- color[3] = pKey->m_Color[3];
- }
- else if (pKey->m_iDataType == TYPE_FLOAT)
- {
- color[0] = static_cast<unsigned char>(pKey->m_flValue);
- }
- else if (pKey->m_iDataType == TYPE_INT)
- {
- color[0] = static_cast<unsigned char>(pKey->m_iValue);
- }
- else if (pKey->m_iDataType == TYPE_STRING)
- {
- // parse the colors out of the string
- float a = 0, b = 0, c = 0, d = 0;
- sscanf(pKey->m_sValue, "%f %f %f %f", &a, &b, &c, &d);
- color[0] = static_cast<unsigned char>(a);
- color[1] = static_cast<unsigned char>(b);
- color[2] = static_cast<unsigned char>(c);
- color[3] = static_cast<unsigned char>(d);
- }
- }
- return color;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the data type of the value stored in a keyName
-// Input : *pszKeyName -
-//-----------------------------------------------------------------------------
-KeyValuesTypes_t KeyValues::GetDataType(const char* pszKeyName)
-{
- KeyValues* pKey = FindKey(pszKeyName, false);
- if (pKey)
- return static_cast<KeyValuesTypes_t>(pKey->m_iDataType);
-
- return TYPE_NONE;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Get the data type of the value stored in this keyName
-//-----------------------------------------------------------------------------
-KeyValuesTypes_t KeyValues::GetDataType(void) const
-{
- return static_cast<KeyValuesTypes_t>(m_iDataType);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the integer value of a keyName.
-// Input : *pszKeyName -
-// iValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetInt(const char* pszKeyName, int iValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
- if (pKey)
- {
- pKey->m_iValue = iValue;
- pKey->m_iDataType = TYPE_INT;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the integer value of a keyName.
-//-----------------------------------------------------------------------------
-void KeyValues::SetUint64(const char* pszKeyName, uint64_t nValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
-
- if (pKey)
- {
- // delete the old value
- delete[] pKey->m_sValue;
- // make sure we're not storing the WSTRING - as we're converting over to STRING
- delete[] pKey->m_wsValue;
- pKey->m_wsValue = nullptr;
-
- pKey->m_sValue = new char[sizeof(uint64_t)];
- *(reinterpret_cast<uint64_t*>(pKey->m_sValue)) = nValue;
- pKey->m_iDataType = TYPE_UINT64;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the float value of a keyName.
-// Input : *pszKeyName -
-// flValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetFloat(const char* pszKeyName, float flValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
- if (pKey)
- {
- pKey->m_flValue = flValue;
- pKey->m_iDataType = TYPE_FLOAT;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the name value of a keyName.
-// Input : *pszSetName -
-//-----------------------------------------------------------------------------
-void KeyValues::SetName(const char* pszSetName)
-{
- HKeySymbol hCaseSensitiveKeyName = INVALID_KEY_SYMBOL, hCaseInsensitiveKeyName = INVALID_KEY_SYMBOL;
- hCaseSensitiveKeyName =
- KeyValuesSystem()->m_pVtable->GetSymbolForStringCaseSensitive(KeyValuesSystem(), hCaseInsensitiveKeyName, pszSetName, false);
-
- m_iKeyName = hCaseInsensitiveKeyName;
- SPLIT_3_BYTES_INTO_1_AND_2(m_iKeyNameCaseSensitive1, m_iKeyNameCaseSensitive2, hCaseSensitiveKeyName);
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the pointer value of a keyName.
-// Input : *pszKeyName -
-// *pValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetPtr(const char* pszKeyName, void* pValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
-
- if (pKey)
- {
- pKey->m_pValue = pValue;
- pKey->m_iDataType = TYPE_PTR;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the string value (internal)
-// Input : *pszValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetStringValue(char const* pszValue)
-{
- // delete the old value
- delete[] m_sValue;
- // make sure we're not storing the WSTRING - as we're converting over to STRING
- delete[] m_wsValue;
- m_wsValue = nullptr;
-
- if (!pszValue)
- {
- // ensure a valid value
- pszValue = "";
- }
-
- // allocate memory for the new value and copy it in
- size_t len = strlen(pszValue);
- m_sValue = new char[len + 1];
- memcpy(m_sValue, pszValue, len + 1);
-
- m_iDataType = TYPE_STRING;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets this key's peer to the KeyValues passed in
-// Input : *pDat -
-//-----------------------------------------------------------------------------
-void KeyValues::SetNextKey(KeyValues* pDat)
-{
- m_pPeer = pDat;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the string value of a keyName.
-// Input : *pszKeyName -
-// *pszValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetString(const char* pszKeyName, const char* pszValue)
-{
- if (KeyValues* pKey = FindKey(pszKeyName, true))
- {
- pKey->SetStringValue(pszValue);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Set the string value of a keyName.
-// Input : *pszKeyName -
-// *pwszValue -
-//-----------------------------------------------------------------------------
-void KeyValues::SetWString(const char* pszKeyName, const wchar_t* pwszValue)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
- if (pKey)
- {
- // delete the old value
- delete[] pKey->m_wsValue;
- // make sure we're not storing the STRING - as we're converting over to WSTRING
- delete[] pKey->m_sValue;
- pKey->m_sValue = nullptr;
-
- if (!pwszValue)
- {
- // ensure a valid value
- pwszValue = L"";
- }
-
- // allocate memory for the new value and copy it in
- size_t len = wcslen(pwszValue);
- pKey->m_wsValue = new wchar_t[len + 1];
- memcpy(pKey->m_wsValue, pwszValue, (len + 1) * sizeof(wchar_t));
-
- pKey->m_iDataType = TYPE_WSTRING;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Sets a color
-// Input : *pszKeyName -
-// color -
-//-----------------------------------------------------------------------------
-void KeyValues::SetColor(const char* pszKeyName, Color color)
-{
- KeyValues* pKey = FindKey(pszKeyName, true);
-
- if (pKey)
- {
- pKey->m_iDataType = TYPE_COLOR;
- pKey->m_Color[0] = color[0];
- pKey->m_Color[1] = color[1];
- pKey->m_Color[2] = color[2];
- pKey->m_Color[3] = color[3];
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &src -
-//-----------------------------------------------------------------------------
-void KeyValues::RecursiveCopyKeyValues(KeyValues& src)
-{
- // garymcthack - need to check this code for possible buffer overruns.
-
- m_iKeyName = src.m_iKeyName;
- m_iKeyNameCaseSensitive1 = src.m_iKeyNameCaseSensitive1;
- m_iKeyNameCaseSensitive2 = src.m_iKeyNameCaseSensitive2;
-
- if (!src.m_pSub)
- {
- m_iDataType = src.m_iDataType;
- char buf[256];
- switch (src.m_iDataType)
- {
- case TYPE_NONE:
- break;
- case TYPE_STRING:
- if (src.m_sValue)
- {
- size_t len = strlen(src.m_sValue) + 1;
- m_sValue = new char[len];
- strncpy(m_sValue, src.m_sValue, len);
- }
- break;
- case TYPE_INT:
- {
- m_iValue = src.m_iValue;
- snprintf(buf, sizeof(buf), "%d", m_iValue);
- size_t len = strlen(buf) + 1;
- m_sValue = new char[len];
- strncpy(m_sValue, buf, len);
- }
- break;
- case TYPE_FLOAT:
- {
- m_flValue = src.m_flValue;
- snprintf(buf, sizeof(buf), "%f", m_flValue);
- size_t len = strlen(buf) + 1;
- m_sValue = new char[len];
- strncpy(m_sValue, buf, len);
- }
- break;
- case TYPE_PTR:
- {
- m_pValue = src.m_pValue;
- }
- break;
- case TYPE_UINT64:
- {
- m_sValue = new char[sizeof(uint64_t)];
- memcpy(m_sValue, src.m_sValue, sizeof(uint64_t));
- }
- break;
- case TYPE_COLOR:
- {
- m_Color[0] = src.m_Color[0];
- m_Color[1] = src.m_Color[1];
- m_Color[2] = src.m_Color[2];
- m_Color[3] = src.m_Color[3];
- }
- break;
-
- default:
- {
- // do nothing . .what the heck is this?
- assert(0);
- }
- break;
- }
- }
-
- // Handle the immediate child
- if (src.m_pSub)
- {
- m_pSub = new KeyValues;
-
- m_pSub->Init();
- m_pSub->SetName(nullptr);
-
- m_pSub->RecursiveCopyKeyValues(*src.m_pSub);
- }
-
- // Handle the immediate peer
- if (src.m_pPeer)
- {
- m_pPeer = new KeyValues;
-
- m_pPeer->Init();
- m_pPeer->SetName(nullptr);
-
- m_pPeer->RecursiveCopyKeyValues(*src.m_pPeer);
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Make a new copy of all subkeys, add them all to the passed-in keyvalues
-// Input : *pParent -
-//-----------------------------------------------------------------------------
-void KeyValues::CopySubkeys(KeyValues* pParent) const
-{
- // recursively copy subkeys
- // Also maintain ordering....
- KeyValues* pPrev = nullptr;
- for (KeyValues* pSub = m_pSub; pSub != nullptr; pSub = pSub->m_pPeer)
- {
- // take a copy of the subkey
- KeyValues* pKey = pSub->MakeCopy();
-
- // add into subkey list
- if (pPrev)
- {
- pPrev->m_pPeer = pKey;
- }
- else
- {
- pParent->m_pSub = pKey;
- }
- pKey->m_pPeer = nullptr;
- pPrev = pKey;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Makes a copy of the whole key-value pair set
-// Output : KeyValues*
-//-----------------------------------------------------------------------------
-KeyValues* KeyValues::MakeCopy(void) const
-{
- KeyValues* pNewKeyValue = new KeyValues;
-
- pNewKeyValue->Init();
- pNewKeyValue->SetName(GetName());
-
- // copy data
- pNewKeyValue->m_iDataType = m_iDataType;
- switch (m_iDataType)
- {
- case TYPE_STRING:
- {
- if (m_sValue)
- {
- size_t len = strlen(m_sValue);
- assert(!pNewKeyValue->m_sValue);
- pNewKeyValue->m_sValue = new char[len + 1];
- memcpy(pNewKeyValue->m_sValue, m_sValue, len + 1);
- }
- }
- break;
- case TYPE_WSTRING:
- {
- if (m_wsValue)
- {
- size_t len = wcslen(m_wsValue);
- pNewKeyValue->m_wsValue = new wchar_t[len + 1];
- memcpy(pNewKeyValue->m_wsValue, m_wsValue, len + 1 * sizeof(wchar_t));
- }
- }
- break;
-
- case TYPE_INT:
- pNewKeyValue->m_iValue = m_iValue;
- break;
-
- case TYPE_FLOAT:
- pNewKeyValue->m_flValue = m_flValue;
- break;
-
- case TYPE_PTR:
- pNewKeyValue->m_pValue = m_pValue;
- break;
-
- case TYPE_COLOR:
- pNewKeyValue->m_Color[0] = m_Color[0];
- pNewKeyValue->m_Color[1] = m_Color[1];
- pNewKeyValue->m_Color[2] = m_Color[2];
- pNewKeyValue->m_Color[3] = m_Color[3];
- break;
-
- case TYPE_UINT64:
- pNewKeyValue->m_sValue = new char[sizeof(uint64_t)];
- memcpy(pNewKeyValue->m_sValue, m_sValue, sizeof(uint64_t));
- break;
- };
-
- // recursively copy subkeys
- CopySubkeys(pNewKeyValue);
- return pNewKeyValue;
-}
-
-ON_DLL_LOAD("vstdlib.dll", KeyValues, (CModule module))
-{
- V_UTF8ToUnicode = module.GetExport("V_UTF8ToUnicode").RCast<int (*)(const char*, wchar_t*, int)>();
- V_UnicodeToUTF8 = module.GetExport("V_UnicodeToUTF8").RCast<int (*)(const wchar_t*, char*, int)>();
- KeyValuesSystem = module.GetExport("KeyValuesSystem").RCast<CKeyValuesSystem* (*)()>();
-}
-
-AUTOHOOK_INIT()
-
-// clang-format off
-AUTOHOOK(KeyValues__LoadFromBuffer, engine.dll + 0x426C30,
-char, __fastcall, (KeyValues* self, const char* pResourceName, const char* pBuffer, void* pFileSystem, void* a5, void* a6, int a7))
-// clang-format on
-{
- static void* pSavedFilesystemPtr = nullptr;
-
- // this is just to allow playlists to get a valid pFileSystem ptr for kv building, other functions that call this particular overload of
- // LoadFromBuffer seem to get called on network stuff exclusively not exactly sure what the address wanted here is, so just taking it
- // from a function call that always happens before playlists is loaded
-
- // note: would be better if we could serialize this to disk for playlists, as this method breaks saving playlists in demos
- if (pFileSystem != nullptr)
- pSavedFilesystemPtr = pFileSystem;
- if (!pFileSystem && !strcmp(pResourceName, "playlists"))
- pFileSystem = pSavedFilesystemPtr;
-
- return KeyValues__LoadFromBuffer(self, pResourceName, pBuffer, pFileSystem, a5, a6, a7);
-}
-
-ON_DLL_LOAD("engine.dll", EngineKeyValues, (CModule module))
-{
- AUTOHOOK_DISPATCH()
-}
diff --git a/NorthstarDLL/shared/keyvalues.h b/NorthstarDLL/shared/keyvalues.h
deleted file mode 100644
index bd62797e..00000000
--- a/NorthstarDLL/shared/keyvalues.h
+++ /dev/null
@@ -1,134 +0,0 @@
-#pragma once
-#include "core/math/color.h"
-
-enum KeyValuesTypes_t : char
-{
- TYPE_NONE = 0x0,
- TYPE_STRING = 0x1,
- TYPE_INT = 0x2,
- TYPE_FLOAT = 0x3,
- TYPE_PTR = 0x4,
- TYPE_WSTRING = 0x5,
- TYPE_COLOR = 0x6,
- TYPE_UINT64 = 0x7,
- TYPE_COMPILED_INT_BYTE = 0x8,
- TYPE_COMPILED_INT_0 = 0x9,
- TYPE_COMPILED_INT_1 = 0xA,
- TYPE_NUMTYPES = 0xB,
-};
-
-enum MergeKeyValuesOp_t
-{
- MERGE_KV_ALL,
- MERGE_KV_UPDATE, // update values are copied into storage, adding new keys to storage or updating existing ones
- MERGE_KV_DELETE, // update values specify keys that get deleted from storage
- MERGE_KV_BORROW, // update values only update existing keys in storage, keys in update that do not exist in storage are discarded
-};
-
-//-----------------------------------------------------------------------------
-// Purpose: Simple recursive data access class
-// Used in vgui for message parameters and resource files
-// Destructor deletes all child KeyValues nodes
-// Data is stored in key (string names) - (string/int/float)value pairs called nodes.
-//
-// About KeyValues Text File Format:
-
-// It has 3 control characters '{', '}' and '"'. Names and values may be quoted or
-// not. The quote '"' character must not be used within name or values, only for
-// quoting whole tokens. You may use escape sequences wile parsing and add within a
-// quoted token a \" to add quotes within your name or token. When using Escape
-// Sequence the parser must now that by setting KeyValues::UsesEscapeSequences( true ),
-// which it's off by default. Non-quoted tokens ends with a whitespace, '{', '}' and '"'.
-// So you may use '{' and '}' within quoted tokens, but not for non-quoted tokens.
-// An open bracket '{' after a key name indicates a list of subkeys which is finished
-// with a closing bracket '}'. Subkeys use the same definitions recursively.
-// Whitespaces are space, return, newline and tabulator. Allowed Escape sequences
-// are \n, \t, \\, \n and \". The number character '#' is used for macro purposes
-// (eg #include), don't use it as first character in key names.
-//-----------------------------------------------------------------------------
-class KeyValues
-{
-private:
- KeyValues(); // for internal use only
-
-public:
- // Constructors/destructors
- KeyValues(const char* pszSetName);
- KeyValues(const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue);
- KeyValues(const char* pszSetName, const char* pszFirstKey, const wchar_t* pwszFirstValue);
- KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue);
- KeyValues(
- const char* pszSetName, const char* pszFirstKey, const char* pszFirstValue, const char* pszSecondKey, const char* pszSecondValue);
- KeyValues(const char* pszSetName, const char* pszFirstKey, int iFirstValue, const char* pszSecondKey, int iSecondValue);
- ~KeyValues(void);
-
- void Init(void);
- void Clear(void);
- void DeleteThis(void);
- void RemoveEverything();
-
- KeyValues* FindKey(const char* pKeyName, bool bCreate = false);
- KeyValues* FindLastSubKey(void) const;
-
- void AddSubKey(KeyValues* pSubkey);
- void RemoveSubKey(KeyValues* pSubKey);
- void InsertSubKey(int nIndex, KeyValues* pSubKey);
- bool ContainsSubKey(KeyValues* pSubKey);
- void SwapSubKey(KeyValues* pExistingSubkey, KeyValues* pNewSubKey);
- void ElideSubKey(KeyValues* pSubKey);
-
- // Data access
- bool IsEmpty(const char* pszKeyName);
- KeyValues* GetFirstTrueSubKey(void) const;
- KeyValues* GetNextTrueSubKey(void) const;
- KeyValues* GetFirstValue(void) const;
- KeyValues* GetNextValue(void) const;
- KeyValues* GetFirstSubKey() const;
- KeyValues* GetNextKey() const;
- const char* GetName(void) const;
- int GetInt(const char* pszKeyName, int iDefaultValue);
- uint64_t GetUint64(const char* pszKeyName, uint64_t nDefaultValue);
- void* GetPtr(const char* pszKeyName, void* pDefaultValue);
- float GetFloat(const char* pszKeyName, float flDefaultValue);
- const char* GetString(const char* pszKeyName = nullptr, const char* pszDefaultValue = "");
- const wchar_t* GetWString(const char* pszKeyName = nullptr, const wchar_t* pwszDefaultValue = L"");
- Color GetColor(const char* pszKeyName, const Color& defaultColor);
- KeyValuesTypes_t GetDataType(const char* pszKeyName);
- KeyValuesTypes_t GetDataType(void) const;
-
- // Key writing
- void SetInt(const char* pszKeyName, int iValue);
- void SetUint64(const char* pszKeyName, uint64_t nValue);
- void SetPtr(const char* pszKeyName, void* pValue);
- void SetNextKey(KeyValues* pDat);
- void SetName(const char* pszName);
- void SetString(const char* pszKeyName, const char* pszValue);
- void SetWString(const char* pszKeyName, const wchar_t* pwszValue);
- void SetStringValue(char const* pszValue);
- void SetColor(const char* pszKeyName, Color color);
- void SetFloat(const char* pszKeyName, float flValue);
-
- void RecursiveCopyKeyValues(KeyValues& src);
- void CopySubkeys(KeyValues* pParent) const;
- KeyValues* MakeCopy(void) const;
-
-public:
- uint32_t m_iKeyName : 24; // 0x0000
- uint32_t m_iKeyNameCaseSensitive1 : 8; // 0x0003
- char* m_sValue; // 0x0008
- wchar_t* m_wsValue; // 0x0010
- union // 0x0018
- {
- int m_iValue;
- float m_flValue;
- void* m_pValue;
- unsigned char m_Color[4];
- };
- char m_szShortName[8]; // 0x0020
- char m_iDataType; // 0x0028
- char m_bHasEscapeSequences; // 0x0029
- uint16_t m_iKeyNameCaseSensitive2; // 0x002A
- KeyValues* m_pPeer; // 0x0030
- KeyValues* m_pSub; // 0x0038
- KeyValues* m_pChain; // 0x0040
-};
diff --git a/NorthstarDLL/shared/maxplayers.cpp b/NorthstarDLL/shared/maxplayers.cpp
deleted file mode 100644
index 711193d4..00000000
--- a/NorthstarDLL/shared/maxplayers.cpp
+++ /dev/null
@@ -1,640 +0,0 @@
-#include "core/tier0.h"
-#include "maxplayers.h"
-
-AUTOHOOK_INIT()
-
-// never set this to anything below 32
-#define NEW_MAX_PLAYERS 64
-// dg note: the theoretical limit is actually 100, 76 works without entity issues, and 64 works without clientside prediction issues.
-
-#define PAD_NUMBER(number, boundary) (((number) + ((boundary)-1)) / (boundary)) * (boundary)
-
-// this is horrible
-constexpr int PlayerResource_Name_Start = 0; // Start of modded allocated space.
-constexpr int PlayerResource_Name_Size = ((NEW_MAX_PLAYERS + 1) * 8); // const char* m_szName[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_Ping_Start = PlayerResource_Name_Start + PlayerResource_Name_Size;
-constexpr int PlayerResource_Ping_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int m_iPing[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_Team_Start = PlayerResource_Ping_Start + PlayerResource_Ping_Size;
-constexpr int PlayerResource_Team_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int m_iTeam[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_PRHealth_Start = PlayerResource_Team_Start + PlayerResource_Team_Size;
-constexpr int PlayerResource_PRHealth_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int m_iPRHealth[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_Connected_Start = PlayerResource_PRHealth_Start + PlayerResource_PRHealth_Size;
-constexpr int PlayerResource_Connected_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int (used as a bool) m_bConnected[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_Alive_Start = PlayerResource_Connected_Start + PlayerResource_Connected_Size;
-constexpr int PlayerResource_Alive_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int (used as a bool) m_bAlive[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_BoolStats_Start = PlayerResource_Alive_Start + PlayerResource_Alive_Size;
-constexpr int PlayerResource_BoolStats_Size = ((NEW_MAX_PLAYERS + 1) * 4); // int (used as a bool idk) m_boolStats[MAX_PLAYERS + 1];
-
-constexpr int PlayerResource_KillStats_Start = PlayerResource_BoolStats_Start + PlayerResource_BoolStats_Size;
-constexpr int PlayerResource_KillStats_Length = PAD_NUMBER((NEW_MAX_PLAYERS + 1) * 6, 4);
-constexpr int PlayerResource_KillStats_Size = (PlayerResource_KillStats_Length * 6); // int m_killStats[MAX_PLAYERS + 1][6];
-
-constexpr int PlayerResource_ScoreStats_Start = PlayerResource_KillStats_Start + PlayerResource_KillStats_Size;
-constexpr int PlayerResource_ScoreStats_Length = PAD_NUMBER((NEW_MAX_PLAYERS + 1) * 5, 4);
-constexpr int PlayerResource_ScoreStats_Size = (PlayerResource_ScoreStats_Length * 4); // int m_scoreStats[MAX_PLAYERS + 1][5];
-
-// must be the usage of the last field to account for any possible paddings
-constexpr int PlayerResource_TotalSize = PlayerResource_ScoreStats_Start + PlayerResource_ScoreStats_Size;
-
-constexpr int Team_PlayerArray_AddedLength = NEW_MAX_PLAYERS - 32;
-constexpr int Team_PlayerArray_AddedSize = PAD_NUMBER(Team_PlayerArray_AddedLength * 8, 4);
-constexpr int Team_AddedSize = Team_PlayerArray_AddedSize;
-
-bool MaxPlayersIncreaseEnabled()
-{
- static bool bMaxPlayersIncreaseEnabled = CommandLine()->CheckParm("-experimentalmaxplayersincrease");
- return bMaxPlayersIncreaseEnabled;
-}
-
-int GetMaxPlayers()
-{
- if (MaxPlayersIncreaseEnabled())
- return NEW_MAX_PLAYERS;
-
- return 32;
-}
-
-template <class T> void ChangeOffset(CMemoryAddress addr, unsigned int offset)
-{
- addr.Patch((BYTE*)&offset, sizeof(T));
-}
-
-// clang-format off
-AUTOHOOK(StringTables_CreateStringTable, engine.dll + 0x22E220,
-void*,, (void* thisptr, const char* name, int maxentries, int userdatafixedsize, int userdatanetworkbits, int flags))
-// clang-format on
-{
- // Change the amount of entries to account for a bigger player amount
- if (!strcmp(name, "userinfo"))
- {
- int maxPlayersPowerOf2 = 1;
- while (maxPlayersPowerOf2 < NEW_MAX_PLAYERS)
- maxPlayersPowerOf2 <<= 1;
-
- maxentries = maxPlayersPowerOf2;
- }
-
- return StringTables_CreateStringTable(thisptr, name, maxentries, userdatafixedsize, userdatanetworkbits, flags);
-}
-
-ON_DLL_LOAD("engine.dll", MaxPlayersOverride_Engine, (CModule module))
-{
- if (!MaxPlayersIncreaseEnabled())
- return;
-
- AUTOHOOK_DISPATCH_MODULE(engine.dll)
-
- // patch GetPlayerLimits to ignore the boundary limit
- module.Offset(0x116458).Patch("0xEB"); // jle => jmp
-
- // patch ED_Alloc to change nFirstIndex
- ChangeOffset<int>(module.Offset(0x18F46C + 1), NEW_MAX_PLAYERS + 8 + 1); // original: 41 (sv.GetMaxClients() + 1)
-
- // patch CGameServer::SpawnServer to change GetMaxClients inline
- ChangeOffset<int>(module.Offset(0x119543 + 2), NEW_MAX_PLAYERS + 8 + 1); // original: 41 (sv.GetMaxClients() + 1)
-
- // patch CGameServer::SpawnServer to change for loop
- ChangeOffset<unsigned char>(module.Offset(0x11957F + 2), NEW_MAX_PLAYERS); // original: 32
-
- // patch CGameServer::SpawnServer to change for loop (there are two)
- ChangeOffset<unsigned char>(module.Offset(0x119586 + 2), NEW_MAX_PLAYERS + 1); // original: 33 (32 + 1)
-
- // patch max players somewhere in CClientState
- ChangeOffset<unsigned char>(module.Offset(0x1A162C + 2), NEW_MAX_PLAYERS - 1); // original: 31 (32 - 1)
-
- // patch max players in userinfo stringtable creation
- /*{
- int maxPlayersPowerOf2 = 1;
- while (maxPlayersPowerOf2 < NEW_MAX_PLAYERS)
- maxPlayersPowerOf2 <<= 1;
- ChangeOffset<unsigned char>((char*)baseAddress + 0x114B79 + 3, maxPlayersPowerOf2); // original: 32
- }*/
- // this is not supposed to work at all but it does on 64 players (how)
- // proper fix below
-
- // patch max players in userinfo stringtable creation loop
- ChangeOffset<unsigned char>(module.Offset(0x114C48 + 2), NEW_MAX_PLAYERS); // original: 32
-
- // do not load prebaked SendTable message list
- module.Offset(0x75859).Patch("EB"); // jnz -> jmp
-}
-
-typedef void (*RunUserCmds_Type)(bool a1, float a2);
-RunUserCmds_Type RunUserCmds_Original;
-
-HMODULE serverBase = 0;
-auto RandomIntZeroMax = (__int64(__fastcall*)())0;
-
-// lazy rebuild
-// clang-format off
-AUTOHOOK(RunUserCmds, server.dll + 0x483D10,
-void,, (bool a1, float a2))
-// clang-format on
-{
- unsigned char v3; // bl
- int v5; // er14
- int i; // edi
- __int64 v7; // rax
- DWORD* v8; // rbx
- int v9; // edi
- __int64* v10; // rsi
- __int64 v11; // rax
- int v12; // er12
- __int64 v13; // rdi
- int v14; // ebx
- int v15; // eax
- __int64 v16; // r8
- int v17; // edx
- char v18; // r15
- char v19; // bp
- int v20; // esi
- __int64* v21; // rdi
- __int64 v22; // rcx
- bool v23; // al
- __int64 v24; // rax
- __int64 v25[NEW_MAX_PLAYERS]; // [rsp+20h] [rbp-138h] BYREF
-
- uintptr_t base = (__int64)serverBase;
- auto g_pGlobals = *(__int64*)(base + 0xBFBE08);
- __int64 globals = g_pGlobals;
-
- auto g_pEngineServer = *(__int64*)(base + 0xBFBD98);
-
- auto qword_1814D9648 = *(__int64*)(base + 0x14D9648);
- auto qword_1814DA408 = *(__int64*)(base + 0x14DA408);
- auto qword_1812107E8 = *(__int64*)(base + 0x12107E8);
- auto qword_1812105A8 = *(__int64*)(base + 0x12105A8);
-
- auto UTIL_PlayerByIndex = (__int64(__fastcall*)(int index))(base + 0x26AA10);
- auto sub_180485590 = (void(__fastcall*)(__int64))(base + 0x485590);
- auto sub_18058CD80 = (void(__fastcall*)(__int64))(base + 0x58CD80);
- auto sub_1805A6D90 = (void(__fastcall*)(__int64))(base + 0x5A6D90);
- auto sub_1805A6E50 = (bool(__fastcall*)(__int64, int, char))(base + 0x5A6E50);
- auto sub_1805A6C20 = (void(__fastcall*)(__int64))(base + 0x5A6C20);
-
- v3 = *(unsigned char*)(g_pGlobals + 73);
- if (*(DWORD*)(qword_1814D9648 + 92) &&
- ((*(unsigned __int8(__fastcall**)(__int64))(*(__int64*)g_pEngineServer + 32))(g_pEngineServer) ||
- !*(DWORD*)(qword_1814DA408 + 92)) &&
- v3)
- {
- globals = g_pGlobals;
- v5 = 1;
- for (i = 1; i <= *(DWORD*)(g_pGlobals + 52); ++i)
- {
- v7 = UTIL_PlayerByIndex(i);
- v8 = (DWORD*)v7;
- if (v7)
- {
- *(__int64*)(base + 0x1210420) = v7;
- *(float*)(g_pGlobals + 16) = a2;
- if (!a1)
- sub_18058CD80(v7);
- sub_1805A6D90((__int64)v8);
- }
- globals = g_pGlobals;
- }
- memset(v25, 0, sizeof(v25));
- v9 = 0;
- if (*(int*)(globals + 52) > 0)
- {
- v10 = v25;
- do
- {
- v11 = UTIL_PlayerByIndex(++v9);
- globals = g_pGlobals;
- *v10++ = v11;
- } while (v9 < *(DWORD*)(globals + 52));
- }
- v12 = *(DWORD*)(qword_1812107E8 + 92);
- if (*(DWORD*)(qword_1812105A8 + 92))
- {
- v13 = *(DWORD*)(globals + 52) - 1;
- if (v13 >= 1)
- {
- v14 = *(DWORD*)(globals + 52);
- do
- {
- v15 = RandomIntZeroMax();
- v16 = v25[v13--];
- v17 = v15 % v14--;
- v25[v13 + 1] = v25[v17];
- v25[v17] = v16;
- } while (v13 >= 1);
- globals = g_pGlobals;
- }
- }
- v18 = 1;
- do
- {
- v19 = 0;
- v20 = 0;
- if (*(int*)(globals + 52) > 0)
- {
- v21 = v25;
- do
- {
- v22 = *v21;
- if (*v21)
- {
- *(__int64*)(base + 0x1210420) = *v21;
- *(float*)(globals + 16) = a2;
- v23 = sub_1805A6E50(v22, v12, v18);
- globals = g_pGlobals;
- if (v23)
- v19 = 1;
- else
- *v21 = 0;
- }
- ++v20;
- ++v21;
- } while (v20 < *(DWORD*)(globals + 52));
- }
- v18 = 0;
- } while (v19);
- if (*(int*)(globals + 52) >= 1)
- {
- do
- {
- v24 = UTIL_PlayerByIndex(v5);
- if (v24)
- {
- *(__int64*)(base + 0x1210420) = v24;
- *(float*)(g_pGlobals + 16) = a2;
- sub_1805A6C20(v24);
- }
- ++v5;
- } while (v5 <= *(DWORD*)(g_pGlobals + 52));
- }
- sub_180485590(*(__int64*)(base + 0xB7B2D8));
- }
-}
-
-// clang-format off
-AUTOHOOK(SendPropArray2, server.dll + 0x12B130,
-__int64,, (__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn, unsigned char unk1))
-// clang-format on
-{
- // Change the amount of elements to account for a bigger player amount
- if (!strcmp(name, "\"player_array\""))
- elements = NEW_MAX_PLAYERS;
-
- return SendPropArray2(recvProp, elements, flags, name, proxyFn, unk1);
-}
-
-ON_DLL_LOAD("server.dll", MaxPlayersOverride_Server, (CModule module))
-{
- if (!MaxPlayersIncreaseEnabled())
- return;
-
- AUTOHOOK_DISPATCH_MODULE(server.dll)
-
- // get required data
- serverBase = (HMODULE)module.m_nAddress;
- RandomIntZeroMax = (decltype(RandomIntZeroMax))(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomIntZeroMax"));
-
- // patch max players amount
- ChangeOffset<unsigned char>(module.Offset(0x9A44D + 3), NEW_MAX_PLAYERS); // 0x20 (32) => 0x80 (128)
-
- // patch SpawnGlobalNonRewinding to change forced edict index
- ChangeOffset<unsigned char>(module.Offset(0x2BC403 + 2), NEW_MAX_PLAYERS + 1); // original: 33 (32 + 1)
-
- constexpr int CPlayerResource_OriginalSize = 4776;
- constexpr int CPlayerResource_AddedSize = PlayerResource_TotalSize;
- constexpr int CPlayerResource_ModifiedSize = CPlayerResource_OriginalSize + CPlayerResource_AddedSize;
-
- // CPlayerResource class allocation function - allocate a bigger amount to fit all new max player data
- ChangeOffset<unsigned int>(module.Offset(0x5C560A + 1), CPlayerResource_ModifiedSize);
-
- // DT_PlayerResource::m_iPing SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C5059 + 2), CPlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C50A8 + 2), CPlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C50E2 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_iPing DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94598), CPlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB9459C), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB945C0), PlayerResource_Ping_Size);
-
- // DT_PlayerResource::m_iTeam SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C5110 + 2), CPlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C519C + 2), CPlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C517E + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_iTeam DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94600), CPlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB94604), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB94628), PlayerResource_Team_Size);
-
- // DT_PlayerResource::m_iPRHealth SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C51C0 + 2), CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C5204 + 2), CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C523E + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_iPRHealth DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94668), CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB9466C), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB94690), PlayerResource_PRHealth_Size);
-
- // DT_PlayerResource::m_bConnected SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C526C + 2), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C52B4 + 2), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C52EE + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_bConnected DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB946D0), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB946D4), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB946F8), PlayerResource_Connected_Size);
-
- // DT_PlayerResource::m_bAlive SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C5321 + 2), CPlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C5364 + 2), CPlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C539E + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_bAlive DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94738), CPlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB9473C), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB94760), PlayerResource_Alive_Size);
-
- // DT_PlayerResource::m_boolStats SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C53CC + 2), CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C5414 + 2), CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C544E + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_boolStats DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB947A0), CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB947A4), NEW_MAX_PLAYERS + 1);
- ChangeOffset<unsigned short>(module.Offset(0xB947C8), PlayerResource_BoolStats_Size);
-
- // DT_PlayerResource::m_killStats SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C547C + 2), CPlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C54E2 + 2), CPlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C54FE + 4), PlayerResource_KillStats_Length);
-
- // DT_PlayerResource::m_killStats DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94808), CPlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB9480C), PlayerResource_KillStats_Length);
- ChangeOffset<unsigned short>(module.Offset(0xB94830), PlayerResource_KillStats_Size);
-
- // DT_PlayerResource::m_scoreStats SendProp
- ChangeOffset<unsigned int>(module.Offset(0x5C5528 + 2), CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C5576 + 2), CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C5584 + 4), PlayerResource_ScoreStats_Length);
-
- // DT_PlayerResource::m_scoreStats DataMap
- ChangeOffset<unsigned int>(module.Offset(0xB94870), CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xB94874), PlayerResource_ScoreStats_Length);
- ChangeOffset<unsigned short>(module.Offset(0xB94898), PlayerResource_ScoreStats_Size);
-
- // CPlayerResource::UpdatePlayerData - m_bConnected
- ChangeOffset<unsigned int>(module.Offset(0x5C66EE + 4), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C672E + 4), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // CPlayerResource::UpdatePlayerData - m_iPing
- ChangeOffset<unsigned int>(module.Offset(0x5C6394 + 4), CPlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C63DB + 4), CPlayerResource_OriginalSize + PlayerResource_Ping_Start);
-
- // CPlayerResource::UpdatePlayerData - m_iTeam
- ChangeOffset<unsigned int>(module.Offset(0x5C63FD + 4), CPlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C6442 + 4), CPlayerResource_OriginalSize + PlayerResource_Team_Start);
-
- // CPlayerResource::UpdatePlayerData - m_iPRHealth
- ChangeOffset<unsigned int>(module.Offset(0x5C645B + 4), CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C64A0 + 4), CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
-
- // CPlayerResource::UpdatePlayerData - m_bConnected
- ChangeOffset<unsigned int>(module.Offset(0x5C64AA + 4), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C64F0 + 4), CPlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // CPlayerResource::UpdatePlayerData - m_bAlive
- ChangeOffset<unsigned int>(module.Offset(0x5C650A + 4), CPlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C654F + 4), CPlayerResource_OriginalSize + PlayerResource_Alive_Start);
-
- // CPlayerResource::UpdatePlayerData - m_boolStats
- ChangeOffset<unsigned int>(module.Offset(0x5C6557 + 4), CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C65A5 + 4), CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
-
- // CPlayerResource::UpdatePlayerData - m_scoreStats
- ChangeOffset<unsigned int>(module.Offset(0x5C65C2 + 3), CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C65E3 + 4), CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
-
- // CPlayerResource::UpdatePlayerData - m_killStats
- ChangeOffset<unsigned int>(module.Offset(0x5C6654 + 3), CPlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x5C665B + 3), CPlayerResource_OriginalSize + PlayerResource_KillStats_Start);
-
- *module.Offset(0x14E7390).RCast<DWORD*>() = 0;
- auto DT_PlayerResource_Construct = module.Offset(0x5C4FE0).RCast<__int64(__fastcall*)()>();
- DT_PlayerResource_Construct();
-
- constexpr int CTeam_OriginalSize = 3336;
- constexpr int CTeam_AddedSize = Team_AddedSize;
- constexpr int CTeam_ModifiedSize = CTeam_OriginalSize + CTeam_AddedSize;
-
- // CTeam class allocation function - allocate a bigger amount to fit all new team player data
- ChangeOffset<unsigned int>(module.Offset(0x23924A + 1), CTeam_ModifiedSize);
-
- // CTeam::CTeam - increase memset length to clean newly allocated data
- ChangeOffset<unsigned int>(module.Offset(0x2395AE + 2), 256 + CTeam_AddedSize);
-
- *module.Offset(0xC945A0).RCast<DWORD*>() = 0;
- auto DT_Team_Construct = module.Offset(0x238F50).RCast<__int64(__fastcall*)()>();
- DT_Team_Construct();
-}
-
-// clang-format off
-AUTOHOOK(RecvPropArray2, client.dll + 0x1CEDA0,
-__int64,, (__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn))
-// clang-format on
-{
- // Change the amount of elements to account for a bigger player amount
- if (!strcmp(name, "\"player_array\""))
- elements = NEW_MAX_PLAYERS;
-
- return RecvPropArray2(recvProp, elements, flags, name, proxyFn);
-}
-
-ON_DLL_LOAD("client.dll", MaxPlayersOverride_Client, (CModule module))
-{
- if (!MaxPlayersIncreaseEnabled())
- return;
-
- AUTOHOOK_DISPATCH_MODULE(client.dll)
-
- constexpr int C_PlayerResource_OriginalSize = 5768;
- constexpr int C_PlayerResource_AddedSize = PlayerResource_TotalSize;
- constexpr int C_PlayerResource_ModifiedSize = C_PlayerResource_OriginalSize + C_PlayerResource_AddedSize;
-
- // C_PlayerResource class allocation function - allocate a bigger amount to fit all new max player data
- ChangeOffset<unsigned int>(module.Offset(0x164C41 + 1), C_PlayerResource_ModifiedSize);
-
- // C_PlayerResource::C_PlayerResource - change loop end value
- ChangeOffset<unsigned char>(module.Offset(0x1640C4 + 2), NEW_MAX_PLAYERS - 32);
-
- // C_PlayerResource::C_PlayerResource - change m_szName address
- ChangeOffset<unsigned int>(
- module.Offset(0x1640D0 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start); // appended to the end of the class
-
- // C_PlayerResource::C_PlayerResource - change m_szName address
- ChangeOffset<unsigned int>(
- module.Offset(0x1640D0 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start); // appended to the end of the class
-
- // C_PlayerResource::C_PlayerResource - increase memset length to clean newly allocated data
- ChangeOffset<unsigned int>(module.Offset(0x1640D0 + 3), 2244 + C_PlayerResource_AddedSize);
-
- // C_PlayerResource::UpdatePlayerName - change m_szName address
- ChangeOffset<unsigned int>(module.Offset(0x16431F + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName - change m_szName address 1
- ChangeOffset<unsigned int>(module.Offset(0x1645B1 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName - change m_szName address 2
- ChangeOffset<unsigned int>(module.Offset(0x1645C0 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName - change m_szName address 3
- ChangeOffset<unsigned int>(module.Offset(0x1645DD + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_szName address 1
- ChangeOffset<unsigned int>(module.Offset(0x164B71 + 4), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_szName address 2
- ChangeOffset<unsigned int>(module.Offset(0x164B9B + 4), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 1
- ChangeOffset<unsigned int>(module.Offset(0x164641 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 2
- ChangeOffset<unsigned int>(module.Offset(0x164650 + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 3
- ChangeOffset<unsigned int>(module.Offset(0x16466D + 3), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 1
- ChangeOffset<unsigned int>(module.Offset(0x164BA3 + 4), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 2
- ChangeOffset<unsigned int>(module.Offset(0x164BCE + 4), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 3
- ChangeOffset<unsigned int>(module.Offset(0x164BE7 + 4), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
-
- // C_PlayerResource::m_szName
- ChangeOffset<unsigned int>(module.Offset(0xc350f8), C_PlayerResource_OriginalSize + PlayerResource_Name_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc350f8 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource size
- ChangeOffset<unsigned int>(module.Offset(0x163415 + 6), C_PlayerResource_ModifiedSize);
-
- // DT_PlayerResource::m_iPing RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x163492 + 2), C_PlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1634D6 + 2), C_PlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163515 + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_iPing
- ChangeOffset<unsigned int>(module.Offset(0xc35170), C_PlayerResource_OriginalSize + PlayerResource_Ping_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc35170 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_iTeam RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x163549 + 2), C_PlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1635C8 + 2), C_PlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1635AD + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_iTeam
- ChangeOffset<unsigned int>(module.Offset(0xc351e8), C_PlayerResource_OriginalSize + PlayerResource_Team_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc351e8 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_iPRHealth RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x1635F9 + 2), C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163625 + 2), C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163675 + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_iPRHealth
- ChangeOffset<unsigned int>(module.Offset(0xc35260), C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc35260 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_bConnected RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x1636A9 + 2), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1636D5 + 2), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163725 + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_bConnected
- ChangeOffset<unsigned int>(module.Offset(0xc352d8), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc352d8 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_bAlive RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x163759 + 2), C_PlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163785 + 2), C_PlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1637D5 + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_bAlive
- ChangeOffset<unsigned int>(module.Offset(0xc35350), C_PlayerResource_OriginalSize + PlayerResource_Alive_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc35350 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_boolStats RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x163809 + 2), C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163835 + 2), C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163885 + 5), NEW_MAX_PLAYERS + 1);
-
- // C_PlayerResource::m_boolStats
- ChangeOffset<unsigned int>(module.Offset(0xc353c8), C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc353c8 + 4), NEW_MAX_PLAYERS + 1);
-
- // DT_PlayerResource::m_killStats RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x1638B3 + 2), C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1638E5 + 2), C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163935 + 5), PlayerResource_KillStats_Length);
-
- // C_PlayerResource::m_killStats
- ChangeOffset<unsigned int>(module.Offset(0xc35440), C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc35440 + 4), PlayerResource_KillStats_Length);
-
- // DT_PlayerResource::m_scoreStats RecvProp
- ChangeOffset<unsigned int>(module.Offset(0x163969 + 2), C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x163995 + 2), C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned int>(module.Offset(0x1639E5 + 5), PlayerResource_ScoreStats_Length);
-
- // C_PlayerResource::m_scoreStats
- ChangeOffset<unsigned int>(module.Offset(0xc354b8), C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start);
- ChangeOffset<unsigned short>(module.Offset(0xc354b8 + 4), PlayerResource_ScoreStats_Length);
-
- // C_PlayerResource::GetPlayerName - change m_bConnected address
- ChangeOffset<unsigned int>(module.Offset(0x164599 + 3), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // C_PlayerResource::GetPlayerName2 (?) - change m_bConnected address
- ChangeOffset<unsigned int>(module.Offset(0x164629 + 3), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // C_PlayerResource::GetPlayerName internal func - change m_bConnected address
- ChangeOffset<unsigned int>(module.Offset(0x164B13 + 3), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // Some other get name func (that seems to be unused) - change m_bConnected address
- ChangeOffset<unsigned int>(module.Offset(0x164860 + 3), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- // Some other get name func 2 (that seems to be unused too) - change m_bConnected address
- ChangeOffset<unsigned int>(module.Offset(0x164834 + 3), C_PlayerResource_OriginalSize + PlayerResource_Connected_Start);
-
- *module.Offset(0xC35068).RCast<DWORD*>() = 0;
- auto DT_PlayerResource_Construct = module.Offset(0x163400).RCast<__int64(__fastcall*)()>();
- DT_PlayerResource_Construct();
-
- constexpr int C_Team_OriginalSize = 3200;
- constexpr int C_Team_AddedSize = Team_AddedSize;
- constexpr int C_Team_ModifiedSize = C_Team_OriginalSize + C_Team_AddedSize;
-
- // C_Team class allocation function - allocate a bigger amount to fit all new team player data
- ChangeOffset<unsigned int>(module.Offset(0x182321 + 1), C_Team_ModifiedSize);
-
- // C_Team::C_Team - increase memset length to clean newly allocated data
- ChangeOffset<unsigned int>(module.Offset(0x1804A2 + 2), 256 + C_Team_AddedSize);
-
- // DT_Team size
- ChangeOffset<unsigned int>(module.Offset(0xC3AA0C), C_Team_ModifiedSize);
-
- *module.Offset(0xC3AFF8).RCast<DWORD*>() = 0;
- auto DT_Team_Construct = module.Offset(0x17F950).RCast<__int64(__fastcall*)()>();
- DT_Team_Construct();
-}
diff --git a/NorthstarDLL/shared/maxplayers.h b/NorthstarDLL/shared/maxplayers.h
deleted file mode 100644
index 40a3ac58..00000000
--- a/NorthstarDLL/shared/maxplayers.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-
-int GetMaxPlayers();
diff --git a/NorthstarDLL/shared/misccommands.cpp b/NorthstarDLL/shared/misccommands.cpp
deleted file mode 100644
index 15da6767..00000000
--- a/NorthstarDLL/shared/misccommands.cpp
+++ /dev/null
@@ -1,391 +0,0 @@
-#include "misccommands.h"
-#include "core/convar/concommand.h"
-#include "shared/playlist.h"
-#include "engine/r2engine.h"
-#include "client/r2client.h"
-#include "core/tier0.h"
-#include "engine/hoststate.h"
-#include "masterserver/masterserver.h"
-#include "mods/modmanager.h"
-#include "server/auth/serverauthentication.h"
-#include "squirrel/squirrel.h"
-
-void ConCommand_force_newgame(const CCommand& arg)
-{
- if (arg.ArgC() < 2)
- return;
-
- g_pHostState->m_iNextState = HostState_t::HS_NEW_GAME;
- strncpy(g_pHostState->m_levelName, arg.Arg(1), sizeof(g_pHostState->m_levelName));
-}
-
-void ConCommand_ns_start_reauth_and_leave_to_lobby(const CCommand& arg)
-{
- // hack for special case where we're on a local server, so we erase our own newly created auth data on disconnect
- g_pMasterServerManager->m_bNewgameAfterSelfAuth = true;
- g_pMasterServerManager->AuthenticateWithOwnServer(g_pLocalPlayerUserID, g_pMasterServerManager->m_sOwnClientAuthToken);
-}
-
-void ConCommand_ns_end_reauth_and_leave_to_lobby(const CCommand& arg)
-{
- if (g_pServerAuthentication->m_RemoteAuthenticationData.size())
- g_pCVar->FindVar("serverfilter")->SetValue(g_pServerAuthentication->m_RemoteAuthenticationData.begin()->first.c_str());
-
- // weird way of checking, but check if client script vm is initialised, mainly just to allow players to cancel this
- if (g_pSquirrel<ScriptContext::CLIENT>->m_pSQVM)
- {
- g_pServerAuthentication->m_bNeedLocalAuthForNewgame = true;
-
- // this won't set playlist correctly on remote clients, don't think they can set playlist until they've left which sorta
- // fucks things should maybe set this in HostState_NewGame?
- R2::SetCurrentPlaylist("tdm");
- strcpy(g_pHostState->m_levelName, "mp_lobby");
- g_pHostState->m_iNextState = HostState_t::HS_NEW_GAME;
- }
-}
-
-void ConCommand_cvar_setdefaultvalue(const CCommand& arg)
-{
- if (arg.ArgC() < 3)
- {
- spdlog::info("usage: cvar_setdefaultvalue mp_gamemode tdm");
- return;
- }
-
- ConVar* pCvar = g_pCVar->FindVar(arg.Arg(1));
- if (!pCvar)
- {
- spdlog::info("usage: cvar_setdefaultvalue mp_gamemode tdm");
- return;
- }
-
- // unfortunately no way for us to not leak memory here, as default value might not be in writeable memory by default
- int nLen = strlen(arg.Arg(2));
- char* pBuf = new char[nLen + 1];
- strncpy_s(pBuf, nLen + 1, arg.Arg(2), nLen);
-
- pCvar->m_pszDefaultValue = pBuf;
-}
-
-void ConCommand_cvar_setvalueanddefaultvalue(const CCommand& arg)
-{
- if (arg.ArgC() < 3)
- {
- spdlog::info("usage: cvar_setvalueanddefaultvalue mp_gamemode tdm");
- return;
- }
-
- ConVar* pCvar = g_pCVar->FindVar(arg.Arg(1));
- if (!pCvar)
- {
- spdlog::info("usage: cvar_setvalueanddefaultvalue mp_gamemode tdm");
- return;
- }
-
- // unfortunately no way for us to not leak memory here, as default value might not be in writeable memory by default
- int nLen = strlen(arg.Arg(2));
- char* pBuf = new char[nLen + 1];
- strncpy_s(pBuf, nLen + 1, arg.Arg(2), nLen);
-
- pCvar->m_pszDefaultValue = pBuf;
- pCvar->SetValue(pCvar->m_pszDefaultValue);
-}
-
-void ConCommand_cvar_reset(const CCommand& arg)
-{
- if (arg.ArgC() < 2)
- {
- spdlog::info("usage: cvar_reset mp_gamemode");
- return;
- }
-
- ConVar* pCvar = g_pCVar->FindVar(arg.Arg(1));
- if (!pCvar)
- {
- spdlog::info("usage: cvar_reset mp_gamemode");
- return;
- }
-
- // reset cvar
- pCvar->SetValue(pCvar->m_pszDefaultValue);
-}
-
-void AddMiscConCommands()
-{
- RegisterConCommand(
- "force_newgame",
- ConCommand_force_newgame,
- "forces a map load through directly setting g_pHostState->m_iNextState to HS_NEW_GAME",
- FCVAR_NONE);
-
- RegisterConCommand(
- "ns_start_reauth_and_leave_to_lobby",
- ConCommand_ns_start_reauth_and_leave_to_lobby,
- "called by the server, used to reauth and return the player to lobby when leaving a game",
- FCVAR_SERVER_CAN_EXECUTE);
-
- // this is a concommand because we make a deferred call to it from another thread
- RegisterConCommand("ns_end_reauth_and_leave_to_lobby", ConCommand_ns_end_reauth_and_leave_to_lobby, "", FCVAR_NONE);
-
- RegisterConCommand(
- "cvar_setdefaultvalue",
- ConCommand_cvar_setdefaultvalue,
- "overwrites the default value of a cvar, for use with script and cvar_reset",
- FCVAR_NONE);
- RegisterConCommand(
- "cvar_setvalueanddefaultvalue",
- ConCommand_cvar_setvalueanddefaultvalue,
- "overwrites the current value and default value of a cvar, for use with script and cvar_reset",
- FCVAR_NONE);
- RegisterConCommand("cvar_reset", ConCommand_cvar_reset, "resets a cvar's value to its default value", FCVAR_NONE);
-}
-
-// fixes up various cvar flags to have more sane values
-void FixupCvarFlags()
-{
- if (CommandLine()->CheckParm("-allowdevcvars"))
- {
- // strip hidden and devonly cvar flags
- int iNumCvarsAltered = 0;
- for (auto& pair : g_pCVar->DumpToMap())
- {
- // strip flags
- int flags = pair.second->GetFlags();
- if (flags & FCVAR_DEVELOPMENTONLY)
- {
- flags &= ~FCVAR_DEVELOPMENTONLY;
- iNumCvarsAltered++;
- }
-
- if (flags & FCVAR_HIDDEN)
- {
- flags &= ~FCVAR_HIDDEN;
- iNumCvarsAltered++;
- }
-
- pair.second->m_nFlags = flags;
- }
-
- spdlog::info("Removed {} hidden/devonly cvar flags", iNumCvarsAltered);
- }
-
- // make all engine client commands FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS
- // these are usually checked through CGameClient::IsEngineClientCommand, but we get more control over this if we just do it through
- // cvar flags
- const char** ppEngineClientCommands = CModule("engine.dll").Offset(0x7C5EF0).RCast<const char**>();
-
- int i = 0;
- do
- {
- ConCommandBase* pCommand = g_pCVar->FindCommandBase(ppEngineClientCommands[i]);
- if (pCommand) // not all the commands in this array actually exist in respawn source
- pCommand->m_nFlags |= FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS;
- } while (ppEngineClientCommands[++i]);
-
- // array of cvars and the flags we want to add to them
- const std::vector<std::tuple<const char*, uint32_t>> CVAR_FIXUP_ADD_FLAGS = {
- // system commands (i.e. necessary for proper functionality)
- // servers need to be able to disconnect
- {"disconnect", FCVAR_SERVER_CAN_EXECUTE},
-
- // cheat commands
- {"give", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"give_server", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"givecurrentammo", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"takecurrentammo", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- {"switchclass", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"set", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"_setClassVarServer", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- {"ent_create", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_throw", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_setname", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_teleport", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_remove", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_remove_all", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"ent_fire", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- {"particle_create", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"particle_recreate", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"particle_kill", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- {"test_setteam", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"melee_lunge_ent", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- // fcvars that should be cheats
- {"net_ignoreAllSnapshots", FCVAR_CHEAT},
- {"highlight_draw", FCVAR_CHEAT},
- // these should potentially be replicated rather than cheat, like sv_footsteps is
- // however they're defined on client, so can't make replicated atm sadly
- {"cl_footstep_event_max_dist", FCVAR_CHEAT},
- {"cl_footstep_event_max_dist_titan", FCVAR_CHEAT},
- };
-
- // array of cvars and the flags we want to remove from them
- const std::vector<std::tuple<const char*, uint32_t>> CVAR_FIXUP_REMOVE_FLAGS = {
- // unsure how this command works, not even sure it's used on retail servers, deffo shouldn't be used on northstar
- {"migrateme", FCVAR_SERVER_CAN_EXECUTE | FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"recheck", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS}, // we don't need this on northstar servers, it's for communities
-
- // unsure how these work exactly (rpt system likely somewhat stripped?), removing anyway since they won't be used
- {"rpt_client_enable", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
- {"rpt_password", FCVAR_GAMEDLL_FOR_REMOTE_CLIENTS},
-
- // these are devonly by default but should be modifyable
- // NOTE: not all of these may actually do anything or work properly in practice
- // network settings
- {"cl_updaterate_mp", FCVAR_DEVELOPMENTONLY},
- {"cl_updaterate_sp", FCVAR_DEVELOPMENTONLY},
- {"clock_bias_sp", FCVAR_DEVELOPMENTONLY},
- {"clock_bias_mp", FCVAR_DEVELOPMENTONLY},
- {"cl_interpolate", FCVAR_DEVELOPMENTONLY}, // super duper ultra fucks anims if changed
- {"cl_interpolateSoAllAnimsLoop", FCVAR_DEVELOPMENTONLY},
- {"cl_cmdrate", FCVAR_DEVELOPMENTONLY},
- {"cl_cmdbackup", FCVAR_DEVELOPMENTONLY},
- {"rate", FCVAR_DEVELOPMENTONLY},
- {"net_minroutable", FCVAR_DEVELOPMENTONLY},
- {"net_maxroutable", FCVAR_DEVELOPMENTONLY},
- {"net_lerpFields", FCVAR_DEVELOPMENTONLY},
- {"net_ignoreAllSnapshots", FCVAR_DEVELOPMENTONLY},
- {"net_chokeloop", FCVAR_DEVELOPMENTONLY},
- {"sv_unlag", FCVAR_DEVELOPMENTONLY},
- {"sv_maxunlag", FCVAR_DEVELOPMENTONLY},
- {"sv_lagpushticks", FCVAR_DEVELOPMENTONLY},
- {"sv_instancebaselines", FCVAR_DEVELOPMENTONLY},
- {"sv_voiceEcho", FCVAR_DEVELOPMENTONLY},
- {"net_compresspackets", FCVAR_DEVELOPMENTONLY},
- {"net_compresspackets_minsize", FCVAR_DEVELOPMENTONLY},
- {"net_verifyEncryption", FCVAR_DEVELOPMENTONLY}, // unsure if functional in retail
-
- // gameplay settings
- {"vel_samples", FCVAR_DEVELOPMENTONLY},
- {"vel_sampleFrequency", FCVAR_DEVELOPMENTONLY},
- {"sv_friction", FCVAR_DEVELOPMENTONLY},
- {"sv_stopspeed", FCVAR_DEVELOPMENTONLY},
- {"sv_airaccelerate", FCVAR_DEVELOPMENTONLY},
- {"sv_forceGrapplesToFail", FCVAR_DEVELOPMENTONLY},
- {"sv_maxvelocity", FCVAR_DEVELOPMENTONLY},
- {"sv_footsteps", FCVAR_DEVELOPMENTONLY},
- // these 2 are flagged as CHEAT above, could be made REPLICATED later potentially
- {"cl_footstep_event_max_dist", FCVAR_DEVELOPMENTONLY},
- {"cl_footstep_event_max_dist_titan", FCVAR_DEVELOPMENTONLY},
- {"sv_balanceTeams", FCVAR_DEVELOPMENTONLY},
- {"rodeo_enable", FCVAR_DEVELOPMENTONLY},
- {"sv_forceRodeoToFail", FCVAR_DEVELOPMENTONLY},
- {"player_find_rodeo_target_per_cmd", FCVAR_DEVELOPMENTONLY}, // todo test before merge
- {"hud_takesshots", FCVAR_DEVELOPMENTONLY}, // very likely does not work but would be cool if it did
-
- {"cam_collision", FCVAR_DEVELOPMENTONLY},
- {"cam_idealdelta", FCVAR_DEVELOPMENTONLY},
- {"cam_ideallag", FCVAR_DEVELOPMENTONLY},
-
- // graphics/visual settings
- {"mat_colorcorrection", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoRadius", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoDepthMax", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoBlurSharpness", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoIntensity", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoBias", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoDistanceLerp", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoBlurRadius", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoExponent", FCVAR_DEVELOPMENTONLY},
- {"r_hbaoDepthFadePctDefault", FCVAR_DEVELOPMENTONLY},
- {"r_drawscreenspaceparticles", FCVAR_DEVELOPMENTONLY},
- {"ui_loadingscreen_fadeout_time", FCVAR_DEVELOPMENTONLY},
- {"ui_loadingscreen_fadein_time", FCVAR_DEVELOPMENTONLY},
- {"ui_loadingscreen_transition_time", FCVAR_DEVELOPMENTONLY},
- {"ui_loadingscreen_mintransition_time", FCVAR_DEVELOPMENTONLY},
- // these 2 could be FCVAR_CHEAT, i guess?
- {"cl_draw_player_model", FCVAR_DEVELOPMENTONLY},
- {"cl_always_draw_3p_player", FCVAR_DEVELOPMENTONLY},
- {"idcolor_neutral", FCVAR_DEVELOPMENTONLY},
- {"idcolor_ally", FCVAR_DEVELOPMENTONLY},
- {"idcolor_ally_cb1", FCVAR_DEVELOPMENTONLY},
- {"idcolor_ally_cb2", FCVAR_DEVELOPMENTONLY},
- {"idcolor_ally_cb3", FCVAR_DEVELOPMENTONLY},
- {"idcolor_enemy", FCVAR_DEVELOPMENTONLY},
- {"idcolor_enemy_cb1", FCVAR_DEVELOPMENTONLY},
- {"idcolor_enemy_cb2", FCVAR_DEVELOPMENTONLY},
- {"idcolor_enemy_cb3", FCVAR_DEVELOPMENTONLY},
- {"playerListPartyColorR", FCVAR_DEVELOPMENTONLY},
- {"playerListPartyColorG", FCVAR_DEVELOPMENTONLY},
- {"playerListPartyColorB", FCVAR_DEVELOPMENTONLY},
- {"playerListUseFriendColor", FCVAR_DEVELOPMENTONLY},
- {"fx_impact_neutral", FCVAR_DEVELOPMENTONLY},
- {"fx_impact_ally", FCVAR_DEVELOPMENTONLY},
- {"fx_impact_enemy", FCVAR_DEVELOPMENTONLY},
- {"hitch_alert_color", FCVAR_DEVELOPMENTONLY},
- {"particles_cull_all", FCVAR_DEVELOPMENTONLY},
- {"particles_cull_dlights", FCVAR_DEVELOPMENTONLY},
- {"map_settings_override", FCVAR_DEVELOPMENTONLY},
- {"highlight_draw", FCVAR_DEVELOPMENTONLY},
-
- // sys/engine settings
- {"sleep_when_meeting_framerate", FCVAR_DEVELOPMENTONLY},
- {"sleep_when_meeting_framerate_headroom_ms", FCVAR_DEVELOPMENTONLY},
- {"not_focus_sleep", FCVAR_DEVELOPMENTONLY},
- {"sp_not_focus_pause", FCVAR_DEVELOPMENTONLY},
- {"joy_requireFocus", FCVAR_DEVELOPMENTONLY},
-
- {"host_thread_mode", FCVAR_DEVELOPMENTONLY},
- {"phys_enable_simd_optimizations", FCVAR_DEVELOPMENTONLY},
- {"phys_enable_experimental_optimizations", FCVAR_DEVELOPMENTONLY},
-
- {"community_frame_run", FCVAR_DEVELOPMENTONLY},
- {"sv_single_core_dedi", FCVAR_DEVELOPMENTONLY},
- {"sv_stressbots", FCVAR_DEVELOPMENTONLY},
-
- {"fatal_script_errors", FCVAR_DEVELOPMENTONLY},
- {"fatal_script_errors_client", FCVAR_DEVELOPMENTONLY},
- {"fatal_script_errors_server", FCVAR_DEVELOPMENTONLY},
- {"script_error_on_midgame_load", FCVAR_DEVELOPMENTONLY}, // idk what this is
-
- {"ai_ainRebuildOnMapStart", FCVAR_DEVELOPMENTONLY},
-
- {"save_enable", FCVAR_DEVELOPMENTONLY},
-
- // cheat commands
- {"switchclass", FCVAR_DEVELOPMENTONLY},
- {"set", FCVAR_DEVELOPMENTONLY},
- {"_setClassVarServer", FCVAR_DEVELOPMENTONLY},
-
- // reparse commands
- {"aisettings_reparse", FCVAR_DEVELOPMENTONLY},
- {"aisettings_reparse_client", FCVAR_DEVELOPMENTONLY},
- {"damagedefs_reparse", FCVAR_DEVELOPMENTONLY},
- {"damagedefs_reparse_client", FCVAR_DEVELOPMENTONLY},
- {"playerSettings_reparse", FCVAR_DEVELOPMENTONLY},
- {"_playerSettings_reparse_Server", FCVAR_DEVELOPMENTONLY},
-
- };
-
- const std::vector<std::tuple<const char*, const char*>> CVAR_FIXUP_DEFAULT_VALUES = {
- {"sv_stressbots", "0"}, // not currently used but this is probably a bad default if we get bots working
- {"cl_pred_optimize", "0"} // fixes issues with animation prediction in thirdperson
- };
-
- for (auto& fixup : CVAR_FIXUP_ADD_FLAGS)
- {
- ConCommandBase* command = g_pCVar->FindCommandBase(std::get<0>(fixup));
- if (command)
- command->m_nFlags |= std::get<1>(fixup);
- }
-
- for (auto& fixup : CVAR_FIXUP_REMOVE_FLAGS)
- {
- ConCommandBase* command = g_pCVar->FindCommandBase(std::get<0>(fixup));
- if (command)
- command->m_nFlags &= ~std::get<1>(fixup);
- }
-
- for (auto& fixup : CVAR_FIXUP_DEFAULT_VALUES)
- {
- ConVar* cvar = g_pCVar->FindVar(std::get<0>(fixup));
- if (cvar && !strcmp(cvar->GetString(), cvar->m_pszDefaultValue))
- {
- cvar->SetValue(std::get<1>(fixup));
- cvar->m_pszDefaultValue = std::get<1>(fixup);
- }
- }
-}
diff --git a/NorthstarDLL/shared/misccommands.h b/NorthstarDLL/shared/misccommands.h
deleted file mode 100644
index 07a07fb3..00000000
--- a/NorthstarDLL/shared/misccommands.h
+++ /dev/null
@@ -1,3 +0,0 @@
-#pragma once
-void AddMiscConCommands();
-void FixupCvarFlags();
diff --git a/NorthstarDLL/shared/playlist.cpp b/NorthstarDLL/shared/playlist.cpp
deleted file mode 100644
index 2b9ad979..00000000
--- a/NorthstarDLL/shared/playlist.cpp
+++ /dev/null
@@ -1,125 +0,0 @@
-#include "playlist.h"
-#include "core/convar/concommand.h"
-#include "core/convar/convar.h"
-#include "squirrel/squirrel.h"
-#include "engine/hoststate.h"
-#include "engine/r2engine.h"
-#include "server/serverpresence.h"
-
-AUTOHOOK_INIT()
-
-// use the R2 namespace for game funcs
-namespace R2
-{
- DEFINED_VAR_AT(engine.dll + 0x18C640, GetCurrentPlaylistName);
- DEFINED_VAR_AT(engine.dll + 0x18EB20, SetCurrentPlaylist);
- DEFINED_VAR_AT(engine.dll + 0x18ED00, SetPlaylistVarOverride);
- DEFINED_VAR_AT(engine.dll + 0x18C680, GetCurrentPlaylistVar);
-} // namespace R2
-
-ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride;
-
-// clang-format off
-AUTOHOOK(clc_SetPlaylistVarOverride__Process, engine.dll + 0x222180,
-char, __fastcall, (void* a1, void* a2))
-// clang-format on
-{
- // 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(g_pGlobals->m_pMapName, "mp_lobby"))
- return 1;
-
- return clc_SetPlaylistVarOverride__Process(a1, a2);
-}
-
-// clang-format off
-AUTOHOOK(SetCurrentPlaylist, engine.dll + 0x18EB20,
-bool, __fastcall, (const char* pPlaylistName))
-// clang-format on
-{
- 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;
-
- SetPlaylistVarOverride(pVarName, pValue);
-}
-
-// clang-format off
-AUTOHOOK(GetCurrentPlaylistVar, engine.dll + 0x18C680,
-const char*, __fastcall, (const char* pVarName, bool bUseOverrides))
-// clang-format on
-{
- if (!bUseOverrides && !strcmp(pVarName, "max_players"))
- bUseOverrides = true;
-
- return GetCurrentPlaylistVar(pVarName, bUseOverrides);
-}
-
-// clang-format off
-AUTOHOOK(GetCurrentGamemodeMaxPlayers, engine.dll + 0x18C430,
-int, __fastcall, ())
-// clang-format on
-{
- const char* pMaxPlayers = R2::GetCurrentPlaylistVar("max_players", 0);
- if (!pMaxPlayers)
- return GetCurrentGamemodeMaxPlayers();
-
- int iMaxPlayers = atoi(pMaxPlayers);
- return iMaxPlayers;
-}
-
-void ConCommand_playlist(const CCommand& args)
-{
- if (args.ArgC() < 2)
- return;
-
- R2::SetCurrentPlaylist(args.Arg(1));
-}
-
-void ConCommand_setplaylistvaroverride(const CCommand& args)
-{
- if (args.ArgC() < 3)
- return;
-
- for (int i = 1; i < args.ArgC(); i += 2)
- R2::SetPlaylistVarOverride(args.Arg(i), args.Arg(i + 1));
-}
-
-ON_DLL_LOAD_RELIESON("engine.dll", PlaylistHooks, (ConCommand, ConVar), (CModule module))
-{
- AUTOHOOK_DISPATCH()
-
- // 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
- // 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");
-
- // 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
- module.Offset(0x18ED8D).Patch("C3");
-
- // patch to allow setplaylistvaroverride to be called before map init on dedicated and private match launched through the game
- module.Offset(0x18ED17).NOP(6);
-}
diff --git a/NorthstarDLL/shared/playlist.h b/NorthstarDLL/shared/playlist.h
deleted file mode 100644
index e56fdf96..00000000
--- a/NorthstarDLL/shared/playlist.h
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-
-// use the R2 namespace for game funcs
-namespace R2
-{
- inline const char* (*GetCurrentPlaylistName)();
- inline void (*SetCurrentPlaylist)(const char* pPlaylistName);
- inline void (*SetPlaylistVarOverride)(const char* pVarName, const char* pValue);
- inline const char* (*GetCurrentPlaylistVar)(const char* pVarName, bool bUseOverrides);
-} // namespace R2