Skip to content

Commit d0fb2ee

Browse files
committed
fix(LiveView): Don't render values that are too large
This pertains to very large structs, because ExportTextItem is too slow, causing FPS to drop to less than 1. Note that the value '500' is arbitrary, please feel free to change this to a more appropriate number if you can find one.
1 parent 7aee8ae commit d0fb2ee

File tree

1 file changed

+62
-8
lines changed

1 file changed

+62
-8
lines changed

UE4SS/src/GUI/LiveView.cpp

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <Unreal/Property/FObjectProperty.hpp>
3636
#include <Unreal/Property/FEnumProperty.hpp>
3737
#include <Unreal/Property/NumericPropertyTypes.hpp>
38+
#include <Unreal/Property/FMapProperty.hpp>
3839
#include <Unreal/UClass.hpp>
3940
#include <Unreal/UEnum.hpp>
4041
#include <Unreal/UFunction.hpp>
@@ -101,6 +102,7 @@ namespace RC::GUI
101102
void* container = nullptr;
102103
UObject* obj = nullptr;
103104
LiveView::ContainerType container_type = LiveView::ContainerType::Object;
105+
bool editable = true;
104106
};
105107
static DeferredPropertyEditPopup s_deferred_property_edit_popup{};
106108

@@ -2198,7 +2200,39 @@ namespace RC::GUI
21982200
FString property_text{};
21992201
auto property_name = to_string(property->GetName());
22002202
auto container_ptr = property->ContainerPtrToValuePtr<void*>(container);
2201-
property->ExportTextItem(property_text, container_ptr, container_ptr, static_cast<UObject*>(container), NULL);
2203+
static constexpr int32 s_max_structure_size = 500;
2204+
auto as_struct_property = CastField<FStructProperty>(property);
2205+
static constexpr auto s_error_too_large = STR("Too large to display!");
2206+
bool editable = true;
2207+
if (auto as_map_property = CastField<FMapProperty>(property))
2208+
{
2209+
auto map = std::bit_cast<FScriptMap*>(container_ptr);
2210+
if (auto value_as_struct_property = CastField<FStructProperty>(as_map_property->GetValueProp());
2211+
value_as_struct_property && value_as_struct_property->GetStruct()->GetStructureSize() * map->Num() > s_max_structure_size)
2212+
{
2213+
editable = false;
2214+
property_text = FString{s_error_too_large};
2215+
}
2216+
else
2217+
{
2218+
property->ExportTextItem(property_text, container_ptr, container_ptr, static_cast<UObject*>(container), NULL);
2219+
}
2220+
}
2221+
else if (auto as_array_property = CastField<FArrayProperty>(property);
2222+
as_array_property && as_array_property->GetSize() * std::bit_cast<FScriptArray*>(container_ptr)->Num() > s_max_structure_size)
2223+
{
2224+
editable = false;
2225+
property_text = FString{s_error_too_large};
2226+
}
2227+
else if (as_struct_property && as_struct_property->GetStruct()->GetStructureSize() > s_max_structure_size)
2228+
{
2229+
editable = false;
2230+
property_text = FString{s_error_too_large};
2231+
}
2232+
else
2233+
{
2234+
property->ExportTextItem(property_text, container_ptr, container_ptr, static_cast<UObject*>(container), NULL);
2235+
}
22022236

22032237
bool open_edit_value_popup{};
22042238

@@ -2286,20 +2320,16 @@ namespace RC::GUI
22862320
container_type == ContainerType::Array ? fmt::format("").c_str() : fmt::format(" (0x{:X})", property_offset).c_str(),
22872321
property_name.c_str());
22882322
}
2289-
if (auto struct_property = CastField<FStructProperty>(property); struct_property && struct_property->GetStruct()->GetFirstProperty())
2323+
if (as_struct_property && as_struct_property->GetStruct()->GetFirstProperty())
22902324
{
22912325
ImGui::SameLine();
22922326
auto tree_node_id = fmt::format("{}{}", static_cast<void*>(container_ptr), property_name);
22932327
if (ImGui_TreeNodeEx(fmt::format("{}", to_string(*property_text)).c_str(), tree_node_id.c_str(), ImGuiTreeNodeFlags_NoAutoOpenOnLog))
22942328
{
22952329
render_property_value_context_menu(tree_node_id);
22962330

2297-
for (FProperty* inner_property : struct_property->GetStruct()->ForEachProperty())
2331+
for (FProperty* inner_property : as_struct_property->GetStruct()->ForEachProperty())
22982332
{
2299-
FString struct_prop_text_item{};
2300-
auto struct_prop_container_ptr = inner_property->ContainerPtrToValuePtr<void*>(container_ptr);
2301-
inner_property->ExportTextItem(struct_prop_text_item, struct_prop_container_ptr, struct_prop_container_ptr, nullptr, NULL);
2302-
23032333
ImGui::Indent();
23042334
FProperty* last_struct_prop{};
23052335
next_item_to_render = render_property_value(inner_property,
@@ -2412,10 +2442,25 @@ namespace RC::GUI
24122442

24132443
if (open_edit_value_popup)
24142444
{
2445+
// Re-snapshot the value, because it may not be set due to it being too large of a type to export quickly.
2446+
// Why is this an empty string ? Wtf ?
2447+
// It seems it's not empty, but imgui isn't rendering the text properly for some reason, it's rendered as spaces.
2448+
// When you copy the text, it does copy the actual text, not spaces.
2449+
//FString snapshotted_property_text{};
2450+
//property->ExportTextItem(snapshotted_property_text, container_ptr, container_ptr, static_cast<UObject*>(container), NULL);
24152451
// Defer the popup opening - store all necessary context
24162452
s_deferred_property_edit_popup.pending = true;
24172453
s_deferred_property_edit_popup.modal_name = edit_property_value_modal_name;
2418-
s_deferred_property_edit_popup.initial_value = to_string(*property_text);
2454+
if (!editable)
2455+
{
2456+
s_deferred_property_edit_popup.editable = false;
2457+
s_deferred_property_edit_popup.initial_value = "Too large to edit!";
2458+
}
2459+
else
2460+
{
2461+
s_deferred_property_edit_popup.editable = true;
2462+
s_deferred_property_edit_popup.initial_value = to_string(*property_text);
2463+
}
24192464
s_deferred_property_edit_popup.property = property;
24202465
s_deferred_property_edit_popup.container = container;
24212466
s_deferred_property_edit_popup.obj = obj;
@@ -3397,6 +3442,10 @@ namespace RC::GUI
33973442
ImGui::Text("The game could crash if the new value is invalid.");
33983443
ImGui::Text("The game can override the new value immediately.");
33993444
ImGui::PushItemWidth(-1.0f);
3445+
if (!s_deferred_property_edit_popup.editable)
3446+
{
3447+
ImGui::BeginDisabled();
3448+
}
34003449
ImGui::InputText("##CurrentPropertyValue", &m_current_property_value_buffer);
34013450
if (ImGui::Button("Apply"))
34023451
{
@@ -3417,6 +3466,10 @@ namespace RC::GUI
34173466
s_deferred_property_edit_popup.property = nullptr; // Clear the deferred state
34183467
}
34193468
}
3469+
if (!s_deferred_property_edit_popup.editable)
3470+
{
3471+
ImGui::EndDisabled();
3472+
}
34203473

34213474
if (ImGui::BeginPopupModal("UnableToSetNewPropertyValueError",
34223475
&m_modal_edit_property_value_error_unable_to_edit,
@@ -3435,6 +3488,7 @@ namespace RC::GUI
34353488
if (!m_modal_edit_property_value_is_open)
34363489
{
34373490
s_deferred_property_edit_popup.property = nullptr;
3491+
s_deferred_property_edit_popup.editable = true;
34383492
}
34393493

34403494
// Handle deferred enum edit popup

0 commit comments

Comments
 (0)