From a0c5a56476cfca1f7fdce5bcaa1ce6f844be664c Mon Sep 17 00:00:00 2001 From: jyelon Date: Fri, 3 Apr 2026 15:52:07 -0400 Subject: [PATCH] More work on properties --- .../UEWingman/Handlers/Create_Blueprint.h | 32 ++++---- .../UEWingman/Handlers/Create_UsingFactory.h | 5 +- .../Source/UEWingman/Handlers/Property_Dump.h | 75 ------------------- .../Source/UEWingman/Handlers/Property_Get.h | 46 ------------ .../Source/UEWingman/Handlers/Property_Set.h | 64 ---------------- .../UEWingman/Private/WingPropHandle.cpp | 26 +++++-- .../Source/UEWingman/Public/WingPropHandle.h | 8 +- 7 files changed, 44 insertions(+), 212 deletions(-) delete mode 100644 Plugins/UEWingman/Source/UEWingman/Handlers/Property_Dump.h delete mode 100644 Plugins/UEWingman/Source/UEWingman/Handlers/Property_Get.h delete mode 100644 Plugins/UEWingman/Source/UEWingman/Handlers/Property_Set.h diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h index 3777a58f..058d9d1f 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_Blueprint.h @@ -5,6 +5,7 @@ #include "WingServer.h" #include "WingHandler.h" #include "WingFactories.h" +#include "WingPropHandle.h" #include "WingTypes.h" #include "Factories/BlueprintFactory.h" #include "Factories/BlueprintMacroFactory.h" @@ -73,31 +74,26 @@ public: // Make the factory. UClass *FactoryClass = Cast(ConfigurationObject); UFactory *Factory = NewObject(GetTransientPackage(), FactoryClass); - - // Get the 'ParentClass' property. - FProperty *Prop = FactoryClass->FindPropertyByName(FName(TEXT("ParentClass"))); - FClassProperty *CProp = CastField(Prop); - - // Check that things are on track. - if ((Factory == nullptr) || (CProp == nullptr)) + if (Factory == nullptr) { - UWingServer::Printf(TEXT("In Create_Blueprint, factory creation is buggy\n")); + UWingServer::Printf(TEXT("ERROR: factory creation failed (bug)\n")); return; } - // Store the parentclass, if specified. - if (ParentClassObj) + // Get the 'ParentClass' property. + WingPropHandle Props; + TSharedPtr PCProp = Props.NamedProperty(Factory, TEXT("ParentClass"), true); + if (!PCProp) return; + + // Store the parent class. + FPropertyAccess::Result SetResult = PCProp->SetValue(ParentClassObj); + if (SetResult != FPropertyAccess::Result::Success) { - if (!ParentClassObj->IsChildOf(CProp->MetaClass)) - { - UWingServer::Printf(TEXT("ParentClass must be child of %s.\n"), - *WingUtils::FormatName(CProp->MetaClass)); - return; - } - CProp->SetObjectPropertyValue_InContainer(Factory, ParentClassObj); + UWingServer::Printf(TEXT("ERROR: property does not allow value: %s\n"), *ParentClass); + return; } - // Create the asset. + // Create the asset using the factory. UObject *Blueprint = WingFactories::CreateAsset(Path, Factory); if (Blueprint == nullptr) return; UWingServer::Printf(TEXT("Created.\n")); diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h index eb509e89..f13d79f7 100644 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h +++ b/Plugins/UEWingman/Source/UEWingman/Handlers/Create_UsingFactory.h @@ -5,7 +5,7 @@ #include "WingServer.h" #include "WingHandler.h" #include "WingFactories.h" -#include "WingProperty.h" +#include "WingPropHandle.h" #include "Factories/BlueprintFunctionLibraryFactory.h" #include "Create_UsingFactory.generated.h" @@ -30,7 +30,8 @@ public: UFactory* CDO = Class->GetDefaultObject(); if (!CDO->CanCreateNew() || !CDO->ShouldShowInNewMenu()) continue; - TArray ConfigProps = FWingProperty::GetNames(Class, CPF_Edit); + WingPropHandle Props; + TArray> ConfigProps = Props.AllProperties(CDO, true, CPF_Edit); if (ConfigProps.Num() > 0) continue; FString FactoryName = WingFactories::DeriveFactoryName(Class); diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Dump.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Dump.h deleted file mode 100644 index 379455ca..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Dump.h +++ /dev/null @@ -1,75 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingProperty.h" -#include "WingTypes.h" -#include "WingUtils.h" -#include "Property_Dump.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Property_Dump : public UWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Target object")) - FString Object; - - UPROPERTY(meta=(Optional, Description="Substring filter for property names")) - FString Query; - - UPROPERTY(meta=(Optional, Description="Only show properties declared on the object's own class, not inherited ones")) - bool Local = false; - - virtual void Register() override - { - UWingServer::AddHandler(this, - TEXT("List all blueprint-visible properties, showing current values and which are editable.")); - } - virtual void Handle() override - { - // Resolve the path to an object and get its editable template. - WingFetcher F; - UObject* Template = F.Walk(Object).Cast(); - if (!Template) return; - TArray AllProps = FWingProperty::GetDetailsImmutable(Template, CPF_Edit); - TArray Props = FWingProperty::FindAllSubstring(AllProps, Query); - if (Local) - { - UClass* ObjClass = Template->GetClass(); - Props.RemoveAll([ObjClass](const FWingProperty& P) { return P->GetOwnerStruct() != ObjClass; }); - } - - if (Props.IsEmpty()) - { - UWingServer::Print(TEXT(" (no blueprint-visible properties found)\n")); - return; - } - - FString CurrentCategory; - for (FWingProperty& P : Props) - { - FString Category = P.GetCategory(); - if (Category != CurrentCategory) - { - CurrentCategory = Category; - UWingServer::Printf(TEXT("\n%s:\n"), *CurrentCategory); - } - - bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst); - UWingServer::Printf(TEXT(" %s %s %s = %s\n"), - bEditable ? TEXT("editable") : TEXT("readonly"), - *UWingTypes::TypeToText(P.Prop), - *WingUtils::FormatName(P.Prop), - *P.GetTruncatedText(100)); - } - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Get.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Get.h deleted file mode 100644 index d18a4f6f..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Get.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingProperty.h" -#include "WingUtils.h" -#include "Property_Get.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Property_Get : public UWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Target object")) - FString Object; - - UPROPERTY(meta=(Description="Property name")) - FString Property; - - virtual void Register() override - { - UWingServer::AddHandler(this, - TEXT("Get the value of a single property.")); - } - virtual void Handle() override - { - WingFetcher F; - UObject* Obj = F.Walk(Object).Cast(); - if (!Obj) return; - - TArray All = FWingProperty::GetDetailsMutable(Obj, CPF_Edit); - FWingProperty *P = WingUtils::FindOneWithExternalID(Property, All, TEXT("Property")); - if (!P) return; - - UWingServer::Print(P->GetText()); - UWingServer::Print(TEXT("\n")); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Set.h b/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Set.h deleted file mode 100644 index 8010798a..00000000 --- a/Plugins/UEWingman/Source/UEWingman/Handlers/Property_Set.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include "CoreMinimal.h" -#include "WingServer.h" -#include "WingHandler.h" -#include "WingFetcher.h" -#include "WingProperty.h" -#include "WingUtils.h" -#include "Property_Set.generated.h" - - -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- -// --------------------------------------------------------------------------- - -UCLASS() -class UWing_Property_Set : public UWingHandler -{ - GENERATED_BODY() - -public: - UPROPERTY(meta=(Description="Target object")) - FString Object; - - UPROPERTY(meta=(Description="Object mapping property names to new values in Unreal text format")) - FWingJsonObject Properties; - - virtual void Register() override - { - UWingServer::AddHandler(this, - TEXT("Set one or more editable properties. Values use Unreal text format.")); - } - virtual void Handle() override - { - // Resolve the path to an object and get its editable template. - WingFetcher F; - UObject* Obj = F.Walk(Object).Cast(); - if (!Obj) return; - - if (!Properties.Json || Properties.Json->Values.Num() == 0) - { - UWingServer::Print(TEXT("Error: No properties specified\n")); - return; - } - TArray All = FWingProperty::GetDetailsMutable(Obj, CPF_Edit); - int SuccessCount = 0; - - // Validation pass — resolve all properties and values before modifying anything. - for (const auto& Pair : Properties.Json->Values) - { - FWingProperty *P = WingUtils::FindOneWithExternalID(Pair.Key, All, TEXT("Property")); - if (!P) return; - } - - // Assignment Pass - store the values. - for (const auto& Pair : Properties.Json->Values) - { - FWingProperty *P = WingUtils::FindOneWithExternalID(Pair.Key, All, TEXT("Property")); - if (P && P->SetJson(Pair.Value)) SuccessCount++; - } - - UWingServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num()); - } -}; diff --git a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp index d1e033d5..8c14d0a3 100644 --- a/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp +++ b/Plugins/UEWingman/Source/UEWingman/Private/WingPropHandle.cpp @@ -164,7 +164,7 @@ WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruc // ///////////////////////////////////////////////////////////////////////////// -TSharedPtr WingPropHandle::NamedProperty(Root& Root, FName Name, bool RootFilter) +TSharedPtr WingPropHandle::TryNamedProperty(Root& Root, FName Name, bool RootFilter) { for (IDetailTreeNode* Node : AllTreeNodes(Root)) { @@ -176,16 +176,32 @@ TSharedPtr WingPropHandle::NamedProperty(Root& Root, FName Name return nullptr; } -TSharedPtr WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter) +TSharedPtr WingPropHandle::TryNamedProperty(UObject* Obj, FName Name, bool RootFilter) { if (!Obj) return nullptr; - return NamedProperty(GetRootForObject(Obj), Name, RootFilter); + return TryNamedProperty(GetRootForObject(Obj), Name, RootFilter); +} + +TSharedPtr WingPropHandle::TryNamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter) +{ + if (!ScriptStruct || !Data) return nullptr; + return TryNamedProperty(GetRootForStruct(ScriptStruct, Data), Name, RootFilter); +} + +TSharedPtr WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter) +{ + TSharedPtr Result = TryNamedProperty(Obj, Name, RootFilter); + if (!Result) + UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); + return Result; } TSharedPtr WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter) { - if (!ScriptStruct || !Data) return nullptr; - return NamedProperty(GetRootForStruct(ScriptStruct, Data), Name, RootFilter); + TSharedPtr Result = TryNamedProperty(ScriptStruct, Data, Name, RootFilter); + if (!Result) + UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString()); + return Result; } ///////////////////////////////////////////////////////////////////////////// diff --git a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h index fdae7ef6..8809b7d2 100644 --- a/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h +++ b/Plugins/UEWingman/Source/UEWingman/Public/WingPropHandle.h @@ -36,10 +36,14 @@ public: // Get a single named property from a UObject. // If RootFilter is true, only properties inside the root object are returned. - TSharedPtr NamedProperty(UObject* Obj, FName Name, bool RootFilter); + TSharedPtr TryNamedProperty(UObject* Obj, FName Name, bool RootFilter); // Get a single named property from a struct. // If RootFilter is true, only properties inside the root object are returned. + TSharedPtr TryNamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter); + + // Like TryNamedProperty, but prints an error if the property is not found. + TSharedPtr NamedProperty(UObject* Obj, FName Name, bool RootFilter); TSharedPtr NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter); // Get "details panel" properties for an object. Handles special @@ -79,5 +83,5 @@ private: static FlatTree AllTreeNodes(Root& Root); Handles AllProperties(Root& Root, bool RootFilter, EPropertyFlags Filter); - static TSharedPtr NamedProperty(Root& Root, FName Name, bool RootFilter); + static TSharedPtr TryNamedProperty(Root& Root, FName Name, bool RootFilter); };