diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp index 89d319d4..2820e71b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp @@ -8,39 +8,10 @@ #include "Components/PanelSlot.h" #include "MaterialGraph/MaterialGraphNode.h" #include "Materials/MaterialExpression.h" -#include "DetailTreeNode.h" -#include "PropertyNode.h" -#include "ObjectPropertyNode.h" -#include "PropertyNode.h" -#include "ObjectPropertyNode.h" -#include "ItemPropertyNode.h" -#include "CategoryPropertyNode.h" ///////////////////////////////////////////////////////////////////////////// // -// IsSubObject -// -///////////////////////////////////////////////////////////////////////////// - -bool WingPropHandle::IsSubObject(const TSharedRef& Node) -{ - FDetailTreeNode& DetailNode = static_cast(*Node); - TSharedPtr PropNode = DetailNode.GetPropertyNode(); - if (!PropNode.IsValid()) return false; - - FPropertyNode* Current = PropNode.Get(); - while (true) - { - if (Current == nullptr) return false; - FPropertyNode *Parent = Current->GetParentNode(); - if (Current->AsObjectNode()) return (Parent != nullptr); - Current = Parent; - } -} - -///////////////////////////////////////////////////////////////////////////// -// -// Get Generator +// Get Root // ///////////////////////////////////////////////////////////////////////////// @@ -52,29 +23,66 @@ TSharedRef WingPropHandle::CreateGenerator() return Module.CreatePropertyRowGenerator(Args); } -TSharedRef WingPropHandle::GetGeneratorForObject(UObject* Obj) +WingPropHandle::Root& WingPropHandle::GetRootForObject(UObject* Obj) { - for (auto& Pair : Generators) + for (Root& R : Roots) { - if (Pair.Key == Obj) return Pair.Value.ToSharedRef(); + if (R.Base == (uint8*)Obj) return R; } TSharedRef Gen = CreateGenerator(); Gen->SetObjects({Obj}); - Generators.Add({Obj, Gen}); - return Gen; + Root& R = Roots.AddDefaulted_GetRef(); + R.Struct = Obj->GetClass(); + R.Base = (uint8*)Obj; + R.End = R.Base + R.Struct->GetStructureSize(); + R.Generator = Gen; + return R; } -TSharedRef WingPropHandle::GetGeneratorForStruct(const UStruct* ScriptStruct, uint8* Data) +WingPropHandle::Root& WingPropHandle::GetRootForStruct(const UStruct* ScriptStruct, uint8* Data) { - for (auto& Pair : Generators) + for (Root& R : Roots) { - if (Pair.Key == Data) return Pair.Value.ToSharedRef(); + if (R.Base == Data) return R; } TSharedRef Gen = CreateGenerator(); TSharedPtr Wrapper = MakeShared(ScriptStruct, Data); Gen->SetStructure(Wrapper); - Generators.Add({Data, Gen}); - return Gen; + Root& R = Roots.AddDefaulted_GetRef(); + R.Struct = ScriptStruct; + R.Base = Data; + R.End = Data + ScriptStruct->GetStructureSize(); + R.Generator = Gen; + return R; +} + +///////////////////////////////////////////////////////////////////////////// +// +// IsInsideRootObject +// +///////////////////////////////////////////////////////////////////////////// + +bool WingPropHandle::IsInsideRootObject(const Root& Root, IPropertyHandle& Handle) +{ + // Walk up to the topmost property handle that still has a property. + // Keep the shared pointers alive so the raw pointer stays valid. + TSharedPtr Held; + IPropertyHandle* Top = &Handle; + while (true) + { + TSharedPtr Parent = Top->GetParentHandle(); + if (!Parent.IsValid() || !Parent->GetProperty()) break; + Held = Parent; + Top = Held.Get(); + } + + // Get the address of the topmost property's data. + void* Addr = nullptr; + if (Top->GetValueData(Addr) != FPropertyAccess::Success || !Addr) + return false; + + uint8* DataPtr = (uint8*)Addr; + return DataPtr >= Root.Base && DataPtr < Root.End; } ///////////////////////////////////////////////////////////////////////////// @@ -85,7 +93,6 @@ TSharedRef WingPropHandle::GetGeneratorForStruct(const US void WingPropHandle::AllTreeNodesRecursive(const TSharedRef& Node, FlatTree& Out) { - if (IsSubObject(Node)) return; if (Node->GetNodeType() == EDetailNodeType::Category) { TArray> Children; @@ -100,12 +107,12 @@ void WingPropHandle::AllTreeNodesRecursive(const TSharedRef& No Out.Add(&*Node); } -WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(TSharedRef Generator) +WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(Root& Root) { FlatTree Result; - for (const TSharedRef& Root : Generator->GetRootTreeNodes()) + for (const TSharedRef& TreeRoot : Root.Generator->GetRootTreeNodes()) { - AllTreeNodesRecursive(Root, Result); + AllTreeNodesRecursive(TreeRoot, Result); } return Result; } @@ -116,18 +123,19 @@ WingPropHandle::FlatTree WingPropHandle::AllTreeNodes(TSharedRef Generator, EPropertyFlags Filter) +WingPropHandle::Handles WingPropHandle::AllProperties(Root& Root, EPropertyFlags Filter) { Handles Result; - for (IDetailTreeNode* Node : AllTreeNodes(Generator)) + for (IDetailTreeNode* Node : AllTreeNodes(Root)) { TSharedPtr Handle = Node->CreatePropertyHandle(); if (Handle.IsValid() && Handle->GetProperty()) { - if (Filter == CPF_None || Handle->GetProperty()->HasAllPropertyFlags(Filter)) - { - Result.Add(Handle); - } + if (Filter != CPF_None && !Handle->GetProperty()->HasAllPropertyFlags(Filter)) + continue; + if (!IsInsideRootObject(Root, *Handle)) + continue; + Result.Add(Handle); } } return Result; @@ -136,13 +144,13 @@ WingPropHandle::Handles WingPropHandle::AllProperties(TSharedRef WingPropHandle::NamedProperty(TSharedRef Generator, FName Name) +TSharedPtr WingPropHandle::NamedProperty(Root& Root, FName Name) { - for (IDetailTreeNode* Node : AllTreeNodes(Generator)) + for (IDetailTreeNode* Node : AllTreeNodes(Root)) { - if (Node->GetNodeName() == Name) - return Node->CreatePropertyHandle(); + if (Node->GetNodeName() != Name) continue; + TSharedPtr Handle = Node->CreatePropertyHandle(); + if (Handle.IsValid() && IsInsideRootObject(Root, *Handle)) + return Handle; } return nullptr; } @@ -164,13 +174,13 @@ TSharedPtr WingPropHandle::NamedProperty(TSharedRef WingPropHandle::NamedProperty(UObject* Obj, FName Name) { if (!Obj) return nullptr; - return NamedProperty(GetGeneratorForObject(Obj), Name); + return NamedProperty(GetRootForObject(Obj), Name); } TSharedPtr WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name) { if (!ScriptStruct || !Data) return nullptr; - return NamedProperty(GetGeneratorForStruct(ScriptStruct, Data), Name); + return NamedProperty(GetRootForStruct(ScriptStruct, Data), Name); } ///////////////////////////////////////////////////////////////////////////// @@ -231,4 +241,3 @@ WingPropHandle::Handles WingPropHandle::GetDetails(UObject* Obj, bool Mutable, E return Result; } - diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h index 56a0a308..4c8a6200 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h @@ -44,18 +44,23 @@ public: TSharedPtr NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name); private: - TArray>> Generators; + struct Root + { + const UStruct* Struct = nullptr; + uint8* Base = nullptr; + uint8* End = nullptr; + TSharedPtr Generator; + }; - // Check whether a detail tree node's property comes from a sub-object. - static bool IsSubObject(const TSharedRef& Node); + static bool IsInsideRootObject(const Root& Root, IPropertyHandle& Handle); + TArray Roots; static TSharedRef CreateGenerator(); - TSharedRef GetGeneratorForObject(UObject* Obj); - TSharedRef GetGeneratorForStruct(const UStruct* ScriptStruct, uint8* Data); - + Root& GetRootForObject(UObject* Obj); + Root& GetRootForStruct(const UStruct* ScriptStruct, uint8* Data); static void AllTreeNodesRecursive(const TSharedRef& Node, FlatTree& Out); - static FlatTree AllTreeNodes(TSharedRef Generator); + static FlatTree AllTreeNodes(Root& Root); - Handles AllProperties(TSharedRef Generator, EPropertyFlags Filter); - static TSharedPtr NamedProperty(TSharedRef Generator, FName Name); + Handles AllProperties(Root& Root, EPropertyFlags Filter); + static TSharedPtr NamedProperty(Root& Root, FName Name); }; diff --git a/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs b/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs index f29532f0..f8617f89 100644 --- a/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs +++ b/Plugins/UEWingman/Source/UEWingman/UEWingman.Build.cs @@ -6,8 +6,6 @@ public class UEWingman : ModuleRules { PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; - // Needed for debug dump of FPropertyNode tree (private headers) - PrivateIncludePaths.Add(System.IO.Path.Combine(EngineDirectory, "Source/Editor/PropertyEditor/Private")); PublicDependencyModuleNames.AddRange(new string[]