More work on properties
This commit is contained in:
@@ -5,6 +5,7 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFactories.h"
|
#include "WingFactories.h"
|
||||||
|
#include "WingPropHandle.h"
|
||||||
#include "WingTypes.h"
|
#include "WingTypes.h"
|
||||||
#include "Factories/BlueprintFactory.h"
|
#include "Factories/BlueprintFactory.h"
|
||||||
#include "Factories/BlueprintMacroFactory.h"
|
#include "Factories/BlueprintMacroFactory.h"
|
||||||
@@ -73,31 +74,26 @@ public:
|
|||||||
// Make the factory.
|
// Make the factory.
|
||||||
UClass *FactoryClass = Cast<UClass>(ConfigurationObject);
|
UClass *FactoryClass = Cast<UClass>(ConfigurationObject);
|
||||||
UFactory *Factory = NewObject<UFactory>(GetTransientPackage(), FactoryClass);
|
UFactory *Factory = NewObject<UFactory>(GetTransientPackage(), FactoryClass);
|
||||||
|
if (Factory == nullptr)
|
||||||
|
{
|
||||||
|
UWingServer::Printf(TEXT("ERROR: factory creation failed (bug)\n"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Get the 'ParentClass' property.
|
// Get the 'ParentClass' property.
|
||||||
FProperty *Prop = FactoryClass->FindPropertyByName(FName(TEXT("ParentClass")));
|
WingPropHandle Props;
|
||||||
FClassProperty *CProp = CastField<FClassProperty>(Prop);
|
TSharedPtr<IPropertyHandle> PCProp = Props.NamedProperty(Factory, TEXT("ParentClass"), true);
|
||||||
|
if (!PCProp) return;
|
||||||
|
|
||||||
// Check that things are on track.
|
// Store the parent class.
|
||||||
if ((Factory == nullptr) || (CProp == nullptr))
|
FPropertyAccess::Result SetResult = PCProp->SetValue(ParentClassObj);
|
||||||
|
if (SetResult != FPropertyAccess::Result::Success)
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("In Create_Blueprint, factory creation is buggy\n"));
|
UWingServer::Printf(TEXT("ERROR: property does not allow value: %s\n"), *ParentClass);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store the parentclass, if specified.
|
// Create the asset using the factory.
|
||||||
if (ParentClassObj)
|
|
||||||
{
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create the asset.
|
|
||||||
UObject *Blueprint = WingFactories::CreateAsset(Path, Factory);
|
UObject *Blueprint = WingFactories::CreateAsset(Path, Factory);
|
||||||
if (Blueprint == nullptr) return;
|
if (Blueprint == nullptr) return;
|
||||||
UWingServer::Printf(TEXT("Created.\n"));
|
UWingServer::Printf(TEXT("Created.\n"));
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFactories.h"
|
#include "WingFactories.h"
|
||||||
#include "WingProperty.h"
|
#include "WingPropHandle.h"
|
||||||
#include "Factories/BlueprintFunctionLibraryFactory.h"
|
#include "Factories/BlueprintFunctionLibraryFactory.h"
|
||||||
#include "Create_UsingFactory.generated.h"
|
#include "Create_UsingFactory.generated.h"
|
||||||
|
|
||||||
@@ -30,7 +30,8 @@ public:
|
|||||||
UFactory* CDO = Class->GetDefaultObject<UFactory>();
|
UFactory* CDO = Class->GetDefaultObject<UFactory>();
|
||||||
if (!CDO->CanCreateNew() || !CDO->ShouldShowInNewMenu()) continue;
|
if (!CDO->CanCreateNew() || !CDO->ShouldShowInNewMenu()) continue;
|
||||||
|
|
||||||
TArray<FName> ConfigProps = FWingProperty::GetNames(Class, CPF_Edit);
|
WingPropHandle Props;
|
||||||
|
TArray<TSharedPtr<IPropertyHandle>> ConfigProps = Props.AllProperties(CDO, true, CPF_Edit);
|
||||||
if (ConfigProps.Num() > 0) continue;
|
if (ConfigProps.Num() > 0) continue;
|
||||||
|
|
||||||
FString FactoryName = WingFactories::DeriveFactoryName(Class);
|
FString FactoryName = WingFactories::DeriveFactoryName(Class);
|
||||||
|
|||||||
@@ -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<UObject>();
|
|
||||||
if (!Template) return;
|
|
||||||
TArray<FWingProperty> AllProps = FWingProperty::GetDetailsImmutable(Template, CPF_Edit);
|
|
||||||
TArray<FWingProperty> 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -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<UObject>();
|
|
||||||
if (!Obj) return;
|
|
||||||
|
|
||||||
TArray<FWingProperty> 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"));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -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<UObject>();
|
|
||||||
if (!Obj) return;
|
|
||||||
|
|
||||||
if (!Properties.Json || Properties.Json->Values.Num() == 0)
|
|
||||||
{
|
|
||||||
UWingServer::Print(TEXT("Error: No properties specified\n"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
TArray<FWingProperty> 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());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@@ -164,7 +164,7 @@ WingPropHandle::Handles WingPropHandle::AllProperties(const UStruct* ScriptStruc
|
|||||||
//
|
//
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(Root& Root, FName Name, bool RootFilter)
|
TSharedPtr<IPropertyHandle> WingPropHandle::TryNamedProperty(Root& Root, FName Name, bool RootFilter)
|
||||||
{
|
{
|
||||||
for (IDetailTreeNode* Node : AllTreeNodes(Root))
|
for (IDetailTreeNode* Node : AllTreeNodes(Root))
|
||||||
{
|
{
|
||||||
@@ -176,16 +176,32 @@ TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(Root& Root, FName Name
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter)
|
TSharedPtr<IPropertyHandle> WingPropHandle::TryNamedProperty(UObject* Obj, FName Name, bool RootFilter)
|
||||||
{
|
{
|
||||||
if (!Obj) return nullptr;
|
if (!Obj) return nullptr;
|
||||||
return NamedProperty(GetRootForObject(Obj), Name, RootFilter);
|
return TryNamedProperty(GetRootForObject(Obj), Name, RootFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<IPropertyHandle> WingPropHandle::TryNamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter)
|
||||||
|
{
|
||||||
|
if (!ScriptStruct || !Data) return nullptr;
|
||||||
|
return TryNamedProperty(GetRootForStruct(ScriptStruct, Data), Name, RootFilter);
|
||||||
|
}
|
||||||
|
|
||||||
|
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(UObject* Obj, FName Name, bool RootFilter)
|
||||||
|
{
|
||||||
|
TSharedPtr<IPropertyHandle> Result = TryNamedProperty(Obj, Name, RootFilter);
|
||||||
|
if (!Result)
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString());
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter)
|
TSharedPtr<IPropertyHandle> WingPropHandle::NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter)
|
||||||
{
|
{
|
||||||
if (!ScriptStruct || !Data) return nullptr;
|
TSharedPtr<IPropertyHandle> Result = TryNamedProperty(ScriptStruct, Data, Name, RootFilter);
|
||||||
return NamedProperty(GetRootForStruct(ScriptStruct, Data), Name, RootFilter);
|
if (!Result)
|
||||||
|
UWingServer::Printf(TEXT("ERROR: Property '%s' not found\n"), *Name.ToString());
|
||||||
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
||||||
|
|||||||
@@ -36,10 +36,14 @@ public:
|
|||||||
|
|
||||||
// Get a single named property from a UObject.
|
// Get a single named property from a UObject.
|
||||||
// If RootFilter is true, only properties inside the root object are returned.
|
// If RootFilter is true, only properties inside the root object are returned.
|
||||||
TSharedPtr<IPropertyHandle> NamedProperty(UObject* Obj, FName Name, bool RootFilter);
|
TSharedPtr<IPropertyHandle> TryNamedProperty(UObject* Obj, FName Name, bool RootFilter);
|
||||||
|
|
||||||
// Get a single named property from a struct.
|
// Get a single named property from a struct.
|
||||||
// If RootFilter is true, only properties inside the root object are returned.
|
// If RootFilter is true, only properties inside the root object are returned.
|
||||||
|
TSharedPtr<IPropertyHandle> TryNamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter);
|
||||||
|
|
||||||
|
// Like TryNamedProperty, but prints an error if the property is not found.
|
||||||
|
TSharedPtr<IPropertyHandle> NamedProperty(UObject* Obj, FName Name, bool RootFilter);
|
||||||
TSharedPtr<IPropertyHandle> NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter);
|
TSharedPtr<IPropertyHandle> NamedProperty(const UStruct* ScriptStruct, uint8* Data, FName Name, bool RootFilter);
|
||||||
|
|
||||||
// Get "details panel" properties for an object. Handles special
|
// Get "details panel" properties for an object. Handles special
|
||||||
@@ -79,5 +83,5 @@ private:
|
|||||||
static FlatTree AllTreeNodes(Root& Root);
|
static FlatTree AllTreeNodes(Root& Root);
|
||||||
|
|
||||||
Handles AllProperties(Root& Root, bool RootFilter, EPropertyFlags Filter);
|
Handles AllProperties(Root& Root, bool RootFilter, EPropertyFlags Filter);
|
||||||
static TSharedPtr<IPropertyHandle> NamedProperty(Root& Root, FName Name, bool RootFilter);
|
static TSharedPtr<IPropertyHandle> TryNamedProperty(Root& Root, FName Name, bool RootFilter);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user