Please help, project suddenly crashing on startup, trying to provide updates for Megagrant App

This project has been working great for 3 months with minimal crashes. I closed the project yesterday after working on it all day with no issues. Today, I went to try to open it and it randomly crashes and shows an error message that I’ve attached below.

I tried verifying and reinstalling the engine but I get the same crash. I have a complete backup from 5 days ago and I have builds from every day since then, but I’m unsure if I can get the editor files back from the built game.

We could resort to the version from 5 days ago, but we’ve accomplished so much since then working around the clock and it would really set us back to go back to that version. I can provide any dump files, just not sure what is needed. Thanks very much in advance, this is a huge setback for us.

archive.cpp

// Copyright Epic Games, Inc. All Rights Reserved.

#include "Serialization/Archive.h"
#include "Serialization/ArchiveProxy.h"
#include "Math/UnrealMathUtility.h"
#include "HAL/UnrealMemory.h"
#include "Containers/Array.h"
#include "Containers/UnrealString.h"
#include "UObject/NameTypes.h"
#include "Logging/LogMacros.h"
#include "Misc/Parse.h"
#include "UObject/ObjectVersion.h"
#include "Serialization/NameAsStringProxyArchive.h"
#include "Misc/CommandLine.h"
#include "Internationalization/Text.h"
#include "Stats/StatsMisc.h"
#include "Stats/Stats.h"
#include "Async/AsyncWork.h"
#include "Serialization/CustomVersion.h"
#include "Misc/EngineVersion.h"
#include "Misc/NetworkVersion.h"
#include "Interfaces/ITargetPlatform.h"
#include "Serialization/CompressedChunkInfo.h"
#include "Serialization/ArchiveSerializedPropertyChain.h"

PRAGMA_DISABLE_UNSAFE_TYPECAST_WARNINGS

namespace ArchiveUtil
{

template<typename T>
FArchive& SerializeByteOrderSwapped(FArchive& Ar, T& Value)
{
	static_assert(!TIsSigned<T>::Value, "To reduce the number of template instances, cast 'Value' to a uint16&, uint32& or uint64& prior to the call.");

	if (Ar.IsLoading())
	{
		// Read and swap.
		Ar.Serialize(&Value, sizeof(T));
		Value = ByteSwap(Value);
	}
	else // Saving
	{
		// Swap and write.
		T SwappedValue = ByteSwap(Value);
		Ar.Serialize(&SwappedValue, sizeof(T));
	}
	return Ar;
}

} // namespace ArchiveUtil


/*-----------------------------------------------------------------------------
	FArchive implementation.
-----------------------------------------------------------------------------*/

FArchiveState::FArchiveState()
{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	ActiveFPLB = &InlineFPLB;
#endif
	SerializedPropertyChain = nullptr;

#if USE_STABLE_LOCALIZATION_KEYS
	LocalizationNamespacePtr = nullptr;
#endif // USE_STABLE_LOCALIZATION_KEYS

	Reset();
}

FArchiveState::FArchiveState(const FArchiveState& ArchiveToCopy)
{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	ActiveFPLB = &InlineFPLB;
#endif
#if USE_STABLE_LOCALIZATION_KEYS
	LocalizationNamespacePtr = nullptr;
#endif // USE_STABLE_LOCALIZATION_KEYS

	CopyTrivialFArchiveStatusMembers(ArchiveToCopy);

	SerializedPropertyChain = nullptr;
	SetSerializedPropertyChain(ArchiveToCopy.SerializedPropertyChain, ArchiveToCopy.SerializedProperty);

	// Don't know why this is set to false, but this is what the original copying code did
	ArIsFilterEditorOnly  = false;

	bCustomVersionsAreReset = ArchiveToCopy.bCustomVersionsAreReset;
	if (ArchiveToCopy.CustomVersionContainer)
	{
		CustomVersionContainer = new FCustomVersionContainer(*ArchiveToCopy.CustomVersionContainer);
	}
	else
	{
		CustomVersionContainer = nullptr;
	}
}

FArchiveState& FArchiveState::operator=(const FArchiveState& ArchiveToCopy)
{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	ActiveFPLB = &InlineFPLB;
	ActiveFPLB->Reset();
#endif
	CopyTrivialFArchiveStatusMembers(ArchiveToCopy);

	SetSerializedPropertyChain(ArchiveToCopy.SerializedPropertyChain, ArchiveToCopy.SerializedProperty);

	// Don't know why this is set to false, but this is what the original copying code did
	ArIsFilterEditorOnly  = false;

	bCustomVersionsAreReset = ArchiveToCopy.bCustomVersionsAreReset;
	if (ArchiveToCopy.CustomVersionContainer)
	{
		if (!CustomVersionContainer)
		{
			CustomVersionContainer = new FCustomVersionContainer(*ArchiveToCopy.CustomVersionContainer);
		}
		else
		{
			*CustomVersionContainer = *ArchiveToCopy.CustomVersionContainer;
		}
	}
	else if (CustomVersionContainer)
	{
		delete CustomVersionContainer;
		CustomVersionContainer = nullptr;
	}

	return *this;
}

FArchiveState::~FArchiveState()
{
	checkf(NextProxy == nullptr, TEXT("Archive destroyed before its proxies"));

	delete CustomVersionContainer;

	delete SerializedPropertyChain;

#if USE_STABLE_LOCALIZATION_KEYS
	delete LocalizationNamespacePtr;
#endif // USE_STABLE_LOCALIZATION_KEYS
}

void FArchiveState::Reset()
{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	ActiveFPLB->Reset();
#endif
	ArUE4Ver							= GPackageFileUE4Version;
	ArLicenseeUE4Ver					= GPackageFileLicenseeUE4Version;
	ArEngineVer							= FEngineVersion::Current();
	ArEngineNetVer						= FNetworkVersion::GetEngineNetworkProtocolVersion();
	ArGameNetVer						= FNetworkVersion::GetGameNetworkProtocolVersion();
	ArIsLoading							= false;
	ArIsSaving							= false;
	ArIsTransacting						= false;
	ArIsTextFormat						= false;
	ArWantBinaryPropertySerialization	= false;
	ArUseUnversionedPropertySerialization = false;
	ArForceUnicode						= false;
	ArIsPersistent						= false;
	ArIsError							= false;
	ArIsCriticalError					= false;
	ArContainsCode						= false;
	ArContainsMap						= false;
	ArRequiresLocalizationGather		= false;
	ArForceByteSwapping					= false;
	ArSerializingDefaults				= false;
	ArIgnoreArchetypeRef				= false;
	ArNoDelta							= false;
	ArNoIntraPropertyDelta				= false;
	ArIgnoreOuterRef					= false;
	ArIgnoreClassGeneratedByRef			= false;
	ArIgnoreClassRef					= false;
	ArAllowLazyLoading					= false;
	ArIsObjectReferenceCollector		= false;
	ArIsModifyingWeakAndStrongReferences= false;
	ArIsCountingMemory					= false;
	ArPortFlags							= 0;
	ArShouldSkipBulkData				= false;
	ArMaxSerializeSize					= 0;
	ArIsFilterEditorOnly				= false;
	ArIsSaveGame						= false;
	ArIsNetArchive						= false;
	ArCustomPropertyList				= nullptr;
	ArUseCustomPropertyList				= false;
	CookingTargetPlatform				= nullptr;
	SerializedProperty					= nullptr;

	delete SerializedPropertyChain;
	SerializedPropertyChain = nullptr;

#if USE_STABLE_LOCALIZATION_KEYS
	SetBaseLocalizationNamespace(FString());
#endif // USE_STABLE_LOCALIZATION_KEYS

#if WITH_EDITOR
	ArDebugSerializationFlags			= 0;
#endif

	// Reset all custom versions to the current registered versions.
	ResetCustomVersions();
}

void FArchiveState::CopyTrivialFArchiveStatusMembers(const FArchiveState& ArchiveToCopy)
{
	ArUE4Ver                             = ArchiveToCopy.ArUE4Ver;
	ArLicenseeUE4Ver                     = ArchiveToCopy.ArLicenseeUE4Ver;
	ArEngineVer                          = ArchiveToCopy.ArEngineVer;
	ArEngineNetVer                       = ArchiveToCopy.ArEngineNetVer;
	ArGameNetVer                         = ArchiveToCopy.ArGameNetVer;
	ArIsLoading                          = ArchiveToCopy.ArIsLoading;
	ArIsSaving                           = ArchiveToCopy.ArIsSaving;
	ArIsTransacting                      = ArchiveToCopy.ArIsTransacting;
	ArIsTextFormat                       = ArchiveToCopy.ArIsTextFormat;
	ArWantBinaryPropertySerialization    = ArchiveToCopy.ArWantBinaryPropertySerialization;
	ArUseUnversionedPropertySerialization = ArchiveToCopy.ArUseUnversionedPropertySerialization;
	ArForceUnicode                       = ArchiveToCopy.ArForceUnicode;
	ArIsPersistent                       = ArchiveToCopy.ArIsPersistent;
	ArIsError                            = ArchiveToCopy.ArIsError;
	ArIsCriticalError                    = ArchiveToCopy.ArIsCriticalError;
	ArContainsCode                       = ArchiveToCopy.ArContainsCode;
	ArContainsMap                        = ArchiveToCopy.ArContainsMap;
	ArRequiresLocalizationGather         = ArchiveToCopy.ArRequiresLocalizationGather;
	ArForceByteSwapping                  = ArchiveToCopy.ArForceByteSwapping;
	ArSerializingDefaults                = ArchiveToCopy.ArSerializingDefaults;
	ArIgnoreArchetypeRef                 = ArchiveToCopy.ArIgnoreArchetypeRef;
	ArNoDelta                            = ArchiveToCopy.ArNoDelta;
	ArNoIntraPropertyDelta               = ArchiveToCopy.ArNoIntraPropertyDelta;
	ArIgnoreOuterRef                     = ArchiveToCopy.ArIgnoreOuterRef;
	ArIgnoreClassGeneratedByRef          = ArchiveToCopy.ArIgnoreClassGeneratedByRef;
	ArIgnoreClassRef                     = ArchiveToCopy.ArIgnoreClassRef;
	ArAllowLazyLoading                   = ArchiveToCopy.ArAllowLazyLoading;
	ArIsObjectReferenceCollector         = ArchiveToCopy.ArIsObjectReferenceCollector;
	ArIsModifyingWeakAndStrongReferences = ArchiveToCopy.ArIsModifyingWeakAndStrongReferences;
	ArIsCountingMemory                   = ArchiveToCopy.ArIsCountingMemory;
	ArPortFlags                          = ArchiveToCopy.ArPortFlags;
	ArShouldSkipBulkData                 = ArchiveToCopy.ArShouldSkipBulkData;
	ArMaxSerializeSize                   = ArchiveToCopy.ArMaxSerializeSize;
	ArIsFilterEditorOnly                 = ArchiveToCopy.ArIsFilterEditorOnly;
	ArIsSaveGame                         = ArchiveToCopy.ArIsSaveGame;
	ArIsNetArchive                       = ArchiveToCopy.ArIsNetArchive;
	ArCustomPropertyList                 = ArchiveToCopy.ArCustomPropertyList;
	ArUseCustomPropertyList              = ArchiveToCopy.ArUseCustomPropertyList;
	CookingTargetPlatform                = ArchiveToCopy.CookingTargetPlatform;
	SerializedProperty					 = ArchiveToCopy.SerializedProperty;
#if USE_STABLE_LOCALIZATION_KEYS
	SetBaseLocalizationNamespace(ArchiveToCopy.GetBaseLocalizationNamespace());
#endif // USE_STABLE_LOCALIZATION_KEYS
}


void FArchiveState::LinkProxy(FArchiveState& Inner, FArchiveState& Proxy)
{
	Proxy.NextProxy = Inner.NextProxy;
	Inner.NextProxy = &Proxy;
}

void FArchiveState::UnlinkProxy(FArchiveState& Inner, FArchiveState& Proxy)
{
	FArchiveState* Prev = &Inner;
	while (Prev->NextProxy != &Proxy)
	{
		Prev = Prev->NextProxy;
		checkf(Prev, TEXT("Proxy link not found - likely  lifetime violation"));
	}

	Prev->NextProxy = Proxy.NextProxy;
	Proxy.NextProxy = nullptr;
}

template<typename T>
FORCEINLINE void FArchiveState::ForEachState(T Func)
{
	FArchiveState& RootState = GetInnermostState();
	Func(RootState);

	for (FArchiveState* Proxy = RootState.NextProxy; Proxy; Proxy = Proxy->NextProxy)
	{
		Func(*Proxy);
	}
}

void FArchiveState::SetArchiveState(const FArchiveState& InState)
{
	ForEachState([&InState](FArchiveState& State) { State = InState; });
}

void FArchiveState::SetError()
{
	ForEachState([](FArchiveState& State) { State.ArIsError = true; });
}

void FArchiveState::SetCriticalError()
{
	ForEachState([](FArchiveState& State) { State.ArIsError = State.ArIsCriticalError = true; });
}

void FArchiveState::ClearError()
{
	ForEachState([](FArchiveState& State) { State.ArIsError = false; });
}

/**
 * Returns the name of the Archive.  Useful for getting the name of the package a struct or object
 * is in when a loading error occurs.
 *
 * This is overridden for the specific Archive Types
 **/
FString FArchiveState::GetArchiveName() const
{
	return TEXT("FArchive");
}

void FArchiveState::GetSerializedPropertyChain(TArray<class FProperty*>& OutProperties) const
{
	if (SerializedPropertyChain)
	{
		const int32 NumProperties = SerializedPropertyChain->GetNumProperties();
		OutProperties.Reserve(NumProperties);

		for (int32 PropertyIndex = 0; PropertyIndex < NumProperties; ++PropertyIndex)
		{
			OutProperties.Add(SerializedPropertyChain->GetPropertyFromStack(PropertyIndex));
		}
	}
}

void FArchiveState::SetSerializedPropertyChain(const FArchiveSerializedPropertyChain* InSerializedPropertyChain, class FProperty* InSerializedPropertyOverride)
{
	if (InSerializedPropertyChain && InSerializedPropertyChain->GetNumProperties() > 0)
	{
		if (!SerializedPropertyChain)
		{
			SerializedPropertyChain = new FArchiveSerializedPropertyChain();
		}
		*SerializedPropertyChain = *InSerializedPropertyChain;
	}
	else
	{
		delete SerializedPropertyChain;
		SerializedPropertyChain = nullptr;
	}

	if (InSerializedPropertyOverride)
	{
		SerializedProperty = InSerializedPropertyOverride;
	}
	else if (SerializedPropertyChain && SerializedPropertyChain->GetNumProperties() > 0)
	{
		SerializedProperty = SerializedPropertyChain->GetPropertyFromStack(0);
	}
	else
	{
		SerializedProperty = nullptr;
	}
}

void FArchive::PushSerializedProperty(class FProperty* InProperty, const bool bIsEditorOnlyProperty)
{
	if (InProperty)
	{
		// Push this property into the chain
		if (!SerializedPropertyChain)
		{
			SerializedPropertyChain = new FArchiveSerializedPropertyChain();
		}
		SerializedPropertyChain->PushProperty(InProperty, bIsEditorOnlyProperty);

		// Update the serialized property pointer with the new head
		SerializedProperty = InProperty;
	}
}

void FArchive::PopSerializedProperty(class FProperty* InProperty, const bool bIsEditorOnlyProperty)
{
	if (InProperty)
	{
		// Pop this property from the chain
		check(SerializedPropertyChain);
		SerializedPropertyChain->PopProperty(InProperty, bIsEditorOnlyProperty);

		// Update the serialized property pointer with the new head
		if (SerializedPropertyChain->GetNumProperties() > 0)
		{
			SerializedProperty = SerializedPropertyChain->GetPropertyFromStack(0);
		}
		else
		{
			SerializedProperty = nullptr;
		}
	}
}

#if WITH_EDITORONLY_DATA
bool FArchiveState::IsEditorOnlyPropertyOnTheStack() const
{
	return SerializedPropertyChain && SerializedPropertyChain->HasEditorOnlyProperty();
}
#endif

#if USE_STABLE_LOCALIZATION_KEYS
void FArchiveState::SetBaseLocalizationNamespace(const FString& InLocalizationNamespace)
{
	if (InLocalizationNamespace.IsEmpty())
	{
		delete LocalizationNamespacePtr;
		LocalizationNamespacePtr = nullptr;
	}
	else
	{
		if (!LocalizationNamespacePtr)
		{
			LocalizationNamespacePtr = new FString();
		}
		*LocalizationNamespacePtr = InLocalizationNamespace;
	}
}
FString FArchiveState::GetBaseLocalizationNamespace() const
{
	return LocalizationNamespacePtr ? *LocalizationNamespacePtr : FString();
}
void FArchiveState::SetLocalizationNamespace(const FString& InLocalizationNamespace)
{
	SetBaseLocalizationNamespace(InLocalizationNamespace);
}
FString FArchiveState::GetLocalizationNamespace() const
{
	return GetBaseLocalizationNamespace();
}
#endif // USE_STABLE_LOCALIZATION_KEYS

#if WITH_EDITOR
FArchive::FScopeAddDebugData::FScopeAddDebugData(FArchive& InAr, const FName& DebugData) : Ar(InAr)
{
	Ar.PushDebugDataString(DebugData);
}

void FArchive::PushDebugDataString(const FName& DebugData)
{
}
#endif

FArchive& FArchive::operator<<( FText& Value )
{
	FText::SerializeText(*this, Value);
	return *this;
}

FArchive& FArchive::operator<<(struct FLazyObjectPtr& Value)
{
	// The base FArchive does not implement this method. Use FArchiveUObject instead.
	UE_LOG(LogSerialization, Fatal, TEXT("FArchive does not support FLazyObjectPtr serialization. Use FArchiveUObject instead."));
	return *this;
}

FArchive& FArchive::operator<<(struct FSoftObjectPtr& Value)
{
	// The base FArchive does not implement this method. Use FArchiveUObject instead.
	UE_LOG(LogSerialization, Fatal, TEXT("FArchive does not support FSoftObjectPtr serialization. Use FArchiveUObject instead."));
	return *this;
}

FArchive& FArchive::operator<<(struct FSoftObjectPath& Value)
{
	// The base FArchive does not implement this method. Use FArchiveUObject instead.
	UE_LOG(LogSerialization, Fatal, TEXT("FArchive does not support FSoftObjectPath serialization. Use FArchiveUObject instead."));
	return *this;
}

FArchive& FArchive::operator<<(struct FWeakObjectPtr& Value)
{
	// The base FArchive does not implement this method. Use FArchiveUObject instead.
	UE_LOG(LogSerialization, Fatal, TEXT("FArchive does not support FWeakObjectPtr serialization. Use FArchiveUObject instead."));
	return *this;
}

#if WITH_EDITOR
void FArchive::SerializeBool( bool& D )
{
	// Serialize bool as if it were UBOOL (legacy, 32 bit int).
	uint32 OldUBoolValue;
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	const uint8 * RESTRICT Src = this->ActiveFPLB->StartFastPathLoadBuffer;
	if (Src + sizeof(uint32) <= this->ActiveFPLB->EndFastPathLoadBuffer)
	{
		OldUBoolValue = FPlatformMemory::ReadUnaligned<uint32>(Src);
		this->ActiveFPLB->StartFastPathLoadBuffer += 4;
	}
	else
#endif
	{
		OldUBoolValue = D ? 1 : 0;
		this->Serialize(&OldUBoolValue, sizeof(OldUBoolValue));
	}
	if (OldUBoolValue > 1)
	{
		UE_LOG(LogSerialization, Error, TEXT("Invalid boolean encountered while reading archive %s - stream is most likely corrupted."), *GetArchiveName());

		this->SetError();
	}
	D = !!OldUBoolValue;
}
#endif

const FCustomVersionContainer& FArchiveState::GetCustomVersions() const
{
	if (!CustomVersionContainer)
	{
		CustomVersionContainer = new FCustomVersionContainer;
	}

	if (bCustomVersionsAreReset)
	{
		bCustomVersionsAreReset = false;

		// If the archive is for reading then we want to use currently registered custom versions, otherwise we expect
		// serialization code to use UsingCustomVersion to populate the container.
		if (this->IsLoading())
		{
			*CustomVersionContainer = FCurrentCustomVersions::GetAll();
		}
		else
		{
			CustomVersionContainer->Empty();
		}
	}

	return *CustomVersionContainer;
}

void FArchiveState::SetCustomVersions(const FCustomVersionContainer& NewVersions)
{
	if (!CustomVersionContainer)
	{
		CustomVersionContainer = new FCustomVersionContainer(NewVersions);
	}
	else
	{
		*CustomVersionContainer = NewVersions;
	}
	bCustomVersionsAreReset = false;
}

void FArchiveState::ResetCustomVersions()
{
	bCustomVersionsAreReset = true;
}

void FArchive::UsingCustomVersion(const FGuid& Key)
{
	// If we're loading, we want to use the version that the archive was serialized with, not register a new one.
	if (IsLoading())
	{
		return;
	}

	FCustomVersion RegisteredVersion = FCurrentCustomVersions::Get(Key).GetValue();
	const_cast<FCustomVersionContainer&>(GetCustomVersions()).SetVersion(Key, RegisteredVersion.Version, RegisteredVersion.GetFriendlyName());
}

int32 FArchiveState::CustomVer(const FGuid& Key) const
{
	auto* CustomVersion = GetCustomVersions().GetVersion(Key);

	// If this fails, you have forgotten to make an Ar.UsingCustomVersion call
	// before serializing your custom version-dependent object.
	check(IsLoading() || CustomVersion);

	return CustomVersion ? CustomVersion->Version : -1;
}

void FArchiveState::SetCustomVersion(const FGuid& Key, int32 Version, FName FriendlyName)
{
	const_cast<FCustomVersionContainer&>(GetCustomVersions()).SetVersion(Key, Version, FriendlyName);
}

FString FArchiveProxy::GetArchiveName() const
{
	return InnerArchive.GetArchiveName();
}

#if USE_STABLE_LOCALIZATION_KEYS
void FArchiveProxy::SetLocalizationNamespace(const FString& InLocalizationNamespace)
{
	InnerArchive.SetLocalizationNamespace(InLocalizationNamespace);
}
FString FArchiveProxy::GetLocalizationNamespace() const
{
	return InnerArchive.GetLocalizationNamespace();
}
#endif // USE_STABLE_LOCALIZATION_KEYS

/**
 * Serialize the given FName as an FString
 */
FArchive& FNameAsStringProxyArchive::operator<<( class FName& N )
{
	if (IsLoading())
	{
		FString LoadedString;
		InnerArchive << LoadedString;
		N = FName(*LoadedString);
	}
	else
	{
		FString SavedString(N.ToString());
		InnerArchive << SavedString;
	}
	return *this;
}

/** Accumulative time spent in IsSaving portion of SerializeCompressed. */
CORE_API double GArchiveSerializedCompressedSavingTime = 0;



// MT compression disabled on console due to memory impact and lack of beneficial usage case.
#define WITH_MULTI_THREADED_COMPRESSION (WITH_EDITORONLY_DATA)
#if WITH_MULTI_THREADED_COMPRESSION
// Helper structure to keep information about async chunks that are in-flight.
class FAsyncCompressionChunk : public FNonAbandonableTask
{
public:
	/** Pointer to source (uncompressed) memory.								*/
	void* UncompressedBuffer;
	/** Pointer to destination (compressed) memory.								*/
	void* CompressedBuffer;
	/** Compressed size in bytes as passed to/ returned from compressor.		*/
	int32 CompressedSize;
	/** Uncompressed size in bytes as passed to compressor.						*/
	int32 UncompressedSize;
	/** Target platform for compressed data										*/
	int32 BitWindow;
	/** Format to compress with													*/
	FName CompressionFormat;
	/** Flags to control compression											*/
	ECompressionFlags Flags;

	/**
	 * Constructor, zeros everything
	 */
	FAsyncCompressionChunk()
		: UncompressedBuffer(0)
		, CompressedBuffer(0)
		, CompressedSize(0)
		, UncompressedSize(0)
		, BitWindow(DEFAULT_ZLIB_BIT_WINDOW)
		, CompressionFormat(NAME_Zlib)
		, Flags(COMPRESS_NoFlags)
	{
	}
	/**
	 * Performs the async compression
	 */
	void DoWork()
	{
		// upgrade old flag method
		if ((Flags & COMPRESS_DeprecatedFormatFlagsMask) != 0)
		{
			UE_LOG(LogSerialization, Warning, TEXT("Old style compression flags are being used with FAsyncCompressionChunk, please update any code using this!"));
			CompressionFormat = FCompression::GetCompressionFormatFromDeprecatedFlags(Flags);
		}

		// Compress from memory to memory.
		verify( FCompression::CompressMemory(CompressionFormat, CompressedBuffer, CompressedSize, UncompressedBuffer, UncompressedSize, Flags, BitWindow) );
	}

	FORCEINLINE TStatId GetStatId() const
	{
		RETURN_QUICK_DECLARE_CYCLE_STAT(FAsyncCompressionChunk, STATGROUP_ThreadPoolAsyncTasks);
	}
};
#endif		// WITH_MULTI_THREADED_COMPRESSION

void FArchive::SerializeCompressed(void* V, int64 Length, FName CompressionFormat, ECompressionFlags Flags, bool bTreatBufferAsFileReader)
{
	if( IsLoading() )
	{
		if (CompressionFormat == NAME_Zlib && FPlatformProperties::GetZlibReplacementFormat() != nullptr)
		{
			// use this platform's replacement format in case it's not zlib
			CompressionFormat = FPlatformProperties::GetZlibReplacementFormat();
		}

		// Serialize package file tag used to determine endianess.
		FCompressedChunkInfo PackageFileTag;
		PackageFileTag.CompressedSize	= 0;
		PackageFileTag.UncompressedSize	= 0;
		*this << PackageFileTag;
		bool bWasByteSwapped = PackageFileTag.CompressedSize != PACKAGE_FILE_TAG;

		// Read in base summary.
		FCompressedChunkInfo Summary;
		*this << Summary;

		bool bHeaderWasValid = true;

		if (bWasByteSwapped)
		{
			bHeaderWasValid = PackageFileTag.CompressedSize == PACKAGE_FILE_TAG_SWAPPED;
			if (bHeaderWasValid)
			{
				Summary.CompressedSize = BYTESWAP_ORDER64(Summary.CompressedSize);
				Summary.UncompressedSize = BYTESWAP_ORDER64(Summary.UncompressedSize);
				PackageFileTag.UncompressedSize = BYTESWAP_ORDER64(PackageFileTag.UncompressedSize);
			}
		}
		else
		{
			bHeaderWasValid = PackageFileTag.CompressedSize == PACKAGE_FILE_TAG; //-V547
		}

		if (!bHeaderWasValid)
		{
			UE_LOG(LogSerialization, Log, TEXT("ArchiveName: %s"), *GetArchiveName());
			UE_LOG(LogSerialization, Log, TEXT("Archive UE4 Version: %d"), UE4Ver());
			UE_LOG(LogSerialization, Log, TEXT("Archive Licensee Version: %d"), LicenseeUE4Ver());
			UE_LOG(LogSerialization, Log, TEXT("Position: %lld"), Tell());
			UE_LOG(LogSerialization, Log, TEXT("Read Size: %lld"), Length);
			UE_LOG(LogSerialization, Fatal, TEXT("BulkData compressed header read error. This package may be corrupt!"));
		}

		// Handle change in compression chunk size in backward compatible way.
		int64 LoadingCompressionChunkSize = PackageFileTag.UncompressedSize;
		if (LoadingCompressionChunkSize == PACKAGE_FILE_TAG)
		{
			LoadingCompressionChunkSize = LOADING_COMPRESSION_CHUNK_SIZE;
		}

		// Figure out how many chunks there are going to be based on uncompressed size and compression chunk size.
		int64	TotalChunkCount	= (Summary.UncompressedSize + LoadingCompressionChunkSize - 1) / LoadingCompressionChunkSize;
		
		// Allocate compression chunk infos and serialize them, keeping track of max size of compression chunks used.
		FCompressedChunkInfo*	CompressionChunks	= new FCompressedChunkInfo[TotalChunkCount];
		int64						MaxCompressedSize	= 0;
		for( int32 ChunkIndex=0; ChunkIndex<TotalChunkCount; ChunkIndex++ )
		{
			*this << CompressionChunks[ChunkIndex];
			if (bWasByteSwapped)
			{
				CompressionChunks[ChunkIndex].CompressedSize	= BYTESWAP_ORDER64( CompressionChunks[ChunkIndex].CompressedSize );
				CompressionChunks[ChunkIndex].UncompressedSize	= BYTESWAP_ORDER64( CompressionChunks[ChunkIndex].UncompressedSize );
			}
			MaxCompressedSize = FMath::Max( CompressionChunks[ChunkIndex].CompressedSize, MaxCompressedSize );
		}

		// Set up destination pointer and allocate memory for compressed chunk[s] (one at a time).
		uint8*	Dest				= (uint8*) V;
		void*	CompressedBuffer	= FMemory::Malloc( MaxCompressedSize );

		// Iterate over all chunks, serialize them into memory and decompress them directly into the destination pointer
		for( int64 ChunkIndex=0; ChunkIndex<TotalChunkCount; ChunkIndex++ )
		{
			const FCompressedChunkInfo& Chunk = CompressionChunks[ChunkIndex];
			// Read compressed data.
			Serialize( CompressedBuffer, Chunk.CompressedSize );
			// Decompress into dest pointer directly.
			bool bUncompressMemorySucceeded = FCompression::UncompressMemory( CompressionFormat, Dest, Chunk.UncompressedSize, CompressedBuffer, Chunk.CompressedSize, COMPRESS_NoFlags);
			verifyf(bUncompressMemorySucceeded, TEXT("Failed to uncompress data in %s. Check log for details."), *GetArchiveName());			// And advance it by read amount.
			Dest += Chunk.UncompressedSize;
		}

		// Free up allocated memory.
		FMemory::Free( CompressedBuffer );
		delete [] CompressionChunks;
	}
	else if( IsSaving() )
	{	
		SCOPE_SECONDS_COUNTER(GArchiveSerializedCompressedSavingTime);
		check( Length > 0 );

		// if there's a cooking target, and it wants to replace Zlib compression with another format, use it. When loading, 
		// the platform will replace Zlib with that format above
		if (CompressionFormat == NAME_Zlib && CookingTargetPlatform != nullptr)
		{
			// use the replacement format
			CompressionFormat = CookingTargetPlatform->GetZlibReplacementFormat();
		}

		// Serialize package file tag used to determine endianess in LoadCompressedData.
		FCompressedChunkInfo PackageFileTag;
		PackageFileTag.CompressedSize	= PACKAGE_FILE_TAG;
		PackageFileTag.UncompressedSize	= GSavingCompressionChunkSize;
		*this << PackageFileTag;

		// Figure out how many chunks there are going to be based on uncompressed size and compression chunk size.
		int64	TotalChunkCount	= (Length + GSavingCompressionChunkSize - 1) / GSavingCompressionChunkSize + 1;
		
		// Keep track of current position so we can later seek back and overwrite stub compression chunk infos.
		int64 StartPosition = Tell();

		// Allocate compression chunk infos and serialize them so we can later overwrite the data.
		FCompressedChunkInfo* CompressionChunks	= new FCompressedChunkInfo[TotalChunkCount];
		for( int64 ChunkIndex=0; ChunkIndex<TotalChunkCount; ChunkIndex++ )
		{
			*this << CompressionChunks[ChunkIndex];
		}

		// The uncompressd size is equal to the passed in length.
		CompressionChunks[0].UncompressedSize	= Length;
		// Zero initialize compressed size so we can update it during chunk compression.
		CompressionChunks[0].CompressedSize		= 0;

#if WITH_MULTI_THREADED_COMPRESSION

#define MAX_COMPRESSION_JOBS (16)
		// Don't scale more than 16x to avoid going overboard wrt temporary memory.
		FAsyncTask<FAsyncCompressionChunk> AsyncChunks[MAX_COMPRESSION_JOBS];

		// used to keep track of which job is the next one we need to retire
		int32 AsyncChunkIndex[MAX_COMPRESSION_JOBS]={0};

		static uint32 GNumUnusedThreads_SerializeCompressed = -1;
		if (GNumUnusedThreads_SerializeCompressed == (uint32)-1)
		{
			// one-time initialization
			GNumUnusedThreads_SerializeCompressed = 1;
			// if we should use all available cores then we want to compress with all
			if( FParse::Param(FCommandLine::Get(), TEXT("USEALLAVAILABLECORES")) == true )
			{
				GNumUnusedThreads_SerializeCompressed = 0;
			}
		}

		// Maximum number of concurrent async tasks we're going to kick off. This is based on the number of processors
		// available in the system.
		int32 MaxConcurrentAsyncChunks = FMath::Clamp<int32>( FPlatformMisc::NumberOfCores() - GNumUnusedThreads_SerializeCompressed, 1, MAX_COMPRESSION_JOBS );
		if (FParse::Param(FCommandLine::Get(), TEXT("MTCHILD")))
		{
			// throttle this back when doing MT cooks
			MaxConcurrentAsyncChunks = FMath::Min<int32>( MaxConcurrentAsyncChunks,4 );
		}

		// Number of chunks left to finalize.
		int64 NumChunksLeftToFinalize	= (Length + GSavingCompressionChunkSize - 1) / GSavingCompressionChunkSize;
		// Number of chunks left to kick off
		int64 NumChunksLeftToKickOff	= NumChunksLeftToFinalize;
		// Start at index 1 as first chunk info is summary.
		int64	CurrentChunkIndex		= 1;
		// Start at index 1 as first chunk info is summary.
		int64	RetireChunkIndex		= 1;
	
		// Number of bytes remaining to kick off compression for.
		int64 BytesRemainingToKickOff	= Length;
		// Pointer to src data if buffer is memory pointer, NULL if it's a FArchive.
		uint8* SrcBuffer = bTreatBufferAsFileReader ? NULL : (uint8*)V;

		check(!bTreatBufferAsFileReader || ((FArchive*)V)->IsLoading());
		check(NumChunksLeftToFinalize);

		// Loop while there is work left to do based on whether we have finalized all chunks yet.
		while( NumChunksLeftToFinalize )
		{
			// If true we are waiting for async tasks to complete and should wait to complete some
			// if there are no async tasks finishing this iteration.
			bool bNeedToWaitForAsyncTask = false;

			// Try to kick off async tasks if there are chunks left to kick off.
			if( NumChunksLeftToKickOff )
			{
				// Find free index based on looking at uncompressed size. We can't use the thread counter
				// for this as that might be a chunk ready for finalization.
				int32 FreeIndex = INDEX_NONE;
				for( int32 i=0; i<MaxConcurrentAsyncChunks; i++ )
				{
					if( !AsyncChunkIndex[i] )
					{
						FreeIndex = i;
						check(AsyncChunks[FreeIndex].IsIdle()); // this is not supposed to be in use
						break;
					}
				}

				// Kick off async compression task if we found a chunk for it.
				if( FreeIndex != INDEX_NONE )
				{
					FAsyncCompressionChunk& NewChunk = AsyncChunks[FreeIndex].GetTask();
					// 2 times the uncompressed size should be more than enough; the compressed data shouldn't be that much larger
					NewChunk.CompressedSize	= 2 * GSavingCompressionChunkSize;
					// Allocate compressed buffer placeholder on first use.
					if( NewChunk.CompressedBuffer == NULL )
					{
						NewChunk.CompressedBuffer = FMemory::Malloc( NewChunk.CompressedSize	);
					}

					// By default everything is chunked up into GSavingCompressionChunkSize chunks.
					NewChunk.UncompressedSize	= FMath::Min( BytesRemainingToKickOff, (int64)GSavingCompressionChunkSize );
					check(NewChunk.UncompressedSize>0);

					// Need to serialize source data if passed in pointer is an FArchive.
					if( bTreatBufferAsFileReader )
					{
						// Allocate memory on first use. We allocate the maximum amount to allow reuse.
						if( !NewChunk.UncompressedBuffer )
						{
							NewChunk.UncompressedBuffer = FMemory::Malloc(GSavingCompressionChunkSize);
						}
						((FArchive*)V)->Serialize(NewChunk.UncompressedBuffer, NewChunk.UncompressedSize);
					}
					// Advance src pointer by amount to be compressed.
					else
					{
						NewChunk.UncompressedBuffer = SrcBuffer;
						SrcBuffer += NewChunk.UncompressedSize;
					}

					// Update status variables for tracking how much work is left, what to do next.
					BytesRemainingToKickOff -= NewChunk.UncompressedSize;
					AsyncChunkIndex[FreeIndex] = CurrentChunkIndex++;
					NewChunk.Flags = Flags;
					NewChunk.CompressionFormat = CompressionFormat;
					NumChunksLeftToKickOff--;

					AsyncChunks[FreeIndex].StartBackgroundTask();
				}
				// No chunks were available to use, complete some
				else
				{
					bNeedToWaitForAsyncTask = true;
				}
			}
			// Wait for the oldest task to finish instead of spinning
			if (NumChunksLeftToKickOff == 0)
			{
				bNeedToWaitForAsyncTask = true;
			}

			// Index of oldest chunk, needed as we need to serialize in order.
			int32 OldestAsyncChunkIndex = INDEX_NONE;
			for( int32 i=0; i<MaxConcurrentAsyncChunks; i++ )
			{
				check(AsyncChunkIndex[i] == 0 || AsyncChunkIndex[i] >= RetireChunkIndex);
				check(AsyncChunkIndex[i] < RetireChunkIndex + MaxConcurrentAsyncChunks);
				if (AsyncChunkIndex[i] == RetireChunkIndex)
				{
					OldestAsyncChunkIndex = i;
				}
			}
			check(OldestAsyncChunkIndex != INDEX_NONE);  // the retire chunk better be outstanding


			bool ChunkReady;
			if (bNeedToWaitForAsyncTask)
			{
				// This guarantees that the async work has finished, doing it on this thread if it hasn't been started
				AsyncChunks[OldestAsyncChunkIndex].EnsureCompletion();
				ChunkReady = true;
			}
			else
			{
				ChunkReady = AsyncChunks[OldestAsyncChunkIndex].IsDone();
			}
			if (ChunkReady)
			{
				FAsyncCompressionChunk& DoneChunk = AsyncChunks[OldestAsyncChunkIndex].GetTask();
				// Serialize the data via archive.
				Serialize( DoneChunk.CompressedBuffer, DoneChunk.CompressedSize );

				// Update associated chunk.
				int64 CompressionChunkIndex = RetireChunkIndex++;
				check(CompressionChunkIndex<TotalChunkCount);
				CompressionChunks[CompressionChunkIndex].CompressedSize		= DoneChunk.CompressedSize;
				CompressionChunks[CompressionChunkIndex].UncompressedSize	= DoneChunk.UncompressedSize;

				// Keep track of total compressed size, stored in first chunk.
				CompressionChunks[0].CompressedSize	+= DoneChunk.CompressedSize;

				// Clean up chunk. Src and dst buffer are not touched as the contain allocations we keep till the end.
				AsyncChunkIndex[OldestAsyncChunkIndex] = 0;
				DoneChunk.CompressedSize	= 0;
				DoneChunk.UncompressedSize = 0;

				// Finalized one :)
				NumChunksLeftToFinalize--;
				bNeedToWaitForAsyncTask = false;
			}
		}

		// Free intermediate buffer storage.
		for( int32 i=0; i<MaxConcurrentAsyncChunks; i++ )
		{
			// Free temporary compressed buffer storage.
			FMemory::Free( AsyncChunks[i].GetTask().CompressedBuffer );
			AsyncChunks[i].GetTask().CompressedBuffer = NULL;
			// Free temporary uncompressed buffer storage if data was serialized in.
			if( bTreatBufferAsFileReader )
			{
				FMemory::Free( AsyncChunks[i].GetTask().UncompressedBuffer );
				AsyncChunks[i].GetTask().UncompressedBuffer = NULL;
			}
		}

#else
		// Set up source pointer amount of data to copy (in bytes)
		uint8*	Src;
		// allocate memory to read into
		if (bTreatBufferAsFileReader)
		{
			Src = (uint8*)FMemory::Malloc(GSavingCompressionChunkSize);
			check(((FArchive*)V)->IsLoading());
		}
		else
		{
			Src = (uint8*) V;
		}
		int64		BytesRemaining			= Length;
		// Start at index 1 as first chunk info is summary.
		int32		CurrentChunkIndex		= 1;
		// 2 times the uncompressed size should be more than enough; the compressed data shouldn't be that much larger
		int64		CompressedBufferSize	= 2 * GSavingCompressionChunkSize;
		void*	CompressedBuffer		= FMemory::Malloc( CompressedBufferSize );

		while( BytesRemaining > 0 )
		{
			int64 BytesToCompress = FMath::Min( BytesRemaining, (int64)GSavingCompressionChunkSize );
			int64 CompressedSize	= CompressedBufferSize;

			// read in the next chunk from the reader
			if (bTreatBufferAsFileReader)
			{
				((FArchive*)V)->Serialize(Src, BytesToCompress);
			}

			check(CompressedSize < INT_MAX);
			int32 CompressedSizeInt = (int32)CompressedSize;
						
			verify( FCompression::CompressMemory( CompressionFormat, CompressedBuffer, CompressedSizeInt, Src, BytesToCompress, Flags ) );
			CompressedSize = CompressedSizeInt;
			// move to next chunk if not reading from file
			if (!bTreatBufferAsFileReader)
			{
				Src += BytesToCompress;
			}
			Serialize( CompressedBuffer, CompressedSize );
			// Keep track of total compressed size, stored in first chunk.
			CompressionChunks[0].CompressedSize	+= CompressedSize;

			// Update current chunk.
			check(CurrentChunkIndex<TotalChunkCount);
			CompressionChunks[CurrentChunkIndex].CompressedSize		= CompressedSize;
			CompressionChunks[CurrentChunkIndex].UncompressedSize	= BytesToCompress;
			CurrentChunkIndex++;
			
			BytesRemaining -= GSavingCompressionChunkSize;
		}

		// free the buffer we read into
		if (bTreatBufferAsFileReader)
		{
			FMemory::Free(Src);
		}

		// Free allocated memory.
		FMemory::Free( CompressedBuffer );
#endif

		// Overrwrite chunk infos by seeking to the beginning, serializing the data and then
		// seeking back to the end.
		auto EndPosition = Tell();
		// Seek to the beginning.
		Seek( StartPosition );
		// Serialize chunk infos.
		for( int32 ChunkIndex=0; ChunkIndex<TotalChunkCount; ChunkIndex++ )
		{
			*this << CompressionChunks[ChunkIndex];
		}
		// Seek back to end.
		Seek( EndPosition );

		// Free intermediate data.
		delete [] CompressionChunks;
	}
}

void FArchive::ByteSwap(void* V, int32 Length)
{
	uint8* Ptr = (uint8*)V;
	int32 Top = Length - 1;
	int32 Bottom = 0;
	while (Bottom < Top)
	{
		Swap(Ptr[Top--], Ptr[Bottom++]);
	}
}

FArchive& FArchive::SerializeByteOrderSwapped(void* V, int32 Length)
{
	if (IsLoading())
	{
		Serialize(V, Length); // Read.
		ByteSwap(V, Length); // Swap.
	}
	else // Writing
	{
		ByteSwap(V, Length); // Swap V.
		Serialize(V, Length); // Write V.
		ByteSwap(V, Length); // Swap V back to its original byte order to prevent caller from observing V swapped.
	}

	return *this;
}

FArchive& FArchive::SerializeByteOrderSwapped(uint16& Value)
{
	return ArchiveUtil::SerializeByteOrderSwapped(*this, Value);
}

FArchive& FArchive::SerializeByteOrderSwapped(uint32& Value)
{
	return ArchiveUtil::SerializeByteOrderSwapped(*this, Value);
}

FArchive& FArchive::SerializeByteOrderSwapped(uint64& Value)
{
	return ArchiveUtil::SerializeByteOrderSwapped(*this, Value);
}

void FArchive::SerializeIntPacked(uint32& Value)
{
	if (IsLoading())
	{
		Value = 0;
		uint8 cnt = 0;
		uint8 more = 1;
		while(more)
		{
			uint8 NextByte;
			Serialize(&NextByte, 1);			// Read next byte

			more = NextByte & 1;				// Check 1 bit to see if theres more after this
			NextByte = NextByte >> 1;			// Shift to get actual 7 bit value
			Value += NextByte << (7 * cnt++);	// Add to total value
		}
	}
	else
	{
		uint8 PackedBytes[5];
		int32 PackedByteCount = 0;
		uint32 Remaining = Value;
		while(true)
		{
			uint8 nextByte = Remaining & 0x7f;		// Get next 7 bits to write
			Remaining = Remaining >> 7;				// Update remaining
			nextByte = nextByte << 1;				// Make room for 'more' bit
			if( Remaining > 0)
			{
				nextByte |= 1;						// set more bit
				PackedBytes[PackedByteCount++] = nextByte;
			}
			else
			{
				PackedBytes[PackedByteCount++] = nextByte;
				break;
			}
		}
		Serialize(PackedBytes, PackedByteCount); // Actually serialize the bytes we made
	}
}

void FArchive::LogfImpl(const TCHAR* Fmt, ...)
{
	// We need to use malloc here directly as GMalloc might not be safe, e.g. if called from within GMalloc!
	int32		BufferSize	= 1024;
	TCHAR*	Buffer		= NULL;
	int32		Result		= -1;

	while(Result == -1)
	{
		FMemory::SystemFree(Buffer);
		Buffer = (TCHAR*) FMemory::SystemMalloc( BufferSize * sizeof(TCHAR) );
		GET_VARARGS_RESULT( Buffer, BufferSize, BufferSize-1, Fmt, Fmt, Result );
		BufferSize *= 2;
	};
	Buffer[Result] = 0;

	// Convert to ANSI and serialize as ANSI char.
	for( int32 i=0; i<Result; i++ )
	{
		ANSICHAR Char = CharCast<ANSICHAR>( Buffer[i] );
		Serialize( &Char, 1 );
	}

	// Write out line terminator.
	for( int32 i=0; LINE_TERMINATOR[i]; i++ )
	{
		ANSICHAR Char = LINE_TERMINATOR[i];
		Serialize( &Char, 1 );
	}

	// Free temporary buffers.
	FMemory::SystemFree( Buffer );
}

void FArchiveState::SetUE4Ver(int32 InVer)
{
	ArUE4Ver = InVer;
}

void FArchiveState::SetLicenseeUE4Ver(int32 InVer)
{
	ArLicenseeUE4Ver = InVer;
}

void FArchiveState::SetEngineVer(const FEngineVersionBase& InVer)
{
	ArEngineVer = InVer;
}

void FArchiveState::SetEngineNetVer(const uint32 InEngineNetVer)
{
	ArEngineNetVer = InEngineNetVer;
}

void FArchiveState::SetGameNetVer(const uint32 InGameNetVer)
{
	ArGameNetVer = InGameNetVer;
}

void FArchiveState::SetIsLoading(bool bInIsLoading)
{
	ArIsLoading = bInIsLoading;
}

void FArchiveState::SetIsSaving(bool bInIsSaving)
{
	ArIsSaving = bInIsSaving;
}

void FArchiveState::SetIsTransacting(bool bInIsTransacting)
{
	ArIsTransacting = bInIsTransacting;
}

void FArchiveState::SetIsTextFormat(bool bInIsTextFormat)
{
	ArIsTextFormat = bInIsTextFormat;
}

void FArchiveState::SetWantBinaryPropertySerialization(bool bInWantBinaryPropertySerialization)
{
	ArWantBinaryPropertySerialization = bInWantBinaryPropertySerialization;
}

void FArchiveState::SetUseUnversionedPropertySerialization(bool bInUseUnversioned)
{
	ArUseUnversionedPropertySerialization = bInUseUnversioned;
}

void FArchiveState::SetForceUnicode(bool bInForceUnicode)
{
	ArForceUnicode = bInForceUnicode;
}

void FArchiveState::SetIsPersistent(bool bInIsPersistent)
{
	ArIsPersistent = bInIsPersistent;
}

static_assert(sizeof(FArchive) == sizeof(FArchiveState), "New FArchive members should be added to FArchiveState instead");

PRAGMA_ENABLE_UNSAFE_TYPECAST_WARNINGS

archive.h

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreTypes.h"
#include "Misc/VarArgs.h"
#include "Misc/AssertionMacros.h"
#include "Templates/EnableIf.h"
#include "Templates/IsEnumClass.h"
#include "Templates/Function.h"
#include "HAL/PlatformProperties.h"
#include "Misc/CompressionFlags.h"
#include "Misc/EngineVersionBase.h"
#include "Internationalization/TextNamespaceFwd.h"
#include "Templates/IsValidVariadicFunctionArg.h"
#include "Templates/AndOrNot.h"
#include "Templates/IsArrayOrRefOfType.h"
#include "Templates/IsSigned.h"

class FArchive;
class FCustomVersionContainer;
class FLinker;
class FName;
class FString;
class FText;
class ITargetPlatform;
class UObject;
class FProperty;
struct FUntypedBulkData;
struct FArchiveSerializedPropertyChain;
template<class TEnum> class TEnumAsByte;
typedef TFunction<bool (double RemainingTime)> FExternalReadCallback;
struct FUObjectSerializeContext;
class FField;
enum class EFileRegionType : uint8;

// Temporary while we shake out the EDL at boot
#define USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME (1)

#if USE_EVENT_DRIVEN_ASYNC_LOAD_AT_BOOT_TIME
	#define EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME (1)
#else
	#define EVENT_DRIVEN_ASYNC_LOAD_ACTIVE_AT_RUNTIME (!GIsInitialLoad) 
#endif

#define DEVIRTUALIZE_FLinkerLoad_Serialize (!WITH_EDITORONLY_DATA)

// Helper macro to make serializing a bitpacked boolean in an archive easier
#define FArchive_Serialize_BitfieldBool(ARCHIVE, BITFIELD_BOOL) { bool TEMP_BITFIELD_BOOL = BITFIELD_BOOL; ARCHIVE << TEMP_BITFIELD_BOOL; BITFIELD_BOOL = TEMP_BITFIELD_BOOL; }

struct CORE_API FArchiveState
{
private:
	// Only FArchive is allowed to instantiate this, by inheritance
	friend class FArchive;

	FArchiveState();

	/** Copy constructor. */
	FArchiveState(const FArchiveState&);

	/**
	 * Copy assignment operator.
	 *
	 * @param ArchiveToCopy The archive to copy from.
	 */
	FArchiveState& operator=(const FArchiveState& ArchiveToCopy);

	virtual ~FArchiveState() = 0;

protected:
	static void LinkProxy(FArchiveState& Inner, FArchiveState& Proxy);
	static void UnlinkProxy(FArchiveState& Inner, FArchiveState& Proxy);

public:
	/** 
	 * Returns lowest level archive state, proxy archives will override this.
	 */
	virtual FArchiveState& GetInnermostState()
	{
		return *this;
	}

	/** 
	 * Modifies current archive state, can be used to override flags.
	 */
	void SetArchiveState(const FArchiveState& InState);

	/**
	 * Sets ArIsError to true. Also sets error in the proxy archiver if one is wrapping this.
	 */
	void SetError();

	/**
	 * Sets ArIsError to false, this does not clear any CriticalErrors
	 */
	void ClearError();

	/**
	 * Sets the archiver IsCriticalError and IsError to true. Also sets CriticalError in the proxy archiver if one is wrapping this.
	 */
	void SetCriticalError();

	/**
	 * Called to get the computed size from a size-detecting archive after it has finished serializing.
	 */
	virtual void CountBytes(SIZE_T InNum, SIZE_T InMax) { }

	/**
	 * Returns the name of the Archive.  Useful for getting the name of the package a struct or object
	 * is in when a loading error occurs.
	 *
	 * This is overridden for the specific Archive Types
	 */
	virtual FString GetArchiveName() const;

	/**
	 * If this archive is a FLinkerLoad or FLinkerSave, returns a pointer to the ULinker portion.
	 *
	 * @return The linker, or nullptr if the archive is not a linker.
	 */
	virtual FLinker* GetLinker()
	{
		return nullptr;
	}

	/** 
	 * Returns the current location within the backing data storage, which can possibly be passed to Seek later to restore a read/write location.
	 * If this returns -1, there is no backing data storage and Seek will not function.
	 */
	virtual int64 Tell()
	{
		return INDEX_NONE;
	}

	/** Returns total size of the backing data storage. */
	virtual int64 TotalSize()
	{
		return INDEX_NONE;
	}

	/** Returns true if the current location within the backing data storage is at the end, always returns false if there is no storage. */
	virtual bool AtEnd()
	{
		int64 Pos = Tell();

		return ((Pos != INDEX_NONE) && (Pos >= TotalSize()));
	}

	/** Returns true if data larger than 1 byte should be swapped to deal with endian mismatches. */
	FORCEINLINE bool IsByteSwapping()
	{
	#if PLATFORM_LITTLE_ENDIAN
		bool SwapBytes = ArForceByteSwapping;
	#else
		bool SwapBytes = this->IsPersistent();
	#endif
		return SwapBytes;
	}

	/** Sets a flag indicating that this archive contains native or generated code. */
	void ThisContainsCode()
	{
		ArContainsCode = true;
	}

	/** Sets a flag indicating that this archive contains a ULevel or UWorld object. */
	void ThisContainsMap()
	{
		ArContainsMap = true;
	}

	/** Sets a flag indicating that this archive contains data required to be gathered for localization. */
	void ThisRequiresLocalizationGather()
	{
		ArRequiresLocalizationGather = true;
	}

	/**
	 * Called to retrieve the archetype from the event driven loader. 
	 * If this returns null, then call GetArchetype yourself. 
	 */
	virtual UObject* GetArchetypeFromLoader(const UObject* Obj)
	{
		return nullptr;
	}

	/** Returns the global engine serialization version used for this archive. */
	FORCEINLINE int32 UE4Ver() const
	{
		return ArUE4Ver;
	}

	/** Returns the licensee-specific version used for this archive, will be 0 by default. */
	FORCEINLINE int32 LicenseeUE4Ver() const
	{
		return ArLicenseeUE4Ver;
	}

	/** Returns the compiled engine version used for this archive. */
	FORCEINLINE FEngineVersionBase EngineVer() const
	{
		return ArEngineVer;
	}

	/** Returns the engine-global network protocol version for this archive. */
	FORCEINLINE uint32 EngineNetVer() const
	{
		return ArEngineNetVer;
	}

	/** Returns the game-specific network protocol version for this archive. */
	FORCEINLINE uint32 GameNetVer() const
	{
		return ArGameNetVer;
	}

	/**
	 * Queries a custom version from the archive.  If the archive is being used to write, the custom version must have already been registered.
	 *
	 * @param Key The guid of the custom version to query.
	 * @return The version number, or 0 if the custom tag isn't stored in the archive.
	 */
	int32 CustomVer(const struct FGuid& Key) const;

	/** Returns true if this archive is for loading data. */
	FORCEINLINE bool IsLoading() const
	{
		return ArIsLoading;
	}

	/** Returns true if this archive is for saving data, this can also be a pre-save preparation archive. */
	FORCEINLINE bool IsSaving() const
	{
		return ArIsSaving;
	}

	/** Returns true if this archive is transacting, which is used to keep track of changes to objects for things like the editor undo system. */
	FORCEINLINE bool IsTransacting() const
	{
		if (FPlatformProperties::HasEditorOnlyData())
		{
			return ArIsTransacting;
		}
		else
		{
			return false;
		}
	}

	/** 
	 * Returns true if this archive serializes to a structured text format. 
	 * Text format archives should use high level constructs from FStructuredArchive for delimiting data rather than manually seeking through the file.
	 */
	FORCEINLINE bool IsTextFormat() const
	{
		return (ArIsTextFormat && WITH_TEXT_ARCHIVE_SUPPORT);
	}

	/** Returns true if this archive wants properties to be serialized in binary form instead of safer but slower tagged form. */
	FORCEINLINE bool WantBinaryPropertySerialization() const
	{
		return ArWantBinaryPropertySerialization;
	}

	/** 
	 * Returns true if tagged property serialization should be replaced by faster unversioned serialization.
	 * This assumes writer and reader share the same property definitions. 
	 */
	FORCEINLINE bool UseUnversionedPropertySerialization() const
	{
		return ArUseUnversionedPropertySerialization;
	}

	/** Returns true if this archive wants to always save strings in UTF16 format even if they are ANSI characters. */
	FORCEINLINE bool IsForcingUnicode() const
	{
		return ArForceUnicode;
	}

	/** 
	 * Returns true if this archive is saving or loading data destined for persistent storage and should skip transient data.
	 * This is also true for some intermediate archives for tasks like duplication that are eventually destined for persistent storage.
	 */
	FORCEINLINE bool IsPersistent() const
	{
		return ArIsPersistent;
	}

	/** Returns true if this archive contains errors, which means that further serialization is generally not safe. */
	FORCEINLINE bool IsError() const
	{
		return ArIsError;
	}

	FORCEINLINE bool GetError() const
	{
		return ArIsError;
	}

	/** Returns true if this archive contains critical errors that cannot be recovered from. */
	FORCEINLINE bool IsCriticalError() const
	{
		return ArIsCriticalError;
	}

	/** Returns true if this archive contains native or generated code. */
	FORCEINLINE bool ContainsCode() const
	{
		return ArContainsCode;
	}

	/** Returns true if this archive contains a ULevel or UWorld object. */
	FORCEINLINE bool ContainsMap() const
	{
		return ArContainsMap;
	}

	/** Returns true if this archive contains data required to be gathered for localization. */
	FORCEINLINE bool RequiresLocalizationGather() const
	{
		return ArRequiresLocalizationGather;
	}

	/** Returns true if this archive should always swap bytes, ignoring endian rules. */
	FORCEINLINE bool ForceByteSwapping() const
	{
		return ArForceByteSwapping;
	}

	/** Returns true if this archive is currently serializing class/struct default values. */
	FORCEINLINE bool IsSerializingDefaults() const
	{
		return (ArSerializingDefaults > 0) ? true : false;
	}

	/** Returns true if this archive should ignore archetype references for structs and classes. */
	FORCEINLINE bool IsIgnoringArchetypeRef() const
	{
		return ArIgnoreArchetypeRef;
	}

	/** Returns true if this archive should handle delta serialization for properties. */
	FORCEINLINE bool DoDelta() const
	{
		return !ArNoDelta;
	}

	/** Returns true if this archive should perform delta serialization within properties (e.g. TMaps and TSets). */
	FORCEINLINE bool DoIntraPropertyDelta() const
	{
		return !ArNoIntraPropertyDelta;
	}

	/** Returns true if this archive should ignore the Outer reference in UObject. */
	FORCEINLINE bool IsIgnoringOuterRef() const
	{
		return ArIgnoreOuterRef;
	}

	/** Returns true if this archive should ignore the ClassGeneratedBy reference in UClass. */
	FORCEINLINE bool IsIgnoringClassGeneratedByRef() const
	{
		return ArIgnoreClassGeneratedByRef;
	}

	/** Returns true if this archive should ignore the Class reference in UObject. */
	FORCEINLINE bool IsIgnoringClassRef() const
	{
		return ArIgnoreClassRef;
	}

	/** Returns true if this archive sould allow lazy loading of bulk / secondary data. */
	FORCEINLINE bool IsAllowingLazyLoading() const
	{
		return ArAllowLazyLoading;
	}

	/** 
	 * Returns true if this archive is only looking for UObject references.
	 * This can be false for reference collectors looking for more general references.
	 */
	FORCEINLINE bool IsObjectReferenceCollector() const
	{
		return ArIsObjectReferenceCollector;
	}

	/** Returns true if this archive should modify/search weak object references as well as strong ones. */
	FORCEINLINE bool IsModifyingWeakAndStrongReferences() const
	{
		return ArIsModifyingWeakAndStrongReferences;
	}

	/** Returns true if this archive is counting memory, normally CountBytes is called to get the size. */
	FORCEINLINE bool IsCountingMemory() const
	{
		return ArIsCountingMemory;
	}

	/** Returns this archive's property serialization modifier flags. */
	FORCEINLINE uint32 GetPortFlags() const
	{
		return ArPortFlags;
	}

	/** Checks to see if any of the passed in property serialization modifier flags are set. */
	FORCEINLINE bool HasAnyPortFlags(uint32 Flags) const
	{
		return ((ArPortFlags & Flags) != 0);
	}

	/** Checks to see if all of the passed in property serialization modifier flags are set. */
	FORCEINLINE bool HasAllPortFlags(uint32 Flags) const
	{
		return ((ArPortFlags & Flags) == Flags);
	}

	/** Returns the editor-only debug serialization flags. */
	FORCEINLINE uint32 GetDebugSerializationFlags() const
	{
#if WITH_EDITOR
		return ArDebugSerializationFlags;
#else
		return 0;
#endif
	}

	/** Returns true if this archive should ignore bulk data. */
	FORCEINLINE bool ShouldSkipBulkData() const
	{
		return ArShouldSkipBulkData;
	}

	/** Returns the maximum size of data that this archive is allowed to serialize. */
	FORCEINLINE int64 GetMaxSerializeSize() const
	{
		return ArMaxSerializeSize;
	}

	/**
	 * Gets the custom version numbers for this archive.
	 * These are used to check for system or game-specific version numbers.
	 *
	 * @return The container of custom versions in the archive.
	 */
	virtual const FCustomVersionContainer& GetCustomVersions() const;

	/**
	 * Sets the custom version numbers for this archive.
	 *
	 * @param CustomVersionContainer - The container of custom versions to copy into the archive.
	 */
	virtual void SetCustomVersions(const FCustomVersionContainer& CustomVersionContainer);

	/** Resets the custom version numbers for this archive. */
	virtual void ResetCustomVersions();

	/**
	 * Sets a specific custom version
	 *
	 * @param Key - The guid of the custom version to query.
	 * @param Version - The version number to set key to
	 * @param FriendlyName - Friendly name corresponding to the key
	 */
	void SetCustomVersion(const struct FGuid& Key, int32 Version, FName FriendlyName);

	/**
	 * Toggle byte order swapping. This is needed in rare cases when we already know that the data
	 * swapping has already occurred or if we know that it will be handled later.
	 *
	 * @param Enabled	set to true to enable byte order swapping
	 */
	void SetByteSwapping(bool Enabled)
	{
		ArForceByteSwapping = Enabled;
	}

	/**
	 * Sets the archive's property serialization modifier flags
	 *
	 * @param	InPortFlags		the new flags to use for property serialization
	 */
	void SetPortFlags(uint32 InPortFlags)
	{
		ArPortFlags = InPortFlags;
	}

	/**
	 * Sets the archives custom serialization modifier flags (nothing to do with PortFlags or Custom versions)
	 *
	 * @param InCustomFlags the new flags to use for custom serialization
	 */
	void SetDebugSerializationFlags(uint32 InCustomFlags)
	{
#if WITH_EDITOR
		ArDebugSerializationFlags = InCustomFlags;
#endif
	}

	/**
	 * Indicates whether this archive is filtering editor-only on save or contains data that had editor-only content stripped.
	 *
	 * @return true if the archive filters editor-only content, false otherwise.
	 */
	bool IsFilterEditorOnly() const
	{
		return ArIsFilterEditorOnly;
	}

	/**
	 * Sets a flag indicating that this archive needs to filter editor-only content.
	 *
	 * @param InFilterEditorOnly Whether to filter editor-only content.
	 */
	virtual void SetFilterEditorOnly(bool InFilterEditorOnly)
	{
		ArIsFilterEditorOnly = InFilterEditorOnly;
	}

	/**
	 * Indicates whether this archive is saving or loading game state
	 *
	 * @note This is intended for game-specific archives and is not true for any of the build in save methods
	 * @return true if the archive is dealing with save games, false otherwise.
	 */
	bool IsSaveGame() const
	{
		return ArIsSaveGame;
	}

	/**
	 * Whether or not this archive is serializing data being sent/received by the netcode
	 */
	FORCEINLINE bool IsNetArchive() const
	{
		return ArIsNetArchive;
	}

	/**
	 * Checks whether the archive is used for cooking.
	 *
	 * @return true if the archive is used for cooking, false otherwise.
	 */
	FORCEINLINE bool IsCooking() const
	{
		check(!CookingTargetPlatform || (!IsLoading() && !IsTransacting() && IsSaving()));

		return !!CookingTargetPlatform;
	}

	/**
	 * Returns the cooking target platform.
	 *
	 * @return Target platform.
	 */
	FORCEINLINE const ITargetPlatform* CookingTarget() const
	{
		return CookingTargetPlatform;
	}

	/**
	 * Sets the cooking target platform.
	 *
	 * @param InCookingTarget The target platform to set.
	 */
	FORCEINLINE void SetCookingTarget(const ITargetPlatform* InCookingTarget)
	{
		CookingTargetPlatform = InCookingTarget;
	}

	/**
	 * Checks whether the archive is used to resolve out-of-date enum indexes
	 * If function returns true, the archive should be called only for objects containing user defined enum
	 *
	 * @return true if the archive is used to resolve out-of-date enum indexes
	 */
	virtual bool UseToResolveEnumerators() const
	{
		return false;
	}

	/**
	 * Checks whether the archive wants to skip the property independent of the other flags
	 */
	virtual bool ShouldSkipProperty(const FProperty* InProperty) const
	{
		return false;
	}

	/**
	 * Overrides the property that is currently being serialized
	 * @note: You likely want to call PushSerializedProperty/PopSerializedProperty instead
	 *
	 * @param InProperty Pointer to the property that is currently being serialized
	 */
	virtual void SetSerializedProperty(FProperty* InProperty)
	{
		SerializedProperty = InProperty;
	}

	/**
	 * Gets the property that is currently being serialized
	 *
	 * @return Pointer to the property that is currently being serialized
	 */
	FORCEINLINE class FProperty* GetSerializedProperty() const
	{
		return SerializedProperty;
	}

	/**
	 * Gets the chain of properties that are currently being serialized
	 * @note This populates the array in stack order, so the 0th entry in the array is the top of the stack of properties
	 */
	void GetSerializedPropertyChain(TArray<class FProperty*>& OutProperties) const;

	/**
	 * Get the raw serialized property chain for this archive
	 * @note Accessing this directly can avoid an array allocation depending on your use-case
	 */
	FORCEINLINE const FArchiveSerializedPropertyChain* GetSerializedPropertyChain() const
	{
		return SerializedPropertyChain;
	}

	/**
	 * Set the raw serialized property chain for this archive, optionally overriding the serialized property too (or null to use the head of the property chain)
	 */
	virtual void SetSerializedPropertyChain(const FArchiveSerializedPropertyChain* InSerializedPropertyChain, class FProperty* InSerializedPropertyOverride = nullptr);

#if WITH_EDITORONLY_DATA
	/** Returns true if the stack of currently serialized properties contains an editor-only property */
	virtual bool IsEditorOnlyPropertyOnTheStack() const;
#endif

	/** Sets the current UObject serialization context for this archive. */
	virtual void SetSerializeContext(FUObjectSerializeContext* InLoadContext) {}

	/** Gets the current UObject serialization context for this archive. */
	virtual FUObjectSerializeContext* GetSerializeContext() { return nullptr; }

#if USE_STABLE_LOCALIZATION_KEYS
	/**
	 * Set the localization namespace that this archive should use when serializing text properties.
	 * This is typically the namespace used by the package being serialized (if serializing a package, or an object within a package).
	 */
	virtual void SetLocalizationNamespace(const FString& InLocalizationNamespace);

	/**
	 * Get the localization namespace that this archive should use when serializing text properties.
	 * This is typically the namespace used by the package being serialized (if serializing a package, or an object within a package).
	 */
	virtual FString GetLocalizationNamespace() const;
#endif // USE_STABLE_LOCALIZATION_KEYS

	/** Resets all of the base archive members. */
	virtual void Reset();

public:
#if DEVIRTUALIZE_FLinkerLoad_Serialize
	/* These are used for fastpath inline serializers  */
	struct FFastPathLoadBuffer
	{
		const uint8* StartFastPathLoadBuffer;
		const uint8* EndFastPathLoadBuffer;
		const uint8* OriginalFastPathLoadBuffer;
		FORCEINLINE FFastPathLoadBuffer()
		{
			Reset();
		}
		FORCEINLINE void Reset()
		{
			StartFastPathLoadBuffer = nullptr;
			EndFastPathLoadBuffer = nullptr;
			OriginalFastPathLoadBuffer = nullptr;
		}
	};
	//@todoio FArchive is really a horrible class and the way it is proxied by FLinkerLoad is double terrible. It makes the fast path really hacky and slower than it would need to be.
	FFastPathLoadBuffer* ActiveFPLB;
	FFastPathLoadBuffer InlineFPLB;
#endif

// These will be private in FArchive
protected:
	/** Copies all of the members except CustomVersionContainer */
	void CopyTrivialFArchiveStatusMembers(const FArchiveState& ArchiveStatusToCopy);

	/** Whether this archive is for loading data. */
	uint8 ArIsLoading : 1;

	/** Whether this archive is for saving data. */
	uint8 ArIsSaving : 1;

	/** Whether archive is transacting, which is used to keep track of changes to objects for things like the editor undo system. */
	uint8 ArIsTransacting : 1;

	/** Whether this archive serializes to a text format. Text format archives should use high level constructs from FStructuredArchive for delimiting data rather than manually seeking through the file. */
	uint8 ArIsTextFormat : 1;

	/** Whether this archive wants properties to be serialized in binary form instead of tagged. */
	uint8 ArWantBinaryPropertySerialization : 1;

	/** Whether tagged property serialization is replaced by faster unversioned serialization. This assumes writer and reader share the same property definitions. */
	uint8 ArUseUnversionedPropertySerialization : 1;

	/** Whether this archive wants to always save strings in UTF16 format even if they are ANSI characters */
	uint8 ArForceUnicode : 1;

	/** Whether this archive saves to persistent storage. This is also true for some intermediate archives like DuplicateObject that are expected to go to persistent storage but may be discarded */
	uint8 ArIsPersistent : 1;

private:
	/** Whether this archive contains errors, which means that further serialization is generally not safe */
	uint8 ArIsError : 1;

	/** Whether this archive contains critical errors that cannot be recovered from */
	uint8 ArIsCriticalError : 1;

public:
	/** Quickly tell if an archive contains script code. */
	uint8 ArContainsCode : 1;

	/** Used to determine whether FArchive contains a level or world. */
	uint8 ArContainsMap : 1;

	/** Used to determine whether FArchive contains data required to be gathered for localization. */
	uint8 ArRequiresLocalizationGather : 1;

	/** Whether we should forcefully swap bytes. */
	uint8 ArForceByteSwapping : 1;

	/** If true, we will not serialize archetype references for structs and classes. */
	uint8 ArIgnoreArchetypeRef : 1;

	/** If true, do not perform delta serialization of properties. */
	uint8 ArNoDelta : 1;

	/** If true, do not perform delta serialization within properties (e.g. TMaps and TSets). */
	uint8 ArNoIntraPropertyDelta : 1;

	/** If true, we will not serialize the Outer reference in UObject. */
	uint8 ArIgnoreOuterRef : 1;

	/** If true, we will not serialize ClassGeneratedBy reference in UClass. */
	uint8 ArIgnoreClassGeneratedByRef : 1;

	/** If true, UObject::Serialize will skip serialization of the Class property. */
	uint8 ArIgnoreClassRef : 1;

	/** Whether to allow lazy loading of bulk/secondary data. */
	uint8 ArAllowLazyLoading : 1;

	/** Whether this archive only cares about serializing object references. */
	uint8 ArIsObjectReferenceCollector : 1;

	/** Whether a reference collector is modifying the references and wants both weak and strong ones */
	uint8 ArIsModifyingWeakAndStrongReferences : 1;

	/** Whether this archive is counting memory. */
	uint8 ArIsCountingMemory : 1;

	/** Whether bulk data serialization should be skipped or not. */
	uint8 ArShouldSkipBulkData : 1;

	/** Whether editor only properties are being filtered from the archive (or has been filtered). */
	uint8 ArIsFilterEditorOnly : 1;

	/** Whether this archive is saving/loading game state */
	uint8 ArIsSaveGame : 1;

	/** Whether or not this archive is sending/receiving network data */
	uint8 ArIsNetArchive : 1;

	/** Set TRUE to use the custom property list attribute for serialization. */
	uint8 ArUseCustomPropertyList : 1;

	/** Whether we are currently serializing defaults. > 0 means yes, <= 0 means no. */
	int32 ArSerializingDefaults;

	/** Modifier flags that be used when serializing UProperties */
	uint32 ArPortFlags;

	/** Max size of data that this archive is allowed to serialize. */
	int64 ArMaxSerializeSize;

	/**
	 * Sets whether this archive is for loading data.
	 *
	 * @param bInIsLoading  true if this archive is for loading, false otherwise.
	 */
	virtual void SetIsLoading(bool bInIsLoading);

	/**
	 * Sets whether this archive is for saving data.
	 *
	 * @param bInIsSaving  true if this archive is for saving, false otherwise.
	 */
	virtual void SetIsSaving(bool bInIsSaving);

	/**
	 * Sets whether this archive is for transacting.
	 *
	 * @param bInIsTransacting  true if this archive is for transacting, false otherwise.
	 */
	virtual void SetIsTransacting(bool bInIsTransacting);

	/**
	 * Sets whether this archive is in text format.
	 *
	 * @param bInIsTextFormat  true if this archive is in text format, false otherwise.
	 */
	virtual void SetIsTextFormat(bool bInIsTextFormat);

	/**
	 * Sets whether this archive wants binary property serialization.
	 *
	 * @param bInWantBinaryPropertySerialization  true if this archive wants binary serialization, false otherwise.
	 */
	virtual void SetWantBinaryPropertySerialization(bool bInWantBinaryPropertySerialization);

	/** Sets whether tagged property serialization should be replaced by faster unversioned serialization. This assumes writer and reader share the same property definitions. */
	virtual void SetUseUnversionedPropertySerialization(bool bInUseUnversioned);

	/**
	 * Sets whether this archive wants to force saving as Unicode.
	 * This is needed when we need to make sure ANSI strings are saved as Unicode.
	 *
	 * @param bInForceUnicode  true if this archive wants to force saving as Unicode, false otherwise.
	 */
	virtual void SetForceUnicode(bool bInForceUnicode);

	/**
	 * Sets whether this archive is to persistent storage.
	 *
	 * @param bInIsPersistent  true if this archive is to persistent storage, false otherwise.
	 */
	virtual void SetIsPersistent(bool bInIsPersistent);

	/**
	 * Sets the archive version number. Used by the code that makes sure that FLinkerLoad's 
	 * internal archive versions match the file reader it creates.
	 *
	 * @param UE4Ver	new version number
	 */
	virtual void SetUE4Ver(int32 InVer);

	/**
	 * Sets the archive licensee version number. Used by the code that makes sure that FLinkerLoad's 
	 * internal archive versions match the file reader it creates.
	 *
	 * @param Ver	new version number
	 */
	virtual void SetLicenseeUE4Ver(int32 InVer);

	/**
	 * Sets the archive engine version. Used by the code that makes sure that FLinkerLoad's
	 * internal archive versions match the file reader it creates.
	 *
	 * @param InVer	new version number
	 */
	virtual void SetEngineVer(const FEngineVersionBase& InVer);

	/**
	 * Sets the archive engine network version.
	 */
	virtual void SetEngineNetVer(const uint32 InEngineNetVer);

	/**
	 * Sets the archive game network version.
	 */
	virtual void SetGameNetVer(const uint32 InGameNetVer);

// These will be private in FArchive
protected:
	/** Holds the archive version. */
	int32 ArUE4Ver;

	/** Holds the archive version for licensees. */
	int32 ArLicenseeUE4Ver;

	/** Holds the engine version. */
	FEngineVersionBase ArEngineVer;

	/** Holds the engine network protocol version. */
	uint32 ArEngineNetVer;

	/** Holds the game network protocol version. */
	uint32 ArGameNetVer;

	/**
	* All the custom versions stored in the archive.
	* Stored as a pointer to a heap-allocated object because of a 3-way dependency between TArray, FCustomVersionContainer and FArchive, which is too much work to change right now.
	* Keeping it as a heap-allocated object also helps with performance in some cases as we don't need to construct it for archives that don't care about custom versions.
	*/
	mutable FCustomVersionContainer* CustomVersionContainer = nullptr;

public:
	/** Custom property list attribute. If the flag below is set, only these properties will be iterated during serialization. If NULL, then no properties will be iterated. */
	const struct FCustomPropertyListNode* ArCustomPropertyList;

#if WITH_EDITOR
	/** Custom serialization modifier flags can be used for anything */
	uint32 ArDebugSerializationFlags;
#endif

// These will be private in FArchive
protected:
	/** Holds the cooking target platform. */
	const ITargetPlatform* CookingTargetPlatform;

	/** Holds the pointer to the property that is currently being serialized */
	FProperty* SerializedProperty;

	/** Holds the chain of properties that are currently being serialized */
	FArchiveSerializedPropertyChain* SerializedPropertyChain;

#if USE_STABLE_LOCALIZATION_KEYS
	/**
	 * The localization namespace that this archive should use when serializing text properties.
	 * This is typically the namespace used by the package being serialized (if serializing a package, or an object within a package).
	 * Stored as a pointer to a heap-allocated string because of a dependency between TArray (thus FString) and FArchive; null should be treated as an empty string.
	 */
	FString* LocalizationNamespacePtr;

	/** See GetLocalizationNamespace */
	FString GetBaseLocalizationNamespace() const;

	/** See SetLocalizationNamespace */
	void SetBaseLocalizationNamespace(const FString& InLocalizationNamespace);
#endif // USE_STABLE_LOCALIZATION_KEYS

	/**
	 * Indicates if the custom versions container is in a 'reset' state.  This will be used to defer the choice about how to
	 * populate the container until it is needed, where the read/write state will be known.
	 */
	mutable bool bCustomVersionsAreReset;

private:
	/** Linked list to all proxies */
	FArchiveState* NextProxy = nullptr;

	template<typename T> void ForEachState(T Func);
};

/**
 * TCheckedObjPtr
 *
 * Wrapper for UObject pointers, which checks that the base class is accurate, upon serializing (to prevent illegal casting)
 */
template<class T> class TCheckedObjPtr
{
	friend class FArchive;

public:
	TCheckedObjPtr()
		: Object(nullptr)
		, bError(false)
	{
	}

	TCheckedObjPtr(T* InObject)
		: Object(InObject)
		, bError(false)
	{
	}

	/**
	 * Assigns a value to the object pointer
	 *
	 * @param InObject	The value to assign to the pointer
	 */
	FORCEINLINE TCheckedObjPtr& operator = (T* InObject)
	{
		Object = InObject;

		return *this;
	}

	/**
	 * Returns the object pointer, for accessing members of the object
	 *
	 * @return	Returns the object pointer
	 */
	FORCEINLINE T* operator -> () const
	{
		return Object;
	}

	/**
	 * Retrieves a writable/serializable reference to the pointer
	 *
	 * @return	Returns a reference to the pointer
	 */
	FORCEINLINE T*& Get()
	{
		return Object;
	}

	/**
	 * Whether or not the pointer is valid/non-null
	 *
	 * @return	Whether or not the pointer is valid
	 */
	FORCEINLINE bool IsValid() const
	{
		return Object != nullptr;
	}

	/**
	 * Whether or not there was an error during the previous serialization.
	 * This occurs if an object was successfully serialized, but with the wrong base class
	 * (which net serialization may have to recover from, if there was supposed to be data serialized along with the object)
	 *
	 * @return	Whether or not there was an error
	 */
	FORCEINLINE bool IsError() const
	{
		return bError;
	}

private:
	/** The object pointer */
	T* Object;

	/** Whether or not there was an error upon serializing */
	bool bError;
};


/**
 * Base class for archives that can be used for loading, saving, and garbage
 * collecting in a byte order neutral way.
 */
class CORE_API FArchive : private FArchiveState
{
public:
	FArchive() = default;
	FArchive(const FArchive&) = default;
	FArchive& operator=(const FArchive& ArchiveToCopy) = default;
	~FArchive() = default;

protected:
	using FArchiveState::LinkProxy;
	using FArchiveState::UnlinkProxy;

public:

	/**
	 * Serializes an FName value from or into this archive.
	 *
	 * This operator can be implemented by sub-classes that wish to serialize FName instances.
	 *
	 * @param Value The value to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(FName& Value)
	{
		return *this;
	}

	/**
	 * Serializes an FText value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	virtual FArchive& operator<<(FText& Value);

	/**
	 * Serializes an UObject value from or into this archive.
	 *
	 * This operator can be implemented by sub-classes that wish to serialize UObject instances.
	 *
	 * @param Value The value to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(UObject*& Value)
	{
		return *this;
	}

	/**
	 * Serializes a Field value from or into this archive.
	 *
	 * This operator can be implemented by sub-classes that wish to serialize UObject instances.
	 *
	 * @param Value The value to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(FField*& Value)
	{
		return *this;
	}

	/**
	 * Serializes a UObject wrapped in a TCheckedObjPtr container, using the above operator,
	 * and verifies the serialized object is derived from the correct base class, to prevent illegal casting.
	 *
	 * @param Value The value to serialize.
	 * @return This instance.
	 */
	template<class T> FORCEINLINE FArchive& operator<<(TCheckedObjPtr<T>& Value)
	{
		Value.bError = false;

		if (IsSaving())
		{
			UObject* SerializeObj = nullptr;

			if (Value.IsValid())
			{
				if (Value.Get()->IsA(T::StaticClass()))
				{
					SerializeObj = Value.Get();
				}
				else
				{
					Value.bError = true;
				}
			}

			*this << SerializeObj;
		}
		else
		{
			*this << Value.Get();

			if (IsLoading() && Value.IsValid() && !Value.Get()->IsA(T::StaticClass()))
			{
				Value.bError = true;
				Value = nullptr;
			}
		}

		return *this;
	}

	/**
	 * Serializes a lazy object pointer value from or into this archive.
	 *
	 * Most of the time, FLazyObjectPtrs are serialized as UObject*, but some archives need to override this.
	 *
	 * @param Value The value to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(struct FLazyObjectPtr& Value);
	
	/**
	 * Serializes asset pointer from or into this archive.
	 *
	 * Most of the time, FSoftObjectPtr are serialized as UObject *, but some archives need to override this.
	 *
	 * @param Value The asset pointer to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(struct FSoftObjectPtr& Value);

	/**
	 * Serializes soft object paths from or into this archive.
	 *
	 * @param Value Soft object path to serialize.
	 * @return This instance.
	 */
	virtual FArchive& operator<<(struct FSoftObjectPath& Value);

	/**
	* Serializes FWeakObjectPtr value from or into this archive.
	*
	* This operator can be implemented by sub-classes that wish to serialize FWeakObjectPtr instances.
	*
	* @param Value The value to serialize.
	* @return This instance.
	*/
	virtual FArchive& operator<<(struct FWeakObjectPtr& Value);

	/** 
	 * Inform the archive that a blueprint would like to force finalization, normally
	 * this is triggered by CDO load, but if there's no CDO we force finalization.
	 */
	virtual void ForceBlueprintFinalization() {}
public:

	/**
	 * Serializes an ANSICHAR value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, ANSICHAR& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.Serialize(&Value, 1);
		}
		return Ar;
	}

	/**
	 * Serializes a WIDECHAR value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, WIDECHAR& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(&Value, sizeof(Value));
		}
		return Ar;
	}

	/**
	 * Serializes an unsigned 8-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, uint8& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.Serialize(&Value, 1);
		}
		return Ar;
	}

	/**
	 * Serializes an enumeration value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	template<class TEnum>
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, TEnumAsByte<TEnum>& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.Serialize(&Value, 1);
		}
		return Ar;
	}

	/**
	 * Serializes a signed 8-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, int8& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.Serialize(&Value, 1);
		}
		return Ar;
	}

	/**
	 * Serializes an unsigned 16-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, uint16& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(Value);
		}
		return Ar;
	}

	/**
	 * Serializes a signed 16-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, int16& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(reinterpret_cast<uint16&>(Value));
		}
		return Ar;
	}

	/**
	 * Serializes an unsigned 32-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, uint32& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(Value);
		}
		return Ar;
	}

	/**
	 * Serializes a Boolean value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
#if WITH_EDITOR
protected:
	virtual void SerializeBool( bool& D );
public:
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, bool& D)
	{
		Ar.SerializeBool(D);
		return Ar;
	}
#else
	FORCEINLINE friend FArchive& operator<<( FArchive& Ar, bool& D )
	{
		// Serialize bool as if it were UBOOL (legacy, 32 bit int).
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		const uint8 * RESTRICT Src = Ar.ActiveFPLB->StartFastPathLoadBuffer;
		if (Src + sizeof(uint32) <= Ar.ActiveFPLB->EndFastPathLoadBuffer)
		{
			D = !!FPlatformMemory::ReadUnaligned<uint32>(Src);
			Ar.ActiveFPLB->StartFastPathLoadBuffer += 4;
		}
		else
#endif
		{
			uint32 OldUBoolValue = D ? 1 : 0;
			Ar.Serialize(&OldUBoolValue, sizeof(OldUBoolValue));
			D = !!OldUBoolValue;
		}
		return Ar;
	}
#endif

	/**
	 * Serializes a signed 32-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, int32& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(reinterpret_cast<uint32&>(Value));
		}
		return Ar;
	}

#if PLATFORM_COMPILER_DISTINGUISHES_INT_AND_LONG
	/**
	 * Serializes a long integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, long& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(reinterpret_cast<unsigned long&>(Value));
		}
		return Ar;
	}	
#endif

	/**
	 * Serializes a single precision floating point value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<( FArchive& Ar, float& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			static_assert(sizeof(float) == sizeof(uint32), "Expected float to be 4 bytes to swap as uint32");
			Ar.ByteOrderSerialize(reinterpret_cast<uint32&>(Value));
		}
		return Ar;
	}

	/**
	 * Serializes a double precision floating point value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, double& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			static_assert(sizeof(double) == sizeof(uint64), "Expected double to be 8 bytes to swap as uint64");
			Ar.ByteOrderSerialize(reinterpret_cast<uint64&>(Value));
		}
		return Ar;
	}

	/**
	 * Serializes a unsigned 64-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	FORCEINLINE friend FArchive& operator<<(FArchive &Ar, uint64& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(Value);
		}
		return Ar;
	}

	/**
	 * Serializes a signed 64-bit integer value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	/*FORCEINLINE*/friend FArchive& operator<<(FArchive& Ar, int64& Value)
	{
#if DEVIRTUALIZE_FLinkerLoad_Serialize
		if (!Ar.FastPathLoad<sizeof(Value)>(&Value))
#endif
		{
			Ar.ByteOrderSerialize(reinterpret_cast<uint64&>(Value));
		}
		return Ar;
	}

	/**
	 * Serializes enum classes as their underlying type.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	template <
		typename EnumType,
		typename = typename TEnableIf<TIsEnumClass<EnumType>::Value>::Type
	>
	FORCEINLINE friend FArchive& operator<<(FArchive& Ar, EnumType& Value)
	{
		return Ar << (__underlying_type(EnumType)&)Value;
	}

	/**
	 * Serializes an FIntRect value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	friend FArchive& operator<<(FArchive& Ar, struct FIntRect& Value);

	/**
	 * Serializes an FString value from or into an archive.
	 *
	 * @param Ar The archive to serialize from or to.
	 * @param Value The value to serialize.
	 */
	friend CORE_API FArchive& operator<<(FArchive& Ar, FString& Value);

public:
	virtual void Serialize(void* V, int64 Length) { }

	virtual void SerializeBits(void* V, int64 LengthBits)
	{
		Serialize(V, (LengthBits + 7) / 8);

		if (IsLoading() && (LengthBits % 8) != 0)
		{
			((uint8*)V)[LengthBits / 8] &= ((1 << (LengthBits & 7)) - 1);
		}
	}

	virtual void SerializeInt(uint32& Value, uint32 Max)
	{
		ByteOrderSerialize(Value);
	}

	/** Packs int value into bytes of 7 bits with 8th bit for 'more' */
	virtual void SerializeIntPacked(uint32& Value);

	/** Tells the archive to attempt to preload the specified object so data can be loaded out of it. */
	virtual void Preload(UObject* Object) { }

	/** Returns the low level archive state for this archive. */
	FArchiveState& GetArchiveState()
	{
		return ImplicitConv<FArchiveState&>(*this);
	}

	const FArchiveState& GetArchiveState() const
	{
		return ImplicitConv<const FArchiveState&>(*this);
	}

	using FArchiveState::SetArchiveState;
	using FArchiveState::SetError;
	using FArchiveState::ClearError;
	using FArchiveState::SetCriticalError;
	using FArchiveState::GetInnermostState;
	using FArchiveState::CountBytes;
	using FArchiveState::GetArchiveName;
	using FArchiveState::GetLinker;
	using FArchiveState::Tell;
	using FArchiveState::TotalSize;
	using FArchiveState::AtEnd;

	/** Attempts to set the current offset into backing data storage, this will do nothing if there is no storage. */
	virtual void Seek(int64 InPos) { }

	/**
	 * Attaches/ associates the passed in bulk data object with the linker.
	 *
	 * @param	Owner		UObject owning the bulk data
	 * @param	BulkData	Bulk data object to associate
	 */
	virtual void AttachBulkData(UObject* Owner, FUntypedBulkData* BulkData) { }

	/**
	 * Detaches the passed in bulk data object from the linker.
	 *
	 * @param	BulkData	Bulk data object to detach
	 * @param	bEnsureBulkDataIsLoaded	Whether to ensure that the bulk data is loaded before detaching
	 */
	virtual void DetachBulkData(FUntypedBulkData* BulkData, bool bEnsureBulkDataIsLoaded) { }

	/**
	* Determine if the given archive is a valid "child" of this archive. In general, this means "is exactly the same" but
	* this function allows a derived archive to support "child" or "internal" archives which are different objects that proxy the
	* original one in some way.
	*
	* @param	BulkData	Bulk data object to detach
	* @param	bEnsureBulkDataIsLoaded	Whether to ensure that the bulk data is loaded before detaching
	*/
	virtual bool IsProxyOf(FArchive* InOther) const
	{
		return InOther == this;
	}

	/**
	 * Hint the archive that the region starting at passed in offset and spanning the passed in size
	 * is going to be read soon and should be precached.
	 *
	 * The function returns whether the precache operation has completed or not which is an important
	 * hint for code knowing that it deals with potential async I/O. The archive is free to either not 
	 * implement this function or only partially precache so it is required that given sufficient time
	 * the function will return true. Archives not based on async I/O should always return true.
	 *
	 * This function will not change the current archive position.
	 *
	 * @param	PrecacheOffset	Offset at which to begin precaching.
	 * @param	PrecacheSize	Number of bytes to precache
	 * @return	false if precache operation is still pending, true otherwise
	 */
	virtual bool Precache(int64 PrecacheOffset, int64 PrecacheSize)
	{
		return true;
	}

	/**
	 * Flushes cache and frees internal data.
	 */
	virtual void FlushCache() { }

	/**
	 * Sets mapping from offsets/ sizes that are going to be used for seeking and serialization to what
	 * is actually stored on disk. If the archive supports dealing with compression in this way it is 
	 * going to return true.
	 *
	 * @param	CompressedChunks	Pointer to array containing information about [un]compressed chunks
	 * @param	CompressionFlags	Flags determining compression format associated with mapping
	 *
	 * @return true if archive supports translating offsets & uncompressing on read, false otherwise
	 */
	virtual bool SetCompressionMap(TArray<struct FCompressedChunk>* CompressedChunks, ECompressionFlags CompressionFlags)
	{
		return false;
	}

	/** 
	 * Attempts to finish writing any buffered data to disk/permanent storage.
	 */
	virtual void Flush() { }

	/** 
	 * Attempts to close and finalize any handles used for backing data storage, returns true if it succeeded.
	 */
	virtual bool Close()
	{
		return !IsError();
	}

	/**
	 * Serializes and compresses/ uncompresses data. This is a shared helper function for compression
	 * support. The data is saved in a way compatible with FIOSystem::LoadCompressedData.
	 *
	 * @param	V		Data pointer to serialize data from/ to
	 * @param	Length	Length of source data if we're saving, unused otherwise
	 * @param	Flags	Flags to control what method to use for [de]compression and optionally control memory vs speed when compressing
	 * @param	bTreatBufferAsFileReader true if V is actually an FArchive, which is used when saving to read data - helps to avoid single huge allocations of source data
	 * @param	bUsePlatformBitWindow use a platform specific bitwindow setting
	 */
	void SerializeCompressed(void* V, int64 Length, FName CompressionFormat, ECompressionFlags Flags=COMPRESS_NoFlags, bool bTreatBufferAsFileReader=false);


	using FArchiveState::IsByteSwapping;

	/** Used to do byte swapping on small items. This does not happen usually, so we don't want it inline. */
	void ByteSwap(void* V, int32 Length);

	/** Serialize data of Length bytes, taking into account byte swapping if needed. */
	FORCEINLINE FArchive& ByteOrderSerialize(void* V, int32 Length)
	{
		if (!IsByteSwapping()) // Most likely case (hot path)
		{
			Serialize(V, Length);
			return *this;
		}
		return SerializeByteOrderSwapped(V, Length); // Slowest and unlikely path (should not be inlined)
	}

	using FArchiveState::ThisContainsCode;
	using FArchiveState::ThisContainsMap;
	using FArchiveState::ThisRequiresLocalizationGather;

	/** Sets a flag indicating that this archive is currently serializing class/struct defaults. */
	void StartSerializingDefaults()
	{
		ArSerializingDefaults++;
	}

	/** Indicate that this archive is no longer serializing class/struct defaults. */
	void StopSerializingDefaults() 
	{
		ArSerializingDefaults--;
	}

	/**
	 * Called when an object begins serializing property data using script serialization.
	 */
	virtual void MarkScriptSerializationStart(const UObject* Obj) { }

	/**
	 * Called when an object stops serializing property data using script serialization.
	 */
	virtual void MarkScriptSerializationEnd(const UObject* Obj) { }

	/**
	 * Called to register a reference to a specific name value, of type TypeObject (UEnum or UStruct normally). Const so it can be called from PostSerialize
	 */
	virtual void MarkSearchableName(const UObject* TypeObject, const FName& ValueName) const { }

	using FArchiveState::GetArchetypeFromLoader;

private:
	void VARARGS LogfImpl(const TCHAR* Fmt, ...);

public:
	// Logf implementation for convenience.
	template <typename FmtType, typename... Types>
	void Logf(const FmtType& Fmt, Types... Args)
	{
		static_assert(TIsArrayOrRefOfType<FmtType, TCHAR>::Value, "Formatting string must be a TCHAR array.");
		static_assert(TAnd<TIsValidVariadicFunctionArg<Types>...>::Value, "Invalid argument(s) passed to FArchive::Logf");

		LogfImpl(Fmt, Args...);
	}

	using FArchiveState::UE4Ver;
	using FArchiveState::LicenseeUE4Ver;
	using FArchiveState::EngineVer;
	using FArchiveState::EngineNetVer;
	using FArchiveState::GameNetVer;

	/**
	 * Registers the custom version to the archive.  This is used to inform the archive that custom version information is about to be stored.
	 * There is no effect when the archive is being loaded from.
	 *
	 * @param Guid The guid of the custom version.  This must have previously been registered with FCustomVersionRegistration.
	 */
	virtual void UsingCustomVersion(const struct FGuid& Guid);

	using FArchiveState::CustomVer;

	/**
	 * Returns a pointer to an archive that represents the same data that the current archive covers, but that can be cached and reused later
	 * In the case of standard archives, this function will just return a pointer to itself. If the archive is actually a temporary proxy to
	 * another archive, and has a shorter lifecycle than the source archive, it should return either a pointer to the underlying archive, or
	 * if the data becomes inaccessible when the proxy object disappears (as is the case with text format archives) then nullptr
	 */
	virtual FArchive* GetCacheableArchive()
	{
		return this;
	}

	using FArchiveState::IsLoading;
	using FArchiveState::IsSaving;
	using FArchiveState::IsTransacting;
	using FArchiveState::IsTextFormat;
	using FArchiveState::WantBinaryPropertySerialization;
	using FArchiveState::UseUnversionedPropertySerialization;
	using FArchiveState::IsForcingUnicode;
	using FArchiveState::IsPersistent;
	using FArchiveState::GetError;
	using FArchiveState::IsError;
	using FArchiveState::IsCriticalError;
	using FArchiveState::ContainsCode;
	using FArchiveState::ContainsMap;
	using FArchiveState::RequiresLocalizationGather;
	using FArchiveState::ForceByteSwapping;
	using FArchiveState::IsSerializingDefaults;
	using FArchiveState::IsIgnoringArchetypeRef;
	using FArchiveState::DoDelta;
	using FArchiveState::DoIntraPropertyDelta;
	using FArchiveState::IsIgnoringOuterRef;
	using FArchiveState::IsIgnoringClassGeneratedByRef;
	using FArchiveState::IsIgnoringClassRef;
	using FArchiveState::IsAllowingLazyLoading;
	using FArchiveState::IsObjectReferenceCollector;
	using FArchiveState::IsModifyingWeakAndStrongReferences;
	using FArchiveState::IsCountingMemory;
	using FArchiveState::GetPortFlags;
	using FArchiveState::HasAnyPortFlags;
	using FArchiveState::HasAllPortFlags;
	using FArchiveState::GetDebugSerializationFlags;
	using FArchiveState::ShouldSkipBulkData;
	using FArchiveState::GetMaxSerializeSize;
	using FArchiveState::GetCustomVersions;
	using FArchiveState::SetCustomVersions;
	using FArchiveState::ResetCustomVersions;
	using FArchiveState::SetCustomVersion;
	using FArchiveState::SetByteSwapping;
	using FArchiveState::SetPortFlags;
	using FArchiveState::SetDebugSerializationFlags;
	using FArchiveState::IsFilterEditorOnly;
	using FArchiveState::SetFilterEditorOnly;
	using FArchiveState::IsSaveGame;
	using FArchiveState::IsNetArchive;
	using FArchiveState::IsCooking;
	using FArchiveState::CookingTarget;
	using FArchiveState::SetCookingTarget;
	using FArchiveState::UseToResolveEnumerators;
	using FArchiveState::ShouldSkipProperty;
	using FArchiveState::SetSerializedProperty;
	using FArchiveState::GetSerializedProperty;
	using FArchiveState::GetSerializedPropertyChain;
	using FArchiveState::SetSerializedPropertyChain;

	/**
	 * Push a property that is currently being serialized onto the property stack
	 * 
	 * @param InProperty			Pointer to the property that is currently being serialized
	 * @param bIsEditorOnlyProperty True if the property is editor only (call FProperty::IsEditorOnlyProperty to work this out, as the archive can't since it can't access CoreUObject types)
	 */
	virtual void PushSerializedProperty(class FProperty* InProperty, const bool bIsEditorOnlyProperty);

	/**
	 * Pop a property that was previously being serialized off the property stack
	 * 
	 * @param InProperty			Pointer to the property that was previously being serialized
	 * @param bIsEditorOnlyProperty True if the property is editor only (call FProperty::IsEditorOnlyProperty to work this out, as the archive can't since it can't access CoreUObject types)
	 */
	virtual void PopSerializedProperty(class FProperty* InProperty, const bool bIsEditorOnlyProperty);

#if WITH_EDITORONLY_DATA
	using FArchiveState::IsEditorOnlyPropertyOnTheStack;
#endif

	using FArchiveState::SetSerializeContext;
	using FArchiveState::GetSerializeContext;

	/**
	 * Adds external read dependency 
	 *
	 * @return true if dependency has been added, false if Archive does not support them
	 */
	virtual bool AttachExternalReadDependency(FExternalReadCallback& ReadCallback) { return false; };

#if USE_STABLE_LOCALIZATION_KEYS
	using FArchiveState::SetLocalizationNamespace;
	using FArchiveState::GetLocalizationNamespace;
#endif // USE_STABLE_LOCALIZATION_KEYS

	/** Resets all of the base archive members. */
	using FArchiveState::Reset;

#if DEVIRTUALIZE_FLinkerLoad_Serialize
private:
	template<SIZE_T Size>
	FORCEINLINE bool FastPathLoad(void* InDest)
	{
		const uint8* RESTRICT Src = ActiveFPLB->StartFastPathLoadBuffer;
		if (Src + Size <= ActiveFPLB->EndFastPathLoadBuffer)
		{
			if (Size == 2)
			{
				uint16 * RESTRICT Dest = (uint16 * RESTRICT)InDest;
				*Dest = FPlatformMemory::ReadUnaligned<uint16>(Src);
			}
			else if (Size == 4)
			{
				uint32 * RESTRICT Dest = (uint32 * RESTRICT)InDest;
				*Dest = FPlatformMemory::ReadUnaligned<uint32>(Src);
			}
			else if (Size == 8)
			{
				uint64 * RESTRICT Dest = (uint64 * RESTRICT)InDest;
				*Dest = FPlatformMemory::ReadUnaligned<uint64>(Src);
			}
			else
			{
				uint8 * RESTRICT Dest = (uint8 * RESTRICT)InDest;
				for (SIZE_T Index = 0; Index < Size; Index++)
				{
					Dest[Index] = Src[Index];
				}
			}
			ActiveFPLB->StartFastPathLoadBuffer += Size;
			return true;
		}
		return false;
	}

public:
	//@todoio FArchive is really a horrible class and the way it is proxied by FLinkerLoad is double terrible. It makes the fast path really hacky and slower than it would need to be.
	using FArchiveState::ActiveFPLB;
	using FArchiveState::InlineFPLB;

#else
	template<SIZE_T Size>
	FORCEINLINE bool FastPathLoad(void* InDest)
	{
		return false;
	}
#endif

private:
	// Used internally only to control the amount of generated code/type under control.
	template<typename T>
	FArchive& ByteOrderSerialize(T& Value)
	{
		static_assert(!TIsSigned<T>::Value, "To reduce the number of template instances, cast 'Value' to a uint16&, uint32& or uint64& prior to the call or use ByteOrderSerialize(void*, int32).");

		if (!IsByteSwapping()) // Most likely case (hot path)
		{
			Serialize(&Value, sizeof(T));
			return *this;
		}
		return SerializeByteOrderSwapped(Value); // Slowest and unlikely path (but fastest than SerializeByteOrderSwapped(void*, int32)).
	}

	// Not inlined to keep ByteOrderSerialize(), small and fast.
	FArchive& SerializeByteOrderSwapped(void* V, int32 Length);
	FArchive& SerializeByteOrderSwapped(uint16& Value);
	FArchive& SerializeByteOrderSwapped(uint32& Value);
	FArchive& SerializeByteOrderSwapped(uint64& Value);
#if PLATFORM_COMPILER_DISTINGUISHES_INT_AND_LONG
	FArchive& SerializeByteOrderSwapped(unsigned long& Value)
	{
		static_assert(sizeof(unsigned long) == sizeof(uint64), "Wrong unsigned long size assuption.");
		return SerializeByteOrderSwapped(reinterpret_cast<uint64&>(Value));
	}
#endif

private:
	using FArchiveState::ArIsLoading;
	using FArchiveState::ArIsSaving;
	using FArchiveState::ArIsTransacting;
	using FArchiveState::ArIsTextFormat;
	using FArchiveState::ArWantBinaryPropertySerialization;
	using FArchiveState::ArUseUnversionedPropertySerialization;
	using FArchiveState::ArForceUnicode;
	using FArchiveState::ArIsPersistent;

public:
	using FArchiveState::ArIsError;
	using FArchiveState::ArIsCriticalError;
	using FArchiveState::ArContainsCode;
	using FArchiveState::ArContainsMap;
	using FArchiveState::ArRequiresLocalizationGather;
	using FArchiveState::ArForceByteSwapping;
	using FArchiveState::ArIgnoreArchetypeRef;
	using FArchiveState::ArNoDelta;
	using FArchiveState::ArNoIntraPropertyDelta;
	using FArchiveState::ArIgnoreOuterRef;
	using FArchiveState::ArIgnoreClassGeneratedByRef;
	using FArchiveState::ArIgnoreClassRef;
	using FArchiveState::ArAllowLazyLoading;
	using FArchiveState::ArIsObjectReferenceCollector;
	using FArchiveState::ArIsModifyingWeakAndStrongReferences;
	using FArchiveState::ArIsCountingMemory;
	using FArchiveState::ArShouldSkipBulkData;
	using FArchiveState::ArIsFilterEditorOnly;
	using FArchiveState::ArIsSaveGame;
	using FArchiveState::ArIsNetArchive;
	using FArchiveState::ArUseCustomPropertyList;
	using FArchiveState::ArSerializingDefaults;
	using FArchiveState::ArPortFlags;
	using FArchiveState::ArMaxSerializeSize;

public:
	using FArchiveState::SetIsLoading;
	using FArchiveState::SetIsSaving;
	using FArchiveState::SetIsTransacting;
	using FArchiveState::SetIsTextFormat;
	using FArchiveState::SetWantBinaryPropertySerialization;
	using FArchiveState::SetUseUnversionedPropertySerialization;
	using FArchiveState::SetForceUnicode;
	using FArchiveState::SetIsPersistent;
	using FArchiveState::SetUE4Ver;
	using FArchiveState::SetLicenseeUE4Ver;
	using FArchiveState::SetEngineVer;
	using FArchiveState::SetEngineNetVer;
	using FArchiveState::SetGameNetVer;

private:
	using FArchiveState::ArUE4Ver;
	using FArchiveState::ArLicenseeUE4Ver;
	using FArchiveState::ArEngineVer;
	using FArchiveState::ArEngineNetVer;
	using FArchiveState::ArGameNetVer;
	using FArchiveState::CustomVersionContainer;

public:
	/** Custom property list attribute. If the flag below is set, only these properties will be iterated during serialization. If NULL, then no properties will be iterated. */
	using FArchiveState::ArCustomPropertyList;

	class FScopeSetDebugSerializationFlags
	{
	private:
#if WITH_EDITOR
		uint32 PreviousFlags;
		FArchive& Ar;
#endif
	public:
		/**
		 * Initializes an object which will set flags for the scope of this code
		 * 
		 * @param NewFlags new flags to set 
		 * @param Remove should we add these flags or remove them default is to add
		 */
#if WITH_EDITOR
		FScopeSetDebugSerializationFlags(FArchive& InAr, uint32 NewFlags, bool Remove = false)
			: Ar(InAr)
		{

			PreviousFlags = Ar.GetDebugSerializationFlags();
			if (Remove)
			{
				Ar.SetDebugSerializationFlags( PreviousFlags & ~NewFlags);
			}
			else
			{
				Ar.SetDebugSerializationFlags( PreviousFlags | NewFlags);
			}

		}
		~FScopeSetDebugSerializationFlags()
		{

			Ar.SetDebugSerializationFlags( PreviousFlags);
		}
#else
		FScopeSetDebugSerializationFlags(FArchive& InAr, uint32 NewFlags, bool Remove = false)
		{}
		~FScopeSetDebugSerializationFlags()
		{}
#endif
	};

#if WITH_EDITOR
	/** Custom serialization modifier flags can be used for anything */
	using FArchiveState::ArDebugSerializationFlags;
	
	/** Debug stack storage if you want to add data to the archive for usage further down the serialization stack this should be used in conjunction with the FScopeAddDebugData struct */
	virtual void PushDebugDataString(const FName& DebugData);
	virtual void PopDebugDataString() { }

	class FScopeAddDebugData
	{
	private:
		FArchive& Ar;
	public:
		CORE_API FScopeAddDebugData(FArchive& InAr, const FName& DebugData);

		~FScopeAddDebugData()
		{
			Ar.PopDebugDataString();
		}
	};
#endif

	/** Called whilst cooking to provide file region hints to the cooker. */
	virtual void PushFileRegionType(EFileRegionType Type) { }
	virtual void PopFileRegionType() { }

private:
	/** Holds the cooking target platform. */
	using FArchiveState::CookingTargetPlatform;

	/** Holds the pointer to the property that is currently being serialized */
	using FArchiveState::SerializedProperty;

	/** Holds the chain of properties that are currently being serialized */
	using FArchiveState::SerializedPropertyChain;

#if USE_STABLE_LOCALIZATION_KEYS
	/**
	 * The localization namespace that this archive should use when serializing text properties.
	 * This is typically the namespace used by the package being serialized (if serializing a package, or an object within a package).
	 * Stored as a pointer to a heap-allocated string because of a dependency between TArray (thus FString) and FArchive; null should be treated as an empty string.
	 */
	using FArchiveState::LocalizationNamespacePtr;
#endif // USE_STABLE_LOCALIZATION_KEYS

	/**
	 * Indicates if the custom versions container is in a 'reset' state.  This will be used to defer the choice about how to
	 * populate the container until it is needed, where the read/write state will be known.
	 */
	using FArchiveState::bCustomVersionsAreReset;
};




/**
 * Template for archive constructors.
 */
template<class T> T Arctor(FArchive& Ar)
{
	T Tmp;
	Ar << Tmp;

	return Tmp;
}

go to that location and send the code of “archive.CPP” and “archive.h” in the text

I can post more, but here’s the block where the error came. I guess due to it not having a valid header?
if (!bHeaderWasValid)
{
UE_LOG(LogSerialization, Log, TEXT(“ArchiveName: %s”), *GetArchiveName());
UE_LOG(LogSerialization, Log, TEXT(“Archive UE4 Version: %d”), UE4Ver());
UE_LOG(LogSerialization, Log, TEXT(“Archive Licensee Version: %d”), LicenseeUE4Ver());
UE_LOG(LogSerialization, Log, TEXT(“Position: %lld”), Tell());
UE_LOG(LogSerialization, Log, TEXT(“Read Size: %lld”), Length);
UE_LOG(LogSerialization, Fatal, TEXT(“BulkData compressed header read error. This package may be corrupt!”));
}

.h is in the same location as CPP .you can save your file as text and send them as an attachment

both files have been added to the original post. I couldn’t add them in .txt files but I added them with the code option.