aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj2
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters6
-rw-r--r--NorthstarDedicatedTest/buildainfile.cpp11
-rw-r--r--NorthstarDedicatedTest/clientruihooks.cpp16
-rw-r--r--NorthstarDedicatedTest/clientvideooverrides.cpp13
-rw-r--r--NorthstarDedicatedTest/crashhandler.cpp216
-rw-r--r--NorthstarDedicatedTest/crashhandler.h4
-rw-r--r--NorthstarDedicatedTest/debugoverlay.cpp13
-rw-r--r--NorthstarDedicatedTest/dedicated.cpp26
-rw-r--r--NorthstarDedicatedTest/dedicatedmaterialsystem.cpp50
-rw-r--r--NorthstarDedicatedTest/demofixes.cpp9
-rw-r--r--NorthstarDedicatedTest/dllmain.cpp2
-rw-r--r--NorthstarDedicatedTest/filesystem.cpp57
-rw-r--r--NorthstarDedicatedTest/hooks.cpp35
-rw-r--r--NorthstarDedicatedTest/hooks.h60
-rw-r--r--NorthstarDedicatedTest/host.cpp12
-rw-r--r--NorthstarDedicatedTest/hoststate.cpp33
-rw-r--r--NorthstarDedicatedTest/keyvalues.cpp38
-rw-r--r--NorthstarDedicatedTest/languagehooks.cpp19
-rw-r--r--NorthstarDedicatedTest/latencyflex.cpp14
-rw-r--r--NorthstarDedicatedTest/logging.cpp408
-rw-r--r--NorthstarDedicatedTest/modlocalisation.cpp12
-rw-r--r--NorthstarDedicatedTest/pch.h2
-rw-r--r--NorthstarDedicatedTest/playlist.cpp94
-rw-r--r--NorthstarDedicatedTest/playlist.h15
-rw-r--r--NorthstarDedicatedTest/rpakfilesystem.cpp67
-rw-r--r--NorthstarDedicatedTest/sourceconsole.cpp73
-rw-r--r--NorthstarDedicatedTest/sourceconsole.h15
-rw-r--r--NorthstarDedicatedTest/sourceinterface.cpp49
29 files changed, 666 insertions, 705 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
index d6c77de4..5b8a7607 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
@@ -117,6 +117,7 @@
<ClInclude Include="bansystem.h" />
<ClInclude Include="bitbuf.h" />
<ClInclude Include="bits.h" />
+ <ClInclude Include="crashhandler.h" />
<ClInclude Include="printcommand.h" />
<ClInclude Include="hoststate.h" />
<ClInclude Include="localchatwriter.h" />
@@ -571,6 +572,7 @@
<ClCompile Include="concommand.cpp" />
<ClCompile Include="configurables.cpp" />
<ClCompile Include="convar.cpp" />
+ <ClCompile Include="crashhandler.cpp" />
<ClCompile Include="cvar.cpp" />
<ClCompile Include="debugoverlay.cpp" />
<ClCompile Include="dedicated.cpp" />
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
index 3ab95494..10bbced8 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
@@ -1482,6 +1482,9 @@
<ClInclude Include="r2client.h">
<Filter>Header Files\Shared\Game Functions</Filter>
</ClInclude>
+ <ClInclude Include="crashhandler.h">
+ <Filter>Header Files\Shared</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@@ -1670,6 +1673,9 @@
<ClCompile Include="r2engine.cpp">
<Filter>Source Files\Shared\Game Functions</Filter>
</ClCompile>
+ <ClCompile Include="crashhandler.cpp">
+ <Filter>Source Files\Shared</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<MASM Include="audio_asm.asm">
diff --git a/NorthstarDedicatedTest/buildainfile.cpp b/NorthstarDedicatedTest/buildainfile.cpp
index ea9d69ef..a80185e5 100644
--- a/NorthstarDedicatedTest/buildainfile.cpp
+++ b/NorthstarDedicatedTest/buildainfile.cpp
@@ -1,8 +1,10 @@
#include "pch.h"
#include "convar.h"
+#include "hoststate.h"
+#include "NSMem.h"
+
#include <fstream>
#include <filesystem>
-#include "NSMem.h"
AUTOHOOK_INIT()
@@ -161,14 +163,13 @@ struct CAI_Network
};
char** pUnkServerMapversionGlobal;
-char* pMapName;
ConVar* Cvar_ns_ai_dumpAINfileFromLoad;
void DumpAINInfo(CAI_Network* aiNetwork)
{
fs::path writePath("r2/maps/graphs");
- writePath /= pMapName;
+ writePath /= R2::g_pHostState->m_levelName;
writePath += ".ain";
// dump from memory
@@ -370,14 +371,14 @@ void,, (void* aimanager, void* buf, const char* filename),
ON_DLL_LOAD("server.dll", BuildAINFile, [](HMODULE baseAddress)
{
+ AUTOHOOK_DISPATCH()
+
Cvar_ns_ai_dumpAINfileFromLoad = new ConVar(
"ns_ai_dumpAINfileFromLoad", "0", FCVAR_NONE, "For debugging: whether we should dump ain data for ains loaded from disk");
pUnkStruct0Count = (int*)((char*)baseAddress + 0x1063BF8);
pppUnkNodeStruct0s = (UnkNodeStruct0***)((char*)baseAddress + 0x1063BE0);
-
pUnkLinkStruct1Count = (int*)((char*)baseAddress + 0x1063AA8);
pppUnkStruct1s = (UnkLinkStruct1***)((char*)baseAddress + 0x1063A90);
pUnkServerMapversionGlobal = (char**)((char*)baseAddress + 0xBFBE08);
- pMapName = (char*)baseAddress + 0x1053370;
}); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/clientruihooks.cpp b/NorthstarDedicatedTest/clientruihooks.cpp
index da556d26..5fb0b348 100644
--- a/NorthstarDedicatedTest/clientruihooks.cpp
+++ b/NorthstarDedicatedTest/clientruihooks.cpp
@@ -1,22 +1,22 @@
#include "pch.h"
#include "convar.h"
+AUTOHOOK_INIT()
+
ConVar* Cvar_rui_drawEnable;
-typedef char (*DrawRUIFuncType)(void* a1, float* a2);
-DrawRUIFuncType DrawRUIFunc;
-char DrawRUIFuncHook(void* a1, float* a2)
+AUTOHOOK(DrawRUIFunc, engine.dll + 0xFC500,
+bool,, (void* a1, float* a2),
{
if (!Cvar_rui_drawEnable->GetBool())
return 0;
-
+
return DrawRUIFunc(a1, a2);
-}
+})
ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", RUI, ConVar, [](HMODULE baseAddress)
{
- Cvar_rui_drawEnable = new ConVar("rui_drawEnable", "1", FCVAR_CLIENTDLL, "Controls whether RUI should be drawn");
+ AUTOHOOK_DISPATCH()
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xFC500, &DrawRUIFuncHook, reinterpret_cast<LPVOID*>(&DrawRUIFunc));
+ Cvar_rui_drawEnable = new ConVar("rui_drawEnable", "1", FCVAR_CLIENTDLL, "Controls whether RUI should be drawn");
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/clientvideooverrides.cpp b/NorthstarDedicatedTest/clientvideooverrides.cpp
index b3609fc2..0bc6bb06 100644
--- a/NorthstarDedicatedTest/clientvideooverrides.cpp
+++ b/NorthstarDedicatedTest/clientvideooverrides.cpp
@@ -1,9 +1,10 @@
#include "pch.h"
#include "modmanager.h"
-typedef void* (*BinkOpenType)(const char* path, uint32_t flags);
-BinkOpenType BinkOpen;
-void* BinkOpenHook(const char* path, uint32_t flags)
+AUTOHOOK_INIT()
+
+AUTOHOOK_PROCADDRESS(BinkOpen, bink2w64.dll, BinkOpen,
+void*,, (const char* path, uint32_t flags),
{
std::string filename(fs::path(path).filename().string());
spdlog::info("BinkOpen {}", filename);
@@ -27,11 +28,9 @@ void* BinkOpenHook(const char* path, uint32_t flags)
}
else
return BinkOpen(path, flags);
-}
+})
ON_DLL_LOAD_CLIENT("client.dll", BinkVideo, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook, GetProcAddress(GetModuleHandleA("bink2w64.dll"), "BinkOpen"), &BinkOpenHook, reinterpret_cast<LPVOID*>(&BinkOpen));
+ AUTOHOOK_DISPATCH()
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/crashhandler.cpp b/NorthstarDedicatedTest/crashhandler.cpp
new file mode 100644
index 00000000..90091883
--- /dev/null
+++ b/NorthstarDedicatedTest/crashhandler.cpp
@@ -0,0 +1,216 @@
+#include "pch.h"
+#include "crashhandler.h"
+#include "dedicated.h"
+#include "configurables.h"
+
+#include <minidumpapiset.h>
+
+HANDLE hExceptionFilter;
+
+long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo)
+{
+ static bool logged = false;
+ if (logged)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ if (!IsDebuggerPresent())
+ {
+ const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode;
+ if (exceptionCode != EXCEPTION_ACCESS_VIOLATION && exceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED &&
+ exceptionCode != EXCEPTION_DATATYPE_MISALIGNMENT && exceptionCode != EXCEPTION_FLT_DENORMAL_OPERAND &&
+ exceptionCode != EXCEPTION_FLT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_FLT_INEXACT_RESULT &&
+ exceptionCode != EXCEPTION_FLT_INVALID_OPERATION && exceptionCode != EXCEPTION_FLT_OVERFLOW &&
+ exceptionCode != EXCEPTION_FLT_STACK_CHECK && exceptionCode != EXCEPTION_FLT_UNDERFLOW &&
+ exceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION && exceptionCode != EXCEPTION_IN_PAGE_ERROR &&
+ exceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_INT_OVERFLOW &&
+ exceptionCode != EXCEPTION_INVALID_DISPOSITION && exceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION &&
+ exceptionCode != EXCEPTION_PRIV_INSTRUCTION && exceptionCode != EXCEPTION_STACK_OVERFLOW)
+ return EXCEPTION_CONTINUE_SEARCH;
+
+ std::stringstream exceptionCause;
+ exceptionCause << "Cause: ";
+ switch (exceptionCode)
+ {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_IN_PAGE_ERROR:
+ {
+ exceptionCause << "Access Violation" << std::endl;
+
+ auto exceptionInfo0 = exceptionInfo->ExceptionRecord->ExceptionInformation[0];
+ auto exceptionInfo1 = exceptionInfo->ExceptionRecord->ExceptionInformation[1];
+
+ if (!exceptionInfo0)
+ exceptionCause << "Attempted to read from: 0x" << (void*)exceptionInfo1;
+ 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;
+ else
+ exceptionCause << "Unknown access violation at: 0x" << (void*)exceptionInfo1;
+
+ break;
+ }
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ exceptionCause << "Array bounds exceeded";
+ break;
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ exceptionCause << "Datatype misalignment";
+ break;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ exceptionCause << "Denormal operand";
+ break;
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ exceptionCause << "Divide by zero (float)";
+ break;
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ exceptionCause << "Divide by zero (int)";
+ break;
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ exceptionCause << "Inexact result";
+ break;
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ exceptionCause << "Invalid operation";
+ break;
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_INT_OVERFLOW:
+ exceptionCause << "Numeric overflow";
+ break;
+ case EXCEPTION_FLT_UNDERFLOW:
+ exceptionCause << "Numeric underflow";
+ break;
+ case EXCEPTION_FLT_STACK_CHECK:
+ exceptionCause << "Stack check";
+ break;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ exceptionCause << "Illegal instruction";
+ break;
+ case EXCEPTION_INVALID_DISPOSITION:
+ exceptionCause << "Invalid disposition";
+ break;
+ case EXCEPTION_NONCONTINUABLE_EXCEPTION:
+ exceptionCause << "Noncontinuable exception";
+ break;
+ case EXCEPTION_PRIV_INSTRUCTION:
+ exceptionCause << "Priviledged instruction";
+ break;
+ case EXCEPTION_STACK_OVERFLOW:
+ exceptionCause << "Stack overflow";
+ break;
+ default:
+ exceptionCause << "Unknown";
+ break;
+ }
+
+ void* exceptionAddress = exceptionInfo->ExceptionRecord->ExceptionAddress;
+
+ HMODULE crashedModuleHandle;
+ GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(exceptionAddress), &crashedModuleHandle);
+
+ MODULEINFO crashedModuleInfo;
+ GetModuleInformation(GetCurrentProcess(), crashedModuleHandle, &crashedModuleInfo, sizeof(crashedModuleInfo));
+
+ char crashedModuleFullName[MAX_PATH];
+ GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH);
+ char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1;
+
+ DWORD64 crashedModuleOffset = ((DWORD64)exceptionAddress) - ((DWORD64)crashedModuleInfo.lpBaseOfDll);
+ CONTEXT* exceptionContext = exceptionInfo->ContextRecord;
+
+ spdlog::error("Northstar has crashed! a minidump has been written and exception info is available below:");
+ spdlog::error(exceptionCause.str());
+ spdlog::error("At: {} + {}", crashedModuleName, (void*)crashedModuleOffset);
+
+ PVOID framesToCapture[62];
+ int frames = RtlCaptureStackBackTrace(0, 62, framesToCapture, NULL);
+ for (int i = 0; i < frames; i++)
+ {
+ HMODULE backtraceModuleHandle;
+ GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(framesToCapture[i]), &backtraceModuleHandle);
+
+ char backtraceModuleFullName[MAX_PATH];
+ GetModuleFileNameExA(GetCurrentProcess(), backtraceModuleHandle, backtraceModuleFullName, MAX_PATH);
+ char* backtraceModuleName = strrchr(backtraceModuleFullName, '\\') + 1;
+
+ void* actualAddress = (void*)framesToCapture[i];
+ void* relativeAddress = (void*)(uintptr_t(actualAddress) - uintptr_t(backtraceModuleHandle));
+
+ spdlog::error(" {} + {} ({})", backtraceModuleName, relativeAddress, actualAddress);
+ }
+
+ spdlog::error("RAX: 0x{0:x}", exceptionContext->Rax);
+ spdlog::error("RBX: 0x{0:x}", exceptionContext->Rbx);
+ spdlog::error("RCX: 0x{0:x}", exceptionContext->Rcx);
+ spdlog::error("RDX: 0x{0:x}", exceptionContext->Rdx);
+ spdlog::error("RSI: 0x{0:x}", exceptionContext->Rsi);
+ spdlog::error("RDI: 0x{0:x}", exceptionContext->Rdi);
+ spdlog::error("RBP: 0x{0:x}", exceptionContext->Rbp);
+ spdlog::error("RSP: 0x{0:x}", exceptionContext->Rsp);
+ spdlog::error("R8: 0x{0:x}", exceptionContext->R8);
+ spdlog::error("R9: 0x{0:x}", exceptionContext->R9);
+ spdlog::error("R10: 0x{0:x}", exceptionContext->R10);
+ spdlog::error("R11: 0x{0:x}", exceptionContext->R11);
+ spdlog::error("R12: 0x{0:x}", exceptionContext->R12);
+ spdlog::error("R13: 0x{0:x}", exceptionContext->R13);
+ spdlog::error("R14: 0x{0:x}", exceptionContext->R14);
+ spdlog::error("R15: 0x{0:x}", exceptionContext->R15);
+
+ time_t time = std::time(nullptr);
+ tm currentTime = *std::localtime(&time);
+ std::stringstream stream;
+ stream << std::put_time(&currentTime, (GetNorthstarPrefix() + "/logs/nsdump%Y-%m-%d %H-%M-%S.dmp").c_str());
+
+ auto hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
+ if (hMinidumpFile)
+ {
+ MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo;
+ dumpExceptionInfo.ThreadId = GetCurrentThreadId();
+ dumpExceptionInfo.ExceptionPointers = exceptionInfo;
+ dumpExceptionInfo.ClientPointers = false;
+
+ MiniDumpWriteDump(
+ GetCurrentProcess(),
+ GetCurrentProcessId(),
+ hMinidumpFile,
+ MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
+ &dumpExceptionInfo,
+ nullptr,
+ nullptr);
+ CloseHandle(hMinidumpFile);
+ }
+ else
+ spdlog::error("Failed to write minidump file {}!", stream.str());
+
+ if (!IsDedicatedServer())
+ MessageBoxA(
+ 0, "Northstar has crashed! Crash info can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK);
+ }
+
+ logged = true;
+ return EXCEPTION_EXECUTE_HANDLER;
+}
+
+BOOL WINAPI ConsoleHandlerRoutine(DWORD eventCode)
+{
+ switch (eventCode)
+ {
+ case CTRL_CLOSE_EVENT:
+ // User closed console, shut everything down
+ spdlog::info("Exiting due to console close...");
+ RemoveCrashHandler();
+ exit(EXIT_SUCCESS);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void InitialiseCrashHandler()
+{
+ hExceptionFilter = AddVectoredExceptionHandler(TRUE, ExceptionFilter);
+ SetConsoleCtrlHandler(ConsoleHandlerRoutine, true);
+}
+
+void RemoveCrashHandler()
+{
+ RemoveVectoredExceptionHandler(hExceptionFilter);
+} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/crashhandler.h b/NorthstarDedicatedTest/crashhandler.h
new file mode 100644
index 00000000..510372d2
--- /dev/null
+++ b/NorthstarDedicatedTest/crashhandler.h
@@ -0,0 +1,4 @@
+#pragma once
+
+void InitialiseCrashHandler();
+void RemoveCrashHandler(); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/debugoverlay.cpp b/NorthstarDedicatedTest/debugoverlay.cpp
index 6cf7703f..e6601223 100644
--- a/NorthstarDedicatedTest/debugoverlay.cpp
+++ b/NorthstarDedicatedTest/debugoverlay.cpp
@@ -2,6 +2,8 @@
#include "dedicated.h"
#include "cvar.h"
+AUTOHOOK_INIT()
+
struct Vector3
{
float x, y, z;
@@ -83,10 +85,8 @@ typedef void (*RenderBoxType)(Vector3 vOrigin, QAngle angles, Vector3 vMins, Vec
static RenderBoxType RenderBox;
static RenderBoxType RenderWireframeBox;
-// engine.dll+0xABCB0
-typedef void (*DrawOverlayType)(OverlayBase_t* a1);
-DrawOverlayType DrawOverlay;
-void __fastcall DrawOverlayHook(OverlayBase_t* pOverlay)
+AUTOHOOK(DrawOverlay, engine.dll + 0xABCB0,
+void, __fastcall, (OverlayBase_t * pOverlay),
{
EnterCriticalSection((LPCRITICAL_SECTION)((char*)sEngineModule + 0x10DB0A38)); // s_OverlayMutex
@@ -129,12 +129,11 @@ void __fastcall DrawOverlayHook(OverlayBase_t* pOverlay)
break;
}
LeaveCriticalSection((LPCRITICAL_SECTION)((char*)sEngineModule + 0x10DB0A38));
-}
+})
ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", DebugOverlay, ConVar, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xABCB0, &DrawOverlayHook, reinterpret_cast<LPVOID*>(&DrawOverlay));
+ AUTOHOOK_DISPATCH()
RenderLine = reinterpret_cast<RenderLineType>((char*)baseAddress + 0x192A70);
diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp
index 25e6d24b..4aa1b072 100644
--- a/NorthstarDedicatedTest/dedicated.cpp
+++ b/NorthstarDedicatedTest/dedicated.cpp
@@ -8,6 +8,8 @@
#include "masterserver.h"
#include "printcommand.h"
+AUTOHOOK_INIT()
+
using namespace R2;
bool IsDedicatedServer()
@@ -92,12 +94,11 @@ void RunServer(CDedicatedExports* dedicated)
}
}
-typedef bool (*IsGameActiveWindowType)();
-IsGameActiveWindowType IsGameActiveWindow;
-bool IsGameActiveWindowHook()
+AUTOHOOK(IsGameActiveWindow, engine.dll + 0x1CDC80,
+bool,, (),
{
- return true;
-}
+ return true;
+})
HANDLE consoleInputThreadHandle = NULL;
@@ -131,6 +132,8 @@ ON_DLL_LOAD_DEDI("engine.dll", DedicatedServer, [](HMODULE engineAddress)
{
spdlog::info("InitialiseDedicated");
+ AUTOHOOK_DISPATCH_MODULE("engine.dll")
+
uintptr_t ea = (uintptr_t)engineAddress;
// Host_Init
@@ -222,9 +225,6 @@ ON_DLL_LOAD_DEDI("engine.dll", DedicatedServer, [](HMODULE engineAddress)
CDedicatedExports** exports = (CDedicatedExports**)((char*)engineAddress + 0x13F0B668);
*exports = dedicatedExports;
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)engineAddress + 0x1CDC80, &IsGameActiveWindowHook, reinterpret_cast<LPVOID*>(&IsGameActiveWindow));
-
// extra potential patches:
// nop engine.dll+1c67d1 and +1c67d8 to skip videomode creategamewindow
// also look into launcher.dll+d381, seems to cause renderthread to get made
@@ -283,16 +283,14 @@ ON_DLL_LOAD_DEDI("tier0.dll", DedicatedServerOrigin, [](HMODULE baseAddress)
});
})
-typedef void (*PrintFatalSquirrelErrorType)(void* sqvm);
-PrintFatalSquirrelErrorType PrintFatalSquirrelError;
-void PrintFatalSquirrelErrorHook(void* sqvm)
+AUTOHOOK(PrintFatalSquirrelError, server.dll + 0x794D0,
+void, , (void* sqvm),
{
PrintFatalSquirrelError(sqvm);
g_pEngine->m_nQuitting = EngineQuitState::QUIT_TODESKTOP;
-}
+})
ON_DLL_LOAD_DEDI("server.dll", DedicatedServerGameDLL, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, baseAddress + 0x794D0, &PrintFatalSquirrelErrorHook, reinterpret_cast<LPVOID*>(&PrintFatalSquirrelError));
+ AUTOHOOK_DISPATCH_MODULE("server.dll")
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
index d01d381f..3f1bf323 100644
--- a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
+++ b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
@@ -4,20 +4,10 @@
#include "tier0.h"
#include "NSMem.h"
-typedef HRESULT (*__stdcall D3D11CreateDeviceType)(
- void* pAdapter,
- int DriverType,
- HMODULE Software,
- UINT Flags,
- int* pFeatureLevels,
- UINT FeatureLevels,
- UINT SDKVersion,
- void** ppDevice,
- int* pFeatureLevel,
- void** ppImmediateContext);
-D3D11CreateDeviceType D3D11CreateDevice;
+AUTOHOOK_INIT()
-HRESULT __stdcall D3D11CreateDeviceHook(
+AUTOHOOK(D3D11CreateDevice, materialsystem_dx11.dll + 0xD9A0E,
+HRESULT, __stdcall, (
void* pAdapter,
int DriverType,
HMODULE Software,
@@ -27,7 +17,7 @@ HRESULT __stdcall D3D11CreateDeviceHook(
UINT SDKVersion,
void** ppDevice,
int* pFeatureLevel,
- void** ppImmediateContext)
+ void** ppImmediateContext),
{
// note: this is super duper temp pretty much just messing around with it
// does run surprisingly well on dedi for a software driver tho if you ignore the +1gb ram usage at times, seems like dedi doesn't
@@ -41,41 +31,13 @@ HRESULT __stdcall D3D11CreateDeviceHook(
return D3D11CreateDevice(
pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, ppDevice, pFeatureLevel, ppImmediateContext);
-}
+})
ON_DLL_LOAD_DEDI("materialsystem_dx11.dll", DedicatedServerMaterialSystem, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xD9A0E, &D3D11CreateDeviceHook, reinterpret_cast<LPVOID*>(&D3D11CreateDevice));
-
- // not using these for now since they're related to nopping renderthread/gamewindow i.e. very hard
- //{
- // // function that launches renderthread
- // char* ptr = (char*)baseAddress + 0x87047;
- // TempReadWrite rw(ptr);
- //
- // // make it not launch renderthread
- // *ptr = (char)0x90;
- // *(ptr + 1) = (char)0x90;
- // *(ptr + 2) = (char)0x90;
- // *(ptr + 3) = (char)0x90;
- // *(ptr + 4) = (char)0x90;
- // *(ptr + 5) = (char)0x90;
- //}
- //
- //{
- // // some function that waits on renderthread job
- // char* ptr = (char*)baseAddress + 0x87d00;
- // TempReadWrite rw(ptr);
- //
- // // return immediately
- // *ptr = (char)0xC3;
- //}
+ AUTOHOOK_DISPATCH()
// CMaterialSystem::FindMaterial
// make the game always use the error material
NSMem::BytePatch((uintptr_t)baseAddress + 0x5F0F1, {0xE9, 0x34, 0x03, 0x00});
-
- // previously had DisableDedicatedWindowCreation stuff here, removing for now since shit and unstable
- // check commit history if needed
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/demofixes.cpp b/NorthstarDedicatedTest/demofixes.cpp
index fba94183..ff06ae12 100644
--- a/NorthstarDedicatedTest/demofixes.cpp
+++ b/NorthstarDedicatedTest/demofixes.cpp
@@ -2,12 +2,15 @@
#include "convar.h"
#include "NSMem.h"
-ON_DLL_LOAD_CLIENT_RELIESON("client.dll", DemoFixes, ConVar, [](HMODULE baseAddress)
+ON_DLL_LOAD_CLIENT("engine.dll", EngineDemoFixes, [](HMODULE baseAddress)
{
// allow demo recording on loopback
- NSMem::NOP((uintptr_t)GetModuleHandleA("engine.dll") + 0x8E1B1, 2);
- NSMem::NOP((uintptr_t)GetModuleHandleA("engine.dll") + 0x56CC3, 2);
+ NSMem::NOP((uintptr_t)baseAddress + 0x8E1B1, 2);
+ NSMem::NOP((uintptr_t)baseAddress + 0x56CC3, 2);
+})
+ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientDemoFixes, ConVar, [](HMODULE baseAddress)
+{
// change default values of demo cvars to enable them by default, but not autorecord
// this is before Host_Init, the setvalue calls here will get overwritten by custom cfgs/launch options
ConVar* Cvar_demo_enableDemos = R2::g_pCVar->FindVar("demo_enabledemos");
diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp
index 718e9413..e27cd529 100644
--- a/NorthstarDedicatedTest/dllmain.cpp
+++ b/NorthstarDedicatedTest/dllmain.cpp
@@ -1,6 +1,7 @@
#include "pch.h"
#include "main.h"
#include "logging.h"
+#include "crashhandler.h"
#include "memalloc.h"
#include "configurables.h"
#include "plugin_abi.h"
@@ -153,6 +154,7 @@ bool InitialiseNorthstar()
curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base);
+ InitialiseCrashHandler();
InitialiseLogging();
InstallInitialHooks();
CreateLogFiles();
diff --git a/NorthstarDedicatedTest/filesystem.cpp b/NorthstarDedicatedTest/filesystem.cpp
index f55fca82..a879b40e 100644
--- a/NorthstarDedicatedTest/filesystem.cpp
+++ b/NorthstarDedicatedTest/filesystem.cpp
@@ -6,6 +6,8 @@
#include <iostream>
#include <sstream>
+AUTOHOOK_INIT()
+
using namespace R2;
bool bReadingOriginalFile = false;
@@ -47,9 +49,8 @@ namespace R2
}
} // namespace R2
-typedef void (*AddSearchPathType)(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType);
-AddSearchPathType AddSearchPath;
-void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType)
+HOOK(AddSearchPathHook, AddSearchPath,
+void,, (IFileSystem* fileSystem, const char* pPath, const char* pathID, SearchPathAdd_t addType),
{
AddSearchPath(fileSystem, pPath, pathID, addType);
@@ -59,7 +60,7 @@ void AddSearchPathHook(IFileSystem* fileSystem, const char* pPath, const char* p
AddSearchPath(fileSystem, sCurrentModPath.c_str(), "GAME", PATH_ADD_TO_HEAD);
AddSearchPath(fileSystem, GetCompiledAssetsPath().string().c_str(), "GAME", PATH_ADD_TO_HEAD);
}
-}
+})
void SetNewModSearchPaths(Mod* mod)
{
@@ -101,20 +102,18 @@ bool TryReplaceFile(const char* pPath, bool shouldCompile)
}
// force modded files to be read from mods, not cache
-typedef bool (*ReadFromCacheType)(IFileSystem* filesystem, char* path, void* result);
-ReadFromCacheType ReadFromCache;
-bool ReadFromCacheHook(IFileSystem* filesystem, char* pPath, void* result)
+HOOK(ReadFromCacheHook, ReadFromCache,
+bool,, (IFileSystem* filesystem, char* pPath, void* result),
{
if (TryReplaceFile(pPath, true))
return false;
return ReadFromCache(filesystem, pPath, result);
-}
+})
// force modded files to be read from mods, not vpk
-typedef FileHandle_t (*ReadFileFromVPKType)(VPKData* vpkInfo, __int64* b, char* filename);
-ReadFileFromVPKType ReadFileFromVPK;
-FileHandle_t ReadFileFromVPKHook(VPKData* vpkInfo, __int64* b, char* filename)
+AUTOHOOK(ReadFileFromVPK, filesystem_stdio.dll + 0x5CBA0,
+FileHandle_t,, (VPKData* vpkInfo, __int64* b, char* filename),
{
// don't compile here because this is only ever called from OpenEx, which already compiles
if (TryReplaceFile(filename, false))
@@ -124,23 +123,20 @@ FileHandle_t ReadFileFromVPKHook(VPKData* vpkInfo, __int64* b, char* filename)
}
return ReadFileFromVPK(vpkInfo, b, filename);
-}
+})
-typedef FileHandle_t (*CBaseFileSystem__OpenExType)(
- IFileSystem* filesystem, const char* pPath, const char* pOptions, uint32_t flags, const char* pPathID, char** ppszResolvedFilename);
-CBaseFileSystem__OpenExType CBaseFileSystem__OpenEx;
-FileHandle_t CBaseFileSystem__OpenExHook(IFileSystem* filesystem, const char* pPath, const char* pOptions, uint32_t flags, const char* pPathID, char **ppszResolvedFilename)
+AUTOHOOK(CBaseFileSystem__OpenEx, filesystem_stdio.dll + 0x15F50,
+FileHandle_t,, (IFileSystem* filesystem, const char* pPath, const char* pOptions, uint32_t flags, const char* pPathID, char **ppszResolvedFilename),
{
TryReplaceFile(pPath, true);
return CBaseFileSystem__OpenEx(filesystem, pPath, pOptions, flags, pPathID, ppszResolvedFilename);
-}
+})
-typedef VPKData* (*MountVPKType)(IFileSystem* fileSystem, const char* vpkPath);
-MountVPKType MountVPK;
-VPKData* MountVPKHook(IFileSystem* fileSystem, const char* vpkPath)
+HOOK(MountVPKHook, MountVPK,
+VPKData*,, (IFileSystem * fileSystem, const char* pVpkPath),
{
- spdlog::info("MountVPK {}", vpkPath);
- VPKData* ret = MountVPK(fileSystem, vpkPath);
+ spdlog::info("MountVPK {}", pVpkPath);
+ VPKData* ret = MountVPK(fileSystem, pVpkPath);
for (Mod mod : g_pModManager->m_loadedMods)
{
@@ -154,7 +150,7 @@ VPKData* MountVPKHook(IFileSystem* fileSystem, const char* vpkPath)
{
// resolve vpk name and try to load one with the same name
// todo: we should be unloading these on map unload manually
- std::string mapName(fs::path(vpkPath).filename().string());
+ std::string mapName(fs::path(pVpkPath).filename().string());
std::string modMapName(fs::path(vpkEntry.m_sVpkPath.c_str()).filename().string());
if (mapName.compare(modMapName))
continue;
@@ -167,18 +163,15 @@ VPKData* MountVPKHook(IFileSystem* fileSystem, const char* vpkPath)
}
return ret;
-}
+})
ON_DLL_LOAD("filesystem_stdio.dll", Filesystem, [](HMODULE baseAddress)
{
+ AUTOHOOK_DISPATCH()
+
R2::g_pFilesystem = new SourceInterface<IFileSystem>("filesystem_stdio.dll", "VFileSystem017");
- // create hooks
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (*g_pFilesystem)->m_vtable->ReadFromCache, &ReadFromCacheHook, reinterpret_cast<LPVOID*>(&ReadFromCache));
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x5CBA0, &ReadFileFromVPKHook, reinterpret_cast<LPVOID*>(&ReadFileFromVPK));
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x15F50, &CBaseFileSystem__OpenExHook, reinterpret_cast<LPVOID*>(&CBaseFileSystem__OpenEx));
- ENABLER_CREATEHOOK(hook, (*g_pFilesystem)->m_vtable->AddSearchPath, &AddSearchPathHook, reinterpret_cast<LPVOID*>(&AddSearchPath));
- ENABLER_CREATEHOOK(hook, (*g_pFilesystem)->m_vtable->MountVPK, &MountVPKHook, reinterpret_cast<LPVOID*>(&MountVPK));
+ AddSearchPathHook.Dispatch((*g_pFilesystem)->m_vtable->AddSearchPath);
+ ReadFromCacheHook.Dispatch((*g_pFilesystem)->m_vtable->ReadFromCache);
+ MountVPKHook.Dispatch((*g_pFilesystem)->m_vtable->MountVPK);
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp
index d4608f85..2b117178 100644
--- a/NorthstarDedicatedTest/hooks.cpp
+++ b/NorthstarDedicatedTest/hooks.cpp
@@ -46,15 +46,37 @@ void __fileAutohook::Dispatch()
hook->Dispatch();
}
-ManualHook::ManualHook(const char* funcName, LPVOID* orig, LPVOID func) : pHookFunc(func), ppOrigFunc(orig)
+void __fileAutohook::DispatchForModule(const char* pModuleName)
+{
+ const int iModuleNameLen = strlen(pModuleName);
+
+ for (__autohook* hook : hooks)
+ if ((hook->iAddressResolutionMode == __autohook::OFFSET_STRING && !strncmp(pModuleName, hook->pAddrString, iModuleNameLen)) ||
+ (hook->iAddressResolutionMode == __autohook::PROCADDRESS && !strcmp(pModuleName, hook->pModuleName)))
+ hook->Dispatch();
+}
+
+ManualHook::ManualHook(const char* funcName, LPVOID func)
+ : pHookFunc(func), ppOrigFunc(nullptr)
+{
+ const int iFuncNameStrlen = strlen(funcName);
+ pFuncName = new char[iFuncNameStrlen];
+ memcpy(pFuncName, funcName, iFuncNameStrlen);
+}
+
+ManualHook::ManualHook(const char* funcName, LPVOID* orig, LPVOID func)
+ : pHookFunc(func), ppOrigFunc(orig)
{
const int iFuncNameStrlen = strlen(funcName);
pFuncName = new char[iFuncNameStrlen];
memcpy(pFuncName, funcName, iFuncNameStrlen);
}
-bool ManualHook::Dispatch(LPVOID addr)
+bool ManualHook::Dispatch(LPVOID addr, LPVOID* orig)
{
+ if (orig)
+ ppOrigFunc = orig;
+
if (MH_CreateHook(addr, pHookFunc, ppOrigFunc) == MH_OK)
{
if (MH_EnableHook(addr) == MH_OK)
@@ -118,16 +140,15 @@ void AddDllLoadCallbackForClient(std::string dll, DllLoadCallbackFuncType callba
AddDllLoadCallback(dll, callback, tag, reliesOn);
}
-typedef LPSTR (*GetCommandLineAType)();
-GetCommandLineAType GetCommandLineAOriginal;
-LPSTR GetCommandLineAHook()
+AUTOHOOK_ABSOLUTEADDR(_GetCommandLineA, GetCommandLineA,
+LPSTR, WINAPI, (),
{
static char* cmdlineModified;
static char* cmdlineOrg;
if (cmdlineOrg == nullptr || cmdlineModified == nullptr)
{
- cmdlineOrg = GetCommandLineAOriginal();
+ cmdlineOrg = _GetCommandLineA();
bool isDedi = strstr(cmdlineOrg, "-dedicated"); // well, this one has to be a real argument
bool ignoreStartupArgs = strstr(cmdlineOrg, "-nostartupargs");
@@ -181,7 +202,7 @@ LPSTR GetCommandLineAHook()
}
return cmdlineModified;
-}
+})
std::vector<std::string> calledTags;
void CallLoadLibraryACallbacks(LPCSTR lpLibFileName, HMODULE moduleAddress)
diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h
index 36c99b39..ba1bca3b 100644
--- a/NorthstarDedicatedTest/hooks.h
+++ b/NorthstarDedicatedTest/hooks.h
@@ -58,6 +58,7 @@ class __fileAutohook
std::vector<__autohook*> hooks;
void Dispatch();
+ void DispatchForModule(const char* pModuleName);
};
// initialise autohooks for this file
@@ -68,6 +69,9 @@ namespace { __fileAutohook __FILEAUTOHOOK; } \
#define AUTOHOOK_DISPATCH() \
__FILEAUTOHOOK.Dispatch(); \
+#define AUTOHOOK_DISPATCH_MODULE(moduleName) \
+__FILEAUTOHOOK.DispatchForModule(__STR(moduleName)); \
+
class __autohook
{
public:
@@ -75,6 +79,7 @@ class __autohook
{
OFFSET_STRING, // we're using a string that of the format dllname.dll + offset
ABSOLUTE_ADDR, // we're using an absolute address, we don't need to process it at all
+ PROCADDRESS // resolve using GetModuleHandle and GetProcAddress
};
char* pFuncName;
@@ -86,6 +91,8 @@ class __autohook
AddressResolutionMode iAddressResolutionMode;
char* pAddrString = nullptr; // for OFFSET_STRING
LPVOID iAbsoluteAddress = nullptr; // for ABSOLUTE_ADDR
+ char* pModuleName; // for PROCADDRESS
+ char* pProcName; // for PROCADDRESS
public:
__autohook() = delete;
@@ -118,12 +125,38 @@ class __autohook
autohook->hooks.push_back(this);
}
+ __autohook(__fileAutohook* autohook, const char* funcName, const char* moduleName, const char* procName, LPVOID* orig, LPVOID func)
+ : pHookFunc(func), ppOrigFunc(orig)
+ {
+ iAddressResolutionMode = PROCADDRESS;
+
+ const int iFuncNameStrlen = strlen(funcName) + 1;
+ pFuncName = new char[iFuncNameStrlen];
+ memcpy(pFuncName, funcName, iFuncNameStrlen);
+
+ const int iModuleNameStrlen = strlen(moduleName) + 1;
+ pModuleName = new char[iModuleNameStrlen];
+ memcpy(pModuleName, moduleName, iModuleNameStrlen);
+
+ const int iProcNameStrlen = strlen(procName) + 1;
+ pProcName = new char[iProcNameStrlen];
+ memcpy(pProcName, procName, iProcNameStrlen);
+
+ autohook->hooks.push_back(this);
+ }
+
~__autohook()
{
delete[] pFuncName;
if (pAddrString)
delete[] pAddrString;
+
+ if (pModuleName)
+ delete[] pModuleName;
+
+ if (pProcName)
+ delete[] pProcName;
}
void Dispatch()
@@ -170,7 +203,13 @@ class __autohook
else
iOffset = std::stoi(pAddrString + iOffsetBegin);
- targetAddr = (char*)pModuleAddr + iOffset;
+ targetAddr = (LPVOID)((uintptr_t)pModuleAddr + iOffset);
+ break;
+ }
+
+ case PROCADDRESS:
+ {
+ targetAddr = GetProcAddress(GetModuleHandleA(pModuleName), pProcName);
break;
}
}
@@ -203,6 +242,14 @@ namespace { \
__autohook CONCAT2(__autohook, __LINE__)(&__FILEAUTOHOOK, __STR(name), addr, (LPVOID*)&name, (LPVOID)CONCAT2(__autohookfunc, name)); \
} \
+// hook a function at a given module and exported function to be dispatched with AUTOHOOK_DISPATCH()
+#define AUTOHOOK_PROCADDRESS(name, moduleName, procName, type, callingConvention, args, func) \
+namespace { \
+ type(*callingConvention name) args; \
+ type callingConvention CONCAT2(__autohookfunc, name) args func \
+ __autohook CONCAT2(__autohook, __LINE__)(&__FILEAUTOHOOK, __STR(name), __STR(moduleName), __STR(procName), (LPVOID*)&name, (LPVOID)CONCAT2(__autohookfunc, name)); \
+} \
+
class ManualHook
{
public:
@@ -213,8 +260,9 @@ class ManualHook
public:
ManualHook() = delete;
+ ManualHook(const char* funcName, LPVOID func);
ManualHook(const char* funcName, LPVOID* orig, LPVOID func);
- bool Dispatch(LPVOID addr);
+ bool Dispatch(LPVOID addr, LPVOID* orig = nullptr);
};
// hook a function to be dispatched manually later
@@ -223,4 +271,10 @@ namespace { \
type(*callingConvention originalFunc) args; \
type callingConvention CONCAT2(__manualhookfunc, varName) args func \
} \
-ManualHook<type(*callingConvention)args> varName = ManualHook<type(*callingConvention)args>(varName, (LPVOID*)&originalFunc, (LPVOID)CONCAT2(__manualhookfunc, varName)); \
+ManualHook varName = ManualHook(__STR(varName), (LPVOID*)&originalFunc, (LPVOID)CONCAT2(__manualhookfunc, varName)); \
+
+#define HOOK_NOORIG(varName, type, callingConvention, args, func) \
+namespace { \
+ type callingConvention CONCAT2(__manualhookfunc, varName) args func \
+} \
+ManualHook varName = ManualHook(__STR(varName), (LPVOID)CONCAT2(__manualhookfunc, varName)); \ \ No newline at end of file
diff --git a/NorthstarDedicatedTest/host.cpp b/NorthstarDedicatedTest/host.cpp
index fcc148b0..5221395a 100644
--- a/NorthstarDedicatedTest/host.cpp
+++ b/NorthstarDedicatedTest/host.cpp
@@ -5,9 +5,10 @@
#include "printmaps.h"
#include "r2engine.h"
-typedef void (*Host_InitType)(bool bDedicated);
-Host_InitType Host_Init;
-void Host_InitHook(bool bDedicated)
+AUTOHOOK_INIT()
+
+AUTOHOOK(Host_Init, engine.dll + 0x155EA0,
+void,, (bool bDedicated),
{
spdlog::info("Host_Init()");
Host_Init(bDedicated);
@@ -62,10 +63,9 @@ void Host_InitHook(bool bDedicated)
R2::Cbuf_AddText(R2::Cbuf_GetCurrentPlayer(), "exec autoexec_ns_server", R2::cmd_source_t::kCommandSrcCode);
else
R2::Cbuf_AddText(R2::Cbuf_GetCurrentPlayer(), "exec autoexec_ns_client", R2::cmd_source_t::kCommandSrcCode);
-}
+})
ON_DLL_LOAD("engine.dll", Host_Init, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x155EA0, &Host_InitHook, reinterpret_cast<LPVOID*>(&Host_Init));
+ AUTOHOOK_DISPATCH()
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/hoststate.cpp b/NorthstarDedicatedTest/hoststate.cpp
index 63d313f8..c3663a42 100644
--- a/NorthstarDedicatedTest/hoststate.cpp
+++ b/NorthstarDedicatedTest/hoststate.cpp
@@ -6,6 +6,8 @@
#include "tier0.h"
#include "r2engine.h"
+AUTOHOOK_INIT()
+
using namespace R2;
// use the R2 namespace for game funcs
@@ -14,9 +16,8 @@ namespace R2
CHostState* g_pHostState;
} // namespace R2
-typedef void (*CHostState__State_NewGameType)(CHostState* hostState);
-CHostState__State_NewGameType CHostState__State_NewGame;
-void CHostState__State_NewGameHook(CHostState* hostState)
+AUTOHOOK(CHostState__State_NewGame, engine.dll + 0x16E7D0,
+void,, (CHostState* hostState),
{
spdlog::info("HostState: NewGame");
@@ -55,11 +56,10 @@ void CHostState__State_NewGameHook(CHostState* hostState)
Cvar_ns_server_password->GetString());
g_ServerAuthenticationManager->StartPlayerAuthServer();
g_ServerAuthenticationManager->m_bNeedLocalAuthForNewgame = false;
-}
+})
-typedef void (*CHostState__State_ChangeLevelMPType)(CHostState* hostState);
-CHostState__State_ChangeLevelMPType CHostState__State_ChangeLevelMP;
-void CHostState__State_ChangeLevelMPHook(CHostState* hostState)
+AUTOHOOK(CHostState__State_ChangeLevelMP, engine.dll + 0x16E520,
+void,, (CHostState* hostState),
{
spdlog::info("HostState: ChangeLevelMP");
@@ -78,11 +78,10 @@ void CHostState__State_ChangeLevelMPHook(CHostState* hostState)
double dStartTime = Tier0::Plat_FloatTime();
CHostState__State_ChangeLevelMP(hostState);
spdlog::info("loading took {}s", Tier0::Plat_FloatTime() - dStartTime);
-}
+})
-typedef void (*CHostState__State_GameShutdownType)(CHostState* hostState);
-CHostState__State_GameShutdownType CHostState__State_GameShutdown;
-void CHostState__State_GameShutdownHook(CHostState* hostState)
+AUTOHOOK(CHostState__State_GameShutdown, engine.dll + 0x16E520,
+void,, (CHostState* hostState),
{
spdlog::info("HostState: GameShutdown");
@@ -90,17 +89,11 @@ void CHostState__State_GameShutdownHook(CHostState* hostState)
g_ServerAuthenticationManager->StopPlayerAuthServer();
CHostState__State_GameShutdown(hostState);
-}
+})
ON_DLL_LOAD_RELIESON("engine.dll", HostState, ConVar, [](HMODULE baseAddress)
{
- g_pHostState = (CHostState*)((char*)baseAddress + 0x7CF180);
+ AUTOHOOK_DISPATCH()
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x16E7D0, CHostState__State_NewGameHook, reinterpret_cast<LPVOID*>(&CHostState__State_NewGame));
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x16E520, CHostState__State_ChangeLevelMPHook, reinterpret_cast<LPVOID*>(&CHostState__State_ChangeLevelMP));
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x16E640, CHostState__State_GameShutdownHook, reinterpret_cast<LPVOID*>(&CHostState__State_GameShutdown));
+ g_pHostState = (CHostState*)((char*)baseAddress + 0x7CF180);
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/keyvalues.cpp b/NorthstarDedicatedTest/keyvalues.cpp
index 4ba11dad..1b711976 100644
--- a/NorthstarDedicatedTest/keyvalues.cpp
+++ b/NorthstarDedicatedTest/keyvalues.cpp
@@ -4,23 +4,7 @@
#include <fstream>
-typedef char (*KeyValues__LoadFromBufferType)(
- void* self, const char* resourceName, const char* pBuffer, void* pFileSystem, void* a5, void* a6, int a7);
-KeyValues__LoadFromBufferType KeyValues__LoadFromBuffer;
-char KeyValues__LoadFromBufferHook(void* self, const char* resourceName, const char* pBuffer, void* pFileSystem, void* a5, void* a6, int a7)
-{
- static void* pSavedFilesystemPtr = nullptr;
-
- // this is just to allow playlists to get a valid pFileSystem ptr for kv building, other functions that call this particular overload of
- // LoadFromBuffer seem to get called on network stuff exclusively not exactly sure what the address wanted here is, so just taking it
- // from a function call that always happens before playlists is loaded
- if (pFileSystem != nullptr)
- pSavedFilesystemPtr = pFileSystem;
- if (!pFileSystem && !strcmp(resourceName, "playlists"))
- pFileSystem = pSavedFilesystemPtr;
-
- return KeyValues__LoadFromBuffer(self, resourceName, pBuffer, pFileSystem, a5, a6, a7);
-}
+AUTOHOOK_INIT()
void ModManager::TryBuildKeyValues(const char* filename)
{
@@ -122,9 +106,23 @@ void ModManager::TryBuildKeyValues(const char* filename)
m_modFiles[normalisedPath] = overrideFile;
}
+AUTOHOOK(KeyValues__LoadFromBuffer, engine.dll + 0x426C30,
+char,, (void* self, const char* resourceName, const char* pBuffer, void* pFileSystem, void* a5, void* a6, int a7),
+{
+ static void* pSavedFilesystemPtr = nullptr;
+
+ // this is just to allow playlists to get a valid pFileSystem ptr for kv building, other functions that call this particular overload of
+ // LoadFromBuffer seem to get called on network stuff exclusively not exactly sure what the address wanted here is, so just taking it
+ // from a function call that always happens before playlists is loaded
+ if (pFileSystem != nullptr)
+ pSavedFilesystemPtr = pFileSystem;
+ if (!pFileSystem && !strcmp(resourceName, "playlists"))
+ pFileSystem = pSavedFilesystemPtr;
+
+ return KeyValues__LoadFromBuffer(self, resourceName, pBuffer, pFileSystem, a5, a6, a7);
+})
+
ON_DLL_LOAD("engine.dll", KeyValues, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x426C30, &KeyValues__LoadFromBufferHook, reinterpret_cast<LPVOID*>(&KeyValues__LoadFromBuffer));
+ AUTOHOOK_DISPATCH()
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/languagehooks.cpp b/NorthstarDedicatedTest/languagehooks.cpp
index ac421077..4e708517 100644
--- a/NorthstarDedicatedTest/languagehooks.cpp
+++ b/NorthstarDedicatedTest/languagehooks.cpp
@@ -4,15 +4,12 @@
#include <filesystem>
#include <regex>
-namespace fs = std::filesystem;
+AUTOHOOK_INIT()
-typedef char* (*GetGameLanguageType)();
-char* GetGameLanguage();
+namespace fs = std::filesystem;
typedef LANGID (*Tier0_DetectDefaultLanguageType)();
-GetGameLanguageType GetGameLanguageOriginal;
-
bool CheckLangAudioExists(char* lang)
{
std::string path {"r2\\sound\\general_"};
@@ -52,7 +49,8 @@ std::string GetAnyInstalledAudioLanguage()
return "NO LANGUAGE DETECTED";
}
-char* GetGameLanguageHook()
+AUTOHOOK(GetGameLanguage, tier0.dll + 0xF560,
+char*,, (),
{
auto tier0Handle = GetModuleHandleA("tier0.dll");
auto Tier0_DetectDefaultLanguageType = GetProcAddress(tier0Handle, "Tier0_DetectDefaultLanguage");
@@ -79,7 +77,7 @@ char* GetGameLanguageHook()
canOriginDictateLang = true; // let it try
{
- auto lang = GetGameLanguageOriginal();
+ auto lang = GetGameLanguage();
if (!CheckLangAudioExists(lang))
{
if (strcmp(lang, "russian") !=
@@ -97,7 +95,7 @@ char* GetGameLanguageHook()
Tier0_DetectDefaultLanguageType(); // force the global in tier0 to be populated with language inferred from user's system rather than
// defaulting to Russian
canOriginDictateLang = false; // Origin has no say anymore, we will fallback to user's system setup language
- auto lang = GetGameLanguageOriginal();
+ auto lang = GetGameLanguage();
spdlog::info("Detected system language: {}", lang);
if (!CheckLangAudioExists(lang))
{
@@ -110,10 +108,9 @@ char* GetGameLanguageHook()
}
return lang;
-}
+})
ON_DLL_LOAD_CLIENT("tier0.dll", LanguageHooks, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xF560, &GetGameLanguageHook, reinterpret_cast<LPVOID*>(&GetGameLanguageOriginal));
+ AUTOHOOK_DISPATCH()
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/latencyflex.cpp b/NorthstarDedicatedTest/latencyflex.cpp
index 87057a00..8c302df8 100644
--- a/NorthstarDedicatedTest/latencyflex.cpp
+++ b/NorthstarDedicatedTest/latencyflex.cpp
@@ -1,21 +1,22 @@
#include "pch.h"
#include "convar.h"
+AUTOHOOK_INIT()
+
ConVar* Cvar_r_latencyflex;
HMODULE m_lfxModule {};
typedef void (*PFN_winelfx_WaitAndBeginFrame)();
PFN_winelfx_WaitAndBeginFrame m_winelfx_WaitAndBeginFrame {};
-typedef void (*OnRenderStartType)();
-OnRenderStartType OnRenderStart;
-void OnRenderStartHook()
+AUTOHOOK(OnRenderStart, client.dll + 0x1952C0,
+void,, (),
{
if (Cvar_r_latencyflex->GetInt())
m_winelfx_WaitAndBeginFrame();
OnRenderStart();
-}
+})
ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, [](HMODULE baseAddress)
{
@@ -30,12 +31,11 @@ ON_DLL_LOAD_CLIENT_RELIESON("client.dll", LatencyFlex, ConVar, [](HMODULE baseAd
return;
}
+ AUTOHOOK_DISPATCH()
+
m_winelfx_WaitAndBeginFrame =
reinterpret_cast<PFN_winelfx_WaitAndBeginFrame>(reinterpret_cast<void*>(GetProcAddress(m_lfxModule, "winelfx_WaitAndBeginFrame")));
spdlog::info("LatencyFleX initialized.");
Cvar_r_latencyflex = new ConVar("r_latencyflex", "1", FCVAR_ARCHIVE, "Whether or not to use LatencyFleX input latency reduction.");
-
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x1952C0, &OnRenderStartHook, reinterpret_cast<LPVOID*>(&OnRenderStart));
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp
index 909d34ce..0f0d76fe 100644
--- a/NorthstarDedicatedTest/logging.cpp
+++ b/NorthstarDedicatedTest/logging.cpp
@@ -1,250 +1,19 @@
#include "pch.h"
#include "logging.h"
-#include "sourceconsole.h"
-#include "spdlog/sinks/basic_file_sink.h"
-#include "dedicated.h"
#include "convar.h"
+#include "configurables.h"
+#include "bitbuf.h"
+#include "spdlog/sinks/basic_file_sink.h"
+
#include <iomanip>
#include <sstream>
#include <Psapi.h>
-#include <minidumpapiset.h>
-#include "configurables.h"
-
-// This needs to be called after hooks are loaded so we can access the command line args
-void CreateLogFiles()
-{
- if (strstr(GetCommandLineA(), "-disablelogs"))
- {
- spdlog::default_logger()->set_level(spdlog::level::off);
- }
- else
- {
- // todo: might be good to delete logs that are too old
- time_t time = std::time(nullptr);
- tm currentTime = *std::localtime(&time);
- std::stringstream stream;
-
- stream << std::put_time(&currentTime, (GetNorthstarPrefix() + "/logs/nslog%Y-%m-%d %H-%M-%S.txt").c_str());
- spdlog::default_logger()->sinks().push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(stream.str(), false));
- spdlog::flush_on(spdlog::level::info);
- }
-}
-
-long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo)
-{
- static bool logged = false;
- if (logged)
- return EXCEPTION_CONTINUE_SEARCH;
-
- if (!IsDebuggerPresent())
- {
- const DWORD exceptionCode = exceptionInfo->ExceptionRecord->ExceptionCode;
- if (exceptionCode != EXCEPTION_ACCESS_VIOLATION && exceptionCode != EXCEPTION_ARRAY_BOUNDS_EXCEEDED &&
- exceptionCode != EXCEPTION_DATATYPE_MISALIGNMENT && exceptionCode != EXCEPTION_FLT_DENORMAL_OPERAND &&
- exceptionCode != EXCEPTION_FLT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_FLT_INEXACT_RESULT &&
- exceptionCode != EXCEPTION_FLT_INVALID_OPERATION && exceptionCode != EXCEPTION_FLT_OVERFLOW &&
- exceptionCode != EXCEPTION_FLT_STACK_CHECK && exceptionCode != EXCEPTION_FLT_UNDERFLOW &&
- exceptionCode != EXCEPTION_ILLEGAL_INSTRUCTION && exceptionCode != EXCEPTION_IN_PAGE_ERROR &&
- exceptionCode != EXCEPTION_INT_DIVIDE_BY_ZERO && exceptionCode != EXCEPTION_INT_OVERFLOW &&
- exceptionCode != EXCEPTION_INVALID_DISPOSITION && exceptionCode != EXCEPTION_NONCONTINUABLE_EXCEPTION &&
- exceptionCode != EXCEPTION_PRIV_INSTRUCTION && exceptionCode != EXCEPTION_STACK_OVERFLOW)
- return EXCEPTION_CONTINUE_SEARCH;
-
- std::stringstream exceptionCause;
- exceptionCause << "Cause: ";
- switch (exceptionCode)
- {
- case EXCEPTION_ACCESS_VIOLATION:
- case EXCEPTION_IN_PAGE_ERROR:
- {
- exceptionCause << "Access Violation" << std::endl;
-
- auto exceptionInfo0 = exceptionInfo->ExceptionRecord->ExceptionInformation[0];
- auto exceptionInfo1 = exceptionInfo->ExceptionRecord->ExceptionInformation[1];
-
- if (!exceptionInfo0)
- exceptionCause << "Attempted to read from: 0x" << (void*)exceptionInfo1;
- 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;
- else
- exceptionCause << "Unknown access violation at: 0x" << (void*)exceptionInfo1;
-
- break;
- }
- case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
- exceptionCause << "Array bounds exceeded";
- break;
- case EXCEPTION_DATATYPE_MISALIGNMENT:
- exceptionCause << "Datatype misalignment";
- break;
- case EXCEPTION_FLT_DENORMAL_OPERAND:
- exceptionCause << "Denormal operand";
- break;
- case EXCEPTION_FLT_DIVIDE_BY_ZERO:
- exceptionCause << "Divide by zero (float)";
- break;
- case EXCEPTION_INT_DIVIDE_BY_ZERO:
- exceptionCause << "Divide by zero (int)";
- break;
- case EXCEPTION_FLT_INEXACT_RESULT:
- exceptionCause << "Inexact result";
- break;
- case EXCEPTION_FLT_INVALID_OPERATION:
- exceptionCause << "Invalid operation";
- break;
- case EXCEPTION_FLT_OVERFLOW:
- case EXCEPTION_INT_OVERFLOW:
- exceptionCause << "Numeric overflow";
- break;
- case EXCEPTION_FLT_UNDERFLOW:
- exceptionCause << "Numeric underflow";
- break;
- case EXCEPTION_FLT_STACK_CHECK:
- exceptionCause << "Stack check";
- break;
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- exceptionCause << "Illegal instruction";
- break;
- case EXCEPTION_INVALID_DISPOSITION:
- exceptionCause << "Invalid disposition";
- break;
- case EXCEPTION_NONCONTINUABLE_EXCEPTION:
- exceptionCause << "Noncontinuable exception";
- break;
- case EXCEPTION_PRIV_INSTRUCTION:
- exceptionCause << "Priviledged instruction";
- break;
- case EXCEPTION_STACK_OVERFLOW:
- exceptionCause << "Stack overflow";
- break;
- default:
- exceptionCause << "Unknown";
- break;
- }
-
- void* exceptionAddress = exceptionInfo->ExceptionRecord->ExceptionAddress;
-
- HMODULE crashedModuleHandle;
- GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(exceptionAddress), &crashedModuleHandle);
-
- MODULEINFO crashedModuleInfo;
- GetModuleInformation(GetCurrentProcess(), crashedModuleHandle, &crashedModuleInfo, sizeof(crashedModuleInfo));
- char crashedModuleFullName[MAX_PATH];
- GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH);
- char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1;
-
- DWORD64 crashedModuleOffset = ((DWORD64)exceptionAddress) - ((DWORD64)crashedModuleInfo.lpBaseOfDll);
- CONTEXT* exceptionContext = exceptionInfo->ContextRecord;
-
- spdlog::error("Northstar has crashed! a minidump has been written and exception info is available below:");
- spdlog::error(exceptionCause.str());
- spdlog::error("At: {} + {}", crashedModuleName, (void*)crashedModuleOffset);
-
- PVOID framesToCapture[62];
- int frames = RtlCaptureStackBackTrace(0, 62, framesToCapture, NULL);
- for (int i = 0; i < frames; i++)
- {
- HMODULE backtraceModuleHandle;
- GetModuleHandleExA(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS, static_cast<LPCSTR>(framesToCapture[i]), &backtraceModuleHandle);
-
- char backtraceModuleFullName[MAX_PATH];
- GetModuleFileNameExA(GetCurrentProcess(), backtraceModuleHandle, backtraceModuleFullName, MAX_PATH);
- char* backtraceModuleName = strrchr(backtraceModuleFullName, '\\') + 1;
-
- void* actualAddress = (void*)framesToCapture[i];
- void* relativeAddress = (void*)(uintptr_t(actualAddress) - uintptr_t(backtraceModuleHandle));
-
- spdlog::error(" {} + {} ({})", backtraceModuleName, relativeAddress, actualAddress);
- }
-
- spdlog::error("RAX: 0x{0:x}", exceptionContext->Rax);
- spdlog::error("RBX: 0x{0:x}", exceptionContext->Rbx);
- spdlog::error("RCX: 0x{0:x}", exceptionContext->Rcx);
- spdlog::error("RDX: 0x{0:x}", exceptionContext->Rdx);
- spdlog::error("RSI: 0x{0:x}", exceptionContext->Rsi);
- spdlog::error("RDI: 0x{0:x}", exceptionContext->Rdi);
- spdlog::error("RBP: 0x{0:x}", exceptionContext->Rbp);
- spdlog::error("RSP: 0x{0:x}", exceptionContext->Rsp);
- spdlog::error("R8: 0x{0:x}", exceptionContext->R8);
- spdlog::error("R9: 0x{0:x}", exceptionContext->R9);
- spdlog::error("R10: 0x{0:x}", exceptionContext->R10);
- spdlog::error("R11: 0x{0:x}", exceptionContext->R11);
- spdlog::error("R12: 0x{0:x}", exceptionContext->R12);
- spdlog::error("R13: 0x{0:x}", exceptionContext->R13);
- spdlog::error("R14: 0x{0:x}", exceptionContext->R14);
- spdlog::error("R15: 0x{0:x}", exceptionContext->R15);
-
- time_t time = std::time(nullptr);
- tm currentTime = *std::localtime(&time);
- std::stringstream stream;
- stream << std::put_time(&currentTime, (GetNorthstarPrefix() + "/logs/nsdump%Y-%m-%d %H-%M-%S.dmp").c_str());
-
- auto hMinidumpFile = CreateFileA(stream.str().c_str(), GENERIC_WRITE, FILE_SHARE_READ, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
- if (hMinidumpFile)
- {
- MINIDUMP_EXCEPTION_INFORMATION dumpExceptionInfo;
- dumpExceptionInfo.ThreadId = GetCurrentThreadId();
- dumpExceptionInfo.ExceptionPointers = exceptionInfo;
- dumpExceptionInfo.ClientPointers = false;
-
- MiniDumpWriteDump(
- GetCurrentProcess(),
- GetCurrentProcessId(),
- hMinidumpFile,
- MINIDUMP_TYPE(MiniDumpWithIndirectlyReferencedMemory | MiniDumpScanMemory),
- &dumpExceptionInfo,
- nullptr,
- nullptr);
- CloseHandle(hMinidumpFile);
- }
- else
- spdlog::error("Failed to write minidump file {}!", stream.str());
-
- if (!IsDedicatedServer())
- MessageBoxA(
- 0, "Northstar has crashed! Crash info can be found in R2Northstar/logs", "Northstar has crashed!", MB_ICONERROR | MB_OK);
- }
-
- logged = true;
- return EXCEPTION_EXECUTE_HANDLER;
-}
-
-HANDLE hExceptionFilter;
-
-BOOL WINAPI ConsoleHandlerRoutine(DWORD eventCode)
-{
- switch (eventCode)
- {
- case CTRL_CLOSE_EVENT:
- // User closed console, shut everything down
- spdlog::info("Exiting due to console close...");
- RemoveVectoredExceptionHandler(hExceptionFilter);
- exit(EXIT_SUCCESS);
- return FALSE;
- }
-
- return TRUE;
-}
-
-void InitialiseLogging()
-{
- hExceptionFilter = AddVectoredExceptionHandler(TRUE, ExceptionFilter);
-
- AllocConsole();
- // seem to cause issues with console log initialisation occasionally
- //freopen("CONOUT$", "w", stdout);
- //freopen("CONOUT$", "w", stderr);
- spdlog::default_logger()->set_pattern("[%H:%M:%S] [%l] %v");
-
- SetConsoleCtrlHandler(ConsoleHandlerRoutine, true);
-}
+AUTOHOOK_INIT()
ConVar* Cvar_spewlog_enable;
-enum SpewType_t
+enum class SpewType_t
{
SPEW_MESSAGE = 0,
@@ -256,56 +25,23 @@ enum SpewType_t
SPEW_TYPE_COUNT
};
-typedef void (*EngineSpewFuncType)();
-EngineSpewFuncType EngineSpewFunc;
+const std::unordered_map<SpewType_t, const char*> PrintSpewTypes = {
+ {SpewType_t::SPEW_MESSAGE, "SPEW_MESSAGE"},
+ {SpewType_t::SPEW_WARNING, "SPEW_WARNING"},
+ {SpewType_t::SPEW_ASSERT, "SPEW_ASSERT"},
+ {SpewType_t::SPEW_ERROR, "SPEW_ERROR"},
+ {SpewType_t::SPEW_LOG, "SPEW_LOG"}
+};
-void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format, va_list args)
+AUTOHOOK(EngineSpewFunc, engine.dll + 0x11CA80,
+void,, (void* pEngineServer, SpewType_t type, const char* format, va_list args),
{
if (!Cvar_spewlog_enable->GetBool())
return;
- const char* typeStr;
- switch (type)
- {
- case SPEW_MESSAGE:
- {
- typeStr = "SPEW_MESSAGE";
- break;
- }
-
- case SPEW_WARNING:
- {
- typeStr = "SPEW_WARNING";
- break;
- }
-
- case SPEW_ASSERT:
- {
- typeStr = "SPEW_ASSERT";
- break;
- }
-
- case SPEW_ERROR:
- {
- typeStr = "SPEW_ERROR";
- break;
- }
-
- case SPEW_LOG:
- {
- typeStr = "SPEW_LOG";
- break;
- }
-
- default:
- {
- typeStr = "SPEW_UNKNOWN";
- break;
- }
- }
-
+ const char* typeStr = PrintSpewTypes.at(type);
char formatted[2048] = {0};
- bool shouldFormat = true;
+ bool bShouldFormat = true;
// because titanfall 2 is quite possibly the worst thing to yet exist, it sometimes gives invalid specifiers which will crash
// ttf2sdk had a way to prevent them from crashing but it doesnt work in debug builds
@@ -352,14 +88,14 @@ void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format,
default:
{
- shouldFormat = false;
+ bShouldFormat = false;
break;
}
}
}
}
- if (shouldFormat)
+ if (bShouldFormat)
vsnprintf(formatted, sizeof(formatted), format, args);
else
{
@@ -371,12 +107,11 @@ void EngineSpewFuncHook(void* engineServer, SpewType_t type, const char* format,
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, ...)
+// used for printing the output of status
+AUTOHOOK(Status_ConMsg, engine.dll + 0x15ABD0,
+void,, (const char* text, ...),
{
char formatted[2048];
va_list list;
@@ -390,11 +125,10 @@ void Status_ConMsg_Hook(const char* text, ...)
formatted[endpos - 1] = '\0'; // cut off repeated newline
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)
+AUTOHOOK(CClientState_ProcessPrint, engine.dll + 0x1A1530,
+bool,, (__int64 thisptr, __int64 msg),
{
char* text = *(char**)(msg + 0x20);
@@ -404,34 +138,10 @@ bool CClientState_ProcessPrint_Hook(__int64 thisptr, __int64 msg)
spdlog::info(text);
return true;
-}
-
-ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", EngineSpewFuncHooks, ConVar, [](HMODULE baseAddress)
-{
- HookEnabler hook;
-
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x11CA80, EngineSpewFuncHook, reinterpret_cast<LPVOID*>(&EngineSpewFunc));
-
- // Hook print function that status concmd uses to actually print data
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x15ABD0, Status_ConMsg_Hook, reinterpret_cast<LPVOID*>(&Status_ConMsg_Original));
-
- // Hook CClientState::ProcessPrint
- ENABLER_CREATEHOOK(
- hook,
- (char*)baseAddress + 0x1A1530,
- CClientState_ProcessPrint_Hook,
- reinterpret_cast<LPVOID*>(&CClientState_ProcessPrint_Original));
-
- Cvar_spewlog_enable = new ConVar("spewlog_enable", "1", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged");
})
-#include "bitbuf.h"
-
ConVar* Cvar_cl_showtextmsg;
-typedef void (*TextMsg_Type)(__int64);
-TextMsg_Type TextMsg_Original;
-
class ICenterPrint
{
public:
@@ -444,11 +154,20 @@ class ICenterPrint
virtual void SetTextColor(int r, int g, int b, int a) = 0;
};
-ICenterPrint* internalCenterPrint = NULL;
+ICenterPrint* pInternalCenterPrint = NULL;
-void TextMsgHook(BFRead* msg)
+enum class TextMsgPrintType_t
{
- int msg_dest = msg->ReadByte();
+ HUD_PRINTNOTIFY = 1,
+ HUD_PRINTCONSOLE,
+ HUD_PRINTTALK,
+ HUD_PRINTCENTER
+};
+
+AUTOHOOK(TextMsg, client.dll + 0x198710,
+void,, (BFRead* msg),
+{
+ TextMsgPrintType_t msg_dest = (TextMsgPrintType_t)msg->ReadByte();
char text[256];
msg->ReadString(text, sizeof(text));
@@ -458,29 +177,64 @@ void TextMsgHook(BFRead* msg)
switch (msg_dest)
{
- case 4: // HUD_PRINTCENTER
- internalCenterPrint->Print(text);
+ case TextMsgPrintType_t::HUD_PRINTCENTER:
+ pInternalCenterPrint->Print(text);
break;
+
default:
spdlog::warn("Unimplemented TextMsg type {}! printing to console", msg_dest);
[[fallthrough]];
- case 2: // HUD_PRINTCONSOLE
+
+ case TextMsgPrintType_t::HUD_PRINTCONSOLE:
auto endpos = strlen(text);
if (text[endpos - 1] == '\n')
text[endpos - 1] = '\0'; // cut off repeated newline
+
spdlog::info(text);
break;
}
+})
+
+// This needs to be called after hooks are loaded so we can access the command line args
+void CreateLogFiles()
+{
+ if (strstr(GetCommandLineA(), "-disablelogs"))
+ {
+ spdlog::default_logger()->set_level(spdlog::level::off);
+ }
+ else
+ {
+ // todo: might be good to delete logs that are too old
+ time_t time = std::time(nullptr);
+ tm currentTime = *std::localtime(&time);
+ std::stringstream stream;
+
+ stream << std::put_time(&currentTime, (GetNorthstarPrefix() + "/logs/nslog%Y-%m-%d %H-%M-%S.txt").c_str());
+ spdlog::default_logger()->sinks().push_back(std::make_shared<spdlog::sinks::basic_file_sink_mt>(stream.str(), false));
+ spdlog::flush_on(spdlog::level::info);
+ }
}
-ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientPrintHooks, ConVar, [](HMODULE baseAddress)
+void InitialiseLogging()
+{
+ AllocConsole();
+ // seem to cause issues with console log initialisation occasionally
+ // freopen("CONOUT$", "w", stdout);
+ // freopen("CONOUT$", "w", stderr);
+ spdlog::default_logger()->set_pattern("[%H:%M:%S] [%l] %v");
+}
+
+ON_DLL_LOAD_CLIENT_RELIESON("engine.dll", EngineSpewFuncHooks, ConVar, [](HMODULE baseAddress)
{
- HookEnabler hook;
+ AUTOHOOK_DISPATCH_MODULE(engine.dll)
- internalCenterPrint = (ICenterPrint*)((char*)baseAddress + 0x216E940);
+ Cvar_spewlog_enable = new ConVar("spewlog_enable", "1", FCVAR_NONE, "Enables/disables whether the engine spewfunc should be logged");
+})
- // "TextMsg" usermessage
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x198710, TextMsgHook, reinterpret_cast<LPVOID*>(&TextMsg_Original));
+ON_DLL_LOAD_CLIENT_RELIESON("client.dll", ClientPrintHooks, ConVar, [](HMODULE baseAddress)
+{
+ AUTOHOOK_DISPATCH_MODULE(client.dll)
Cvar_cl_showtextmsg = new ConVar("cl_showtextmsg", "1", FCVAR_NONE, "Enable/disable text messages printing on the screen.");
+ pInternalCenterPrint = (ICenterPrint*)((char*)baseAddress + 0x216E940);
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/modlocalisation.cpp b/NorthstarDedicatedTest/modlocalisation.cpp
index 85df8902..ad01192d 100644
--- a/NorthstarDedicatedTest/modlocalisation.cpp
+++ b/NorthstarDedicatedTest/modlocalisation.cpp
@@ -1,9 +1,10 @@
#include "pch.h"
#include "modmanager.h"
-typedef bool (*AddLocalisationFileType)(void* pVguiLocalize, const char* path, const char* pathId, char unknown);
-AddLocalisationFileType AddLocalisationFile;
-bool AddLocalisationFileHook(void* pVguiLocalize, const char* path, const char* pathId, char unknown)
+AUTOHOOK_INIT()
+
+AUTOHOOK(AddLocalisationFile, localize.dll + 0x6D80,
+bool,, (void* pVguiLocalize, const char* path, const char* pathId, char unknown),
{
static bool bLoadModLocalisationFiles = true;
bool ret = AddLocalisationFile(pVguiLocalize, path, pathId, unknown);
@@ -24,10 +25,9 @@ bool AddLocalisationFileHook(void* pVguiLocalize, const char* path, const char*
bLoadModLocalisationFiles = true;
return ret;
-}
+})
ON_DLL_LOAD_CLIENT("localize.dll", Localize, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0x6D80, AddLocalisationFileHook, reinterpret_cast<LPVOID*>(&AddLocalisationFile));
+ AUTOHOOK_DISPATCH()
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h
index d1ee9c74..f6faa2c1 100644
--- a/NorthstarDedicatedTest/pch.h
+++ b/NorthstarDedicatedTest/pch.h
@@ -8,8 +8,6 @@
#define _WINSOCK_DEPRECATED_NO_WARNINGS // temp because i'm very lazy and want to use inet_addr, remove later
#define RAPIDJSON_HAS_STDSTRING 1
-// httplib ssl
-
// add headers that you want to pre-compile here
#include "memalloc.h"
diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp
index 0e0ed3c2..67e3a821 100644
--- a/NorthstarDedicatedTest/playlist.cpp
+++ b/NorthstarDedicatedTest/playlist.cpp
@@ -10,53 +10,62 @@ AUTOHOOK_INIT()
// use the R2 namespace for game funcs
namespace R2
{
- GetCurrentPlaylistNameType GetCurrentPlaylistName;
- SetCurrentPlaylistType SetCurrentPlaylist;
- SetPlaylistVarOverrideType SetPlaylistVarOverride;
- GetCurrentPlaylistVarType GetCurrentPlaylistVar;
+ const char* (*GetCurrentPlaylistName)();
+ void (*SetCurrentPlaylist)(const char* pPlaylistName);
+ void (*SetPlaylistVarOverride)(const char* pVarName, const char* pValue);
+ const char* (*GetCurrentPlaylistVar)(const char* pVarName, bool bUseOverrides);
} // namespace R2
ConVar* Cvar_ns_use_clc_SetPlaylistVarOverride;
-typedef char (*Onclc_SetPlaylistVarOverrideType)(void* a1, void* a2);
-Onclc_SetPlaylistVarOverrideType Onclc_SetPlaylistVarOverride;
-char Onclc_SetPlaylistVarOverrideHook(void* a1, void* a2)
+AUTOHOOK(clc_SetPlaylistVarOverride__Process, engine.dll + 0x222180,
+char,, (void* a1, void* a2),
{
// the private_match playlist is the only situation where there should be any legitimate sending of this netmessage
- // todo: check mp_lobby here too
+ // todo: check map == mp_lobby here too
if (!Cvar_ns_use_clc_SetPlaylistVarOverride->GetBool() || strcmp(R2::GetCurrentPlaylistName(), "private_match"))
return 1;
- return Onclc_SetPlaylistVarOverride(a1, a2);
-}
+ return clc_SetPlaylistVarOverride__Process(a1, a2);
+})
+
+AUTOHOOK(SetCurrentPlaylist, engine.dll + 0x18EB20,
+void,, (const char* pPlaylistName),
+{
+ SetCurrentPlaylist(pPlaylistName);
+ spdlog::info("Set playlist to {}", pPlaylistName);
+})
-void SetPlaylistVarOverrideHook(const char* varName, const char* value)
+AUTOHOOK(SetPlaylistVarOverride, engine.dll + 0x18ED00,
+void,, (const char* pVarName, const char* pValue),
{
- if (strlen(value) >= 64)
+ if (strlen(pValue) >= 64)
return;
- R2::SetPlaylistVarOverride(varName, value);
-}
+ R2::SetPlaylistVarOverride(pVarName, pValue);
+})
-const char* GetCurrentPlaylistVarHook(const char* varName, bool useOverrides)
+AUTOHOOK(GetCurrentPlaylistVar, engine.dll + 0x18C680,
+const char*,, (const char* pVarName, bool bUseOverrides),
{
- if (!useOverrides && !strcmp(varName, "max_players"))
- useOverrides = true;
+ if (!bUseOverrides && !strcmp(pVarName, "max_players"))
+ bUseOverrides = true;
+
+ return R2::GetCurrentPlaylistVar(pVarName, bUseOverrides);
+})
- return R2::GetCurrentPlaylistVar(varName, useOverrides);
-}
-typedef int (*GetCurrentGamemodeMaxPlayersType)();
-GetCurrentGamemodeMaxPlayersType GetCurrentGamemodeMaxPlayers;
-int GetCurrentGamemodeMaxPlayersHook()
+AUTOHOOK(GetCurrentGamemodeMaxPlayers, engine.dll + 0x18C430,
+int,, (),
{
- const char* maxPlayersStr = R2::GetCurrentPlaylistVar("max_players", 0);
- if (!maxPlayersStr)
+ const char* pMaxPlayers = R2::GetCurrentPlaylistVar("max_players", 0);
+ if (!pMaxPlayers)
return GetCurrentGamemodeMaxPlayers();
- int maxPlayers = atoi(maxPlayersStr);
- return maxPlayers;
-}
+ int iMaxPlayers = atoi(pMaxPlayers);
+ return iMaxPlayers;
+})
+
void ConCommand_playlist(const CCommand& args)
{
@@ -77,16 +86,18 @@ void ConCommand_setplaylistvaroverride(const CCommand& args)
ON_DLL_LOAD_RELIESON("engine.dll", PlaylistHooks, ConCommand, [](HMODULE baseAddress)
{
+ AUTOHOOK_DISPATCH()
+
+ R2::GetCurrentPlaylistName = (const char* (*)())((char*)baseAddress + 0x18C640);
+ R2::SetCurrentPlaylist = (void (*)(const char*))((char*)baseAddress + 0x18EB20);
+ R2::SetPlaylistVarOverride = (void (*)(const char*, const char*))((char*)baseAddress + 0x18ED00);
+ R2::GetCurrentPlaylistVar = (const char* (*)(const char*, bool))((char*)baseAddress + 0x18C680);
+
// playlist is the name of the command on respawn servers, but we already use setplaylist so can't get rid of it
RegisterConCommand("playlist", ConCommand_playlist, "Sets the current playlist", FCVAR_NONE);
RegisterConCommand("setplaylist", ConCommand_playlist, "Sets the current playlist", FCVAR_NONE);
RegisterConCommand("setplaylistvaroverrides", ConCommand_setplaylistvaroverride, "sets a playlist var override", FCVAR_NONE);
- R2::GetCurrentPlaylistName = (R2::GetCurrentPlaylistNameType)((char*)baseAddress + 0x18C640);
- R2::SetCurrentPlaylist = (R2::SetCurrentPlaylistType)((char*)baseAddress + 0x18EB20);
- R2::SetPlaylistVarOverride = (R2::SetPlaylistVarOverrideType)((char*)baseAddress + 0x18ED00);
- R2::GetCurrentPlaylistVar = (R2::GetCurrentPlaylistVarType)((char*)baseAddress + 0x18C680);
-
// note: clc_SetPlaylistVarOverride is pretty insecure, since it allows for entirely arbitrary playlist var overrides to be sent to the
// server, this is somewhat restricted on custom servers to prevent it being done outside of private matches, but ideally it should be
// disabled altogether, since the custom menus won't use it anyway this should only really be accepted if you want vanilla client
@@ -94,25 +105,10 @@ ON_DLL_LOAD_RELIESON("engine.dll", PlaylistHooks, ConCommand, [](HMODULE baseAdd
Cvar_ns_use_clc_SetPlaylistVarOverride = new ConVar(
"ns_use_clc_SetPlaylistVarOverride", "0", FCVAR_GAMEDLL, "Whether the server should accept clc_SetPlaylistVarOverride messages");
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x222180, &Onclc_SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&Onclc_SetPlaylistVarOverride));
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x18ED00, &SetPlaylistVarOverrideHook, reinterpret_cast<LPVOID*>(&R2::SetPlaylistVarOverride));
- ENABLER_CREATEHOOK(
- hook, (char*)baseAddress + 0x18C680, &GetCurrentPlaylistVarHook, reinterpret_cast<LPVOID*>(&R2::GetCurrentPlaylistVar));
- ENABLER_CREATEHOOK(
- hook,
- (char*)baseAddress + 0x18C430,
- &GetCurrentGamemodeMaxPlayersHook,
- reinterpret_cast<LPVOID*>(&GetCurrentGamemodeMaxPlayers));
-
- uintptr_t ba = (uintptr_t)baseAddress;
-
// patch to prevent clc_SetPlaylistVarOverride from being able to crash servers if we reach max overrides due to a call to Error (why is
// this possible respawn, wtf) todo: add a warning for this
- NSMem::BytePatch(ba + 0x18ED8D, "C3");
+ NSMem::BytePatch((uintptr_t)baseAddress + 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);
+ NSMem::NOP((uintptr_t)baseAddress + 0x18ED17, 6);
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/playlist.h b/NorthstarDedicatedTest/playlist.h
index 4ad48ee9..c77b37d9 100644
--- a/NorthstarDedicatedTest/playlist.h
+++ b/NorthstarDedicatedTest/playlist.h
@@ -3,15 +3,8 @@
// use the R2 namespace for game funcs
namespace R2
{
- typedef const char* (*GetCurrentPlaylistNameType)();
- extern GetCurrentPlaylistNameType GetCurrentPlaylistName;
-
- typedef void (*SetCurrentPlaylistType)(const char* playlistName);
- extern SetCurrentPlaylistType SetCurrentPlaylist;
-
- typedef void (*SetPlaylistVarOverrideType)(const char* varName, const char* value);
- extern SetPlaylistVarOverrideType SetPlaylistVarOverride;
-
- typedef const char* (*GetCurrentPlaylistVarType)(const char* varName, bool useOverrides);
- extern GetCurrentPlaylistVarType GetCurrentPlaylistVar;
+ extern const char* (*GetCurrentPlaylistName)();
+ extern void (*SetCurrentPlaylist)(const char* pPlaylistName);
+ extern void (*SetPlaylistVarOverride)(const char* pVarName, const char* pValue);
+ extern const char* (*GetCurrentPlaylistVar)(const char* pVarName, bool bUseOverrides);
} // namespace R2
diff --git a/NorthstarDedicatedTest/rpakfilesystem.cpp b/NorthstarDedicatedTest/rpakfilesystem.cpp
index e7c88674..bba69ff3 100644
--- a/NorthstarDedicatedTest/rpakfilesystem.cpp
+++ b/NorthstarDedicatedTest/rpakfilesystem.cpp
@@ -3,21 +3,18 @@
#include "modmanager.h"
#include "dedicated.h"
-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 void* (*UnloadPakType)(int pakHandle, void* callback);
-typedef void* (*ReadFullFileFromDiskType)(const char* requestedPath, void* a2);
+AUTOHOOK_INIT()
// there are more i'm just too lazy to add
struct PakLoadFuncs
{
void* unk0[2];
- LoadPakSyncType LoadPakSync;
- LoadPakAsyncType LoadPakAsync;
+ void* (*LoadPakSync)(const char* pPath, void* unknownSingleton, int flags);
+ int (*LoadPakAsync)(const char* pPath, void* unknownSingleton, int flags, void* callback0, void* callback1);
void* unk1[2];
- UnloadPakType UnloadPak;
+ void* (*UnloadPak)(int iPakHandle, void* callback);
void* unk2[17];
- ReadFullFileFromDiskType ReadFullFileFromDisk;
+ void* (*ReadFullFileFromDisk)(const char* pPath, void* a2);
};
PakLoadFuncs* g_pakLoadApi;
@@ -116,10 +113,10 @@ void LoadCustomMapPaks(char** pakName, bool* bNeedToFreePakName)
}
}
-LoadPakAsyncType LoadPakAsyncOriginal;
-int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callback0, void* callback1)
+HOOK(LoadPakAsyncHook, LoadPakAsync,
+int,, (char* pPath, void* unknownSingleton, int flags, void* callback0, void* callback1),
{
- HandlePakAliases(&path);
+ HandlePakAliases(&pPath);
bool bNeedToFreePakName = false;
@@ -127,13 +124,13 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba
if (bShouldLoadPaks)
{
// make a copy of the path for comparing to determine whether we should load this pak on dedi, before it could get overwritten by LoadCustomMapPaks
- std::string originalPath(path);
+ std::string originalPath(pPath);
// disable preloading while we're doing this
bShouldLoadPaks = false;
LoadPreloadPaks();
- LoadCustomMapPaks(&path, &bNeedToFreePakName);
+ LoadCustomMapPaks(&pPath, &bNeedToFreePakName);
bShouldLoadPaks = true;
@@ -146,17 +143,17 @@ int LoadPakAsyncHook(char* path, void* unknownSingleton, int flags, void* callba
}
}
- int ret = LoadPakAsyncOriginal(path, unknownSingleton, flags, callback0, callback1);
- spdlog::info("LoadPakAsync {} {}", path, ret);
+ int ret = LoadPakAsync(pPath, unknownSingleton, flags, callback0, callback1);
+ spdlog::info("LoadPakAsync {} {}", pPath, ret);
if (bNeedToFreePakName)
- delete[] path;
+ delete[] pPath;
return ret;
-}
+})
-UnloadPakType UnloadPakOriginal;
-void* UnloadPakHook(int pakHandle, void* callback)
+HOOK(UnloadPakHook, UnloadPak,
+void*,, (int iPakHandle, void* callback),
{
static bool bShouldUnloadPaks = true;
if (bShouldUnloadPaks)
@@ -166,16 +163,17 @@ void* UnloadPakHook(int pakHandle, void* callback)
bShouldUnloadPaks = true;
}
- spdlog::info("UnloadPak {}", pakHandle);
- return UnloadPakOriginal(pakHandle, callback);
-}
+ spdlog::info("UnloadPak {}", iPakHandle);
+ return UnloadPak(iPakHandle, callback);
+})
// we hook this exclusively for resolving stbsp paths, but seemingly it's also used for other stuff like vpk and rpak loads
-// possibly just async loading all together?
-ReadFullFileFromDiskType ReadFullFileFromDiskOriginal;
-void* ReadFullFileFromDiskHook(const char* requestedPath, void* a2)
+// possibly just async loading altogether?
+
+HOOK(ReadFullFileFromDiskHook, ReadFullFileFromDisk,
+void*, , (const char* pPath, void* a2),
{
- fs::path path(requestedPath);
+ fs::path path(pPath);
char* allocatedNewPath = nullptr;
if (path.extension() == ".stbsp")
@@ -193,27 +191,28 @@ void* ReadFullFileFromDiskHook(const char* requestedPath, void* a2)
allocatedNewPath = new char[newPath.size() + 1];
strncpy(allocatedNewPath, newPath.c_str(), newPath.size());
allocatedNewPath[newPath.size()] = '\0';
- requestedPath = allocatedNewPath;
+ pPath = allocatedNewPath;
}
}
- void* ret = ReadFullFileFromDiskOriginal(requestedPath, a2);
+ void* ret = ReadFullFileFromDisk(pPath, a2);
if (allocatedNewPath)
delete[] allocatedNewPath;
return ret;
-}
+})
+
ON_DLL_LOAD("engine.dll", RpakFilesystem, [](HMODULE baseAddress)
{
+ AUTOHOOK_DISPATCH();
+
g_pPakLoadManager = new PakLoadManager;
g_pakLoadApi = *(PakLoadFuncs**)((char*)baseAddress + 0x5BED78);
pUnknownPakLoadSingleton = (void**)((char*)baseAddress + 0x7C5E20);
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, g_pakLoadApi->LoadPakAsync, &LoadPakAsyncHook, reinterpret_cast<LPVOID*>(&LoadPakAsyncOriginal));
- ENABLER_CREATEHOOK(hook, g_pakLoadApi->UnloadPak, &UnloadPakHook, reinterpret_cast<LPVOID*>(&UnloadPakOriginal));
- ENABLER_CREATEHOOK(
- hook, g_pakLoadApi->ReadFullFileFromDisk, &ReadFullFileFromDiskHook, reinterpret_cast<LPVOID*>(&ReadFullFileFromDiskOriginal));
+ LoadPakAsyncHook.Dispatch(g_pakLoadApi->LoadPakAsync);
+ UnloadPakHook.Dispatch(g_pakLoadApi->UnloadPak);
+ ReadFullFileFromDiskHook.Dispatch(g_pakLoadApi->ReadFullFileFromDisk);
}) \ No newline at end of file
diff --git a/NorthstarDedicatedTest/sourceconsole.cpp b/NorthstarDedicatedTest/sourceconsole.cpp
index 7627a2f1..55e78ad3 100644
--- a/NorthstarDedicatedTest/sourceconsole.cpp
+++ b/NorthstarDedicatedTest/sourceconsole.cpp
@@ -5,29 +5,41 @@
#include "concommand.h"
#include "printcommand.h"
-SourceInterface<CGameConsole>* g_SourceGameConsole;
+SourceInterface<CGameConsole>* g_pSourceGameConsole;
void ConCommand_toggleconsole(const CCommand& arg)
{
- if ((*g_SourceGameConsole)->IsConsoleVisible())
- (*g_SourceGameConsole)->Hide();
+ if ((*g_pSourceGameConsole)->IsConsoleVisible())
+ (*g_pSourceGameConsole)->Hide();
else
- (*g_SourceGameConsole)->Activate();
+ (*g_pSourceGameConsole)->Activate();
}
void ConCommand_showconsole(const CCommand& arg)
{
- (*g_SourceGameConsole)->Activate();
+ (*g_pSourceGameConsole)->Activate();
}
void ConCommand_hideconsole(const CCommand& arg)
{
- (*g_SourceGameConsole)->Hide();
+ (*g_pSourceGameConsole)->Hide();
}
-typedef void (*OnCommandSubmittedType)(CConsoleDialog* consoleDialog, const char* pCommand);
-OnCommandSubmittedType onCommandSubmittedOriginal;
-void OnCommandSubmittedHook(CConsoleDialog* consoleDialog, const char* pCommand)
+void SourceConsoleSink::sink_it_(const spdlog::details::log_msg& msg)
+{
+ if (!(*g_pSourceGameConsole)->m_bInitialized)
+ return;
+
+ spdlog::memory_buf_t formatted;
+ spdlog::sinks::base_sink<std::mutex>::formatter_->format(msg, formatted);
+ (*g_pSourceGameConsole)
+ ->m_pConsole->m_pConsolePanel->ColorPrint(m_LogColours[msg.level], fmt::to_string(formatted).c_str());
+}
+
+void SourceConsoleSink::flush_() {}
+
+HOOK(OnCommandSubmittedHook, OnCommandSubmitted,
+void,, (CConsoleDialog* consoleDialog, const char* pCommand),
{
consoleDialog->m_pConsolePanel->Print("] ");
consoleDialog->m_pConsolePanel->Print(pCommand);
@@ -35,55 +47,24 @@ void OnCommandSubmittedHook(CConsoleDialog* consoleDialog, const char* pCommand)
TryPrintCvarHelpForCommand(pCommand);
- onCommandSubmittedOriginal(consoleDialog, pCommand);
-}
+ OnCommandSubmitted(consoleDialog, pCommand);
+})
// called from sourceinterface.cpp in client createinterface hooks, on GameClientExports001
void InitialiseConsoleOnInterfaceCreation()
{
- (*g_SourceGameConsole)->Initialize();
+ (*g_pSourceGameConsole)->Initialize();
+ // hook OnCommandSubmitted so we print inputted commands
+ OnCommandSubmittedHook.Dispatch((*g_pSourceGameConsole)->m_pConsole->m_vtable->OnCommandSubmitted);
auto consoleLogger = std::make_shared<SourceConsoleSink>();
consoleLogger->set_pattern("[%l] %v");
-
spdlog::default_logger()->sinks().push_back(consoleLogger);
-
- // hook OnCommandSubmitted so we print inputted commands
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook,
- (void*)((*g_SourceGameConsole)->m_pConsole->m_vtable->OnCommandSubmitted),
- &OnCommandSubmittedHook,
- reinterpret_cast<LPVOID*>(&onCommandSubmittedOriginal));
-}
-
-SourceConsoleSink::SourceConsoleSink()
-{
- logColours.emplace(spdlog::level::trace, SourceColor(0, 255, 255, 255));
- logColours.emplace(spdlog::level::debug, SourceColor(0, 255, 255, 255));
- logColours.emplace(spdlog::level::info, SourceColor(255, 255, 255, 255));
- logColours.emplace(spdlog::level::warn, SourceColor(255, 255, 0, 255));
- logColours.emplace(spdlog::level::err, SourceColor(255, 0, 0, 255));
- logColours.emplace(spdlog::level::critical, SourceColor(255, 0, 0, 255));
- logColours.emplace(spdlog::level::off, SourceColor(0, 0, 0, 0));
-}
-
-void SourceConsoleSink::sink_it_(const spdlog::details::log_msg& msg)
-{
- if (!(*g_SourceGameConsole)->m_bInitialized)
- return;
-
- spdlog::memory_buf_t formatted;
- spdlog::sinks::base_sink<std::mutex>::formatter_->format(msg, formatted);
- (*g_SourceGameConsole)
- ->m_pConsole->m_pConsolePanel->ColorPrint(logColours[msg.level], fmt::to_string(formatted).c_str()); // todo needs colour support
}
-void SourceConsoleSink::flush_() {}
-
ON_DLL_LOAD_CLIENT_RELIESON("client.dll", SourceConsole, ConCommand, [](HMODULE baseAddress)
{
- g_SourceGameConsole = new SourceInterface<CGameConsole>("client.dll", "GameConsole004");
+ g_pSourceGameConsole = new SourceInterface<CGameConsole>("client.dll", "GameConsole004");
RegisterConCommand("toggleconsole", ConCommand_toggleconsole, "Show/hide the console.", FCVAR_DONTRECORD);
RegisterConCommand("showconsole", ConCommand_showconsole, "Show the console.", FCVAR_DONTRECORD);
RegisterConCommand("hideconsole", ConCommand_hideconsole, "Hide the console.", FCVAR_DONTRECORD);
diff --git a/NorthstarDedicatedTest/sourceconsole.h b/NorthstarDedicatedTest/sourceconsole.h
index e8d44a84..9f6c2bf8 100644
--- a/NorthstarDedicatedTest/sourceconsole.h
+++ b/NorthstarDedicatedTest/sourceconsole.h
@@ -86,16 +86,21 @@ class CGameConsole
CConsoleDialog* m_pConsole;
};
-extern SourceInterface<CGameConsole>* g_SourceGameConsole;
+extern SourceInterface<CGameConsole>* g_pSourceGameConsole;
// spdlog logger
class SourceConsoleSink : public spdlog::sinks::base_sink<std::mutex>
{
private:
- std::map<spdlog::level::level_enum, SourceColor> logColours;
-
- public:
- SourceConsoleSink();
+ std::map<spdlog::level::level_enum, SourceColor> m_LogColours = {
+ {spdlog::level::trace, SourceColor(0, 255, 255, 255)},
+ {spdlog::level::debug, SourceColor(0, 255, 255, 255)},
+ {spdlog::level::info, SourceColor(255, 255, 255, 255)},
+ {spdlog::level::warn, SourceColor(255, 255, 0, 255)},
+ {spdlog::level::err, SourceColor(255, 0, 0, 255)},
+ {spdlog::level::critical, SourceColor(255, 0, 0, 255)},
+ {spdlog::level::off, SourceColor(0, 0, 0, 0)}
+ };
protected:
void sink_it_(const spdlog::details::log_msg& msg) override;
diff --git a/NorthstarDedicatedTest/sourceinterface.cpp b/NorthstarDedicatedTest/sourceinterface.cpp
index 05e83856..6528344d 100644
--- a/NorthstarDedicatedTest/sourceinterface.cpp
+++ b/NorthstarDedicatedTest/sourceinterface.cpp
@@ -2,64 +2,51 @@
#include "sourceinterface.h"
#include "sourceconsole.h"
+AUTOHOOK_INIT()
+
// really wanted to do a modular callback system here but honestly couldn't be bothered so hardcoding stuff for now: todo later
-CreateInterfaceFn ClientCreateInterfaceOriginal;
-void* ClientCreateInterfaceHook(const char* pName, int* pReturnCode)
+AUTOHOOK_PROCADDRESS(ClientCreateInterface, "client.dll", CreateInterface,
+void*,, (const char* pName, const int* pReturnCode),
{
- void* ret = ClientCreateInterfaceOriginal(pName, pReturnCode);
+ void* ret = ClientCreateInterface(pName, pReturnCode);
spdlog::info("CreateInterface CLIENT {}", pName);
if (!strcmp(pName, "GameClientExports001"))
InitialiseConsoleOnInterfaceCreation();
return ret;
-}
+})
-CreateInterfaceFn ServerCreateInterfaceOriginal;
-void* ServerCreateInterfaceHook(const char* pName, int* pReturnCode)
+AUTOHOOK_PROCADDRESS(ServerCreateInterface, "server.dll", CreateInterface,
+void*,, (const char* pName, const int* pReturnCode),
{
- void* ret = ServerCreateInterfaceOriginal(pName, pReturnCode);
+ void* ret = ServerCreateInterface(pName, pReturnCode);
spdlog::info("CreateInterface SERVER {}", pName);
return ret;
-}
+})
-CreateInterfaceFn EngineCreateInterfaceOriginal;
-void* EngineCreateInterfaceHook(const char* pName, int* pReturnCode)
+AUTOHOOK_PROCADDRESS(EngineCreateInterface, "engine.dll", CreateInterface,
+void*,, (const char* pName, const int* pReturnCode),
{
- void* ret = EngineCreateInterfaceOriginal(pName, pReturnCode);
+ void* ret = EngineCreateInterface(pName, pReturnCode);
spdlog::info("CreateInterface ENGINE {}", pName);
return ret;
-}
+})
ON_DLL_LOAD("client.dll", ClientInterface, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook,
- GetProcAddress(baseAddress, "CreateInterface"),
- &ClientCreateInterfaceHook,
- reinterpret_cast<LPVOID*>(&ClientCreateInterfaceOriginal));
+ AUTOHOOK_DISPATCH_MODULE("client.dll")
})
ON_DLL_LOAD("server.dll", ServerInterface, [](HMODULE baseAddress)
{
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook,
- GetProcAddress(baseAddress, "CreateInterface"),
- &ServerCreateInterfaceHook,
- reinterpret_cast<LPVOID*>(&ServerCreateInterfaceOriginal));
+ AUTOHOOK_DISPATCH_MODULE("server.dll")
})
ON_DLL_LOAD("engine.dll", EngineInterface, [](HMODULE baseAddress)
-{
- HookEnabler hook;
- ENABLER_CREATEHOOK(
- hook,
- GetProcAddress(baseAddress, "CreateInterface"),
- &EngineCreateInterfaceHook,
- reinterpret_cast<LPVOID*>(&EngineCreateInterfaceOriginal));
+{
+ AUTOHOOK_DISPATCH_MODULE("engine.dll")
}) \ No newline at end of file