Add Smart HUD UI scaling based on anchors. Add widget recursive dump. Add debug logs.
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
#include "UETools.hpp"
|
||||
#include "UETools.hpp"
|
||||
#include "Engine_classes.hpp"
|
||||
|
||||
std::shared_ptr<spdlog::logger> g_logger;
|
||||
|
||||
SDK::APawn* GetPawnFromWorld(SDK::UWorld* world) {
|
||||
if (!world) world = SDK::UWorld::GetWorld();
|
||||
if (!world) return nullptr;
|
||||
@@ -17,6 +19,7 @@ SDK::APawn* GetPawnFromWorld(SDK::UWorld* world) {
|
||||
}
|
||||
|
||||
void ReactivateDevConsole(std::shared_ptr<spdlog::logger> logger) {
|
||||
g_logger = logger;
|
||||
std::thread([logger]() {
|
||||
auto start = std::chrono::high_resolution_clock::now(); // Measure the time to renable console
|
||||
SDK::UEngine* Engine = nullptr;
|
||||
@@ -62,14 +65,99 @@ void ReactivateDevConsole(std::shared_ptr<spdlog::logger> logger) {
|
||||
}).detach();
|
||||
}
|
||||
// --- HUD & UI methods ---
|
||||
static void ApplyOffsetsRecursive_Internal(SDK::UWidget* Widget, float Left, float Right, int CurrentDepth, int MaxDepth) {
|
||||
void ApplyOffsetsSmart_Internal( SDK::UWidget* Widget, float Left, float Right, int Depth = 0, int MaxDepth = 1) {
|
||||
if (!Widget) return;
|
||||
|
||||
// Apply if CanvasSlot
|
||||
if (Widget->Slot && Widget->Slot->IsA(SDK::UCanvasPanelSlot::StaticClass())) {
|
||||
if (Depth <= MaxDepth) {
|
||||
auto* Slot = static_cast<SDK::UCanvasPanelSlot*>(Widget->Slot);
|
||||
|
||||
SDK::FMargin Offsets = Slot->GetOffsets();
|
||||
SDK::FAnchors Anchors = Slot->GetAnchors();
|
||||
|
||||
float MinX = Anchors.Minimum.X;
|
||||
float MaxX = Anchors.Maximum.X;
|
||||
#ifdef MY_VERBOSE_LOGS
|
||||
if (g_logger) g_logger->debug("CanvasPanelSlot: {} {} - Slot: {} {} - Offets: {} {} {} {} - Anchors: {} {} {} {}",
|
||||
Widget->GetName(), Widget->Class->GetName(),
|
||||
Slot->GetName(), Slot->Class->GetName(),
|
||||
Offsets.Left, Offsets.Top, Offsets.Right, Offsets.Bottom,
|
||||
Anchors.Minimum.X, Anchors.Minimum.Y, Anchors.Maximum.X, Anchors.Maximum.Y);
|
||||
#endif
|
||||
if (MinX == 0.f && MaxX == 1.f) return; // Ignore stretch
|
||||
if (MinX == 0.5f && MaxX == 0.5f) return; // Ignore centered
|
||||
|
||||
if (MinX == 0.f && MaxX == 0.f) // Modify only pure left
|
||||
Offsets.Left = Left;
|
||||
else if (MinX == 1.f && MaxX == 1.f) // Modify only pure right
|
||||
Offsets.Left = -Right;
|
||||
|
||||
Slot->SetOffsets(Offsets);
|
||||
}
|
||||
}
|
||||
|
||||
// Stop to max depth
|
||||
if (Depth >= MaxDepth) return;
|
||||
|
||||
// Browse the children
|
||||
if (Widget->IsA(SDK::UPanelWidget::StaticClass())) {
|
||||
auto* Panel = static_cast<SDK::UPanelWidget*>(Widget);
|
||||
|
||||
for (int i = 0; i < Panel->GetChildrenCount(); ++i)
|
||||
ApplyOffsetsSmart_Internal(Panel->GetChildAt(i), Left, Right, Depth + 1, MaxDepth);
|
||||
}
|
||||
|
||||
if (Widget->IsA(SDK::UUserWidget::StaticClass())) {
|
||||
auto* UW = static_cast<SDK::UUserWidget*>(Widget);
|
||||
|
||||
if (UW->WidgetTree && UW->WidgetTree->RootWidget)
|
||||
ApplyOffsetsSmart_Internal(UW->WidgetTree->RootWidget, Left, Right, Depth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyOffsetsSmart(SDK::UWidget* Widget, float Left, float Right, int MaxDepth) {
|
||||
#ifdef MY_VERBOSE_LOGS
|
||||
if (g_logger) g_logger->debug("=========================================================");
|
||||
if (g_logger) g_logger->debug("Widget offset applying: {} {}",
|
||||
Widget->GetName(), Widget->Class->GetName());
|
||||
if (g_logger) g_logger->debug("=========================================================");
|
||||
#endif
|
||||
ApplyOffsetsSmart_Internal(Widget, Left, Right, 0, MaxDepth);
|
||||
}
|
||||
|
||||
static void ApplyOffsetsRecursive_Internal(SDK::UWidget* Widget, float Left, float Right,
|
||||
const std::vector<SDK::UObject*>& ExcludeObjects, const std::vector<std::string>& ExcludeClass,
|
||||
int CurrentDepth, int MaxDepth) {
|
||||
if (!Widget || CurrentDepth > MaxDepth) return;
|
||||
|
||||
// Apply offsets according to Slot type
|
||||
for (const auto& ExcludeObject : ExcludeObjects) {
|
||||
if (ExcludeObject == Widget) return;
|
||||
}
|
||||
|
||||
std::string widgetName;
|
||||
std::string className;
|
||||
|
||||
widgetName = Widget->GetName();
|
||||
if (Widget->Class) className = Widget->Class->GetName();
|
||||
for (const auto& pattern : ExcludeClass) {
|
||||
if (widgetName.find(pattern) != std::string::npos || className.find(pattern) != std::string::npos)
|
||||
return;
|
||||
}
|
||||
|
||||
if (Widget->Slot) {
|
||||
if (Widget->Slot->IsA(SDK::UCanvasPanelSlot::StaticClass())) {
|
||||
auto* Slot = static_cast<SDK::UCanvasPanelSlot*>(Widget->Slot);
|
||||
SDK::FMargin Offsets = Slot->GetOffsets();
|
||||
#ifdef MY_VERBOSE_LOGS
|
||||
SDK::FAnchors anchors = Slot->GetAnchors();
|
||||
if (g_logger) g_logger->debug("CanvasPanelSlot: {} {} - Slot: {} {} - Offets: {} {} {} {} - Anchors: {} {} {} {}", \
|
||||
Widget->GetName(), Widget->Class->GetName(), \
|
||||
Slot->GetName(), Slot->Class->GetName(), \
|
||||
Offsets.Left, Offsets.Top, Offsets.Right, Offsets.Bottom, \
|
||||
anchors.Minimum.X, anchors.Minimum.Y, anchors.Maximum.X, anchors.Maximum.Y);
|
||||
#endif
|
||||
Offsets.Left = Left;
|
||||
Offsets.Right = Right;
|
||||
Slot->SetOffsets(Offsets);
|
||||
@@ -77,6 +165,12 @@ static void ApplyOffsetsRecursive_Internal(SDK::UWidget* Widget, float Left, flo
|
||||
else if (Widget->Slot->IsA(SDK::UVerticalBoxSlot::StaticClass())) {
|
||||
auto* Slot = static_cast<SDK::UVerticalBoxSlot*>(Widget->Slot);
|
||||
SDK::FMargin Margin = Slot->Padding;
|
||||
#ifdef MY_VERBOSE_LOGS
|
||||
if (g_logger) g_logger->debug("VerticalBox Slot: {} {} - Slot: {} {} - Margins: {} {} {} {}", \
|
||||
Widget->GetName(), Widget->Class->GetName(), \
|
||||
Slot->GetName(), Slot->Class->GetName(), \
|
||||
Margin.Left, Margin.Top, Margin.Right, Margin.Bottom);
|
||||
#endif
|
||||
Margin.Left = Left;
|
||||
Margin.Right = Right;
|
||||
Slot->SetPadding(Margin);
|
||||
@@ -87,23 +181,24 @@ static void ApplyOffsetsRecursive_Internal(SDK::UWidget* Widget, float Left, flo
|
||||
auto* Panel = static_cast<SDK::UPanelWidget*>(Widget);
|
||||
int childrenCount = Panel->GetChildrenCount();
|
||||
for (int i = 0; i < childrenCount; ++i) {
|
||||
ApplyOffsetsRecursive_Internal(Panel->GetChildAt(i), Left, Right, CurrentDepth + 1, MaxDepth);
|
||||
ApplyOffsetsRecursive_Internal(Panel->GetChildAt(i), Left, Right, ExcludeObjects, ExcludeClass, CurrentDepth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
// Go deeper if the widget is an UserWidget
|
||||
if (Widget->IsA(SDK::UUserWidget::StaticClass())) {
|
||||
auto* ChildWidget = static_cast<SDK::UUserWidget*>(Widget);
|
||||
if (ChildWidget->WidgetTree && ChildWidget->WidgetTree->RootWidget) {
|
||||
ApplyOffsetsRecursive_Internal(ChildWidget->WidgetTree->RootWidget, Left, Right, CurrentDepth + 1, MaxDepth);
|
||||
ApplyOffsetsRecursive_Internal(ChildWidget->WidgetTree->RootWidget, Left, Right, ExcludeObjects, ExcludeClass, CurrentDepth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyOffsetsRecursive(SDK::UWidget* Widget, float Left, float Right, int MaxDepth) {
|
||||
ApplyOffsetsRecursive_Internal(Widget, Left, Right, 0, MaxDepth);
|
||||
void ApplyOffsetsRecursive(SDK::UWidget* Widget, float Left, float Right,
|
||||
const std::vector<SDK::UObject*>& ExcludeObjects, const std::vector<std::string>& ExcludeClass, int MaxDepth) {
|
||||
ApplyOffsetsRecursive_Internal(Widget, Left, Right, ExcludeObjects, ExcludeClass, 0, MaxDepth);
|
||||
}
|
||||
|
||||
static void ApplyOverlayOffsetRecursive_Internal(SDK::UWidget* Widget, float Offset, SDK::EHorizontalAlignment alignment,
|
||||
static void ApplyOverlayOffsetRecursive_Internal(SDK::UWidget* Widget, float left, float right, SDK::EHorizontalAlignment alignment,
|
||||
const std::vector<std::string>& ExcludeNames, int CurrentDepth, int MaxDepth) {
|
||||
if (!Widget || CurrentDepth > MaxDepth) return;
|
||||
|
||||
@@ -121,10 +216,9 @@ static void ApplyOverlayOffsetRecursive_Internal(SDK::UWidget* Widget, float Off
|
||||
SDK::FMargin Padding = Slot->Padding;
|
||||
|
||||
if (Slot->HorizontalAlignment == alignment) {
|
||||
Padding.Left = Offset;
|
||||
Padding.Right = Offset;
|
||||
Padding.Left = left;
|
||||
Padding.Right = right;
|
||||
}
|
||||
|
||||
Slot->SetPadding(Padding);
|
||||
};
|
||||
|
||||
@@ -135,14 +229,14 @@ static void ApplyOverlayOffsetRecursive_Internal(SDK::UWidget* Widget, float Off
|
||||
SDK::UPanelWidget* Panel = (SDK::UPanelWidget*)Widget;
|
||||
int childrenCount = Panel->GetChildrenCount();
|
||||
for (int i = 0; i < childrenCount; ++i) {
|
||||
ApplyOverlayOffsetRecursive_Internal(Panel->GetChildAt(i), Offset, alignment, ExcludeNames, CurrentDepth + 1, MaxDepth);
|
||||
ApplyOverlayOffsetRecursive_Internal(Panel->GetChildAt(i), left, right, alignment, ExcludeNames, CurrentDepth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyOverlayOffsetRecursive(SDK::UWidget* Widget, float Offset, SDK::EHorizontalAlignment alignment,
|
||||
void ApplyOverlayOffsetRecursive(SDK::UWidget* Widget, float left, float right, SDK::EHorizontalAlignment alignment,
|
||||
const std::vector<std::string>& ExcludeNames, int MaxDepth) {
|
||||
ApplyOverlayOffsetRecursive_Internal(Widget, Offset, alignment, ExcludeNames, 0, MaxDepth);
|
||||
ApplyOverlayOffsetRecursive_Internal(Widget, left, right, alignment, ExcludeNames, 0, MaxDepth);
|
||||
}
|
||||
|
||||
void FindAndApplyCanvasRecursive(SDK::UWidget* widget, float offset, int MaxDepth, int currentDepth) {
|
||||
@@ -244,4 +338,39 @@ void DumpUIAnalysis(std::shared_ptr<spdlog::logger> logger) {
|
||||
|
||||
void ClearWidgetTracking() {
|
||||
g_WidgetTracker.clear();
|
||||
}
|
||||
|
||||
void DumpWidgetRecursive(SDK::UWidget* Widget, int Depth, int MaxDepth) {
|
||||
if (!Widget || Depth > MaxDepth) return;
|
||||
|
||||
std::string indent(Depth * 2, ' ');
|
||||
std::string className = Widget->Class ? Widget->Class->GetName() : "UnknownClass";
|
||||
std::string widgetName = Widget->GetName();
|
||||
if (g_logger)
|
||||
g_logger->debug("{}Widget: {} [{}]", indent, widgetName, className);
|
||||
|
||||
// Slot info si disponible
|
||||
if (Widget->Slot) {
|
||||
std::string slotClass = Widget->Slot->Class ? Widget->Slot->Class->GetName() : "UnknownSlot";
|
||||
if (g_logger)
|
||||
g_logger->debug("{} Slot class: {}", indent, slotClass);
|
||||
}
|
||||
|
||||
// Descendre dans les enfants si c'est un panel et qu'on est encore sous MaxDepth
|
||||
if (Depth < MaxDepth) {
|
||||
if (Widget->IsA(SDK::UPanelWidget::StaticClass())) {
|
||||
auto* panel = static_cast<SDK::UPanelWidget*>(Widget);
|
||||
int count = panel->GetChildrenCount();
|
||||
for (int i = 0; i < count; ++i) {
|
||||
DumpWidgetRecursive(panel->GetChildAt(i), Depth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
|
||||
if (Widget->IsA(SDK::UUserWidget::StaticClass())) {
|
||||
auto* userWidget = static_cast<SDK::UUserWidget*>(Widget);
|
||||
if (userWidget->WidgetTree && userWidget->WidgetTree->RootWidget) {
|
||||
DumpWidgetRecursive(userWidget->WidgetTree->RootWidget, Depth + 1, MaxDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user