2025-07-31 10:38:51 +02:00
# include "Memory.hpp" ;
# include "Maths.hpp" ;
# include "ObfuscateString.h"
# include <string>
# include <spdlog/spdlog.h>
# include <spdlog/sinks/rotating_file_sink.h>
# include <filesystem>
// Constants
const std : : string PLUGIN_NAME = " WuchangFF " ;
const std : : string PLUGIN_LOG = PLUGIN_NAME + " .log " ;
const std : : string gameExecutable = " Project_Plague-Win64-Shipping.exe " ;
// Logger
std : : shared_ptr < spdlog : : logger > logger ;
// Plugin states
static bool AOBScanDone = false ;
static bool g_fix_enabled = false ;
2025-08-08 10:46:57 +02:00
static bool g_aspect_ratio_axis_constrain_fix_enabled = false ;
2025-07-31 10:38:51 +02:00
static bool g_DOF_fix_enabled = false ;
2025-08-08 10:46:57 +02:00
static bool g_Vignetting_fix_enabled = false ;
static bool g_Fog_fix_enabled = false ;
2025-07-31 10:38:51 +02:00
// AOB Scan pointers
2025-08-08 10:46:57 +02:00
static uint8_t * HORPLUSaddress = nullptr ;
2025-07-31 10:38:51 +02:00
static uint8_t * DOFaddress = nullptr ;
2025-08-08 10:46:57 +02:00
static uint8_t * Vignettingaddress = nullptr ;
static uint8_t * Fogaddress = nullptr ;
2025-07-31 10:38:51 +02:00
// Prototypes
2025-08-08 10:46:57 +02:00
static void HORPlusFixEnabled ( bool fix_enabled ) ;
2025-07-31 10:38:51 +02:00
static void DOFFixEnabled ( bool fix_enabled ) ;
2025-08-08 10:46:57 +02:00
static void VignettingFixEnabled ( bool fix_enabled ) ;
static void FogFixEnabled ( bool fix_enabled ) ;
2025-07-31 10:38:51 +02:00
extern " C " __declspec ( dllexport ) void SetFixEnabled ( bool enabled )
{
g_fix_enabled = enabled ;
if ( g_fix_enabled & & ! AOBScanDone ) {
logger - > info ( " --------------- AOB scan started --------------- " ) ;
2025-08-20 10:53:58 +02:00
if ( FOVaddress = = nullptr ) {
constexpr auto FOVStringObfuscated = make_obfuscated < 0x4A > ( " EB ?? F3 0F ?? ?? ?? ?? ?? ?? F3 0F ?? ?? ?? 0F ?? ?? 8B " ) ;
FOVaddress = Memory : : AOBScan ( gameExecutable , FOVStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 3E1037A - EB 08 - jmp "Project_Plague-Win64-Shipping.exe" + 3E10384
//"Project_Plague-Win64-Shipping.exe" + 3E1037C - F3 0F 10 83 E0 02 00 00 - movss xmm0, [rbx + 000002E0]
//"Project_Plague-Win64-Shipping.exe" + 3E10384 - F3 0F 11 47 30 - movss[rdi + 30], xmm0
//"Project_Plague-Win64-Shipping.exe" + 3E10389 - 0F 57 C0 - xorps xmm0, xmm0
//"Project_Plague-Win64-Shipping.exe" + 3E1038C - 8B 83 F0 02 00 00 - mov eax, [rbx + 000002F0]
if ( ! FOVaddress )
logger - > warn ( " FOV signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
logger - > info ( " FOV signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( FOVaddress ) ) ;
FOVaddress + = 0xa ; // Offset for the target opcode
}
}
if ( Aspectaddress_1 = = nullptr ) {
constexpr auto AspectStringObfuscated = make_obfuscated < 0x4A > ( " C3 CC CC CC CC CC CC CC CC 48 89 ?? ?? ?? 57 48 ?? ?? ?? 0F ?? ?? 48 ?? ?? 48 ?? ?? 0F ?? ?? ?? 0F ?? ?? ?? F2 0F " ) ;
Aspectaddress_1 = Memory : : AOBScan ( gameExecutable , AspectStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 10A7443 - 89 41 44 - mov[rcx + 44], eax
//"Project_Plague-Win64-Shipping.exe" + 10A7446 - 8B 42 48 - mov eax, [rdx + 48]
//"Project_Plague-Win64-Shipping.exe" + 10A7449 - 89 41 48 - mov[rcx + 48], eax
//"Project_Plague-Win64-Shipping.exe" + 10A744C - 8B 49 4C - mov ecx, [rcx + 4C]
//"Project_Plague-Win64-Shipping.exe" + 10A744F - 33 4A 4C - xor ecx, [rdx + 4C]
if ( ! Aspectaddress_1 )
logger - > warn ( " Aspect ratio #1 signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
logger - > info ( " Aspect ratio #1 signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( Aspectaddress_1 ) ) ;
Aspectaddress_1 + = 0x62 ;
}
}
if ( Aspectaddress_2 = = nullptr ) {
constexpr auto AspectStringObfuscated = make_obfuscated < 0x4A > ( " C3 CC CC CC CC CC 48 89 ?? ?? ?? 57 48 ?? ?? ?? 0F ?? ?? 48 ?? ?? 48 ?? ?? 0F ?? ?? ?? 0F ?? ?? ?? F2 0F " ) ;
Aspectaddress_2 = Memory : : AOBScan ( gameExecutable , AspectStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 1914483 - 89 41 44 - mov[rcx + 44], eax
//"Project_Plague-Win64-Shipping.exe" + 1914486 - 8B 42 48 - mov eax, [rdx + 48]
//"Project_Plague-Win64-Shipping.exe" + 1914489 - 89 41 48 - mov[rcx + 48], eax
//"Project_Plague-Win64-Shipping.exe" + 191448C - 8B 49 4C - mov ecx, [rcx + 4C]
//"Project_Plague-Win64-Shipping.exe" + 191448F - 33 4A 4C - xor ecx, [rdx + 4C]
if ( ! Aspectaddress_2 )
logger - > warn ( " Aspect ratio #2 signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
logger - > info ( " Aspect ratio #2 signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( Aspectaddress_2 ) ) ;
Aspectaddress_2 + = 0x5F ;
}
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
2025-07-31 10:38:51 +02:00
if ( DOFaddress = = nullptr ) {
2025-08-08 10:46:57 +02:00
constexpr auto DOFStringObfuscated = make_obfuscated < 0x4A > ( " 48 ?? ?? 8B ?? ?? E8 ?? ?? ?? ?? 48 ?? ?? 48 6B ?? ?? 48 8D " ) ;
2025-08-20 10:53:58 +02:00
DOFaddress = Memory : : AOBScan ( gameExecutable , DOFStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 2BD06A4 - 48 8B 05 1D 15 9D 05 - mov rax, ["Project_Plague-Win64-Shipping.exe" + 85A1BC8]
//"Project_Plague-Win64-Shipping.exe" + 2BD06AB - 48 8B CB - mov rcx, rbx
//"Project_Plague-Win64-Shipping.exe" + 2BD06AE - 8B 78 04 - mov edi, [rax + 04]
//"Project_Plague-Win64-Shipping.exe" + 2BD06B1 - E8 AA 5F 8A 01 - call "Project_Plague-Win64-Shipping.exe" + 4476660
//"Project_Plague-Win64-Shipping.exe" + 2BD06B6 - 48 63 C8 - movsxd rcx, eax
2025-07-31 10:38:51 +02:00
if ( ! DOFaddress )
logger - > warn ( " DOF signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
2025-08-08 10:46:57 +02:00
logger - > info ( " DOF signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( DOFaddress ) ) ;
DOFaddress + = 0x3 ;
}
}
if ( Vignettingaddress = = nullptr ) {
constexpr auto VignettingStringObfuscated = make_obfuscated < 0x4A > ( " 8B ?? 83 ?? ?? 7D ?? 89 B3 ?? ?? ?? ?? EB " ) ;
2025-08-20 10:53:58 +02:00
Vignettingaddress = Memory : : AOBScan ( gameExecutable , VignettingStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 4474088 - C7 83 B0 1F 00 00 00 00 80 3F - mov[rbx + 00001FB0], 3F800000
//"Project_Plague-Win64-Shipping.exe" + 4474092 - 48 8B 05 87 FE 1F 04 - mov rax, ["Project_Plague-Win64-Shipping.exe" + 8673F20]
//"Project_Plague-Win64-Shipping.exe" + 4474099 - 8B 08 - mov ecx, [rax]
//"Project_Plague-Win64-Shipping.exe" + 447409B - 83 F9 02 - cmp ecx, 02
//"Project_Plague-Win64-Shipping.exe" + 447409E - 7D 08 - jnl "Project_Plague-Win64-Shipping.exe" + 44740A8
2025-08-08 10:46:57 +02:00
if ( ! Vignettingaddress )
logger - > warn ( " Vignetting signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
logger - > info ( " Vignetting signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( Vignettingaddress ) ) ;
2025-07-31 10:38:51 +02:00
}
}
2025-08-08 10:46:57 +02:00
if ( Fogaddress = = nullptr ) {
constexpr auto FogStringObfuscated = make_obfuscated < 0x4A > ( " 75 ?? B3 ?? EB ?? 32 ?? 48 8B ?? ?? ?? 48 ?? ?? 74 ?? E8 ?? ?? ?? ?? 0F ?? ?? 48 8B " ) ;
2025-08-20 10:53:58 +02:00
Fogaddress = Memory : : AOBScan ( gameExecutable , FogStringObfuscated . decrypt ( ) , PAGE_EXECUTE_READ ) ;
//"Project_Plague-Win64-Shipping.exe" + 28E27FD - 48 8B 05 54 9A C6 05 - mov rax, ["Project_Plague-Win64-Shipping.exe" + 854C258]
//"Project_Plague-Win64-Shipping.exe" + 28E2804 - 83 78 04 01 - cmp dword ptr[rax + 04], 01
//"Project_Plague-Win64-Shipping.exe" + 28E2808 - 75 04 - jne "Project_Plague-Win64-Shipping.exe" + 28E280E
//"Project_Plague-Win64-Shipping.exe" + 28E280A - B3 01 - mov bl, 01
//"Project_Plague-Win64-Shipping.exe" + 28E280C - EB 02 - jmp "Project_Plague-Win64-Shipping.exe" + 28E2810
2025-08-08 10:46:57 +02:00
if ( ! Fogaddress )
logger - > warn ( " Fog signature not found. Maybe your game has been updated and is no more compatible with this plugin. " ) ;
else {
logger - > info ( " Fog signature found at address: 0x{:X}. " , reinterpret_cast < uintptr_t > ( Fogaddress ) ) ;
}
}
if ( HORPLUSaddress & & DOFaddress & & Vignettingaddress & & Fogaddress ) {
logger - > info ( " All AOB signatures found. Ready to patch... " ) ;
AOBScanDone = true ;
}
logger - > info ( " --------------- AOB scan finished --------------- " ) ;
2025-07-31 10:38:51 +02:00
}
if ( g_fix_enabled ) {
2025-08-08 10:46:57 +02:00
if ( HORPLUSaddress ) HORPlusFixEnabled ( g_aspect_ratio_axis_constrain_fix_enabled ) ;
2025-07-31 10:38:51 +02:00
if ( DOFaddress ) DOFFixEnabled ( g_DOF_fix_enabled ) ;
2025-08-08 10:46:57 +02:00
if ( Vignettingaddress ) VignettingFixEnabled ( g_Vignetting_fix_enabled ) ;
if ( Fogaddress ) FogFixEnabled ( g_Fog_fix_enabled ) ;
2025-07-31 10:38:51 +02:00
}
else {
2025-08-08 10:46:57 +02:00
if ( HORPLUSaddress ) HORPlusFixEnabled ( false ) ;
2025-07-31 10:38:51 +02:00
if ( DOFaddress ) DOFFixEnabled ( false ) ;
2025-08-08 10:46:57 +02:00
if ( Vignettingaddress ) VignettingFixEnabled ( false ) ;
if ( Fogaddress ) FogFixEnabled ( false ) ;
2025-07-31 10:38:51 +02:00
logger - > info ( " All fixes disabled. " ) ;
}
}
// Setters for Reshade addon call
2025-08-08 10:46:57 +02:00
extern " C " __declspec ( dllexport ) void SetARAxisConstrainFixEnabled ( bool enabled , bool init )
2025-07-31 10:38:51 +02:00
{
2025-08-08 10:46:57 +02:00
g_aspect_ratio_axis_constrain_fix_enabled = enabled ;
if ( ! init ) HORPlusFixEnabled ( g_aspect_ratio_axis_constrain_fix_enabled ) ;
2025-07-31 10:38:51 +02:00
}
extern " C " __declspec ( dllexport ) void SetDOFFixEnabled ( bool enabled , bool init )
{
g_DOF_fix_enabled = enabled ;
if ( ! init ) DOFFixEnabled ( g_DOF_fix_enabled ) ;
}
2025-08-08 10:46:57 +02:00
extern " C " __declspec ( dllexport ) void SetVignettingFixEnabled ( bool enabled , bool init )
2025-07-31 10:38:51 +02:00
{
2025-08-08 10:46:57 +02:00
g_Vignetting_fix_enabled = enabled ;
if ( ! init ) VignettingFixEnabled ( g_Vignetting_fix_enabled ) ;
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
extern " C " __declspec ( dllexport ) void SetFogFixEnabled ( bool enabled , bool init )
{
g_Fog_fix_enabled = enabled ;
if ( ! init ) FogFixEnabled ( g_Fog_fix_enabled ) ;
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
// 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 " ) ;
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
if ( ! fix_enabled & & HORPLUSaddress ) {
Memory : : RestoreBytes ( HORPLUSaddress ) ;
logger - > info ( " HOR+ fix disabled " ) ;
2025-07-31 10:38:51 +02:00
}
}
2025-08-08 10:46:57 +02:00
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
logger - > info ( " Depth of field fix enabled " ) ;
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
if ( ! fix_enabled & & DOFaddress ) {
Memory : : RestoreBytes ( DOFaddress ) ;
logger - > info ( " Depth of field fix disabled " ) ;
2025-07-31 10:38:51 +02:00
}
}
2025-08-08 10:46:57 +02:00
static void VignettingFixEnabled ( bool fix_enabled ) {
if ( g_fix_enabled & & fix_enabled & & Vignettingaddress ) {
Memory : : PatchBytes ( Vignettingaddress , " \x31 \xC9 " , 2 ) ; // xor ecx,ecx r.Tonemapper.Quality=0
logger - > info ( " Vignetting fix enabled " ) ;
}
if ( ! fix_enabled & & Vignettingaddress ) {
Memory : : RestoreBytes ( Vignettingaddress ) ;
logger - > info ( " Vignetting fix disabled " ) ;
2025-07-31 10:38:51 +02:00
}
}
2025-08-08 10:46:57 +02:00
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
logger - > info ( " Fog fix enabled " ) ;
2025-07-31 10:38:51 +02:00
}
2025-08-08 10:46:57 +02:00
if ( ! fix_enabled & & Fogaddress ) {
Memory : : RestoreBytes ( Fogaddress ) ;
logger - > info ( " Fog fix disabled " ) ;
2025-07-31 10:38:51 +02:00
}
}
static void InitializeLogger ( )
{
try
{
std : : filesystem : : path log_path = std : : filesystem : : absolute ( PLUGIN_LOG ) ;
if ( std : : filesystem : : exists ( log_path ) )
std : : filesystem : : remove ( log_path ) ;
logger = std : : make_shared < spdlog : : logger > ( " Wuchang Fallen Feathers " , std : : make_shared < spdlog : : sinks : : rotating_file_sink_st > ( PLUGIN_LOG , 10 * 1024 * 1024 , 1 ) ) ;
logger - > flush_on ( spdlog : : level : : debug ) ; // Flush automatically
}
catch ( const spdlog : : spdlog_ex & ex )
{
std : : string plugin_error_message = " Could not open " + PLUGIN_LOG ;
MessageBoxA ( nullptr , plugin_error_message . c_str ( ) , " Logger Error " , MB_ICONERROR | MB_OK ) ;
}
}
// Standard dll entry
BOOL APIENTRY DllMain ( HMODULE hModule , DWORD reason , LPVOID )
{
if ( reason = = DLL_PROCESS_ATTACH )
{
InitializeLogger ( ) ;
logger - > info ( " Plugin {} loaded. " , PLUGIN_NAME ) ;
}
else if ( reason = = DLL_PROCESS_DETACH )
{
logger - > info ( " Plugin {} unloaded. " , PLUGIN_NAME ) ;
spdlog : : drop_all ( ) ;
}
return TRUE ;
}