133 lines
3.9 KiB
C++
133 lines
3.9 KiB
C++
#include "WingJson.h"
|
|
#include "WingTypes.h"
|
|
#include "WingServer.h"
|
|
#include "UObject/UnrealType.h"
|
|
#include "UObject/EnumProperty.h"
|
|
#include "Dom/JsonValue.h"
|
|
|
|
|
|
bool WingJson::PopulateFromJson(FWingProperty& P, const FJsonObject* Json, bool AllOptional)
|
|
{
|
|
FString JsonKey = P.Prop->GetName();
|
|
bool bOptional = AllOptional || P.Prop->HasMetaData(TEXT("Optional"));
|
|
|
|
if (!Json->HasField(JsonKey))
|
|
{
|
|
if (!bOptional)
|
|
{
|
|
UWingServer::Printf(TEXT("ERROR: Missing required parameter '%s'\n"), *JsonKey);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void* ValuePtr = P.Prop->ContainerPtrToValuePtr<void>(P.Container);
|
|
|
|
// Special handling for FWingJsonObject and FWingJsonArray
|
|
if (FStructProperty* StructProp = CastField<FStructProperty>(P.Prop))
|
|
{
|
|
if (StructProp->Struct == FWingJsonObject::StaticStruct())
|
|
{
|
|
if (!Json->HasTypedField<EJson::Object>(JsonKey))
|
|
{
|
|
UWingServer::Printf(TEXT("ERROR: '%s' must be an object\n"), *JsonKey);
|
|
return false;
|
|
}
|
|
static_cast<FWingJsonObject*>(ValuePtr)->Json = Json->GetObjectField(JsonKey);
|
|
return true;
|
|
}
|
|
|
|
if (StructProp->Struct == FWingJsonArray::StaticStruct())
|
|
{
|
|
if (!Json->HasTypedField<EJson::Array>(JsonKey))
|
|
{
|
|
UWingServer::Printf(TEXT("ERROR: '%s' must be an array\n"), *JsonKey);
|
|
return false;
|
|
}
|
|
static_cast<FWingJsonArray*>(ValuePtr)->Array = Json->GetArrayField(JsonKey);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Handle based on JSON value type.
|
|
TSharedPtr<FJsonValue> JsonValue = Json->TryGetField(JsonKey);
|
|
|
|
if (JsonValue->Type == EJson::Number)
|
|
{
|
|
double D = JsonValue->AsNumber();
|
|
if (FIntProperty* IntProp = CastField<FIntProperty>(P.Prop))
|
|
{ IntProp->SetPropertyValue(ValuePtr, (int32)D); return true; }
|
|
if (FFloatProperty* FloatProp = CastField<FFloatProperty>(P.Prop))
|
|
{ FloatProp->SetPropertyValue(ValuePtr, (float)D); return true; }
|
|
if (FDoubleProperty* DoubleProp = CastField<FDoubleProperty>(P.Prop))
|
|
{ DoubleProp->SetPropertyValue(ValuePtr, D); return true; }
|
|
if (FByteProperty* ByteProp = CastField<FByteProperty>(P.Prop))
|
|
{ ByteProp->SetPropertyValue(ValuePtr, (uint8)D); return true; }
|
|
UWingServer::Printf(TEXT("ERROR: '%s' received a number but expects %s\n"), *JsonKey, *P.Prop->GetCPPType());
|
|
return false;
|
|
}
|
|
|
|
if (JsonValue->Type == EJson::Boolean)
|
|
{
|
|
if (FBoolProperty* BoolProp = CastField<FBoolProperty>(P.Prop))
|
|
{ BoolProp->SetPropertyValue(ValuePtr, JsonValue->AsBool()); return true; }
|
|
UWingServer::Printf(TEXT("ERROR: '%s' received a boolean but expects %s\n"), *JsonKey, *P.Prop->GetCPPType());
|
|
return false;
|
|
}
|
|
|
|
if (JsonValue->Type == EJson::String)
|
|
{
|
|
return P.SetText(JsonValue->AsString());
|
|
}
|
|
|
|
UWingServer::Printf(TEXT("ERROR: '%s' must be a string, number, or boolean\n"), *JsonKey);
|
|
return false;
|
|
}
|
|
|
|
bool WingJson::PopulateFromJson(
|
|
TArray<FWingProperty>& Props, const FJsonObject* Json, bool AllOptional)
|
|
{
|
|
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(P.Prop->GetName());
|
|
|
|
// Check for unknown fields in the JSON
|
|
for (const auto& KV : Json->Values)
|
|
{
|
|
if (!KnownKeys.Contains(KV.Key))
|
|
{
|
|
UWingServer::Printf(TEXT("ERROR: Unknown parameter '%s'\n"), *KV.Key);
|
|
Ok = false;
|
|
}
|
|
}
|
|
|
|
// Populate each property from JSON
|
|
for (FWingProperty& P : Props)
|
|
{
|
|
if (!PopulateFromJson(P, Json, AllOptional)) Ok = false;
|
|
}
|
|
return Ok;
|
|
}
|
|
|
|
bool WingJson::PopulateFromJson(
|
|
UStruct* StructType, void* Container, const FJsonObject* Json)
|
|
{
|
|
TArray<FWingProperty> Props = FWingProperty::GetAll(StructType, Container, (EPropertyFlags)0);
|
|
return PopulateFromJson(Props, Json);
|
|
}
|
|
|
|
bool WingJson::PopulateFromJson(
|
|
UStruct* StructType, void* Container,
|
|
const TSharedPtr<FJsonValue>& JsonValue)
|
|
{
|
|
if (!JsonValue.IsValid() || (JsonValue->Type != EJson::Object))
|
|
{
|
|
UWingServer::Print(TEXT("ERROR: Expected a JSON object\n"));
|
|
return false;
|
|
}
|
|
return PopulateFromJson(StructType, Container, JsonValue->AsObject().Get());
|
|
}
|