diff --git a/WuchangFF/dllmain.cpp b/WuchangFF/dllmain.cpp index ece4d7e..45a8733 100644 --- a/WuchangFF/dllmain.cpp +++ b/WuchangFF/dllmain.cpp @@ -1,6 +1,7 @@ #include "CommonHeaders.h" #include "UEngine.hpp" #include "UETools.hpp" +#include "UEWidgets.hpp" #include "UEvars.hpp" #include "Logger.hpp" #include "SDK/Basic.hpp" @@ -8,15 +9,21 @@ #include "SDK/BP_CombatCharacter_Player_Final_classes.hpp" #include "SDK/ExtendedStatComponent_Stamina_classes.hpp" #include "SDK/Impl_BaseAIController_classes.hpp" +#include "SDK/WB_MainUI_classes.hpp" +#include "SDK/WB_ShowAddItemMain_New_classes.hpp" +#include "SDK/WB_NewHelpBlock_classes.hpp" +#include "SDK/WB_GameSaving_classes.hpp" +#include "SDK/WB_PoseMain_classes.hpp" +#include "SDK/WB_PlayerCoins_classes.hpp" +#include "SDK/WB_NewPlayerGuidelines_classes.hpp" using namespace SDK; // Constants const std::string PLUGIN_NAME = "WuchangFF"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; -constexpr ULONGLONG DEFAULT_DELAY_BETWEEN_TICK = 500; // Used ProcessEvent tick +constexpr ULONGLONG DEFAULT_DELAY_BETWEEN_TICK = 1000; // Used ProcessEvent tick constexpr ULONGLONG DEFAULT_DELAY_BETWEEN_ACTOR_TICK = 30; // Used for enemies tick - // Logger std::shared_ptr logger; @@ -44,6 +51,7 @@ static std::atomic g_Stamina_fix_enabled = false; static std::atomic g_Stealth_fix_enabled = false; static int g_AdditionalFOVValue = 0; static float g_CameraMultiplier = 1.f; +static int g_HUDOffsets = 0; static float g_WorldTimeDilationValue = 1.f; static float g_AITimeDilationValue = 1.f; static bool user_inputs_logged = false; @@ -77,6 +85,7 @@ static SafetyHookMid TimeDilationHook{}; // Prototypes static void FOVFixEnabled(); static void UltraWideFixEnabled(GameFixes fix); +static void HUDUpdate(bool writeLog); static void CameraDistanceFixEnabled(); static void DOFFixEnabled(); static void CAFixEnabled(); @@ -146,6 +155,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) { } if (!init && CameraDistanceaddress) CameraDistanceFixEnabled(); if (!init && DOFaddress) DOFFixEnabled(); + if (!init) HUDUpdate(true); if (!init && Vignettingaddress) VignettingFixEnabled(); if (!init && Fogaddress) FogFixEnabled(); if (!init && WorldTimedilationaddress) { @@ -163,6 +173,7 @@ extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enable if (fix == GameFixes::FOV) { g_fov_fix_enabled = enabled; FOVFixEnabled(); } if (fix == GameFixes::UltraWide) { g_ultrawide_fix_enabled = enabled; UltraWideFixEnabled(GameFixes::UltraWide); } if (fix == GameFixes::Camera) { g_Camera_fix_enabled = enabled; CameraDistanceFixEnabled(); } + if (fix == GameFixes::HUD) { g_HUD_fix_enabled = enabled; HUDUpdate(true); } if (fix == GameFixes::DOF) { g_DOF_fix_enabled = enabled; DOFFixEnabled(); } if (fix == GameFixes::Vignetting) { g_Vignetting_fix_enabled = enabled; VignettingFixEnabled(); } if (fix == GameFixes::Fog) { g_Fog_fix_enabled = enabled; FogFixEnabled(); } @@ -177,6 +188,10 @@ extern "C" __declspec(dllexport) void SetValues(GameSetting setting, float value if (setting == GameSetting::CameraDistance) g_CameraMultiplier = value; if (setting == GameSetting::WorldTimeDilation) g_WorldTimeDilationValue = value; if (setting == GameSetting::AITimeDilation) g_AITimeDilationValue = value; + if (setting == GameSetting::HUD) { + g_HUDOffsets = ((int)value * screenWidth) / 100; + HUDUpdate(false); + } } // Getters for Reshade addon call extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { @@ -196,6 +211,16 @@ extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { } // Code injection functions +static float g_UIScale = 1.f; +static UWidget* playerState = nullptr; +static UWidget* tipPanel = nullptr; +static UWidget* activeSlots = nullptr; +static UWidget* showItems = nullptr; +static UWidget* playerGuideLines = nullptr; +static UWidget* newHelpblock = nullptr; +static UWidget* coins = nullptr; +static UWidget* pose = nullptr; +static UWidget* gameSaving = nullptr; static ULONGLONG lastScanResolutionTick = 0; // Last time Actors were scanned for enemies time dilation static void ProcessEvent() { if (!PEHook && ProcessEventaddress) { @@ -211,12 +236,68 @@ static void ProcessEvent() { } if (object && func) { std::string funcName = func->GetName(); - std::string objectName = object->GetName(); + if (funcName == "Construct") TrackWidgetConstruct((UUserWidget*)object); + if (funcName == "Destruct") TrackWidgetDestruct((UUserWidget*)object); + if (funcName == "Construct" || funcName == "Destruct") { + // Right HUD elements + auto HandleWidget = [&](auto* typedWidget, auto*& gWidgetPtr) { // Lambda to initialize pointers on Construct and nullify them on Destruct + if (funcName == "Construct") { + gWidgetPtr = typedWidget; + HUDUpdate(false); + } + else if (funcName == "Destruct") gWidgetPtr = nullptr; + }; + if (object->IsA(UWB_NewPlayerGuidelines_C::StaticClass())) // valid + HandleWidget(static_cast(object), playerGuideLines); + else if (object->IsA(UWB_GameSaving_C::StaticClass())) // valid + HandleWidget(static_cast(object), gameSaving); + else if (object->IsA(UWB_ShowAddItemMain_New_C::StaticClass())) // valid + HandleWidget(static_cast(object), showItems); + else if (object->IsA(UWB_NewHelpBlock_C::StaticClass())) // valid + HandleWidget(static_cast(object), newHelpblock); + else if (object->IsA(UWB_PoseMain_C::StaticClass())) // valid + HandleWidget(static_cast(object), pose); + else if (object->IsA(UWB_PlayerCoins_C::StaticClass())) // valid + HandleWidget(static_cast(object), coins); + // Left HUD elements (player state, key tips, active slots) + else if (object->IsA(UWB_MainUI_C::StaticClass())) { + auto* HUDWidget = static_cast(object); + if (funcName == "Construct") { + g_UIScale = SDK::UWidgetLayoutLibrary::GetViewportScale(HUDWidget); + //SetLogger(logger); + if (HUDWidget->WB_PlayerState) playerState = reinterpret_cast(HUDWidget->WB_PlayerState); + if (HUDWidget->WB_KeyTipPanel_47) tipPanel = reinterpret_cast(HUDWidget->WB_KeyTipPanel_47); + if (HUDWidget->WB_ActiveSlots) activeSlots = reinterpret_cast(HUDWidget->WB_ActiveSlots); + HUDUpdate(false); + } + if (funcName == "Destruct") { + playerState = nullptr; + tipPanel = nullptr; + activeSlots = nullptr; + } + } + } } }); } } +static void HUDUpdate(bool writeLog) { + if (writeLog) logger->info("HUD & UI scaling fix {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled"); + float HUDoffset = (g_fix_enabled && g_HUD_fix_enabled) ? g_HUDOffsets : 0.f; + + ApplyTransformOffset(playerState, HUDoffset / g_UIScale); + ApplyTransformOffset(tipPanel, HUDoffset / g_UIScale); + ApplyTransformOffset(pose, HUDoffset / g_UIScale); + ApplyTransformOffset(activeSlots, -(HUDoffset / g_UIScale)); + ApplyTransformOffset(showItems, -(HUDoffset / g_UIScale)); + ApplyTransformOffset(playerGuideLines, -(HUDoffset / g_UIScale)); + ApplyTransformOffset(newHelpblock, -(HUDoffset / g_UIScale)); + ApplyTransformOffset(gameSaving, -(HUDoffset / g_UIScale)); + ApplyTransformOffset(coins, -(HUDoffset / g_UIScale)); +} + + static bool bHastoCompensateFOV = false; static float currentAspect = 0.f; static void FOVFixEnabled() { @@ -308,13 +389,15 @@ static void EnableCheats(Cheat cheat) { if (controller && controller->IsA(AImpl_BaseAIController_C::StaticClass())) { // enemy spotted auto* aiController = static_cast(controller); if (aiController && aiController->Perception) { - if (g_Stealth_fix_enabled) aiController->EnableAlertPerception(false); - else { - aiController->EnableAlertPerception(true); - aiController->FlushEnableSense(); - aiController->UpdateSenseTarget(); + if (!aiController->IsBoss) { // Won't apply to bosses to avoid breaking the fight + if (g_Stealth_fix_enabled) aiController->EnableAlertPerception(false); + else { + aiController->EnableAlertPerception(true); + aiController->FlushEnableSense(); + aiController->UpdateSenseTarget(); + } } - } + } character->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; } } @@ -407,6 +490,7 @@ static void EnableConsole() { logger->info("-------------- Console re-enabling --------------"); ReactivateDevConsole(logger); } + // Standard dll entry BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { if (reason == DLL_PROCESS_ATTACH) {