diff --git a/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj b/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj
new file mode 100644
index 0000000..d67238c
--- /dev/null
+++ b/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj
@@ -0,0 +1,136 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 17.0
+ Win32Proj
+ {8170a17f-e536-4fdb-bc01-78bf09a9a48b}
+ ProspectClientLoader
+ 10.0
+ Prospect.Client.Loader
+
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+ Application
+ true
+ v143
+ Unicode
+
+
+ Application
+ false
+ v143
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj.filters b/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj.filters
new file mode 100644
index 0000000..ce0c35c
--- /dev/null
+++ b/src/Prospect.Client.Loader/Prospect.Client.Loader.vcxproj.filters
@@ -0,0 +1,22 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/src/Prospect.Client.Loader/main.cpp b/src/Prospect.Client.Loader/main.cpp
new file mode 100644
index 0000000..84d962b
--- /dev/null
+++ b/src/Prospect.Client.Loader/main.cpp
@@ -0,0 +1,139 @@
+#include
+#include
+#include
+#include
+#include
+
+// Function to create and launch a process with parameters
+HANDLE StartProcess(const wchar_t* exePath, DWORD* processID) {
+ STARTUPINFO si = { 0 };
+ PROCESS_INFORMATION pi = { 0 };
+ si.cb = sizeof(si);
+
+ // Command-line arguments to pass to the process
+ wchar_t commandLine[MAX_PATH] = L""; // Buffer for full command
+ _snwprintf_s(commandLine, sizeof(commandLine) / sizeof(wchar_t), L"\"%s\" -log -steam_auth PF_TITLEID=2EA46", exePath);
+
+ if (CreateProcess(NULL, commandLine, NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
+ *processID = pi.dwProcessId;
+ printf("Successfully started process: %ls (PID: %lu)\n", exePath, *processID);
+ ResumeThread(pi.hThread);
+ CloseHandle(pi.hThread);
+ return pi.hProcess;
+ }
+ else {
+ printf("Failed to start process. Error: %lu\n", GetLastError());
+ return NULL;
+ }
+}
+
+// Function to get the base address of the main module (PE Image)
+uintptr_t GetModuleBaseAddress(DWORD processID) {
+ uintptr_t baseAddress = 0;
+ HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE | TH32CS_SNAPMODULE32, processID);
+ if (hSnapshot != INVALID_HANDLE_VALUE) {
+ MODULEENTRY32 moduleEntry;
+ moduleEntry.dwSize = sizeof(MODULEENTRY32);
+ if (Module32First(hSnapshot, &moduleEntry)) {
+ baseAddress = (uintptr_t)moduleEntry.modBaseAddr;
+ }
+ CloseHandle(hSnapshot);
+ }
+ else {
+ printf("Failed to take process snapshot. Error: %lu\n", GetLastError());
+ }
+ return baseAddress;
+}
+
+// Function to get a handle to the target process
+HANDLE OpenTargetProcess(DWORD processID) {
+ HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, processID);
+ if (hProcess == NULL) {
+ printf("Failed to open process. Error: %lu\n", GetLastError());
+ }
+ return hProcess;
+}
+
+bool CheckTutorialActorsOffset(HANDLE hProcess, uintptr_t address) {
+ BYTE buffer[2];
+ SIZE_T bytesRead;
+ if (ReadProcessMemory(hProcess, (LPCVOID)address, buffer, sizeof(buffer), &bytesRead)) {
+ return buffer[0] == 0x32 && buffer[1] == 0xDB;
+ } else {
+ DWORD error = GetLastError();
+ if (error == 299) {
+ printf("Incomplete memory read. Retrying...\n");
+ Sleep(1000);
+ return CheckTutorialActorsOffset(hProcess, address);
+ }
+ printf("Failed to read memory. Error: %lu\n", error);
+ return false;
+ }
+}
+
+bool Patch(const wchar_t* processName) {
+ DWORD processID;
+ uintptr_t imageBase, address;
+ BYTE newValues[2] = { 0xB3, 0x01 };
+ SIZE_T bytesWritten;
+
+ HANDLE hProcess = StartProcess(processName, &processID);
+ if (hProcess == NULL) {
+ return false;
+ }
+
+ // Wait a bit for PE image to load
+ Sleep(5000);
+ // Find the PE Image Base Address
+ imageBase = GetModuleBaseAddress(processID);
+ if (imageBase == 0) {
+ printf("Failed to find PE Image Base Address.\n");
+ return false;
+ }
+ printf("PE Image Base Address: 0x%p\n", (void*)imageBase);
+
+ // Season 3 Patch tutorial actors loader: sub_3DA7520 -> loc_3DA75B6
+ address = imageBase + 0x3DA75B6;
+ bool found = CheckTutorialActorsOffset(hProcess, address);
+ if (!found) {
+ // Season 2 Patch tutorial actors loader: sub_3D19900 -> loc_3D19996
+ address = imageBase + 0x3D19996;
+ found = CheckTutorialActorsOffset(hProcess, address);
+ }
+
+ if (!found) {
+ printf("Failed to find necessary memory chunk!");
+ return false;
+ }
+
+ DWORD oldProtect;
+ if (VirtualProtectEx(hProcess, (LPVOID)address, sizeof(newValues), PAGE_EXECUTE_READWRITE, &oldProtect)) {
+ if (WriteProcessMemory(hProcess, (LPVOID)address, newValues, sizeof(newValues), &bytesWritten)) {
+ printf("Memory Write Success: Wrote 0xB3 0x01 at address 0x%p\n", (void*)address);
+ }
+ else {
+ printf("Failed to write memory. Error: %lu\n", GetLastError());
+ }
+ // Restore original protection
+ VirtualProtectEx(hProcess, (LPVOID)address, sizeof(newValues), oldProtect, &oldProtect);
+ }
+ else {
+ printf("Failed to change memory protection. Error: %lu\n", GetLastError());
+ }
+
+ // Clean up
+ CloseHandle(hProcess);
+ return true;
+}
+
+int main() {
+ bool success = Patch(L"Prospect-Win64-Shipping.exe");
+ if (!success) {
+ // Wait for user input to exit
+ printf("An error occurred when patching the executable! Press any key to exit...\n");
+ getchar();
+ return 1;
+ }
+
+ return 0;
+}
\ No newline at end of file
diff --git a/src/Prospect.Server.Game/Prospect.Server.Game.csproj b/src/Prospect.Server.Game/Prospect.Server.Game.csproj
index 3659f1a..704692d 100644
--- a/src/Prospect.Server.Game/Prospect.Server.Game.csproj
+++ b/src/Prospect.Server.Game/Prospect.Server.Game.csproj
@@ -5,6 +5,7 @@
net8.0
enable
enable
+ Debug;Release;Season 3 Release;Season 2 Release;Season 2 Debug;Season 3 Debug
diff --git a/src/Prospect.Steam/Prospect.Steam.csproj b/src/Prospect.Steam/Prospect.Steam.csproj
index 5210c96..37ebcaf 100644
--- a/src/Prospect.Steam/Prospect.Steam.csproj
+++ b/src/Prospect.Steam/Prospect.Steam.csproj
@@ -3,6 +3,7 @@
net8.0
true
+ Debug;Release;Season 3 Release;Season 2 Release;Season 2 Debug;Season 3 Debug
diff --git a/src/Prospect.Unreal.Generator/Prospect.Unreal.Generator.csproj b/src/Prospect.Unreal.Generator/Prospect.Unreal.Generator.csproj
index fdada5a..a6948a7 100644
--- a/src/Prospect.Unreal.Generator/Prospect.Unreal.Generator.csproj
+++ b/src/Prospect.Unreal.Generator/Prospect.Unreal.Generator.csproj
@@ -4,6 +4,7 @@
netstandard2.0
9.0
true
+ Debug;Release;Season 3 Release;Season 2 Release;Season 2 Debug;Season 3 Debug
diff --git a/src/Prospect.Unreal.Tests/Prospect.Unreal.Tests.csproj b/src/Prospect.Unreal.Tests/Prospect.Unreal.Tests.csproj
index 6ad5418..fba6736 100644
--- a/src/Prospect.Unreal.Tests/Prospect.Unreal.Tests.csproj
+++ b/src/Prospect.Unreal.Tests/Prospect.Unreal.Tests.csproj
@@ -5,6 +5,8 @@
enable
false
+
+ Debug;Release;Season 3 Release;Season 2 Release;Season 2 Debug;Season 3 Debug
diff --git a/src/Prospect.Unreal/Prospect.Unreal.csproj b/src/Prospect.Unreal/Prospect.Unreal.csproj
index 69d0772..412fdbc 100644
--- a/src/Prospect.Unreal/Prospect.Unreal.csproj
+++ b/src/Prospect.Unreal/Prospect.Unreal.csproj
@@ -5,6 +5,7 @@
enable
enable
true
+ Debug;Release;Season 3 Release;Season 2 Release;Season 2 Debug;Season 3 Debug
diff --git a/src/Prospect.sln b/src/Prospect.sln
index bbafc87..df8ef87 100644
--- a/src/Prospect.sln
+++ b/src/Prospect.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35514.174
@@ -21,6 +21,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prospect.Unreal.Tests", "Pr
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Prospect.Unreal.Generator", "Prospect.Unreal.Generator\Prospect.Unreal.Generator.csproj", "{71E3E262-49C5-4B6C-9670-D0741CEDB63B}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Prospect.Client.Loader", "Prospect.Client.Loader\Prospect.Client.Loader.vcxproj", "{8170A17F-E536-4FDB-BC01-78BF09A9A48B}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
@@ -216,6 +218,7 @@ Global
{380DD490-8F01-4025-91D7-74C289AA5B75} = {76364BAA-BC9D-4A92-AA2A-8914FAE22834}
{14DAE1A4-6F3F-43C0-AC17-9DCDE420AF34} = {168B6247-2D33-4942-AB3F-C5041B3BDFEA}
{71E3E262-49C5-4B6C-9670-D0741CEDB63B} = {76364BAA-BC9D-4A92-AA2A-8914FAE22834}
+ {8170A17F-E536-4FDB-BC01-78BF09A9A48B} = {31D3D5D2-B011-4F9B-B6CC-D0A35675D797}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {12888C62-D3A2-4DD7-A9A5-1481D95865D0}