aboutsummaryrefslogtreecommitdiff
path: root/NorthstarDedicatedTest
diff options
context:
space:
mode:
Diffstat (limited to 'NorthstarDedicatedTest')
-rw-r--r--NorthstarDedicatedTest/ExploitFixes.cpp155
-rw-r--r--NorthstarDedicatedTest/ExploitFixes.h2
-rw-r--r--NorthstarDedicatedTest/ExploitFixes_UTF8Parser.h310
-rw-r--r--NorthstarDedicatedTest/NSMem.h200
-rw-r--r--NorthstarDedicatedTest/clientvideooverrides.cpp7
-rw-r--r--NorthstarDedicatedTest/concommand.h3
-rw-r--r--NorthstarDedicatedTest/convar.cpp2
-rw-r--r--NorthstarDedicatedTest/convar.h2
-rw-r--r--NorthstarDedicatedTest/cvar.h3
-rw-r--r--NorthstarDedicatedTest/dedicated.cpp28
-rw-r--r--NorthstarDedicatedTest/dedicatedmaterialsystem.cpp4
-rw-r--r--NorthstarDedicatedTest/languagehooks.cpp4
-rw-r--r--NorthstarDedicatedTest/latencyflex.cpp4
-rw-r--r--NorthstarDedicatedTest/logging.cpp3
-rw-r--r--NorthstarDedicatedTest/masterserver.cpp16
-rw-r--r--NorthstarDedicatedTest/maxplayers.cpp4
-rw-r--r--NorthstarDedicatedTest/misccommands.cpp42
-rw-r--r--NorthstarDedicatedTest/miscserverfixes.cpp4
-rw-r--r--NorthstarDedicatedTest/modmanager.cpp20
-rw-r--r--NorthstarDedicatedTest/modmanager.h3
-rw-r--r--NorthstarDedicatedTest/pch.h10
-rw-r--r--NorthstarDedicatedTest/playlist.cpp6
-rw-r--r--NorthstarDedicatedTest/rpakfilesystem.cpp11
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp29
-rw-r--r--NorthstarDedicatedTest/version.cpp18
25 files changed, 513 insertions, 377 deletions
diff --git a/NorthstarDedicatedTest/ExploitFixes.cpp b/NorthstarDedicatedTest/ExploitFixes.cpp
index 36bd36f4..4c91ef75 100644
--- a/NorthstarDedicatedTest/ExploitFixes.cpp
+++ b/NorthstarDedicatedTest/ExploitFixes.cpp
@@ -5,6 +5,19 @@
#include "NSMem.h"
#include "cvar.h"
+ConVar* ns_exploitfixes_log;
+#define SHOULD_LOG (ns_exploitfixes_log->m_Value.m_nValue > 0)
+#define BLOCKED_INFO(s) \
+ ([=]() -> bool { \
+ if (SHOULD_LOG) \
+ { \
+ std::stringstream stream; \
+ stream << "ExploitFixes.cpp: " << BLOCK_PREFIX << s; \
+ spdlog::error(stream.str()); \
+ } \
+ return false; \
+ }())
+
// Make sure 3 or less floats are valid
bool ValidateFloats(float a, float b = 0, float c = 0) { return !isnan(a) && !isnan(b) && !isnan(c); }
@@ -66,9 +79,31 @@ KHOOK(CClient_ProcessSetConVar, ("engine.dll", "48 8B D1 48 8B 49 18 48 8B 01 48
auto msg = (NET_SetConVar*)pMsg;
- constexpr int SETCONVAR_SANITY_AMOUNT_LIMIT = 20;
- if (msg->m_ConVars_count < 1 || msg->m_ConVars_count > SETCONVAR_SANITY_AMOUNT_LIMIT)
- return false; // Nope
+ bool areWeServer;
+
+ {
+ // Figure out of we are the client or the server
+ // To do this, we utilize the msg's m_pMessageHandler pointer
+ // m_pMessageHandler points to a virtual class that handles all net messages
+ // The first virtual table function of our m_pMessageHandler will differ if it is IServerMessageHandler or IClientMessageHandler
+ void* msgHandlerVTableFirstFunc = **(void****)(msg->m_pMessageHandler);
+ static auto engineBaseAddress = (uintptr_t)GetModuleHandleA("engine.dll");
+ auto offset = uintptr_t(msgHandlerVTableFirstFunc) - engineBaseAddress;
+
+ constexpr uintptr_t CLIENTSTATE_FIRST_VFUNC_OFFSET = 0x8A15C;
+ areWeServer = offset != CLIENTSTATE_FIRST_VFUNC_OFFSET;
+ }
+
+ std::string BLOCK_PREFIX = std::string{"NET_SetConVar ("} + (areWeServer ? "server" : "client") + "): Blocked dangerous/invalid msg: ";
+
+ if (areWeServer)
+ {
+ 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++)
{
@@ -89,25 +124,41 @@ KHOOK(CClient_ProcessSetConVar, ("engine.dll", "48 8B D1 48 8B 49 18 48 8B 01 48
}
if (!nameValid || !valValid)
- return false; // Missing null terminators
+ return BLOCKED_INFO("Missing null terminators");
auto realVar = g_pCVar->FindVar(entry->name);
- if (!realVar)
- // Not an actual cvar, no thanks
- return false;
+ if (realVar)
+ memcpy(entry->name, realVar->m_ConCommandBase.m_pszName, strlen(realVar->m_ConCommandBase.m_pszName) + 1); // Force name to match case
- // Force name to match case
- memcpy(entry->name, realVar->m_ConCommandBase.m_pszName, strlen(realVar->m_ConCommandBase.m_pszName) + 1);
+ bool isValidFlags = true;
+ if (areWeServer)
+ {
+ if (realVar)
+ isValidFlags = ConVar::IsFlagSet(realVar, FCVAR_USERINFO); // ConVar MUST be userinfo var
+ }
+ else
+ {
+ // TODO: Should probably have some sanity checks, but can't find any that are consistent
+ }
- if (!ConVar::IsFlagSet(realVar, FCVAR_USERINFO) || ConVar::IsFlagSet(realVar, FCVAR_CHEAT))
+ if (!isValidFlags)
{
- return false;
+ if (!realVar)
+ {
+ return BLOCKED_INFO("Invalid flags on nonexistant cvar (how tho???)");
+ }
+ else
+ {
+ return BLOCKED_INFO(
+ "Invalid flags (" << std::hex << "0x" << realVar->m_ConCommandBase.m_nFlags << "), var is " << entry->name);
+ }
+
}
}
else
{
- return false; // Not risking that one, they all gotta be readable
+ return BLOCKED_INFO("Unreadable memory at " << (void*)entry); // Not risking that one, they all gotta be readable
}
}
@@ -130,15 +181,27 @@ KHOOK(CClient_ProcessUsercmds, ("engine.dll", "40 55 56 48 83 EC 58"), bool, __f
auto msg = (CLC_Move*)pMsg;
- if (msg->m_nBackupCommands < 0 || msg->m_nNewCommands < 1)
- return false; // Nice try buster
+ 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 << ")");
+ }
constexpr int NUMCMD_SANITY_LIMIT = 16;
if ((msg->m_nNewCommands + msg->m_nBackupCommands) > NUMCMD_SANITY_LIMIT)
- return false; // Im good
+ {
+ return BLOCKED_INFO("Command count is too high (new: " << msg->m_nNewCommands << ", backup: " << msg->m_nBackupCommands << ")");
+
+ }
if (msg->m_nLength <= 0)
- return false;
+ return BLOCKED_INFO("Invalid message length (" << msg->m_nLength << ")");
return oCClient_ProcessUsercmds(thisptr, pMsg);
}
@@ -175,23 +238,56 @@ KHOOK(ReadUsercmd, ("server.dll", "4C 89 44 24 ? 53 55 56 57"), void, __fastcall
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) + "): ";
+
+ if (cmd->worldViewAngles.IsInvalid())
+ {
+ BLOCKED_INFO("CMD has invalid worldViewAngles");
+ goto INVALID_CMD;
+ }
- if (cmd->worldViewAngles.IsInvalid() || cmd->localViewAngles.IsInvalid() || cmd->attackangles.IsInvalid() ||
- cmd->cameraAngles.IsInvalid())
+ if (cmd->attackangles.IsInvalid())
{
+ BLOCKED_INFO("CMD has invalid attackangles");
+ goto INVALID_CMD;
+ }
+
+ if (cmd->localViewAngles.IsInvalid())
+ {
+ BLOCKED_INFO("CMD has invalid localViewAngles");
+ goto INVALID_CMD;
+ }
+
+ if (cmd->cameraAngles.IsInvalid())
+ {
+ BLOCKED_INFO("CMD has invalid cameraAngles");
goto INVALID_CMD;
}
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
+ }
+
- if (!cmd->move.IsValid() || // Prevent player freeze (and even server crash) exploit
- !cmd->cameraPos.IsValid()) // IIRC this can crash spectating clients or anyone watching replays
+ if (!cmd->move.IsValid())
+ {
+ BLOCKED_INFO("Invalid move vector");
goto INVALID_CMD;
+ }
- if (!ValidateFloats(cmd->cameraPos.x, cmd->cameraPos.y, cmd->cameraPos.z))
- goto INVALID_CMD; // IIRC this can crash spectating clients or anyone watching replays
+ if (!cmd->cameraPos.IsValid())
+ {
+ BLOCKED_INFO("Invalid cameraPos"); // IIRC this can crash spectating clients or anyone watching replays
+ goto INVALID_CMD;
+ }
return;
INVALID_CMD:
@@ -227,7 +323,8 @@ KHOOK(
{
if (!ExploitFixes_UTF8Parser::CheckValid(a1, a2, strData))
{
- spdlog::warn("ParseUTF8 Hook: Ignoring potentially-crashing utf8 string");
+ const char* BLOCK_PREFIX = "ParseUTF8 Hook: ";
+ BLOCKED_INFO("Ignoring potentially-crashing utf8 string");
return false;
}
}
@@ -244,8 +341,8 @@ void DoBytePatches()
// patches to make commands run from client/ui script still work
// note: this is likely preventable in a nicer way? test prolly
- NSMem::BytePatch(engineBase + 0x4FB65, {0xEB, 0x11});
- NSMem::BytePatch(engineBase + 0x4FBAC, {0xEB, 0x16});
+ NSMem::BytePatch(engineBase + 0x4FB65, "EB 11");
+ NSMem::BytePatch(engineBase + 0x4FBAC, "EB 16");
// disconnect concommand
{
@@ -266,16 +363,15 @@ void DoBytePatches()
for (auto exportName : ANTITAMPER_EXPORTS)
{
- auto address = (uintptr_t)GetProcAddress(NULL, exportName);
+ auto address = (uintptr_t)GetProcAddress(GetModuleHandleA("server.dll"), exportName);
if (!address)
{
spdlog::warn("Failed to find AntiTamper function export \"{}\"", exportName);
}
else
{
-
// Just return, none of them have any args or are userpurge
- NSMem::BytePatch(address, {0xC3});
+ NSMem::BytePatch(address, "C3");
spdlog::info("Patched AntiTamper function export \"{}\"", exportName);
}
@@ -302,4 +398,7 @@ void ExploitFixes::LoadCallback(HMODULE unused)
MessageBoxA(0, "FAILED to initialize all exploit patches.", "Northstar", MB_ICONERROR);
exit(0);
}
+
+ ns_exploitfixes_log =
+ new ConVar("ns_exploitfixes_log", "1", FCVAR_GAMEDLL, "Whether to log whenever ExploitFixes.cpp blocks/corrects something");
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/ExploitFixes.h b/NorthstarDedicatedTest/ExploitFixes.h
index 7a407a3d..16196cbf 100644
--- a/NorthstarDedicatedTest/ExploitFixes.h
+++ b/NorthstarDedicatedTest/ExploitFixes.h
@@ -5,5 +5,5 @@
namespace ExploitFixes
{
- void LoadCallback(HMODULE unused);
+void LoadCallback(HMODULE unused);
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/ExploitFixes_UTF8Parser.h b/NorthstarDedicatedTest/ExploitFixes_UTF8Parser.h
index b06d442b..09c26293 100644
--- a/NorthstarDedicatedTest/ExploitFixes_UTF8Parser.h
+++ b/NorthstarDedicatedTest/ExploitFixes_UTF8Parser.h
@@ -6,170 +6,170 @@
namespace ExploitFixes_UTF8Parser
{
- bool __fastcall CheckValid(INT64* a1, DWORD* a2, char* strData)
- {
- static auto sub_F1320 = (INT64(__fastcall*)(DWORD a1, char* a2))NSMem::PatternScan("engine.dll", "83 F9 7F 77 08 88 0A");
+bool __fastcall CheckValid(INT64* a1, DWORD* a2, char* strData)
+{
+ static auto sub_F1320 = (INT64(__fastcall*)(DWORD a1, char* a2))NSMem::PatternScan("engine.dll", "83 F9 7F 77 08 88 0A");
- 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
+ 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)
+ 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)
{
- ++v4;
- --v7;
- if (v3 != 2)
+ while (1)
{
- while (1)
- {
- if (!NSMem::IsMemoryReadable(v4, 1))
- return false; // INVALID
+ if (!NSMem::IsMemoryReadable(v4, 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;
+ 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;
+ 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);
}
- v11 = 10;
- LABEL_6:
- v5 |= v11;
- *_strData++ = v11;
- goto LABEL_7;
+ _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;
}
+LABEL_48:
+ return true;
+}
} // namespace ExploitFixes_UTF8Parser \ No newline at end of file
diff --git a/NorthstarDedicatedTest/NSMem.h b/NorthstarDedicatedTest/NSMem.h
index a5bbd42f..50928dd2 100644
--- a/NorthstarDedicatedTest/NSMem.h
+++ b/NorthstarDedicatedTest/NSMem.h
@@ -6,119 +6,147 @@
#pragma region Pattern Scanning
namespace NSMem
{
- inline void* PatternScan(void* module, const int* pattern, int patternSize, int offset)
+inline std::vector<int> HexBytesToString(const char* str)
+{
+ std::vector<int> patternNums;
+ int size = strlen(str);
+ for (int i = 0; i < size; i++)
{
- if (!module)
- return NULL;
-
- auto dosHeader = (PIMAGE_DOS_HEADER)module;
- auto ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)module + dosHeader->e_lfanew);
-
- auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
+ char c = str[i];
- auto scanBytes = (BYTE*)module;
+ // If this is a space character, ignore it
+ if (c == ' ' || c == '\t')
+ continue;
- for (auto i = 0; i < sizeOfImage - patternSize; ++i)
+ if (c == '?')
{
- bool found = true;
- for (auto j = 0; j < patternSize; ++j)
+ // Add a wildcard (-1)
+ patternNums.push_back(-1);
+ }
+ else if (i < size - 1)
+ {
+ BYTE result = 0;
+ for (int j = 0; j < 2; j++)
{
- if (scanBytes[i + j] != pattern[j] && pattern[j] != -1)
+ int val = 0;
+ char c = *(str + i + j);
+ if (c >= 'a')
{
- found = false;
- break;
+ val = c - 'a' + 0xA;
+ }
+ else if (c >= 'A')
+ {
+ val = c - 'A' + 0xA;
+ }
+ else if (isdigit(c))
+ {
+ val = c - '0';
+ }
+ else
+ {
+ assert(false, "Failed to parse invalid hex string.");
+ val = -1;
}
- }
- if (found)
- {
- uintptr_t addressInt = (uintptr_t)(&scanBytes[i]) + offset;
- return (uint8_t*)addressInt;
+ result += (j == 0) ? val * 16 : val;
}
+ patternNums.push_back(result);
}
- return nullptr;
+ i++;
}
- inline void* PatternScan(const char* moduleName, const char* pattern, int offset = 0)
- {
- std::vector<int> patternNums;
+ return patternNums;
+}
- bool lastChar = 0;
- int size = strlen(pattern);
- for (int i = 0; i < size; i++)
- {
- char c = pattern[i];
+inline void* PatternScan(void* module, const int* pattern, int patternSize, int offset)
+{
+ if (!module)
+ return NULL;
- // If this is a space character, ignore it
- if (c == ' ' || c == '\t')
- continue;
+ auto dosHeader = (PIMAGE_DOS_HEADER)module;
+ auto ntHeaders = (PIMAGE_NT_HEADERS)((BYTE*)module + dosHeader->e_lfanew);
- if (c == '?')
- {
- // Add a wildcard (-1)
- patternNums.push_back(-1);
- }
- else if (i < size - 1)
+ auto sizeOfImage = ntHeaders->OptionalHeader.SizeOfImage;
+
+ auto scanBytes = (BYTE*)module;
+
+ for (auto i = 0; i < sizeOfImage - patternSize; ++i)
+ {
+ bool found = true;
+ for (auto j = 0; j < patternSize; ++j)
+ {
+ if (scanBytes[i + j] != pattern[j] && pattern[j] != -1)
{
- BYTE result = 0;
- for (int j = 0; j < 2; j++)
- {
- int val = 0;
- char c = (pattern + i + j)[0];
- if (c >= 'a')
- {
- val = c - 'a' + 0xA;
- }
- else if (c >= 'A')
- {
- val = c - 'A' + 0xA;
- }
- else
- {
- val = c - '0';
- }
-
- result += (j == 0) ? val * 16 : val;
- }
- patternNums.push_back(result);
+ found = false;
+ break;
}
+ }
- i++;
+ if (found)
+ {
+ uintptr_t addressInt = (uintptr_t)(&scanBytes[i]) + offset;
+ return (uint8_t*)addressInt;
}
- return PatternScan(GetModuleHandleA(moduleName), &patternNums[0], patternNums.size(), offset);
}
- inline void BytePatch(uintptr_t address, const BYTE* vals, int size)
- {
- WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, vals, size, NULL);
- }
+ return nullptr;
+}
- inline void BytePatch(uintptr_t address, std::initializer_list<BYTE> vals)
- {
- std::vector<BYTE> bytes = vals;
- if (!bytes.empty())
- BytePatch(address, &bytes[0], bytes.size());
- }
+inline void* PatternScan(const char* moduleName, const char* pattern, int offset = 0)
+{
+ std::vector<int> patternNums = HexBytesToString(pattern);
- inline void NOP(uintptr_t address, int size)
- {
- BYTE* buf = (BYTE*)malloc(size);
- memset(buf, 0x90, size);
- BytePatch(address, buf, size);
- free(buf);
- }
+ return PatternScan(GetModuleHandleA(moduleName), &patternNums[0], patternNums.size(), offset);
+}
- inline bool IsMemoryReadable(void* ptr, size_t size)
- {
- BYTE* buffer = (BYTE*)malloc(size);
+inline void BytePatch(uintptr_t address, const BYTE* vals, int size)
+{
+ WriteProcessMemory(GetCurrentProcess(), (LPVOID)address, vals, size, NULL);
+}
- size_t numWritten = 0;
- ReadProcessMemory(GetCurrentProcess(), ptr, buffer, size, &numWritten);
- free(buffer);
+inline void BytePatch(uintptr_t address, std::initializer_list<BYTE> vals)
+{
+ std::vector<BYTE> bytes = vals;
+ if (!bytes.empty())
+ BytePatch(address, &bytes[0], bytes.size());
+}
- return numWritten == size;
- }
+inline void BytePatch(uintptr_t address, const char* bytesStr)
+{
+ std::vector<int> byteInts = HexBytesToString(bytesStr);
+ std::vector<BYTE> bytes;
+ for (int v : byteInts)
+ bytes.push_back(v);
+
+ if (!bytes.empty())
+ BytePatch(address, &bytes[0], bytes.size());
+}
+
+inline void NOP(uintptr_t address, int size)
+{
+ BYTE* buf = (BYTE*)malloc(size);
+ memset(buf, 0x90, size);
+ BytePatch(address, buf, size);
+ free(buf);
+}
+
+inline bool IsMemoryReadable(void* ptr, size_t size)
+{
+ static SYSTEM_INFO sysInfo;
+ if (!sysInfo.dwPageSize)
+ GetSystemInfo(&sysInfo); // This should always be 4096 unless ur playing on NES or some shit but whatever
+
+ MEMORY_BASIC_INFORMATION memInfo;
+
+ if (!VirtualQuery(ptr, &memInfo, sizeof(memInfo)))
+ return false;
+
+ if (memInfo.RegionSize < size)
+ return false;
+
+ return (memInfo.State & MEM_COMMIT) && !(memInfo.Protect & PAGE_NOACCESS);
+}
} // namespace NSMem
#pragma region KHOOK
diff --git a/NorthstarDedicatedTest/clientvideooverrides.cpp b/NorthstarDedicatedTest/clientvideooverrides.cpp
index 0b5ff5f5..d5674f51 100644
--- a/NorthstarDedicatedTest/clientvideooverrides.cpp
+++ b/NorthstarDedicatedTest/clientvideooverrides.cpp
@@ -2,7 +2,7 @@
#include "clientvideooverrides.h"
#include "modmanager.h"
-typedef void*(*BinkOpenType)(const char* path, uint32_t flags);
+typedef void* (*BinkOpenType)(const char* path, uint32_t flags);
BinkOpenType BinkOpen;
void* BinkOpenHook(const char* path, uint32_t flags)
@@ -16,7 +16,7 @@ void* BinkOpenHook(const char* path, uint32_t flags)
{
if (!mod.Enabled)
continue;
-
+
if (std::find(mod.BinkVideos.begin(), mod.BinkVideos.end(), filename) != mod.BinkVideos.end())
fileOwner = &mod;
}
@@ -34,5 +34,6 @@ void* BinkOpenHook(const char* path, uint32_t flags)
void InitialiseClientVideoOverrides(HMODULE baseAddress)
{
HookEnabler hook;
- ENABLER_CREATEHOOK(hook, GetProcAddress(GetModuleHandleA("bink2w64.dll"), "BinkOpen"), &BinkOpenHook, reinterpret_cast<LPVOID*>(&BinkOpen));
+ ENABLER_CREATEHOOK(
+ hook, GetProcAddress(GetModuleHandleA("bink2w64.dll"), "BinkOpen"), &BinkOpenHook, reinterpret_cast<LPVOID*>(&BinkOpen));
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/concommand.h b/NorthstarDedicatedTest/concommand.h
index eb812c32..8f5d59e0 100644
--- a/NorthstarDedicatedTest/concommand.h
+++ b/NorthstarDedicatedTest/concommand.h
@@ -106,5 +106,4 @@ class ConCommand : public ConCommandBase
void RegisterConCommand(const char* name, void (*callback)(const CCommand&), const char* helpString, int flags);
void InitialiseConCommands(HMODULE baseAddress);
-#define MAKE_CONCMD(name, helpStr, flags, fn) \
-RegisterConCommand(name, fn, helpStr, flags); \ No newline at end of file
+#define MAKE_CONCMD(name, helpStr, flags, fn) RegisterConCommand(name, fn, helpStr, flags); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/convar.cpp b/NorthstarDedicatedTest/convar.cpp
index 3f2728d0..c750bd4d 100644
--- a/NorthstarDedicatedTest/convar.cpp
+++ b/NorthstarDedicatedTest/convar.cpp
@@ -36,8 +36,6 @@ void InitialiseConVars(HMODULE baseAddress)
HookEnabler hook;
ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x417FA0, &ConVar::IsFlagSet, reinterpret_cast<LPVOID*>(&CvarIsFlagSet));
-
-
}
//-----------------------------------------------------------------------------
diff --git a/NorthstarDedicatedTest/convar.h b/NorthstarDedicatedTest/convar.h
index fc5b0eb9..72dc1d3c 100644
--- a/NorthstarDedicatedTest/convar.h
+++ b/NorthstarDedicatedTest/convar.h
@@ -129,7 +129,7 @@ class ConVar
};
ConCommandBase m_ConCommandBase{}; // 0x0000
- const char* defaultVal{}; // 0x0040
+ const char* defaultVal{}; // 0x0040
CVValue_t m_Value{}; // 0x0048
bool m_bHasMin{}; // 0x005C
float m_fMinVal{}; // 0x0060
diff --git a/NorthstarDedicatedTest/cvar.h b/NorthstarDedicatedTest/cvar.h
index e254af4e..8e993b19 100644
--- a/NorthstarDedicatedTest/cvar.h
+++ b/NorthstarDedicatedTest/cvar.h
@@ -26,8 +26,7 @@ class CCVarIteratorInternal // Fully reversed table, just look at the virtual fu
//-----------------------------------------------------------------------------
class CCvar
{
- public:
-
+ public:
M_VMETHOD(ConCommandBase*, FindCommandBase, 14, (const char* pszCommandName), (this, pszCommandName));
M_VMETHOD(ConVar*, FindVar, 16, (const char* pszVarName), (this, pszVarName));
M_VMETHOD(ConCommand*, FindCommand, 18, (const char* pszCommandName), (this, pszCommandName));
diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp
index e0206d1f..c97ac91d 100644
--- a/NorthstarDedicatedTest/dedicated.cpp
+++ b/NorthstarDedicatedTest/dedicated.cpp
@@ -7,8 +7,8 @@
bool IsDedicated()
{
- // return CommandLine()->CheckParm("-dedicated");
- return strstr(GetCommandLineA(), "-dedicated");
+ static bool result = strstr(GetCommandLineA(), "-dedicated");
+ return result;
}
// CDedidcatedExports defs
@@ -136,10 +136,10 @@ void InitialiseDedicated(HMODULE engineAddress)
auto ptr = ea + 0x1C4EBD;
// cmp => mov
- NSMem::BytePatch(ptr + 1, {0xC6, 0x87});
+ NSMem::BytePatch(ptr + 1, "C6 87");
// 00 => 01
- NSMem::BytePatch(ptr + 7, {0x01});
+ NSMem::BytePatch(ptr + 7, "01");
}
{
@@ -160,7 +160,7 @@ void InitialiseDedicated(HMODULE engineAddress)
// previously patched these, took me a couple weeks to figure out they were the issue
// removing these will mess up register state when this function is over, so we'll write HS_RUN to the wrong address
// so uhh, don't do that
- //NSMem::NOP(ea + 0x156B4C + 7, 8);
+ // NSMem::NOP(ea + 0x156B4C + 7, 8);
NSMem::NOP(ea + 0x156B4C + 15, 9);
}
@@ -188,7 +188,7 @@ void InitialiseDedicated(HMODULE engineAddress)
{
// Host_Init
// change the number of rpaks to load from 6 to 1, so we only load common.rpak
- NSMem::BytePatch(ea + 0x15653B + 1, {0x01});
+ NSMem::BytePatch(ea + 0x15653B + 1, "01");
}
{
@@ -212,10 +212,11 @@ void InitialiseDedicated(HMODULE engineAddress)
{
// func that checks if origin is inited
// always return 1
- NSMem::BytePatch(ea + 0x183B70, {
- 0xB0, 0x01, // mov al,01
- 0xC3 // ret
- });
+ NSMem::BytePatch(
+ ea + 0x183B70, {
+ 0xB0, 0x01, // mov al,01
+ 0xC3 // ret
+ });
}
{
@@ -301,9 +302,10 @@ void InitialiseDedicatedOrigin(HMODULE baseAddress)
// for any big ea lawyers, this can't be used to play the game without origin, game will throw a fit if you try to do anything without
// an origin id as a client for dedi it's fine though, game doesn't care if origin is disabled as long as there's only a server
- NSMem::BytePatch((uintptr_t)GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"), {
- 0xC3 // ret
- });
+ NSMem::BytePatch(
+ (uintptr_t)GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"), {
+ 0xC3 // ret
+ });
}
typedef void (*PrintFatalSquirrelErrorType)(void* sqvm);
diff --git a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
index 8fa2b58d..b3452fc8 100644
--- a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
+++ b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
@@ -61,9 +61,7 @@ void InitialiseDedicatedMaterialSystem(HMODULE baseAddress)
{
// CMaterialSystem::FindMaterial
// make the game always use the error material
- NSMem::BytePatch((uintptr_t)baseAddress + 0x5F0F1, {
- 0xE9, 0x34, 0x03, 0x00
- });
+ NSMem::BytePatch((uintptr_t)baseAddress + 0x5F0F1, {0xE9, 0x34, 0x03, 0x00});
}
// previously had DisableDedicatedWindowCreation stuff here, removing for now since shit and unstable
diff --git a/NorthstarDedicatedTest/languagehooks.cpp b/NorthstarDedicatedTest/languagehooks.cpp
index 8d60ca22..95638ef2 100644
--- a/NorthstarDedicatedTest/languagehooks.cpp
+++ b/NorthstarDedicatedTest/languagehooks.cpp
@@ -15,7 +15,7 @@ GetGameLanguageType GetGameLanguageOriginal;
bool CheckLangAudioExists(char* lang)
{
- std::string path {"r2\\sound\\general_"};
+ std::string path{"r2\\sound\\general_"};
path += lang;
path += ".mstr";
return fs::exists(path);
@@ -31,7 +31,7 @@ std::vector<std::string> file_list(fs::path dir, std::regex ext_pattern)
using iterator = fs::directory_iterator;
const iterator end;
- for (iterator iter {dir}; iter != end; ++iter)
+ for (iterator iter{dir}; iter != end; ++iter)
{
const std::string filename = iter->path().filename().string();
std::smatch matches;
diff --git a/NorthstarDedicatedTest/latencyflex.cpp b/NorthstarDedicatedTest/latencyflex.cpp
index 4ac1c760..623ac06b 100644
--- a/NorthstarDedicatedTest/latencyflex.cpp
+++ b/NorthstarDedicatedTest/latencyflex.cpp
@@ -8,9 +8,9 @@ OnRenderStartType OnRenderStart;
ConVar* Cvar_r_latencyflex;
-HMODULE m_lfxModule {};
+HMODULE m_lfxModule{};
typedef void (*PFN_winelfx_WaitAndBeginFrame)();
-PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame {};
+PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame{};
void OnRenderStartHook()
{
diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp
index 98e80592..25b9a530 100644
--- a/NorthstarDedicatedTest/logging.cpp
+++ b/NorthstarDedicatedTest/logging.cpp
@@ -68,8 +68,7 @@ long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo)
else if (exceptionInfo0 == 1)
exceptionCause << "Attempted to write to: 0x" << (void*)exceptionInfo1;
else if (exceptionInfo0 == 8)
- exceptionCause << "Data Execution Prevention (DEP) at: 0x" << (void*)std::hex
- << exceptionInfo1;
+ exceptionCause << "Data Execution Prevention (DEP) at: 0x" << (void*)std::hex << exceptionInfo1;
else
exceptionCause << "Unknown access violation at: 0x" << (void*)exceptionInfo1;
diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp
index 076c0a14..ab6388c3 100644
--- a/NorthstarDedicatedTest/masterserver.cpp
+++ b/NorthstarDedicatedTest/masterserver.cpp
@@ -557,7 +557,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken
curl_easy_setopt(
curl, CURLOPT_URL,
fmt::format("{}/client/auth_with_self?id={}&playerToken={}", Cvar_ns_masterserver_hostname->GetString(), uidStr, tokenStr)
- .c_str());
+ .c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -699,7 +699,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c
fmt::format(
"{}/client/auth_with_server?id={}&playerToken={}&server={}&password={}", Cvar_ns_masterserver_hostname->GetString(),
uidStr, tokenStr, serverIdStr, escapedPassword)
- .c_str());
+ .c_str());
curl_free(escapedPassword);
}
@@ -833,7 +833,7 @@ void MasterServerManager::AddSelfToServerList(
"{}/server/add_server?port={}&authPort={}&name={}&description={}&map={}&playlist={}&maxPlayers={}&password={}",
Cvar_ns_masterserver_hostname->GetString(), port, authPort, nameEscaped, descEscaped, mapEscaped, playlistEscaped,
maxPlayers, passwordEscaped)
- .c_str());
+ .c_str());
curl_free(nameEscaped);
curl_free(descEscaped);
@@ -937,7 +937,7 @@ void MasterServerManager::AddSelfToServerList(
Cvar_ns_player_auth_port->GetInt(), escapedNameNew, escapedDescNew, escapedMapNew,
escapedPlaylistNew, g_ServerAuthenticationManager->m_additionalPlayerData.size(), maxPlayers,
escapedPasswordNew)
- .c_str());
+ .c_str());
curl_free(escapedNameNew);
curl_free(escapedDescNew);
@@ -1038,7 +1038,7 @@ void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist,
fmt::format(
"{}/server/update_values?id={}&map={}&playlist={}&maxPlayers={}", Cvar_ns_masterserver_hostname->GetString(),
m_ownServerId, mapEscaped, playlistEscaped, maxPlayers)
- .c_str());
+ .c_str());
curl_free(mapEscaped);
curl_free(playlistEscaped);
@@ -1077,7 +1077,7 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount)
curl, CURLOPT_URL,
fmt::format(
"{}/server/update_values?id={}&playerCount={}", Cvar_ns_masterserver_hostname->GetString(), m_ownServerId, playerCount)
- .c_str());
+ .c_str());
CURLcode result = curl_easy_perform(curl);
@@ -1117,7 +1117,7 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata,
fmt::format(
"{}/accounts/write_persistence?id={}&serverId={}", Cvar_ns_masterserver_hostname->GetString(), strPlayerId,
m_ownServerId)
- .c_str());
+ .c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -1262,7 +1262,7 @@ void CHostState__State_GameShutdownHook(CHostState* hostState)
CHostState__State_GameShutdown(hostState);
}
-MasterServerManager::MasterServerManager() : m_pendingConnectionInfo{}, m_ownServerId{ "" }, m_ownClientAuthToken{ "" } {}
+MasterServerManager::MasterServerManager() : m_pendingConnectionInfo{}, m_ownServerId{""}, m_ownClientAuthToken{""} {}
void InitialiseSharedMasterServer(HMODULE baseAddress)
{
diff --git a/NorthstarDedicatedTest/maxplayers.cpp b/NorthstarDedicatedTest/maxplayers.cpp
index 54f1a896..9550553c 100644
--- a/NorthstarDedicatedTest/maxplayers.cpp
+++ b/NorthstarDedicatedTest/maxplayers.cpp
@@ -46,9 +46,7 @@ constexpr int Team_PlayerArray_AddedSize = PAD_NUMBER(Team_PlayerArray_AddedLeng
constexpr int Team_AddedSize = Team_PlayerArray_AddedSize;
#include "NSMem.h"
-template <class T> void ChangeOffset(void* addr, unsigned int offset) {
- NSMem::BytePatch((uintptr_t)addr, (BYTE*)&offset, sizeof(T));
-}
+template <class T> void ChangeOffset(void* addr, unsigned int offset) { NSMem::BytePatch((uintptr_t)addr, (BYTE*)&offset, sizeof(T)); }
/*
typedef bool(*MatchRecvPropsToSendProps_R_Type)(__int64 lookup, __int64 tableNameBroken, __int64 sendTable, __int64 recvTable);
diff --git a/NorthstarDedicatedTest/misccommands.cpp b/NorthstarDedicatedTest/misccommands.cpp
index dca87947..cdadff8d 100644
--- a/NorthstarDedicatedTest/misccommands.cpp
+++ b/NorthstarDedicatedTest/misccommands.cpp
@@ -10,7 +10,8 @@ void AddMiscConCommands()
{
MAKE_CONCMD(
"force_newgame", "forces a map load through directly setting g_pHostState->m_iNextState to HS_NEW_GAME", FCVAR_NONE,
- [](const CCommand& arg) {
+ [](const CCommand& arg)
+ {
if (arg.ArgC() < 2)
return;
@@ -20,29 +21,34 @@ void AddMiscConCommands()
MAKE_CONCMD(
"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, [](const CCommand& arg) {
+ FCVAR_SERVER_CAN_EXECUTE,
+ [](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_MasterServerManager->m_bNewgameAfterSelfAuth = true;
g_MasterServerManager->AuthenticateWithOwnServer(g_LocalPlayerUserID, g_MasterServerManager->m_ownClientAuthToken);
});
// this is a concommand because we make a deferred call to it from another thread
- MAKE_CONCMD("ns_end_reauth_and_leave_to_lobby", "", FCVAR_NONE, [](const CCommand& arg) {
- Cbuf_AddText(
- Cbuf_GetCurrentPlayer(), fmt::format("serverfilter {}", g_ServerAuthenticationManager->m_authData.begin()->first).c_str(),
- cmd_source_t::kCommandSrcCode);
- Cbuf_Execute();
-
- // weird way of checking, but check if client script vm is initialised, mainly just to allow players to cancel this
- if (g_ClientSquirrelManager->sqvm)
+ MAKE_CONCMD(
+ "ns_end_reauth_and_leave_to_lobby", "", FCVAR_NONE,
+ [](const CCommand& arg)
{
- g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = true;
+ Cbuf_AddText(
+ Cbuf_GetCurrentPlayer(), fmt::format("serverfilter {}", g_ServerAuthenticationManager->m_authData.begin()->first).c_str(),
+ cmd_source_t::kCommandSrcCode);
+ Cbuf_Execute();
- // 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?
- SetCurrentPlaylist("tdm");
- strcpy(g_pHostState->m_levelName, "mp_lobby");
- g_pHostState->m_iNextState = HS_NEW_GAME;
- }
- });
+ // weird way of checking, but check if client script vm is initialised, mainly just to allow players to cancel this
+ if (g_ClientSquirrelManager->sqvm)
+ {
+ g_ServerAuthenticationManager->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?
+ SetCurrentPlaylist("tdm");
+ strcpy(g_pHostState->m_levelName, "mp_lobby");
+ g_pHostState->m_iNextState = HS_NEW_GAME;
+ }
+ });
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/miscserverfixes.cpp b/NorthstarDedicatedTest/miscserverfixes.cpp
index 7d977d64..30cd5777 100644
--- a/NorthstarDedicatedTest/miscserverfixes.cpp
+++ b/NorthstarDedicatedTest/miscserverfixes.cpp
@@ -10,7 +10,7 @@ void InitialiseMiscServerFixes(HMODULE baseAddress)
// ret at the start of the concommand GenerateObjFile as it can crash servers
{
- NSMem::BytePatch(ba + 0x38D920, {0xC3});
+ NSMem::BytePatch(ba + 0x38D920, "C3");
}
// nop out call to VGUI shutdown since it crashes the game when quitting from the console
@@ -21,7 +21,7 @@ void InitialiseMiscServerFixes(HMODULE baseAddress)
// 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
{
- NSMem::BytePatch(ba + 0x153920, {0xC3});
+ NSMem::BytePatch(ba + 0x153920, "C3");
}
}
diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp
index 99bb5fdb..0ac7e4b6 100644
--- a/NorthstarDedicatedTest/modmanager.cpp
+++ b/NorthstarDedicatedTest/modmanager.cpp
@@ -194,7 +194,7 @@ ModManager::ModManager()
m_hScriptsRsonHash = STR_HASH("scripts\\vscripts\\scripts.rson");
m_hPdefHash = STR_HASH(
"cfg\\server\\persistent_player_data_version_231.pdef" // this can have multiple versions, but we use 231 so that's what we hash
- );
+ );
LoadMods();
}
@@ -283,7 +283,8 @@ void ModManager::LoadMods()
// preexisting convars note: we don't delete convars if they already exist because they're used for script stuff, unfortunately this
// causes us to leak memory on reload, but not much, potentially find a way to not do this at some point
for (ModConVar* convar : mod.ConVars)
- if (!g_pCVar->FindVar(convar->Name.c_str())) // make sure convar isn't registered yet, unsure if necessary but idk what behaviour is for defining same convar multiple times
+ if (!g_pCVar->FindVar(convar->Name.c_str())) // make sure convar isn't registered yet, unsure if necessary but idk what
+ // behaviour is for defining same convar multiple times
new ConVar(convar->Name.c_str(), convar->DefaultValue.c_str(), convar->Flags, convar->HelpString.c_str());
// read vpk paths
@@ -305,8 +306,7 @@ void ModManager::LoadMods()
dVpkJson.Parse<rapidjson::ParseFlag::kParseCommentsFlag | rapidjson::ParseFlag::kParseTrailingCommasFlag>(
vpkJsonStringStream.str().c_str());
- bUseVPKJson =
- !dVpkJson.HasParseError() && dVpkJson.IsObject();
+ bUseVPKJson = !dVpkJson.HasParseError() && dVpkJson.IsObject();
}
for (fs::directory_entry file : fs::directory_iterator(mod.ModDirectory / "vpk"))
@@ -324,7 +324,8 @@ void ModManager::LoadMods()
(file.path().parent_path() / formattedPath.substr(strlen("english"), formattedPath.find(".bsp") - 3)).string();
ModVPKEntry& modVpk = mod.Vpks.emplace_back();
- modVpk.m_bAutoLoad = !bUseVPKJson || (dVpkJson.HasMember("Preload") && dVpkJson["Preload"].IsObject() && dVpkJson["Preload"].HasMember(vpkName) && dVpkJson["Preload"][vpkName].IsTrue());
+ modVpk.m_bAutoLoad = !bUseVPKJson || (dVpkJson.HasMember("Preload") && dVpkJson["Preload"].IsObject() &&
+ dVpkJson["Preload"].HasMember(vpkName) && dVpkJson["Preload"][vpkName].IsTrue());
modVpk.m_sVpkPath = vpkName;
if (m_hasLoadedMods && modVpk.m_bAutoLoad)
@@ -352,8 +353,7 @@ void ModManager::LoadMods()
dRpakJson.Parse<rapidjson::ParseFlag::kParseCommentsFlag | rapidjson::ParseFlag::kParseTrailingCommasFlag>(
rpakJsonStringStream.str().c_str());
- bUseRpakJson =
- !dRpakJson.HasParseError() && dRpakJson.IsObject();
+ bUseRpakJson = !dRpakJson.HasParseError() && dRpakJson.IsObject();
}
// read pak aliases
@@ -377,11 +377,13 @@ void ModManager::LoadMods()
std::string pakName(file.path().filename().string());
ModRpakEntry& modPak = mod.Rpaks.emplace_back();
- modPak.m_bAutoLoad = !bUseRpakJson || (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() && dRpakJson["Preload"].HasMember(pakName) && dRpakJson["Preload"][pakName].IsTrue());
+ modPak.m_bAutoLoad =
+ !bUseRpakJson || (dRpakJson.HasMember("Preload") && dRpakJson["Preload"].IsObject() &&
+ dRpakJson["Preload"].HasMember(pakName) && dRpakJson["Preload"][pakName].IsTrue());
modPak.m_sPakPath = pakName;
// not using atm because we need to resolve path to rpak
- //if (m_hasLoadedMods && modPak.m_bAutoLoad)
+ // if (m_hasLoadedMods && modPak.m_bAutoLoad)
// g_PakLoadManager->LoadPakAsync(pakName.c_str());
}
}
diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h
index c79c507d..7f12559f 100644
--- a/NorthstarDedicatedTest/modmanager.h
+++ b/NorthstarDedicatedTest/modmanager.h
@@ -97,7 +97,8 @@ class Mod
std::string Pdiff; // only need one per mod
std::vector<ModRpakEntry> Rpaks;
- std::unordered_map<std::string, std::string> RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite
+ std::unordered_map<std::string, std::string>
+ RpakAliases; // paks we alias to other rpaks, e.g. to load sp_crashsite paks on the map mp_crashsite
// other stuff
diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h
index cc44c107..c5c78dc7 100644
--- a/NorthstarDedicatedTest/pch.h
+++ b/NorthstarDedicatedTest/pch.h
@@ -31,17 +31,15 @@ template <typename ReturnType, typename... Args> ReturnType CallVFunc(int index,
return (*reinterpret_cast<ReturnType(__fastcall***)(void*, Args...)>(thisPtr))[index](thisPtr, args...);
}
-template <typename T, size_t index, typename ...Args> constexpr T CallVFunc_Alt(void* classBase, Args... args) noexcept {
+template <typename T, size_t index, typename... Args> constexpr T CallVFunc_Alt(void* classBase, Args... args) noexcept
+{
return ((*(T(__thiscall***)(void*, Args...))(classBase))[index])(classBase, args...);
}
-
#define STR_HASH(s) (std::hash<std::string>()(s))
// Example usage: M_VMETHOD(int, GetEntityIndex, 8, (CBaseEntity* ent), (this, ent))
-#define M_VMETHOD(returnType, name, index, args, argsRaw) \
-FORCEINLINE returnType name args noexcept { \
- return CallVFunc_Alt<returnType, index> argsRaw; \
-}
+#define M_VMETHOD(returnType, name, index, args, argsRaw) \
+ FORCEINLINE returnType name args noexcept { return CallVFunc_Alt<returnType, index> argsRaw; }
#endif \ No newline at end of file
diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp
index a0a2dc33..fdb23893 100644
--- a/NorthstarDedicatedTest/playlist.cpp
+++ b/NorthstarDedicatedTest/playlist.cpp
@@ -98,11 +98,9 @@ void InitialisePlaylistHooks(HMODULE baseAddress)
// patch to prevent clc_SetPlaylistVarOverride from being able to crash servers if we reach max overrides due to a call to Error (why is
// this possible respawn, wtf) todo: add a warning for this
{
- NSMem::BytePatch(ba + 0x18ED8D, {
- 0xC3 // jmp => ret
- });
+ NSMem::BytePatch(ba + 0x18ED8D, "C3");
}
// patch to allow setplaylistvaroverride to be called before map init on dedicated and private match launched through the game
NSMem::NOP(ba + 0x18ED17, 6);
-}
+} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp
index ba7cf3d2..6853029b 100644
--- a/NorthstarDedicatedTest/rpakfilesystem.cpp
+++ b/NorthstarDedicatedTest/rpakfilesystem.cpp
@@ -7,7 +7,7 @@ typedef void* (*LoadCommonPaksForMapType)(char* map);
LoadCommonPaksForMapType LoadCommonPaksForMap;
typedef void* (*LoadPakSyncType)(const char* path, void* unknownSingleton, int flags);
-typedef int(*LoadPakAsyncType)(const char* path, void* unknownSingleton, int flags, void* callback0, void* callback1);
+typedef int (*LoadPakAsyncType)(const char* path, void* unknownSingleton, int flags, void* callback0, void* callback1);
// there are more i'm just too lazy to add
struct PakLoadFuncs
@@ -59,20 +59,21 @@ void LoadPreloadPaks()
for (ModRpakEntry& pak : mod.Rpaks)
if (pak.m_bAutoLoad)
g_PakLoadManager->LoadPakAsync((modPakPath / pak.m_sPakPath).string().c_str());
- }
+ }
bShouldPreload = true;
}
LoadPakSyncType LoadPakSyncOriginal;
void* LoadPakSyncHook(char* path, void* unknownSingleton, int flags)
-{
+{
HandlePakAliases(&path);
- // note: we don't handle loading any preloaded custom paks synchronously since LoadPakSync is never actually called in retail, just load them async instead
+ // note: we don't handle loading any preloaded custom paks synchronously since LoadPakSync is never actually called in retail, just load
+ // them async instead
LoadPreloadPaks();
spdlog::info("LoadPakSync {}", path);
- return LoadPakSyncOriginal(path, unknownSingleton, flags);
+ return LoadPakSyncOriginal(path, unknownSingleton, flags);
}
LoadPakAsyncType LoadPakAsyncOriginal;
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index 4581e4b6..46fa6491 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -628,25 +628,26 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
// patch to disable kicking based on incorrect serverfilter in connectclient, since we repurpose it for use as an auth token
{
- NSMem::BytePatch(ba + 0x114655, {
- 0xEB // jz => jmp
- });
+ NSMem::BytePatch(
+ ba + 0x114655,
+ "EB" // jz => jmp
+ );
}
// patch to disable fairfight marking players as cheaters and kicking them
{
- NSMem::BytePatch(ba + 0x101012, {
- 0xE9, // jz => jmp
- 0x90,
- 0x0
- });
+ NSMem::BytePatch(
+ ba + 0x101012,
+ "E9 90 00" // jz => jmp
+ );
}
// patch to allow same of multiple account
{
- NSMem::BytePatch(ba + 0x114510, {
- 0xEB, // jz => jmp
- });
+ NSMem::BytePatch(
+ ba + 0x114510,
+ "EB" // jz => jmp
+ );
}
// patch to set bWasWritingStringTableSuccessful in CNetworkStringTableContainer::WriteBaselines if it fails
@@ -654,9 +655,11 @@ void InitialiseServerAuthentication(HMODULE baseAddress)
uintptr_t writeAddress = (uintptr_t)(&bWasWritingStringTableSuccessful - (ba + 0x234EDC));
auto addr = ba + 0x234ED2;
- NSMem::BytePatch(addr, { 0xC7, 0x05 });
+ NSMem::BytePatch(addr, "C7 05");
NSMem::BytePatch(addr + 2, (BYTE*)&writeAddress, sizeof(writeAddress));
- NSMem::BytePatch(addr + 6, {0, 0, 0, 0});
+
+ NSMem::BytePatch(addr + 6, "00 00 00 00");
+
NSMem::NOP(addr + 10, 5);
}
}
diff --git a/NorthstarDedicatedTest/version.cpp b/NorthstarDedicatedTest/version.cpp
index dfeb9670..a0bcee20 100644
--- a/NorthstarDedicatedTest/version.cpp
+++ b/NorthstarDedicatedTest/version.cpp
@@ -4,7 +4,8 @@
char version[16];
char NSUserAgent[32];
-void InitialiseVersion() {
+void InitialiseVersion()
+{
HRSRC hResInfo;
DWORD dwSize;
HGLOBAL hResData;
@@ -14,13 +15,16 @@ void InitialiseVersion() {
HINSTANCE hInst = ::GetModuleHandle(NULL);
hResInfo = FindResourceW(hInst, MAKEINTRESOURCE(1), RT_VERSION);
- if (hResInfo != NULL) {
+ if (hResInfo != NULL)
+ {
dwSize = SizeofResource(hInst, hResInfo);
hResData = LoadResource(hInst, hResInfo);
- if (hResData != NULL) {
+ if (hResData != NULL)
+ {
pRes = LockResource(hResData);
pResCopy = LocalAlloc(LMEM_FIXED, dwSize);
- if (pResCopy != 0) {
+ if (pResCopy != 0)
+ {
CopyMemory(pResCopy, pRes, dwSize);
VerQueryValueW(pResCopy, L"\\", (LPVOID*)&lpFfi, &uLen);
@@ -35,11 +39,13 @@ void InitialiseVersion() {
// We actually use the rightmost integer do determine whether or not we're a debug/dev build
// If it is set to 1 (as in resources.rc), we are a dev build
// On github CI, we set this 1 to a 0 automatically as we replace the 0.0.0.1 with the real version number
- if (dwRightMost == 1) {
+ if (dwRightMost == 1)
+ {
sprintf(version, "%d.%d.%d.%d+dev", dwLeftMost, dwSecondLeft, dwSecondRight, dwRightMost);
sprintf(NSUserAgent, "R2Northstar/%d.%d.%d+dev", dwLeftMost, dwSecondLeft, dwSecondRight);
}
- else {
+ else
+ {
sprintf(version, "%d.%d.%d.%d", dwLeftMost, dwSecondLeft, dwSecondRight, dwRightMost);
sprintf(NSUserAgent, "R2Northstar/%d.%d.%d", dwLeftMost, dwSecondLeft, dwSecondRight);
}