Add game resolution retrieving. Improved stealth cheat. Improved UI & HUD scaling.

This commit is contained in:
2026-03-07 17:01:27 +01:00
parent 87dd5e2f37
commit bf30c80d91

View File

@@ -12,6 +12,7 @@
#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/Styx3_classes.hpp"
@@ -20,6 +21,7 @@ using namespace SDK;
// Constants
const std::string PLUGIN_NAME = "Styx";
const std::string PLUGIN_LOG = PLUGIN_NAME + ".log";
constexpr ULONGLONG DEFAULT_DELAY_BETWEEN_TICK = 500; // Used for enemies time dilation
// Logger
std::shared_ptr<spdlog::logger> logger;
@@ -84,7 +86,6 @@ static void FOVFixEnabled();
static void UltraWideFixEnabled();
static void CameraDistanceFixEnabled();
static void HUDUpdate(bool writeLog);
static void HUDFixEnabled(UWidget* widget, float left, float right, bool writeLog, int depth);
static void DOFFixEnabled();
static void CAFixEnabled();
static void VignettingFixEnabled();
@@ -95,16 +96,19 @@ static void ProcessEvent();
// UEngine variable
static UWidget* g_UIMainMenuWidget = nullptr;
static UWidget* g_UISettingsWidget = nullptr;
static UWidget* g_UIDescriptionWidget = 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 UWidget* g_StatusWidget = nullptr;
static UWidget* g_GaugesWidget = nullptr;
static UWidget* g_ChangeWheelWidget = nullptr;
static UWidget* g_AbilityWheelWidget = nullptr;
static UWidget* g_CraftingWidget = nullptr;
static UUserWidget* g_CraftingWidget = nullptr;
static UWidget* g_QuestWidget = nullptr;
static UWidget* g_LootWidget = nullptr;
static AStyx3PlayerCharacter* g_Player = nullptr;
extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
@@ -180,7 +184,6 @@ extern "C" __declspec(dllexport) void SetFixEnabled(bool enabled, bool init) {
}
ProcessEvent();
}
// Setters for Reshade addon call
extern "C" __declspec(dllexport) void SetFixesEnabled(GameFixes fix, bool enabled) { // Set each fix individually
if (fix == GameFixes::DevConsole) { g_Console = enabled; EnableConsole(); }
@@ -215,7 +218,6 @@ extern "C" __declspec(dllexport) void SetValues(GameSetting setting, float value
// Getters for Reshade addon call
extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) {
if (!infos) return;
infos->FOVIn = g_FOV_In;
infos->FOVOut = g_FOV_Out;
infos->cameraIn = g_CameraIn;
@@ -223,14 +225,24 @@ extern "C" __declspec(dllexport) void GetGameInfos(GameInfos* infos) {
infos->CompensatedFOV = g_CompensatedFOV;
infos->Health = g_PlayerHealth;
infos->Mana = g_PlayerAmber;
infos->screenWidth = screenWidth;
infos->screenHeight = screenHeight;
infos->aspectRatio = (float)screenWidth / screenHeight;
infos->consoleEnabled = g_Console_Enabled;
}
// -- Code injection functions --
static ULONGLONG lastScanTick = 0; // Last time tick was called
static void ProcessEvent() {
if (!PEHook && ProcessEventaddress) {
PEHook = safetyhook::create_mid(ProcessEventaddress + 0xc,
[](SafetyHookContext& ctx) {
ULONGLONG now = GetTickCount64();
if (now - lastScanTick >= DEFAULT_DELAY_BETWEEN_TICK) { // si le délai est passé
lastScanTick = now;
GetResolution(screenWidth, screenHeight, g_AspectRatio);
}
UObject* object = (UObject*)ctx.rcx;
UFunction* func = (UFunction*)ctx.rdx;
if (!object || !func) return;
@@ -238,15 +250,13 @@ static void ProcessEvent() {
std::string funcName = func->GetName();
std::string objectName = object->GetName();
// Full stealth fix: disable AI perception.
if (funcName == "OnPerceptionIntensityUpdated") {
if (object->IsA(AStyx3AIController::StaticClass())) {
auto* AIController = static_cast<AStyx3AIController*>(object);
if (g_Player && AIController->PerceptionGaugeComponent) {
if (g_Stealth_fix_enabled)
AIController->PerceptionGaugeComponent->ResetGauges(g_Player);
else
AIController->PerceptionGaugeComponent->SetActiveBufferDetection(g_Player, true);
}
if (object->IsA(AStyx3AIController::StaticClass()) && funcName == "OnPerceptionIntensityUpdated") {
auto* AIController = static_cast<AStyx3AIController*>(object);
if (g_Player && AIController->PerceptionGaugeComponent) {
if (g_Stealth_fix_enabled)
AIController->PerceptionGaugeComponent->ResetGauges(g_Player);
else
AIController->PerceptionGaugeComponent->SetActiveBufferDetection(g_Player, true);
}
}
if (object->IsA(UUserWidget::StaticClass()) && (funcName == "Construct" || funcName == "Destruct" || funcName == "Tick")) {
@@ -265,7 +275,7 @@ static void ProcessEvent() {
auto* settings = static_cast<UUI_Settings_C*>(object);
auto* widget = static_cast<UUserWidget*>(object);
UpdateUI({ &g_UISettingsWidget, &g_UIDescriptionWidget }, { widget->WidgetTree->RootWidget, settings->Description_Holder });
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);
@@ -273,6 +283,11 @@ static void ProcessEvent() {
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);
@@ -304,9 +319,12 @@ static void ProcessEvent() {
if (!g_StatusWidget && match("StatusWidget")) g_StatusWidget = Widget;
else if (!g_GaugesWidget && match("Gauges")) g_GaugesWidget = Widget;
else if (!g_ChangeWheelWidget && match("ChangeWheel")) g_ChangeWheelWidget = Widget;
else if (!g_AbilityWheelWidget && match("AbilityWheel")) g_AbilityWheelWidget = Widget;
else if (!g_AbilityWheelWidget && match("AbilityWheel")) g_AbilityWheelWidget = Widget; // g_QuestWidget
else if (!g_QuestWidget && match("Notifications_Missions")) g_QuestWidget = Widget;
else if (!g_LootWidget && match("Notifications_Loot")) g_LootWidget = Widget;
// Stop early if everything found-
if (g_StatusWidget && g_GaugesWidget && g_ChangeWheelWidget && g_AbilityWheelWidget /*&& g_CraftingDescWidget*/)
if (g_StatusWidget && g_GaugesWidget && g_ChangeWheelWidget && g_AbilityWheelWidget && g_QuestWidget && g_LootWidget)
return;
// Descend Panel children
if (Widget->IsA(SDK::UPanelWidget::StaticClass())) {
@@ -325,12 +343,11 @@ static void ProcessEvent() {
if (objectName.contains("Crafting")) {
auto* crafting = static_cast<UUserWidget*>(object);
if (funcName == "Construct") {
g_CraftingWidget = crafting->WidgetTree->RootWidget;
g_CraftingWidget = static_cast<UUserWidget*>(object);
HUDUpdate(false);
}
else if (funcName == "Destruct") {
g_CraftingWidget = nullptr;
//g_CraftingDescWidget = nullptr;
}
}
else if (objectName.contains("HUD_Widget_C")) {
@@ -342,6 +359,8 @@ static void ProcessEvent() {
}
}
else if (funcName == "Destruct") {
g_QuestWidget = nullptr;
g_LootWidget = nullptr;
g_StatusWidget = nullptr;
g_GaugesWidget = nullptr;
g_ChangeWheelWidget = nullptr;
@@ -354,22 +373,6 @@ static void ProcessEvent() {
}
}
// -- HUD positionning --
static void HUDUpdate(bool writeLog) {
HUDFixEnabled(g_UIMainMenuWidget, g_UIOffsets, g_UIOffsets , false, 1);
HUDFixEnabled(g_UISettingsWidget, g_UIOffsets, g_UIOffsets, false, 1);
HUDFixEnabled(g_UIDescriptionWidget, 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_PauseWidget, g_UIOffsets, g_UIOffsets, false, 2);
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
HUDFixEnabled(g_CraftingWidget, g_UIOffsets, g_UIOffsets, false, 1); // Use original left and right offset + for Anchors of type 1, 1, 1, 1
}
//static bool g_offsetsInitialized = false;
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;
@@ -381,6 +384,25 @@ static void HUDFixEnabled(UWidget* widget, float left, float right, bool writeLo
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");
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);
}
static void FOVFixEnabled() {
if (g_fix_enabled && (g_fov_fix_enabled || g_ultrawide_fix_enabled) && CameraComponentaddress) {
if (!FOVHook) { // Hook only once
@@ -526,8 +548,6 @@ static void VignettingFixEnabled() {
}
static void FogFixEnabled() {
if (g_Fog_fix_enabled)
DumpUIAnalysis(logger);
if (g_fix_enabled && g_Fog_fix_enabled && Fogaddress)
Memory::PatchBytes(Fogaddress + 0xd, "\xEB", 1); // jmp -> r.Fog 0
if (!(g_fix_enabled && g_Fog_fix_enabled) && Fogaddress)