UI repositionning improvements. Add UI widgets repositionning.

This commit is contained in:
2026-03-11 08:08:35 +01:00
parent a0343c1b4d
commit 9c6bcc4753

View File

@@ -2,18 +2,19 @@
#include "CommonHeaders.h"
#include "UEngine.hpp"
#include "UETools.hpp"
#include "UEWidgets.hpp"
#include "UEvars.hpp"
#include "UEMath.hpp"
#include "Logger.hpp"
#include "SDK/Basic.hpp"
#include "SDK/Engine_classes.hpp"
#include "SDK/UI_Settings_classes.hpp"
#include "SDK/UI_InputButton_Menu_classes.hpp"
#include "SDK/UI_Profile_classes.hpp"
#include "SDK/UI_MainMenu_classes.hpp"
#include "SDK/UI_Difficulty_classes.hpp"
#include "SDK/UI_InGameMenu_classes.hpp"
#include "SDK/UI_PauseMenu_classes.hpp"
#include "SDK/UI_Saves_classes.hpp"
#include "SDK/Styx3_classes.hpp"
using namespace SDK;
@@ -30,7 +31,7 @@ std::shared_ptr<spdlog::logger> logger;
static int screenWidth = GetSystemMetrics(SM_CXSCREEN);
static int screenHeight = GetSystemMetrics(SM_CYSCREEN);
float g_AspectRatio = (float)screenWidth / screenHeight;
float g_BaseAspectRatio = 2.39;
float g_BaseAspectRatio = 2.39f;
// Plugin states
static bool AOBScanDone = false;
@@ -94,14 +95,16 @@ static void EnableConsole();
static void EnableCheats(Cheat cheat);
static void ProcessEvent();
// UEngine variable
static UWidget* g_UIMainMenuWidget = nullptr;
static UWidget* g_UISettingsWidget = nullptr;
static UWidget* g_UISettingsDescWidget = nullptr;
static UWidget* g_DifficultyWidget = nullptr;
static UWidget* g_difficultyMenusWidget = nullptr;
static UWidget* g_ProfileWidget = nullptr;
static UWidget* g_InGameMenuWidget = nullptr;
static UWidget* g_PauseWidget = nullptr;
static UUserWidget* g_UIMainMenuWidget = nullptr;
static UUserWidget* g_UISettingsWidget = nullptr;
static UUserWidget* g_DifficultyWidget = nullptr;
static UUserWidget* g_ProfileWidget = nullptr;
static UUserWidget* g_InGameMenuWidget = nullptr;
static UUserWidget* g_PauseWidget = nullptr;
static UUserWidget* g_SavesWidget = nullptr;
static UUserWidget* g_MapWidget = nullptr;
static UUserWidget* g_GameOverWidget = nullptr;
static UUserWidget* g_LoadingWidget = nullptr;
static UWidget* g_StatusWidget = nullptr;
static UWidget* g_GaugesWidget = nullptr;
static UWidget* g_ChangeWheelWidget = nullptr;
@@ -135,7 +138,7 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
Make(&Vignettingaddress, VignettingStringObfuscated, "Vignetting"),
Make(&Fogaddress, FogStringObfuscated, "Fog"),
Make(&WorldTimedilationaddress, WorldTimeDilationStringObfuscated, "World time dilation"),
Make(&Timedilationaddress, TimeDilationStringObfuscated, "Actor time dilation")
Make(&Timedilationaddress, TimeDilationStringObfuscated, "Actor time dilation"),
};
// Scan all signature in a batch
Memory::AOBScanBatch(signatures, logger);
@@ -238,7 +241,7 @@ static void ProcessEvent() {
PEHook = safetyhook::create_mid(ProcessEventaddress + 0xc,
[](SafetyHookContext& ctx) {
ULONGLONG now = GetTickCount64();
if (now - lastScanTick >= DEFAULT_DELAY_BETWEEN_TICK) { // si le délai est passé
if (now - lastScanTick >= DEFAULT_DELAY_BETWEEN_TICK) { // Delay between each tick to avoid ProcessEvent stuttering
lastScanTick = now;
GetResolution(screenWidth, screenHeight, g_AspectRatio);
}
@@ -248,62 +251,52 @@ static void ProcessEvent() {
if (!object || !func) return;
std::string funcName = func->GetName();
// Full stealth fix: disable AI perception.
if (object->IsA(AStyx3AIController::StaticClass()) && funcName == "OnPerceptionIntensityUpdated") {
auto* AIController = static_cast<AStyx3AIController*>(object);
if (g_Player && AIController->PerceptionGaugeComponent) {
if (g_Stealth_fix_enabled)
if (g_Stealth_fix_enabled) {
AIController->PerceptionGaugeComponent->ResetGauges(g_Player);
else
if (g_Player) g_Player->bIsPerceptible = false;
}
else {
AIController->PerceptionGaugeComponent->SetActiveBufferDetection(g_Player, true);
if (g_Player) g_Player->bIsPerceptible = true;
}
}
}
if (object->IsA(UUserWidget::StaticClass()) && (funcName == "Construct" || funcName == "Destruct" || funcName == "Tick")) {
std::string objectName = object->GetName();
auto UpdateUI = [&](const std::vector<UWidget**>& targets, const std::vector<UWidget*>& values) {
// UI scaling
auto HandleWidget = [&](auto* typedWidget, auto*& gWidgetPtr) { // Lambda to initialize pointers on Construct and nullify them on Destruct
if (funcName == "Construct") {
for (size_t i = 0; i < targets.size(); ++i)
*targets[i] = values[i];
gWidgetPtr = typedWidget;
HUDUpdate(false);
}
else if (funcName == "Destruct")
for (auto* t : targets) *t = nullptr;
else if (funcName == "Destruct") gWidgetPtr = nullptr;
};
// UI scaling
if (object->IsA(UUI_Settings_C::StaticClass())) {
auto* settings = static_cast<UUI_Settings_C*>(object);
auto* widget = static_cast<UUserWidget*>(object);
UpdateUI({ &g_UISettingsWidget, &g_UISettingsDescWidget }, { widget->WidgetTree->RootWidget, settings->Description_Holder });
}
else if (object->IsA(UUI_Difficulty_C::StaticClass())) {
auto* difficulty = static_cast<UUI_Difficulty_C*>(object);
auto* widget = static_cast<UUserWidget*>(object);
UpdateUI({ &g_DifficultyWidget, &g_difficultyMenusWidget }, { widget->WidgetTree->RootWidget, difficulty->VerticalBox_Menu });
}
else if (object->IsA(UUI_InGameMenu_C::StaticClass())) {
auto* inGameMenu = static_cast<UUI_InGameMenu_C*>(object);
UpdateUI({ &g_InGameMenuWidget }, { inGameMenu->WidgetTree->RootWidget });
}
else if (object->IsA(UUI_PauseMenu_C::StaticClass())) {
auto* pauseMenu = static_cast<UUI_PauseMenu_C*>(object);
UpdateUI({ &g_PauseWidget }, { pauseMenu->WidgetTree->RootWidget });
}
else if (object->IsA(UUI_Profile_C::StaticClass())) {
auto* profile = static_cast<UUI_Profile_C*>(object);
UpdateUI({ &g_ProfileWidget }, { profile->WidgetTree->RootWidget });
}
else if (object->IsA(UUI_MainMenu_C::StaticClass())) {
auto* mainmenu = static_cast<UUI_MainMenu_C*>(object);
UpdateUI({ &g_UIMainMenuWidget }, { mainmenu->WidgetTree->RootWidget });
}
// HUD scaling
if (object->IsA(UUI_Settings_C::StaticClass()))
HandleWidget(static_cast<UUI_Settings_C*>(object), g_UISettingsWidget);
else if (object->IsA(UUI_Difficulty_C::StaticClass()))
HandleWidget(static_cast<UUI_Difficulty_C*>(object), g_DifficultyWidget);
else if (object->IsA(UUI_InGameMenu_C::StaticClass()))
HandleWidget(static_cast<UUI_InGameMenu_C*>(object), g_InGameMenuWidget);
else if (object->IsA(UUI_PauseMenu_C::StaticClass()))
HandleWidget(static_cast<UUI_PauseMenu_C*>(object), g_PauseWidget);
else if (object->IsA(UUI_Profile_C::StaticClass()))
HandleWidget(static_cast<UUI_Profile_C*>(object), g_ProfileWidget);
else if (object->IsA(UUI_MainMenu_C::StaticClass()))
HandleWidget(static_cast<UUI_MainMenu_C*>(object), g_UIMainMenuWidget);
else if (object->IsA(UUI_Saves_C::StaticClass()))
HandleWidget(static_cast<UUI_Saves_C*>(object), g_SavesWidget);
else if (objectName.rfind("UI_Map_C", 0) == 0)
HandleWidget(static_cast<UUserWidget*>(object), g_MapWidget);
else if (objectName.rfind("UI_GameOver_C", 0) == 0)
HandleWidget(static_cast<UUserWidget*>(object), g_GameOverWidget);
else if (objectName.rfind("UI_Loading_C", 0) == 0)
HandleWidget(static_cast<UUserWidget*>(object), g_LoadingWidget);
else {
std::function<void(SDK::UWidget*)> FindWidgets;
FindWidgets = [&](SDK::UWidget* Widget) { // Find all HUD important widgets in container
@@ -341,14 +334,11 @@ static void ProcessEvent() {
};
if (objectName.rfind("Crafting", 0) == 0) {
auto* crafting = static_cast<UUserWidget*>(object);
if (funcName == "Construct") {
g_CraftingWidget = static_cast<UUserWidget*>(object);
HUDUpdate(false);
}
else if (funcName == "Destruct") {
g_CraftingWidget = nullptr;
}
else if (funcName == "Destruct") g_CraftingWidget = nullptr;
}
else if (objectName.rfind("HUD_Widget_C", 0) == 0) {
auto* HUDWidget = static_cast<UUserWidget*>(object);
@@ -373,36 +363,29 @@ static void ProcessEvent() {
}
}
// -- HUD positionning --
static void HUDFixEnabled(UWidget* widget, float left, float right, bool writeLog, int depth) {
if (writeLog) logger->info("HUD fix {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled");
if (!widget) return;
float targetOffsetLeft = g_fix_enabled && g_HUD_fix_enabled ? left : 100.f;
float targetOffsetRight = g_fix_enabled && g_HUD_fix_enabled ? right : 100.f;
if (widget->IsA(UCanvasPanel::StaticClass()) || (widget->Slot && widget->Slot->IsA(UCanvasPanelSlot::StaticClass()))) // Apply offsets To CanvasPanel
ApplyOffsetsSmart(widget, targetOffsetLeft, targetOffsetRight, depth);
}
static void HUDUpdate(bool writeLog) {
if (writeLog) logger->info("HUD & UI scaling {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled");
if (g_fix_enabled && g_HUD_fix_enabled) {
HUDFixEnabled(g_UIMainMenuWidget, g_UIOffsets, g_UIOffsets , false, 1);
HUDFixEnabled(g_UISettingsWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_UISettingsDescWidget, g_UIOffsets + 1500.f, 675.f, false, 1);
HUDFixEnabled(g_ProfileWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_DifficultyWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_difficultyMenusWidget, g_UIOffsets + 576.f + 100.f, 576, false, 1);
HUDFixEnabled(g_InGameMenuWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_PauseWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_StatusWidget, g_HUDOffsets, 0.f, false, 1);
HUDFixEnabled(g_GaugesWidget, 0 , g_HUDOffsets + 690.f, false, 1); // Use original left and right offset + for Anchors of type 1, 1, 1, 1
HUDFixEnabled(g_AbilityWheelWidget,0 , g_HUDOffsets + 78.f, false, 1); // Use original left and right offset + for Anchors of type 1, 1, 1, 1
HUDFixEnabled(g_ChangeWheelWidget, 0, g_HUDOffsets + 24.f, false, 1); // Use original left and right offset for Anchors of type 1, 1, 1, 1
ApplyPositionOffset(g_CraftingWidget, g_UIOffsets, FVector2D(0.5f, 0.5f)); // for widgets that only display at left (nothing at right)
ApplyTransformOffset(g_LootWidget, g_HUDOffsets);
ApplyTransformOffset(g_QuestWidget, g_HUDOffsets);
}
if (writeLog) logger->info("HUD & UI scaling fix {}", g_fix_enabled && g_HUD_fix_enabled ? "enabled" : "disabled");
float UIoffset = (g_fix_enabled && g_HUD_fix_enabled) ? g_UIOffsets : 0.f;
float HUDoffset = (g_fix_enabled && g_HUD_fix_enabled) ? g_HUDOffsets : 0.f;
float compensation = (g_fix_enabled && g_HUD_fix_enabled) ? 90.f : 0.f;
float targetAspect = 16.f / 9.f;
CenterWidget(g_UIMainMenuWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_UISettingsWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_ProfileWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_DifficultyWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_InGameMenuWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_PauseWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_SavesWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_MapWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
CenterWidget(g_GameOverWidget, UIoffset, screenWidth, screenHeight, g_AspectRatio, targetAspect, compensation);
ApplyOffsetsSmart(g_StatusWidget, HUDoffset, 0.f, 1);
ApplyOffsetsSmart(g_GaugesWidget, 0, HUDoffset + 690.f, 1); // Use original left and right offset + for Anchors of type 1, 1, 1, 1
ApplyOffsetsSmart(g_AbilityWheelWidget, 0, HUDoffset + 78.f, 1); // Use original left and right offset + for Anchors of type 1, 1, 1, 1
ApplyOffsetsSmart(g_ChangeWheelWidget, 0, HUDoffset + 24.f, 1); // Use original left and right offset for Anchors of type 1, 1, 1, 1
ApplyPositionOffset(g_CraftingWidget, UIoffset, FVector2D(0.5f, 0.5f)); // for widgets that only display at left (nothing at right)
ApplyTransformOffset(g_LootWidget, HUDoffset);
ApplyTransformOffset(g_QuestWidget, HUDoffset);
}
static void FOVFixEnabled() {
@@ -496,11 +479,8 @@ static void EnableCheats(Cheat cheat) {
if (percentageHealth > 0.0001f)
g_Player->CurrentHealth = g_Player->CurrentHealth / percentageHealth;
}
g_PlayerAmber = g_Player->CurrentAmber;
if (g_Amber_fix_enabled) g_Player->CurrentAmber = g_Player->MaxAmber;
g_Player->bIsPerceptible = false;
}
if (object->IsA(AStyx3AICharacter::StaticClass())) {
AStyx3AICharacter* enemy = static_cast<AStyx3AICharacter*>(object);