// Copyright Epic Games, Inc. All Rights Reserved. #include "CoreMinimal.h" #include "UObject/ObjectMacros.h" #include "UObject/UObjectGlobals.h" #include "UObject/UnrealType.h" #include "UObject/UnrealTypePrivate.h" #include "UObject/PropertyHelper.h" // WARNING: This should always be the last include in any file that needs it (except .generated.h) #include "UObject/UndefineUPropertyMacros.h" /*----------------------------------------------------------------------------- FBoolProperty. -----------------------------------------------------------------------------*/ IMPLEMENT_FIELD(FBoolProperty) FBoolProperty::FBoolProperty(FFieldVariant InOwner, const FName& InName, EObjectFlags InObjectFlags) : FProperty(InOwner, InName, InObjectFlags), FieldSize(0), ByteOffset(0), ByteMask(1), FieldMask(1) { SetBoolSize(1, false, 1); } FBoolProperty::FBoolProperty(FFieldVariant InOwner, const FName& InName, EObjectFlags InObjectFlags, int32 InOffset, EPropertyFlags InFlags, uint32 InBitMask, uint32 InElementSize, bool bIsNativeBool) : FProperty(InOwner, InName, InObjectFlags, InOffset, InFlags | CPF_HasGetValueTypeHash), FieldSize(0), ByteOffset(0), ByteMask(1), FieldMask(1) { SetBoolSize(InElementSize, bIsNativeBool, InBitMask); } #if WITH_EDITORONLY_DATA FBoolProperty::FBoolProperty(UField* InField) : FProperty(InField) { UBoolProperty* SourceProperty = CastChecked(InField); FieldSize = SourceProperty->FieldSize; ByteOffset = SourceProperty->ByteOffset; ByteMask = SourceProperty->ByteMask; FieldMask = SourceProperty->FieldMask; } #endif // WITH_EDITORONLY_DATA void FBoolProperty::PostDuplicate(const FField& InField) { const FBoolProperty& Source = static_cast(InField); FieldSize = Source.FieldSize; ByteOffset = Source.ByteOffset; ByteMask = Source.ByteMask; FieldMask = Source.FieldMask; Super::PostDuplicate(InField); } void FBoolProperty::SetBoolSize(const uint32 InSize, const bool bIsNativeBool, const uint32 InBitMask /*= 0*/) { if (bIsNativeBool) { PropertyFlags |= (CPF_IsPlainOldData | CPF_NoDestructor | CPF_ZeroConstructor); } else { PropertyFlags &= ~(CPF_IsPlainOldData | CPF_ZeroConstructor); PropertyFlags |= CPF_NoDestructor; } uint32 TestBitmask = InBitMask ? InBitMask : 1; ElementSize = InSize; FieldSize = (uint8)ElementSize; ByteOffset = 0; if (bIsNativeBool) { ByteMask = true; FieldMask = 255; } else { // Calculate ByteOffset and get ByteMask. for (ByteOffset = 0; ByteOffset < InSize && ((ByteMask = *((uint8*)&TestBitmask + ByteOffset)) == 0); ByteOffset++) ; FieldMask = ByteMask; } check((int32)FieldSize == ElementSize); check(ElementSize != 0); check(FieldMask != 0); check(ByteMask != 0); } int32 FBoolProperty::GetMinAlignment() const { int32 Alignment = 0; switch (ElementSize) { case sizeof(uint8): Alignment = alignof(uint8); break; case sizeof(uint16): Alignment = alignof(uint16); break; case sizeof(uint32): Alignment = alignof(uint32); break; case sizeof(uint64): Alignment = alignof(uint64); break; default: UE_LOG(LogProperty, Fatal, TEXT("Unsupported FBoolProperty %s size %d."), *GetName(), (int32)ElementSize); } return Alignment; } void FBoolProperty::LinkInternal(FArchive& Ar) { check(FieldSize != 0); ElementSize = FieldSize; if (IsNativeBool()) { PropertyFlags |= (CPF_IsPlainOldData | CPF_NoDestructor | CPF_ZeroConstructor); } else { PropertyFlags &= ~(CPF_IsPlainOldData | CPF_ZeroConstructor); PropertyFlags |= CPF_NoDestructor; } } void FBoolProperty::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar << FieldSize; Ar << ByteOffset; Ar << ByteMask; Ar << FieldMask; // Serialize additional flags which will help to identify this FBoolProperty type and size. uint8 BoolSize = (uint8)ElementSize; Ar << BoolSize; uint8 NativeBool = false; if (Ar.IsLoading()) { Ar << NativeBool; // if (!IsPendingKill()) { SetBoolSize(BoolSize, !!NativeBool); } } else { NativeBool = Ar.IsSaving() ? (IsNativeBool() ? 1 : 0) : 0; Ar << NativeBool; } } FString FBoolProperty::GetCPPType(FString* ExtendedTypeText /*=NULL*/, uint32 CPPExportFlags /*=0*/) const { check(FieldSize != 0); if (IsNativeBool() || ((CPPExportFlags & (CPPF_Implementation | CPPF_ArgumentOrReturnValue)) == (CPPF_Implementation | CPPF_ArgumentOrReturnValue)) || ((CPPExportFlags & CPPF_BlueprintCppBackend) != 0)) { // Export as bool if this is actually a bool or it's being exported as a return value of C++ function definition. return TEXT("bool"); } else { // Bitfields switch (ElementSize) { case sizeof(uint64): return TEXT("uint64"); case sizeof(uint32): return TEXT("uint32"); case sizeof(uint16): return TEXT("uint16"); case sizeof(uint8): return TEXT("uint8"); default: UE_LOG(LogProperty, Fatal, TEXT("Unsupported FBoolProperty %s size %d."), *GetName(), ElementSize); break; } } return TEXT("uint32"); } FString FBoolProperty::GetCPPTypeForwardDeclaration() const { return FString(); } FString FBoolProperty::GetCPPMacroType(FString& ExtendedTypeText) const { check(FieldSize != 0); if (IsNativeBool()) { return TEXT("UBOOL"); } else { switch (ElementSize) { case sizeof(uint64): return TEXT("UBOOL64"); case sizeof(uint32): return TEXT("UBOOL32"); case sizeof(uint16): return TEXT("UBOOL16"); case sizeof(uint8): return TEXT("UBOOL8"); default: UE_LOG(LogProperty, Fatal, TEXT("Unsupported FBoolProperty %s size %d."), *GetName(), ElementSize); break; } } return TEXT("UBOOL32"); } template void LoadFromType(FBoolProperty* Property, const FPropertyTag& Tag, FStructuredArchive::FSlot Slot, uint8* Data) { T IntValue; Slot << IntValue; if (IntValue != 0) { #if !(UE_BUILD_SHIPPING || UE_BUILD_TEST) if (IntValue != 1) { UE_LOG(LogClass, Log, TEXT("Loading %s property (%s) that is now a bool - value '%d', expecting 0 or 1. Value set to true."), *Tag.Type.ToString(), *Property->GetPathName(), IntValue); } #endif Property->SetPropertyValue_InContainer(Data, true, Tag.ArrayIndex); } else { Property->SetPropertyValue_InContainer(Data, false, Tag.ArrayIndex); } } EConvertFromTypeResult FBoolProperty::ConvertFromType(const FPropertyTag& Tag, FStructuredArchive::FSlot Slot, uint8* Data, UStruct* DefaultsStruct) { if (Tag.Type == NAME_IntProperty) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_Int8Property) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_Int16Property) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_Int64Property) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_ByteProperty) { // if the byte property was an enum we won't allow a conversion to bool if (Tag.EnumName == NAME_None) { // If we're a nested property the EnumName tag got lost, don't allow this if (GetOwner()) { return EConvertFromTypeResult::UseSerializeItem; } LoadFromType(this, Tag, Slot, Data); } else { return EConvertFromTypeResult::UseSerializeItem; } } else if (Tag.Type == NAME_UInt16Property) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_UInt32Property) { LoadFromType(this, Tag, Slot, Data); } else if (Tag.Type == NAME_UInt64Property) { LoadFromType(this, Tag, Slot, Data); } else { return EConvertFromTypeResult::UseSerializeItem; } return EConvertFromTypeResult::Converted; } void FBoolProperty::ExportTextItem(FString& ValueStr, const void* PropertyValue, const void* DefaultValue, UObject* Parent, int32 PortFlags, UObject* ExportRootScope) const { check(FieldSize != 0); const uint8* ByteValue = (uint8*)PropertyValue + ByteOffset; const bool bValue = 0 != ((*ByteValue) & FieldMask); const TCHAR* Temp = nullptr; if (0 != (PortFlags & PPF_ExportCpp)) { Temp = (bValue ? TEXT("true") : TEXT("false")); } else { Temp = (bValue ? TEXT("True") : TEXT("False")); } ValueStr += FString::Printf(TEXT("%s"), Temp); } const TCHAR* FBoolProperty::ImportText_Internal(const TCHAR* Buffer, void* Data, int32 PortFlags, UObject* Parent, FOutputDevice* ErrorText) const { FString Temp; Buffer = FPropertyHelpers::ReadToken(Buffer, Temp); if (!Buffer) { return NULL; } check(FieldSize != 0); uint8* ByteValue = (uint8*)Data + ByteOffset; const FCoreTexts& CoreTexts = FCoreTexts::Get(); if (Temp == TEXT("1") || Temp == TEXT("True") || Temp == *CoreTexts.True.ToString() || Temp == TEXT("Yes") || Temp == *CoreTexts.Yes.ToString()) { *ByteValue |= ByteMask; } else if (Temp == TEXT("0") || Temp == TEXT("False") || Temp == *CoreTexts.False.ToString() || Temp == TEXT("No") || Temp == *CoreTexts.No.ToString()) { *ByteValue &= ~FieldMask; } else { // UE_LOG(LogProperty, Log, "Import: Failed to get bool" ); return NULL; } return Buffer; } bool FBoolProperty::Identical(const void* A, const void* B, uint32 PortFlags) const { check(FieldSize != 0); const uint8* ByteValueA = (const uint8*)A + ByteOffset; const uint8* ByteValueB = (const uint8*)B + ByteOffset; return ((*ByteValueA ^ (B ? *ByteValueB : 0)) & FieldMask) == 0; } void FBoolProperty::SerializeItem(FStructuredArchive::FSlot Slot, void* Value, void const* Defaults) const { check(FieldSize != 0); uint8* ByteValue = (uint8*)Value + ByteOffset; uint8 B = (*ByteValue & FieldMask) ? 1 : 0; Slot << B; *ByteValue = ((*ByteValue) & ~FieldMask) | (B ? ByteMask : 0); } bool FBoolProperty::NetSerializeItem(FArchive& Ar, UPackageMap* Map, void* Data, TArray* MetaData) const { check(FieldSize != 0); uint8* ByteValue = (uint8*)Data + ByteOffset; uint8 Value = ((*ByteValue & FieldMask) != 0); Ar.SerializeBits(&Value, 1); *ByteValue = ((*ByteValue) & ~FieldMask) | (Value ? ByteMask : 0); return true; } void FBoolProperty::CopyValuesInternal(void* Dest, void const* Src, int32 Count) const { check(FieldSize != 0 && !IsNativeBool()); for (int32 Index = 0; Index < Count; Index++) { uint8* DestByteValue = (uint8*)Dest + Index * ElementSize + ByteOffset; uint8* SrcByteValue = (uint8*)Src + Index * ElementSize + ByteOffset; *DestByteValue = (*DestByteValue & ~FieldMask) | (*SrcByteValue & FieldMask); } } void FBoolProperty::ClearValueInternal(void* Data) const { check(FieldSize != 0); uint8* ByteValue = (uint8*)Data + ByteOffset; *ByteValue &= ~FieldMask; } void FBoolProperty::InitializeValueInternal(void* Data) const { check(FieldSize != 0); uint8* ByteValue = (uint8*)Data + ByteOffset; *ByteValue &= ~FieldMask; } uint32 FBoolProperty::GetValueTypeHashInternal(const void* Src) const { return GetTypeHash(*(const bool*)Src); } #include "UObject/DefineUPropertyMacros.h"