From 480a475a229ffefa329ab2ddd121ed313b607b90 Mon Sep 17 00:00:00 2001 From: Emmanuel AYME Date: Tue, 24 Feb 2026 07:14:14 +0100 Subject: [PATCH] Add HUD & UI scaling. Enemies time dilation imporvement. --- Cronos The New Dawn/dllmain.cpp | 195 +++++++++++++++++++++----------- 1 file changed, 132 insertions(+), 63 deletions(-) diff --git a/Cronos The New Dawn/dllmain.cpp b/Cronos The New Dawn/dllmain.cpp index f109195..4713139 100644 --- a/Cronos The New Dawn/dllmain.cpp +++ b/Cronos The New Dawn/dllmain.cpp @@ -12,7 +12,6 @@ using namespace SDK; const std::string PLUGIN_NAME = "CronosTND"; const std::string PLUGIN_LOG = PLUGIN_NAME + ".log"; const float baseAspect = 1.7777778; -constexpr ULONGLONG DEFAULT_ACTORS_SCAN_BETWEEN_TICKS = 300; // Used for enemies time dilation // Logger std::shared_ptr logger; @@ -21,35 +20,34 @@ std::shared_ptr logger; static int screenWidth = GetSystemMetrics(SM_CXSCREEN); static int screenHeight = GetSystemMetrics(SM_CYSCREEN); static float aspectRatio = (float)screenWidth / screenHeight; - // Plugin states static bool AOBScanDone = false; static bool g_Console = false; static bool g_fix_enabled = false; static bool g_fov_fix_enabled = false; static bool g_aspect_fix_enabled = false; +static bool g_HUD_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 bool g_cam_distance_fix_enabled = false; static bool g_SkipIntro_fix_enabled = false; static bool g_TimeDilation_fix_enabled = false; -static bool g_GodeMode_fix_enabled = false; +static bool g_GodMode_fix_enabled = false; static bool g_IgnoreHits_fix_enabled = false; static bool g_Stealth_fix_enabled = false; static int g_AdditionalFOVValue = 0; +static int g_HUDOffsets = 0; static float g_cameraDistanceMultiplier = 1.f; static float g_WorldTimeDilationValue = 1.f; static float g_AITimeDilationValue = 1.f; static bool user_inputs_logged = false; - // Shared values static float g_FOV_In = 0; static float g_Compensated_FOV = 0; static float g_FOV_Out = 0; static float g_Camera_In = 180; static float g_Camera_Out = 180; - // AOB Scan pointers static uint8_t* FOVaddress = nullptr; static uint8_t* Aspectaddress = nullptr; @@ -59,9 +57,9 @@ static uint8_t* Fogaddress = nullptr; static uint8_t* FogOpacityEngineaddress = nullptr; static uint8_t* CameraDistanceaddress = nullptr; static uint8_t* WorldTimedilationaddress = nullptr; +static uint8_t* Timedilationaddress = nullptr; static uint8_t* GodModeaddress = nullptr; static uint8_t* StealthModeaddress = nullptr; - // Hooking static SafetyHookMid FOVHook{}; static SafetyHookMid AspectHook{}; @@ -70,11 +68,12 @@ static SafetyHookMid FogMaxOpacityHook{}; static SafetyHookMid CameraDistanceHook{}; static SafetyHookMid PEHook{}; static SafetyHookMid WorldTimeDilationHook{}; +static SafetyHookMid TimeDilationHook{}; static SafetyHookMid StealthHook{}; - // Prototypes static void FOVFixEnabled(); static void UltrawideFixEnabled(); +static void HUDFixEnabled(UWidget* widget, bool writeLog, int depth = INT_MAX); static void DOFFixEnabled(); static void VignettingFixEnabled(); static void FogFixEnabled(); @@ -82,9 +81,13 @@ static void CameraDistanceFixEnabled(); static void EnableConsole(); static void ProcessEvent(); static void EnableCheats(Cheat cheat); +// UEngine variable +UWidget* g_HUDWidget = nullptr; +UWidget* g_WorkbenchWidget = nullptr; +UWidget* g_SettingsWidget = nullptr; +UWidget* g_TutorialWidget = nullptr; -extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) -{ +extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) { g_fix_enabled = enabled; if (!AOBScanDone) { // Unreal Engine 5.5.4 logger->info("--------------- AOB scan started ---------------"); @@ -100,6 +103,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) constexpr auto FogOpacityStringObfuscated = make_obfuscated<0xB3>("0F 2E ?? C4 02 ?? ?? 74 ?? F3 0F ?? ?? ?? ?? ?? ?? E9 ?? ?? ?? ?? C3"); constexpr auto CamDistanceStringObfuscated = make_obfuscated<0xF2>("E8 ?? ?? ?? ?? F2 0F ?? ?? ?? ?? 48 8D ?? ?? F3 0F ?? ?? ?? ?? ?? ?? 48 8D ?? ?? ?? ?? ?? 0F"); constexpr auto WorldTimeDilationStringObfuscated = make_obfuscated<0X59>("F3 0F 10 ?? ?? ?? ?? ?? F3 0F 59 ?? ?? ?? ?? ?? F3 0F 59 ?? ?? ?? ?? ?? C3"); + constexpr auto TimeDilationStringObfuscated = make_obfuscated<0x44>("F3 0F ?? ?? ?? EB ?? F3 0F ?? ?? ?? ?? ?? ?? 48 8B ?? ?? 4C ?? ?? F3 0F ?? ?? 44"); constexpr auto GodModeStringObfuscated = make_obfuscated<0XB8>("F3 41 0F ?? ?? 80 B8 ?? ?? ?? ?? ?? F3 0F ?? ?? F3 0F ?? ?? 74"); constexpr auto StealthStringObfuscated = make_obfuscated<0XDB>("FF 90 C0 04 ?? ?? 48 8B ?? ?? ?? 48 ?? ?? 74 ?? E8 ?? ?? ?? ?? 48 8B ?? ?? ?? 48 8B ?? ?? ?? 48 83 ?? ?? 5F C3"); // Prepare all data for scanning @@ -112,6 +116,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) Make(&Fogaddress, FogStringObfuscated, "Fog"), Make(&FogOpacityEngineaddress, FogOpacityStringObfuscated, "Fog opacity"), Make(&WorldTimedilationaddress, WorldTimeDilationStringObfuscated, "World time dilation"), + Make(&Timedilationaddress, TimeDilationStringObfuscated, "Actor time dilation"), Make(&GodModeaddress, GodModeStringObfuscated, "God mode"), Make(&StealthModeaddress, StealthStringObfuscated, "Stealth") }; @@ -148,6 +153,12 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) if (!init && FOVaddress) FOVFixEnabled(); if (!init && Aspectaddress) UltrawideFixEnabled(); + if (!init) { + HUDFixEnabled(g_HUDWidget, true); + HUDFixEnabled(g_WorkbenchWidget, false, 1); + HUDFixEnabled(g_SettingsWidget, false, 1); + HUDFixEnabled(g_TutorialWidget, false, 1); + } if (!init && DOFaddress) DOFFixEnabled(); if (!init && Vignettingaddress) VignettingFixEnabled(); if (!init && Fogaddress && FogOpacityEngineaddress) FogFixEnabled(); @@ -158,7 +169,6 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) EnableCheats(Cheat::IgnoreHits); EnableCheats(Cheat::Stealth); } - ProcessEvent(); } @@ -167,31 +177,36 @@ 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_aspect_fix_enabled = enabled; UltrawideFixEnabled(); } + if (fix == GameFixes::HUD) { g_HUD_fix_enabled = enabled; + HUDFixEnabled(g_HUDWidget, true); + HUDFixEnabled(g_WorkbenchWidget, false, 1); + HUDFixEnabled(g_SettingsWidget, false, 1); + HUDFixEnabled(g_TutorialWidget, false, 1); } if (fix == GameFixes::Camera) { g_cam_distance_fix_enabled = enabled; CameraDistanceFixEnabled(); } 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(); } if (fix == GameFixes::SkipIntro) { g_SkipIntro_fix_enabled = enabled; } if (fix == GameFixes::TimeDilation) { g_TimeDilation_fix_enabled = enabled; EnableCheats(Cheat::TimeDilation); } - if (fix == GameFixes::GodMode) { g_GodeMode_fix_enabled = enabled; EnableCheats(Cheat::GodMode); } + if (fix == GameFixes::GodMode) { g_GodMode_fix_enabled = enabled; EnableCheats(Cheat::GodMode); } if (fix == GameFixes::IgnoreHits) { g_IgnoreHits_fix_enabled = enabled; EnableCheats(Cheat::IgnoreHits); } if (fix == GameFixes::Stealth) { g_Stealth_fix_enabled = enabled; EnableCheats(Cheat::Stealth); } } -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::WorldTimeDilation) g_WorldTimeDilationValue = value; + if (setting == GameSetting::AITimeDilation) + g_AITimeDilationValue = value; -extern "C" __declspec(dllexport) void SetCameraDistance(float cameraDistance) { - g_cameraDistanceMultiplier = cameraDistance; -} - -extern "C" __declspec(dllexport) void SetWorldTimeDilation(float timeDilation) { - g_WorldTimeDilationValue = timeDilation; -} - -extern "C" __declspec(dllexport) void SetAITimeDilation(float timeDilation) { - g_AITimeDilationValue = timeDilation; + if (setting == GameSetting::HUD) { + g_HUDOffsets = ((int)value * screenWidth) / 100; + HUDFixEnabled(g_HUDWidget, true); + HUDFixEnabled(g_WorkbenchWidget, false, 1); + HUDFixEnabled(g_SettingsWidget, false, 1); + HUDFixEnabled(g_TutorialWidget, false, 1); + } } // Getters for Reshade addon calls @@ -214,11 +229,10 @@ static void ProcessEvent() { UObject* object = (UObject*)ctx.rcx; UFunction* func = (UFunction*)ctx.rdx; - if (object && func && g_DOF_fix_enabled) { + if (object && func) { std::string funcName = func->GetName(); std::string objectName = object->GetName(); - std::string objectFullName = object->GetFullName(); - // Skip disclaimers + if (objectName.contains("StartGameMenuWidget")) { auto* widget = static_cast(object); if (widget && widget->Class && widget->IsA(UStartGameWidget::StaticClass()) && funcName == "OnNext" && !inContinue) { @@ -227,6 +241,64 @@ static void ProcessEvent() { inContinue = false; } } + if (funcName == "Construct" || funcName == "Destruct" || funcName.contains("Tick")) { + // UI scaling + if (objectName.contains("StartGameMenuWidget")) { + auto* widget = static_cast(object); + if (widget && widget->Class && widget->IsA(UStartGameWidget::StaticClass()) && funcName == "OnNext" && !inContinue) { + inContinue = true; + if (g_SkipIntro_fix_enabled) widget->Continue(); + inContinue = false; + } + } + else if (objectName.contains("ExtendTutorial_Widget") && object->IsA(UUserWidget::StaticClass())) { + auto* widget = static_cast(object); + if (funcName == "Construct" && widget->WidgetTree && widget->WidgetTree->RootWidget) { + g_TutorialWidget = widget->WidgetTree->RootWidget; + HUDFixEnabled(g_TutorialWidget, false, 1); + } + else if (funcName == "Destruct") g_TutorialWidget = nullptr; + } + else if (objectName.contains("SettingsWidget") && object->IsA(UUserWidget::StaticClass())) { + auto* settingsWidget = static_cast(object); + if (funcName == "Construct") { + if (settingsWidget && settingsWidget->Class && settingsWidget->Main_panel) { + g_SettingsWidget = settingsWidget->Main_panel; + HUDFixEnabled(g_SettingsWidget, false, 1); + } + } + else if (funcName == "Destruct") g_SettingsWidget = nullptr; + } + else if (objectName.contains("WBP_UpgradeMenuWidget_C") && object->IsA(UUserWidget::StaticClass())) { + auto* widget = static_cast(object); + if (funcName == "Construct") { + if (widget && widget->WidgetTree && widget->WidgetTree->RootWidget) { + g_WorkbenchWidget = widget->WidgetTree->RootWidget; + if (g_WorkbenchWidget) HUDFixEnabled(g_WorkbenchWidget, false, 1); + } + } + else if (funcName == "Destruct") g_WorkbenchWidget = nullptr; + } + // HUD scaling + else if (objectName.contains("HudWidget") && object->IsA(USHGameplayHudWidget::StaticClass())) { + USHGameplayHudWidget* HUDWidget = static_cast(object); + if (funcName == "Construct") { + if (HUDWidget && HUDWidget->WidgetTree) { + g_HUDWidget = HUDWidget->WidgetTree->RootWidget; + if (g_HUDWidget) HUDFixEnabled(g_HUDWidget, false); + } + } + else if (funcName.contains("Tick")) { + for (auto* collectWidget : HUDWidget->CollectItemsWidgets) { + if (!collectWidget) continue; + // Apply offset to collectible objects + ApplyOverlayOffsetRecursive(collectWidget->MainOverlay, g_fix_enabled && g_HUD_fix_enabled ? g_HUDOffsets - 100 : 0, + EHorizontalAlignment::HAlign_Fill, { "VerticalBox" }); + } + } + else if (funcName == "Destruct") g_HUDWidget = nullptr; + } + } } }); } @@ -254,6 +326,18 @@ static void FOVFixEnabled() { } } +// HUD fix hook UUserWidget -> AddToViewPort to log and know which HUD widget will be targeted +static void HUDFixEnabled(UWidget* widget, bool writeLog, int depth) { + if (writeLog) logger->info("HUD fix {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled"); + if (!widget) return; + + float targetOffset = g_fix_enabled && g_HUD_fix_enabled ? g_HUDOffsets : 0.f; + if (widget->IsA(UCanvasPanel::StaticClass())) // Apply offsets To CanvasPanel + ApplyOffsetsRecursive(widget, targetOffset, targetOffset, depth); + else // Apply offsets to OvelaySlot + ApplyOverlayOffsetRecursive(widget, targetOffset, EHorizontalAlignment::HAlign_Fill, { "VerticalBox" }, depth); +} + static UExponentialHeightFogComponent* fogComponent = nullptr; static UWorld* previousWorld = nullptr; static void FogFixEnabled() { @@ -284,48 +368,33 @@ static void FogFixEnabled() { } // Cheats -static UWorld* LastWorld = nullptr; -static ULONGLONG lastScanTick = 0; // Last time Actors were scanned for enemies time dilation static void EnableCheats(Cheat cheat) { if (WorldTimedilationaddress && !WorldTimeDilationHook) { WorldTimeDilationHook = safetyhook::create_mid(WorldTimedilationaddress + 0x10, [](SafetyHookContext& ctx) { // From AWorldSettings retrieved from world->K2_GetWorldSettings() ctx.xmm0.f32[0] *= g_TimeDilation_fix_enabled ? g_WorldTimeDilationValue : 1.f; - UWorld* world = UWorld::GetWorld(); - if (!world || !world->OwningGameInstance) return; - if (world != LastWorld) { - LastWorld = world; - } - APawn* playerPawn = GetPawnFromWorld(world); - - ULONGLONG now = GetTickCount64(); - if (now - lastScanTick < DEFAULT_ACTORS_SCAN_BETWEEN_TICKS) return; - lastScanTick = now; - - if (world->Levels.Num() == 0) return; - // Enemies time dilation & stealth - for (int i = 0; i < world->Levels.Num(); i++) { // Loop through level to find actors - ULevel* Level = world->Levels[i]; - if (!Level) continue; - - for (int j = 0; j < Level->Actors.Num(); j++) { // Loop through actors - AActor* actor = Level->Actors[j]; - if (!actor || !playerPawn || actor == playerPawn) continue; // We don't want to affect Traveler - if (!actor->IsA(ACronosBaseEnemyCharacter::StaticClass())) continue; // actor is enemy - // Set enemy alert - ACronosBaseEnemyCharacter* enemy = static_cast(actor); - if (!enemy) continue; - - enemy->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; // Enemy time dilation - } - } - // ignore hits - AActor* traveler = static_cast(playerPawn); - if (traveler) traveler->bCanBeDamaged = !g_IgnoreHits_fix_enabled; // Traveler won't be hurt }); } + // Enemies time dilation + if (Timedilationaddress && !TimeDilationHook) { + TimeDilationHook = safetyhook::create_mid(Timedilationaddress, + [](SafetyHookContext& ctx) { + if (!ctx.rbx) return; + UObject* object = (UObject*)ctx.rbx; + if (!object || !object->Class) return; + + if (object->IsA(ACronosBaseEnemyCharacter::StaticClass())) { + ACronosBaseEnemyCharacter* character = static_cast(object); + if (character->Controller && character->Controller->IsA(AAIController::StaticClass())) { + AActor* enemy = static_cast(character); + if (enemy) + enemy->CustomTimeDilation = g_TimeDilation_fix_enabled ? g_AITimeDilationValue : 1.f; + } + } + }); + } if (StealthModeaddress && !StealthHook) { // Hook function UAIPerceptionComponent -> GetPerceivedHostileActors StealthHook = safetyhook::create_mid(StealthModeaddress - 0x86, [](SafetyHookContext& ctx) { @@ -336,12 +405,12 @@ static void EnableCheats(Cheat cheat) { perception->ForgetAll(); }); } - if (g_GodeMode_fix_enabled && GodModeaddress) + if (g_GodMode_fix_enabled && GodModeaddress) Memory::PatchBytes(GodModeaddress, "\x90\x90\x90\x90\x90", 5); // subss xmm6,xmm9 - if (!g_GodeMode_fix_enabled && GodModeaddress) Memory::RestoreBytes(GodModeaddress); + if (!g_GodMode_fix_enabled && GodModeaddress) Memory::RestoreBytes(GodModeaddress); if (cheat == Cheat::TimeDilation) logger->info("Time dilation cheat {}", g_TimeDilation_fix_enabled ? "enabled" : "disabled"); - if (cheat == Cheat::GodMode) logger->info("God mode cheat {}", g_GodeMode_fix_enabled ? "enabled" : "disabled"); + if (cheat == Cheat::GodMode) logger->info("God mode cheat {}", g_GodMode_fix_enabled ? "enabled" : "disabled"); if (cheat == Cheat::IgnoreHits) logger->info("Ignore hits cheat {}", g_IgnoreHits_fix_enabled ? "enabled" : "disabled"); if (cheat == Cheat::Stealth) logger->info("Stealth cheat {}", g_Stealth_fix_enabled ? "enabled" : "disabled"); }