diff --git a/EternalStrands/dllmain.cpp b/EternalStrands/dllmain.cpp index 23f816b..f26f508 100644 --- a/EternalStrands/dllmain.cpp +++ b/EternalStrands/dllmain.cpp @@ -1,29 +1,21 @@ -#include -#include "CommonHeaders.h" -#include "GameFixes.h" -#include "GameInformations.h" -#include "ObfuscateString.h" -#include "Memory.hpp" -#include "Maths.hpp" +#include "CommonHeaders.h" +#include "Logger.hpp" #include "UEngine.hpp" +#include "UETools.hpp" #include "SDK/Basic.hpp" #include "SDK/Engine_classes.hpp" -#include "SDK/UMG_classes.hpp" #include "SDK/BPW_UI_HUD_Expedition_classes.hpp" -//#include "SDK/BPW_UI_HUD_Vitals_Stamina_3D_classes.hpp" -#include "SDK/BPW_UI_HUD_Vitals_classes.hpp" -#include "SDK/BPW_UI_HUD_Compass_classes.hpp" -//#include "SDK/BPW_UI_HUD_MagicandWeaponSelector_classes.hpp" -//#include "SDK/BPW_UI_HUD_EpicHealthBar_classes.hpp" +#include "SDK/BPW_UI_HUD_Basecamp_classes.hpp" using namespace SDK; // Constants const std::string PLUGIN_NAME = "EternalStrands"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; - // Logger std::shared_ptr logger; +// Screen informations +static int screenWidth = GetSystemMetrics(SM_CXSCREEN); // Plugin states static bool AOBScanDone = false; @@ -32,20 +24,22 @@ static bool g_fix_enabled = false; static bool g_fov_fix_enabled = false; static bool g_ultrawide_fix_enabled = false; static bool g_Camera_fix_enabled = false; +static bool g_HUD_fix_enabled = false; static bool g_DOF_fix_enabled = false; static bool g_CA_fix_enabled = false; static bool g_Vignetting_fix_enabled = false; static bool g_Fog_fix_enabled = false; static bool g_VolumetricFog_fix_enabled = false; static int g_AdditionalFOVValue = 0; +static int g_HUDOffsets = 0; static float g_cameraDistanceMultiplier = 1.f; +static bool user_inputs_logged = false; // Shared values static float g_FOV_In = 60.f; static float g_FOV_Out = 60.f; static float g_Camera_In = 450.f; static float g_Camera_Out = 450.f; -static bool g_Console_Enabled = false; // AOB Unreal Engine offsets addresses static uint8_t* GObjectsaddress = nullptr; @@ -67,6 +61,7 @@ static uint8_t* NativeConstructaddress = nullptr; // Hooking static SafetyHookMid FOVHook{}; +static SafetyHookMid PEHook{}; static SafetyHookMid CameraHook{}; static SafetyHookMid FogHook{}; static SafetyHookMid ProcessEventHook{}; @@ -82,7 +77,12 @@ static void VignettingFixEnabled(); static void FogFixEnabled(); static void VolumetricFogFixEnabled(); static void EnableConsole(); -static void HUDFixEnabled(); +static void HUDFixEnabled(UWidget* widget, int left, int right, bool writeLog, int depth = INT_MAX); +static void ProcessEvent(); +// Unreal Engine variables +static UBPW_UI_HUD_Basecamp_C* g_BaseCampHUD = nullptr; +static UBPW_UI_HUD_Basecamp_C* g_BaseCampLayer = nullptr; +static UBPW_UI_HUD_Expedition_C* g_ExpeditionHUD = nullptr; extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) { @@ -241,12 +241,18 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!init && FOVaddress) FOVFixEnabled(); if (!init && AspectRatioAxisConstraintaddress && ConstrainAspectRatioaddress) UltraWideFixEnabled(); if (!init && Cameraaddress) CameraFixEnabled(); + if (!init) { + HUDFixEnabled(g_BaseCampHUD, g_HUDOffsets, g_HUDOffsets, true); + HUDFixEnabled(g_ExpeditionHUD, g_HUDOffsets, g_HUDOffsets, false, 3); + HUDFixEnabled(g_BaseCampLayer, 0.f, g_HUDOffsets, false, 1); + } if (!init && DOFaddress) DOFFixEnabled(); if (!init && CAaddress) CAFixEnabled(); if (!init && Vignettingaddress) VignettingFixEnabled(); if (!init && Fogaddress) FogFixEnabled(); if (!init && VolumetricFogaddress) VolumetricFogFixEnabled(); if (!init && GObjectsaddress && AppendStringaddress && ProcessEventaddress) EnableConsole(); + ProcessEvent(); } // Setters for Reshade addon call @@ -255,6 +261,10 @@ extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enable if (fix == GameFixes::DevConsole) { g_Console = enabled; EnableConsole(); }; if (fix == GameFixes::FOV) { g_fov_fix_enabled = enabled; FOVFixEnabled(); } if (fix == GameFixes::UltraWide) { g_ultrawide_fix_enabled = enabled; UltraWideFixEnabled(); } + if (fix == GameFixes::HUD) { g_HUD_fix_enabled = enabled; + HUDFixEnabled(g_BaseCampHUD, g_HUDOffsets, g_HUDOffsets, true); + HUDFixEnabled(g_ExpeditionHUD, g_HUDOffsets, g_HUDOffsets, false, 3); + HUDFixEnabled(g_BaseCampLayer, 0.f, g_HUDOffsets, false, 1); } if (fix == GameFixes::Camera) { g_Camera_fix_enabled = enabled; CameraFixEnabled(); } if (fix == GameFixes::DOF) { g_DOF_fix_enabled = enabled; DOFFixEnabled(); } if (fix == GameFixes::ChromaticAberrations) { g_CA_fix_enabled = enabled; CAFixEnabled(); } @@ -263,16 +273,16 @@ extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enable if (fix == GameFixes::VolumetricFog) { g_VolumetricFog_fix_enabled = enabled; VolumetricFogFixEnabled(); } } -extern "C" __declspec(dllexport) void SetFOV(int fov) -{ - g_AdditionalFOVValue = fov; +extern "C" __declspec(dllexport) void SetValues(GameSetting setting, float value) { + if (setting == GameSetting::FOV) g_AdditionalFOVValue = (int)(value); + if (setting == GameSetting::CameraDistance) g_cameraDistanceMultiplier = value; + if (setting == GameSetting::HUD) { + g_HUDOffsets = ((int)value * screenWidth) / 100; + HUDFixEnabled(g_BaseCampHUD, g_HUDOffsets, g_HUDOffsets, false); + HUDFixEnabled(g_ExpeditionHUD, g_HUDOffsets, g_HUDOffsets, false, 3); + HUDFixEnabled(g_BaseCampLayer, 0.f, g_HUDOffsets, false, 1); + } } - -extern "C" __declspec(dllexport) void SetCameraDistance(float cameraDistance) -{ - g_cameraDistanceMultiplier = cameraDistance; -} - // Getters for Reshade addon call extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { if (!infos) return; @@ -285,6 +295,41 @@ extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) { } // Code injection functions +static void ProcessEvent() { + if (!PEHook && ProcessEventaddress) { + PEHook = safetyhook::create_mid(ProcessEventaddress + 0xc, + [](SafetyHookContext& ctx) { + UObject* object = (UObject*)ctx.rcx; + UFunction* func = (UFunction*)ctx.rdx; + + if (object && func && object->IsA(UUserWidget::StaticClass())) { + std::string funcName = func->GetName(); + + if (funcName == "Construct") TrackWidgetConstruct((SDK::UUserWidget*)object); + if (funcName == "Destruct") TrackWidgetDestruct((SDK::UUserWidget*)object); + + // HUD + if (object->IsA(UBPW_UI_HUD_Basecamp_C::StaticClass())) { + auto* widget = static_cast(object); + if (widget) { + g_BaseCampHUD = widget; + HUDFixEnabled(g_BaseCampHUD, g_HUDOffsets, g_HUDOffsets, false, 3); + } + } + if (object->IsA(UBPW_UI_HUD_Expedition_C::StaticClass())) { + auto* widget = static_cast(object); + if (widget) { + g_ExpeditionHUD = widget; + g_BaseCampLayer = widget->BPW_HUD_BasecampLayer; + HUDFixEnabled(g_ExpeditionHUD, g_HUDOffsets, g_HUDOffsets, false, 3); + HUDFixEnabled(g_BaseCampLayer, 0.f, g_HUDOffsets, false, 1); + } + } + } + }); + } +} + static void FOVFixEnabled() { if (g_fix_enabled && g_fov_fix_enabled && FOVaddress) { if (!FOVHook) { // Hook only once @@ -341,61 +386,13 @@ static void CameraFixEnabled() { } } -static void HUDFixEnabled() { - //if (NativeConstructaddress) { - // if (!NativeConstructHook) { - // NativeConstructHook = safetyhook::create_mid(NativeConstructaddress, - // [](SafetyHookContext& ctx) { - // if (!ctx.rcx) return; +static void HUDFixEnabled(UWidget* widget, int left, int right, bool writeLog, int depth) { + if (writeLog) logger->info("HUD fix {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled"); + if (!widget) return; - // auto* widget = reinterpret_cast(ctx.rcx); - // if (!widget) return; - // std::string widgetName = widget->GetName(); - - // //logger->debug("Widget class name: {}", widgetName); - // if (widgetName.contains("BPW_UI_HUD_Expedition_C") && widget->IsA(UBPW_UI_HUD_Expedition_C::StaticClass())) { - // auto* expeditionHUD = static_cast(widget); - - // if (expeditionHUD->BPW_UI_HUD_Compass && expeditionHUD->BPW_UI_HUD_Compass->Img_Compass) { - // auto compassImage = expeditionHUD->BPW_UI_HUD_Compass->Img_Compass; - // //expeditionHUD->BPW_InventoryWheel-> - // if (auto compassSlot = static_cast(compassImage->Slot)) - // compassSlot->SetPadding({ 0, 0, 650, 0 }); - // } - // auto* HUDVitals = expeditionHUD->BPW_Vitals; - - // std::thread([HUDVitals]() { - // std::this_thread::sleep_for(std::chrono::milliseconds(100)); - - // auto healthImage = HUDVitals->Img_HealthGauge; - // auto manaImage = HUDVitals->Img_ManaGauge; - // auto manaSMoke = HUDVitals->VFX_ManaSmoke; - // auto MantlePowerImage = HUDVitals->Img_MantlePower; - - // if (MantlePowerImage && MantlePowerImage->Slot && - // MantlePowerImage->Slot->IsA(UOverlaySlot::StaticClass())) { - // auto* mantlePowerSlot = static_cast(MantlePowerImage->Slot); - // mantlePowerSlot->SetPadding({ 650, 0, 0, 0 }); - // } - - // if (manaImage && manaImage->Slot && - // manaImage->Slot->IsA(UOverlaySlot::StaticClass())) { - // auto* manaSlot = static_cast(manaImage->Slot); - // manaSlot->SetPadding({ 650, 0, 0, 0 }); - // } - - // if (manaSMoke && manaSMoke->Slot && - // manaSMoke->Slot->IsA(UOverlaySlot::StaticClass())) { - // auto* manaSMokeSlot = static_cast(manaSMoke->Slot); - // manaSMokeSlot->SetPadding({ 650, 0, 0, 0 }); - // } - // //HUDVitals->InvalidateLayoutAndVolatility(); - // logger->debug("[HUD] Vitals repositioned after delay"); - // }).detach(); - // } - // }); - // } - //} + float targetOffsetLeft = g_fix_enabled && g_HUD_fix_enabled ? left : 0.f; + float targetOffsetRight = g_fix_enabled && g_HUD_fix_enabled ? right : 0.f; + ApplyOffsetsRecursive(widget, targetOffsetLeft, targetOffsetRight, depth); } // Memory patch fixes static void UltraWideFixEnabled() { @@ -456,77 +453,23 @@ static void VolumetricFogFixEnabled() { } // UE Console creation -static void EnableConsole() -{ +static void EnableConsole() { if (g_Console_Enabled || !g_Console || !GObjectsaddress || !AppendStringaddress || !ProcessEventaddress) { - if (!g_Console && g_fix_enabled) + if (!g_Console && !user_inputs_logged) { logger->info("------------------ User inputs ------------------"); + user_inputs_logged = true; + } return; } logger->info("-------------- Console re-enabling --------------"); - std::thread([&]() { - auto start = std::chrono::high_resolution_clock::now(); // Measure the time to renable console - UEngine* Engine = nullptr; - - for (int i = 0; i < 10; ++i) { // gives 10 seconds to find UE Engine - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - Engine = UEngine::GetEngine(); - if (Engine && Engine->ConsoleClass && Engine->GameViewport) - break; - } - - if (!Engine || !Engine->ConsoleClass || !Engine->GameViewport) { - logger->error("Console could not be found in engine."); - return; - } - logger->info("Console found in engine"); - - /* Creates a new UObject of class-type specified by Engine->ConsoleClass */ - UObject* NewObject = UGameplayStatics::SpawnObject(Engine->ConsoleClass, Engine->GameViewport); - if (NewObject) - { - logger->info("Successfully spawned console object"); - // Set the console viewport so that it will be displayed - Engine->GameViewport->ViewportConsole = static_cast(NewObject); - auto end = std::chrono::high_resolution_clock::now(); - std::chrono::duration elapsed = end - start; - - logger->info("Console fully reactivated in {:.3f}s and bound to key Tilde", elapsed.count()); - logger->info("------------------ User inputs ------------------"); - - g_Console_Enabled = true; - } - else { - logger->error("Could not spawn console object"); - } - }).detach(); -} - -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("Eternal Strands", std::make_shared(PLUGIN_LOG, 10 * 1024 * 1024, 1)); - logger->set_level(spdlog::level::debug); - 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); - } + ReactivateDevConsole(logger); } // Standard dll entry -BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) -{ - if (reason == DLL_PROCESS_ATTACH) - { - InitializeLogger(); +BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID) { + if (reason == DLL_PROCESS_ATTACH) { + logger = InitializeLogger("Eternal Strands", PLUGIN_LOG); logger->info("Plugin {} loaded.", PLUGIN_NAME); } else if (reason == DLL_PROCESS_DETACH)