From c949a4db059208f177bcb0af9b6a3e8aab2fd6cc Mon Sep 17 00:00:00 2001 From: jyelon Date: Sat, 4 Apr 2026 23:57:59 -0400 Subject: [PATCH] Better handling of property mutability, and also, walk into structs. --- .../UEWingman/Handlers/Create_ClassArg.h | 2 +- .../Source/UEWingman/Handlers/Details_Dump.h | 2 +- .../Source/UEWingman/Handlers/Details_Get.h | 2 +- .../Source/UEWingman/Handlers/Details_Set.h | 4 +- .../UEWingman/Handlers/Details_SetMany.h | 2 +- .../Source/UEWingman/Handlers/GraphNode_Add.h | 2 +- .../Handlers/GraphNode_SetDefaults.h | 4 +- .../Handlers/GraphNode_SetPositions.h | 2 +- .../UEWingman/Handlers/GraphPin_Connect.h | 2 +- .../UEWingman/Handlers/GraphPin_Disconnect.h | 2 +- .../UEWingman/Private/WingFactories.cpp | 2 +- .../Source/UEWingman/Private/WingFetcher.cpp | 49 ++++++++++++ .../UEWingman/Private/WingGraphExport.cpp | 2 +- .../Source/UEWingman/Private/WingProperty.cpp | 76 ++++++++++++++----- .../Source/UEWingman/Private/WingServer.cpp | 6 +- .../UEWingman/Private/WingVariables.cpp | 4 +- .../Source/UEWingman/Public/WingFetcher.h | 1 + .../Source/UEWingman/Public/WingHandler.h | 28 +++++++ .../Source/UEWingman/Public/WingProperty.h | 30 +++++--- 19 files changed, 172 insertions(+), 50 deletions(-) diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_ClassArg.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_ClassArg.h index ae9d9079..d6f97bd2 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_ClassArg.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_ClassArg.h @@ -281,7 +281,7 @@ public: } // Set the 'Class' property. - TArray Props = FWingProperty::GetAll(Factory, CPF_Edit); + TArray Props = FWingProperty::GetVisible(Factory); FWingProperty::Remove(Props, TEXT("BlueprintType")); if (Props.Num() != 1) { diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h index 4abcdb80..ef19aba6 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Dump.h @@ -29,7 +29,7 @@ public: UObject* Target = F.Walk(Object).Cast(); if (!Target) return; - TArray Props = FWingProperty::GetDetails(Target, CPF_Edit, false); + TArray Props = FWingProperty::GetDetails(Target, false); // Group by category, preserving within-category order. TSortedMap> Categories; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h index 0a7f828b..e36afb59 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Get.h @@ -32,7 +32,7 @@ public: UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; - TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, false); + TArray Props = FWingProperty::GetDetails(Obj, false); FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"), WingOut::Stdout); if (!P) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h index f74055d5..d5d744e9 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_Set.h @@ -35,10 +35,10 @@ public: UObject* Obj = F.Walk(Object).Cast(); if (!Obj) return; - TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, true); + TArray Props = FWingProperty::GetDetails(Obj, true); FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"), WingOut::Stdout); if (!P) return; - + if (P->SetText(Value, WingOut::Stdout)) WingOut::Stdout.Print(TEXT("OK\n")); } diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h index bce27d0e..0e823f5b 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Details_SetMany.h @@ -38,7 +38,7 @@ public: return; } - TArray Props = FWingProperty::GetDetails(Obj, CPF_Edit, true); + TArray Props = FWingProperty::GetDetails(Obj, true); // Validation pass — resolve all properties before modifying anything. for (const auto& Pair : Properties.Json->Values) diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Add.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Add.h index 885238e1..b47954ee 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Add.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_Add.h @@ -66,7 +66,7 @@ public: // Parse the json array, turning it into an array of spawn node entries. TArray Entries; FSpawnNodeEntry Entry; - TArray Props = FWingProperty::GetAll(&Entry, CPF_None); + TArray Props = FWingProperty::GetAll(&Entry); for (const TSharedPtr& Elt : Nodes.Array) { if (!FWingProperty::PopulateFromJson(Props, *Elt, false, WingOut::Stdout)) return; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h index b9db5e5c..38a0e0a7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetDefaults.h @@ -91,7 +91,7 @@ public: UEdGraphNode* Node = F.Node(Entry.Node).Cast(); if (!Node) return; - TArray All = FWingProperty::GetDetails(Node, CPF_Edit, true); + TArray All = FWingProperty::GetDetails(Node, true); FWingProperty *P = WingUtils::FindOneWithExternalID(Entry.Name, All, TEXT("Property"), WingOut::Stdout); if (!P) return; @@ -121,7 +121,7 @@ public: } FSetNodeDefaultEntry Entry; - TArray Props = FWingProperty::GetAll(&Entry, CPF_None); + TArray Props = FWingProperty::GetAll(&Entry); for (const TSharedPtr& PinVal : Pins.Array) { if (!FWingProperty::PopulateFromJson(Props, *PinVal, false, WingOut::Stdout)) continue; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h index 948afd5b..384c1774 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphNode_SetPositions.h @@ -57,7 +57,7 @@ public: int32 SuccessCount = 0; FMoveNodeEntry Entry; - TArray Props = FWingProperty::GetAll(&Entry, CPF_None); + TArray Props = FWingProperty::GetAll(&Entry); for (const TSharedPtr& Elt : Nodes.Array) { if (!FWingProperty::PopulateFromJson(Props, *Elt, false, WingOut::Stdout)) continue; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h index 7a5ce4f8..226f66b4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Connect.h @@ -57,7 +57,7 @@ public: int32 TotalCount = Connections.Array.Num(); FConnectPinsEntry Entry; - TArray EntryProps = FWingProperty::GetAll(&Entry, CPF_None); + TArray EntryProps = FWingProperty::GetAll(&Entry); for (const TSharedPtr& ConnVal : Connections.Array) { if (!FWingProperty::PopulateFromJson(EntryProps, *ConnVal, false, WingOut::Stdout)) diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h index 97891876..0ee32835 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/GraphPin_Disconnect.h @@ -57,7 +57,7 @@ public: int32 TotalDisconnected = 0; FDisconnectPinEntry Entry; - TArray EntryProps = FWingProperty::GetAll(&Entry, CPF_None); + TArray EntryProps = FWingProperty::GetAll(&Entry); for (const TSharedPtr& DiscVal : Disconnections.Array) { if (!FWingProperty::PopulateFromJson(EntryProps, *DiscVal, false, WingOut::Stdout)) continue; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp index 6a3f3405..49278031 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFactories.cpp @@ -50,7 +50,7 @@ bool WingFactories::CanCreate(TSubclassOf FactoryClass) TArray WingFactories::GetParameterNames(TSubclassOf FactoryClass) { - return FWingProperty::GetNames(FactoryClass, CPF_Edit); + return FWingProperty::GetVisibleNames(FactoryClass); } UObject* WingFactories::CreateAsset(const FString& Path, UFactory* Factory, WingOut Errors) diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp index 7e073a9a..41aeab48 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingFetcher.cpp @@ -1,5 +1,6 @@ #include "WingFetcher.h" #include "WingServer.h" +#include "WingHandler.h" #include "WingUtils.h" #include "WingActorComponent.h" #include "Engine/Blueprint.h" @@ -29,6 +30,7 @@ WingFetcher::WalkFunc WingFetcher::GetWalker(const FString& Step) if (Step.Equals(TEXT("component"), ESearchCase::IgnoreCase)) return &WingFetcher::Component; if (Step.Equals(TEXT("widget"), ESearchCase::IgnoreCase)) return &WingFetcher::Widget; if (Step.Equals(TEXT("levelblueprint"), ESearchCase::IgnoreCase)) return &WingFetcher::LevelBlueprint; + if (Step.Equals(TEXT("structprop"), ESearchCase::IgnoreCase)) return &WingFetcher::StructProp; return nullptr; } @@ -370,3 +372,50 @@ WingFetcher& WingFetcher::LevelBlueprint(const FString& Value) SetObj(LevelBP); return *this; } + +WingFetcher& WingFetcher::StructProp(const FString& Value) +{ + if (bError) return *this; + + FName InternalID = WingUtils::CheckInternalizeID(Value, Errors); + if (InternalID.IsNone()) return SetError(); + + if (!Obj) + { + TypeMismatch(TEXT("structprop"), TEXT("UObject")); + return SetError(); + } + + FStructProperty* StructProp = nullptr; + + // The "host" is the object containing this property. + UObject *HostObject = Obj; + void *HostBase = Obj; + UStruct *HostType = Obj->GetClass(); + bool HostEditable = true; + + // If we are *already* inside a UWingStructPointer, update the host + // fields, to make it possible to navigate even further inside. + if (UWingStructPointer *SPtr = ::Cast(Obj)) + { + HostObject = SPtr->Object; + HostBase = SPtr->StructBase; + HostType = SPtr->StructType; + HostEditable = SPtr->Editable; + } + + StructProp = FindFProperty(HostType, InternalID); + if (!StructProp) + { + Errors.Printf(TEXT("ERROR: No struct property '%s' found on %s\n"), *Value, *HostType->GetName()); + return SetError(); + } + + UWingStructPointer* Ptr = NewObject(); + Ptr->Object = HostObject; + Ptr->StructType = StructProp->Struct; + Ptr->StructBase = StructProp->ContainerPtrToValuePtr(HostBase); + Ptr->Editable = HostEditable && StructProp->HasAllPropertyFlags(CPF_Edit); + SetObj(Ptr); + return *this; +} diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp index ae1a8c2e..21210ab4 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingGraphExport.cpp @@ -250,7 +250,7 @@ void WingGraphExport::EmitNode(UEdGraphNode* Node) void WingGraphExport::EmitNodeProperties(UEdGraphNode* Node, WingOut Out, bool bPrimary) { - TArray Props = FWingProperty::GetDetails(Node, CPF_Edit, false); + TArray Props = FWingProperty::GetDetails(Node, false); FString PrimaryCategory; if (UMaterialGraphNode* MatNode = Cast(Node)) diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp index 29b180a7..a392be8d 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingProperty.cpp @@ -16,6 +16,7 @@ bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; FObjectPropertyBase *OProp = CastField(Prop); if (!OProp) { @@ -47,6 +48,7 @@ bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const bool FWingProperty::SetDouble(double D, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; FNumericProperty *NProp = CastField(Prop); if (!NProp) { @@ -95,6 +97,7 @@ bool FWingProperty::SetDouble(double D, WingOut Errors) const bool FWingProperty::SetInt64(int64 I, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; FNumericProperty *NProp = CastField(Prop); if (!NProp) { @@ -133,6 +136,7 @@ bool FWingProperty::SetInt64(int64 I, WingOut Errors) const bool FWingProperty::SetBool(bool B, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; if (FBoolProperty* BoolProp = CastField(Prop)) { Prop->SetValue_InContainer(Container, &B); @@ -144,6 +148,8 @@ bool FWingProperty::SetBool(bool B, WingOut Errors) const bool FWingProperty::SetText(FString Value, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; + // Pin types get parsed by UWingTypes. if (IsPinTypeProperty(Prop)) { @@ -201,6 +207,8 @@ bool FWingProperty::SetText(FString Value, WingOut Errors) const bool FWingProperty::SetJson(const FJsonValue &JsonValue, WingOut Errors) const { + if (!CheckEditable(Errors)) return false; + if (JsonValue.Type == EJson::String) { return SetText(JsonValue.AsString(), Errors); @@ -376,28 +384,35 @@ FString FWingProperty::GetCategory() const return Result; } -void FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray &Props) -{ - for (TFieldIterator It(Obj.UStructPtr); It; ++It) - { - if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue; - Props.Add(FWingProperty(*It, Obj.StructPtr)); - } -} - -TArray FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags) +TArray FWingProperty::GetAll(FWingStructAndUStruct Obj) { TArray Result; - GetAll(Obj, Flags, Result); + for (TFieldIterator It(Obj.UStructPtr); It; ++It) + { + bool Editable = !It->HasAnyPropertyFlags(CPF_EditConst); + Result.Add(FWingProperty(*It, Obj.StructPtr, Editable)); + } return Result; } -TArray FWingProperty::GetNames(UStruct *US, EPropertyFlags Flags) +TArray FWingProperty::GetVisible(FWingStructAndUStruct Obj) +{ + TArray Result; + for (TFieldIterator It(Obj.UStructPtr); It; ++It) + { + if (!It->HasAllPropertyFlags(CPF_Edit)) continue; + bool Editable = !It->HasAnyPropertyFlags(CPF_EditConst); + Result.Add(FWingProperty(*It, Obj.StructPtr, Editable)); + } + return Result; +} + +TArray FWingProperty::GetVisibleNames(UStruct *US) { TArray Result; for (TFieldIterator It(US); It; ++It) { - if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue; + if (!It->HasAllPropertyFlags(CPF_Edit)) continue; Result.Add(It->GetFName()); } return Result; @@ -419,10 +434,20 @@ void FWingProperty::Move(TArray &Out, TArray &In, In.SetNum(Dst); } -TArray FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable) +TArray FWingProperty::GetDetails(UObject* Obj, bool Mutable) { if (!Obj) return {}; + // If it's a UWingStructPointer, return the properties + // of the struct instead. Propagate editability of the host. + if (UWingStructPointer *SP = Cast(Obj)) + { + TArray Result = + GetVisible(FWingStructAndUStruct(SP->StructBase, SP->StructType)); + if (!Mutable || (!SP->Editable)) StripEditable(Result); + return Result; + } + // Blueprints don't have editable properties. So // instead, we fetch properties from the generated CDO. if (UBlueprint *BP = ::Cast(Obj)) @@ -446,7 +471,7 @@ TArray FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla } } - TArray Result = GetAll(Obj, Flags); + TArray Result = GetVisible(Obj); // If it's a Material Graph node, also collect properties from // the associated material expression. @@ -455,7 +480,7 @@ TArray FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla { if (UMaterialExpression* Expr = MatNode->MaterialExpression) { - GetAll(Expr, Flags, Result); + Result.Append(GetVisible(Expr)); } } @@ -466,10 +491,11 @@ TArray FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Fla FWingProperty::Remove(Result, TEXT("Slot")); if (UPanelSlot* Slot = Widget->Slot) { - GetAll(Slot, Flags, Result); + Result.Append(GetVisible(Slot)); } } + if (!Mutable) StripEditable(Result); return Result; } @@ -555,4 +581,20 @@ bool FWingProperty::CheckImportTextResult(const FString &Value, WingOut Errors) } } return true; +} + +void FWingProperty::StripEditable(TArray &Props) +{ + for (FWingProperty &Elt : Props) Elt.Editable = false; +} + +bool FWingProperty::CheckEditable(WingOut Errors) const +{ + if (!Editable) + { + Errors.Printf(TEXT("ERROR: Cannot edit property %s, not marked editable"), + *WingUtils::FormatName(Prop)); + return false; + } + return true; } \ No newline at end of file diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp index 9a94f3a4..09e61bbf 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingServer.cpp @@ -331,7 +331,7 @@ void UWingServer::TryCallHandler(const FString &Line) Handler->Configuration = Found; // Populate the handler object with the request parameters. - TArray Props = FWingProperty::GetAll(Handler, CPF_Edit); + TArray Props = FWingProperty::GetVisible(Handler); if (!FWingProperty::PopulateFromJson(Props, *Request, false, WingOut::Stdout)) { UWingServer::SuggestManual(WingManual::Section::HandlerHelp); @@ -365,8 +365,6 @@ void UWingServer::AcceptNewConnections() Client->Socket = ClientSocket; Client->ThreadFuture = Async(EAsyncExecution::Thread, [this, Client]() { ClientThreadFunc(this, Client); }); Clients.Add(Client); - - UE_LOG(LogTemp, Display, TEXT("UEWingman: Client connected.")); } void UWingServer::CleanupFinishedClients() @@ -448,10 +446,8 @@ void UWingServer::ClientThreadFunc(UWingServer* Server, TSharedPtrbDone = true; - UE_LOG(LogTemp, Display, TEXT("UEWingman: Client disconnected.")); } - // ============================================================ // BuildWingHandlerRegistry // ============================================================ diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp index edaff310..08d35094 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingVariables.cpp @@ -319,7 +319,7 @@ WingVariables::Var WingVariables::LoadBlueprintVariableDescription(FBPVariableDe FProperty* Prop = CDO->GetClass()->FindPropertyByName(Desc.VarName); if (Prop) { - Result.DefaultValue = FWingProperty(Prop, CDO).GetText(); + Result.DefaultValue = FWingProperty(Prop, CDO, false).GetText(); Result.DefaultSpecified = true; } } @@ -494,7 +494,7 @@ bool WingVariables::ModifyBlueprintDefaults(WingOut Errors) *WingTokenizer::ExternalizeID(Input.Name)); return false; } - if (!FWingProperty(Prop, CDO).SetText(Input.DefaultValue, Errors)) return false; + if (!FWingProperty(Prop, CDO, true).SetText(Input.DefaultValue, Errors)) return false; } } return true; diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h index 9ddc8b06..3ab286fd 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingFetcher.h @@ -54,6 +54,7 @@ public: WingFetcher& Component(const FString& Value); WingFetcher& Widget(const FString& Value); WingFetcher& LevelBlueprint(const FString& Value); + WingFetcher& StructProp(const FString& Value); // Return true if there haven't been any errors. // Note that errors always automatically generate diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h b/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h index f3f8c8ad..b4e3ff53 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingHandler.h @@ -94,6 +94,9 @@ struct FWingStructAndUStruct void *StructPtr; UStruct *UStructPtr; + // Explicit constructor. + explicit FWingStructAndUStruct(void *Base, UStruct *S) : StructPtr(Base), UStructPtr(S) {} + // Copy constructor. FWingStructAndUStruct(FWingStructAndUStruct &Src) : StructPtr(Src.StructPtr), UStructPtr(Src.UStructPtr) {} @@ -103,4 +106,29 @@ struct FWingStructAndUStruct // Construct from a UStruct pointer. template>> FWingStructAndUStruct(T *Struct) : StructPtr(Struct), UStructPtr(Struct->StaticStruct()) {} +}; + + +// WingStructPointer: Allows us to store a pointer to a +// ustruct in a variable of class UObject, through the magic +// of an extra level of indirection. If the struct is part of +// a UObject, then the Object field should be point at the +// object to ensure it doesn't get garbage collected. If the +// editable flag is false, it means the struct is for viewing +// only. + +UCLASS() +class UWingStructPointer : public UObject +{ + GENERATED_BODY() +public: + UPROPERTY() + UObject* Object; + + UPROPERTY() + UStruct* StructType; + + void *StructBase; + + bool Editable; }; \ No newline at end of file diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h b/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h index de11e10a..7096969a 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingProperty.h @@ -12,11 +12,12 @@ struct FWingProperty FProperty* Prop = nullptr; void* Container = nullptr; + bool Editable = false; // Construct a property reference. // - FWingProperty(FProperty* InProp, void* InContainer) - : Prop(InProp), Container(InContainer) {} + FWingProperty(FProperty* InProp, void* InContainer, bool Edit) + : Prop(InProp), Container(InContainer), Editable(Edit) {} // Construct a null property reference. // @@ -57,7 +58,7 @@ struct FWingProperty // FString GetTruncatedText(int32 MaxLen) const; - // Print the property's type, name, and value. + // Print the property's editflag, type, name, and value. // void Print(WingOut Out) const; @@ -69,16 +70,22 @@ struct FWingProperty // explicit operator bool() const { return Prop != nullptr; } - // Get the raw properties of the specified object or struct. + // Get all the properties of the specified object or struct. // // This gets the properties that are literally present in the // specified object or struct. No special interpretation is done. // - static TArray GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags); + static TArray GetAll(FWingStructAndUStruct Obj); + + // Get all the visible properties of the specified object or struct. + // + // This gets the properties that have CPF_Edit marked on them. + // + static TArray GetVisible(FWingStructAndUStruct Obj); // Get just the names of the properties of the specified struct/class. // - static TArray GetNames(UStruct *US, EPropertyFlags Flags); + static TArray GetVisibleNames(UStruct *US); // Remove any properties with the specified name. // @@ -98,12 +105,10 @@ struct FWingProperty // click a material graph node, the details panel shows you properties // of the node, but also properties of the material expression. // - // When editing an inherited ActorComponent, you're actually editing - // properties that *override* the original properties of the ActorComponent. - // The 'mutable' flag tells it whether to create overrides for these - // properties. + // If you do not specify mutable, then all properties will be marked + // non-editable. // - static TArray GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable); + static TArray GetDetails(UObject* Obj, bool Mutable); // Functions to populate properties from a JSON object. // @@ -113,8 +118,9 @@ struct FWingProperty bool AllOptional, WingOut Errors); private: - static void GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray &Props); + static void StripEditable(TArray &Props); static bool IsPinTypeProperty(FProperty *Prop); void PrintExpectsReceived(const TCHAR *Type, WingOut Errors) const; bool CheckImportTextResult(const FString &Value, WingOut Errors) const; + bool CheckEditable(WingOut Errors) const; };