bool FDataTableImporterJSON::ReadStruct(const TSharedRef<FJsonObject>& InParsedObject, UScriptStruct* InStruct, const FName InRowName, void* InStructData) { // Now read in each property for (TFieldIterator<UProperty> It(InStruct); It; ++It) { UProperty* BaseProp = *It; check(BaseProp); const FString ColumnName = DataTableUtils::GetPropertyDisplayName(BaseProp, BaseProp->GetName()); TSharedPtr<FJsonValue> ParsedPropertyValue; for (const FString& PropertyName : DataTableUtils::GetPropertyImportNames(BaseProp)) { ParsedPropertyValue = InParsedObject->TryGetField(PropertyName); if (ParsedPropertyValue.IsValid()) { break; } } if (!ParsedPropertyValue.IsValid()) { ImportProblems.Add(FString::Printf(TEXT("Row '%s' is missing an entry for '%s'."), *InRowName.ToString(), *ColumnName)); continue; } if (BaseProp->ArrayDim == 1) { void* Data = BaseProp->ContainerPtrToValuePtr<void>(InStructData, 0); ReadStructEntry(ParsedPropertyValue.ToSharedRef(), InRowName, ColumnName, InStructData, BaseProp, Data); } else { const TCHAR* const ParsedPropertyType = JSONTypeToString(ParsedPropertyValue->Type); const TArray< TSharedPtr<FJsonValue> >* PropertyValuesPtr; if (!ParsedPropertyValue->TryGetArray(PropertyValuesPtr)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Array, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } if (BaseProp->ArrayDim != PropertyValuesPtr->Num()) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is a static sized array with %d elements, but we have %d values to import"), *ColumnName, *InRowName.ToString(), BaseProp->ArrayDim, PropertyValuesPtr->Num())); } for (int32 ArrayEntryIndex = 0; ArrayEntryIndex < BaseProp->ArrayDim; ++ArrayEntryIndex) { if (PropertyValuesPtr->IsValidIndex(ArrayEntryIndex)) { void* Data = BaseProp->ContainerPtrToValuePtr<void>(InStructData, ArrayEntryIndex); const TSharedPtr<FJsonValue>& PropertyValueEntry = (*PropertyValuesPtr)[ArrayEntryIndex]; ReadArrayEntry(PropertyValueEntry.ToSharedRef(), InRowName, ColumnName, ArrayEntryIndex, BaseProp, Data); } } } } return true; }
bool FDataTableImporterJSON::ReadStructEntry(const TSharedRef<FJsonValue>& InParsedPropertyValue, const FName InRowName, const FString& InColumnName, const void* InRowData, UProperty* InProperty, void* InPropertyData) { const TCHAR* const ParsedPropertyType = JSONTypeToString(InParsedPropertyValue->Type); if (UNumericProperty *NumProp = Cast<UNumericProperty>(InProperty)) { FString EnumValue; if (NumProp->IsEnum() && InParsedPropertyValue->TryGetString(EnumValue)) { FString Error = DataTableUtils::AssignStringToProperty(EnumValue, InProperty, (uint8*)InRowData); if (!Error.IsEmpty()) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' has invalid enum value: %s."), *InColumnName, *InRowName.ToString(), *EnumValue)); return false; } } else if (NumProp->IsInteger()) { int64 PropertyValue = 0; if (!InParsedPropertyValue->TryGetNumber(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Integer, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } NumProp->SetIntPropertyValue(InPropertyData, PropertyValue); } else { double PropertyValue = 0.0; if (!InParsedPropertyValue->TryGetNumber(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Double, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } NumProp->SetFloatingPointPropertyValue(InPropertyData, PropertyValue); } } else if (UBoolProperty* BoolProp = Cast<UBoolProperty>(InProperty)) { bool PropertyValue = false; if (!InParsedPropertyValue->TryGetBool(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Boolean, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } BoolProp->SetPropertyValue(InPropertyData, PropertyValue); } else if (UArrayProperty* ArrayProp = Cast<UArrayProperty>(InProperty)) { const TArray< TSharedPtr<FJsonValue> >* PropertyValuesPtr; if (!InParsedPropertyValue->TryGetArray(PropertyValuesPtr)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Array, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } FScriptArrayHelper ArrayHelper(ArrayProp, InPropertyData); ArrayHelper.EmptyValues(); for (const TSharedPtr<FJsonValue>& PropertyValueEntry : *PropertyValuesPtr) { const int32 NewEntryIndex = ArrayHelper.AddValue(); void* ArrayEntryData = ArrayHelper.GetRawPtr(NewEntryIndex); ReadArrayEntry(PropertyValueEntry.ToSharedRef(), InRowName, InColumnName, NewEntryIndex, ArrayProp->Inner, ArrayEntryData); } } else if (UStructProperty* StructProp = Cast<UStructProperty>(InProperty)) { const TSharedPtr<FJsonObject>* PropertyValue = nullptr; if (InParsedPropertyValue->TryGetObject(PropertyValue)) { return ReadStruct(PropertyValue->ToSharedRef(), StructProp->Struct, InRowName, InPropertyData); } else { // If the JSON does not contain a JSON object for this struct, we try to use the backwards-compatible string deserialization, same as the "else" block below FString PropertyValueString; if (!InParsedPropertyValue->TryGetString(PropertyValueString)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected String, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } const FString Error = DataTableUtils::AssignStringToProperty(PropertyValueString, InProperty, (uint8*)InRowData); if (Error.Len() > 0) { ImportProblems.Add(FString::Printf(TEXT("Problem assigning string '%s' to property '%s' on row '%s' : %s"), *PropertyValueString, *InColumnName, *InRowName.ToString(), *Error)); return false; } return true; } } else { FString PropertyValue; if (!InParsedPropertyValue->TryGetString(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected String, got %s."), *InColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } const FString Error = DataTableUtils::AssignStringToProperty(PropertyValue, InProperty, (uint8*)InRowData); if(Error.Len() > 0) { ImportProblems.Add(FString::Printf(TEXT("Problem assigning string '%s' to property '%s' on row '%s' : %s"), *PropertyValue, *InColumnName, *InRowName.ToString(), *Error)); return false; } } return true; }
bool FDataTableImporterJSON::ReadStructEntry(const TSharedRef<FJsonValue>& ParsedPropertyValue, const FName InRowName, const void* InRowData, UProperty* InProperty, void* InPropertyData) { const FString ColumnName = DataTableUtils::GetPropertyDisplayName(InProperty, InProperty->GetName()); const TCHAR* const ParsedPropertyType = JSONTypeToString(ParsedPropertyValue->Type); if (UNumericProperty *NumProp = Cast<UNumericProperty>(InProperty)) { if (NumProp->IsInteger()) { int64 PropertyValue = 0; if (!ParsedPropertyValue->TryGetNumber(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Integer, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } NumProp->SetIntPropertyValue(InPropertyData, PropertyValue); } else { double PropertyValue = 0.0; if (!ParsedPropertyValue->TryGetNumber(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Double, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } NumProp->SetFloatingPointPropertyValue(InPropertyData, PropertyValue); } } else if (UBoolProperty* BoolProp = Cast<UBoolProperty>(InProperty)) { bool PropertyValue = false; if (!ParsedPropertyValue->TryGetBool(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Boolean, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } BoolProp->SetPropertyValue(InPropertyData, PropertyValue); } else if (UArrayProperty* ArrayProp = Cast<UArrayProperty>(InProperty)) { const TArray< TSharedPtr<FJsonValue> >* PropertyValuesPtr; if (!ParsedPropertyValue->TryGetArray(PropertyValuesPtr)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected Array, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } FScriptArrayHelper ArrayHelper(ArrayProp, InPropertyData); for (const TSharedPtr<FJsonValue>& PropertyValueEntry : *PropertyValuesPtr) { const int32 NewEntryIndex = ArrayHelper.AddValue(); void* ArrayEntryData = ArrayHelper.GetRawPtr(NewEntryIndex); ReadArrayEntry(PropertyValueEntry.ToSharedRef(), InRowName, ColumnName, NewEntryIndex, ArrayProp->Inner, ArrayEntryData); } } else { FString PropertyValue; if (!ParsedPropertyValue->TryGetString(PropertyValue)) { ImportProblems.Add(FString::Printf(TEXT("Property '%s' on row '%s' is the incorrect type. Expected String, got %s."), *ColumnName, *InRowName.ToString(), ParsedPropertyType)); return false; } const FString Error = DataTableUtils::AssignStringToProperty(PropertyValue, InProperty, (uint8*)InRowData); if(Error.Len() > 0) { ImportProblems.Add(FString::Printf(TEXT("Problem assigning string '%s' to property '%s' on row '%s' : %s"), *PropertyValue, *ColumnName, *InRowName.ToString(), *Error)); return false; } } return true; }