void UPhysicsSerializer::Serialize( FArchive& Ar ) { QUICK_SCOPE_CYCLE_COUNTER(STAT_Serialize); Super::Serialize(Ar); if (Ar.UE4Ver() >= VER_UE4_BODYINSTANCE_BINARY_SERIALIZATION) { bool bCooked = Ar.IsCooking(); Ar << bCooked; if (bCooked) { if (Ar.IsCooking()) { TArray<FName> ActualFormatsToSave; ActualFormatsToSave.Add(FPlatformProperties::GetPhysicsFormat()); BinaryFormatData.Serialize(Ar, this, &ActualFormatsToSave); } else { #if WITH_PHYSX const uint32 Alignment = PHYSX_SERIALIZATION_ALIGNMENT; #else const uint32 Alignment = DEFAULT_ALIGNMENT; #endif BinaryFormatData.Serialize(Ar, this, nullptr, false, Alignment); } } } }
void UBodySetup::Serialize(FArchive& Ar) { Super::Serialize(Ar); // Load GUID (or create one for older versions) Ar << BodySetupGuid; // If we loaded a ZERO Guid, fix that if(Ar.IsLoading() && !BodySetupGuid.IsValid()) { MarkPackageDirty(); UE_LOG(LogPhysics, Log, TEXT("FIX GUID FOR: %s"), *GetPathName()); BodySetupGuid = FGuid::NewGuid(); } bool bCooked = Ar.IsCooking(); Ar << bCooked; if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogPhysics, Fatal, TEXT("This platform requires cooked packages, and physX data was not cooked into %s."), *GetFullName()); } if (bCooked) { if (Ar.IsCooking()) { // Make sure to reset bHasCookedCollision data to true before calling GetCookedData for cooking bHasCookedCollisionData = true; FName Format = Ar.CookingTarget()->GetPhysicsFormat(this); bHasCookedCollisionData = GetCookedData(Format) != NULL; // Get the data from the DDC or build it TArray<FName> ActualFormatsToSave; ActualFormatsToSave.Add(Format); Ar << bHasCookedCollisionData; CookedFormatData.Serialize(Ar, this, &ActualFormatsToSave); } else { if (Ar.UE4Ver() >= VER_UE4_STORE_HASCOOKEDDATA_FOR_BODYSETUP) { Ar << bHasCookedCollisionData; } CookedFormatData.Serialize(Ar, this); } } if ( Ar.IsLoading() ) { AggGeom.Serialize( Ar ); } }
void USoundCue::Serialize( FArchive& Ar ) { // Always force the duration to be updated when we are saving or cooking if (Ar.IsSaving() || Ar.IsCooking()) { Duration = (FirstNode ? FirstNode->GetDuration() : 0.f); } Super::Serialize( Ar ); if (!Ar.IsCooking()) { Ar << SoundCueGraph; } }
void ARadiantStaticMeshWebViewActor::Serialize(FArchive& Ar) { Super::Serialize(Ar); static const int ArchiveVersion = 1; int Version = ArchiveVersion; Ar << Version; bool bCooked = Ar.IsCooking(); Ar << bCooked; if (bCooked) { #if WITH_EDITORONLY_DATA check(!Ar.IsLoading()); if (!InteractionMesh) { ExtractInteractionMesh(); } #else check(Ar.IsLoading()); #endif Ar << InteractionMesh; } }
void FRawCurveTracks::Serialize(FArchive& Ar) { // @TODO: If we're about to serialize vector curve, add here if(Ar.UE4Ver() >= VER_UE4_SKELETON_ADD_SMARTNAMES) { for(FFloatCurve& Curve : FloatCurves) { Curve.Serialize(Ar); } } #if WITH_EDITORONLY_DATA if( !Ar.IsCooking() ) { if( Ar.UE4Ver() >= VER_UE4_ANIMATION_ADD_TRACKCURVES ) { for( FTransformCurve& Curve : TransformCurves ) { Curve.Serialize( Ar ); } } } #endif // WITH_EDITORONLY_DATA if (Ar.IsLoading()) { SortFloatCurvesByUID(); } }
void USubstanceImageInput::Serialize(FArchive& Ar) { Super::Serialize(Ar); Ar.UsingCustomVersion(FSubstanceCoreCustomVersion::GUID); //! todo: remove image date if all consumers are freezed if (Ar.IsSaving()) { ImageRGB.StoreCompressedOnDisk(0 == CompressionRGB ? COMPRESS_ZLIB : COMPRESS_None); ImageA.StoreCompressedOnDisk(0 == CompressionAlpha ? COMPRESS_ZLIB : COMPRESS_None); } ImageRGB.Serialize(Ar, this); ImageA.Serialize(Ar, this); // image inputs can be used multiple times ImageRGB.ClearBulkDataFlags(BULKDATA_SingleUse); ImageA.ClearBulkDataFlags(BULKDATA_SingleUse); Ar << CompressionRGB; Ar << CompressionAlpha; if (Ar.IsCooking()) { SourceFilePath = FString(); SourceFileTimestamp = FString(); } }
void USoundCue::Serialize(FArchive& Ar) { // Always force the duration to be updated when we are saving or cooking if (Ar.IsSaving() || Ar.IsCooking()) { Duration = (FirstNode ? FirstNode->GetDuration() : 0.f); } Super::Serialize(Ar); if (Ar.UE4Ver() >= VER_UE4_COOKED_ASSETS_IN_EDITOR_SUPPORT) { FStripDataFlags StripFlags(Ar); #if WITH_EDITORONLY_DATA if (!StripFlags.IsEditorDataStripped()) { Ar << SoundCueGraph; } #endif } #if WITH_EDITOR else { Ar << SoundCueGraph; } #endif }
void FShadowMap2D::Serialize(FArchive& Ar) { FShadowMap::Serialize(Ar); if( Ar.IsCooking() && !Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::DistanceFieldShadows) ) { UShadowMapTexture2D* Dummy = NULL; Ar << Dummy; } else { Ar << Texture; } Ar << CoordinateScale << CoordinateBias; for (int Channel = 0; Channel < ARRAY_COUNT(bChannelValid); Channel++) { Ar << bChannelValid[Channel]; } if (Ar.UE4Ver() >= VER_UE4_STATIC_SHADOWMAP_PENUMBRA_SIZE) { Ar << InvUniformPenumbraSize; } else if (Ar.IsLoading()) { const float LegacyValue = 1.0f / .05f; InvUniformPenumbraSize = FVector4(LegacyValue, LegacyValue, LegacyValue, LegacyValue); } }
void FShaderResource::Serialize(FArchive& Ar) { Ar << SpecificType; Ar << Target; Ar << Code; Ar << OutputHash; Ar << NumInstructions; Ar << NumTextureSamplers; if (Ar.IsLoading()) { INC_DWORD_STAT_BY_FName(GetMemoryStatType((EShaderFrequency)Target.Frequency).GetName(), (int64)Code.Num()); INC_DWORD_STAT_BY(STAT_Shaders_ShaderResourceMemory, GetSizeBytes()); FShaderCache::LogShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, Code); // The shader resource has been serialized in, so this shader resource is now initialized. check(Canary != FShader::ShaderMagic_CleaningUp); Canary = FShader::ShaderMagic_Initialized; } #if WITH_EDITORONLY_DATA else if(Ar.IsCooking()) { FShaderCache::CookShader((EShaderPlatform)Target.Platform, (EShaderFrequency)Target.Frequency, OutputHash, Code); } #endif }
void USoundNode::Serialize(FArchive& Ar) { Super::Serialize(Ar); if (!Ar.IsCooking()) { Ar << GraphNode; } }
void USoundNode::Serialize(FArchive& Ar) { Super::Serialize(Ar); if (!Ar.IsCooking() && Ar.UE4Ver() >= VER_UE4_SOUND_CUE_GRAPH_EDITOR) { Ar << GraphNode; } }
void Serialize(FArchive& Ar, UObject* Owner, int32 Idx) { const uint8 AdjacencyDataStripFlag = 1; FStripDataFlags StripFlags( Ar, Ar.IsCooking() && !Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::Tessellation) ? AdjacencyDataStripFlag : 0 ); UStaticMesh* StaticMesh = Cast<UStaticMesh>( Owner ); bool bNeedsCPUAccess = true; if( !StripFlags.IsEditorDataStripped() ) { RawTriangles.Serialize( Ar, Owner ); } Ar << Elements; if( !StripFlags.IsDataStrippedForServer() ) { PositionVertexBuffer.Serialize( Ar, bNeedsCPUAccess ); VertexBuffer.Serialize( Ar, bNeedsCPUAccess ); ColorVertexBuffer.Serialize( Ar, bNeedsCPUAccess ); Ar << NumVertices; IndexBuffer.Serialize( Ar, bNeedsCPUAccess ); if (Ar.UE4Ver() >= VER_UE4_SHADOW_ONLY_INDEX_BUFFERS) { ShadowIndexBuffer.Serialize(Ar, bNeedsCPUAccess); } if( !StripFlags.IsEditorDataStripped() ) { Ar << WireframeIndexBuffer; } if ( !StripFlags.IsClassDataStripped( AdjacencyDataStripFlag ) ) { AdjacencyIndexBuffer.Serialize( Ar, bNeedsCPUAccess ); } } if (Ar.IsLoading()) { if (PositionVertexBuffer.GetNumVertices() != NumVertices) { PositionVertexBuffer.RemoveLegacyShadowVolumeVertices(NumVertices); } if (VertexBuffer.GetNumVertices() != NumVertices) { VertexBuffer.RemoveLegacyShadowVolumeVertices(NumVertices); } if (VertexBuffer.GetNumVertices() != NumVertices) { ColorVertexBuffer.RemoveLegacyShadowVolumeVertices(NumVertices); } } }
void UTextureCube::Serialize(FArchive& Ar) { DECLARE_SCOPE_CYCLE_COUNTER(TEXT("UTextureCube::Serialize"), STAT_TextureCube_Serialize, STATGROUP_LoadTime); Super::Serialize(Ar); FStripDataFlags StripFlags(Ar); bool bCooked = Ar.IsCooking(); Ar << bCooked; if (bCooked || Ar.IsCooking()) { SerializeCookedPlatformData(Ar); } #if WITH_EDITOR if (Ar.IsLoading() && !Ar.IsTransacting() && !bCooked) { BeginCachePlatformData(); } #endif // #if WITH_EDITOR }
// Begin UObject interface. void UDialogueWave::Serialize( FArchive& Ar ) { Super::Serialize( Ar ); Ar.ThisRequiresLocalizationGather(); bool bCooked = Ar.IsCooking(); Ar << bCooked; if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogAudio, Fatal, TEXT("This platform requires cooked packages, and audio data was not cooked into %s."), *GetFullName()); } }
void FStreamedAudioChunk::Serialize(FArchive& Ar, UObject* Owner, int32 ChunkIndex) { bool bCooked = Ar.IsCooking(); Ar << bCooked; BulkData.Serialize(Ar, Owner, ChunkIndex); Ar << DataSize; #if WITH_EDITORONLY_DATA if (!bCooked) { Ar << DerivedDataKey; } #endif // #if WITH_EDITORONLY_DATA }
void FStreamedAudioChunk::Serialize(FArchive& Ar, UObject* Owner, int32 ChunkIndex) { DECLARE_SCOPE_CYCLE_COUNTER( TEXT("FStreamedAudioChunk::Serialize"), STAT_StreamedAudioChunk_Serialize, STATGROUP_LoadTime ); bool bCooked = Ar.IsCooking(); Ar << bCooked; BulkData.Serialize(Ar, Owner, ChunkIndex); Ar << DataSize; #if WITH_EDITORONLY_DATA if (!bCooked) { Ar << DerivedDataKey; } #endif // #if WITH_EDITORONLY_DATA }
void UUserDefinedStruct::SerializeTaggedProperties(FArchive& Ar, uint8* Data, UStruct* DefaultsStruct, uint8* Defaults, const UObject* BreakRecursionIfFullyLoad) const { #if WITH_EDITOR /* The following code is responsible for UUserDefinedStruct's default values serialization. */ auto UDDefaultsStruct = Cast<UUserDefinedStruct>(DefaultsStruct); const bool bDuplicate = (0 != (Ar.GetPortFlags() & PPF_Duplicate)); /* When saving delta, we want the difference between current data and true structure's default values. When Defaults is NULL then zeroed data will be used for comparison.*/ const bool bUseNewDefaults = !Defaults && UDDefaultsStruct && Ar.DoDelta() && Ar.IsSaving() && !bDuplicate && !Ar.IsCooking(); /* Object serialized from delta will have missing properties filled with zeroed data, we want structure's default data instead */ const bool bLoadDefaultFirst = UDDefaultsStruct && !bDuplicate && Ar.IsLoading(); const bool bPrepareDefaultStruct = bUseNewDefaults || bLoadDefaultFirst; FStructOnScope StructDefaultMem(bPrepareDefaultStruct ? UDDefaultsStruct : NULL); if (bPrepareDefaultStruct) { FStructureEditorUtils::Fill_MakeStructureDefaultValue(UDDefaultsStruct, StructDefaultMem.GetStructMemory()); } if (bUseNewDefaults) { Defaults = StructDefaultMem.GetStructMemory(); } if (bLoadDefaultFirst) { if (Defaults == nullptr) { Defaults = StructDefaultMem.GetStructMemory(); } UDDefaultsStruct->CopyScriptStruct(Data, Defaults); } #endif // WITH_EDITOR Super::SerializeTaggedProperties(Ar, Data, DefaultsStruct, Defaults); }
void ULightComponent::Serialize(FArchive& Ar) { Super::Serialize(Ar); if (Ar.UE4Ver() >= VER_UE4_STATIC_SHADOW_DEPTH_MAPS) { if (Ar.IsCooking() && !Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::HighQualityLightmaps)) { // Toss lighting data only needed for high quality lightmaps FStaticShadowDepthMap EmptyDepthMap; Ar << EmptyDepthMap; } else { Ar << StaticShadowDepthMap; } } }
void USoundWave::SerializeCookedPlatformData(FArchive& Ar) { if (IsTemplate()) { return; } DECLARE_SCOPE_CYCLE_COUNTER( TEXT("USoundWave::SerializeCookedPlatformData"), STAT_SoundWave_SerializeCookedPlatformData, STATGROUP_LoadTime ); #if WITH_EDITORONLY_DATA if (Ar.IsCooking() && Ar.IsPersistent()) { check(!Ar.CookingTarget()->IsServerOnly()); FName PlatformFormat = Ar.CookingTarget()->GetWaveFormat(this); FString DerivedDataKey; GetStreamedAudioDerivedDataKey(*this, PlatformFormat, DerivedDataKey); FStreamedAudioPlatformData *PlatformDataToSave = CookedPlatformData.FindRef(DerivedDataKey); if (PlatformDataToSave == NULL) { PlatformDataToSave = new FStreamedAudioPlatformData(); PlatformDataToSave->Cache(*this, PlatformFormat, EStreamedAudioCacheFlags::InlineChunks | EStreamedAudioCacheFlags::Async); CookedPlatformData.Add(DerivedDataKey, PlatformDataToSave); } PlatformDataToSave->FinishCache(); PlatformDataToSave->Serialize(Ar, this); } else #endif // #if WITH_EDITORONLY_DATA { check(!FPlatformProperties::IsServerOnly()); CleanupCachedRunningPlatformData(); check(RunningPlatformData == NULL); // Don't serialize streaming data on servers, even if this platform supports streaming in theory RunningPlatformData = new FStreamedAudioPlatformData(); RunningPlatformData->Serialize(Ar, this); } }
void FFormatContainer::Serialize(FArchive& Ar, UObject* Owner, const TArray<FName>* FormatsToSave) { if (Ar.IsLoading()) { int32 NumFormats = 0; Ar << NumFormats; for (int32 Index = 0; Index < NumFormats; Index++) { FName Name; Ar << Name; FByteBulkData& Bulk = GetFormat(Name); Bulk.Serialize(Ar, Owner); } } else { check(Ar.IsCooking() && FormatsToSave); // this thing is for cooking only, and you need to provide a list of formats int32 NumFormats = 0; for (TMap<FName, FByteBulkData*>:: TIterator It(Formats); It; ++It) { if (FormatsToSave->Contains(It.Key()) && It.Value()->GetBulkDataSize() > 0) { NumFormats++; } } Ar << NumFormats; for (TMap<FName, FByteBulkData*>:: TIterator It(Formats); It; ++It) { if (FormatsToSave->Contains(It.Key()) && It.Value()->GetBulkDataSize() > 0) { NumFormats--; FName Name = It.Key(); Ar << Name; FByteBulkData* Bulk = It.Value(); check(Bulk); Bulk->Serialize(Ar, Owner); } } check(NumFormats == 0); } }
void FShadowMap2D::Serialize(FArchive& Ar) { FShadowMap::Serialize(Ar); if( Ar.IsCooking() && !Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::DistanceFieldShadows) ) { UShadowMapTexture2D* Dummy = NULL; Ar << Dummy; } else { Ar << Texture; } Ar << CoordinateScale << CoordinateBias; for (int Channel = 0; Channel < ARRAY_COUNT(bChannelValid); Channel++) { Ar << bChannelValid[Channel]; } }
void UNavCollision::Serialize(FArchive& Ar) { Super::Serialize(Ar); const int32 VerInitial = 1; const int32 VerAreaClass = 2; const int32 VerConvexTransforms = 3; const int32 VerLatest = VerConvexTransforms; // use magic number to determine if serialized stream has version :/ const int32 MagicNum = 0xA237F237; int64 StreamStartPos = Ar.Tell(); int32 Version = VerLatest; int32 MyMagicNum = MagicNum; Ar << MyMagicNum; if (MyMagicNum != MagicNum) { Version = VerInitial; Ar.Seek(StreamStartPos); } else { Ar << Version; } // loading a dummy GUID to have serialization not break on // packages serialized before switching over UNavCollision to // use BodySetup's guid rather than its own one // motivation: not creating a new engine version // @NOTE could be addressed during next engine version bump FGuid Guid; Ar << Guid; bool bCooked = Ar.IsCooking(); Ar << bCooked; if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogNavigation, Fatal, TEXT("This platform requires cooked packages, and NavCollision data was not cooked into %s."), *GetFullName()); } if (bCooked && ShouldUseConvexCollision()) { if (Ar.IsCooking()) { FName Format = NAVCOLLISION_FORMAT; GetCookedData(Format); // Get the data from the DDC or build it TArray<FName> ActualFormatsToSave; ActualFormatsToSave.Add(Format); CookedFormatData.Serialize(Ar, this, &ActualFormatsToSave); } else { CookedFormatData.Serialize(Ar, this); } } if (Version >= VerAreaClass) { Ar << AreaClass; } if (Version < VerConvexTransforms && Ar.IsLoading() && GIsEditor) { bForceGeometryRebuild = true; } }
void USoundWave::Serialize( FArchive& Ar ) { DECLARE_SCOPE_CYCLE_COUNTER( TEXT("USoundWave::Serialize"), STAT_SoundWave_Serialize, STATGROUP_LoadTime ); Super::Serialize( Ar ); bool bCooked = Ar.IsCooking(); Ar << bCooked; if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogAudio, Fatal, TEXT("This platform requires cooked packages, and audio data was not cooked into %s."), *GetFullName()); } Ar.UsingCustomVersion(FFrameworkObjectVersion::GUID); if (Ar.IsLoading() && (Ar.UE4Ver() >= VER_UE4_SOUND_COMPRESSION_TYPE_ADDED) && (Ar.CustomVer(FFrameworkObjectVersion::GUID) < FFrameworkObjectVersion::RemoveSoundWaveCompressionName)) { FName DummyCompressionName; Ar << DummyCompressionName; } bool bSupportsStreaming = false; if (Ar.IsLoading() && FPlatformProperties::SupportsAudioStreaming()) { bSupportsStreaming = true; } else if (Ar.IsCooking() && Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::AudioStreaming)) { bSupportsStreaming = true; } if (bCooked) { // Only want to cook/load full data if we don't support streaming if (!IsStreaming() || !bSupportsStreaming) { if (Ar.IsCooking()) { #if WITH_ENGINE TArray<FName> ActualFormatsToSave; if (!Ar.CookingTarget()->IsServerOnly()) { // for now we only support one format per wav FName Format = Ar.CookingTarget()->GetWaveFormat(this); GetCompressedData(Format); // Get the data from the DDC or build it ActualFormatsToSave.Add(Format); } CompressedFormatData.Serialize(Ar, this, &ActualFormatsToSave); #endif } else { CompressedFormatData.Serialize(Ar, this); } } } else { // only save the raw data for non-cooked packages RawData.Serialize( Ar, this ); } Ar << CompressedDataGuid; if (IsStreaming()) { if (bCooked) { // only cook/load streaming data if it's supported if (bSupportsStreaming) { SerializeCookedPlatformData(Ar); } } #if WITH_EDITORONLY_DATA if (Ar.IsLoading() && !Ar.IsTransacting() && !bCooked && !GetOutermost()->HasAnyPackageFlags(PKG_ReloadingForCooker)) { BeginCachePlatformData(); } #endif // #if WITH_EDITORONLY_DATA } }
void USoundWave::Serialize( FArchive& Ar ) { Super::Serialize( Ar ); bool bCooked = Ar.IsCooking(); Ar << bCooked; if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogAudio, Fatal, TEXT("This platform requires cooked packages, and audio data was not cooked into %s."), *GetFullName()); } if (Ar.IsCooking()) { CompressionName = Ar.CookingTarget()->GetWaveFormat(this); } if (Ar.UE4Ver() >= VER_UE4_SOUND_COMPRESSION_TYPE_ADDED) { Ar << CompressionName; } if (bCooked) { // Only want to cook/load full data if we don't support streaming if (!IsStreaming() || (Ar.IsLoading() && !FPlatformProperties::SupportsAudioStreaming()) || (Ar.IsCooking() && !Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::AudioStreaming))) { if (Ar.IsCooking()) { #if WITH_ENGINE TArray<FName> ActualFormatsToSave; if (!Ar.CookingTarget()->IsServerOnly()) { // for now we only support one format per wav FName Format = Ar.CookingTarget()->GetWaveFormat(this); GetCompressedData(Format); // Get the data from the DDC or build it ActualFormatsToSave.Add(Format); } CompressedFormatData.Serialize(Ar, this, &ActualFormatsToSave); #endif } else { CompressedFormatData.Serialize(Ar, this); } } } else { // only save the raw data for non-cooked packages RawData.Serialize( Ar, this ); } Ar << CompressedDataGuid; if (IsStreaming()) { if (bCooked) { // only cook/load streaming data if it's supported if ((Ar.IsLoading() && FPlatformProperties::SupportsAudioStreaming()) || (Ar.IsCooking() && Ar.CookingTarget()->SupportsFeature(ETargetPlatformFeatures::AudioStreaming))) { SerializeCookedPlatformData(Ar); } } #if WITH_EDITORONLY_DATA if (Ar.IsLoading() && !Ar.IsTransacting() && !bCooked && !(GetOutermost()->PackageFlags & PKG_ReloadingForCooker)) { BeginCachePlatformData(); } #endif // #if WITH_EDITORONLY_DATA } }
/** * Serialize function used to serialize this bulk data structure. * * @param Ar Archive to serialize with * @param Owner Object owning the bulk data * @param Idx Index of bulk data item being serialized */ void FUntypedBulkData::Serialize( FArchive& Ar, UObject* Owner, int32 Idx ) { check( LockStatus == LOCKSTATUS_Unlocked ); if(Ar.IsTransacting()) { // Special case for transacting bulk data arrays. // constructing the object during load will save it to the transaction buffer. If it tries to load the bulk data now it will try to break it. bool bActuallySave = Ar.IsSaving() && (!Owner || !Owner->HasAnyFlags(RF_NeedLoad)); Ar << bActuallySave; if (bActuallySave) { if(Ar.IsLoading()) { // Flags for bulk data. Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // Allocate bulk data. check(bShouldFreeOnEmpty); BulkData = FMemory::Realloc( BulkData, GetBulkDataSize() ); // Deserialize bulk data. SerializeBulkData( Ar, BulkData ); } else if(Ar.IsSaving()) { // Flags for bulk data. Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // Don't attempt to load or serialize BulkData if the current size is 0. // This could be a newly constructed BulkData that has not yet been loaded, // and allocating 0 bytes now will cause a crash when we load. if (GetBulkDataSize() > 0) { // Make sure bulk data is loaded. MakeSureBulkDataIsLoaded(); // Serialize bulk data. SerializeBulkData(Ar, BulkData); } } } } else if( Ar.IsPersistent() && !Ar.IsObjectReferenceCollector() && !Ar.ShouldSkipBulkData() ) { #if TRACK_BULKDATA_USE FThreadSafeBulkDataToObjectMap::Get().Add( this, Owner ); #endif // Offset where the bulkdata flags are stored int64 SavedBulkDataFlagsPos = Ar.Tell(); Ar << BulkDataFlags; // Number of elements in array. Ar << ElementCount; // We're loading from the persistent archive. if( Ar.IsLoading() ) { Filename = TEXT(""); // @todo when Landscape (and others?) only Lock/Unlock once, we can enable this if (false) // FPlatformProperties::RequiresCookedData()) { // Bulk data that is being serialized via seekfree loading is single use only. This allows us // to free the memory as e.g. the bulk data won't be attached to an archive in the case of // seek free loading. BulkDataFlags |= BULKDATA_SingleUse; } // Size on disk, which in the case of compression is != GetBulkDataSize() Ar << BulkDataSizeOnDisk; Ar << BulkDataOffsetInFile; // fix up the file offset if (Owner != NULL && Owner->GetLinker()) { BulkDataOffsetInFile += Owner->GetLinker()->Summary.BulkDataStartOffset; } // determine whether the payload is stored inline or at the end of the file bool bPayloadInline = !(BulkDataFlags&BULKDATA_PayloadAtEndOfFile); // check( (bPayloadInline && BulkDataOffsetInFile == Ar.Tell()) || // (!bPayloadInline && BulkDataOffsetInFile > Ar.Tell())); // We're allowing defered serialization. if( Ar.IsAllowingLazyLoading() && Owner != NULL) { Linker = Owner->GetLinker(); #if WITH_EDITOR check(Linker); Ar.AttachBulkData( Owner, this ); AttachedAr = &Ar; #else check(Linker.IsValid()); Filename = Linker->Filename; #endif // WITH_EDITOR // only skip over payload, if it's stored inline if (bPayloadInline) { Ar.Seek( Ar.Tell() + BulkDataSizeOnDisk ); } } // Serialize the bulk data right away. else { // memory for bulk data can come from preallocated GPU-accessible resource memory or default to system memory BulkData = GetBulkDataResourceMemory(Owner,Idx); if( !BulkData ) { BulkData = FMemory::Realloc( BulkData, GetBulkDataSize() ); } if (bPayloadInline) { // if the payload is stored inline, just serialize it SerializeBulkData( Ar, BulkData ); } else { // if the payload is NOT stored inline ... // store the current file offset int64 CurOffset = Ar.Tell(); // seek to the location in the file where the payload is stored Ar.Seek(BulkDataOffsetInFile); // serialize the payload SerializeBulkData( Ar, BulkData ); // seek to the location we came from Ar.Seek(CurOffset); } } } // We're saving to the persistent archive. else if( Ar.IsSaving() ) { // check if we save the package compressed UPackage* Pkg = Owner ? dynamic_cast<UPackage*>(Owner->GetOutermost()) : nullptr; if (Pkg && !!(Pkg->PackageFlags & PKG_StoreCompressed) ) { ECompressionFlags BaseCompressionMethod = COMPRESS_Default; if (Ar.IsCooking()) { BaseCompressionMethod = Ar.CookingTarget()->GetBaseCompressionMethod(); } StoreCompressedOnDisk(BaseCompressionMethod); } // Remove single element serialization requirement before saving out bulk data flags. BulkDataFlags &= ~BULKDATA_ForceSingleElementSerialization; // Make sure bulk data is loaded. MakeSureBulkDataIsLoaded(); // Only serialize status information if wanted. int64 SavedBulkDataSizeOnDiskPos = INDEX_NONE; int64 SavedBulkDataOffsetInFilePos = INDEX_NONE; // Keep track of position we are going to serialize placeholder BulkDataSizeOnDisk. SavedBulkDataSizeOnDiskPos = Ar.Tell(); BulkDataSizeOnDisk = INDEX_NONE; // And serialize the placeholder which is going to be overwritten later. Ar << BulkDataSizeOnDisk; // Keep track of position we are going to serialize placeholder BulkDataOffsetInFile. SavedBulkDataOffsetInFilePos = Ar.Tell(); BulkDataOffsetInFile = INDEX_NONE; // And serialize the placeholder which is going to be overwritten later. Ar << BulkDataOffsetInFile; // try to get the linkersave object ULinkerSave* LinkerSave = dynamic_cast<ULinkerSave*>(Ar.GetLinker()); // determine whether we are going to store the payload inline or not. bool bStoreInline = !!(BulkDataFlags&BULKDATA_ForceInlinePayload) || LinkerSave == NULL; if (!bStoreInline) { // set the flag indicating where the payload is stored BulkDataFlags |= BULKDATA_PayloadAtEndOfFile; // with no LinkerSave we have to store the data inline check(LinkerSave != NULL); // add the bulkdata storage info object to the linkersave int32 Index = LinkerSave->BulkDataToAppend.AddZeroed(1); ULinkerSave::FBulkDataStorageInfo& BulkStore = LinkerSave->BulkDataToAppend[Index]; BulkStore.BulkDataOffsetInFilePos = SavedBulkDataOffsetInFilePos; BulkStore.BulkDataSizeOnDiskPos = SavedBulkDataSizeOnDiskPos; BulkStore.BulkData = this; // Serialize bulk data into the storage info BulkDataSizeOnDisk = -1; } else { // set the flag indicating where the payload is stored BulkDataFlags &= ~BULKDATA_PayloadAtEndOfFile; int64 SavedBulkDataStartPos = Ar.Tell(); // Serialize bulk data. SerializeBulkData( Ar, BulkData ); // store the payload endpos int64 SavedBulkDataEndPos = Ar.Tell(); checkf(SavedBulkDataStartPos >= 0 && SavedBulkDataEndPos >= 0, TEXT("Bad archive positions for bulkdata. StartPos=%d EndPos=%d"), SavedBulkDataStartPos, SavedBulkDataEndPos); BulkDataSizeOnDisk = SavedBulkDataEndPos - SavedBulkDataStartPos; BulkDataOffsetInFile = SavedBulkDataStartPos; } // store current file offset before seeking back int64 CurrentFileOffset = Ar.Tell(); // Seek back and overwrite the flags Ar.Seek(SavedBulkDataFlagsPos); Ar << BulkDataFlags; // Seek back and overwrite placeholder for BulkDataSizeOnDisk Ar.Seek( SavedBulkDataSizeOnDiskPos ); Ar << BulkDataSizeOnDisk; // Seek back and overwrite placeholder for BulkDataOffsetInFile Ar.Seek( SavedBulkDataOffsetInFilePos ); Ar << BulkDataOffsetInFile; // Seek to the end of written data so we don't clobber any data in subsequent write // operations Ar.Seek(CurrentFileOffset); } } }
void UReflectionCaptureComponent::Serialize(FArchive& Ar) { Super::Serialize(Ar); bool bCooked = false; if (Ar.UE4Ver() >= VER_UE4_REFLECTION_CAPTURE_COOKING) { bCooked = Ar.IsCooking(); // Save a bool indicating whether this is cooked data // This is needed when loading cooked data, to know to serialize differently Ar << bCooked; } if (FPlatformProperties::RequiresCookedData() && !bCooked && Ar.IsLoading()) { UE_LOG(LogMaterial, Fatal, TEXT("This platform requires cooked packages, and this reflection capture does not contain cooked data %s."), *GetName()); } if (bCooked) { static FName FullHDR(TEXT("FullHDR")); static FName EncodedHDR(TEXT("EncodedHDR")); // Saving for cooking path if (Ar.IsCooking()) { // Get all the reflection capture formats that the target platform wants TArray<FName> Formats; Ar.CookingTarget()->GetReflectionCaptureFormats(Formats); int32 NumFormats = Formats.Num(); Ar << NumFormats; for (int32 FormatIndex = 0; FormatIndex < NumFormats; FormatIndex++) { FName CurrentFormat = Formats[FormatIndex]; Ar << CurrentFormat; if (CurrentFormat == FullHDR) { // FullHDRDerivedData would have been set in PostLoad during cooking if it exists in the DDC // Can't generate it if missing, since that requires rendering the scene bool bValid = FullHDRDerivedData != NULL; Ar << bValid; if (bValid) { Ar << FullHDRDerivedData->CompressedCapturedData; } } else { check(CurrentFormat == EncodedHDR); TRefCountPtr<FReflectionCaptureEncodedHDRDerivedData> EncodedHDRData; // FullHDRDerivedData would have been set in PostLoad during cooking if it exists in the DDC // Generate temporary encoded HDR data for saving if (FullHDRDerivedData != NULL) { EncodedHDRData = FReflectionCaptureEncodedHDRDerivedData::GenerateEncodedHDRData(*FullHDRDerivedData, StateId, Brightness); } bool bValid = EncodedHDRData != NULL; Ar << bValid; if (bValid) { Ar << EncodedHDRData->CapturedData; } else if (!IsTemplate()) { // Temporary warning until the cooker can do scene captures itself in the case of missing DDC UE_LOG(LogMaterial, Warning, TEXT("Reflection capture requires encoded HDR data but none was found in the DDC! This reflection will be black. Fix by loading the map in the editor once. %s."), *GetFullName()); } } } } else { // Loading cooked data path int32 NumFormats = 0; Ar << NumFormats; for (int32 FormatIndex = 0; FormatIndex < NumFormats; FormatIndex++) { FName CurrentFormat; Ar << CurrentFormat; bool bValid = false; Ar << bValid; if (bValid) { if (CurrentFormat == FullHDR) { FullHDRDerivedData = new FReflectionCaptureFullHDRDerivedData(); Ar << FullHDRDerivedData->CompressedCapturedData; } else { check(CurrentFormat == EncodedHDR); EncodedHDRDerivedData = new FReflectionCaptureEncodedHDRDerivedData(); Ar << EncodedHDRDerivedData->CapturedData; } } else if (CurrentFormat == EncodedHDR) { // Temporary warning until the cooker can do scene captures itself in the case of missing DDC UE_LOG(LogMaterial, Error, TEXT("Reflection capture was loaded without any valid capture data and will be black. This can happen if the DDC was not up to date during cooking. Load the map in the editor once before cooking to fix. %s."), *GetFullName()); } } } } }