aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--LauncherInjector/LauncherInjector.vcxproj71
-rw-r--r--LauncherInjector/main.cpp266
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj80
-rw-r--r--NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters6
-rw-r--r--NorthstarDedicatedTest/convar.cpp2
-rw-r--r--NorthstarDedicatedTest/dedicated.cpp26
-rw-r--r--NorthstarDedicatedTest/dedicatedmaterialsystem.cpp2
-rw-r--r--NorthstarDedicatedTest/dllmain.cpp30
-rw-r--r--NorthstarDedicatedTest/filesystem.cpp2
-rw-r--r--NorthstarDedicatedTest/gameutils.cpp36
-rw-r--r--NorthstarDedicatedTest/gameutils.h17
-rw-r--r--NorthstarDedicatedTest/hooks.cpp158
-rw-r--r--NorthstarDedicatedTest/hooks.h4
-rw-r--r--NorthstarDedicatedTest/hookutils.cpp4
-rw-r--r--NorthstarDedicatedTest/include/MinHook.x64.dllbin15360 -> 0 bytes
-rw-r--r--NorthstarDedicatedTest/include/MinHook.x64.libbin4048 -> 32400 bytes
-rw-r--r--NorthstarDedicatedTest/keyvalues.cpp3
-rw-r--r--NorthstarDedicatedTest/languagehooks.cpp109
-rw-r--r--NorthstarDedicatedTest/languagehooks.h3
-rw-r--r--NorthstarDedicatedTest/logging.cpp3
-rw-r--r--NorthstarDedicatedTest/main.h2
-rw-r--r--NorthstarDedicatedTest/masterserver.cpp149
-rw-r--r--NorthstarDedicatedTest/masterserver.h5
-rw-r--r--NorthstarDedicatedTest/memalloc.cpp91
-rw-r--r--NorthstarDedicatedTest/memalloc.h40
-rw-r--r--NorthstarDedicatedTest/modmanager.cpp8
-rw-r--r--NorthstarDedicatedTest/modmanager.h3
-rw-r--r--NorthstarDedicatedTest/pch.h2
-rw-r--r--NorthstarDedicatedTest/playlist.cpp2
-rw-r--r--NorthstarDedicatedTest/serverauthentication.cpp2
-rw-r--r--R2Northstar.sln25
-rw-r--r--loader_launcher_proxy/Memory.cpp84
-rw-r--r--loader_launcher_proxy/Memory.h24
-rw-r--r--loader_launcher_proxy/dllmain.cpp156
-rw-r--r--loader_launcher_proxy/framework.h7
-rw-r--r--loader_launcher_proxy/loader_launcher_proxy.vcxproj107
-rw-r--r--loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters33
-rw-r--r--loader_launcher_proxy/pch.cpp5
-rw-r--r--loader_launcher_proxy/pch.h13
-rw-r--r--loader_wsock32_proxy/dllmain.cpp137
-rw-r--r--loader_wsock32_proxy/hookutils.cpp71
-rw-r--r--loader_wsock32_proxy/loader.cpp86
-rw-r--r--loader_wsock32_proxy/loader.h8
-rw-r--r--loader_wsock32_proxy/loader_wsock32_proxy.vcxproj120
-rw-r--r--loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters49
-rw-r--r--loader_wsock32_proxy/pch.cpp5
-rw-r--r--loader_wsock32_proxy/pch.h16
-rw-r--r--loader_wsock32_proxy/wsock32.asm7
-rw-r--r--loader_wsock32_proxy/wsock32.def78
49 files changed, 1750 insertions, 407 deletions
diff --git a/LauncherInjector/LauncherInjector.vcxproj b/LauncherInjector/LauncherInjector.vcxproj
index e205207d..8870c732 100644
--- a/LauncherInjector/LauncherInjector.vcxproj
+++ b/LauncherInjector/LauncherInjector.vcxproj
@@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@@ -27,19 +19,6 @@
<ProjectName>NorthstarLauncher</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>Application</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
@@ -58,12 +37,6 @@
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@@ -71,50 +44,12 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <LanguageStandard>stdcpp17</LanguageStandard>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <LanguageStandard>stdcpp17</LanguageStandard>
- </ClCompile>
- <Link>
- <SubSystem>Console</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -122,10 +57,13 @@
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
+ <AdditionalOptions>/F8000000 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <StackReserveSize>8000000</StackReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -137,12 +75,15 @@
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpp17</LanguageStandard>
+ <AdditionalOptions>/F8000000 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <StackReserveSize>8000000</StackReserveSize>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
diff --git a/LauncherInjector/main.cpp b/LauncherInjector/main.cpp
index 5828e9e2..7697e80d 100644
--- a/LauncherInjector/main.cpp
+++ b/LauncherInjector/main.cpp
@@ -1,12 +1,25 @@
+#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <TlHelp32.h>
#include <filesystem>
#include <sstream>
-#include <iostream>
#include <fstream>
+#include <Shlwapi.h>
namespace fs = std::filesystem;
+extern "C" {
+ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
+ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+}
+
+HMODULE hLauncherModule;
+HMODULE hHookModule;
+HMODULE hTier0Module;
+
+wchar_t exePath[4096];
+wchar_t buffer[8192];
+
DWORD GetProcessByName(std::wstring processName)
{
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
@@ -33,132 +46,195 @@ DWORD GetProcessByName(std::wstring processName)
return 0;
}
-#define PROCESS_NAME L"Titanfall2-unpacked.exe"
-#define DLL_NAME L"Northstar.dll"
+bool GetExePathWide(wchar_t* dest, DWORD destSize)
+{
+ if (!dest) return NULL;
+ if (destSize < MAX_PATH) return NULL;
-int main(int argc, char* argv[]) {
- if (!fs::exists(PROCESS_NAME))
+ DWORD length = GetModuleFileNameW(NULL, dest, destSize);
+ return length && PathRemoveFileSpecW(dest);
+}
+
+FARPROC GetLauncherMain()
+{
+ static FARPROC Launcher_LauncherMain;
+ if (!Launcher_LauncherMain)
+ Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain");
+ return Launcher_LauncherMain;
+}
+
+void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location)
+{
+ char text[4096];
+ std::string message = std::system_category().message(dwMessageId);
+
+ sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs\n\nMake sure you followed the Northstar installation instructions carefully.", libName, location, dwMessageId, message.c_str());
+
+ if (!fs::exists("Titanfall2.exe") && fs::exists("..\\Titanfall2.exe"))
{
- MessageBoxA(0, "Titanfall2-unpacked.exe not found! Please launch from your titanfall 2 directory and ensure you have Northstar installed correctly!", "", MB_OK);
- return 1;
+ auto curDir = std::filesystem::current_path().filename().string();
+ auto aboveDir = std::filesystem::current_path().parent_path().filename().string();
+ sprintf_s(text, "%s\n\nWe detected that in your case you have extracted the files into a *subdirectory* of your Titanfall 2 installation.\nPlease move all the files and folders from current folder (\"%s\") into the Titanfall 2 installation directory just above (\"%s\").\n\nPlease try out the above steps by yourself before reaching out to the community for support.", text, curDir.c_str(), aboveDir.c_str());
}
- if (!fs::exists(DLL_NAME))
+ MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Error", 0);
+}
+
+void EnsureOriginStarted()
+{
+ if (GetProcessByName(L"Origin.exe") || GetProcessByName(L"EADesktop.exe"))
+ return; // already started
+
+ // unpacked exe will crash if origin isn't open on launch, so launch it
+ // get origin path from registry, code here is reversed from OriginSDK.dll
+ HKEY key;
+ if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Origin", 0, KEY_READ, &key) != ERROR_SUCCESS)
{
- MessageBoxA(0, "Northstar.dll not found! Please launch from your titanfall 2 directory and ensure you have Northstar installed correctly!", "", MB_OK);
- return 1;
+ MessageBoxA(0, "Error: failed reading Origin path!", "Northstar Launcher Error", MB_OK);
+ return;
}
- bool isdedi = false;
- for (int i = 0; i < argc; i++)
- if (!strcmp(argv[i], "-dedicated"))
- isdedi = true;
-
- if (!isdedi && !GetProcessByName(L"Origin.exe") && !GetProcessByName(L"EADesktop.exe"))
+ char originPath[520];
+ DWORD originPathLength = 520;
+ if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS)
{
- // unpacked exe will crash if origin isn't open on launch, so launch it
- // get origin path from registry, code here is reversed from OriginSDK.dll
- HKEY key;
- if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\WOW6432Node\\Origin", 0, KEY_READ, &key) != ERROR_SUCCESS)
- {
- MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK);
- return 1;
- }
+ MessageBoxA(0, "Error: failed reading Origin path!", "Northstar Launcher Error", MB_OK);
+ return;
+ }
- char originPath[520];
- DWORD originPathLength = 520;
- if (RegQueryValueExA(key, "ClientPath", 0, 0, (LPBYTE)&originPath, &originPathLength) != ERROR_SUCCESS)
- {
- MessageBoxA(0, "Error: failed reading origin path!", "", MB_OK);
- return 1;
- }
+ PROCESS_INFORMATION pi;
+ memset(&pi, 0, sizeof(pi));
+ STARTUPINFO si;
+ memset(&si, 0, sizeof(si));
+ CreateProcessA(originPath, (char*)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
- PROCESS_INFORMATION pi;
- memset(&pi, 0, sizeof(pi));
- STARTUPINFO si;
- memset(&si, 0, sizeof(si));
- CreateProcessA(originPath, (LPSTR)"", NULL, NULL, false, CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, (LPSTARTUPINFOA)&si, &pi);
+ printf("[*] Waiting for Origin...\n");
- // wait for origin to be ready, this process is created when origin is ready enough to launch game without any errors
- while (!GetProcessByName(L"OriginClientService.exe") && !GetProcessByName(L"EADesktop.exe"))
- Sleep(200);
- }
+ // wait for origin to be ready, this process is created when origin is ready enough to launch game without any errors
+ while (!GetProcessByName(L"OriginClientService.exe") && !GetProcessByName(L"EADesktop.exe"))
+ Sleep(200);
- // get cmdline args from file
- std::wstring args;
- std::ifstream cmdlineArgFile;
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+}
- args.append(L" ");
- for (int i = 0; i < argc; i++)
+void PrependPath()
+{
+ wchar_t* pPath;
+ size_t len;
+ errno_t err = _wdupenv_s(&pPath, &len, L"PATH");
+ if (!err)
{
- std::string str = argv[i];
-
- args.append(std::wstring(str.begin(), str.end()));
- args.append(L" ");
+ swprintf_s(buffer, L"PATH=%s\\bin\\x64_retail\\;%s", exePath, pPath);
+ auto result = _wputenv(buffer);
+ if (result == -1)
+ {
+ MessageBoxW(GetForegroundWindow(), L"Warning: could not prepend the current directory to app's PATH environment variable. Something may break because of that.", L"Northstar Launcher Warning", 0);
+ }
+ free(pPath);
}
-
- if (!isdedi)
- cmdlineArgFile = std::ifstream("ns_startup_args.txt");
else
- cmdlineArgFile = std::ifstream("ns_startup_args_dedi.txt");
-
- if (cmdlineArgFile)
{
- std::stringstream argBuffer;
- argBuffer << cmdlineArgFile.rdbuf();
- cmdlineArgFile.close();
-
- std::string str = argBuffer.str();
- args.append(std::wstring(str.begin(), str.end()));
+ MessageBoxW(GetForegroundWindow(), L"Warning: could not get current PATH environment variable in order to prepend the current directory to it. Something may break because of that.", L"Northstar Launcher Warning", 0);
}
+}
- //if (isdedi)
- // // copy -dedicated into args if we have it in commandline args
- // args.append(L" -dedicated");
-
- STARTUPINFO startupInfo;
- PROCESS_INFORMATION processInfo;
+bool ShouldLoadNorthstar(int argc, char* argv[])
+{
+ bool loadNorthstar = true;
+ for (int i = 0; i < argc; i++)
+ if (!strcmp(argv[i], "-vanilla"))
+ loadNorthstar = false;
- memset(&startupInfo, 0, sizeof(startupInfo));
- memset(&processInfo, 0, sizeof(processInfo));
+ if (!loadNorthstar)
+ return loadNorthstar;
- CreateProcessW(PROCESS_NAME, (LPWSTR)args.c_str(), NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &startupInfo, &processInfo);
+ auto runNorthstarFile = std::ifstream("run_northstar.txt");
+ if (runNorthstarFile)
+ {
+ std::stringstream runNorthstarFileBuffer;
+ runNorthstarFileBuffer << runNorthstarFile.rdbuf();
+ runNorthstarFile.close();
+ if (runNorthstarFileBuffer.str()._Starts_with("0"))
+ loadNorthstar = false;
+ }
+ return loadNorthstar;
+}
- HMODULE hKernel32 = GetModuleHandleW(L"kernel32.dll");
- LPTHREAD_START_ROUTINE pLoadLibraryW = (LPTHREAD_START_ROUTINE)GetProcAddress(hKernel32, "LoadLibraryW");
+bool LoadNorthstar()
+{
+ FARPROC Hook_Init = nullptr;
+ {
+ swprintf_s(buffer, L"%s\\Northstar.dll", exePath);
+ hHookModule = LoadLibraryExW(buffer, 0i64, 8u);
+ if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar");
+ if (!hHookModule || Hook_Init == nullptr)
+ {
+ LibraryLoadError(GetLastError(), L"Northstar.dll", buffer);
+ return false;
+ }
+ }
- SIZE_T dwLength = (wcslen(DLL_NAME) + 1) * 2;
- LPVOID lpLibName = VirtualAllocEx(processInfo.hProcess, NULL, dwLength, MEM_COMMIT, PAGE_READWRITE);
+ ((bool (*)()) Hook_Init)();
+ return true;
+}
- SIZE_T written = 0;
- WriteProcessMemory(processInfo.hProcess, lpLibName, DLL_NAME, dwLength, &written);
+int main(int argc, char* argv[]) {
- HANDLE hThread = CreateRemoteThread(processInfo.hProcess, NULL, NULL, pLoadLibraryW, lpLibName, NULL, NULL);
+ // checked to avoid starting origin, Northstar.dll will check for -dedicated as well on its own
+ bool noOriginStartup = false;
+ for (int i = 0; i < argc; i++)
+ if (!strcmp(argv[i], "-noOriginStartup") || !strcmp(argv[i], "-dedicated"))
+ noOriginStartup = true;
- if (hThread == NULL)
+ if (!noOriginStartup)
{
- // injection failed
-
- std::string errorMessage = "Injection failed! CreateRemoteThread returned ";
- errorMessage += std::to_string(GetLastError()).c_str();
- errorMessage += ", make sure bob hasn't accidentally shipped a debug build";
-
- MessageBoxA(0, errorMessage.c_str(), "", MB_OK);
- return 0;
+ EnsureOriginStarted();
}
- WaitForSingleObject(hThread, INFINITE);
-
- //MessageBoxA(0, std::to_string(GetLastError()).c_str(), "", MB_OK);
+ {
+ if (!GetExePathWide(exePath, sizeof(exePath)))
+ {
+ MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Launcher Error", 0);
+ return 1;
+ }
- CloseHandle(hThread);
+ PrependPath();
- ResumeThread(processInfo.hThread);
+ printf("[*] Loading tier0.dll\n");
+ swprintf_s(buffer, L"%s\\bin\\x64_retail\\tier0.dll", exePath);
+ hTier0Module = LoadLibraryExW(buffer, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hTier0Module)
+ {
+ LibraryLoadError(GetLastError(), L"tier0.dll", buffer);
+ return 1;
+ }
- VirtualFreeEx(processInfo.hProcess, lpLibName, dwLength, MEM_RELEASE);
+ bool loadNorthstar = ShouldLoadNorthstar(argc, argv);
+ if (loadNorthstar)
+ {
+ printf("[*] Loading Northstar\n");
+ if (!LoadNorthstar())
+ return 1;
+ }
+ else
+ printf("[*] Going to load the vanilla game\n");
- CloseHandle(processInfo.hProcess);
- CloseHandle(processInfo.hThread);
+ printf("[*] Loading launcher.dll\n");
+ swprintf_s(buffer, L"%s\\bin\\x64_retail\\launcher.dll", exePath);
+ hLauncherModule = LoadLibraryExW(buffer, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hLauncherModule)
+ {
+ LibraryLoadError(GetLastError(), L"launcher.dll", buffer);
+ return 1;
+ }
+ }
- return 0;
+ printf("[*] Launching the game...\n");
+ auto LauncherMain = GetLauncherMain();
+ if (!LauncherMain)
+ MessageBoxA(GetForegroundWindow(), "Failed loading launcher.dll.\nThe game cannot continue and has to exit.", "Northstar Launcher Error", 0);
+ //auto result = ((__int64(__fastcall*)())LauncherMain)();
+ //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64);
+ return ((int(/*__fastcall*/*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(NULL, NULL, NULL, 0); // the parameters aren't really used anyways
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
index bd0d9eb6..23b2cccf 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj
@@ -1,14 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
- <ProjectConfiguration Include="Debug|Win32">
- <Configuration>Debug</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
- <ProjectConfiguration Include="Release|Win32">
- <Configuration>Release</Configuration>
- <Platform>Win32</Platform>
- </ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
@@ -27,19 +19,6 @@
<ProjectName>Northstar</ProjectName>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>true</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
- <ConfigurationType>DynamicLibrary</ConfigurationType>
- <UseDebugLibraries>false</UseDebugLibraries>
- <PlatformToolset>v143</PlatformToolset>
- <WholeProgramOptimization>true</WholeProgramOptimization>
- <CharacterSet>Unicode</CharacterSet>
- </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
@@ -58,12 +37,6 @@
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
- <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
- </ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
@@ -71,56 +44,12 @@
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <LinkIncremental>true</LinkIncremental>
- </PropertyGroup>
- <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <LinkIncremental>false</LinkIncremental>
- </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;_DEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- <LanguageStandard>stdcpp17</LanguageStandard>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableUAC>false</EnableUAC>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
- <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
- <ClCompile>
- <WarningLevel>Level3</WarningLevel>
- <FunctionLevelLinking>true</FunctionLevelLinking>
- <IntrinsicFunctions>true</IntrinsicFunctions>
- <SDLCheck>true</SDLCheck>
- <PreprocessorDefinitions>WIN32;NDEBUG;NORTHSTARDEDICATEDTEST_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
- <ConformanceMode>true</ConformanceMode>
- <PrecompiledHeader>Use</PrecompiledHeader>
- <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
- <LanguageStandard>stdcpp17</LanguageStandard>
- </ClCompile>
- <Link>
- <SubSystem>Windows</SubSystem>
- <EnableCOMDATFolding>true</EnableCOMDATFolding>
- <OptimizeReferences>true</OptimizeReferences>
- <GenerateDebugInformation>true</GenerateDebugInformation>
- <EnableUAC>false</EnableUAC>
- <AdditionalDependencies>%(AdditionalDependencies)</AdditionalDependencies>
- </Link>
- </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
@@ -136,7 +65,7 @@
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
- <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;$(ProjectDir)include\libcurl\lib\libcurl_a.lib;dbghelp.lib;Wldap32.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcurl\lib\libcurl_a.lib;dbghelp.lib;Wldap32.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ForceSymbolReferences>
</ForceSymbolReferences>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -158,6 +87,7 @@
<PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
<LanguageStandard>stdcpp17</LanguageStandard>
<AdditionalIncludeDirectories>$(ProjectDir)include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
@@ -165,7 +95,7 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC>
- <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcrypto_static.lib;$(ProjectDir)include\libssl_static.lib;$(ProjectDir)include\libcurl\lib\libcurl_a.lib;dbghelp.lib;Wldap32.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <AdditionalDependencies>$(ProjectDir)include\MinHook.x64.lib;$(ProjectDir)include\libcurl\lib\libcurl_a.lib;dbghelp.lib;Wldap32.lib;Normaliz.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ForceSymbolReferences>
</ForceSymbolReferences>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
@@ -586,6 +516,7 @@
<ClInclude Include="include\spdlog\tweakme.h" />
<ClInclude Include="include\spdlog\version.h" />
<ClInclude Include="keyvalues.h" />
+ <ClInclude Include="languagehooks.h" />
<ClInclude Include="logging.h" />
<ClInclude Include="main.h" />
<ClInclude Include="masterserver.h" />
@@ -627,6 +558,7 @@
<ClCompile Include="hooks.cpp" />
<ClCompile Include="hookutils.cpp" />
<ClCompile Include="keyvalues.cpp" />
+ <ClCompile Include="languagehooks.cpp" />
<ClCompile Include="memalloc.cpp" />
<ClCompile Include="miscclientfixes.cpp" />
<ClCompile Include="misccommands.cpp" />
@@ -636,9 +568,7 @@
<ClCompile Include="masterserver.cpp" />
<ClCompile Include="modmanager.cpp" />
<ClCompile Include="pch.cpp">
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
- <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="pdef.cpp" />
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
index 8d6bc246..be15618c 100644
--- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
+++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters
@@ -1428,6 +1428,9 @@
<ClInclude Include="bansystem.h">
<Filter>Header Files\Server\Authentication</Filter>
</ClInclude>
+ <ClInclude Include="languagehooks.h">
+ <Filter>Header Files\Client</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="dllmain.cpp">
@@ -1544,6 +1547,9 @@
<ClCompile Include="bansystem.cpp">
<Filter>Source Files\Server\Authentication</Filter>
</ClCompile>
+ <ClCompile Include="languagehooks.cpp">
+ <Filter>Source Files\Client</Filter>
+ </ClCompile>
</ItemGroup>
<ItemGroup>
<None Include="include\spdlog\fmt\bundled\LICENSE.rst">
diff --git a/NorthstarDedicatedTest/convar.cpp b/NorthstarDedicatedTest/convar.cpp
index ed7e8dac..de460662 100644
--- a/NorthstarDedicatedTest/convar.cpp
+++ b/NorthstarDedicatedTest/convar.cpp
@@ -20,7 +20,7 @@ ConVar* RegisterConVar(const char* name, const char* defaultValue, int flags, co
ConVar* newVar = new ConVar;
conVarConstructor(newVar, name, defaultValue, flags, helpString);
- g_CustomConvars.insert(std::make_pair(name, newVar));
+ g_CustomConvars.emplace(name, newVar);
return newVar;
}
diff --git a/NorthstarDedicatedTest/dedicated.cpp b/NorthstarDedicatedTest/dedicated.cpp
index 83a9950a..8dedcdd9 100644
--- a/NorthstarDedicatedTest/dedicated.cpp
+++ b/NorthstarDedicatedTest/dedicated.cpp
@@ -6,13 +6,14 @@
bool IsDedicated()
{
- return CommandLine()->CheckParm("-dedicated");
+ //return CommandLine()->CheckParm("-dedicated");
+ return strstr(GetCommandLineA(), "-dedicated");
}
// CDedidcatedExports defs
struct CDedicatedExports; // forward declare
-typedef void (*DedicatedSys_PrintfType)(CDedicatedExports* dedicated, char* msg);
+typedef void (*DedicatedSys_PrintfType)(CDedicatedExports* dedicated, const char* msg);
typedef void (*DedicatedRunServerType)(CDedicatedExports* dedicated);
// would've liked to just do this as a class but have not been able to get it to work
@@ -26,7 +27,7 @@ struct CDedicatedExports
DedicatedRunServerType RunServer;
};
-void Sys_Printf(CDedicatedExports* dedicated, char* msg)
+void Sys_Printf(CDedicatedExports* dedicated, const char* msg)
{
spdlog::info("[DEDICATED PRINT] {}", msg);
}
@@ -35,7 +36,7 @@ typedef void(*CHostState__InitType)(CHostState* self);
void RunServer(CDedicatedExports* dedicated)
{
- Sys_Printf(dedicated, (char*)"CDedicatedExports::RunServer(): starting");
+ Sys_Printf(dedicated, "CDedicatedExports::RunServer(): starting");
// init hoststate, if we don't do this, we get a crash later on
CHostState__InitType CHostState__Init = (CHostState__InitType)((char*)GetModuleHandleA("engine.dll") + 0x16E110);
@@ -209,7 +210,7 @@ void InitialiseDedicated(HMODULE engineAddress)
TempReadWrite rw(ptr);
// remove call to Shader_Connect
- *ptr = 0x90;
+ *ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
@@ -246,7 +247,7 @@ void InitialiseDedicated(HMODULE engineAddress)
TempReadWrite rw(ptr);
// remove call to ui loading stuff
- *ptr = 0x90;
+ *ptr = (char)0x90;
*(ptr + 1) = (char)0x90;
*(ptr + 2) = (char)0x90;
*(ptr + 3) = (char)0x90;
@@ -382,23 +383,18 @@ void InitialiseDedicated(HMODULE engineAddress)
CommandLine()->AppendParm("+exec", "autoexec_ns_server");
}
-typedef void(*Tier0_InitOriginType)();
-Tier0_InitOriginType Tier0_InitOrigin;
-void Tier0_InitOriginHook()
+void InitialiseDedicatedOrigin(HMODULE baseAddress)
{
// disable origin on dedicated
// 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
- Tier0_InitOrigin();
-}
-void InitialiseDedicatedOrigin(HMODULE baseAddress)
-{
if (!IsDedicated())
return;
- HookEnabler hook;
- ENABLER_CREATEHOOK(hook, GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin"), &Tier0_InitOriginHook, reinterpret_cast<LPVOID*>(&Tier0_InitOrigin));
+ char* ptr = (char*)GetProcAddress(GetModuleHandleA("tier0.dll"), "Tier0_InitOrigin");
+ TempReadWrite rw(ptr);
+ *ptr = (char)0xC3; // ret
}
typedef void(*PrintFatalSquirrelErrorType)(void* sqvm);
diff --git a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
index 7097e11a..1d0e13b6 100644
--- a/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
+++ b/NorthstarDedicatedTest/dedicatedmaterialsystem.cpp
@@ -59,7 +59,7 @@ void InitialiseDedicatedMaterialSystem(HMODULE baseAddress)
TempReadWrite rw(ptr);
// make the game always use the error material
- *ptr = 0xE9;
+ *ptr = (char)0xE9;
*(ptr + 1) = (char)0x34;
*(ptr + 2) = (char)0x03;
*(ptr + 3) = (char)0x00;
diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp
index c7cfce8b..c5a914e5 100644
--- a/NorthstarDedicatedTest/dllmain.cpp
+++ b/NorthstarDedicatedTest/dllmain.cpp
@@ -28,6 +28,7 @@
#include "rpakfilesystem.h"
#include "bansystem.h"
#include "memalloc.h"
+#include "languagehooks.h"
bool initialised = false;
@@ -45,52 +46,49 @@ BOOL APIENTRY DllMain( HMODULE hModule,
break;
}
- if (!initialised)
- InitialiseNorthstar();
- initialised = true;
-
return TRUE;
}
void WaitForDebugger(HMODULE baseAddress)
{
// earlier waitfordebugger call than is in vanilla, just so we can debug stuff a little easier
- if (CommandLine()->CheckParm("-waitfordebugger"))
+ //if (CommandLine()->CheckParm("-waitfordebugger"))
+ if (strstr(GetCommandLineA(), "-waitfordebugger"))
{
spdlog::info("waiting for debugger...");
- spdlog::info("{} bytes have been statically allocated", g_iStaticAllocated);
while (!IsDebuggerPresent())
Sleep(100);
}
}
-// in the future this will be called from launcher instead of dllmain
-void InitialiseNorthstar()
+bool InitialiseNorthstar()
{
if (initialised)
{
- spdlog::error("Called InitialiseNorthstar more than once!");
- return;
+ //spdlog::warn("Called InitialiseNorthstar more than once!"); // it's actually 100% fine for that to happen
+ return false;
}
+
initialised = true;
+ curl_global_init_mem(CURL_GLOBAL_DEFAULT, _malloc_base, _free_base, _realloc_base, _strdup_base, _calloc_base);
+
InitialiseLogging();
// apply initial hooks
InstallInitialHooks();
InitialiseInterfaceCreationHooks();
- // adding a callback to tier0 won't work for some reason
- AddDllLoadCallback("launcher.dll", InitialiseTier0GameUtilFunctions);
+ AddDllLoadCallback("tier0.dll", InitialiseTier0GameUtilFunctions);
AddDllLoadCallback("engine.dll", WaitForDebugger);
AddDllLoadCallback("engine.dll", InitialiseEngineGameUtilFunctions);
AddDllLoadCallback("server.dll", InitialiseServerGameUtilFunctions);
// dedi patches
{
+ AddDllLoadCallback("tier0.dll", InitialiseDedicatedOrigin);
AddDllLoadCallback("engine.dll", InitialiseDedicated);
- AddDllLoadCallback("launcher.dll", InitialiseDedicatedOrigin);
AddDllLoadCallback("server.dll", InitialiseDedicatedServerGameDLL);
AddDllLoadCallback("materialsystem_dx11.dll", InitialiseDedicatedMaterialSystem);
// this fucking sucks, but seemingly we somehow load after rtech_game???? unsure how, but because of this we have to apply patches here, not on rtech_game load
@@ -102,6 +100,7 @@ void InitialiseNorthstar()
// client-exclusive patches
{
+ AddDllLoadCallback("tier0.dll", InitialiseTier0LanguageHooks);
AddDllLoadCallback("engine.dll", InitialiseClientEngineSecurityPatches);
AddDllLoadCallback("client.dll", InitialiseClientSquirrel);
AddDllLoadCallback("client.dll", InitialiseSourceConsole);
@@ -132,4 +131,9 @@ void InitialiseNorthstar()
// mod manager after everything else
AddDllLoadCallback("engine.dll", InitialiseModManager);
+
+ // run callbacks for any libraries that are already loaded by now
+ CallAllPendingDLLLoadCallbacks();
+
+ return true;
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/filesystem.cpp b/NorthstarDedicatedTest/filesystem.cpp
index 89eb9423..1fe3ec9d 100644
--- a/NorthstarDedicatedTest/filesystem.cpp
+++ b/NorthstarDedicatedTest/filesystem.cpp
@@ -57,7 +57,7 @@ std::string ReadVPKFile(const char* path)
char data[4096];
do
{
- bytesRead = (*g_Filesystem)->m_vtable2->Read(&(*g_Filesystem)->m_vtable2, data, std::size(data), fileHandle);
+ bytesRead = (*g_Filesystem)->m_vtable2->Read(&(*g_Filesystem)->m_vtable2, data, (int)std::size(data), fileHandle);
fileStream.write(data, bytesRead);
} while (bytesRead == std::size(data));
diff --git a/NorthstarDedicatedTest/gameutils.cpp b/NorthstarDedicatedTest/gameutils.cpp
index 642c44e6..1cbd8648 100644
--- a/NorthstarDedicatedTest/gameutils.cpp
+++ b/NorthstarDedicatedTest/gameutils.cpp
@@ -78,12 +78,32 @@ void InitialiseServerGameUtilFunctions(HMODULE baseAddress)
void InitialiseTier0GameUtilFunctions(HMODULE baseAddress)
{
- baseAddress = GetModuleHandleA("tier0.dll");
-
- CreateGlobalMemAlloc = (CreateGlobalMemAllocType)GetProcAddress(baseAddress, "CreateGlobalMemAlloc");
- g_pMemAllocSingleton = CreateGlobalMemAlloc();
-
- Error = (ErrorType)GetProcAddress(baseAddress, "Error");
- CommandLine = (CommandLineType)GetProcAddress(baseAddress, "CommandLine");
- Plat_FloatTime = (Plat_FloatTimeType)GetProcAddress(baseAddress, "Plat_FloatTime");
+ if (!baseAddress)
+ {
+ spdlog::critical("tier0 base address is null, but it should be already loaded");
+ throw "tier0 base address is null, but it should be already loaded";
+ }
+ if (g_pMemAllocSingleton)
+ return; // seems this function was already called
+ CreateGlobalMemAlloc = reinterpret_cast<CreateGlobalMemAllocType>(GetProcAddress(baseAddress, "CreateGlobalMemAlloc"));
+ IMemAlloc** ppMemAllocSingleton = reinterpret_cast<IMemAlloc**>(GetProcAddress(baseAddress, "g_pMemAllocSingleton"));
+ if (!ppMemAllocSingleton)
+ {
+ spdlog::critical("Address of g_pMemAllocSingleton is a null pointer, this should never happen");
+ throw "Address of g_pMemAllocSingleton is a null pointer, this should never happen";
+ }
+ if (!*ppMemAllocSingleton)
+ {
+ g_pMemAllocSingleton = CreateGlobalMemAlloc();
+ *ppMemAllocSingleton = g_pMemAllocSingleton;
+ spdlog::info("Created new g_pMemAllocSingleton");
+ }
+ else
+ {
+ g_pMemAllocSingleton = *ppMemAllocSingleton;
+ }
+
+ Error = reinterpret_cast<ErrorType>(GetProcAddress(baseAddress, "Error"));
+ CommandLine = reinterpret_cast<CommandLineType>(GetProcAddress(baseAddress, "CommandLine"));
+ Plat_FloatTime = reinterpret_cast<Plat_FloatTimeType>(GetProcAddress(baseAddress, "Plat_FloatTime"));
} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/gameutils.h b/NorthstarDedicatedTest/gameutils.h
index 8def57eb..43f387d1 100644
--- a/NorthstarDedicatedTest/gameutils.h
+++ b/NorthstarDedicatedTest/gameutils.h
@@ -7,10 +7,19 @@ class IMemAlloc
public:
struct VTable
{
- void* unknown[1];
- void* (*Alloc)(IMemAlloc* memAlloc, size_t nSize);
- void* unknown2[3];
- void (*Free)(IMemAlloc* memAlloc, void* pMem);
+ void* unknown[1]; // alloc debug
+ void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize);
+ void* unknown2[1]; // realloc debug
+ void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize);
+ void* unknown3[1]; // free #1
+ void (*Free) (IMemAlloc* memAlloc, void* pMem);
+ void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag
+ size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem);
+ void* unknown5[9]; // they all do literally nothing
+ void (*DumpStats) (IMemAlloc* memAlloc);
+ void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase);
+ void* unknown6[4];
+ int (*heapchk) (IMemAlloc* memAlloc);
};
VTable* m_vtable;
diff --git a/NorthstarDedicatedTest/hooks.cpp b/NorthstarDedicatedTest/hooks.cpp
index 3de8d483..0e653d4e 100644
--- a/NorthstarDedicatedTest/hooks.cpp
+++ b/NorthstarDedicatedTest/hooks.cpp
@@ -5,15 +5,31 @@
#include <wchar.h>
#include <iostream>
#include <vector>
+#include <fstream>
+#include <sstream>
+#include <filesystem>
+#include <Psapi.h>
+
+typedef LPSTR(*GetCommandLineAType)();
+LPSTR GetCommandLineAHook();
typedef HMODULE(*LoadLibraryExAType)(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+typedef HMODULE(*LoadLibraryAType)(LPCSTR lpLibFileName);
+HMODULE LoadLibraryAHook(LPCSTR lpLibFileName);
+
typedef HMODULE(*LoadLibraryExWType)(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags);
+typedef HMODULE(*LoadLibraryWType)(LPCWSTR lpLibFileName);
+HMODULE LoadLibraryWHook(LPCWSTR lpLibFileName);
+
+GetCommandLineAType GetCommandLineAOriginal;
LoadLibraryExAType LoadLibraryExAOriginal;
+LoadLibraryAType LoadLibraryAOriginal;
LoadLibraryExWType LoadLibraryExWOriginal;
+LoadLibraryWType LoadLibraryWOriginal;
void InstallInitialHooks()
{
@@ -21,8 +37,57 @@ void InstallInitialHooks()
spdlog::error("MH_Initialize failed");
HookEnabler hook;
+ ENABLER_CREATEHOOK(hook, &GetCommandLineA, &GetCommandLineAHook, reinterpret_cast<LPVOID*>(&GetCommandLineAOriginal));
ENABLER_CREATEHOOK(hook, &LoadLibraryExA, &LoadLibraryExAHook, reinterpret_cast<LPVOID*>(&LoadLibraryExAOriginal));
+ ENABLER_CREATEHOOK(hook, &LoadLibraryA, &LoadLibraryAHook, reinterpret_cast<LPVOID*>(&LoadLibraryAOriginal));
ENABLER_CREATEHOOK(hook, &LoadLibraryExW, &LoadLibraryExWHook, reinterpret_cast<LPVOID*>(&LoadLibraryExWOriginal));
+ ENABLER_CREATEHOOK(hook, &LoadLibraryW, &LoadLibraryWHook, reinterpret_cast<LPVOID*>(&LoadLibraryWOriginal));
+}
+
+LPSTR GetCommandLineAHook()
+{
+ static char* cmdlineModified;
+ static char* cmdlineOrg;
+
+ if (cmdlineOrg == nullptr || cmdlineModified == nullptr)
+ {
+ cmdlineOrg = GetCommandLineAOriginal();
+ bool isDedi = strstr(cmdlineOrg, "-dedicated"); // well, this one has to be a real argument
+
+ std::string args;
+ std::ifstream cmdlineArgFile;
+
+ // it looks like CommandLine() prioritizes parameters apprearing first, so we want the real commandline to take priority
+ // not to mention that cmdlineOrg starts with the EXE path
+ args.append(cmdlineOrg);
+ args.append(" ");
+
+ // append those from the file
+
+ cmdlineArgFile = std::ifstream(!isDedi ? "ns_startup_args.txt" : "ns_startup_args_dedi.txt");
+
+ if (cmdlineArgFile)
+ {
+ std::stringstream argBuffer;
+ argBuffer << cmdlineArgFile.rdbuf();
+ cmdlineArgFile.close();
+
+ args.append(argBuffer.str());
+ }
+
+ auto len = args.length();
+ cmdlineModified = new char[len + 1];
+ if (!cmdlineModified)
+ {
+ spdlog::error("malloc failed for command line");
+ return cmdlineOrg;
+ }
+ memcpy(cmdlineModified, args.c_str(), len + 1);
+
+ spdlog::info("Command line: {}", cmdlineModified);
+ }
+
+ return cmdlineModified;
}
// dll load callback stuff
@@ -46,21 +111,75 @@ void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback)
dllLoadCallbacks.push_back(callbackStruct);
}
-HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+void CallLoadLibraryACallbacks(LPCSTR lpLibFileName, HMODULE moduleAddress)
{
- HMODULE moduleAddress = LoadLibraryExAOriginal(lpLibFileName, hFile, dwFlags);
-
- if (moduleAddress)
+ for (auto& callbackStruct : dllLoadCallbacks)
+ {
+ if (!callbackStruct->called && strstr(lpLibFileName + (strlen(lpLibFileName) - callbackStruct->dll.length()), callbackStruct->dll.c_str()) != nullptr)
+ {
+ callbackStruct->callback(moduleAddress);
+ callbackStruct->called = true;
+ }
+ }
+}
+
+void CallLoadLibraryWCallbacks(LPCWSTR lpLibFileName, HMODULE moduleAddress)
+{
+ for (auto& callbackStruct : dllLoadCallbacks)
+ {
+ std::wstring wcharStrDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end());
+ const wchar_t* callbackDll = wcharStrDll.c_str();
+ if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcharStrDll.length()), callbackDll) != nullptr)
+ {
+ callbackStruct->callback(moduleAddress);
+ callbackStruct->called = true;
+ }
+ }
+}
+
+void CallAllPendingDLLLoadCallbacks()
+{
+ HMODULE hMods[1024];
+ HANDLE hProcess = GetCurrentProcess();
+ DWORD cbNeeded;
+ unsigned int i;
+
+ // Get a list of all the modules in this process.
+ if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded))
{
- for (auto& callbackStruct : dllLoadCallbacks)
+ for (i = 0; i < (cbNeeded / sizeof(HMODULE)); i++)
{
- if (!callbackStruct->called && strstr(lpLibFileName + (strlen(lpLibFileName) - strlen(callbackStruct->dll.c_str())), callbackStruct->dll.c_str()) != nullptr)
+ wchar_t szModName[MAX_PATH];
+
+ // Get the full path to the module's file.
+ if (GetModuleFileNameExW(hProcess, hMods[i], szModName, sizeof(szModName) / sizeof(TCHAR)))
{
- callbackStruct->callback(moduleAddress);
- callbackStruct->called = true;
+ CallLoadLibraryWCallbacks(szModName, hMods[i]);
}
}
}
+}
+
+HMODULE LoadLibraryExAHook(LPCSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
+{
+ HMODULE moduleAddress = LoadLibraryExAOriginal(lpLibFileName, hFile, dwFlags);
+
+ if (moduleAddress)
+ {
+ CallLoadLibraryACallbacks(lpLibFileName, moduleAddress);
+ }
+
+ return moduleAddress;
+}
+
+HMODULE LoadLibraryAHook(LPCSTR lpLibFileName)
+{
+ HMODULE moduleAddress = LoadLibraryAOriginal(lpLibFileName);
+
+ if (moduleAddress)
+ {
+ CallLoadLibraryACallbacks(lpLibFileName, moduleAddress);
+ }
return moduleAddress;
}
@@ -71,16 +190,19 @@ HMODULE LoadLibraryExWHook(LPCWSTR lpLibFileName, HANDLE hFile, DWORD dwFlags)
if (moduleAddress)
{
- for (auto& callbackStruct : dllLoadCallbacks)
- {
- std::wstring wcharStrDll = std::wstring(callbackStruct->dll.begin(), callbackStruct->dll.end());
- const wchar_t* callbackDll = wcharStrDll.c_str();
- if (!callbackStruct->called && wcsstr(lpLibFileName + (wcslen(lpLibFileName) - wcslen(callbackDll)), callbackDll) != nullptr)
- {
- callbackStruct->callback(moduleAddress);
- callbackStruct->called = true;
- }
- }
+ CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress);
+ }
+
+ return moduleAddress;
+}
+
+HMODULE LoadLibraryWHook(LPCWSTR lpLibFileName)
+{
+ HMODULE moduleAddress = LoadLibraryWOriginal(lpLibFileName);
+
+ if (moduleAddress)
+ {
+ CallLoadLibraryWCallbacks(lpLibFileName, moduleAddress);
}
return moduleAddress;
diff --git a/NorthstarDedicatedTest/hooks.h b/NorthstarDedicatedTest/hooks.h
index 972b38a6..10e4d4ba 100644
--- a/NorthstarDedicatedTest/hooks.h
+++ b/NorthstarDedicatedTest/hooks.h
@@ -4,4 +4,6 @@
void InstallInitialHooks();
typedef void(*DllLoadCallbackFuncType)(HMODULE moduleAddress);
-void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback); \ No newline at end of file
+void AddDllLoadCallback(std::string dll, DllLoadCallbackFuncType callback);
+
+void CallAllPendingDLLLoadCallbacks(); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/hookutils.cpp b/NorthstarDedicatedTest/hookutils.cpp
index e86c671c..8ab24a3b 100644
--- a/NorthstarDedicatedTest/hookutils.cpp
+++ b/NorthstarDedicatedTest/hookutils.cpp
@@ -38,7 +38,7 @@ void HookEnabler::CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOrigina
else
{
if (targetName != nullptr)
- spdlog::error("MH_CreateHook failed for function %s", targetName);
+ spdlog::error("MH_CreateHook failed for function {}", targetName);
else
spdlog::error("MH_CreateHook failed for unknown function");
}
@@ -51,7 +51,7 @@ HookEnabler::~HookEnabler()
if (MH_EnableHook(hook->targetAddress) != MH_OK)
{
if (hook->targetName != nullptr)
- spdlog::error("MH_EnableHook failed for function %s", hook->targetName);
+ spdlog::error("MH_EnableHook failed for function {}", hook->targetName);
else
spdlog::error("MH_EnableHook failed for unknown function");
}
diff --git a/NorthstarDedicatedTest/include/MinHook.x64.dll b/NorthstarDedicatedTest/include/MinHook.x64.dll
deleted file mode 100644
index b4f51c2e..00000000
--- a/NorthstarDedicatedTest/include/MinHook.x64.dll
+++ /dev/null
Binary files differ
diff --git a/NorthstarDedicatedTest/include/MinHook.x64.lib b/NorthstarDedicatedTest/include/MinHook.x64.lib
index 909fe682..213df08f 100644
--- a/NorthstarDedicatedTest/include/MinHook.x64.lib
+++ b/NorthstarDedicatedTest/include/MinHook.x64.lib
Binary files differ
diff --git a/NorthstarDedicatedTest/keyvalues.cpp b/NorthstarDedicatedTest/keyvalues.cpp
index 6de93822..b14ecf42 100644
--- a/NorthstarDedicatedTest/keyvalues.cpp
+++ b/NorthstarDedicatedTest/keyvalues.cpp
@@ -50,7 +50,7 @@ void ModManager::TryBuildKeyValues(const char* filename)
// copy over patch kv files, and add #bases to new file, last mods' patches should be applied first
// note: #include should be identical but it's actually just broken, thanks respawn
- for (int i = m_loadedMods.size() - 1; i > -1; i--)
+ for (int64_t i = m_loadedMods.size() - 1; i > -1; i--)
{
if (!m_loadedMods[i].Enabled)
continue;
@@ -92,6 +92,7 @@ void ModManager::TryBuildKeyValues(const char* filename)
char rootName[64];
memset(rootName, 0, sizeof(rootName));
+ rootName[63] = '\0';
// iterate until we hit an ascii char that isn't in a # command or comment to get root obj name
int i = 0;
diff --git a/NorthstarDedicatedTest/languagehooks.cpp b/NorthstarDedicatedTest/languagehooks.cpp
new file mode 100644
index 00000000..08bacaf9
--- /dev/null
+++ b/NorthstarDedicatedTest/languagehooks.cpp
@@ -0,0 +1,109 @@
+#include "pch.h"
+#include "languagehooks.h"
+#include "gameutils.h"
+#include <filesystem>
+#include <regex>
+
+namespace fs = std::filesystem;
+
+typedef char* (*GetGameLanguageType)();
+char* GetGameLanguage();
+
+typedef LANGID(*Tier0_DetectDefaultLanguageType)();
+
+GetGameLanguageType GetGameLanguageOriginal;
+
+bool CheckLangAudioExists(char* lang)
+{
+ std::string path{ "r2\\sound\\general_" };
+ path += lang;
+ path += ".mstr";
+ return fs::exists(path);
+}
+
+std::vector<std::string> file_list(fs::path dir, std::regex ext_pattern)
+{
+ std::vector<std::string> result;
+
+ using iterator = fs::directory_iterator;
+
+ const iterator end;
+ for (iterator iter{ dir }; iter != end; ++iter)
+ {
+ const std::string filename = iter->path().filename().string();
+ std::smatch matches;
+ if (fs::is_regular_file(*iter) && std::regex_match(filename, matches, ext_pattern))
+ {
+ result.push_back(std::move(matches.str(1)));
+ }
+ }
+
+ return result;
+}
+
+std::string GetAnyInstalledAudioLanguage()
+{
+ for (const auto& lang : file_list("r2\\sound\\", std::regex(".*?general_([a-z]+)_patch_1\\.mstr")))
+ if (lang != "general" || lang != "")
+ return lang;
+ return "NO LANGUAGE DETECTED";
+}
+
+char* GetGameLanguageHook()
+{
+ auto tier0Handle = GetModuleHandleA("tier0.dll");
+ auto Tier0_DetectDefaultLanguageType = GetProcAddress(tier0Handle, "Tier0_DetectDefaultLanguage");
+ char* ingameLang1 = (char*)tier0Handle + 0xA9B60; // one of the globals we need to override if overriding lang (size: 256)
+ bool& canOriginDictateLang = *(bool*)((char*)tier0Handle + 0xA9A90);
+
+ const char* forcedLanguage;
+ if (CommandLine()->CheckParm("-language", &forcedLanguage))
+ {
+ if (!CheckLangAudioExists((char*)forcedLanguage))
+ {
+ spdlog::info("User tried to force the language (-language) to \"{}\", but audio for this language doesn't exist and the game is bound to error, falling back to next option...", forcedLanguage);
+ }
+ else
+ {
+ spdlog::info("User forcing the language (-language) to: {}", forcedLanguage);
+ strncpy(ingameLang1, forcedLanguage, 256);
+ return ingameLang1;
+ }
+ }
+
+ canOriginDictateLang = true; // let it try
+ {
+ auto lang = GetGameLanguageOriginal();
+ if (!CheckLangAudioExists(lang))
+ {
+ spdlog::info("Origin detected language \"{}\", but we do not have audio for it installed, falling back to the next option", lang);
+
+ }
+ else
+ {
+ spdlog::info("Origin detected language: {}", lang);
+ return lang;
+ }
+ }
+
+ 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();
+ spdlog::info("Detected system language: {}", lang);
+ if (!CheckLangAudioExists(lang))
+ {
+ spdlog::warn("Caution, audio for this language does NOT exist. You might want to override your game language with -language command line option.");
+ auto lang = GetAnyInstalledAudioLanguage();
+ spdlog::warn("Falling back to first installed audio language: {}", lang.c_str());
+ strncpy(ingameLang1, lang.c_str(), 256);
+ return ingameLang1;
+ }
+
+ return lang;
+}
+
+void InitialiseTier0LanguageHooks(HMODULE baseAddress)
+{
+ HookEnabler hook;
+ ENABLER_CREATEHOOK(hook, (char*)baseAddress + 0xF560, &GetGameLanguageHook, reinterpret_cast<LPVOID*>(&GetGameLanguageOriginal));
+} \ No newline at end of file
diff --git a/NorthstarDedicatedTest/languagehooks.h b/NorthstarDedicatedTest/languagehooks.h
new file mode 100644
index 00000000..55b591e0
--- /dev/null
+++ b/NorthstarDedicatedTest/languagehooks.h
@@ -0,0 +1,3 @@
+#pragma once
+
+void InitialiseTier0LanguageHooks(HMODULE baseAddress);
diff --git a/NorthstarDedicatedTest/logging.cpp b/NorthstarDedicatedTest/logging.cpp
index e13a9150..7d5f7ae5 100644
--- a/NorthstarDedicatedTest/logging.cpp
+++ b/NorthstarDedicatedTest/logging.cpp
@@ -113,7 +113,7 @@ long __stdcall ExceptionFilter(EXCEPTION_POINTERS* exceptionInfo)
GetModuleFileNameExA(GetCurrentProcess(), crashedModuleHandle, crashedModuleFullName, MAX_PATH);
char* crashedModuleName = strrchr(crashedModuleFullName, '\\') + 1;
- DWORD crashedModuleOffset = ((DWORD)exceptionAddress) - ((DWORD)crashedModuleInfo.lpBaseOfDll);
+ 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:");
@@ -186,6 +186,7 @@ void InitialiseLogging()
AllocConsole();
freopen("CONOUT$", "w", stdout);
+ freopen("CONOUT$", "w", stderr);
spdlog::default_logger()->set_pattern("[%H:%M:%S] [%l] %v");
spdlog::flush_on(spdlog::level::info);
diff --git a/NorthstarDedicatedTest/main.h b/NorthstarDedicatedTest/main.h
index ef5d86dc..90e88912 100644
--- a/NorthstarDedicatedTest/main.h
+++ b/NorthstarDedicatedTest/main.h
@@ -1,3 +1,3 @@
#pragma once
-extern "C" __declspec(dllexport) void InitialiseNorthstar(); \ No newline at end of file
+extern "C" __declspec(dllexport) bool InitialiseNorthstar(); \ No newline at end of file
diff --git a/NorthstarDedicatedTest/masterserver.cpp b/NorthstarDedicatedTest/masterserver.cpp
index 0913be11..01f4bc8e 100644
--- a/NorthstarDedicatedTest/masterserver.cpp
+++ b/NorthstarDedicatedTest/masterserver.cpp
@@ -3,7 +3,6 @@
#include "concommand.h"
#include "gameutils.h"
#include "hookutils.h"
-#include "libcurl/include/curl/curl.h"
#include "serverauthentication.h"
#include "gameutils.h"
#include "rapidjson/document.h"
@@ -38,6 +37,39 @@ CHostState__State_ChangeLevelSPType CHostState__State_ChangeLevelSP;
typedef void(*CHostState__State_GameShutdownType)(CHostState* hostState);
CHostState__State_GameShutdownType CHostState__State_GameShutdown;
+const char* HttplibErrorToString(httplib::Error error)
+{
+ switch (error)
+ {
+ case httplib::Error::Success:
+ return "httplib::Error::Success";
+ case httplib::Error::Unknown:
+ return "httplib::Error::Unknown";
+ case httplib::Error::Connection:
+ return "httplib::Error::Connection";
+ case httplib::Error::BindIPAddress:
+ return "httplib::Error::BindIPAddress";
+ case httplib::Error::Read:
+ return "httplib::Error::Read";
+ case httplib::Error::Write:
+ return "httplib::Error::Write";
+ case httplib::Error::ExceedRedirectCount:
+ return "httplib::Error::ExceedRedirectCount";
+ case httplib::Error::Canceled:
+ return "httplib::Error::Canceled";
+ case httplib::Error::SSLConnection:
+ return "httplib::Error::SSLConnection";
+ case httplib::Error::SSLLoadingCerts:
+ return "httplib::Error::SSLLoadingCerts";
+ case httplib::Error::SSLServerVerification:
+ return "httplib::Error::SSLServerVerification";
+ case httplib::Error::UnsupportedMultipartBoundaryChars:
+ return "httplib::Error::UnsupportedMultipartBoundaryChars";
+ }
+
+ return "";
+}
+
RemoteServerInfo::RemoteServerInfo(const char* newId, const char* newName, const char* newDescription, const char* newMap, const char* newPlaylist, int newPlayerCount, int newMaxPlayers, bool newRequiresPassword)
{
// passworded servers don't have public ips
@@ -59,6 +91,18 @@ RemoteServerInfo::RemoteServerInfo(const char* newId, const char* newName, const
maxPlayers = newMaxPlayers;
}
+void MasterServerManager::SetCommonHttpClientOptions(CURL* curl)
+{
+ curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
+ //curl_easy_setopt(curl, CURLOPT_STDERR, stdout);
+ if (CommandLine()->FindParm("-msinsecure")) // TODO: this check doesn't seem to work
+ {
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
+ }
+}
+
void MasterServerManager::ClearServerList()
{
// this doesn't really do anything lol, probably isn't threadsafe
@@ -90,12 +134,11 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or
spdlog::info("Trying to authenticate with northstar masterserver for user {}", uidStr);
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/origin_auth?id={}&token={}", Cvar_ns_masterserver_hostname->m_pszString, uidStr, tokenStr).c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -105,12 +148,12 @@ void MasterServerManager::AuthenticateOriginWithMasterServer(char* uid, char* or
{
m_successfullyConnected = true;
- rapidjson::Document originAuthInfo;
+ rapidjson_document originAuthInfo;
originAuthInfo.Parse(readBuffer.c_str());
if (originAuthInfo.HasParseError())
{
- spdlog::error("Failed reading origin auth info response: encountered parse error \{}\"", rapidjson::GetParseError_En(originAuthInfo.GetParseError()));
+ spdlog::error("Failed reading origin auth info response: encountered parse error \"{}\"", rapidjson::GetParseError_En(originAuthInfo.GetParseError()));
goto REQUEST_END_CLEANUP;
}
@@ -163,12 +206,11 @@ void MasterServerManager::RequestServerList()
spdlog::info("Requesting server list from {}", Cvar_ns_masterserver_hostname->m_pszString);
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/servers", Cvar_ns_masterserver_hostname->m_pszString).c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -178,7 +220,7 @@ void MasterServerManager::RequestServerList()
{
m_successfullyConnected = true;
- rapidjson::Document serverInfoJson;
+ rapidjson_document serverInfoJson;
serverInfoJson.Parse(readBuffer.c_str());
if (serverInfoJson.HasParseError())
@@ -200,7 +242,7 @@ void MasterServerManager::RequestServerList()
goto REQUEST_END_CLEANUP;
}
- rapidjson::GenericArray<false, rapidjson::Value> serverArray = serverInfoJson.GetArray();
+ rapidjson::GenericArray<false, rapidjson_document::GenericValue> serverArray = serverInfoJson.GetArray();
spdlog::info("Got {} servers", serverArray.Size());
@@ -273,7 +315,7 @@ void MasterServerManager::RequestServerList()
std::sort(m_remoteServers.begin(), m_remoteServers.end(), [](RemoteServerInfo& a, RemoteServerInfo& b)
{
return a.playerCount > b.playerCount;
- });
+ });
}
else
{
@@ -301,12 +343,11 @@ void MasterServerManager::RequestMainMenuPromos()
Sleep(500);
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/mainmenupromos", Cvar_ns_masterserver_hostname->m_pszString).c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -316,7 +357,7 @@ void MasterServerManager::RequestMainMenuPromos()
{
m_successfullyConnected = true;
- rapidjson::Document mainMenuPromoJson;
+ rapidjson_document mainMenuPromoJson;
mainMenuPromoJson.Parse(readBuffer.c_str());
if (mainMenuPromoJson.HasParseError())
@@ -412,12 +453,11 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken
std::thread requestThread([this, uidStr, tokenStr]()
{
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/client/auth_with_self?id={}&playerToken={}", Cvar_ns_masterserver_hostname->m_pszString, uidStr, tokenStr).c_str());
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -427,7 +467,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken
{
m_successfullyConnected = true;
- rapidjson::Document authInfoJson;
+ rapidjson_document authInfoJson;
authInfoJson.Parse(readBuffer.c_str());
if (authInfoJson.HasParseError())
@@ -480,7 +520,7 @@ void MasterServerManager::AuthenticateWithOwnServer(char* uid, char* playerToken
goto REQUEST_END_CLEANUP;
}
- newAuthData.pdata[i++] = (char)byte.GetUint();
+ newAuthData.pdata[i++] = static_cast<char>(byte.GetUint());
}
std::lock_guard<std::mutex> guard(g_ServerAuthenticationManager->m_authDataMutex);
@@ -538,11 +578,10 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c
spdlog::info("Attempting authentication with server of id \"{}\"", serverIdStr);
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -560,7 +599,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c
{
m_successfullyConnected = true;
- rapidjson::Document connectionInfoJson;
+ rapidjson_document connectionInfoJson;
connectionInfoJson.Parse(readBuffer.c_str());
if (connectionInfoJson.HasParseError())
@@ -595,7 +634,7 @@ void MasterServerManager::AuthenticateWithServer(char* uid, char* playerToken, c
}
m_pendingConnectionInfo.ip.S_un.S_addr = inet_addr(connectionInfoJson["ip"].GetString());
- m_pendingConnectionInfo.port = connectionInfoJson["port"].GetInt();
+ m_pendingConnectionInfo.port = (unsigned short)connectionInfoJson["port"].GetUint();
strncpy(m_pendingConnectionInfo.authToken, connectionInfoJson["authToken"].GetString(), 31);
m_pendingConnectionInfo.authToken[31] = 0;
@@ -645,37 +684,36 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name
m_ownServerAuthToken[0] = 0;
// build modinfo obj
- rapidjson::Document modinfoDoc;
+ rapidjson_document modinfoDoc;
modinfoDoc.SetObject();
- modinfoDoc.AddMember("Mods", rapidjson::Value(rapidjson::kArrayType), modinfoDoc.GetAllocator());
+ modinfoDoc.AddMember("Mods", rapidjson_document::GenericValue(rapidjson::kArrayType), modinfoDoc.GetAllocator());
- int currentModIndex = 0;
- for (Mod& mod : g_ModManager->m_loadedMods)
- {
- if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size()))
- continue;
+ int currentModIndex = 0;
+ for (Mod& mod : g_ModManager->m_loadedMods)
+ {
+ if (!mod.Enabled || (!mod.RequiredOnClient && !mod.Pdiff.size()))
+ continue;
- modinfoDoc["Mods"].PushBack(rapidjson::Value(rapidjson::kObjectType), modinfoDoc.GetAllocator());
- modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator());
- modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator());
- modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator());
- modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator());
+ modinfoDoc["Mods"].PushBack(rapidjson_document::GenericValue(rapidjson::kObjectType), modinfoDoc.GetAllocator());
+ modinfoDoc["Mods"][currentModIndex].AddMember("Name", rapidjson::StringRef(&mod.Name[0]), modinfoDoc.GetAllocator());
+ modinfoDoc["Mods"][currentModIndex].AddMember("Version", rapidjson::StringRef(&mod.Version[0]), modinfoDoc.GetAllocator());
+ modinfoDoc["Mods"][currentModIndex].AddMember("RequiredOnClient", mod.RequiredOnClient, modinfoDoc.GetAllocator());
+ modinfoDoc["Mods"][currentModIndex].AddMember("Pdiff", rapidjson::StringRef(&mod.Pdiff[0]), modinfoDoc.GetAllocator());
- currentModIndex++;
- }
+ currentModIndex++;
+ }
- rapidjson::StringBuffer buffer;
- buffer.Clear();
- rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
- modinfoDoc.Accept(writer);
- const char* modInfoString = buffer.GetString();
+ rapidjson::StringBuffer buffer;
+ buffer.Clear();
+ rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
+ modinfoDoc.Accept(writer);
+ const char* modInfoString = buffer.GetString();
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_POST, 1L);
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -712,7 +750,7 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name
{
m_successfullyConnected = true;
- rapidjson::Document serverAddedJson;
+ rapidjson_document serverAddedJson;
serverAddedJson.Parse(readBuffer.c_str());
if (serverAddedJson.HasParseError())
@@ -746,8 +784,8 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name
goto REQUEST_END_CLEANUP;
}
- strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId));
- m_ownServerId[sizeof(m_ownServerId) - 1] = 0;
+ strncpy(m_ownServerId, serverAddedJson["id"].GetString(), sizeof(m_ownServerId));
+ m_ownServerId[sizeof(m_ownServerId) - 1] = 0;
strncpy(m_ownServerAuthToken, serverAddedJson["serverAuthToken"].GetString(), sizeof(m_ownServerAuthToken));
m_ownServerAuthToken[sizeof(m_ownServerAuthToken) - 1] = 0;
@@ -760,13 +798,14 @@ void MasterServerManager::AddSelfToServerList(int port, int authPort, char* name
do
{
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/server/heartbeat?id={}&playerCount={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, g_ServerAuthenticationManager->m_additionalPlayerData.size()).c_str());
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
+ curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
CURLcode result = curl_easy_perform(curl);
if (result != CURLcode::CURLE_OK)
@@ -805,11 +844,10 @@ void MasterServerManager::UpdateServerMapAndPlaylist(char* map, char* playlist,
std::thread requestThread([this, strMap, strPlaylist, maxPlayers]
{
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -846,11 +884,10 @@ void MasterServerManager::UpdateServerPlayerCount(int playerCount)
std::thread requestThread([this, playerCount]
{
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/server/update_values?id={}&playerCount={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId, playerCount).c_str());
@@ -884,12 +921,11 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata,
std::thread requestThread([this, strPlayerId, strPdata, pdataSize]
{
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/accounts/write_persistence?id={}&serverId={}", Cvar_ns_masterserver_hostname->m_pszString, strPlayerId, m_ownServerId).c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
@@ -912,7 +948,7 @@ void MasterServerManager::WritePlayerPersistentData(char* playerId, char* pdata,
curl_easy_cleanup(curl);
- m_savingPersistentData = false;
+ m_savingPersistentData = false;
});
requestThread.detach();
@@ -926,11 +962,10 @@ void MasterServerManager::RemoveSelfFromServerList()
std::thread requestThread([this] {
CURL* curl = curl_easy_init();
+ SetCommonHttpClientOptions(curl);
std::string readBuffer;
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
- curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
- curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlWriteToStringBufferCallback);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
curl_easy_setopt(curl, CURLOPT_URL, fmt::format("{}/server/remove_server?id={}", Cvar_ns_masterserver_hostname->m_pszString, m_ownServerId).c_str());
@@ -1004,9 +1039,9 @@ void CHostState__State_GameShutdownHook(CHostState* hostState)
CHostState__State_GameShutdown(hostState);
}
-MasterServerManager::MasterServerManager()
+MasterServerManager::MasterServerManager() : m_pendingConnectionInfo{}, m_ownServerId{ "" }, m_ownClientAuthToken{ "" }
{
- curl_global_init(CURL_GLOBAL_DEFAULT);
+
}
void InitialiseSharedMasterServer(HMODULE baseAddress)
diff --git a/NorthstarDedicatedTest/masterserver.h b/NorthstarDedicatedTest/masterserver.h
index b4d0d476..d3c83052 100644
--- a/NorthstarDedicatedTest/masterserver.h
+++ b/NorthstarDedicatedTest/masterserver.h
@@ -37,7 +37,7 @@ public:
char authToken[32];
in_addr ip;
- int port;
+ unsigned short port;
};
struct MainMenuPromoData
@@ -93,6 +93,9 @@ public:
bool m_bHasMainMenuPromoData = false;
MainMenuPromoData m_MainMenuPromoData;
+private:
+ void SetCommonHttpClientOptions(CURL* curl);
+
public:
MasterServerManager();
void ClearServerList();
diff --git a/NorthstarDedicatedTest/memalloc.cpp b/NorthstarDedicatedTest/memalloc.cpp
index 113f56b9..1b9eaae8 100644
--- a/NorthstarDedicatedTest/memalloc.cpp
+++ b/NorthstarDedicatedTest/memalloc.cpp
@@ -2,39 +2,76 @@
#include "memalloc.h"
#include "gameutils.h"
-// so for anyone reading this code, you may be curious why the fuck i'm overriding new to alloc into a static 100k buffer
-// pretty much, the issue here is that we need to use the game's memory allocator (g_pMemAllocSingleton) or risk heap corruptions, but this allocator is defined in tier0
-// as such, it doesn't exist when we inject
-// initially i wanted to just call malloc and free until g_pMemAllocSingleton was initialised, but the issue then becomes that we might try to
-// call g_pMemAllocSingleton->Free on memory that was allocated with malloc, which will cause game to crash
-// so, the best idea i had for this was to just alloc 100k of memory, have all pre-tier0 allocations use that
-// (from what i can tell we hit about 12k before tier0 is loaded atm in debug builds, so it's more than enough)
-// then just use the game's allocator after that
-// yes, this means we leak 100k of memory, idk how else to do this without breaking stuff
+// TODO: rename to malloc and free after removing statically compiled .libs
-const int STATIC_ALLOC_SIZE = 100000; // alot more than we need, could reduce to 50k or even 25k later potentially
-
-size_t g_iStaticAllocated = 0;
-char pStaticAllocBuf[STATIC_ALLOC_SIZE];
-
-void* operator new(size_t n)
+extern "C" void* _malloc_base(size_t n)
{
// allocate into static buffer if g_pMemAllocSingleton isn't initialised
- if (g_pMemAllocSingleton)
- return g_pMemAllocSingleton->m_vtable->Alloc(g_pMemAllocSingleton, n);
- else
+ if (!g_pMemAllocSingleton)
{
- void* ret = pStaticAllocBuf + g_iStaticAllocated;
- g_iStaticAllocated += n;
- return ret;
- }
+ InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll"));
+ }
+ return g_pMemAllocSingleton->m_vtable->Alloc(g_pMemAllocSingleton, n);
}
-void operator delete(void* p)
+/*extern "C" void* malloc(size_t n)
{
- // if it was allocated into the static buffer, just do nothing, safest way to deal with it
- if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE)
- return;
+ return _malloc_base(n);
+}*/
+extern "C" void _free_base(void* p)
+{
+ if (!g_pMemAllocSingleton)
+ {
+ spdlog::warn("Trying to free something before g_pMemAllocSingleton was ready, this should never happen");
+ InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll"));
+ }
g_pMemAllocSingleton->m_vtable->Free(g_pMemAllocSingleton, p);
-} \ No newline at end of file
+}
+
+
+extern "C" void* _realloc_base(void* oldPtr, size_t size)
+{
+ if (!g_pMemAllocSingleton)
+ {
+ InitialiseTier0GameUtilFunctions(GetModuleHandleA("tier0.dll"));
+ }
+ return g_pMemAllocSingleton->m_vtable->Realloc(g_pMemAllocSingleton, oldPtr, size);
+}
+
+extern "C" void* _calloc_base(size_t n, size_t size)
+{
+ size_t bytes = n * size;
+ void* memory = _malloc_base(bytes);
+ if (memory)
+ {
+ memset(memory, 0, bytes);
+ }
+ return memory;
+}
+
+extern "C" char* _strdup_base(const char* src)
+{
+ char* str;
+ char* p;
+ int len = 0;
+
+ while (src[len])
+ len++;
+ str = reinterpret_cast<char*>(_malloc_base(len + 1));
+ p = str;
+ while (*src)
+ *p++ = *src++;
+ *p = '\0';
+ return str;
+}
+
+void* operator new(size_t n)
+{
+ return _malloc_base(n);
+}
+
+void operator delete(void* p)
+{
+ _free_base(p);
+}// /FORCE:MULTIPLE \ No newline at end of file
diff --git a/NorthstarDedicatedTest/memalloc.h b/NorthstarDedicatedTest/memalloc.h
index fe3c5255..92ab9672 100644
--- a/NorthstarDedicatedTest/memalloc.h
+++ b/NorthstarDedicatedTest/memalloc.h
@@ -1,6 +1,42 @@
#pragma once
-extern size_t g_iStaticAllocated;
+#include "include/rapidjson/document.h"
+//#include "include/rapidjson/allocators.h"
+
+extern "C" void* _malloc_base(size_t size);
+extern "C" void* _calloc_base(size_t const count, size_t const size);
+extern "C" void* _realloc_base(void* block, size_t size);
+extern "C" void* _recalloc_base(void* const block, size_t const count, size_t const size);
+extern "C" void _free_base(void* const block);
+extern "C" char* _strdup_base(const char* src);
void* operator new(size_t n);
-void operator delete(void* p); \ No newline at end of file
+void operator delete(void* p);
+
+//void* malloc(size_t n);
+
+class SourceAllocator {
+public:
+ static const bool kNeedFree = true;
+ void* Malloc(size_t size) {
+ if (size) // behavior of malloc(0) is implementation defined.
+ return _malloc_base(size);
+ else
+ return NULL; // standardize to returning NULL.
+ }
+ void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+ (void)originalSize;
+ if (newSize == 0) {
+ _free_base(originalPtr);
+ return NULL;
+ }
+ return _realloc_base(originalPtr, newSize);
+ }
+ static void Free(void* ptr) { _free_base(ptr); }
+};
+
+typedef rapidjson::GenericDocument<rapidjson::UTF8<>, rapidjson::MemoryPoolAllocator<SourceAllocator>, SourceAllocator> rapidjson_document;
+//typedef rapidjson::GenericDocument<rapidjson::UTF8<>, SourceAllocator, SourceAllocator> rapidjson_document;
+//typedef rapidjson::Document rapidjson_document;
+//using MyDocument = rapidjson::GenericDocument<rapidjson::UTF8<>, MemoryAllocator>;
+//using rapidjson_document = rapidjson::GenericDocument<rapidjson::UTF8<>, SourceAllocator, SourceAllocator>;
diff --git a/NorthstarDedicatedTest/modmanager.cpp b/NorthstarDedicatedTest/modmanager.cpp
index 4f4a2da0..23dd2d6e 100644
--- a/NorthstarDedicatedTest/modmanager.cpp
+++ b/NorthstarDedicatedTest/modmanager.cpp
@@ -22,7 +22,7 @@ Mod::Mod(fs::path modDir, char* jsonBuf)
ModDirectory = modDir;
- rapidjson::Document modJson;
+ rapidjson_document modJson;
modJson.Parse<rapidjson::ParseFlag::kParseCommentsFlag | rapidjson::ParseFlag::kParseTrailingCommasFlag>(jsonBuf);
// fail if parse error
@@ -309,7 +309,7 @@ void ModManager::LoadMods()
if (fs::is_regular_file(file))
{
std::string kvStr = file.path().lexically_relative(mod.ModDirectory / "keyvalues").lexically_normal().string();
- mod.KeyValues.insert(std::make_pair(std::hash<std::string>{}(kvStr), kvStr));
+ mod.KeyValues.emplace(std::hash<std::string>{}(kvStr), kvStr);
}
}
}
@@ -333,7 +333,7 @@ void ModManager::LoadMods()
}
// in a seperate loop because we register mod files in reverse order, since mods loaded later should have their files prioritised
- for (int i = m_loadedMods.size() - 1; i > -1; i--)
+ for (int64_t i = m_loadedMods.size() - 1; i > -1; i--)
{
if (!m_loadedMods[i].Enabled)
continue;
@@ -379,7 +379,7 @@ void ModManager::UnloadMods()
// should we be doing this here or should scripts be doing this manually?
// main issue with doing this here is when we reload mods for connecting to a server, we write enabled mods, which isn't necessarily what we wanna do
if (!m_enabledModsCfg.HasMember(mod.Name.c_str()))
- m_enabledModsCfg.AddMember(rapidjson::StringRef(mod.Name.c_str()), rapidjson::Value(false), m_enabledModsCfg.GetAllocator());
+ m_enabledModsCfg.AddMember(rapidjson_document::StringRefType(mod.Name.c_str()), rapidjson_document::GenericValue(false), m_enabledModsCfg.GetAllocator());
m_enabledModsCfg[mod.Name.c_str()].SetBool(mod.Enabled);
}
diff --git a/NorthstarDedicatedTest/modmanager.h b/NorthstarDedicatedTest/modmanager.h
index 5f2f6441..20cb0a42 100644
--- a/NorthstarDedicatedTest/modmanager.h
+++ b/NorthstarDedicatedTest/modmanager.h
@@ -4,6 +4,7 @@
#include <vector>
#include <filesystem>
#include "rapidjson/document.h"
+#include "memalloc.h"
namespace fs = std::filesystem;
@@ -100,7 +101,7 @@ class ModManager
private:
bool m_hasLoadedMods = false;
bool m_hasEnabledModsCfg;
- rapidjson::Document m_enabledModsCfg;
+ rapidjson_document m_enabledModsCfg;
// precalculated hashes
size_t m_hScriptsRsonHash;
diff --git a/NorthstarDedicatedTest/pch.h b/NorthstarDedicatedTest/pch.h
index 9ac5b8a9..a07d1401 100644
--- a/NorthstarDedicatedTest/pch.h
+++ b/NorthstarDedicatedTest/pch.h
@@ -11,10 +11,12 @@
// httplib ssl
// add headers that you want to pre-compile here
+#include "memalloc.h"
#include <Windows.h>
#include "logging.h"
#include "include/MinHook.h"
#include "spdlog/spdlog.h"
+#include "libcurl/include/curl/curl.h"
#include "hookutils.h"
#endif \ No newline at end of file
diff --git a/NorthstarDedicatedTest/playlist.cpp b/NorthstarDedicatedTest/playlist.cpp
index 59a13a26..9cbd0c05 100644
--- a/NorthstarDedicatedTest/playlist.cpp
+++ b/NorthstarDedicatedTest/playlist.cpp
@@ -95,7 +95,7 @@ void InitialisePlaylistHooks(HMODULE baseAddress)
{
void* ptr = (char*)baseAddress + 0x18ED8D;
TempReadWrite rw(ptr);
- *((char*)ptr) = 0xC3; // jmp => ret
+ *((char*)ptr) = (char)0xC3; // jmp => ret
}
if (IsDedicated())
diff --git a/NorthstarDedicatedTest/serverauthentication.cpp b/NorthstarDedicatedTest/serverauthentication.cpp
index 1093ff7f..da84280c 100644
--- a/NorthstarDedicatedTest/serverauthentication.cpp
+++ b/NorthstarDedicatedTest/serverauthentication.cpp
@@ -168,7 +168,7 @@ bool ServerAuthenticationManager::AuthenticatePlayer(void* player, int64_t uid,
// get file length
pdataStream.seekg(0, pdataStream.end);
- int length = pdataStream.tellg();
+ auto length = pdataStream.tellg();
pdataStream.seekg(0, pdataStream.beg);
// copy pdata into buffer
diff --git a/R2Northstar.sln b/R2Northstar.sln
index 1b664dd9..3dfdb218 100644
--- a/R2Northstar.sln
+++ b/R2Northstar.sln
@@ -1,35 +1,38 @@

Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 16
-VisualStudioVersion = 16.0.30621.155
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.32014.148
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Northstar", "NorthstarDedicatedTest\NorthstarDedicatedTest.vcxproj", "{CFAD2623-064F-453C-8196-79EE10292E32}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NorthstarLauncher", "LauncherInjector\LauncherInjector.vcxproj", "{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader_launcher_proxy", "loader_launcher_proxy\loader_launcher_proxy.vcxproj", "{F65C322D-66DF-4AF1-B650-70221DE334C0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader_wsock32_proxy", "loader_wsock32_proxy\loader_wsock32_proxy.vcxproj", "{CF55F3B5-F348-450A-9CCB-C269F21D629D}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
Release|x64 = Release|x64
- Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x64.ActiveCfg = Debug|x64
{CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x64.Build.0 = Debug|x64
- {CFAD2623-064F-453C-8196-79EE10292E32}.Debug|x86.ActiveCfg = Debug|Win32
{CFAD2623-064F-453C-8196-79EE10292E32}.Release|x64.ActiveCfg = Release|x64
{CFAD2623-064F-453C-8196-79EE10292E32}.Release|x64.Build.0 = Release|x64
- {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x86.ActiveCfg = Release|Win32
- {CFAD2623-064F-453C-8196-79EE10292E32}.Release|x86.Build.0 = Release|Win32
{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x64.ActiveCfg = Debug|x64
{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x64.Build.0 = Debug|x64
- {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x86.ActiveCfg = Debug|Win32
- {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Debug|x86.Build.0 = Debug|Win32
{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x64.ActiveCfg = Release|x64
{0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x64.Build.0 = Release|x64
- {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.ActiveCfg = Release|Win32
- {0EA82CB0-53FE-4D4C-96DF-47FA970513D0}.Release|x86.Build.0 = Release|Win32
+ {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.ActiveCfg = Debug|x64
+ {F65C322D-66DF-4AF1-B650-70221DE334C0}.Debug|x64.Build.0 = Debug|x64
+ {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.ActiveCfg = Release|x64
+ {F65C322D-66DF-4AF1-B650-70221DE334C0}.Release|x64.Build.0 = Release|x64
+ {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Debug|x64.ActiveCfg = Debug|x64
+ {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Debug|x64.Build.0 = Debug|x64
+ {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Release|x64.ActiveCfg = Release|x64
+ {CF55F3B5-F348-450A-9CCB-C269F21D629D}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/loader_launcher_proxy/Memory.cpp b/loader_launcher_proxy/Memory.cpp
new file mode 100644
index 00000000..f00c4d96
--- /dev/null
+++ b/loader_launcher_proxy/Memory.cpp
@@ -0,0 +1,84 @@
+#include "pch.h"
+
+extern HMODULE hTier0Module;
+IMemAlloc** g_ppMemAllocSingleton;
+
+void LoadTier0Handle()
+{
+ if (!hTier0Module) hTier0Module = GetModuleHandleA("tier0.dll");
+ if (!hTier0Module) return;
+
+ g_ppMemAllocSingleton = (IMemAlloc**)GetProcAddress(hTier0Module, "g_pMemAllocSingleton");
+}
+
+const int STATIC_ALLOC_SIZE = 4096;
+
+size_t g_iStaticAllocated = 0;
+void* g_pLastAllocated = nullptr;
+char pStaticAllocBuf[STATIC_ALLOC_SIZE];
+
+// they should never be used here, except in LibraryLoadError?
+
+void* malloc(size_t n)
+{
+ // allocate into static buffer
+ if (g_iStaticAllocated + n <= STATIC_ALLOC_SIZE)
+ {
+ void* ret = pStaticAllocBuf + g_iStaticAllocated;
+ g_iStaticAllocated += n;
+ return ret;
+ }
+ else
+ {
+ // try to fallback to g_pMemAllocSingleton
+ if (!hTier0Module || !g_ppMemAllocSingleton) LoadTier0Handle();
+ if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton)
+ return (*g_ppMemAllocSingleton)->m_vtable->Alloc(*g_ppMemAllocSingleton, n);
+ else
+ throw "Cannot allocate";
+ }
+}
+
+void free(void* p)
+{
+ // if it was allocated into the static buffer, just do nothing, safest way to deal with it
+ if (p >= pStaticAllocBuf && p <= pStaticAllocBuf + STATIC_ALLOC_SIZE)
+ return;
+
+ if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton)
+ (*g_ppMemAllocSingleton)->m_vtable->Free(*g_ppMemAllocSingleton, p);
+}
+
+void* realloc(void* old_ptr, size_t size) {
+ // it was allocated into the static buffer
+ if (old_ptr >= pStaticAllocBuf && old_ptr <= pStaticAllocBuf + STATIC_ALLOC_SIZE)
+ {
+ if (g_pLastAllocated == old_ptr)
+ {
+ // nothing was allocated after this
+ size_t old_size = g_iStaticAllocated - ((size_t)g_pLastAllocated - (size_t)pStaticAllocBuf);
+ size_t diff = size - old_size;
+ if (diff > 0)
+ g_iStaticAllocated += diff;
+ return old_ptr;
+ }
+ else
+ {
+ return malloc(size);
+ }
+ }
+
+ if (g_ppMemAllocSingleton && *g_ppMemAllocSingleton)
+ return (*g_ppMemAllocSingleton)->m_vtable->Realloc(*g_ppMemAllocSingleton, old_ptr, size);
+ return nullptr;
+}
+
+void* operator new(size_t n)
+{
+ return malloc(n);
+}
+
+void operator delete(void* p)
+{
+ return free(p);
+}
diff --git a/loader_launcher_proxy/Memory.h b/loader_launcher_proxy/Memory.h
new file mode 100644
index 00000000..c983966c
--- /dev/null
+++ b/loader_launcher_proxy/Memory.h
@@ -0,0 +1,24 @@
+#pragma once
+
+class IMemAlloc
+{
+public:
+ struct VTable
+ {
+ void* unknown[1]; // alloc debug
+ void* (*Alloc) (IMemAlloc* memAlloc, size_t nSize);
+ void* unknown2[1]; // realloc debug
+ void* (*Realloc)(IMemAlloc* memAlloc, void* pMem, size_t nSize);
+ void* unknown3[1]; // free #1
+ void (*Free) (IMemAlloc* memAlloc, void* pMem);
+ void* unknown4[2]; // nullsubs, maybe CrtSetDbgFlag
+ size_t(*GetSize) (IMemAlloc* memAlloc, void* pMem);
+ void* unknown5[9]; // they all do literally nothing
+ void (*DumpStats) (IMemAlloc* memAlloc);
+ void (*DumpStatsFileBase) (IMemAlloc* memAlloc, const char* pchFileBase);
+ void* unknown6[4];
+ int (*heapchk) (IMemAlloc* memAlloc);
+ };
+
+ VTable* m_vtable;
+};
diff --git a/loader_launcher_proxy/dllmain.cpp b/loader_launcher_proxy/dllmain.cpp
new file mode 100644
index 00000000..cf69d63e
--- /dev/null
+++ b/loader_launcher_proxy/dllmain.cpp
@@ -0,0 +1,156 @@
+#include "pch.h"
+#include <stdio.h>
+#include <string>
+#include <system_error>
+#include <Shlwapi.h>
+#include <sstream>
+#include <fstream>
+
+HMODULE hLauncherModule;
+HMODULE hHookModule;
+HMODULE hTier0Module;
+
+using CreateInterfaceFn = void* (*)(const char* pName, int* pReturnCode);
+
+// does not seem to ever be used
+extern "C" _declspec(dllexport) void* __fastcall CreateInterface(const char* pName, int* pReturnCode)
+{
+ //AppSystemCreateInterfaceFn(pName, pReturnCode);
+ printf("external CreateInterface: name: %s\n", pName);
+
+ static CreateInterfaceFn launcher_CreateInterface = (CreateInterfaceFn)GetProcAddress(hLauncherModule, "CreateInterface");
+ auto res = launcher_CreateInterface(pName, pReturnCode);
+
+ printf("external CreateInterface: return code: %p\n", res);
+ return res;
+}
+
+bool GetExePathWide(wchar_t* dest, DWORD destSize)
+{
+ if (!dest) return NULL;
+ if (destSize < MAX_PATH) return NULL;
+
+ DWORD length = GetModuleFileNameW(NULL, dest, destSize);
+ return length && PathRemoveFileSpecW(dest);
+}
+
+FARPROC GetLauncherMain()
+{
+ static FARPROC Launcher_LauncherMain;
+ if (!Launcher_LauncherMain)
+ Launcher_LauncherMain = GetProcAddress(hLauncherModule, "LauncherMain");
+ return Launcher_LauncherMain;
+}
+
+void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location)
+{
+ char text[2048];
+ std::string message = std::system_category().message(dwMessageId);
+ sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str());
+ MessageBoxA(GetForegroundWindow(), text, "Northstar Launcher Proxy Error", 0);
+}
+
+BOOL APIENTRY DllMain( HMODULE hModule,
+ DWORD ul_reason_for_call,
+ LPVOID lpReserved
+ )
+{
+ switch (ul_reason_for_call)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ case DLL_PROCESS_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+wchar_t exePath[4096];
+wchar_t dllPath[4096];
+
+bool ShouldLoadNorthstar()
+{
+ bool loadNorthstar = !strstr(GetCommandLineA(), "-vanilla");
+
+ if (!loadNorthstar)
+ return loadNorthstar;
+
+ auto runNorthstarFile = std::ifstream("run_northstar.txt");
+ if (runNorthstarFile)
+ {
+ std::stringstream runNorthstarFileBuffer;
+ runNorthstarFileBuffer << runNorthstarFile.rdbuf();
+ runNorthstarFile.close();
+ if (runNorthstarFileBuffer.str()._Starts_with("0"))
+ loadNorthstar = false;
+ }
+ return loadNorthstar;
+}
+
+bool LoadNorthstar()
+{
+ FARPROC Hook_Init = nullptr;
+ {
+ swprintf_s(dllPath, L"%s\\Northstar.dll", exePath);
+ hHookModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar");
+ if (!hHookModule || Hook_Init == nullptr)
+ {
+ LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath);
+ return false;
+ }
+ }
+
+ ((bool (*)()) Hook_Init)();
+ return true;
+}
+
+extern "C" __declspec(dllexport) int LauncherMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ {
+ if (!GetExePathWide(exePath, 4096))
+ {
+ MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Launcher Proxy Error", 0);
+ return 1;
+ }
+
+ bool loadNorthstar = ShouldLoadNorthstar();
+
+ if (loadNorthstar)
+ {
+ swprintf_s(dllPath, L"%s\\bin\\x64_retail\\tier0.dll", exePath);
+ hTier0Module = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hTier0Module)
+ {
+ LibraryLoadError(GetLastError(), L"tier0.dll", dllPath);
+ return 1;
+ }
+
+ if (!LoadNorthstar())
+ return 1;
+ }
+ //else printf("\n\n WILL !!!NOT!!! LOAD NORTHSTAR\n\n");
+
+ swprintf_s(dllPath, L"%s\\bin\\x64_retail\\launcher.org.dll", exePath);
+ hLauncherModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hLauncherModule)
+ {
+ LibraryLoadError(GetLastError(), L"launcher.org.dll", dllPath);
+ return 1;
+ }
+ }
+
+ auto LauncherMain = GetLauncherMain();
+ if (!LauncherMain)
+ MessageBoxA(GetForegroundWindow(), "Failed loading launcher.org.dll.\nThe game cannot continue and has to exit.", "Northstar Launcher Proxy Error", 0);
+ //auto result = ((__int64(__fastcall*)())LauncherMain)();
+ //auto result = ((signed __int64(__fastcall*)(__int64))LauncherMain)(0i64);
+ return ((int(__fastcall*)(HINSTANCE, HINSTANCE, LPSTR, int))LauncherMain)(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
+}
+
+// doubt that will help us here (in launcher.dll) though
+extern "C" {
+ __declspec(dllexport) DWORD AmdPowerXpressRequestHighPerformance = 0x00000001;
+ __declspec(dllexport) DWORD NvOptimusEnablement = 0x00000001;
+}
diff --git a/loader_launcher_proxy/framework.h b/loader_launcher_proxy/framework.h
new file mode 100644
index 00000000..d1b49600
--- /dev/null
+++ b/loader_launcher_proxy/framework.h
@@ -0,0 +1,7 @@
+#pragma once
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#define WIN32_EXTRA_LEAN
+#define VC_EXTRALEAN
+// Windows Header Files
+#include <Windows.h>
diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj b/loader_launcher_proxy/loader_launcher_proxy.vcxproj
new file mode 100644
index 00000000..24cdabc0
--- /dev/null
+++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj
@@ -0,0 +1,107 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{f65c322d-66df-4af1-b650-70221de334c0}</ProjectGuid>
+ <RootNamespace>loaderlauncherproxy</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <TargetName>launcher</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <TargetName>launcher</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableUAC>false</EnableUAC>
+ <AdditionalDependencies>shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;LOADERLAUNCHERPROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableUAC>false</EnableUAC>
+ <AdditionalOptions>/HIGHENTROPYVA:NO %(AdditionalOptions)</AdditionalOptions>
+ <AdditionalDependencies>shlwapi.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="framework.h" />
+ <ClInclude Include="pch.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp" />
+ <ClCompile Include="pch.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters
new file mode 100644
index 00000000..1e57c7b1
--- /dev/null
+++ b/loader_launcher_proxy/loader_launcher_proxy.vcxproj.filters
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="framework.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="pch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pch.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/loader_launcher_proxy/pch.cpp b/loader_launcher_proxy/pch.cpp
new file mode 100644
index 00000000..64b7eef6
--- /dev/null
+++ b/loader_launcher_proxy/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/loader_launcher_proxy/pch.h b/loader_launcher_proxy/pch.h
new file mode 100644
index 00000000..885d5d62
--- /dev/null
+++ b/loader_launcher_proxy/pch.h
@@ -0,0 +1,13 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+// add headers that you want to pre-compile here
+#include "framework.h"
+
+#endif //PCH_H
diff --git a/loader_wsock32_proxy/dllmain.cpp b/loader_wsock32_proxy/dllmain.cpp
new file mode 100644
index 00000000..0b518dbe
--- /dev/null
+++ b/loader_wsock32_proxy/dllmain.cpp
@@ -0,0 +1,137 @@
+#include "pch.h"
+#include "loader.h"
+
+#include <Shlwapi.h>
+#include <filesystem>
+
+HINSTANCE hLThis = 0;
+FARPROC p[857];
+HINSTANCE hL = 0;
+
+bool GetExePathWide(wchar_t* dest, DWORD destSize)
+{
+ if (!dest) return NULL;
+ if (destSize < MAX_PATH) return NULL;
+
+ DWORD length = GetModuleFileNameW(NULL, dest, destSize);
+ return length && PathRemoveFileSpecW(dest);
+}
+
+wchar_t exePath[4096];
+wchar_t dllPath[8192];
+wchar_t dllPath2[4096];
+
+BOOL WINAPI DllMain(HINSTANCE hInst, DWORD reason, LPVOID)
+{
+ if (reason == DLL_PROCESS_ATTACH)
+ {
+ hLThis = hInst;
+
+ if (!GetExePathWide(exePath, 4096))
+ {
+ MessageBoxA(GetForegroundWindow(), "Failed getting game directory.\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0);
+ return 1;
+ }
+
+ if (!ProvisionNorthstar()) // does not call InitialiseNorthstar yet, will do it on LauncherMain hook
+ return 1;
+
+ // copy the original library for system to our local directory, with changed name so that we can load it
+ swprintf_s(dllPath, L"%s\\bin\\x64_retail\\wsock32.org.dll", exePath);
+ GetSystemDirectoryW(dllPath2, 4096);
+ swprintf_s(dllPath2, L"%s\\wsock32.dll", dllPath2);
+ try
+ {
+ std::filesystem::copy_file(dllPath2, dllPath);
+ }
+ catch (const std::exception& e)
+ {
+ if (!std::filesystem::exists(dllPath))
+ {
+ swprintf_s(dllPath, L"Failed copying wsock32.dll from system32 to \"%s\"\n\n%S", dllPath, e.what());
+ MessageBoxW(GetForegroundWindow(), dllPath, L"Northstar Wsock32 Proxy Error", 0);
+ }
+ }
+ hL = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (!hL) return false;
+
+ // load the functions to proxy
+ // it's only some of them, because in case of wsock32 most of the functions can actually be natively redirected
+ // (see wsock32.def and https://source.winehq.org/WineAPI/wsock32.html)
+ p[1] = GetProcAddress(hL, "EnumProtocolsA");
+ p[2] = GetProcAddress(hL, "EnumProtocolsW");
+ p[4] = GetProcAddress(hL, "GetAddressByNameA");
+ p[5] = GetProcAddress(hL, "GetAddressByNameW");
+ p[17] = GetProcAddress(hL, "WEP");
+ p[30] = GetProcAddress(hL, "WSARecvEx");
+ p[36] = GetProcAddress(hL, "__WSAFDIsSet");
+ p[45] = GetProcAddress(hL, "getnetbyname");
+ p[52] = GetProcAddress(hL, "getsockopt");
+ p[56] = GetProcAddress(hL, "inet_network");
+ p[67] = GetProcAddress(hL, "s_perror");
+ p[72] = GetProcAddress(hL, "setsockopt");
+ }
+
+ if (reason == DLL_PROCESS_DETACH)
+ {
+ FreeLibrary(hL);
+ return 1;
+ }
+
+ return 1;
+}
+
+extern "C"
+{
+ FARPROC PA = NULL;
+ int RunASM();
+
+ void PROXY_EnumProtocolsA() {
+ PA = p[1];
+ RunASM();
+ }
+ void PROXY_EnumProtocolsW() {
+ PA = p[2];
+ RunASM();
+ }
+ void PROXY_GetAddressByNameA() {
+ PA = p[4];
+ RunASM();
+ }
+ void PROXY_GetAddressByNameW() {
+ PA = p[5];
+ RunASM();
+ }
+ void PROXY_WEP() {
+ PA = p[17];
+ RunASM();
+ }
+ void PROXY_WSARecvEx() {
+ PA = p[30];
+ RunASM();
+ }
+ void PROXY___WSAFDIsSet() {
+ PA = p[36];
+ RunASM();
+ }
+ void PROXY_getnetbyname() {
+ PA = p[45];
+ RunASM();
+ }
+ void PROXY_getsockopt() {
+ PA = p[52];
+ RunASM();
+ }
+ void PROXY_inet_network() {
+ PA = p[56];
+ RunASM();
+ }
+ void PROXY_s_perror() {
+ PA = p[67];
+ RunASM();
+ }
+ void PROXY_setsockopt() {
+ PA = p[72];
+ RunASM();
+ }
+} \ No newline at end of file
diff --git a/loader_wsock32_proxy/hookutils.cpp b/loader_wsock32_proxy/hookutils.cpp
new file mode 100644
index 00000000..8603cb35
--- /dev/null
+++ b/loader_wsock32_proxy/hookutils.cpp
@@ -0,0 +1,71 @@
+#include "pch.h"
+#include "../NorthstarDedicatedTest/hookutils.h"
+
+#define ERROR(...) { char err[2048]; sprintf_s(err, __VA_ARGS__); MessageBoxA(GetForegroundWindow(), err, "Northstar Wsock32 Proxy Error", 0); }
+
+TempReadWrite::TempReadWrite(void* ptr)
+{
+ m_ptr = ptr;
+ MEMORY_BASIC_INFORMATION mbi;
+ VirtualQuery(m_ptr, &mbi, sizeof(mbi));
+ VirtualProtect(mbi.BaseAddress, mbi.RegionSize, PAGE_EXECUTE_READWRITE, &mbi.Protect);
+ m_origProtection = mbi.Protect;
+}
+
+TempReadWrite::~TempReadWrite()
+{
+ MEMORY_BASIC_INFORMATION mbi;
+ VirtualQuery(m_ptr, &mbi, sizeof(mbi));
+ VirtualProtect(mbi.BaseAddress, mbi.RegionSize, m_origProtection, &mbi.Protect);
+}
+
+
+void HookEnabler::CreateHook(LPVOID ppTarget, LPVOID ppDetour, LPVOID* ppOriginal, const char* targetName)
+{
+ // the macro for this uses ppTarget's name as targetName, and this typically starts with &
+ // targetname is used for debug stuff and debug output is nicer if we don't have this
+ if (*targetName == '&')
+ targetName++;
+
+ if (MH_CreateHook(ppTarget, ppDetour, ppOriginal) == MH_OK)
+ {
+ HookTarget* target = new HookTarget;
+ target->targetAddress = ppTarget;
+ target->targetName = (char*)targetName;
+
+ m_hookTargets.push_back(target);
+ }
+ else
+ {
+ if (targetName != nullptr)
+ {
+ ERROR("MH_CreateHook failed for function %s", targetName);
+ }
+ else
+ {
+ ERROR("MH_CreateHook failed for unknown function");
+ }
+ }
+}
+
+HookEnabler::~HookEnabler()
+{
+ for (auto& hook : m_hookTargets)
+ {
+ if (MH_EnableHook(hook->targetAddress) != MH_OK)
+ {
+ if (hook->targetName != nullptr)
+ {
+ ERROR("MH_EnableHook failed for function %s", hook->targetName);
+ }
+ else
+ {
+ ERROR("MH_EnableHook failed for unknown function");
+ }
+ }
+ else
+ {
+ //ERROR("Enabling hook %s", hook->targetName);
+ }
+ }
+} \ No newline at end of file
diff --git a/loader_wsock32_proxy/loader.cpp b/loader_wsock32_proxy/loader.cpp
new file mode 100644
index 00000000..907caa9d
--- /dev/null
+++ b/loader_wsock32_proxy/loader.cpp
@@ -0,0 +1,86 @@
+#include "pch.h"
+#include "loader.h"
+#include "../NorthstarDedicatedTest/hookutils.h"
+#include <string>
+#include <system_error>
+#include <sstream>
+#include <fstream>
+
+void LibraryLoadError(DWORD dwMessageId, const wchar_t* libName, const wchar_t* location)
+{
+ char text[2048];
+ std::string message = std::system_category().message(dwMessageId);
+ sprintf_s(text, "Failed to load the %ls at \"%ls\" (%lu):\n\n%hs", libName, location, dwMessageId, message.c_str());
+ MessageBoxA(GetForegroundWindow(), text, "Northstar Wsock32 Proxy Error", 0);
+}
+
+bool ShouldLoadNorthstar()
+{
+ bool loadNorthstar = strstr(GetCommandLineA(), "-northstar");
+
+ if (loadNorthstar)
+ return loadNorthstar;
+
+ auto runNorthstarFile = std::ifstream("run_northstar.txt");
+ if (runNorthstarFile)
+ {
+ std::stringstream runNorthstarFileBuffer;
+ runNorthstarFileBuffer << runNorthstarFile.rdbuf();
+ runNorthstarFile.close();
+ if (!runNorthstarFileBuffer.str()._Starts_with("0"))
+ loadNorthstar = true;
+ }
+ return loadNorthstar;
+}
+
+bool LoadNorthstar()
+{
+ FARPROC Hook_Init = nullptr;
+ {
+ swprintf_s(dllPath, L"%s\\Northstar.dll", exePath);
+ auto hHookModule = LoadLibraryExW(dllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH);
+ if (hHookModule) Hook_Init = GetProcAddress(hHookModule, "InitialiseNorthstar");
+ if (!hHookModule || Hook_Init == nullptr)
+ {
+ LibraryLoadError(GetLastError(), L"Northstar.dll", dllPath);
+ return false;
+ }
+ }
+
+ ((bool (*)()) Hook_Init)();
+ return true;
+}
+
+typedef int(*LauncherMainType)(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
+LauncherMainType LauncherMainOriginal;
+
+int LauncherMainHook(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
+{
+ if (ShouldLoadNorthstar())
+ LoadNorthstar();
+ return LauncherMainOriginal(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
+}
+
+bool ProvisionNorthstar()
+{
+ if (!ShouldLoadNorthstar())
+ return true;
+
+ if (MH_Initialize() != MH_OK)
+ {
+ MessageBoxA(GetForegroundWindow(), "MH_Initialize failed\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0);
+ return false;
+ }
+
+ auto launcherHandle = GetModuleHandleA("launcher.dll");
+ if (!launcherHandle)
+ {
+ MessageBoxA(GetForegroundWindow(), "Launcher isn't loaded yet.\nThe game cannot continue and has to exit.", "Northstar Wsock32 Proxy Error", 0);
+ return false;
+ }
+
+ HookEnabler hook;
+ ENABLER_CREATEHOOK(hook, GetProcAddress(launcherHandle, "LauncherMain"), &LauncherMainHook, reinterpret_cast<LPVOID*>(&LauncherMainOriginal));
+
+ return true;
+} \ No newline at end of file
diff --git a/loader_wsock32_proxy/loader.h b/loader_wsock32_proxy/loader.h
new file mode 100644
index 00000000..9a14b2e7
--- /dev/null
+++ b/loader_wsock32_proxy/loader.h
@@ -0,0 +1,8 @@
+#pragma once
+
+extern wchar_t exePath[4096];
+extern wchar_t dllPath[8192];
+extern wchar_t dllPath2[4096];
+
+bool ShouldLoadNorthstar();
+bool ProvisionNorthstar();
diff --git a/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj
new file mode 100644
index 00000000..9866d368
--- /dev/null
+++ b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>16.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{cf55f3b5-f348-450a-9ccb-c269f21d629d}</ProjectGuid>
+ <RootNamespace>loaderwsock32proxy</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.props" />
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <TargetName>wsock32</TargetName>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <TargetName>wsock32</TargetName>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;LOADERWSOCK32PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ <AdditionalIncludeDirectories>..\NorthstarDedicatedTest\</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableUAC>false</EnableUAC>
+ <ModuleDefinitionFile>wsock32.def</ModuleDefinitionFile>
+ <AdditionalDependencies>..\NorthstarDedicatedTest\include\MinHook.x64.lib;mswsock.lib;ws2_32.lib;Shlwapi.lib;imagehlp.lib;dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;LOADERWSOCK32PROXY_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <PrecompiledHeaderFile>pch.h</PrecompiledHeaderFile>
+ <AdditionalIncludeDirectories>..\NorthstarDedicatedTest\</AdditionalIncludeDirectories>
+ <LanguageStandard>stdcpp17</LanguageStandard>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableUAC>false</EnableUAC>
+ <ModuleDefinitionFile>wsock32.def</ModuleDefinitionFile>
+ <AdditionalDependencies>..\NorthstarDedicatedTest\include\MinHook.x64.lib;mswsock.lib;ws2_32.lib;Shlwapi.lib;imagehlp.lib;dbghelp.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;wsock32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClInclude Include="loader.h" />
+ <ClInclude Include="pch.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp" />
+ <ClCompile Include="hookutils.cpp" />
+ <ClCompile Include="loader.cpp" />
+ <ClCompile Include="pch.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <MASM Include="wsock32.asm" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="wsock32.def" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ <Import Project="$(VCTargetsPath)\BuildCustomizations\masm.targets" />
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters
new file mode 100644
index 00000000..6d131e5b
--- /dev/null
+++ b/loader_wsock32_proxy/loader_wsock32_proxy.vcxproj.filters
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="pch.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="loader.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="pch.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="loader.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="hookutils.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <MASM Include="wsock32.asm">
+ <Filter>Source Files</Filter>
+ </MASM>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="wsock32.def">
+ <Filter>Source Files</Filter>
+ </None>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/loader_wsock32_proxy/pch.cpp b/loader_wsock32_proxy/pch.cpp
new file mode 100644
index 00000000..64b7eef6
--- /dev/null
+++ b/loader_wsock32_proxy/pch.cpp
@@ -0,0 +1,5 @@
+// pch.cpp: source file corresponding to the pre-compiled header
+
+#include "pch.h"
+
+// When you are using pre-compiled headers, this source file is necessary for compilation to succeed.
diff --git a/loader_wsock32_proxy/pch.h b/loader_wsock32_proxy/pch.h
new file mode 100644
index 00000000..0103ff59
--- /dev/null
+++ b/loader_wsock32_proxy/pch.h
@@ -0,0 +1,16 @@
+// pch.h: This is a precompiled header file.
+// Files listed below are compiled only once, improving build performance for future builds.
+// This also affects IntelliSense performance, including code completion and many code browsing features.
+// However, files listed here are ALL re-compiled if any one of them is updated between builds.
+// Do not add files here that you will be updating frequently as this negates the performance advantage.
+
+#ifndef PCH_H
+#define PCH_H
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files
+#include <windows.h>
+
+#include "include/MinHook.h"
+
+#endif //PCH_H
diff --git a/loader_wsock32_proxy/wsock32.asm b/loader_wsock32_proxy/wsock32.asm
new file mode 100644
index 00000000..22a9c384
--- /dev/null
+++ b/loader_wsock32_proxy/wsock32.asm
@@ -0,0 +1,7 @@
+.data
+extern PA : qword
+.code
+RunASM proc
+jmp qword ptr [PA]
+RunASM endp
+end
diff --git a/loader_wsock32_proxy/wsock32.def b/loader_wsock32_proxy/wsock32.def
new file mode 100644
index 00000000..448440b4
--- /dev/null
+++ b/loader_wsock32_proxy/wsock32.def
@@ -0,0 +1,78 @@
+LIBRARY wsock32
+EXPORTS
+ AcceptEx=mswsock.AcceptEx
+ EnumProtocolsA=PROXY_EnumProtocolsA
+ EnumProtocolsW=PROXY_EnumProtocolsW
+ GetAcceptExSockaddrs=mswsock.GetAcceptExSockaddrs
+ GetAddressByNameA=PROXY_GetAddressByNameA
+ GetAddressByNameW=PROXY_GetAddressByNameW
+ GetNameByTypeA=ws2_32.GetNameByTypeA
+ GetNameByTypeW=ws2_32.GetNameByTypeW
+ GetServiceA=ws2_32.GetServiceA
+ GetServiceW=ws2_32.GetServiceW
+ GetTypeByNameA=ws2_32.GetTypeByNameA
+ GetTypeByNameW=ws2_32.GetTypeByNameW
+ MigrateWinsockConfiguration=ws2_32.MigrateWinsockConfiguration
+ NPLoadNameSpaces=ws2_32.NPLoadNameSpaces
+ SetServiceA=ws2_32.SetServiceA
+ SetServiceW=ws2_32.SetServiceW
+ TransmitFile=mswsock.TransmitFile
+ WEP=PROXY_WEP
+ WSAAsyncGetHostByAddr=ws2_32.WSAAsyncGetHostByAddr
+ WSAAsyncGetHostByName=ws2_32.WSAAsyncGetHostByName
+ WSAAsyncGetProtoByName=ws2_32.WSAAsyncGetProtoByName
+ WSAAsyncGetProtoByNumber=ws2_32.WSAAsyncGetProtoByNumber
+ WSAAsyncGetServByName=ws2_32.WSAAsyncGetServByName
+ WSAAsyncGetServByPort=ws2_32.WSAAsyncGetServByPort
+ WSAAsyncSelect=ws2_32.WSAAsyncSelect
+ WSACancelAsyncRequest=ws2_32.WSACancelAsyncRequest
+ WSACancelBlockingCall=ws2_32.WSACancelBlockingCall
+ WSACleanup=ws2_32.WSACleanup @116
+ WSAGetLastError=ws2_32.WSAGetLastError @111
+ WSAIsBlocking=ws2_32.WSAIsBlocking
+ WSARecvEx=PROXY_WSARecvEx
+ WSASetBlockingHook=ws2_32.WSASetBlockingHook
+ WSASetLastError=ws2_32.WSASetLastError @112
+ WSAStartup=ws2_32.WSAStartup @115
+ WSAUnhookBlockingHook=ws2_32.WSAUnhookBlockingHook
+ WSApSetPostRoutine=ws2_32.WSApSetPostRoutine
+ __WSAFDIsSet=PROXY___WSAFDIsSet @151
+ accept=ws2_32.accept @1
+ bind=ws2_32.bind @2
+ closesocket=ws2_32.closesocket @3
+ connect=ws2_32.connect @4
+ dn_expand=ws2_32.dn_expand @1106
+ gethostbyaddr=ws2_32.gethostbyaddr
+ gethostbyname=ws2_32.gethostbyname @52
+ gethostname=ws2_32.gethostname @57
+ getnetbyname=PROXY_getnetbyname @ 1101
+ getpeername=ws2_32.getpeername @5
+ getprotobyname=ws2_32.getprotobyname
+ getprotobynumber=ws2_32.getprotobynumber
+ getservbyname=ws2_32.getservbyname
+ getservbyport=ws2_32.getservbyport
+ getsockname=ws2_32.getsockname @6
+ getsockopt=PROXY_getsockopt @7
+ htonl=ws2_32.htonl
+ htons=ws2_32.htons @9
+ inet_addr=ws2_32.inet_addr
+ inet_network=PROXY_inet_network
+ inet_ntoa=ws2_32.inet_ntoa
+ ioctlsocket=ws2_32.ioctlsocket @12
+ listen=ws2_32.listen @13
+ ntohl=ws2_32.ntohl
+ ntohs=ws2_32.ntohs @15
+ rcmd=ws2_32.rcmd
+ recv=ws2_32.recv @16
+ recvfrom=ws2_32.recvfrom @17
+ rexec=ws2_32.rexec
+ rresvport=ws2_32.rresvport
+ s_perror=PROXY_s_perror
+ select=ws2_32.select @18
+ select=ws2_32.select @18
+ send=ws2_32.send @19
+ sendto=ws2_32.sendto @20
+ sethostname=ws2_32.sethostname
+ setsockopt=PROXY_setsockopt @21
+ shutdown=ws2_32.shutdown @22
+ socket=ws2_32.socket @23