diff --git a/WuchangFF/WuchangFF.vcxproj b/WuchangFF/WuchangFF.vcxproj
index 47dcc12..1a3a766 100644
--- a/WuchangFF/WuchangFF.vcxproj
+++ b/WuchangFF/WuchangFF.vcxproj
@@ -192,15 +192,6 @@
-
-
-
-
-
-
-
-
-
@@ -209,12 +200,6 @@
-
-
-
-
-
-
diff --git a/WuchangFF/dllmain.cpp b/WuchangFF/dllmain.cpp
index aa548a1..121756f 100644
--- a/WuchangFF/dllmain.cpp
+++ b/WuchangFF/dllmain.cpp
@@ -6,31 +6,56 @@
#include
#include
-
// Constants
const std::string PLUGIN_NAME = "WuchangFF";
const std::string PLUGIN_LOG = PLUGIN_NAME + ".log";
const std::string gameExecutable = "Project_Plague-Win64-Shipping.exe";
+const float defaultAspect = 1.777778; // Default aspect that must not be compensated because FOV is already HOR+
// Logger
std::shared_ptr logger;
+// Screen informations
+static int screenWidth = GetSystemMetrics(SM_CXSCREEN);
+static int screenHeight = GetSystemMetrics(SM_CYSCREEN);
+static float aspectRatio = (float)screenWidth / screenHeight;
+static float baseAspect = 2.2222223; // Base game aspect ratio
+
// Plugin states
static bool AOBScanDone = false;
static bool g_fix_enabled = false;
-static bool g_aspect_ratio_axis_constrain_fix_enabled = false;
+static bool g_fov_fix_enabled = false;
+static bool g_aspect_ratio_fix_enabled = false;
static bool g_DOF_fix_enabled = false;
static bool g_Vignetting_fix_enabled = false;
static bool g_Fog_fix_enabled = false;
+static int g_AdditionalFOVValue = 0;
+
+// Shared values
+static float g_FOV_In = 0;
+static float g_Compensated_FOV = 0;
+static float g_FOV_Out = 0;
// AOB Scan pointers
-static uint8_t* HORPLUSaddress = nullptr;
+static uint8_t* FOVaddress = nullptr;
+static uint8_t* Aspectaddress_1 = nullptr;
+static uint8_t* Aspectaddress_2 = nullptr;
static uint8_t* DOFaddress = nullptr;
static uint8_t* Vignettingaddress = nullptr;
static uint8_t* Fogaddress = nullptr;
+// FOV Addresses
+uintptr_t t_fov_address_to_patch = 0;
+uintptr_t t_aspect_address_to_patch = 0;
+
+// VEH debugger handles
+PVOID vehFOVHandle = nullptr;
+PVOID vehApectHandle_1 = nullptr;
+PVOID vehApectHandle_2 = nullptr;
+
// Prototypes
-static void HORPlusFixEnabled(bool fix_enabled);
+static void FOVFixEnabled(bool fix_enabled);
+static void AspectFixEnabled(bool fix_enabled);
static void DOFFixEnabled(bool fix_enabled);
static void VignettingFixEnabled(bool fix_enabled);
static void FogFixEnabled(bool fix_enabled);
@@ -140,21 +165,24 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled)
}
}
- if (HORPLUSaddress && DOFaddress && Vignettingaddress && Fogaddress) {
+ if (FOVaddress && Aspectaddress_1 && Aspectaddress_2 && DOFaddress && Vignettingaddress && Fogaddress) {
logger->info("All AOB signatures found. Ready to patch...");
AOBScanDone = true;
}
logger->info("--------------- AOB scan finished ---------------");
}
+
if (g_fix_enabled) {
- if (HORPLUSaddress) HORPlusFixEnabled(g_aspect_ratio_axis_constrain_fix_enabled);
+ if (FOVaddress) FOVFixEnabled(g_fov_fix_enabled || g_aspect_ratio_fix_enabled);
+ if (Aspectaddress_1 && Aspectaddress_2) AspectFixEnabled(g_aspect_ratio_fix_enabled);
if (DOFaddress) DOFFixEnabled(g_DOF_fix_enabled);
if (Vignettingaddress) VignettingFixEnabled(g_Vignetting_fix_enabled);
if (Fogaddress) FogFixEnabled(g_Fog_fix_enabled);
}
else {
- if (HORPLUSaddress) HORPlusFixEnabled(false);
+ if (FOVaddress) FOVFixEnabled(false);
+ if (Aspectaddress_1 && Aspectaddress_2) AspectFixEnabled(false);
if (DOFaddress) DOFFixEnabled(false);
if (Vignettingaddress) VignettingFixEnabled(false);
if (Fogaddress) FogFixEnabled(false);
@@ -162,11 +190,17 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled)
}
}
-// Setters for Reshade addon call
-extern "C" __declspec(dllexport) void SetARAxisConstrainFixEnabled(bool enabled, bool init)
+extern "C" __declspec(dllexport) void SetFOVFixEnabled(bool enabled, bool init)
{
- g_aspect_ratio_axis_constrain_fix_enabled = enabled;
- if (!init) HORPlusFixEnabled(g_aspect_ratio_axis_constrain_fix_enabled);
+ g_fov_fix_enabled = enabled;
+ if (!init) FOVFixEnabled(g_fov_fix_enabled || g_aspect_ratio_fix_enabled); // FOV fix must be enabled when aspect ratio is too to compensate FOV
+}
+
+// Setters for Reshade addon call
+extern "C" __declspec(dllexport) void SetAspectRatioFixEnabled(bool enabled, bool init)
+{
+ g_aspect_ratio_fix_enabled = enabled;
+ if (!init) AspectFixEnabled(g_aspect_ratio_fix_enabled);
}
extern "C" __declspec(dllexport) void SetDOFFixEnabled(bool enabled, bool init)
@@ -187,18 +221,138 @@ extern "C" __declspec(dllexport) void SetFogFixEnabled(bool enabled, bool init)
if (!init) FogFixEnabled(g_Fog_fix_enabled);
}
-// Memory patch fixes
-static void HORPlusFixEnabled(bool fix_enabled) {
- if (g_fix_enabled && fix_enabled && HORPLUSaddress) {
- Memory::PatchBytes(HORPLUSaddress, "\x31\xD2\x90\x90\x90\x90\x90\x90", 8); // xor edx,edx AspectRatioAxisConstraint=AspectRatio_MaintainYFOV
- logger->info("HOR+ fix enabled");
+extern "C" __declspec(dllexport) void SetFOV(int fov)
+{
+ g_AdditionalFOVValue = fov;
+}
+
+// Getters for Reshade addon call
+extern "C" __declspec(dllexport) float GetFOVIn() {
+ return g_FOV_In;
+}
+
+extern "C" __declspec(dllexport) float GetCompensatedFOV() {
+ return g_Compensated_FOV;
+}
+
+extern "C" __declspec(dllexport) float GetFOVOut() {
+ return g_FOV_Out;
+}
+
+// VEH debugger breakpoint fixes
+LONG WINAPI FOVVehHandler(PEXCEPTION_POINTERS ep) {
+ if (!ep || !ep->ContextRecord || !ep->ExceptionRecord) return EXCEPTION_CONTINUE_SEARCH;
+ if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
+
+ CONTEXT* ctx = ep->ContextRecord; // Vérifie si on est sur l'instruction cible //logger->info("Avant if ep");
+ if (ctx->Rip == reinterpret_cast(FOVaddress)) {
+ t_fov_address_to_patch = static_cast(ctx->Rdi) + 0x30;
+
+ float* xmm0 = reinterpret_cast(&ctx->Xmm0);
+ g_FOV_In = *xmm0;
+ // Calculate compensated FOV if aspect fix is checked
+ if (g_aspect_ratio_fix_enabled && baseAspect > defaultAspect)
+ g_Compensated_FOV = *xmm0 = Maths::CompensateHorizontalFOV(g_FOV_In, baseAspect, aspectRatio);
+ else
+ g_Compensated_FOV = *xmm0;
+
+ *xmm0 += (g_fov_fix_enabled ? g_AdditionalFOVValue : 0);
+ g_FOV_Out = *xmm0;
+
+ *reinterpret_cast(t_fov_address_to_patch) = g_FOV_Out; // Patch new FOV value in memory
+
+ // Skip original opcode size in bytes otherwise the game will crash
+ ctx->Rip += 5;
+
+ return EXCEPTION_CONTINUE_EXECUTION;
}
- if (!fix_enabled && HORPLUSaddress) {
- Memory::RestoreBytes(HORPLUSaddress);
- logger->info("HOR+ fix disabled");
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+LONG WINAPI AspectVehHandler_1(PEXCEPTION_POINTERS ep) {
+ if (!ep || !ep->ContextRecord || !ep->ExceptionRecord) return EXCEPTION_CONTINUE_SEARCH;
+ if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
+
+ CONTEXT* ctx = ep->ContextRecord; // Check if instruction breakpoint is the one targeted
+ if (ctx->Rip == reinterpret_cast(Aspectaddress_1)) {
+ // Retrieves the addresse where aspect ratio will be stored
+ t_aspect_address_to_patch = static_cast(ctx->Rcx) + 0x48;
+ // Retrieves where the base aspect ratio is actually stored
+ baseAspect = *reinterpret_cast(&ctx->Rax);
+ *reinterpret_cast(t_aspect_address_to_patch) = baseAspect; // Patch base aspect ratio
+
+ // Skip original opcode size in bytes otherwise the game will crash
+ ctx->Rip += 3;
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+LONG WINAPI AspectVehHandler_2(PEXCEPTION_POINTERS ep) {
+ if (!ep || !ep->ContextRecord || !ep->ExceptionRecord) return EXCEPTION_CONTINUE_SEARCH;
+ if (ep->ExceptionRecord->ExceptionCode != EXCEPTION_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH;
+
+ CONTEXT* ctx = ep->ContextRecord; // Check if instruction breakpoint is the one targeted
+ if (ctx->Rip == reinterpret_cast(Aspectaddress_2)) {
+ // Retrieves the addresse where aspect ratio will be stored
+ t_aspect_address_to_patch = static_cast(ctx->Rcx) + 0x48;
+ *reinterpret_cast(t_aspect_address_to_patch) = aspectRatio; // Patch new aspect ratio value in memory
+
+ // Skip original opcode size in bytes otherwise the game will crash
+ ctx->Rip += 3;
+
+ return EXCEPTION_CONTINUE_EXECUTION;
+ }
+
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+// Code injection functions
+static void FOVFixEnabled(bool fix_enabled) {
+ if (g_fix_enabled && fix_enabled && FOVaddress) {
+ vehFOVHandle = nullptr;
+ vehFOVHandle = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(FOVaddress), vehFOVHandle ,true, FOVVehHandler, 0);
+ if (vehFOVHandle)
+ logger->info("FOV fix enabled and hardware breakpoint armed");
+ }
+ if (!fix_enabled && FOVaddress) {
+ if (vehFOVHandle)
+ vehFOVHandle = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(FOVaddress), vehFOVHandle, false, nullptr, 0);
+ if (!vehFOVHandle)
+ logger->info("FOV fix disabled and hardware breakpoint disarmed");
}
}
+static void AspectFixEnabled(bool fix_enabled) {
+ if (g_fix_enabled && fix_enabled && Aspectaddress_1 && Aspectaddress_2) {
+ vehApectHandle_1 = nullptr;
+ vehApectHandle_2 = nullptr;
+ vehApectHandle_1 = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(Aspectaddress_1), vehApectHandle_1, true, AspectVehHandler_1, 1);
+ vehApectHandle_2 = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(Aspectaddress_2), vehApectHandle_2, true, AspectVehHandler_2, 2);
+
+ if (vehApectHandle_1 && vehApectHandle_2)
+ logger->info("Aspect ratio fix enabled and hardware breakpoint armed");
+
+ if (FOVaddress) FOVFixEnabled(true); // Compensate FOV if aspect fix is checked
+ }
+ if (!fix_enabled && Aspectaddress_1) {
+ if (vehApectHandle_1)
+ vehApectHandle_1 = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(Aspectaddress_1), vehApectHandle_1, false, nullptr, 1);
+
+ if (vehApectHandle_2)
+ vehApectHandle_2 = Memory::SetupOrClearHardwareBreakPointForAllThreads(reinterpret_cast(Aspectaddress_2), vehApectHandle_2, false, nullptr, 2);
+ if (!vehApectHandle_1 && !vehApectHandle_2)
+ logger->info("Aspect ratio fix disabled and hardware breakpoint disarmed");
+
+ // When aspect fix is unchecked no more FOV compensation is needed
+ if (FOVaddress && !g_fov_fix_enabled) FOVFixEnabled(false);
+ }
+}
+
+// Memory patch fixes
static void DOFFixEnabled(bool fix_enabled) {
if (g_fix_enabled && fix_enabled && DOFaddress) {
Memory::PatchBytes(DOFaddress, "\x31\xFF\x90", 3); // xor edi,edi r.DepthOfFieldQuality = 0
@@ -223,7 +377,7 @@ static void VignettingFixEnabled(bool fix_enabled) {
static void FogFixEnabled(bool fix_enabled) {
if (g_fix_enabled && fix_enabled && Fogaddress) {
- Memory::PatchBytes(Fogaddress, "\xEB", 1); // jmp "Project_Plague-Win64-Shipping.exe"+28E280E
+ Memory::PatchBytes(Fogaddress, "\xEB", 1); // jmp "Project_Plague-Win64-Shipping.exe"+28E280E r.Fog = 0
logger->info("Fog fix enabled");
}
if (!fix_enabled && Fogaddress) {
@@ -249,6 +403,7 @@ static void InitializeLogger()
}
}
+
// Standard dll entry
BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID)
{