From 07d508ed4ebcd247250b8a983e5c85dffee4d5ef Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 14:53:25 +0300 Subject: initial work on maxplayers --- .../NorthstarDedicatedTest.vcxproj | 6 +- .../NorthstarDedicatedTest.vcxproj.filters | 6 + NorthstarDedicatedTest/dllmain.cpp | 6 + NorthstarDedicatedTest/hooks.cpp | 34 +- NorthstarDedicatedTest/hooks.h | 2 +- NorthstarDedicatedTest/maxplayers.cpp | 559 +++++++++++++++++++++ NorthstarDedicatedTest/maxplayers.h | 4 + 7 files changed, 613 insertions(+), 4 deletions(-) create mode 100644 NorthstarDedicatedTest/maxplayers.cpp create mode 100644 NorthstarDedicatedTest/maxplayers.h diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index c684b69d..14fb634f 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -43,13 +43,13 @@ DynamicLibrary true - v143 + v142 Unicode DynamicLibrary false - v143 + v142 true Unicode @@ -576,6 +576,7 @@ + @@ -611,6 +612,7 @@ + diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 7c856ea1..a3c17054 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1386,6 +1386,9 @@ Header Files\include\openssl\internal + + Header Files\Shared + @@ -1493,6 +1496,9 @@ Source Files\Client + + Source Files\Shared + diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 212b5711..c8f29550 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -25,6 +25,7 @@ #include "scriptmainmenupromos.h" #include "miscclientfixes.h" #include "memalloc.h" +#include "maxplayers.h" bool initialised = false; @@ -116,6 +117,11 @@ void InitialiseNorthstar() AddDllLoadCallback("filesystem_stdio.dll", InitialiseFilesystem); AddDllLoadCallback("engine.dll", InitialiseKeyValues); + // maxplayers increase + AddDllLoadCallback("engine.dll", InitialiseMaxPlayersOverride_Engine); + AddDllLoadCallback("client.dll", InitialiseMaxPlayersOverride_Client, true); + AddDllLoadCallback("server.dll", InitialiseMaxPlayersOverride_Server, true); + // mod manager after everything else AddDllLoadCallback("engine.dll", InitialiseModManager); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index 3de8d483..e5ea0cb6 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -1,10 +1,12 @@ #include "pch.h" #include "hooks.h" #include "hookutils.h" +#include "sigscanning.h" #include #include #include +#include typedef HMODULE(*LoadLibraryExAType)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); @@ -12,9 +14,15 @@ HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); +typedef BOOLEAN(*PDLL_INIT_ROUTINE)(PVOID DllHandle, ULONG Reason, PCONTEXT Context); +typedef BOOLEAN(*LdrpCallInitRoutineType)(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); +BOOLEAN LdrpCallInitRoutineHook(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); + LoadLibraryExAType LoadLibraryExAOriginal; LoadLibraryExWType LoadLibraryExWOriginal; +LdrpCallInitRoutineType LdrpCallInitRoutineHookOriginal; + void InstallInitialHooks() { if (MH_Initialize() != MH_OK) @@ -23,6 +31,9 @@ void InstallInitialHooks() HookEnabler hook; ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast(&LoadLibraryExAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast(&LoadLibraryExWOriginal)); + + void* LdrpCallInitRoutine = FindSignature("ntdll.dll", "\x48\x89\x5C\x24\x00\x44\x89\x44\x24\x00\x48\x89\x54\x24", "xxxx?xxxx?xxxx"); + ENABLER_CREATEHOOK(hook, LdrpCallInitRoutine, &LdrpCallInitRoutineHook, reinterpret_cast(&LdrpCallInitRoutineHookOriginal)); } // dll load callback stuff @@ -32,16 +43,18 @@ struct DllLoadCallback std::string dll; DllLoadCallbackFuncType callback; bool called; + bool preinit; }; std::vector dllLoadCallbacks; -void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback) +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback, bool preinit) { DllLoadCallback* callbackStruct = new DllLoadCallback; callbackStruct->dll = dll; callbackStruct->callback = callback; callbackStruct->called = false; + callbackStruct->preinit = preinit; dllLoadCallbacks.push_back(callbackStruct); } @@ -84,4 +97,23 @@ HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) } return moduleAddress; +} + +BOOLEAN LdrpCallInitRoutineHook(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context) +{ + char fullModulePath[MAX_PATH] = { 0 }; + GetModuleFileNameA((HMODULE)BaseAddress, fullModulePath, sizeof(fullModulePath)); + + std::string name = std::filesystem::path(fullModulePath).filename().string(); + + for (auto& callbackStruct : dllLoadCallbacks) + { + if (!callbackStruct->called && callbackStruct->preinit && name == callbackStruct->dll) + { + callbackStruct->callback((HMODULE)BaseAddress); + callbackStruct->called = true; + } + } + + return LdrpCallInitRoutineHookOriginal(EntryPoint, BaseAddress, Reason, Context); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h index 972b38a6..012b12ec 100644 --- a/NorthstarDedicatedTest/hooks.h +++ b/NorthstarDedicatedTest/hooks.h @@ -4,4 +4,4 @@ void InstallInitialHooks(); typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress); -void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); \ No newline at end of file +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback, bool preinit = false); \ No newline at end of file diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp new file mode 100644 index 00000000..bf550693 --- /dev/null +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -0,0 +1,559 @@ +#include "pch.h" +#include "maxplayers.h" + +// never set this to anything below 32 +#define NEW_MAX_PLAYERS 64 + +#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; + +template +void ChangeOffset(void* addr, unsigned int offset) +{ + TempReadWrite rw(addr); + *((T*)addr) = offset; +} + +/* +typedef bool(*MatchRecvPropsToSendProps_R_Type)(__int64 lookup, __int64 tableNameBroken, __int64 sendTable, __int64 recvTable); +MatchRecvPropsToSendProps_R_Type MatchRecvPropsToSendProps_R_Original; + +bool MatchRecvPropsToSendProps_R_Hook(__int64 lookup, __int64 tableNameBroken, __int64 sendTable, __int64 recvTable) +{ + const char* tableName = *(const char**)(sendTable + 0x118); + + spdlog::info("MatchRecvPropsToSendProps_R table name {}", tableName); + + bool orig = MatchRecvPropsToSendProps_R_Original(lookup, tableNameBroken, sendTable, recvTable); + return orig; +} + +typedef bool(*DataTable_SetupReceiveTableFromSendTable_Type)(__int64 sendTable, bool needsDecoder); +DataTable_SetupReceiveTableFromSendTable_Type DataTable_SetupReceiveTableFromSendTable_Original; + +bool DataTable_SetupReceiveTableFromSendTable_Hook(__int64 sendTable, bool needsDecoder) +{ + const char* tableName = *(const char**)(sendTable + 0x118); + + spdlog::info("DataTable_SetupReceiveTableFromSendTable table name {}", tableName); + if (!strcmp(tableName, "m_bConnected")) { + char f[64]; + sprintf_s(f, "%p", sendTable); + MessageBoxA(0, f, "DataTable_SetupReceiveTableFromSendTable", 0); + } + + return DataTable_SetupReceiveTableFromSendTable_Original(sendTable, needsDecoder); +} +*/ + +void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) +{ + // patch GetPlayerLimits to ignore the boundary limit + ChangeOffset((char*)baseAddress + 0x116458, 0xEB); // jle => jmp + + // patch ED_Alloc to change nFirstIndex + ChangeOffset((char*)baseAddress + 0x18F46C + 1, NEW_MAX_PLAYERS + 8 + 1); // original: 41 (sv.GetMaxClients() + 1) + + // patch CGameServer::SpawnServer to change GetMaxClients inline + ChangeOffset((char*)baseAddress + 0x119543 + 2, NEW_MAX_PLAYERS + 8 + 1); // original: 41 (sv.GetMaxClients() + 1) + + // patch CGameServer::SpawnServer to change for loop + ChangeOffset((char*)baseAddress + 0x11957F + 2, NEW_MAX_PLAYERS); // original: 32 + + // patch CGameServer::SpawnServer to change for loop (there are two) + ChangeOffset((char*)baseAddress + 0x119586 + 2, NEW_MAX_PLAYERS + 1); // original: 33 (32 + 1) + + // patch max players somewhere in CClientState + ChangeOffset((char*)baseAddress + 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((char*)baseAddress + 0x114B79 + 3, maxPlayersPowerOf2); // original: 32 + } + + // patch max players in userinfo stringtable creation loop + ChangeOffset((char*)baseAddress + 0x114C48 + 2, NEW_MAX_PLAYERS); // original: 32 + + // do not load prebaked SendTable message list + ChangeOffset((char*)baseAddress + 0x75859, 0xEB); // jnz -> jmp + + // HookEnabler hook; + // ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x209000, &MatchRecvPropsToSendProps_R_Hook, reinterpret_cast(&MatchRecvPropsToSendProps_R_Original)); + // ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FACD0, &DataTable_SetupReceiveTableFromSendTable_Hook, reinterpret_cast(&DataTable_SetupReceiveTableFromSendTable_Original)); +} + +typedef void(*RunUserCmds_Type)(bool a1, float a2); +RunUserCmds_Type RunUserCmds_Original; + +HMODULE serverBase = 0; +auto RandomIntZeroMax = (__int64(__fastcall*)())0; + +// lazy rebuild +void RunUserCmds_Hook(bool a1, float a2) +{ + 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 + 32i64))(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 = 0i64; + } + ++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)); + } +} + +void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress) +{ + // get required data + serverBase = GetModuleHandleA("server.dll"); + RandomIntZeroMax = (decltype(RandomIntZeroMax))(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomIntZeroMax")); + + // patch max players amount + ChangeOffset((char*)baseAddress + 0x9A44D + 3, NEW_MAX_PLAYERS); // 0x20 (32) => 0x80 (128) + + // patch SpawnGlobalNonRewinding to change forced edict index + ChangeOffset((char*)baseAddress + 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((char*)baseAddress + 0x5C560A + 1, CPlayerResource_ModifiedSize); + + // DT_PlayerResource::m_iPing SendProp + ChangeOffset((char*)baseAddress + 0x5C5059 + 2, CPlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0x5C50A8 + 2, CPlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0x5C50E2 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_iPing DataMap + ChangeOffset((char*)baseAddress + 0xB94598, CPlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0xB9459C, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB945C0, PlayerResource_Ping_Size); + + // DT_PlayerResource::m_iTeam SendProp + ChangeOffset((char*)baseAddress + 0x5C5110 + 2, CPlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0x5C519C + 2, CPlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0x5C517E + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_iTeam DataMap + ChangeOffset((char*)baseAddress + 0xB94600, CPlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0xB94604, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB94628, PlayerResource_Team_Size); + + // DT_PlayerResource::m_iPRHealth SendProp + ChangeOffset((char*)baseAddress + 0x5C51C0 + 2, CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0x5C5204 + 2, CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0x5C523E + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_iPRHealth DataMap + ChangeOffset((char*)baseAddress + 0xB94668, CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0xB9466C, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB94690, PlayerResource_PRHealth_Size); + + // DT_PlayerResource::m_bConnected SendProp + ChangeOffset((char*)baseAddress + 0x5C526C + 2, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x5C52B4 + 2, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x5C52EE + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_bConnected DataMap + ChangeOffset((char*)baseAddress + 0xB946D0, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0xB946D4, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB946F8, PlayerResource_Connected_Size); + + // DT_PlayerResource::m_bAlive SendProp + ChangeOffset((char*)baseAddress + 0x5C5321 + 2, CPlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0x5C5364 + 2, CPlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0x5C539E + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_bAlive DataMap + ChangeOffset((char*)baseAddress + 0xB94738, CPlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0xB9473C, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB94760, PlayerResource_Alive_Size); + + // DT_PlayerResource::m_boolStats SendProp + ChangeOffset((char*)baseAddress + 0x5C53CC + 2, CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0x5C5414 + 2, CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0x5C544E + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_boolStats DataMap + ChangeOffset((char*)baseAddress + 0xB947A0, CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0xB947A4, NEW_MAX_PLAYERS + 1); + ChangeOffset((char*)baseAddress + 0xB947C8, PlayerResource_BoolStats_Size); + + // DT_PlayerResource::m_killStats SendProp + ChangeOffset((char*)baseAddress + 0x5C547C + 2, CPlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0x5C54E2 + 2, CPlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0x5C54FE + 4, PlayerResource_KillStats_Length); + + // DT_PlayerResource::m_killStats DataMap + ChangeOffset((char*)baseAddress + 0xB94808, CPlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0xB9480C, PlayerResource_KillStats_Length); + ChangeOffset((char*)baseAddress + 0xB94830, PlayerResource_KillStats_Size); + + // DT_PlayerResource::m_scoreStats SendProp + ChangeOffset((char*)baseAddress + 0x5C5528 + 2, CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0x5C5576 + 2, CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0x5C5584 + 4, PlayerResource_ScoreStats_Length); + + // DT_PlayerResource::m_scoreStats DataMap + ChangeOffset((char*)baseAddress + 0xB94870, CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0xB94874, PlayerResource_ScoreStats_Length); + ChangeOffset((char*)baseAddress + 0xB94898, PlayerResource_ScoreStats_Size); + + // CPlayerResource::UpdatePlayerData - m_bConnected + ChangeOffset((char*)baseAddress + 0x5C66EE + 4, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x5C672E + 4, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + + // CPlayerResource::UpdatePlayerData - m_iPing + ChangeOffset((char*)baseAddress + 0x5C6394 + 4, CPlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0x5C63DB + 4, CPlayerResource_OriginalSize + PlayerResource_Ping_Start); + + // CPlayerResource::UpdatePlayerData - m_iTeam + ChangeOffset((char*)baseAddress + 0x5C63FD + 4, CPlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0x5C6442 + 4, CPlayerResource_OriginalSize + PlayerResource_Team_Start); + + // CPlayerResource::UpdatePlayerData - m_iPRHealth + ChangeOffset((char*)baseAddress + 0x5C645B + 4, CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0x5C64A0 + 4, CPlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + + // CPlayerResource::UpdatePlayerData - m_bConnected + ChangeOffset((char*)baseAddress + 0x5C64AA + 4, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x5C64F0 + 4, CPlayerResource_OriginalSize + PlayerResource_Connected_Start); + + // CPlayerResource::UpdatePlayerData - m_bAlive + ChangeOffset((char*)baseAddress + 0x5C650A + 4, CPlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0x5C654F + 4, CPlayerResource_OriginalSize + PlayerResource_Alive_Start); + + // CPlayerResource::UpdatePlayerData - m_boolStats + ChangeOffset((char*)baseAddress + 0x5C6557 + 4, CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0x5C65A5 + 4, CPlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + + // CPlayerResource::UpdatePlayerData - m_scoreStats + ChangeOffset((char*)baseAddress + 0x5C65C2 + 3, CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0x5C65E3 + 4, CPlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + + // CPlayerResource::UpdatePlayerData - m_killStats + ChangeOffset((char*)baseAddress + 0x5C6654 + 3, CPlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0x5C665B + 3, CPlayerResource_OriginalSize + PlayerResource_KillStats_Start); + + // GameLoop::RunUserCmds - rebuild + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x483D10, &RunUserCmds_Hook, reinterpret_cast(&RunUserCmds_Original)); +} + +void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) +{ + 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((char*)baseAddress + 0x164C41 + 1, C_PlayerResource_ModifiedSize); + + // C_PlayerResource::C_PlayerResource - change loop end value + ChangeOffset((char*)baseAddress + 0x1640C4 + 2, NEW_MAX_PLAYERS - 32); + + // C_PlayerResource::C_PlayerResource - change m_szName address + ChangeOffset((char*)baseAddress + 0x1640D0 + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); // appended to the end of the class + + // C_PlayerResource::C_PlayerResource - change m_szName address + ChangeOffset((char*)baseAddress + 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((char*)baseAddress + 0x1640D0 + 3, 2244 + C_PlayerResource_AddedSize); + + // C_PlayerResource::UpdatePlayerName - change m_szName address + ChangeOffset((char*)baseAddress + 0x16431F + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName - change m_szName address 1 + ChangeOffset((char*)baseAddress + 0x1645B1 + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName - change m_szName address 2 + ChangeOffset((char*)baseAddress + 0x1645C0 + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName - change m_szName address 3 + ChangeOffset((char*)baseAddress + 0x1645DD + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_szName address 1 + ChangeOffset((char*)baseAddress + 0x164B71 + 4, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_szName address 2 + ChangeOffset((char*)baseAddress + 0x164B9B + 4, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 1 + ChangeOffset((char*)baseAddress + 0x164641 + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 2 + ChangeOffset((char*)baseAddress + 0x164650 + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName2 (?) - change m_szName address 3 + ChangeOffset((char*)baseAddress + 0x16466D + 3, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 1 + ChangeOffset((char*)baseAddress + 0x164BA3 + 4, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 2 + ChangeOffset((char*)baseAddress + 0x164BCE + 4, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_szName2 (?) address 3 + ChangeOffset((char*)baseAddress + 0x164BE7 + 4, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + + // C_PlayerResource::m_szName + ChangeOffset((char*)baseAddress + 0xc350f8, C_PlayerResource_OriginalSize + PlayerResource_Name_Start); + ChangeOffset((char*)baseAddress + 0xc350f8 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource size + ChangeOffset((char*)baseAddress + 0x163415 + 6, C_PlayerResource_ModifiedSize); + + // DT_PlayerResource::m_iPing RecvProp + ChangeOffset((char*)baseAddress + 0x163492 + 2, C_PlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0x1634D6 + 2, C_PlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0x163515 + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_iPing + ChangeOffset((char*)baseAddress + 0xc35170, C_PlayerResource_OriginalSize + PlayerResource_Ping_Start); + ChangeOffset((char*)baseAddress + 0xc35170 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_iTeam RecvProp + ChangeOffset((char*)baseAddress + 0x163549 + 2, C_PlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0x1635C8 + 2, C_PlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0x1635AD + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_iTeam + ChangeOffset((char*)baseAddress + 0xc351e8, C_PlayerResource_OriginalSize + PlayerResource_Team_Start); + ChangeOffset((char*)baseAddress + 0xc351e8 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_iPRHealth RecvProp + ChangeOffset((char*)baseAddress + 0x1635F9 + 2, C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0x163625 + 2, C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0x163675 + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_iPRHealth + ChangeOffset((char*)baseAddress + 0xc35260, C_PlayerResource_OriginalSize + PlayerResource_PRHealth_Start); + ChangeOffset((char*)baseAddress + 0xc35260 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_bConnected RecvProp + ChangeOffset((char*)baseAddress + 0x1636A9 + 2, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x1636D5 + 2, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0x163725 + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_bConnected + ChangeOffset((char*)baseAddress + 0xc352d8, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + ChangeOffset((char*)baseAddress + 0xc352d8 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_bAlive RecvProp + ChangeOffset((char*)baseAddress + 0x163759 + 2, C_PlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0x163785 + 2, C_PlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0x1637D5 + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_bAlive + ChangeOffset((char*)baseAddress + 0xc35350, C_PlayerResource_OriginalSize + PlayerResource_Alive_Start); + ChangeOffset((char*)baseAddress + 0xc35350 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_boolStats RecvProp + ChangeOffset((char*)baseAddress + 0x163809 + 2, C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0x163835 + 2, C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0x163885 + 5, NEW_MAX_PLAYERS + 1); + + // C_PlayerResource::m_boolStats + ChangeOffset((char*)baseAddress + 0xc353c8, C_PlayerResource_OriginalSize + PlayerResource_BoolStats_Start); + ChangeOffset((char*)baseAddress + 0xc353c8 + 4, NEW_MAX_PLAYERS + 1); + + // DT_PlayerResource::m_killStats RecvProp + ChangeOffset((char*)baseAddress + 0x1638B3 + 2, C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0x1638E5 + 2, C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0x163935 + 5, PlayerResource_KillStats_Length); + + // C_PlayerResource::m_killStats + ChangeOffset((char*)baseAddress + 0xc35440, C_PlayerResource_OriginalSize + PlayerResource_KillStats_Start); + ChangeOffset((char*)baseAddress + 0xc35440 + 4, PlayerResource_KillStats_Length); + + // DT_PlayerResource::m_scoreStats RecvProp + ChangeOffset((char*)baseAddress + 0x163969 + 2, C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0x163995 + 2, C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0x1639E5 + 5, PlayerResource_ScoreStats_Length); + + // C_PlayerResource::m_scoreStats + ChangeOffset((char*)baseAddress + 0xc354b8, C_PlayerResource_OriginalSize + PlayerResource_ScoreStats_Start); + ChangeOffset((char*)baseAddress + 0xc354b8 + 4, PlayerResource_ScoreStats_Length); + + // C_PlayerResource::GetPlayerName - change m_bConnected address + ChangeOffset((char*)baseAddress + 0x164599 + 3, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + + // C_PlayerResource::GetPlayerName2 (?) - change m_bConnected address + ChangeOffset((char*)baseAddress + 0x164629 + 3, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + + // C_PlayerResource::GetPlayerName internal func - change m_bConnected address + ChangeOffset((char*)baseAddress + 0x164B13 + 3, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + + // Some other get name func (that seems to be unused) - change m_bConnected address + ChangeOffset((char*)baseAddress + 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((char*)baseAddress + 0x164834 + 3, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); +} \ No newline at end of file diff --git a/NorthstarDedicatedTest/maxplayers.h b/NorthstarDedicatedTest/maxplayers.h new file mode 100644 index 00000000..cd191fc8 --- /dev/null +++ b/NorthstarDedicatedTest/maxplayers.h @@ -0,0 +1,4 @@ +#pragma once +void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress); +void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress); +void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress); \ No newline at end of file -- cgit v1.2.3 From 2dac0c0c284f2464b919c1f20c741dda8ff17163 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 14:56:08 +0300 Subject: add maxplayers to filters --- NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters | 3 +++ 1 file changed, 3 insertions(+) diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 5b287ad1..37be2f7e 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1389,6 +1389,9 @@ Header Files\Server + + Header Files\Shared + -- cgit v1.2.3 From 22f39a161516fee4e1350ec4e8830c120d1d53c5 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 15:50:01 +0300 Subject: fix status command not working for server operator --- .../NorthstarDedicatedTest.vcxproj.filters | 6 +++++ NorthstarDedicatedTest/logging.cpp | 30 +++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 37be2f7e..a3d5e82d 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1499,6 +1499,12 @@ Source Files\Client + + Source Files\Shared + + + Source Files\Server + diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index 09ae6961..6525df27 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -242,7 +242,7 @@ void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format, } } - char formatted[2048]; + char formatted[2048] = { 0 }; bool shouldFormat = true; // because titanfall 2 is quite possibly the worst thing to yet exist, it sometimes gives invalid specifiers which will crash @@ -304,11 +304,39 @@ void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format, spdlog::warn("Failed to format {} \"{}\"", typeStr, format); } + auto endpos = strlen(formatted); + if (formatted[endpos - 1] == '\n') + formatted[endpos - 1] = '\0'; // cut off repeated newline + spdlog::info("[SERVER {}] {}", typeStr, formatted); } + +typedef void(*Status_ConMsg_Type)(const char* text, ...); +Status_ConMsg_Type Status_ConMsg_Original; + +void Status_ConMsg_Hook(const char* text, ...) +{ + char formatted[2048]; + va_list list; + + va_start(list, text); + vsprintf_s(formatted, text, list); + va_end(list); + + auto endpos = strlen(formatted); + if (formatted[endpos - 1] == '\n') + formatted[endpos - 1] = '\0'; // cut off repeated newline + + spdlog::info(formatted); +} + void InitialiseEngineSpewFuncHooks(HMODULE baseAddress) { HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x11CA80, EngineSpewFuncHook, reinterpret_cast(&EngineSpewFunc)); + + // Hook print function that status concmd uses to actually print data + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x15ABD0, Status_ConMsg_Hook, reinterpret_cast(&Status_ConMsg_Original)); } \ No newline at end of file -- cgit v1.2.3 From 785ad98f7077b9b1a1b1ada21219465c21dcbb09 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:59:24 +0300 Subject: 64 maxplayers --- NorthstarDedicatedTest/maxplayers.cpp | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index bf550693..1c984c96 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -79,6 +79,24 @@ bool DataTable_SetupReceiveTableFromSendTable_Hook(__int64 sendTable, bool needs } */ +typedef void* (*StringTables_CreateStringTable_Type)(__int64 thisptr, const char* name, int maxentries, int userdatafixedsize, int userdatanetworkbits, int flags); +StringTables_CreateStringTable_Type StringTables_CreateStringTable_Original; + +void* StringTables_CreateStringTable_Hook(__int64 thisptr, const char* name, int maxentries, int userdatafixedsize, int userdatanetworkbits, int flags) +{ + // 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_Original(thisptr, name, maxentries, userdatafixedsize, userdatanetworkbits, flags); +} + void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) { // patch GetPlayerLimits to ignore the boundary limit @@ -100,12 +118,14 @@ void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) ChangeOffset((char*)baseAddress + 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((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((char*)baseAddress + 0x114C48 + 2, NEW_MAX_PLAYERS); // original: 32 @@ -113,9 +133,12 @@ void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) // do not load prebaked SendTable message list ChangeOffset((char*)baseAddress + 0x75859, 0xEB); // jnz -> jmp - // HookEnabler hook; + HookEnabler hook; + // ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x209000, &MatchRecvPropsToSendProps_R_Hook, reinterpret_cast(&MatchRecvPropsToSendProps_R_Original)); // ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1FACD0, &DataTable_SetupReceiveTableFromSendTable_Hook, reinterpret_cast(&DataTable_SetupReceiveTableFromSendTable_Original)); + + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x22E220, &StringTables_CreateStringTable_Hook, reinterpret_cast(&StringTables_CreateStringTable_Original)); } typedef void(*RunUserCmds_Type)(bool a1, float a2); -- cgit v1.2.3 From bf41a73a0a9d3c5c26086559570a9d6502f137c3 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 18:01:58 +0300 Subject: change toolset back to v143 --- NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index c324d60f..759ede07 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -43,13 +43,13 @@ DynamicLibrary true - v142 + v143 Unicode DynamicLibrary false - v142 + v143 true Unicode -- cgit v1.2.3 From 1cb1d1e19804d1b7b52c8b2bd21f10dde4bf6bf8 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Mon, 27 Dec 2021 19:56:08 +0300 Subject: remove hook preload as it's not crossplatform use a universal solution instead --- NorthstarDedicatedTest/dllmain.cpp | 4 ++-- NorthstarDedicatedTest/hooks.cpp | 32 +------------------------------- NorthstarDedicatedTest/hooks.h | 2 +- NorthstarDedicatedTest/maxplayers.cpp | 8 ++++++++ 4 files changed, 12 insertions(+), 34 deletions(-) diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index 1eafef7f..6f57d265 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -121,8 +121,8 @@ void InitialiseNorthstar() // maxplayers increase AddDllLoadCallback("engine.dll", InitialiseMaxPlayersOverride_Engine); - AddDllLoadCallback("client.dll", InitialiseMaxPlayersOverride_Client, true); - AddDllLoadCallback("server.dll", InitialiseMaxPlayersOverride_Server, true); + AddDllLoadCallback("client.dll", InitialiseMaxPlayersOverride_Client); + AddDllLoadCallback("server.dll", InitialiseMaxPlayersOverride_Server); // mod manager after everything else AddDllLoadCallback("engine.dll", InitialiseModManager); diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp index e5ea0cb6..302fa7bb 100644 --- a/NorthstarDedicatedTest/hooks.cpp +++ b/NorthstarDedicatedTest/hooks.cpp @@ -14,15 +14,9 @@ HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags); -typedef BOOLEAN(*PDLL_INIT_ROUTINE)(PVOID DllHandle, ULONG Reason, PCONTEXT Context); -typedef BOOLEAN(*LdrpCallInitRoutineType)(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); -BOOLEAN LdrpCallInitRoutineHook(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context); - LoadLibraryExAType LoadLibraryExAOriginal; LoadLibraryExWType LoadLibraryExWOriginal; -LdrpCallInitRoutineType LdrpCallInitRoutineHookOriginal; - void InstallInitialHooks() { if (MH_Initialize() != MH_OK) @@ -31,9 +25,6 @@ void InstallInitialHooks() HookEnabler hook; ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast(&LoadLibraryExAOriginal)); ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast(&LoadLibraryExWOriginal)); - - void* LdrpCallInitRoutine = FindSignature("ntdll.dll", "\x48\x89\x5C\x24\x00\x44\x89\x44\x24\x00\x48\x89\x54\x24", "xxxx?xxxx?xxxx"); - ENABLER_CREATEHOOK(hook, LdrpCallInitRoutine, &LdrpCallInitRoutineHook, reinterpret_cast(&LdrpCallInitRoutineHookOriginal)); } // dll load callback stuff @@ -43,18 +34,16 @@ struct DllLoadCallback std::string dll; DllLoadCallbackFuncType callback; bool called; - bool preinit; }; std::vector dllLoadCallbacks; -void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback, bool preinit) +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback) { DllLoadCallback* callbackStruct = new DllLoadCallback; callbackStruct->dll = dll; callbackStruct->callback = callback; callbackStruct->called = false; - callbackStruct->preinit = preinit; dllLoadCallbacks.push_back(callbackStruct); } @@ -97,23 +86,4 @@ HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags) } return moduleAddress; -} - -BOOLEAN LdrpCallInitRoutineHook(PDLL_INIT_ROUTINE EntryPoint, PVOID BaseAddress, ULONG Reason, PVOID Context) -{ - char fullModulePath[MAX_PATH] = { 0 }; - GetModuleFileNameA((HMODULE)BaseAddress, fullModulePath, sizeof(fullModulePath)); - - std::string name = std::filesystem::path(fullModulePath).filename().string(); - - for (auto& callbackStruct : dllLoadCallbacks) - { - if (!callbackStruct->called && callbackStruct->preinit && name == callbackStruct->dll) - { - callbackStruct->callback((HMODULE)BaseAddress); - callbackStruct->called = true; - } - } - - return LdrpCallInitRoutineHookOriginal(EntryPoint, BaseAddress, Reason, Context); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h index 012b12ec..972b38a6 100644 --- a/NorthstarDedicatedTest/hooks.h +++ b/NorthstarDedicatedTest/hooks.h @@ -4,4 +4,4 @@ void InstallInitialHooks(); typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress); -void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback, bool preinit = false); \ No newline at end of file +void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); \ No newline at end of file diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index 1c984c96..e649b0a6 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -427,6 +427,10 @@ void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress) // GameLoop::RunUserCmds - rebuild HookEnabler hook; ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x483D10, &RunUserCmds_Hook, reinterpret_cast(&RunUserCmds_Original)); + + *(DWORD*)((char*)baseAddress + 0x14E7390) = 0; + auto DT_PlayerResource_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x5C4FE0); + DT_PlayerResource_Construct(); } void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) @@ -579,4 +583,8 @@ void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) // Some other get name func 2 (that seems to be unused too) - change m_bConnected address ChangeOffset((char*)baseAddress + 0x164834 + 3, C_PlayerResource_OriginalSize + PlayerResource_Connected_Start); + + *(DWORD*)((char*)baseAddress + 0xC35068) = 0; + auto DT_PlayerResource_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x163400); + DT_PlayerResource_Construct(); } \ No newline at end of file -- cgit v1.2.3 From bea776a8f6bcba5f702483d868d6fb6c4a069416 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 11:53:34 +0300 Subject: fix C(_)Team classes --- NorthstarDedicatedTest/maxplayers.cpp | 70 +++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index e649b0a6..e7d23032 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -3,6 +3,7 @@ // 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) @@ -40,6 +41,10 @@ constexpr int PlayerResource_ScoreStats_Size = (PlayerResource_ScoreStats_Length // 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; + template void ChangeOffset(void* addr, unsigned int offset) { @@ -289,6 +294,18 @@ void RunUserCmds_Hook(bool a1, float a2) } } +typedef __int64(*SendPropArray2_Type)(__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn, unsigned char unk1); +SendPropArray2_Type SendPropArray2_Original; + +__int64 __fastcall SendPropArray2_Hook(__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn, unsigned char unk1) +{ + // Change the amount of elements to account for a bigger player amount + if (!strcmp(name, "\"player_array\"")) + elements = NEW_MAX_PLAYERS; + + return SendPropArray2_Original(recvProp, elements, flags, name, proxyFn, unk1); +} + void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress) { // get required data @@ -431,6 +448,37 @@ void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress) *(DWORD*)((char*)baseAddress + 0x14E7390) = 0; auto DT_PlayerResource_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x5C4FE0); 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((char*)baseAddress + 0x23924A + 1, CTeam_ModifiedSize); + + // CTeam::CTeam - increase memset length to clean newly allocated data + ChangeOffset((char*)baseAddress + 0x2395AE + 2, 256 + CTeam_AddedSize); + + // hook required to change the size of DT_Team::"player_array" + HookEnabler hook2; + ENABLER_CREATEHOOK(hook2, (char*)baseAddress + 0x12B130, &SendPropArray2_Hook, reinterpret_cast(&SendPropArray2_Original)); + hook2.~HookEnabler(); // force hook before calling construct function + + *(DWORD*)((char*)baseAddress + 0xC945A0) = 0; + auto DT_Team_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x238F50); + DT_Team_Construct(); +} + +typedef __int64(*RecvPropArray2_Type)(__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn); +RecvPropArray2_Type RecvPropArray2_Original; + +__int64 __fastcall RecvPropArray2_Hook(__int64 recvProp, int elements, int flags, const char* name, __int64 proxyFn) +{ + // Change the amount of elements to account for a bigger player amount + if (!strcmp(name, "\"player_array\"")) + elements = NEW_MAX_PLAYERS; + + return RecvPropArray2_Original(recvProp, elements, flags, name, proxyFn); } void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) @@ -587,4 +635,26 @@ void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) *(DWORD*)((char*)baseAddress + 0xC35068) = 0; auto DT_PlayerResource_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x163400); 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((char*)baseAddress + 0x182321 + 1, C_Team_ModifiedSize); + + // C_Team::C_Team - increase memset length to clean newly allocated data + ChangeOffset((char*)baseAddress + 0x1804A2 + 2, 256 + C_Team_AddedSize); + + // DT_Team size + ChangeOffset((char*)baseAddress + 0xC3AA0C, C_Team_ModifiedSize); + + // hook required to change the size of DT_Team::"player_array" + HookEnabler hook; + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1CEDA0, &RecvPropArray2_Hook, reinterpret_cast(&RecvPropArray2_Original)); + hook.~HookEnabler(); // force hook before calling construct function + + *(DWORD*)((char*)baseAddress + 0xC3AFF8) = 0; + auto DT_Team_Construct = (__int64(__fastcall*)())((char*)baseAddress + 0x17F950); + DT_Team_Construct(); } \ No newline at end of file -- cgit v1.2.3 From e49f026c92c75c4f10afd7f8895d8ebe2a01e97d Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 12:18:58 +0300 Subject: implement svc_Print, copy NS hostname to source cvar --- NorthstarDedicatedTest/logging.cpp | 18 ++++++++++++++++++ NorthstarDedicatedTest/masterserver.cpp | 12 +++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp index 6525df27..0e72cc80 100644 --- a/NorthstarDedicatedTest/logging.cpp +++ b/NorthstarDedicatedTest/logging.cpp @@ -331,6 +331,21 @@ void Status_ConMsg_Hook(const char* text, ...) spdlog::info(formatted); } +typedef bool(*CClientState_ProcessPrint_Type)(__int64 thisptr, __int64 msg); +CClientState_ProcessPrint_Type CClientState_ProcessPrint_Original; + +bool CClientState_ProcessPrint_Hook(__int64 thisptr, __int64 msg) +{ + char* text = *(char**)(msg + 0x20); + + auto endpos = strlen(text); + if (text[endpos - 1] == '\n') + text[endpos - 1] = '\0'; // cut off repeated newline + + spdlog::info(text); + return true; +} + void InitialiseEngineSpewFuncHooks(HMODULE baseAddress) { HookEnabler hook; @@ -339,4 +354,7 @@ void InitialiseEngineSpewFuncHooks(HMODULE baseAddress) // Hook print function that status concmd uses to actually print data ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x15ABD0, Status_ConMsg_Hook, reinterpret_cast(&Status_ConMsg_Original)); + + // Hook CClientState::ProcessPrint + ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1A1530, CClientState_ProcessPrint_Hook, reinterpret_cast(&CClientState_ProcessPrint_Original)); } \ No newline at end of file diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index 706f60ec..d7fea6d1 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -21,6 +21,9 @@ ConVar* Cvar_ns_server_name; ConVar* Cvar_ns_server_desc; ConVar* Cvar_ns_server_password; +// Source ConVar +ConVar* Cvar_hostname; + MasterServerManager* g_MasterServerManager; typedef void(*CHostState__State_NewGameType)(CHostState* hostState); @@ -127,7 +130,7 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or if (originAuthInfo.HasParseError()) { - spdlog::error("Failed reading origin auth info response: encountered parse error \{}\"", rapidjson::GetParseError_En(originAuthInfo.GetParseError())); + spdlog::error("Failed reading origin auth info response: encountered parse error \"{}\"", rapidjson::GetParseError_En(originAuthInfo.GetParseError())); goto REQUEST_END_CLEANUP; } @@ -852,6 +855,10 @@ void CHostState__State_NewGameHook(CHostState* hostState) if (maxPlayersVar) // GetCurrentPlaylistVar can return null so protect against this maxPlayers = std::stoi(maxPlayersVar); + // Copy new server name cvar to source + Cvar_hostname->m_pszString = Cvar_ns_server_name->m_pszString; + Cvar_hostname->m_StringLength = Cvar_ns_server_name->m_StringLength; + g_MasterServerManager->AddSelfToServerList(Cvar_hostport->m_nValue, Cvar_ns_player_auth_port->m_nValue, Cvar_ns_server_name->m_pszString, Cvar_ns_server_desc->m_pszString, hostState->m_levelName, (char*)GetCurrentPlaylistName(), maxPlayers, Cvar_ns_server_password->m_pszString); g_ServerAuthenticationManager->StartPlayerAuthServer(); g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = false; @@ -898,6 +905,9 @@ void InitialiseSharedMasterServer(HMODULE baseAddress) Cvar_ns_server_password = RegisterConVar("ns_server_password", "", FCVAR_GAMEDLL, ""); Cvar_ns_report_server_to_masterserver = RegisterConVar("ns_report_server_to_masterserver", "1", FCVAR_GAMEDLL, ""); Cvar_ns_report_sp_server_to_masterserver = RegisterConVar("ns_report_sp_server_to_masterserver", "0", FCVAR_GAMEDLL, ""); + + Cvar_hostname = *(ConVar**)((char*)baseAddress + 0x1315bae8); + g_MasterServerManager = new MasterServerManager; RegisterConCommand("ns_fetchservers", ConCommand_ns_fetchservers, "", FCVAR_CLIENTDLL); -- cgit v1.2.3 From 010a6e1399d09faf1eac21b57efd55c736b11608 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 12:27:28 +0300 Subject: fix build error in masterserver.cpp --- NorthstarDedicatedTest/masterserver.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp index b5b394cc..da017b24 100644 --- a/NorthstarDedicatedTest/masterserver.cpp +++ b/NorthstarDedicatedTest/masterserver.cpp @@ -892,18 +892,22 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata, bool MasterServerManager::RemoveSelfFromServerListThread() { + bool removed = true; + // we dont process this at all atm, maybe do later, but atm not necessary LazyCreateHttpClient(); if (auto result = m_httpClient->Delete(fmt::format("/server/remove_server?id={}", m_ownServerId).c_str())) { m_successfullyConnected = true; + m_ownServerId[0] = 0; } else { m_successfullyConnected = false; + removed = false; } - m_ownServerId[0] = 0; + return removed; } void MasterServerManager::RemoveSelfFromServerList() -- cgit v1.2.3 From 1c1b18e1b7887a76eb56bd33fd983fdcfd171a08 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 12:31:54 +0300 Subject: add a toggle for maxplayers increase functionality (unrecommended) --- NorthstarDedicatedTest/maxplayers.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index e7d23032..ed2ac26a 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "maxplayers.h" +#include "gameutils.h" // never set this to anything below 32 #define NEW_MAX_PLAYERS 64 @@ -102,8 +103,17 @@ void* StringTables_CreateStringTable_Hook(__int64 thisptr, const char* name, int return StringTables_CreateStringTable_Original(thisptr, name, maxentries, userdatafixedsize, userdatanetworkbits, flags); } +bool MaxPlayersIncreaseEnabled() +{ + // Unrecommended: this will break compatibility with clients/servers that have it enabled. + return CommandLine() && !CommandLine()->CheckParm("-nomaxplayersincrease"); +} + void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) { + if (!MaxPlayersIncreaseEnabled()) + return; + // patch GetPlayerLimits to ignore the boundary limit ChangeOffset((char*)baseAddress + 0x116458, 0xEB); // jle => jmp @@ -308,6 +318,9 @@ __int64 __fastcall SendPropArray2_Hook(__int64 recvProp, int elements, int flags void InitialiseMaxPlayersOverride_Server(HMODULE baseAddress) { + if (!MaxPlayersIncreaseEnabled()) + return; + // get required data serverBase = GetModuleHandleA("server.dll"); RandomIntZeroMax = (decltype(RandomIntZeroMax))(GetProcAddress(GetModuleHandleA("vstdlib.dll"), "RandomIntZeroMax")); @@ -483,6 +496,9 @@ __int64 __fastcall RecvPropArray2_Hook(__int64 recvProp, int elements, int flags void InitialiseMaxPlayersOverride_Client(HMODULE baseAddress) { + if (!MaxPlayersIncreaseEnabled()) + return; + constexpr int C_PlayerResource_OriginalSize = 5768; constexpr int C_PlayerResource_AddedSize = PlayerResource_TotalSize; constexpr int C_PlayerResource_ModifiedSize = C_PlayerResource_OriginalSize + C_PlayerResource_AddedSize; -- cgit v1.2.3 From bb93442db8b1e450adf08a8305335020c436d358 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 12:56:08 +0300 Subject: dedicated console command input --- NorthstarDedicatedTest/dedicated.cpp | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 83a9950a..26dcc9ae 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -76,6 +76,32 @@ bool IsGameActiveWindowHook() return true; } +HANDLE consoleInputThreadHandle = NULL; + +DWORD WINAPI ConsoleInputThread(PVOID pThreadParameter) +{ + while (!g_pEngine || !g_pHostState || g_pHostState->m_iCurrentState != HostState_t::HS_RUN) + Sleep(1000); + + // Bind stdin to receive console input. + FILE* fp = nullptr; + freopen_s(&fp, "CONIN$", "r", stdin); + + spdlog::info("Ready to receive console commands."); + + { + // Process console input + std::string input; + while (g_pEngine && g_pEngine->m_nQuitting == EngineQuitState::QUIT_NOTQUITTING && std::getline(std::cin, input)) + { + input += "\n"; + Cbuf_AddText(Cbuf_GetCurrentPlayer(), input.c_str(), cmd_source_t::kCommandSrcCode); + } + } + + return 0; +} + void InitialiseDedicated(HMODULE engineAddress) { if (!IsDedicated()) @@ -380,6 +406,9 @@ void InitialiseDedicated(HMODULE engineAddress) CommandLine()->AppendParm("+host_preload_shaders", "0"); CommandLine()->AppendParm("+net_usesocketsforloopback", "1"); CommandLine()->AppendParm("+exec", "autoexec_ns_server"); + + // create console input thread + consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL); } typedef void(*Tier0_InitOriginType)(); -- cgit v1.2.3 From 8179de9831dd415794269015a40de44baa4c29d1 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 13:17:55 +0300 Subject: add parm checks for dedicated input + disable quick edit --- NorthstarDedicatedTest/dedicated.cpp | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 26dcc9ae..91e9cef6 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -407,8 +407,30 @@ void InitialiseDedicated(HMODULE engineAddress) CommandLine()->AppendParm("+net_usesocketsforloopback", "1"); CommandLine()->AppendParm("+exec", "autoexec_ns_server"); + // Disable Quick Edit mode to reduce chance of user unintentionally hanging their server by selecting something. + if (!CommandLine()->CheckParm("-bringbackquickedit")) + { + spdlog::info("Quick Edit enabled by user request"); + + HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE); + DWORD mode = 0; + + if (GetConsoleMode(stdIn, &mode)) { + if (mode & ENABLE_QUICK_EDIT_MODE) { + mode &= ~ENABLE_QUICK_EDIT_MODE; + mode &= ~ENABLE_MOUSE_INPUT; + + mode |= ENABLE_PROCESSED_INPUT; + + SetConsoleMode(stdIn, mode); + } + } + } + // create console input thread - consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL); + if (!CommandLine()->CheckParm("-noconsoleinput")) + consoleInputThreadHandle = CreateThread(0, 0, ConsoleInputThread, 0, 0, NULL); + else spdlog::info("Console input disabled by user request"); } typedef void(*Tier0_InitOriginType)(); -- cgit v1.2.3 From 4e9e9d9766663c39e21fcdd33e865cdc8cbf7e6a Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 13:34:09 +0300 Subject: fix quick edit enabled message --- NorthstarDedicatedTest/dedicated.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp index 91e9cef6..f77567ec 100644 --- a/NorthstarDedicatedTest/dedicated.cpp +++ b/NorthstarDedicatedTest/dedicated.cpp @@ -410,8 +410,6 @@ void InitialiseDedicated(HMODULE engineAddress) // Disable Quick Edit mode to reduce chance of user unintentionally hanging their server by selecting something. if (!CommandLine()->CheckParm("-bringbackquickedit")) { - spdlog::info("Quick Edit enabled by user request"); - HANDLE stdIn = GetStdHandle(STD_INPUT_HANDLE); DWORD mode = 0; @@ -425,7 +423,7 @@ void InitialiseDedicated(HMODULE engineAddress) SetConsoleMode(stdIn, mode); } } - } + } else spdlog::info("Quick Edit enabled by user request"); // create console input thread if (!CommandLine()->CheckParm("-noconsoleinput")) -- cgit v1.2.3 From 2942ea56527100d5e39e0bbba4a1d16b1cde6128 Mon Sep 17 00:00:00 2001 From: HappyDOGE <28511119+HappyDOGE@users.noreply.github.com> Date: Tue, 28 Dec 2021 19:18:32 +0300 Subject: make max players increase disabled by default --- NorthstarDedicatedTest/maxplayers.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp index ed2ac26a..9d08e83f 100644 --- a/NorthstarDedicatedTest/maxplayers.cpp +++ b/NorthstarDedicatedTest/maxplayers.cpp @@ -105,8 +105,7 @@ void* StringTables_CreateStringTable_Hook(__int64 thisptr, const char* name, int bool MaxPlayersIncreaseEnabled() { - // Unrecommended: this will break compatibility with clients/servers that have it enabled. - return CommandLine() && !CommandLine()->CheckParm("-nomaxplayersincrease"); + return CommandLine() && CommandLine()->CheckParm("-experimentalmaxplayersincrease"); } void InitialiseMaxPlayersOverride_Engine(HMODULE baseAddress) -- cgit v1.2.3