Enormouse overhaul
This commit is contained in:
@@ -14,32 +14,313 @@
|
||||
#include "Dom/JsonValue.h"
|
||||
|
||||
|
||||
static bool IsPinTypeProperty(FProperty* Prop)
|
||||
bool FWingProperty::SetObject(UObject *Obj, WingOut Errors) const
|
||||
{
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
return StructProp && StructProp->Struct == FEdGraphPinType::StaticStruct();
|
||||
FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop);
|
||||
if (!OProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("object"), Errors);
|
||||
return false;
|
||||
}
|
||||
if (Obj)
|
||||
{
|
||||
if (!Obj->IsA(OProp->PropertyClass))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' expects %s, but received %s\n"),
|
||||
*WingUtils::FormatName(Prop), *OProp->PropertyClass->GetName(), *Obj->GetClass()->GetName());
|
||||
return false;
|
||||
}
|
||||
if (FClassProperty *CProp = CastField<FClassProperty>(Prop))
|
||||
{
|
||||
UClass *Class = CastChecked<UClass>(Obj);
|
||||
if (!Class->IsChildOf(CProp->MetaClass))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' expects a subclass of %s, but received %s\n"),
|
||||
*WingUtils::FormatName(Prop), *CProp->MetaClass->GetName(), *Class->GetName());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
OProp->SetObjectPropertyValue_InContainer(Container, Obj);
|
||||
return true;
|
||||
}
|
||||
|
||||
FWingProperty::FWingProperty(FProperty* InProp, void* InContainer)
|
||||
: Prop(InProp), Container(InContainer) {}
|
||||
|
||||
FWingProperty::FWingProperty(FProperty* InProp, UObject* InContainer)
|
||||
: Prop(InProp), Container(static_cast<void*>(InContainer)) {}
|
||||
|
||||
FString FWingProperty::GetCategory()
|
||||
bool FWingProperty::SetDouble(double D, WingOut Errors) const
|
||||
{
|
||||
FString Result = Prop->GetMetaData(TEXT("Category"));
|
||||
if (Result.IsEmpty()) Result = "Unclassified";
|
||||
return Result;
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("double"), Errors);
|
||||
return false;
|
||||
}
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
uint8 buffer[16];
|
||||
NProp->SetFloatingPointPropertyValue(buffer, D);
|
||||
if (!FMath::IsFinite(NProp->GetFloatingPointPropertyValue(buffer)))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lf\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), D);
|
||||
return false;
|
||||
}
|
||||
Prop->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 buffer[16];
|
||||
if (FMath::Floor(D) != D)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("double"), Errors);
|
||||
return false;
|
||||
}
|
||||
if (FMath::Abs(D) > (double)((1LL)<<53))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: To store very large numbers in '%s', do not pass them as double. Use string or int.\n"),
|
||||
*WingUtils::FormatName(Prop));
|
||||
return false;
|
||||
}
|
||||
int64 I = (int64)D;
|
||||
NProp->SetIntPropertyValue(buffer, I);
|
||||
if (NProp->GetSignedIntPropertyValue(buffer) != I)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
NProp->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FWingProperty::SetInt64(int64 I, WingOut Errors) const
|
||||
{
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("int"), Errors);
|
||||
return false;
|
||||
}
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
uint8 buffer[16];
|
||||
double D = I;
|
||||
NProp->SetFloatingPointPropertyValue(buffer, D);
|
||||
int64 RT = (int64)NProp->GetFloatingPointPropertyValue(buffer);
|
||||
if (RT != I)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
Prop->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 buffer[16];
|
||||
NProp->SetIntPropertyValue(buffer, I);
|
||||
if (NProp->GetSignedIntPropertyValue(buffer) != I)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
NProp->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FWingProperty::SetBool(bool B, WingOut Errors) const
|
||||
{
|
||||
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Prop))
|
||||
{
|
||||
Prop->SetValue_InContainer(Container, &B);
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("boolean"), Errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FWingProperty::SetText(FString Value, WingOut Errors) const
|
||||
{
|
||||
// Pin types get parsed by UWingTypes.
|
||||
if (IsPinTypeProperty(Prop))
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = true;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = true;
|
||||
if (!UWingTypes::TextToType(Value, PinType, Req, Errors)) return false;
|
||||
Prop->SetValue_InContainer(Container, &PinType);
|
||||
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.
|
||||
UEnum *Enum = nullptr;
|
||||
if (FByteProperty* ByteProp = CastField<FByteProperty>(Prop))
|
||||
Enum = ByteProp->Enum;
|
||||
if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Prop))
|
||||
Enum = EnumProp->GetEnum();
|
||||
if (Enum != nullptr)
|
||||
{
|
||||
int64 EnumValue;
|
||||
if (!WingUtils::StringToEnum(Enum, Value, EnumValue, Errors)) return false;
|
||||
Value = Enum->GetNameStringByValue(EnumValue);
|
||||
}
|
||||
|
||||
// Now Use ImportText
|
||||
const TCHAR* Result = Prop->ImportText_InContainer(*Value, Container, nullptr, PPF_None);
|
||||
if ((!Result) || (*Result != 0))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"),
|
||||
*Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType());
|
||||
return false;
|
||||
}
|
||||
if (!CheckImportTextResult(Value, Errors)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWingProperty::SetJson(const FJsonValue &JsonValue, WingOut Errors) const
|
||||
{
|
||||
if (JsonValue.Type == EJson::String)
|
||||
{
|
||||
return SetText(JsonValue.AsString(), Errors);
|
||||
}
|
||||
|
||||
if (JsonValue.Type == EJson::Number)
|
||||
{
|
||||
return SetDouble(JsonValue.AsNumber(), Errors);
|
||||
}
|
||||
|
||||
if (JsonValue.Type == EJson::Boolean)
|
||||
{
|
||||
return SetBool(JsonValue.AsBool(), Errors);
|
||||
}
|
||||
|
||||
if (JsonValue.Type == EJson::Object)
|
||||
{
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
if (StructProp && (StructProp->Struct == FWingJsonObject::StaticStruct()))
|
||||
{
|
||||
FWingJsonObject Val;
|
||||
Val.Json = JsonValue.AsObject();
|
||||
Prop->SetValue_InContainer(Container, &Val);
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("json object"), Errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JsonValue.Type == EJson::Array)
|
||||
{
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
if (StructProp && (StructProp->Struct == FWingJsonArray::StaticStruct()))
|
||||
{
|
||||
FWingJsonArray Val;
|
||||
Val.Array = JsonValue.AsArray();
|
||||
Prop->SetValue_InContainer(Container, &Val);
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("json array"), Errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintExpectsReceived(TEXT("Unrecognized Json Data"), Errors);
|
||||
return false;
|
||||
}
|
||||
|
||||
TOptional<UObject*> FWingProperty::GetObject(WingOut Errors) const
|
||||
{
|
||||
FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop);
|
||||
if (!OProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("object"), Errors);
|
||||
return {};
|
||||
}
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
return OProp->GetObjectPropertyValue(VP);
|
||||
}
|
||||
|
||||
TOptional<double> FWingProperty::GetDouble(WingOut Errors) const
|
||||
{
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("double"), Errors);
|
||||
return {};
|
||||
}
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
return NProp->GetFloatingPointPropertyValue(VP);
|
||||
}
|
||||
else
|
||||
{
|
||||
int64 I = NProp->GetSignedIntPropertyValue(VP);
|
||||
double D = (double)I;
|
||||
if ((int64)D != I)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' value %lld cannot be represented losslessly as double\n"),
|
||||
*WingUtils::FormatName(Prop), I);
|
||||
return {};
|
||||
}
|
||||
return D;
|
||||
}
|
||||
}
|
||||
|
||||
TOptional<int64> FWingProperty::GetInt64(WingOut Errors) const
|
||||
{
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("int"), Errors);
|
||||
return {};
|
||||
}
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
double D = NProp->GetFloatingPointPropertyValue(VP);
|
||||
if (FMath::Floor(D) != D)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' value %lf is not an integer\n"),
|
||||
*WingUtils::FormatName(Prop), D);
|
||||
return {};
|
||||
}
|
||||
if (FMath::Abs(D) > (double)((1LL)<<53))
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Property '%s' value %lf is too large to convert to int64 losslessly\n"),
|
||||
*WingUtils::FormatName(Prop), D);
|
||||
return {};
|
||||
}
|
||||
return (int64)D;
|
||||
}
|
||||
else
|
||||
{
|
||||
return NProp->GetSignedIntPropertyValue(VP);
|
||||
}
|
||||
}
|
||||
|
||||
TOptional<bool> FWingProperty::GetBool(WingOut Errors) const
|
||||
{
|
||||
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Prop))
|
||||
{
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
return BoolProp->GetPropertyValue(VP);
|
||||
}
|
||||
PrintExpectsReceived(TEXT("boolean"), Errors);
|
||||
return {};
|
||||
}
|
||||
|
||||
FString FWingProperty::GetText() const
|
||||
{
|
||||
if (IsPinTypeProperty(Prop))
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
Prop->GetValue_InContainer(Container, &PinType);
|
||||
return UWingTypes::TypeToText(PinType);
|
||||
FEdGraphPinType *PinType = Prop->ContainerPtrToValuePtr<FEdGraphPinType>(Container);
|
||||
return UWingTypes::TypeToText(*PinType);
|
||||
}
|
||||
FString Result;
|
||||
Prop->ExportTextItem_InContainer(Result, Container, nullptr, nullptr, PPF_None);
|
||||
@@ -56,269 +337,35 @@ FString FWingProperty::GetTruncatedText(int32 MaxLen) const
|
||||
return Result;
|
||||
}
|
||||
|
||||
void FWingProperty::PrintExpectsReceived(const TCHAR *Type)
|
||||
|
||||
FString FWingProperty::GetCategory() const
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: '%s' received a %s, but expects %s\n"),
|
||||
*WingUtils::FormatName(Prop), Type, *Prop->GetCPPType());
|
||||
FString Result = Prop->GetMetaData(TEXT("Category"));
|
||||
if (Result.IsEmpty()) Result = "Unclassified";
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
bool FWingProperty::CheckImportTextResult(const FString &Value)
|
||||
void FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags, TArray<FWingProperty> &Props)
|
||||
{
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
if (FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop))
|
||||
{
|
||||
UObject *Obj = OProp->GetObjectPropertyValue(VP);
|
||||
if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"),
|
||||
*Value, *WingUtils::FormatName(Prop));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWingProperty::SetText(FString Value)
|
||||
{
|
||||
// Pin types get parsed by UWingTypes.
|
||||
if (IsPinTypeProperty(Prop))
|
||||
{
|
||||
FEdGraphPinType PinType;
|
||||
UWingTypes::Requirements Req;
|
||||
Req.BlueprintType = true;
|
||||
Req.Blueprintable = false;
|
||||
Req.AllowContainer = true;
|
||||
if (!UWingTypes::TextToType(Value, PinType, Req)) return false;
|
||||
Prop->SetValue_InContainer(Container, &PinType);
|
||||
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.
|
||||
UEnum *Enum = nullptr;
|
||||
if (FByteProperty* ByteProp = CastField<FByteProperty>(Prop))
|
||||
Enum = ByteProp->Enum;
|
||||
if (FEnumProperty* EnumProp = CastField<FEnumProperty>(Prop))
|
||||
Enum = EnumProp->GetEnum();
|
||||
if (Enum != nullptr)
|
||||
{
|
||||
int64 EnumValue;
|
||||
if (!WingUtils::StringToEnum(Enum, Value, EnumValue)) return false;
|
||||
Value = Enum->GetNameStringByValue(EnumValue);
|
||||
}
|
||||
|
||||
// Now Use ImportText
|
||||
const TCHAR* Result = Prop->ImportText_InContainer(*Value, Container, nullptr, PPF_None);
|
||||
if ((!Result) || (*Result != 0))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s' (type: %s)\n"),
|
||||
*Value, *WingUtils::FormatName(Prop), *Prop->GetCPPType());
|
||||
return false;
|
||||
}
|
||||
if (!CheckImportTextResult(Value)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FWingProperty::SetDouble(double D)
|
||||
{
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("double"));
|
||||
return false;
|
||||
}
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
uint8 buffer[16];
|
||||
NProp->SetFloatingPointPropertyValue(buffer, D);
|
||||
if (!FMath::IsFinite(NProp->GetFloatingPointPropertyValue(buffer)))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lf\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), D);
|
||||
return false;
|
||||
}
|
||||
Prop->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 buffer[16];
|
||||
if (FMath::Floor(D) != D)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("double"));
|
||||
return false;
|
||||
}
|
||||
if (FMath::Abs(D) > (double)((1LL)<<53))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: To store very large numbers in '%s', do not pass them as double. Use string or int.\n"),
|
||||
*WingUtils::FormatName(Prop));
|
||||
return false;
|
||||
}
|
||||
int64 I = (int64)D;
|
||||
NProp->SetIntPropertyValue(buffer, I);
|
||||
if (NProp->GetSignedIntPropertyValue(buffer) != I)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
NProp->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FWingProperty::SetInt64(int64 I)
|
||||
{
|
||||
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||
if (!NProp)
|
||||
{
|
||||
PrintExpectsReceived(TEXT("int"));
|
||||
return false;
|
||||
}
|
||||
if (NProp->IsFloatingPoint())
|
||||
{
|
||||
uint8 buffer[16];
|
||||
double D = I;
|
||||
NProp->SetFloatingPointPropertyValue(buffer, D);
|
||||
int64 RT = (int64)NProp->GetFloatingPointPropertyValue(buffer);
|
||||
if (RT != I)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
Prop->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8 buffer[16];
|
||||
NProp->SetIntPropertyValue(buffer, I);
|
||||
if (NProp->GetSignedIntPropertyValue(buffer) != I)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lld\n"),
|
||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
||||
return false;
|
||||
}
|
||||
NProp->SetValue_InContainer(Container, buffer);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool FWingProperty::SetBool(bool B)
|
||||
{
|
||||
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Prop))
|
||||
{
|
||||
Prop->SetValue_InContainer(Container, &B);
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("boolean"));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FWingProperty::SetJson(const TSharedPtr<FJsonValue> &JsonValue)
|
||||
{
|
||||
if (JsonValue->Type == EJson::String)
|
||||
{
|
||||
return SetText(JsonValue->AsString());
|
||||
}
|
||||
|
||||
if (JsonValue->Type == EJson::Number)
|
||||
{
|
||||
return SetDouble(JsonValue->AsNumber());
|
||||
}
|
||||
|
||||
if (JsonValue->Type == EJson::Boolean)
|
||||
{
|
||||
return SetBool(JsonValue->AsBool());
|
||||
}
|
||||
|
||||
if (JsonValue->Type == EJson::Object)
|
||||
{
|
||||
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
if (StructProp && (StructProp->Struct == FWingJsonObject::StaticStruct()))
|
||||
{
|
||||
static_cast<FWingJsonObject*>(ValuePtr)->Json = JsonValue->AsObject();
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("json object"));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JsonValue->Type == EJson::Array)
|
||||
{
|
||||
void* ValuePtr = Prop->ContainerPtrToValuePtr<void>(Container);
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
if (StructProp && (StructProp->Struct == FWingJsonArray::StaticStruct()))
|
||||
{
|
||||
static_cast<FWingJsonArray*>(ValuePtr)->Array = JsonValue->AsArray();
|
||||
return true;
|
||||
}
|
||||
PrintExpectsReceived(TEXT("json array"));
|
||||
return false;
|
||||
}
|
||||
|
||||
PrintExpectsReceived(TEXT("Unrecognized Json Data"));
|
||||
return false;
|
||||
}
|
||||
|
||||
void FWingProperty::Collect(UStruct* StructType, void* Container, TArray<FWingProperty> &Props, EPropertyFlags Flags)
|
||||
{
|
||||
TMap<FString, TArray<FWingProperty>> Grouped;
|
||||
|
||||
for (TFieldIterator<FProperty> It(StructType); It; ++It)
|
||||
TArray<FWingProperty> Result;
|
||||
for (TFieldIterator<FProperty> It(Obj.UStructPtr); It; ++It)
|
||||
{
|
||||
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
||||
FString SortCat = *It->GetMetaData(TEXT("Category"));
|
||||
Grouped.FindOrAdd(SortCat).Add(FWingProperty(*It, Container));
|
||||
}
|
||||
TArray<FString> Categories;
|
||||
|
||||
Grouped.GetKeys(Categories);
|
||||
Categories.Sort([](const FString& A, const FString& B) {
|
||||
if (A.IsEmpty()) return false;
|
||||
if (B.IsEmpty()) return true;
|
||||
return A < B;
|
||||
});
|
||||
|
||||
for (const FString& Category : Categories)
|
||||
{
|
||||
Props.Append(Grouped[Category]);
|
||||
Result.Add(FWingProperty(*It, Obj.StructPtr));
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FWingProperty> FWingProperty::GetAll(UObject* Object, EPropertyFlags Flags)
|
||||
{
|
||||
return GetAll(Object->GetClass(), Object, Flags);
|
||||
}
|
||||
|
||||
TArray<FWingProperty> FWingProperty::GetAll(UStruct* StructType, void* Container, EPropertyFlags Flags)
|
||||
TArray<FWingProperty> FWingProperty::GetAll(FWingStructAndUStruct Obj, EPropertyFlags Flags)
|
||||
{
|
||||
TArray<FWingProperty> Result;
|
||||
Collect(StructType, Container, Result, Flags);
|
||||
GetAll(Obj, Flags, Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
TArray<FWingProperty> FWingProperty::GetNamed(UStruct* StructType, void* Container, const TArray<FName> &Names)
|
||||
{
|
||||
TArray<FWingProperty> Result;
|
||||
for (FName Name : Names)
|
||||
{
|
||||
FProperty *Prop = StructType->FindPropertyByName(Name);
|
||||
if (Prop != nullptr) Result.Emplace(Prop, Container);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
||||
TArray<FName> FWingProperty::GetNames(UStruct *StructType, EPropertyFlags Flags)
|
||||
TArray<FName> FWingProperty::GetNames(UStruct *US, EPropertyFlags Flags)
|
||||
{
|
||||
TArray<FName> Result;
|
||||
for (TFieldIterator<FProperty> It(StructType); It; ++It)
|
||||
for (TFieldIterator<FProperty> It(US); It; ++It)
|
||||
{
|
||||
if (Flags != 0 && !It->HasAnyPropertyFlags(Flags)) continue;
|
||||
Result.Add(It->GetFName());
|
||||
@@ -326,29 +373,23 @@ TArray<FName> FWingProperty::GetNames(UStruct *StructType, EPropertyFlags Flags)
|
||||
return Result;
|
||||
}
|
||||
|
||||
void FWingProperty::Remove(TArray<FWingProperty>& Props, const FString& Name)
|
||||
void FWingProperty::Remove(TArray<FWingProperty>& Props, FName Name)
|
||||
{
|
||||
Props.RemoveAll([&](const FWingProperty& P) { return P.Prop->GetName() == Name; });
|
||||
}
|
||||
|
||||
void FWingProperty::Move(TArray<FWingProperty> &Out, TArray<FWingProperty> &In, const FString &Name)
|
||||
void FWingProperty::Move(TArray<FWingProperty> &Out, TArray<FWingProperty> &In, FName Name)
|
||||
{
|
||||
int Dst = 0;
|
||||
for (int i = 0; i < In.Num(); i++)
|
||||
{
|
||||
if (In[i]->GetName() == Name)
|
||||
{
|
||||
Out.Add(In[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
In[Dst++] = In[i];
|
||||
}
|
||||
if (In[i]->GetFName() == Name) Out.Add(In[i]);
|
||||
else In[Dst++] = In[i];
|
||||
}
|
||||
In.SetNum(Dst);
|
||||
}
|
||||
|
||||
TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFlags Flags, bool Mutable)
|
||||
TArray<FWingProperty> FWingProperty::GetDetails(UObject* Obj, EPropertyFlags Flags, bool Mutable)
|
||||
{
|
||||
if (!Obj) return {};
|
||||
|
||||
@@ -358,7 +399,7 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
||||
{
|
||||
if (BP->GeneratedClass == nullptr)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName());
|
||||
WingOut::Stdout.Printf(TEXT("ERROR: Blueprint '%s' has no GeneratedClass\n"), *Obj->GetName());
|
||||
return {};
|
||||
}
|
||||
Obj = BP->GeneratedClass->GetDefaultObject();
|
||||
@@ -370,13 +411,12 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
||||
Obj = Mutable ? Ref->GetMutableTemplate() : Ref->GetImmutableTemplate();
|
||||
if (!Obj)
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString());
|
||||
WingOut::Stdout.Printf(TEXT("ERROR: Component '%s' has no template\n"), *Ref->VariableName.ToString());
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
TArray<FWingProperty> Result;
|
||||
Collect(Obj->GetClass(), Obj, Result, Flags);
|
||||
TArray<FWingProperty> Result = GetAll(Obj, Flags);
|
||||
|
||||
// If it's a Material Graph node, also collect properties from
|
||||
// the associated material expression.
|
||||
@@ -385,7 +425,7 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
||||
{
|
||||
if (UMaterialExpression* Expr = MatNode->MaterialExpression)
|
||||
{
|
||||
Collect(Expr->GetClass(), Expr, Result, Flags);
|
||||
GetAll(Expr, Flags, Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -396,7 +436,7 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
||||
FWingProperty::Remove(Result, TEXT("Slot"));
|
||||
if (UPanelSlot* Slot = Widget->Slot)
|
||||
{
|
||||
Collect(Slot->GetClass(), Slot, Result, Flags);
|
||||
GetAll(Slot, Flags, Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,50 +444,29 @@ TArray<FWingProperty> FWingProperty::GetDetailsGeneral(UObject* Obj, EPropertyFl
|
||||
}
|
||||
|
||||
|
||||
TArray<FWingProperty> FWingProperty::FindAllSubstring(const TArray<FWingProperty>& Props, const FString& Substring)
|
||||
{
|
||||
if (Substring.IsEmpty()) return Props;
|
||||
TArray<FWingProperty> Result;
|
||||
for (const FWingProperty& P : Props)
|
||||
{
|
||||
if (WingUtils::FormatName(P.Prop).Contains(Substring, ESearchCase::IgnoreCase))
|
||||
Result.Add(P);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
bool FWingProperty::PopulateFromJson(FWingProperty& P, const FJsonObject* Json, bool AllOptional)
|
||||
{
|
||||
FString JsonKey = WingUtils::FormatName(P.Prop);
|
||||
TSharedPtr<FJsonValue> Value = Json->TryGetField(JsonKey);
|
||||
|
||||
if (Value == nullptr)
|
||||
{
|
||||
bool Optional = AllOptional || P.Prop->HasMetaData(TEXT("Optional"));
|
||||
if (Optional) return true;
|
||||
UWingServer::Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey);
|
||||
return false;
|
||||
}
|
||||
|
||||
return P.SetJson(Value);
|
||||
}
|
||||
|
||||
bool FWingProperty::PopulateFromJson(
|
||||
TArray<FWingProperty>& Props, const FJsonObject* Json, bool AllOptional)
|
||||
bool FWingProperty::PopulateFromJson(TArray<FWingProperty>& Props, const FJsonValue& Json, bool AllOptional, WingOut Errors)
|
||||
{
|
||||
bool Ok = true;
|
||||
|
||||
// Build a set of known property names for the unknown-field check.
|
||||
TSet<FString> KnownKeys;
|
||||
for (const FWingProperty& P : Props)
|
||||
KnownKeys.Add(WingUtils::FormatName(P.Prop));
|
||||
|
||||
// Check for unknown fields in the JSON
|
||||
for (const auto& KV : Json->Values)
|
||||
// Make sure they passed in a JSON object.
|
||||
TSharedPtr<FJsonObject> Obj = Json.AsObject();
|
||||
if (Obj == nullptr)
|
||||
{
|
||||
if (!KnownKeys.Contains(KV.Key))
|
||||
Errors.Printf(TEXT("property data should be stored in a json object\n"));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Build a set of known property names for the unknown-field check.
|
||||
TSet<FName> KnownKeys;
|
||||
for (const FWingProperty& P : Props) KnownKeys.Add(P->GetFName());
|
||||
|
||||
// Check for unknown fields in the JSON
|
||||
for (const auto& KV : Obj->Values)
|
||||
{
|
||||
FName Name = WingUtils::CheckInternalizeID(KV.Key, Errors);
|
||||
if (!KnownKeys.Contains(Name))
|
||||
{
|
||||
UWingServer::Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key);
|
||||
Errors.Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key);
|
||||
Ok = false;
|
||||
}
|
||||
}
|
||||
@@ -455,23 +474,51 @@ bool FWingProperty::PopulateFromJson(
|
||||
// Populate each property from JSON
|
||||
for (FWingProperty& P : Props)
|
||||
{
|
||||
if (!PopulateFromJson(P, Json, AllOptional)) Ok = false;
|
||||
FString JsonKey = WingUtils::FormatName(P.Prop);
|
||||
TSharedPtr<FJsonValue> Value = Obj->TryGetField(JsonKey);
|
||||
if (!Value)
|
||||
{
|
||||
bool Optional = AllOptional || P.Prop->HasMetaData(TEXT("Optional"));
|
||||
if (!Optional)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey);
|
||||
Ok = false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (!P.SetJson(*Value, Errors)) Ok = false;
|
||||
}
|
||||
return Ok;
|
||||
}
|
||||
|
||||
bool FWingProperty::PopulateFromJson(UStruct* StructType, void* Container, const FJsonObject* Object)
|
||||
|
||||
bool FWingProperty::IsPinTypeProperty(FProperty* Prop)
|
||||
{
|
||||
TArray<FWingProperty> Props = FWingProperty::GetAll(StructType, Container, (EPropertyFlags)0);
|
||||
return PopulateFromJson(Props, Object);
|
||||
FStructProperty* StructProp = CastField<FStructProperty>(Prop);
|
||||
return StructProp && StructProp->Struct == FEdGraphPinType::StaticStruct();
|
||||
}
|
||||
|
||||
bool FWingProperty::PopulateFromJson(UStruct* StructType, void* Container, const TSharedPtr<FJsonValue>& Object)
|
||||
|
||||
|
||||
void FWingProperty::PrintExpectsReceived(const TCHAR *Type, WingOut Errors) const
|
||||
{
|
||||
if (!Object.IsValid() || (Object->Type != EJson::Object))
|
||||
{
|
||||
UWingServer::Print(TEXT("ERROR: Expected a JSON object\n"));
|
||||
return false;
|
||||
}
|
||||
return PopulateFromJson(StructType, Container, Object->AsObject().Get());
|
||||
Errors.Printf(TEXT("ERROR: '%s' received a %s, but expects %s\n"),
|
||||
*WingUtils::FormatName(Prop), Type, *Prop->GetCPPType());
|
||||
}
|
||||
|
||||
|
||||
bool FWingProperty::CheckImportTextResult(const FString &Value, WingOut Errors) const
|
||||
{
|
||||
if (FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop))
|
||||
{
|
||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
||||
UObject *Obj = OProp->GetObjectPropertyValue(VP);
|
||||
if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0)
|
||||
{
|
||||
Errors.Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"),
|
||||
*Value, *WingUtils::FormatName(Prop));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user