better expression of class properties
This commit is contained in:
@@ -58,12 +58,12 @@ public:
|
||||
|
||||
// Resolve the component class by name
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = false;
|
||||
Req.IsChildOf = UActorComponent::StaticClass();
|
||||
UClass* ComponentClass = UWingTypes::TextToOneObjectType(Class, Req, WingOut::Stdout);
|
||||
if (!ComponentClass) return;
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Class, PinType, Req, WingOut::Stdout)) return;
|
||||
UClass* ComponentClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
check(ComponentClass);
|
||||
if (!UWingComponentReference::CheckValidComponentClass(ComponentClass, WingOut::Stdout)) return;
|
||||
|
||||
// Find the specified parent component
|
||||
|
||||
@@ -52,11 +52,12 @@ public:
|
||||
if (!Type.IsEmpty())
|
||||
{
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = false;
|
||||
UClass* TypeClass = UWingTypes::TextToOneObjectType(Type, Req, WingOut::Stdout);
|
||||
if (!TypeClass) return;
|
||||
Req.IsChildOf = UObject::StaticClass();
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Type, PinType, Req, WingOut::Stdout)) return;
|
||||
UClass* TypeClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
check(TypeClass);
|
||||
Filter.ClassPaths.Add(TypeClass->GetClassPathName());
|
||||
}
|
||||
|
||||
|
||||
@@ -40,11 +40,12 @@ public:
|
||||
|
||||
// Resolve the interface class
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = false;
|
||||
UClass* InterfaceClass = UWingTypes::TextToOneInterfaceType(Interface, Req, WingOut::Stdout);
|
||||
if (!InterfaceClass) return;
|
||||
Req.IsChildOf = UInterface::StaticClass();
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Interface, PinType, Req, WingOut::Stdout)) return;
|
||||
UClass* InterfaceClass = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
check(InterfaceClass);
|
||||
|
||||
// Check for duplicates
|
||||
for (const FBPInterfaceDescription& IfaceDesc : BP->ImplementedInterfaces)
|
||||
|
||||
@@ -44,11 +44,12 @@ public:
|
||||
|
||||
// Resolve the interface name to a UClass*
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = false;
|
||||
UClass* FoundInterface = UWingTypes::TextToOneInterfaceType(Interface, Req, WingOut::Stdout);
|
||||
if (!FoundInterface) return;
|
||||
Req.IsChildOf = UInterface::StaticClass();
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Interface, PinType, Req, WingOut::Stdout)) return;
|
||||
UClass* FoundInterface = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
check(FoundInterface);
|
||||
|
||||
// Verify this blueprint actually implements it
|
||||
bool Found = false;
|
||||
|
||||
@@ -42,12 +42,14 @@ public:
|
||||
|
||||
// Find the new parent class by short type name
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = true;
|
||||
Req.AllowContainer = false;
|
||||
UClass* NewParentClassObj = UWingTypes::TextToOneObjectType(Parent, Req, WingOut::Stdout);
|
||||
if (!NewParentClassObj) return;
|
||||
|
||||
Req.IsChildOf = UObject::StaticClass();
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Parent, PinType, Req, WingOut::Stdout)) return;
|
||||
UClass* NewParentClassObj = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
check(NewParentClassObj);
|
||||
|
||||
// Validate reparent
|
||||
if (!WingUtils::CanReparentBlueprint(BP->GeneratedClass, NewParentClassObj))
|
||||
{
|
||||
|
||||
@@ -213,12 +213,13 @@ public:
|
||||
if (!Class.IsEmpty())
|
||||
{
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = false;
|
||||
Req.Blueprintable = Config.Blueprintable;
|
||||
Req.AllowContainer = false;
|
||||
Req.AllowNone = !Config.ValidPointer;
|
||||
Req.IsChildOf = ConfObj->BaseClass;
|
||||
ClassObj = UWingTypes::TextToOneObjectType(Class, Req, WingOut::Stdout);
|
||||
if (!ClassObj) return;
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Class, PinType, Req, WingOut::Stdout)) return;
|
||||
ClassObj = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
}
|
||||
|
||||
// Check constraints.
|
||||
|
||||
@@ -157,6 +157,21 @@ bool FWingProperty::SetText(FString Value, WingOut Errors) const
|
||||
return true;
|
||||
}
|
||||
|
||||
// Class properties get parsed by UWingTypes.
|
||||
if (FClassProperty *CProp = CastField<FClassProperty>(Prop))
|
||||
{
|
||||
UWingTypes::Requirements Req;
|
||||
Req.IsChildOf = CProp->MetaClass;
|
||||
if (CProp->MetaClass == nullptr) Req.IsChildOf = UObject::StaticClass();
|
||||
Req.AllowNone = true;
|
||||
Req.AllowContainer = false;
|
||||
FEdGraphPinType PinType;
|
||||
if (!UWingTypes::TextToType(Value, PinType, Req, Errors)) return false;
|
||||
CProp->SetObjectPropertyValue_InContainer(Container,
|
||||
Cast<UClass>(PinType.PinSubCategoryObject.Get()));
|
||||
return true;
|
||||
}
|
||||
|
||||
// If it's an enum type, use our parsing routine which is smarter about
|
||||
// prefixes than ImportText. We canonicalize the string, and then send
|
||||
// it onward to ImportText.
|
||||
@@ -322,6 +337,12 @@ FString FWingProperty::GetText() const
|
||||
FEdGraphPinType *PinType = Prop->ContainerPtrToValuePtr<FEdGraphPinType>(Container);
|
||||
return UWingTypes::TypeToText(*PinType);
|
||||
}
|
||||
if (FClassProperty *CProp = CastField<FClassProperty>(Prop))
|
||||
{
|
||||
UObject *Obj = CProp->GetObjectPropertyValue_InContainer(Container);
|
||||
if (Obj) return UWingTypes::TypeToText(Obj);
|
||||
return TEXT("None");
|
||||
}
|
||||
FString Result;
|
||||
Prop->ExportTextItem_InContainer(Result, Container, nullptr, nullptr, PPF_None);
|
||||
return Result;
|
||||
|
||||
@@ -14,6 +14,15 @@
|
||||
#include "Kismet2/KismetEditorUtilities.h"
|
||||
|
||||
|
||||
static const FName NAME_TypeArray(TEXT("Array"));
|
||||
static const FName NAME_TypeSet(TEXT("Set"));
|
||||
static const FName NAME_TypeMap(TEXT("Map"));
|
||||
static const FName NAME_TypeSoft(TEXT("Soft"));
|
||||
static const FName NAME_TypeClass(TEXT("Class"));
|
||||
static const FName NAME_TypeSoftClass(TEXT("SoftClass"));
|
||||
static const FName NAME_StartOfType(TEXT("Start-of-Type"));
|
||||
static const FName NAME_NoneMeaningNullptr(TEXT("None"));
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Simple Accessors
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -318,7 +327,8 @@ FString UWingTypes::TypeToText(FName Category, FName SubCategory, UObject* SubCa
|
||||
(Category == UEdGraphSchema_K2::PC_Int64) ||
|
||||
(Category == UEdGraphSchema_K2::PC_Name) ||
|
||||
(Category == UEdGraphSchema_K2::PC_String) ||
|
||||
(Category == UEdGraphSchema_K2::PC_Text))
|
||||
(Category == UEdGraphSchema_K2::PC_Text) ||
|
||||
(Category == NAME_NoneMeaningNullptr))
|
||||
{
|
||||
return Category.ToString();
|
||||
}
|
||||
@@ -408,6 +418,7 @@ FString UWingTypes::TypeToText(const UObject* Obj)
|
||||
{
|
||||
UWingTypes* Types = GEditor->GetEditorSubsystem<UWingTypes>();
|
||||
if (!Types) return FString();
|
||||
if (Obj == nullptr) return TEXT("None");
|
||||
return Types->ChooseShortName(Obj);
|
||||
}
|
||||
|
||||
@@ -415,6 +426,7 @@ FString UWingTypes::TypeToTextOrDie(const UObject* Obj)
|
||||
{
|
||||
UWingTypes* Types = GEditor->GetEditorSubsystem<UWingTypes>();
|
||||
if (!Types) return FString();
|
||||
if (Obj == nullptr) return TEXT("None");
|
||||
FString Result = Types->ChooseShortName(Obj);
|
||||
check(!Result.IsEmpty());
|
||||
return Result;
|
||||
@@ -424,15 +436,6 @@ FString UWingTypes::TypeToTextOrDie(const UObject* Obj)
|
||||
// Parser and Resolve Short Name
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static const FName NAME_TypeArray(TEXT("Array"));
|
||||
static const FName NAME_TypeSet(TEXT("Set"));
|
||||
static const FName NAME_TypeMap(TEXT("Map"));
|
||||
static const FName NAME_TypeSoft(TEXT("Soft"));
|
||||
static const FName NAME_TypeClass(TEXT("Class"));
|
||||
static const FName NAME_TypeSoftClass(TEXT("SoftClass"));
|
||||
|
||||
static const FName NAME_StartOfType("Start-of-Type");
|
||||
|
||||
void UWingTypes::PrintParseError(WingTokenizer& Tok, const TCHAR* Message, WingOut Errors)
|
||||
{
|
||||
FString TypeText(Tok.GetRange(NAME_StartOfType, 1));
|
||||
@@ -611,14 +614,6 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
check(Types);
|
||||
Tok.SaveCursor(NAME_StartOfType);
|
||||
|
||||
if (!Require.BlueprintType.IsSet() ||
|
||||
!Require.Blueprintable.IsSet() ||
|
||||
!Require.AllowContainer.IsSet())
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: TextToType called with underspecified Requirements list.\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
OutPinType = FEdGraphPinType();
|
||||
if (!Types->ParseType(Tok, OutPinType, Errors))
|
||||
{
|
||||
@@ -631,7 +626,28 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
|
||||
if (!Require.AllowContainer.GetValue())
|
||||
// Check for none. If the type is none, and allownone is specified,
|
||||
// then that overrides a lot of other requirements. We set a flag for this.
|
||||
bool IsNone = OutPinType.PinCategory == NAME_NoneMeaningNullptr;
|
||||
bool AllowNoneIsOverriding = (Require.AllowNone && IsNone);
|
||||
|
||||
// None is never allowed inside a container.
|
||||
if (IsNone && OutPinType.IsContainer())
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: 'None' is not allowed in an array/set/map\n"));
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
|
||||
// Don't allow none unless AllowNone is set.
|
||||
if (!Require.AllowNone && IsNone)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: 'None' is not allowed here\n"));
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
|
||||
if (!Require.AllowContainer)
|
||||
{
|
||||
if (OutPinType.IsContainer())
|
||||
{
|
||||
@@ -642,7 +658,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
}
|
||||
}
|
||||
|
||||
if (!Require.PinCategory.IsNone())
|
||||
if (!Require.PinCategory.IsNone() && (!AllowNoneIsOverriding))
|
||||
{
|
||||
if (OutPinType.PinCategory != Require.PinCategory)
|
||||
{
|
||||
@@ -653,8 +669,17 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
}
|
||||
}
|
||||
|
||||
if (Require.IsChildOf)
|
||||
if (Require.IsChildOf && (!AllowNoneIsOverriding))
|
||||
{
|
||||
// If the base class is not an interface, don't allow interfaces.
|
||||
if (!Require.IsChildOf->IsChildOf(UInterface::StaticClass())
|
||||
&& OutPinType.PinCategory == UEdGraphSchema_K2::PC_Interface)
|
||||
{
|
||||
FString Text(Tok.GetRange(NAME_StartOfType, 0));
|
||||
Errors.Printf(TEXT("ERROR: '%s' is an interface, not a class\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::HandlerHelp);
|
||||
OutPinType = FEdGraphPinType(); return false;
|
||||
}
|
||||
if (!IsChildOf(OutPinType, Require.IsChildOf))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Type must derive from %s\n"), *WingUtils::FormatName(Require.IsChildOf));
|
||||
@@ -663,7 +688,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
}
|
||||
}
|
||||
|
||||
if (Require.BlueprintType.GetValue())
|
||||
if (Require.BlueprintType && (!AllowNoneIsOverriding))
|
||||
{
|
||||
if (!IsBlueprintType(OutPinType))
|
||||
{
|
||||
@@ -674,7 +699,7 @@ bool UWingTypes::TextToType(WingTokenizer &Tok, FEdGraphPinType& OutPinType, con
|
||||
}
|
||||
}
|
||||
|
||||
if (Require.Blueprintable.GetValue())
|
||||
if (Require.Blueprintable && (!AllowNoneIsOverriding))
|
||||
{
|
||||
if (!IsBlueprintable(OutPinType))
|
||||
{
|
||||
@@ -694,36 +719,6 @@ bool UWingTypes::TextToType(const FString &Text, FEdGraphPinType& OutPinType, co
|
||||
return TextToType(Tok, OutPinType, Require, true, Errors);
|
||||
}
|
||||
|
||||
UClass* UWingTypes::TextToOneObjectType(const FString& Text, const Requirements &Require, WingOut Errors)
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
if (!TextToType(Text, PinType, Require, Errors)) return nullptr;
|
||||
UClass* Class = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
if ((!Class) || (PinType.PinCategory != UEdGraphSchema_K2::PC_Object) ||
|
||||
(PinType.IsContainer()))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: '%s' is not an object class\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||
return nullptr;
|
||||
}
|
||||
return Class;
|
||||
}
|
||||
|
||||
UClass* UWingTypes::TextToOneInterfaceType(const FString& Text, const Requirements &Require, WingOut Errors)
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
if (!TextToType(Text, PinType, Require, Errors)) return nullptr;
|
||||
UClass* Class = Cast<UClass>(PinType.PinSubCategoryObject.Get());
|
||||
if ((!Class) || (PinType.PinCategory != UEdGraphSchema_K2::PC_Interface) ||
|
||||
(PinType.IsContainer()))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: '%s' is not an interface class\n"), *Text);
|
||||
UWingServer::SuggestManual(WingManual::Section::Types);
|
||||
return nullptr;
|
||||
}
|
||||
return Class;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Subsystem lifecycle
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -750,6 +745,7 @@ void UWingTypes::Initialize(FSubsystemCollectionBase& Collection)
|
||||
ReserveShortName(UEdGraphSchema_K2::PC_Name);
|
||||
ReserveShortName(UEdGraphSchema_K2::PC_String);
|
||||
ReserveShortName(UEdGraphSchema_K2::PC_Text);
|
||||
ReserveShortName(NAME_NoneMeaningNullptr);
|
||||
|
||||
// Scan priority packages first, then everything else in sorted order.
|
||||
ChooseShortNames(FindPackage(nullptr, TEXT("/Script/CoreUObject")));
|
||||
|
||||
@@ -136,9 +136,10 @@ public:
|
||||
|
||||
struct Requirements
|
||||
{
|
||||
TOptional<bool> BlueprintType;
|
||||
TOptional<bool> Blueprintable;
|
||||
TOptional<bool> AllowContainer;
|
||||
bool BlueprintType = false;
|
||||
bool Blueprintable = false;
|
||||
bool AllowContainer = false;
|
||||
bool AllowNone = false;
|
||||
UClass *IsChildOf = nullptr;
|
||||
FName PinCategory = FName();
|
||||
};
|
||||
@@ -153,16 +154,6 @@ public:
|
||||
// requirements, prints an error and returns false.
|
||||
static bool TextToType(const FString& Text, FEdGraphPinType& OutPinType, const Requirements &Require, WingOut Errors);
|
||||
|
||||
// Parse a type. If it doesn't parse, or if the type doesn't satisfy the
|
||||
// requirements, prints an error and returns false. Requires that the type
|
||||
// is an object type (even if that's not specified in the requirements struct).
|
||||
static UClass* TextToOneObjectType(const FString& Text, const Requirements &Require, WingOut Errors);
|
||||
|
||||
// Parse a type. If it doesn't parse, or if the type doesn't satisfy the
|
||||
// requirements, prints an error and returns false. Requires that the type
|
||||
// is an interface type (even if that's not specified in the requirements struct).
|
||||
static UClass* TextToOneInterfaceType(const FString& Text, const Requirements &Require, WingOut Errors);
|
||||
|
||||
private:
|
||||
// ---------------------------------------------------------------------------
|
||||
// Subsystem lifecycle
|
||||
|
||||
Reference in New Issue
Block a user