虚幻4 加载蓝图的的过程(1)——读取文件头

首先是读取文件头:

文件头结构体:

Engine_Updating\Engine\Source\Runtime\CoreUObject\Public\UObject\Linker.h

/**
 * A "table of contents" for an Unreal package file.  Stored at the top of the file.
 */
struct FPackageFileSummary
{
	/**
	 * Magic tag compared against PACKAGE_FILE_TAG to ensure that package is an Unreal package.
	 */
	int32		Tag;

private:
	/* UE4 file version */
	int32		FileVersionUE4;
	/* Licensee file version */
	int32		FileVersionLicenseeUE4;
	/* Custom version numbers. Keyed off a unique tag for each custom component. */
	FCustomVersionContainer CustomVersionContainer;

public:
	/**
	 * Total size of all information that needs to be read in to create a FLinkerLoad. This includes
	 * the package file summary, name table and import & export maps.
	 */
	int32		TotalHeaderSize;

	/**
	 * The flags for the package
	 */
	uint32	PackageFlags;

	/**
	 * The Generic Browser folder name that this package lives in
	 */
	FString	FolderName;

	/**
	 * Number of names used in this package
	 */
	int32		NameCount;

	/**
	 * Location into the file on disk for the name data
	 */
	int32 	NameOffset;

	/**
	 * Number of gatherable text data items in this package
	 */
	int32	GatherableTextDataCount;

	/**
	 * Location into the file on disk for the gatherable text data items
	 */
	int32 	GatherableTextDataOffset;
	
	/**
	 * Number of exports contained in this package
	 */
	int32		ExportCount;

	/**
	 * Location into the file on disk for the ExportMap data
	 */
	int32		ExportOffset;

	/**
	 * Number of imports contained in this package
	 */
	int32		ImportCount;

	/**
	 * Location into the file on disk for the ImportMap data
	 */
	int32		ImportOffset;

	/**
	* Location into the file on disk for the DependsMap data
	*/
	int32		DependsOffset;

	/**
	 * Number of references contained in this package
	 */
	int32		StringAssetReferencesCount;

	/**
	 * Location into the file on disk for the string asset references map data
	 */
	int32		StringAssetReferencesOffset;

	/**
	 * Thumbnail table offset
	 */
	int32		ThumbnailTableOffset;

	/**
	 * Current id for this package
	 */
	FGuid	Guid;

	/**
	 * Data about previous versions of this package
	 */
	TArray Generations;

	/**
	 * Engine version this package was saved with. For hotfix releases and engine versions which maintain strict binary compatibility with another version, this may differ from CompatibleWithEngineVersion.
	 */
	FEngineVersion SavedByEngineVersion;

	/**
	 * Engine version this package is compatible with. See SavedByEngineVersion.
	 */
	FEngineVersion CompatibleWithEngineVersion;

	/**
	 * Flags used to compress the file on save and uncompress on load.
	 */
	uint32	CompressionFlags;

	/**
	 * Value that is used to determine if the package was saved by Epic (or licensee) or by a modder, etc
	 */
	uint32	PackageSource;

	/**
	 * Array of compressed chunks in case this package was stored compressed.
	 */
	TArray CompressedChunks;

	/**
	 * List of additional packages that are needed to be cooked for this package (ie streaming levels)
	 */
	TArray	AdditionalPackagesToCook;

	/** 
	 * If true, this file will not be saved with version numbers or was saved without version numbers. In this case they are assumed to be the current version. 
	 * This is only used for full cooks for distribution because it is hard to guarantee correctness 
	 **/
	bool bUnversioned;

#if WITH_ENGINE
	/**
	 * Information about the textures stored in the package.
	 */
	FTextureAllocations	TextureAllocations;
#endif		// WITH_ENGINE

	/**
	 * Location into the file on disk for the asset registry tag data
	 */
	int32 	AssetRegistryDataOffset;

	/** Offset to the location in the file where the bulkdata starts */
	int64	BulkDataStartOffset;
	/**
	 * Offset to the location in the file where the FWorldTileInfo data starts
	 */
	int32 	WorldTileInfoDataOffset;

	/**
	 * Streaming install ChunkIDs
	 */
	TArray	ChunkIDs;


	/** Constructor */
	COREUOBJECT_API FPackageFileSummary();

	int32 GetFileVersionUE4() const
	{
		return FileVersionUE4;
	}

	int32 GetFileVersionLicenseeUE4() const
	{
		return FileVersionLicenseeUE4;
	}

	const FCustomVersionContainer& GetCustomVersionContainer() const
	{
		return CustomVersionContainer;
	}

	void SetCustomVersionContainer(const FCustomVersionContainer& InContainer)
	{
		CustomVersionContainer = InContainer;
	}

	void SetFileVersions(const int32 EpicUE4, const int32 LicenseeUE4, const bool bInSaveUnversioned = false)
	{
		FileVersionUE4 = EpicUE4;
		FileVersionLicenseeUE4 = LicenseeUE4;
		bUnversioned = bInSaveUnversioned;
	}

	/** I/O function */
	friend COREUOBJECT_API FArchive& operator<<( FArchive& Ar, FPackageFileSummary& Sum );
};


读取文件头函数位置:

Engine_Updating\Engine\Source\Runtime\CoreUObject\Private\UObject\PackageFileSummary.cpp

FArchive& operator<<( FArchive& Ar, FPackageFileSummary& Sum )
{
	bool bCanStartSerializing = true;
	int64 ArchiveSize = 0;
	if (Ar.IsLoading())
	{
		// Sanity checks before we even start serializing the archive
		ArchiveSize = Ar.TotalSize();
		const int64 MinimumPackageSize = 32; // That should get us safely to Sum.TotalHeaderSize
		bCanStartSerializing = ArchiveSize >= MinimumPackageSize;
		UE_CLOG(!bCanStartSerializing, LogLinker, Warning,
			TEXT("Failed to read package file summary, the file \"%s\" is too small (%lld bytes, expected at least %lld bytes)"),
			*Ar.GetArchiveName(), ArchiveSize, MinimumPackageSize);
	}
	if (bCanStartSerializing)
	{
		Ar << Sum.Tag;
	}
	// only keep loading if we match the magic
	if( Sum.Tag == PACKAGE_FILE_TAG || Sum.Tag == PACKAGE_FILE_TAG_SWAPPED )
	{
		// The package has been stored in a separate endianness than the linker expected so we need to force
		// endian conversion. Latent handling allows the PC version to retrieve information about cooked packages.
		if( Sum.Tag == PACKAGE_FILE_TAG_SWAPPED )
		{
			// Set proper tag.
			Sum.Tag = PACKAGE_FILE_TAG;
			// Toggle forced byte swapping.
			if( Ar.ForceByteSwapping() )
			{
				Ar.SetByteSwapping( false );
			}
			else
			{
				Ar.SetByteSwapping( true );
			}
		}
		/**
		 * The package file version number when this package was saved.
		 *
		 * Lower 16 bits stores the UE3 engine version
		 * Upper 16 bits stores the UE4/licensee version
		 * For newer packages this is -6
		 *		-2 indicates presence of enum-based custom versions
		 *		-3 indicates guid-based custom versions
		 *		-4 indicates removal of the UE3 version. Packages saved with this ID cannot be loaded in older engine versions 
		 *		-5 indicates the replacement of writing out the "UE3 version" so older versions of engine can gracefully fail to open newer packages
		 *		-6 indicates optimizations to how custom versions are being serialized
		 */
		const int32 CurrentLegacyFileVersion = -6;
		int32 LegacyFileVersion = CurrentLegacyFileVersion;
		Ar << LegacyFileVersion;

		if (Ar.IsLoading())
		{
			if (LegacyFileVersion < 0) // means we have modern version numbers
			{
				if (LegacyFileVersion < CurrentLegacyFileVersion)
				{
					// we can't safely load more than this because the legacy version code differs in ways we can not predict.
					// Make sure that the linker will fail to load with it.
					Sum.FileVersionUE4 = 0;
					Sum.FileVersionLicenseeUE4 = 0;
					return Ar;
				}

				if (LegacyFileVersion != -4)
				{
					int32 LegacyUE3Version = 0;
					Ar << LegacyUE3Version;
				}
				Ar << Sum.FileVersionUE4;
				Ar << Sum.FileVersionLicenseeUE4;

				if (LegacyFileVersion <= -2)
				{
					Sum.CustomVersionContainer.Serialize(Ar, GetCustomVersionFormatForArchive(LegacyFileVersion));
				}

				if (!Sum.FileVersionUE4 && !Sum.FileVersionLicenseeUE4)
				{
					// this file is unversioned, remember that, then use current versions
					Sum.bUnversioned = true;
					Sum.FileVersionUE4 = GPackageFileUE4Version;
					Sum.FileVersionLicenseeUE4 = GPackageFileLicenseeUE4Version;

					Sum.CustomVersionContainer = FCustomVersionContainer::GetRegistered();
				}
			}
			else
			{
				// This is probably an old UE3 file, make sure that the linker will fail to load with it.
				Sum.FileVersionUE4 = 0;
				Sum.FileVersionLicenseeUE4 = 0;
			}
		}
		else
		{
			if (Sum.bUnversioned)
			{
				int32 Zero = 0;
				Ar << Zero; // LegacyUE3version
				Ar << Zero; // VersionUE4
				Ar << Zero; // VersionLicenseeUE4

				FCustomVersionContainer NoCustomVersions;
				NoCustomVersions.Serialize(Ar);
			}
			else
			{
				// Must write out the last UE3 engine version, so that older versions identify it as new
				int32 LegacyUE3Version = 864;
				Ar << LegacyUE3Version;
				Ar << Sum.FileVersionUE4;
				Ar << Sum.FileVersionLicenseeUE4;

				// Serialise custom version map.
				Sum.CustomVersionContainer.Serialize(Ar);
			}
		}
		Ar << Sum.TotalHeaderSize;
		Ar << Sum.FolderName;
		Ar << Sum.PackageFlags;

#if WITH_EDITOR
		if (Ar.IsLoading())
		{
			// This flag should never be saved and its reused, so we need to make sure it hasn't been loaded.
			Sum.PackageFlags &= ~PKG_NewlyCreated;
		}
#endif // WITH_EDITOR

		if( Sum.PackageFlags & PKG_FilterEditorOnly )
		{
			Ar.SetFilterEditorOnly(true);
		}
		Ar << Sum.NameCount					<< Sum.NameOffset;
		if (Sum.FileVersionUE4 >= VER_UE4_SERIALIZE_TEXT_IN_PACKAGES)
		{
			Ar << Sum.GatherableTextDataCount	<< Sum.GatherableTextDataOffset;
		}
		Ar << Sum.ExportCount				<< Sum.ExportOffset;
		Ar << Sum.ImportCount				<< Sum.ImportOffset;
		Ar << Sum.DependsOffset;

		if (Ar.IsLoading() && (Sum.FileVersionUE4 < VER_UE4_OLDEST_LOADABLE_PACKAGE || Sum.FileVersionUE4 > GPackageFileUE4Version))
		{
			return Ar; // we can't safely load more than this because the below was different in older files.
		}

		if (Ar.IsSaving() || Sum.FileVersionUE4 >= VER_UE4_ADD_STRING_ASSET_REFERENCES_MAP)
		{
			Ar << Sum.StringAssetReferencesCount << Sum.StringAssetReferencesOffset;
		}

		Ar << Sum.ThumbnailTableOffset;

		int32 GenerationCount = Sum.Generations.Num();
		Ar << Sum.Guid << GenerationCount;
		if( Ar.IsLoading() && GenerationCount > 0 )
		{
			Sum.Generations.Empty( 1 );
			Sum.Generations.AddUninitialized( GenerationCount );
		}
		for( int32 i=0; i= VER_UE4_ENGINE_VERSION_OBJECT )
		{
			if(Ar.IsCooking() || (Ar.IsSaving() && !FEngineVersion::Current().HasChangelist()))
			{
				FEngineVersion EmptyEngineVersion;
				Ar << EmptyEngineVersion;
			}
			else
			{
				Ar << Sum.SavedByEngineVersion;
			}
		}
		else
		{
			int32 EngineChangelist = 0;
			Ar << EngineChangelist;

			if(Ar.IsLoading() && EngineChangelist != 0)
			{
				Sum.SavedByEngineVersion.Set(4, 0, 0, EngineChangelist, TEXT(""));
			}
		}

		if (Sum.GetFileVersionUE4() >= VER_UE4_PACKAGE_SUMMARY_HAS_COMPATIBLE_ENGINE_VERSION )
		{
			if(Ar.IsCooking() || (Ar.IsSaving() && !FEngineVersion::Current().HasChangelist()))
			{
				FEngineVersion EmptyEngineVersion;
				Ar << EmptyEngineVersion;
			}
			else
			{
				Ar << Sum.CompatibleWithEngineVersion;
			}
		}
		else
		{
			if (Ar.IsLoading())
			{
				Sum.CompatibleWithEngineVersion = Sum.SavedByEngineVersion;
			}
		}

		Ar << Sum.CompressionFlags;
		Ar << Sum.CompressedChunks;
		Ar << Sum.PackageSource;

		Ar << Sum.AdditionalPackagesToCook;

#if WITH_ENGINE
		//@todo legacy
		Ar << Sum.TextureAllocations;
#else
		check(!"this can't serialize successfully");
#endif		// WITH_ENGINE

		Ar << Sum.AssetRegistryDataOffset;
		Ar << Sum.BulkDataStartOffset;
		
		if (Sum.GetFileVersionUE4() >= VER_UE4_WORLD_LEVEL_INFO)
		{
			Ar << Sum.WorldTileInfoDataOffset;
		}

		if (Sum.GetFileVersionUE4() >= VER_UE4_CHANGED_CHUNKID_TO_BE_AN_ARRAY_OF_CHUNKIDS)
		{
			Ar << Sum.ChunkIDs;
		}
		else if (Sum.GetFileVersionUE4() >= VER_UE4_ADDED_CHUNKID_TO_ASSETDATA_AND_UPACKAGE)
		{
			// handle conversion of single ChunkID to an array of ChunkIDs
			if (Ar.IsLoading())
			{
				int ChunkID = -1;
				Ar << ChunkID;

				// don't load <0 entries since an empty array represents the same thing now
				if (ChunkID >= 0)
				{
					Sum.ChunkIDs.Add( ChunkID );
				}
			}
		}
	}

	return Ar;
}



你可能感兴趣的:(虚幻4 加载蓝图的的过程(1)——读取文件头)