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 UAnimGraphNode_BoneDrivenController::Serialize(FArchive& Ar)
{
	Super::Serialize(Ar);

	Ar.UsingCustomVersion(FAnimationCustomVersion::GUID);

	const int32 AnimVersion = Ar.CustomVer(FAnimationCustomVersion::GUID);

	if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerRemapping)
	{
		if (AnimVersion < FAnimationCustomVersion::BoneDrivenControllerMatchingMaya)
		{
			// The node used to be able to only drive a single component rather than a selection of components
			Node.ConvertTargetComponentToBits();

			// The old definition of range was clamping the output, rather than the input
			if (Node.bUseRange && !FMath::IsNearlyZero(Node.Multiplier))
			{
				// Before: Output = clamp(Input * Multipler)
				// After: Output = clamp(Input) * Multiplier
				Node.RangeMin /= Node.Multiplier;
				Node.RangeMax /= Node.Multiplier;
			}
		}

		Node.RemappedMin = Node.RangeMin;
		Node.RemappedMax = Node.RangeMax;
	}
}
void UPaperFlipbookComponent::Serialize(FArchive& Ar)
{
	Super::Serialize(Ar);

	Ar.UsingCustomVersion(FPaperCustomVersion::GUID);
}
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
	}
}