bool UArrayProperty::ConvertFromType(const FPropertyTag& Tag, FArchive& Ar, uint8* Data, UStruct* DefaultsStruct, bool& bOutAdvanceProperty) { // TODO: The ArrayProperty Tag really doesn't have adequate information for // many types. This should probably all be moved in to ::SerializeItem bOutAdvanceProperty = false; if (Tag.Type == NAME_ArrayProperty && Tag.InnerType != NAME_None && Tag.InnerType != Inner->GetID()) { void* ArrayPropertyData = ContainerPtrToValuePtr<void>(Data); int32 ElementCount = 0; Ar << ElementCount; FScriptArrayHelper ScriptArrayHelper(this, ArrayPropertyData); ScriptArrayHelper.EmptyAndAddValues(ElementCount); // Convert properties from old type to new type automatically if types are compatible (array case) if (ElementCount > 0) { FPropertyTag InnerPropertyTag; InnerPropertyTag.Type = Tag.InnerType; InnerPropertyTag.ArrayIndex = 0; bool bDummyAdvance; if (Inner->ConvertFromType(InnerPropertyTag, Ar, ScriptArrayHelper.GetRawPtr(0), DefaultsStruct, bDummyAdvance)) { for (int32 i = 1; i < ElementCount; ++i) { verify(Inner->ConvertFromType(InnerPropertyTag, Ar, ScriptArrayHelper.GetRawPtr(i), DefaultsStruct, bDummyAdvance)); } bOutAdvanceProperty = true; } // TODO: Implement SerializeFromMismatchedTag handling for arrays of structs else { UE_LOG(LogClass, Warning, TEXT("Array Inner Type mismatch in %s of %s - Previous (%s) Current(%s) for package: %s"), *Tag.Name.ToString(), *GetName(), *Tag.InnerType.ToString(), *Inner->GetID().ToString(), *Ar.GetArchiveName() ); } } else { bOutAdvanceProperty = true; } return true; } return false; }
void FPropertyLocalizationDataGatherer::GatherLocalizationDataFromChildTextProperies(const FString& PathToParent, UProperty* const Property, void* const ValueAddress, const bool ForceIsEditorOnly) { UTextProperty* const TextProperty = Cast<UTextProperty>(Property); UArrayProperty* const ArrayProperty = Cast<UArrayProperty>(Property); UStructProperty* const StructProperty = Cast<UStructProperty>(Property); // Property is a text property. if (TextProperty) { GatherLocalizationDataFromTextProperty(PathToParent, TextProperty, ValueAddress, ForceIsEditorOnly); } else { // Handles both native, fixed-size arrays and plain old non-array properties. const bool IsFixedSizeArray = Property->ArrayDim > 1; for(int32 i = 0; i < Property->ArrayDim; ++i) { const FString PathToElement = FString(PathToParent.IsEmpty() ? TEXT("") : PathToParent + TEXT(".")) + (IsFixedSizeArray ? Property->GetName() + FString::Printf(TEXT("[%d]"), i) : Property->GetName()); void* const ElementValueAddress = reinterpret_cast<uint8*>(ValueAddress) + Property->ElementSize * i; // Property is a DYNAMIC array property. if (ArrayProperty) { // Iterate over all elements of the array. FScriptArrayHelper ScriptArrayHelper(ArrayProperty, ElementValueAddress); const int32 ElementCount = ScriptArrayHelper.Num(); for(int32 j = 0; j < ElementCount; ++j) { GatherLocalizationDataFromChildTextProperies(PathToElement + FString::Printf(TEXT("(%d)"), j), ArrayProperty->Inner, ScriptArrayHelper.GetRawPtr(j), ForceIsEditorOnly || Property->HasAnyPropertyFlags(CPF_EditorOnly)); } } // Property is a struct property. else if (StructProperty) { // Iterate over all properties of the struct's class. for (TFieldIterator<UProperty>PropIt(StructProperty->Struct, EFieldIteratorFlags::IncludeSuper, EFieldIteratorFlags::ExcludeDeprecated, EFieldIteratorFlags::IncludeInterfaces); PropIt; ++PropIt) { const FString Path = PathToElement; GatherLocalizationDataFromChildTextProperies(PathToElement, *PropIt, PropIt->ContainerPtrToValuePtr<void>(ElementValueAddress), ForceIsEditorOnly || Property->HasAnyPropertyFlags(CPF_EditorOnly)); } } } } }
void FEmitDefaultValueHelper::InnerGenerate(FEmitterLocalContext& Context, const UProperty* Property, const FString& PathToMember, const uint8* ValuePtr, const uint8* DefaultValuePtr, bool bWithoutFirstConstructionLine) { auto OneLineConstruction = [](FEmitterLocalContext& LocalContext, const UProperty* LocalProperty, const uint8* LocalValuePtr, FString& OutSingleLine, bool bGenerateEmptyStructConstructor) -> bool { bool bComplete = true; FString ValueStr = HandleSpecialTypes(LocalContext, LocalProperty, LocalValuePtr); if (ValueStr.IsEmpty()) { ValueStr = LocalContext.ExportTextItem(LocalProperty, LocalValuePtr); auto StructProperty = Cast<const UStructProperty>(LocalProperty); if (ValueStr.IsEmpty() && StructProperty) { check(StructProperty->Struct); if (bGenerateEmptyStructConstructor) { ValueStr = FString::Printf(TEXT("%s{}"), *FEmitHelper::GetCppName(StructProperty->Struct)); //don;t override existing values } bComplete = false; } else if (ValueStr.IsEmpty()) { UE_LOG(LogK2Compiler, Error, TEXT("FEmitDefaultValueHelper Cannot generate initilization: %s"), *LocalProperty->GetPathName()); } } OutSingleLine += ValueStr; return bComplete; }; auto StructProperty = Cast<const UStructProperty>(Property); check(!StructProperty || StructProperty->Struct); auto ArrayProperty = Cast<const UArrayProperty>(Property); check(!ArrayProperty || ArrayProperty->Inner); if (!bWithoutFirstConstructionLine) { FString ValueStr; const bool bComplete = OneLineConstruction(Context, Property, ValuePtr, ValueStr, false); if (!ValueStr.IsEmpty()) { Context.AddLine(FString::Printf(TEXT("%s = %s;"), *PathToMember, *ValueStr)); } // array initialization "array_var = TArray<..>()" is complete, but it still needs items. if (bComplete && !ArrayProperty) { return; } } if (StructProperty) { for (auto LocalProperty : TFieldRange<const UProperty>(StructProperty->Struct)) { OuterGenerate(Context, LocalProperty, PathToMember, ValuePtr, DefaultValuePtr, EPropertyAccessOperator::Dot); } } if (ArrayProperty) { const bool bInitializeWithoutScriptStruct = false; FScriptArrayHelper ScriptArrayHelper(ArrayProperty, ValuePtr); UStructProperty* InnerStructProperty = Cast<UStructProperty>(ArrayProperty->Inner); UScriptStruct* RegularInnerStruct = ((!bInitializeWithoutScriptStruct) && InnerStructProperty && !FEmitDefaultValueHelper::SpecialStructureConstructor(InnerStructProperty->Struct, nullptr, nullptr)) ? InnerStructProperty->Struct : nullptr; if (ScriptArrayHelper.Num()) { const TCHAR* ArrayReserveFunctionName = RegularInnerStruct ? TEXT("AddUninitialized") : TEXT("Reserve"); Context.AddLine(FString::Printf(TEXT("%s.%s(%d);"), *PathToMember, ArrayReserveFunctionName, ScriptArrayHelper.Num())); if (RegularInnerStruct) { const FString InnerStructStr = Context.FindGloballyMappedObject(RegularInnerStruct); Context.AddLine(FString::Printf(TEXT("%s->InitializeStruct(%s.GetData(), %d);"), *InnerStructStr, *PathToMember, ScriptArrayHelper.Num())); } } const FStructOnScope DefaultStruct(RegularInnerStruct); for (int32 Index = 0; Index < ScriptArrayHelper.Num(); ++Index) { const uint8* LocalValuePtr = ScriptArrayHelper.GetRawPtr(Index); bool bComplete = false; if (!RegularInnerStruct) { FString ValueStr; bComplete = OneLineConstruction(Context, ArrayProperty->Inner, LocalValuePtr, ValueStr, bInitializeWithoutScriptStruct); ensure(bComplete || bInitializeWithoutScriptStruct); Context.AddLine(FString::Printf(TEXT("%s.Add(%s);"), *PathToMember, *ValueStr)); } if (RegularInnerStruct || (bInitializeWithoutScriptStruct && !bComplete)) { const FString LocalPathToMember = FString::Printf(TEXT("%s[%d]"), *PathToMember, Index); InnerGenerate(Context, ArrayProperty->Inner, LocalPathToMember, LocalValuePtr, DefaultStruct.GetStructMemory(), true); } } } }