2323#include < GUI/LiveView/Filter/InstancesOnly.hpp>
2424#include < GUI/LiveView/Filter/NonInstancesOnly.hpp>
2525#include < GUI/LiveView/Filter/SearchFilter.hpp>
26+ #include < GUI/LiveView/Filter/MaxValueSize.hpp>
2627#include < GUI/UFunctionCallerWidget.hpp>
2728#include < Helpers/String.hpp>
2829#include < JSON/JSON.hpp>
3536#include < Unreal/Property/FObjectProperty.hpp>
3637#include < Unreal/Property/FEnumProperty.hpp>
3738#include < Unreal/Property/NumericPropertyTypes.hpp>
39+ #include < Unreal/Property/FMapProperty.hpp>
3840#include < Unreal/UClass.hpp>
3941#include < Unreal/UEnum.hpp>
4042#include < Unreal/UFunction.hpp>
@@ -101,6 +103,7 @@ namespace RC::GUI
101103 void * container = nullptr ;
102104 UObject* obj = nullptr ;
103105 LiveView::ContainerType container_type = LiveView::ContainerType::Object;
106+ bool editable = true ;
104107 };
105108 static DeferredPropertyEditPopup s_deferred_property_edit_popup{};
106109
@@ -336,6 +339,14 @@ namespace RC::GUI
336339 filter_data.new_bool (STR (" Enabled" ), is_enabled);
337340 }
338341
342+ static auto add_int32_filter_to_json (JSON::Array& json_filters, const StringType& filter_name, int32_t value) -> void
343+ {
344+ auto & json_object = json_filters.new_object ();
345+ json_object.new_string (STR (" FilterName" ), filter_name);
346+ auto & filter_data = json_object.new_object (STR (" FilterData" ));
347+ filter_data.new_number (STR (" Value" ), value);
348+ }
349+
339350 template <typename ContainerType>
340351 static auto add_array_filter_to_json (JSON::Array& json_filters, const StringType& filter_name, const ContainerType& container, const StringType& array_name)
341352 -> void
@@ -391,6 +402,9 @@ namespace RC::GUI
391402 add_array_filter_to_json (json_filters, Filter::HasPropertyType::s_debug_name, Filter::HasPropertyType::list_property_types, STR (" PropertyTypes" ));
392403 add_array_filter_to_json (json_filters, Filter::FunctionParamFlags::s_debug_name, Filter::FunctionParamFlags::s_checkboxes, STR (" FunctionParamFlags" ));
393404 }
405+ {
406+ add_int32_filter_to_json (json_filters, Filter::MaxValueSize::s_debug_name, Filter::MaxValueSize::s_value);
407+ }
394408
395409 auto json_file = File::open (StringType{UE4SSProgram::get_program ().get_working_directory ()} + fmt::format (STR (" \\ liveview\\ filters.meta.json" )),
396410 File::OpenFor::Writing,
@@ -530,6 +544,16 @@ namespace RC::GUI
530544 return LoopAction::Continue;
531545 });
532546 }
547+ else if (filter_name == Filter::MaxValueSize::s_debug_name)
548+ {
549+ auto number = filter_data.get <JSON::Number>(STR (" Value" )).get <int64_t >();
550+ if (number > std::numeric_limits<int32_t >::max ())
551+ {
552+ number = std::numeric_limits<int32_t >::max ();
553+ }
554+ Filter::MaxValueSize::s_value = static_cast <int32_t >(number);
555+ Filter::MaxValueSize::s_value_buffer = fmt::format (" {}" , Filter::MaxValueSize::s_value);
556+ }
533557
534558 return LoopAction::Continue;
535559 });
@@ -2198,7 +2222,38 @@ namespace RC::GUI
21982222 FString property_text{};
21992223 auto property_name = to_string (property->GetName ());
22002224 auto container_ptr = property->ContainerPtrToValuePtr <void *>(container);
2201- property->ExportTextItem (property_text, container_ptr, container_ptr, static_cast <UObject*>(container), NULL );
2225+ auto as_struct_property = CastField<FStructProperty>(property);
2226+ static constexpr auto s_error_too_large = STR (" Too large to display on one line! Click to view individual members." );
2227+ bool editable = true ;
2228+ if (auto as_map_property = CastField<FMapProperty>(property))
2229+ {
2230+ auto map = std::bit_cast<FScriptMap*>(container_ptr);
2231+ if (auto value_as_struct_property = CastField<FStructProperty>(as_map_property->GetValueProp ());
2232+ value_as_struct_property && value_as_struct_property->GetStruct ()->GetStructureSize () * map->Num () > Filter::MaxValueSize::s_value)
2233+ {
2234+ editable = false ;
2235+ property_text = FString{s_error_too_large};
2236+ }
2237+ else
2238+ {
2239+ property->ExportTextItem (property_text, container_ptr, container_ptr, static_cast <UObject*>(container), NULL );
2240+ }
2241+ }
2242+ else if (auto as_array_property = CastField<FArrayProperty>(property);
2243+ as_array_property && as_array_property->GetSize () * std::bit_cast<FScriptArray*>(container_ptr)->Num () > Filter::MaxValueSize::s_value)
2244+ {
2245+ editable = false ;
2246+ property_text = FString{s_error_too_large};
2247+ }
2248+ else if (as_struct_property && as_struct_property->GetStruct ()->GetStructureSize () > Filter::MaxValueSize::s_value)
2249+ {
2250+ editable = false ;
2251+ property_text = FString{s_error_too_large};
2252+ }
2253+ else
2254+ {
2255+ property->ExportTextItem (property_text, container_ptr, container_ptr, static_cast <UObject*>(container), NULL );
2256+ }
22022257
22032258 bool open_edit_value_popup{};
22042259
@@ -2215,7 +2270,9 @@ namespace RC::GUI
22152270 }
22162271 if (ImGui::MenuItem (" Copy value" ))
22172272 {
2218- ImGui::SetClipboardText (to_string (*property_text).c_str ());
2273+ FString snapshotted_value{};
2274+ property->ExportTextItem (snapshotted_value, container_ptr, container_ptr, static_cast <UObject*>(container), NULL );
2275+ ImGui::SetClipboardText (to_string (*snapshotted_value).c_str ());
22192276 }
22202277 if (container_type == ContainerType::Object || container_type == ContainerType::Struct)
22212278 {
@@ -2286,20 +2343,16 @@ namespace RC::GUI
22862343 container_type == ContainerType::Array ? fmt::format (" " ).c_str () : fmt::format (" (0x{:X})" , property_offset).c_str (),
22872344 property_name.c_str ());
22882345 }
2289- if (auto struct_property = CastField<FStructProperty>(property); struct_property && struct_property ->GetStruct ()->GetFirstProperty ())
2346+ if (as_struct_property && as_struct_property ->GetStruct ()->GetFirstProperty ())
22902347 {
22912348 ImGui::SameLine ();
22922349 auto tree_node_id = fmt::format (" {}{}" , static_cast <void *>(container_ptr), property_name);
22932350 if (ImGui_TreeNodeEx (fmt::format (" {}" , to_string (*property_text)).c_str (), tree_node_id.c_str (), ImGuiTreeNodeFlags_NoAutoOpenOnLog))
22942351 {
22952352 render_property_value_context_menu (tree_node_id);
22962353
2297- for (FProperty* inner_property : struct_property ->GetStruct ()->ForEachProperty ())
2354+ for (FProperty* inner_property : as_struct_property ->GetStruct ()->ForEachProperty ())
22982355 {
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-
23032356 ImGui::Indent ();
23042357 FProperty* last_struct_prop{};
23052358 next_item_to_render = render_property_value (inner_property,
@@ -2412,10 +2465,25 @@ namespace RC::GUI
24122465
24132466 if (open_edit_value_popup)
24142467 {
2468+ // Re-snapshot the value, because it may not be set due to it being too large of a type to export quickly.
2469+ // Why is this an empty string ? Wtf ?
2470+ // It seems it's not empty, but imgui isn't rendering the text properly for some reason, it's rendered as spaces.
2471+ // When you copy the text, it does copy the actual text, not spaces.
2472+ // FString snapshotted_property_text{};
2473+ // property->ExportTextItem(snapshotted_property_text, container_ptr, container_ptr, static_cast<UObject*>(container), NULL);
24152474 // Defer the popup opening - store all necessary context
24162475 s_deferred_property_edit_popup.pending = true ;
24172476 s_deferred_property_edit_popup.modal_name = edit_property_value_modal_name;
2418- s_deferred_property_edit_popup.initial_value = to_string (*property_text);
2477+ if (!editable)
2478+ {
2479+ s_deferred_property_edit_popup.editable = false ;
2480+ s_deferred_property_edit_popup.initial_value = " Too large to edit!" ;
2481+ }
2482+ else
2483+ {
2484+ s_deferred_property_edit_popup.editable = true ;
2485+ s_deferred_property_edit_popup.initial_value = to_string (*property_text);
2486+ }
24192487 s_deferred_property_edit_popup.property = property;
24202488 s_deferred_property_edit_popup.container = container;
24212489 s_deferred_property_edit_popup.obj = obj;
@@ -3397,6 +3465,10 @@ namespace RC::GUI
33973465 ImGui::Text (" The game could crash if the new value is invalid." );
33983466 ImGui::Text (" The game can override the new value immediately." );
33993467 ImGui::PushItemWidth (-1 .0f );
3468+ if (!s_deferred_property_edit_popup.editable )
3469+ {
3470+ ImGui::BeginDisabled ();
3471+ }
34003472 ImGui::InputText (" ##CurrentPropertyValue" , &m_current_property_value_buffer);
34013473 if (ImGui::Button (" Apply" ))
34023474 {
@@ -3417,6 +3489,10 @@ namespace RC::GUI
34173489 s_deferred_property_edit_popup.property = nullptr ; // Clear the deferred state
34183490 }
34193491 }
3492+ if (!s_deferred_property_edit_popup.editable )
3493+ {
3494+ ImGui::EndDisabled ();
3495+ }
34203496
34213497 if (ImGui::BeginPopupModal (" UnableToSetNewPropertyValueError" ,
34223498 &m_modal_edit_property_value_error_unable_to_edit,
@@ -3435,6 +3511,7 @@ namespace RC::GUI
34353511 if (!m_modal_edit_property_value_is_open)
34363512 {
34373513 s_deferred_property_edit_popup.property = nullptr ;
3514+ s_deferred_property_edit_popup.editable = true ;
34383515 }
34393516
34403517 // Handle deferred enum edit popup
@@ -3824,6 +3901,37 @@ namespace RC::GUI
38243901 }
38253902 }
38263903 }
3904+ // Row 8
3905+ ImGui::TableNextRow ();
3906+ ImGui::TableNextColumn ();
3907+ ImGui::Text (" Maximum Value Size" );
3908+ ImGui::TableNextColumn ();
3909+ ImGui::SetNextItemWidth (ImGui::GetContentRegionAvail ().x );
3910+ if (ImGui::InputText (" ##MaxValueSize" , &Filter::MaxValueSize::s_value_buffer))
3911+ {
3912+ int32_t new_value{-1 };
3913+ try
3914+ {
3915+ new_value = std::stoi (Filter::MaxValueSize::s_value_buffer);
3916+ }
3917+ catch (...)
3918+ {
3919+ if (Filter::MaxValueSize::s_value > 0 )
3920+ {
3921+ new_value = std::numeric_limits<int32_t >::max ();
3922+ }
3923+ else
3924+ {
3925+ new_value = 0 ;
3926+ }
3927+ }
3928+ if (new_value < 0 )
3929+ {
3930+ new_value = Filter::MaxValueSize::s_value;
3931+ }
3932+ Filter::MaxValueSize::s_value = new_value;
3933+ Filter::MaxValueSize::s_value_buffer = fmt::format (" {}" , Filter::MaxValueSize::s_value);
3934+ }
38273935
38283936 ImGui::TableNextRow ();
38293937 ImGui::TableNextColumn ();
0 commit comments