Migrating back to WingProperty. Sigh.
This commit is contained in:
@@ -4,8 +4,9 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFetcher.h"
|
#include "WingFetcher.h"
|
||||||
#include "WingPropHandle.h"
|
#include "WingProperty.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
|
#include "WingTypes.h"
|
||||||
#include "Details_Dump.generated.h"
|
#include "Details_Dump.generated.h"
|
||||||
|
|
||||||
UCLASS()
|
UCLASS()
|
||||||
@@ -23,7 +24,7 @@ public:
|
|||||||
virtual void Register() override
|
virtual void Register() override
|
||||||
{
|
{
|
||||||
UWingServer::AddHandler(this,
|
UWingServer::AddHandler(this,
|
||||||
TEXT("Test handler: dump properties using IPropertyHandle."));
|
TEXT("Test handler: dump properties using FWingProperty."));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void Handle() override
|
virtual void Handle() override
|
||||||
@@ -32,28 +33,31 @@ public:
|
|||||||
UObject* Target = F.Walk(Object).Cast<UObject>();
|
UObject* Target = F.Walk(Object).Cast<UObject>();
|
||||||
if (!Target) return;
|
if (!Target) return;
|
||||||
|
|
||||||
WingPropHandle Props;
|
TArray<FWingProperty> Props = FWingProperty::GetDetailsImmutable(Target, CPF_Edit);
|
||||||
WingPropHandle::Handles Handles = Props.GetDetails(Target, false);
|
Props = FWingProperty::FindAllSubstring(Props, Query);
|
||||||
|
|
||||||
// Group by category, preserving within-category order.
|
// Group by category, preserving within-category order.
|
||||||
FString QueryLower = Query.ToLower();
|
TSortedMap<FString, TArray<FWingProperty>> Categories;
|
||||||
TSortedMap<FString, TArray<TSharedPtr<IPropertyHandle>>> Categories;
|
for (const FWingProperty& P : Props)
|
||||||
for (const TSharedPtr<IPropertyHandle>& H : Handles)
|
|
||||||
{
|
{
|
||||||
FString Name = WingUtils::FormatName(H);
|
FString Category = P.Prop->GetMetaData(TEXT("Category"));
|
||||||
if (!QueryLower.IsEmpty() && !Name.ToLower().Contains(QueryLower))
|
|
||||||
continue;
|
|
||||||
FString Category = H->GetDefaultCategoryName().ToString();
|
|
||||||
if (Category.IsEmpty()) Category = TEXT("Unclassified");
|
if (Category.IsEmpty()) Category = TEXT("Unclassified");
|
||||||
Categories.FindOrAdd(Category).Add(H);
|
Categories.FindOrAdd(Category).Add(P);
|
||||||
}
|
}
|
||||||
|
|
||||||
FStringBuilderBase& Out = UWingServer::GetPrintBuffer();
|
FStringBuilderBase& Out = UWingServer::GetPrintBuffer();
|
||||||
for (const auto& Pair : Categories)
|
for (const auto& Pair : Categories)
|
||||||
{
|
{
|
||||||
Out.Appendf(TEXT("\n%s:\n"), *Pair.Key);
|
Out.Appendf(TEXT("\n%s:\n"), *Pair.Key);
|
||||||
for (const TSharedPtr<IPropertyHandle>& H : Pair.Value)
|
for (const FWingProperty& P : Pair.Value)
|
||||||
WingPropHandle::Print(*H, Out);
|
{
|
||||||
|
bool bEditable = !P->HasAnyPropertyFlags(CPF_EditConst);
|
||||||
|
Out.Appendf(TEXT(" %s %s %s = %s\n"),
|
||||||
|
bEditable ? TEXT("editable") : TEXT("readonly"),
|
||||||
|
*UWingTypes::TypeToText(P.Prop),
|
||||||
|
*WingUtils::FormatName(P.Prop),
|
||||||
|
*P.GetTruncatedText(100));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFetcher.h"
|
#include "WingFetcher.h"
|
||||||
#include "WingPropHandle.h"
|
#include "WingProperty.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
#include "Details_Get.generated.h"
|
#include "Details_Get.generated.h"
|
||||||
|
|
||||||
@@ -32,11 +32,10 @@ public:
|
|||||||
UObject* Obj = F.Walk(Object).Cast<UObject>();
|
UObject* Obj = F.Walk(Object).Cast<UObject>();
|
||||||
if (!Obj) return;
|
if (!Obj) return;
|
||||||
|
|
||||||
WingPropHandle Props;
|
TArray<FWingProperty> Props = FWingProperty::GetDetailsImmutable(Obj, CPF_Edit);
|
||||||
WingPropHandle::Handles Handles = Props.GetDetails(Obj, false);
|
FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"));
|
||||||
TSharedPtr<IPropertyHandle>* P = WingUtils::FindOneWithExternalID(Property, Handles, TEXT("Property"));
|
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
|
|
||||||
UWingServer::Print(WingPropHandle::GetText(**P));
|
UWingServer::Print(P->GetText());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFetcher.h"
|
#include "WingFetcher.h"
|
||||||
#include "WingPropHandle.h"
|
#include "WingProperty.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
#include "Details_Set.generated.h"
|
#include "Details_Set.generated.h"
|
||||||
|
|
||||||
@@ -35,12 +35,11 @@ public:
|
|||||||
UObject* Obj = F.Walk(Object).Cast<UObject>();
|
UObject* Obj = F.Walk(Object).Cast<UObject>();
|
||||||
if (!Obj) return;
|
if (!Obj) return;
|
||||||
|
|
||||||
WingPropHandle Props;
|
TArray<FWingProperty> Props = FWingProperty::GetDetailsMutable(Obj, CPF_Edit);
|
||||||
WingPropHandle::Handles Handles = Props.GetDetails(Obj, true);
|
FWingProperty* P = WingUtils::FindOneWithExternalID(Property, Props, TEXT("Property"));
|
||||||
TSharedPtr<IPropertyHandle>* P = WingUtils::FindOneWithExternalID(Property, Handles, TEXT("Property"));
|
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
|
|
||||||
if (WingPropHandle::SetText(**P, Value))
|
if (P->SetText(Value))
|
||||||
UWingServer::Print(TEXT("OK\n"));
|
UWingServer::Print(TEXT("OK\n"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
#include "WingServer.h"
|
#include "WingServer.h"
|
||||||
#include "WingHandler.h"
|
#include "WingHandler.h"
|
||||||
#include "WingFetcher.h"
|
#include "WingFetcher.h"
|
||||||
#include "WingPropHandle.h"
|
#include "WingProperty.h"
|
||||||
#include "WingUtils.h"
|
#include "WingUtils.h"
|
||||||
#include "Details_SetMany.generated.h"
|
#include "Details_SetMany.generated.h"
|
||||||
|
|
||||||
@@ -38,13 +38,12 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
WingPropHandle Props;
|
TArray<FWingProperty> Props = FWingProperty::GetDetailsMutable(Obj, CPF_Edit);
|
||||||
WingPropHandle::Handles Handles = Props.GetDetails(Obj, true);
|
|
||||||
|
|
||||||
// Validation pass — resolve all properties before modifying anything.
|
// Validation pass — resolve all properties before modifying anything.
|
||||||
for (const auto& Pair : Properties.Json->Values)
|
for (const auto& Pair : Properties.Json->Values)
|
||||||
{
|
{
|
||||||
TSharedPtr<IPropertyHandle>* P = WingUtils::FindOneWithExternalID(Pair.Key, Handles, TEXT("Property"));
|
FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property"));
|
||||||
if (!P) return;
|
if (!P) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,8 +51,8 @@ public:
|
|||||||
int SuccessCount = 0;
|
int SuccessCount = 0;
|
||||||
for (const auto& Pair : Properties.Json->Values)
|
for (const auto& Pair : Properties.Json->Values)
|
||||||
{
|
{
|
||||||
TSharedPtr<IPropertyHandle>* P = WingUtils::FindOneWithExternalID(Pair.Key, Handles, TEXT("Property"));
|
FWingProperty* P = WingUtils::FindOneWithExternalID(Pair.Key, Props, TEXT("Property"));
|
||||||
if (WingPropHandle::SetJson(**P, Pair.Value)) SuccessCount++;
|
if (P->SetJson(Pair.Value)) SuccessCount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
UWingServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
|
UWingServer::Printf(TEXT("Set %d/%d properties.\n"), SuccessCount, Properties.Json->Values.Num());
|
||||||
|
|||||||
@@ -62,15 +62,25 @@ void FWingProperty::PrintExpectsReceived(const TCHAR *Type)
|
|||||||
*WingUtils::FormatName(Prop), Type, *Prop->GetCPPType());
|
*WingUtils::FormatName(Prop), Type, *Prop->GetCPPType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool FWingProperty::CheckImportTextResult(const FString &Value)
|
||||||
|
{
|
||||||
|
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)
|
bool FWingProperty::SetText(FString Value)
|
||||||
{
|
{
|
||||||
// Mostly, this is implemented by Unreal's ImportText_Incontainer.
|
|
||||||
// We override it for a few very specific types.
|
|
||||||
|
|
||||||
// Notify that we're modifying the containing object.
|
|
||||||
if (Prop->GetOwnerClass())
|
|
||||||
UWingServer::AddTouchedObject(static_cast<UObject*>(Container));
|
|
||||||
|
|
||||||
// Pin types get parsed by UWingTypes.
|
// Pin types get parsed by UWingTypes.
|
||||||
if (IsPinTypeProperty(Prop))
|
if (IsPinTypeProperty(Prop))
|
||||||
{
|
{
|
||||||
@@ -111,20 +121,101 @@ bool FWingProperty::SetText(FString Value)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FWingProperty::CheckImportTextResult(const FString &Value)
|
bool FWingProperty::SetDouble(double D)
|
||||||
{
|
{
|
||||||
uint8 *VP = Prop->ContainerPtrToValuePtr<uint8>(Container);
|
FNumericProperty *NProp = CastField<FNumericProperty>(Prop);
|
||||||
if (FObjectPropertyBase *OProp = CastField<FObjectPropertyBase>(Prop))
|
if (!NProp)
|
||||||
{
|
{
|
||||||
UObject *Obj = OProp->GetObjectPropertyValue(VP);
|
PrintExpectsReceived(TEXT("double"));
|
||||||
if (Obj == nullptr && Value.TrimStartAndEnd().Compare(TEXT("None"), ESearchCase::IgnoreCase) != 0)
|
return false;
|
||||||
|
}
|
||||||
|
if (NProp->IsFloatingPoint())
|
||||||
|
{
|
||||||
|
uint8 buffer[16];
|
||||||
|
NProp->SetFloatingPointPropertyValue(buffer, D);
|
||||||
|
if (!FMath::IsFinite(NProp->GetFloatingPointPropertyValue(buffer)))
|
||||||
{
|
{
|
||||||
UWingServer::Printf(TEXT("ERROR: Failed to parse '%s' for property '%s'\n"),
|
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s cannot hold %lf\n"),
|
||||||
*Value, *WingUtils::FormatName(Prop));
|
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), D);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
Prop->SetValue_InContainer(Container, buffer);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -137,65 +228,12 @@ bool FWingProperty::SetJson(const TSharedPtr<FJsonValue> &JsonValue)
|
|||||||
|
|
||||||
if (JsonValue->Type == EJson::Number)
|
if (JsonValue->Type == EJson::Number)
|
||||||
{
|
{
|
||||||
// If the property is float or double, just store the value.
|
return SetDouble(JsonValue->AsNumber());
|
||||||
double D = JsonValue->AsNumber();
|
|
||||||
if (FFloatProperty* FloatProp = CastField<FFloatProperty>(Prop))
|
|
||||||
{
|
|
||||||
float Value = (float)D;
|
|
||||||
Prop->SetValue_InContainer(Container, &Value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
else if (FDoubleProperty* DoubleProp = CastField<FDoubleProperty>(Prop))
|
|
||||||
{
|
|
||||||
double Value = (double)D;
|
|
||||||
Prop->SetValue_InContainer(Container, &Value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// At this point, we've ruled out it being a float or double property.
|
|
||||||
// All that's left is integers. Verify that the number can be converted
|
|
||||||
// losslessly to an int64, and then do so.
|
|
||||||
if (FMath::Floor(D) != D)
|
|
||||||
{
|
|
||||||
PrintExpectsReceived(TEXT("float"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (FMath::Abs(D) > (double)((1LL)<<53))
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: To store very large numbers in '%s', please pass a json string\n"),
|
|
||||||
*WingUtils::FormatName(Prop));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
int64 I = (int64)D;
|
|
||||||
|
|
||||||
// Now store the integer. Make sure it fits first.
|
|
||||||
if (FNumericProperty *NumericProperty = CastField<FNumericProperty>(Prop))
|
|
||||||
{
|
|
||||||
uint8 buffer[16];
|
|
||||||
NumericProperty->SetIntPropertyValue(buffer, I);
|
|
||||||
if (NumericProperty->GetSignedIntPropertyValue(buffer) != I)
|
|
||||||
{
|
|
||||||
UWingServer::Printf(TEXT("ERROR: Property '%s' of type %s is too small to hold %lld\n"),
|
|
||||||
*WingUtils::FormatName(Prop), *Prop->GetCPPType(), I);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
NumericProperty->SetValue_InContainer(Container, buffer);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
PrintExpectsReceived(TEXT("integer"));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JsonValue->Type == EJson::Boolean)
|
if (JsonValue->Type == EJson::Boolean)
|
||||||
{
|
{
|
||||||
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(Prop))
|
return SetBool(JsonValue->AsBool());
|
||||||
{
|
|
||||||
bool Value = JsonValue->AsBool();
|
|
||||||
Prop->SetValue_InContainer(Container, &Value);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
PrintExpectsReceived(TEXT("boolean"));
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (JsonValue->Type == EJson::Object)
|
if (JsonValue->Type == EJson::Object)
|
||||||
|
|||||||
@@ -14,8 +14,14 @@ struct FWingProperty
|
|||||||
FWingProperty(FProperty* InProp, void* InContainer);
|
FWingProperty(FProperty* InProp, void* InContainer);
|
||||||
FWingProperty(FProperty* InProp, UObject* InContainer);
|
FWingProperty(FProperty* InProp, UObject* InContainer);
|
||||||
|
|
||||||
|
bool SetDouble(double D);
|
||||||
|
bool SetInt64(int64 I);
|
||||||
|
bool SetBool(bool B);
|
||||||
|
|
||||||
FString GetText() const;
|
FString GetText() const;
|
||||||
bool SetText(FString Value);
|
bool SetText(FString Value);
|
||||||
|
|
||||||
|
// Store data from a json object.
|
||||||
bool SetJson(const TSharedPtr<FJsonValue> &Value);
|
bool SetJson(const TSharedPtr<FJsonValue> &Value);
|
||||||
|
|
||||||
// Get the Category metadata.
|
// Get the Category metadata.
|
||||||
|
|||||||
Reference in New Issue
Block a user