【UE】pak的mount(带源码解析)

这篇具有很好参考价值的文章主要介绍了【UE】pak的mount(带源码解析)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

本文使用的引擎版本为UE4.27
为了方便理解,文中选取的代码均为部分截取,只截取与小节相关的部分

概述

正常的散文件加载是使用FFileHelper::LoadFileToArray等接口来读取文件内容。但pak作为一个类似于压缩包的格式,其中的文件无法直接使用这种方式读取。故需要使用mount来挂载。

mount操作告诉系统有哪些文件可以从pak中读到,并提供虚拟路径使系统可以通过FPakPlatformFile::CopyFileFFileHelper::LoadFileToString等操作普通文件的方法操作pak中的文件

几个涉及到的结构

IPlatformFile:文件IO的接口,是整个文件系统的基类。该类及其子类以链式组织,每个实例存有其下层的引用,每层访问的时候都先查找自身,找不到才向下层查找。

FPakPlatformFile:继承于IPlatformFile,负责pak的mount。它的私有成员ExcludedNonPakExtensions记录了几个只应存在pak里的文件拓展:uasset、umap、ubulk、uexp、uptnl和ushaderbytecode。这些文件如果在pak里没有找到,就不再查找它的下层了。

FPakListEntry:定义在FPakPlatformFile内的结构体,有ReadOrder和PakFile两个属性。FPakPlatformFile中用几个TArray来记录mount到的pak

FPakFile:Pak在C++中存储的形式。有PakFilename、LastUseTime、Info等成员
FPakInfo:Pak的提纲信息,存有版本号、哈希值、魔数、是否加密等
FPakEntry:Pak中单个文件的信息,存储文件大小、在pak中的偏移量、是否加密等

Mount时机

很多地方都会调到FPakPlatformFile::Mount进行pak的Mount,这里只分析引擎启动时进行的mount

引擎启动时进行的初始化mount位于 FPakPlatformFile::Initialize。如果使用命令行指定了PakFile单例,会在引擎PreInit的阶段通过ConditionallyCreateFileWrapper函数创建单例并调用 FPakPlatformFile::Initialize。如果没有在命令行中指定,则该初始化函数在EditorInit阶段才进行。后者的调用堆栈如下:
【UE】pak的mount(带源码解析)

pak读取优先级

概述中提到,mount的作用是为了提供一种读取pak文件的方法,使pak中的文件也能使用操作散文件的操作方法。即:mount并不是读取pak中的文件。故mount顺序其实对pak的读取优先级没有影响

那么pak读取的优先级到底取决于什么呢? 做热更需求的时候如何保证自己新添加的pak可以覆盖掉原来pak中的资源?答案是取决于FPakListEntry的ReadOrder:ReadOrder大的pak会覆盖小的pak的资源内容

// IPlatformFilePak.h
struct FPakListEntry
{
	FPakListEntry(): ReadOrder(0), PakFile(nullptr){}

	uint32		ReadOrder;
	TRefCountPtr<FPakFile>	PakFile;
	
	// ReadOrder越大,优先级越高。故热更的时候只需要保证新pak的ReadOrder大于原来的pak即可
	FORCEINLINE bool operator < (const FPakListEntry& RHS) const
	{
		return ReadOrder > RHS.ReadOrder;
	}
};	

这个ReadOrder是在FPakPlatformFile::Mount(const TCHAR* InPakFilename, uint32 PakOrder, ...)指定的,未指定的话使用最低的优先级0

在进入mount之前,Initialize函数中会按照pak的路径和名字,给这个pak赋一个ReadOrder(即下文中的PakOrder)。

目录优先级

// IPlatformFilePak.cpp
bool FPakPlatformFile::Initialize(IPlatformFile* Inner, const TCHAR* CmdLine)
{
	……
#if EXCLUDE_NONPAK_UE_EXTENSIONS && !WITH_EDITOR
	// Extensions for file types that should only ever be in a pak file. Used to stop unnecessary access to the lower level platform file
	ExcludedNonPakExtensions.Add(TEXT("uasset"));
	ExcludedNonPakExtensions.Add(TEXT("umap"));
	ExcludedNonPakExtensions.Add(TEXT("ubulk"));
	ExcludedNonPakExtensions.Add(TEXT("uexp"));
	ExcludedNonPakExtensions.Add(TEXT("uptnl"));
	ExcludedNonPakExtensions.Add(TEXT("ushaderbytecode"));
#endif
	……
	// Find and mount pak files from the specified directories.
	TArray<FString> PakFolders;
	GetPakFolders(FCommandLine::Get(), PakFolders);
	MountAllPakFiles(PakFolders, *StartupPaksWildcard);
	……
}

FPakPlatformFile初始化的时候除了对一些成员变量进行初始化以外,还会调用MountAllPakFiles进行pak的mount。

int32 FPakPlatformFile::MountAllPakFiles(const TArray<FString>& PakFolders, const FString& WildCard)
{
	……
	if (bMountPaks)
	{
		TArray<FString> FoundPakFiles;
		FindAllPakFiles(LowerLevel, PakFolders, WildCard, FoundPakFiles);
		……
		for (int32 PakFileIndex = 0; PakFileIndex < FoundPakFiles.Num(); PakFileIndex++)
		{
			const FString& PakFilename = FoundPakFiles[PakFileIndex];
			……
			uint32 PakOrder = GetPakOrderFromPakFilePath(PakFilename);

			UE_LOG(LogPakFile, Display, TEXT("Mounting pak file %s."), *PakFilename);

			if (Mount(*PakFilename, PakOrder))
			{
				++NumPakFilesMounted;
			}
		}
	}
	return NumPakFilesMounted;
}

MountAllPakFiles其实就是读取需要mount的pak,遍历进行挂载。
其中GetPakOrderFromPakFilePath依据pak所属目录获取其优先级:

int32 FPakPlatformFile::GetPakOrderFromPakFilePath(const FString& PakFilePath)
{
	if (PakFilePath.StartsWith(FString::Printf(TEXT("%sPaks/%s-"), *FPaths::ProjectContentDir(), FApp::GetProjectName())))
	{
		return 4;
	}
	else if (PakFilePath.StartsWith(FPaths::ProjectContentDir()))
	{
		return 3;
	}
	else if (PakFilePath.StartsWith(FPaths::EngineContentDir()))
	{
		return 2;
	}
	else if (PakFilePath.StartsWith(FPaths::ProjectSavedDir()))
	{
		return 1;
	}

	return 0;
}

可以看到,确立pak读取优先级的基本策略是:Project/Content/Paks/ProjectName-*.pak > Project/Content/Paks/*.pak > Engine/Content/Paks/*.pak > Project/Saved/Paks/*.pak

根据文件名定优先级

在经过上述目录优先级的处理以后,如果文件名以_n_P结尾,则将其优先级提升到 P a k O r d e r + ( n + 1 ) × 100     ( n ≥ 1 ) PakOrder + (n + 1)×100 \space\space\space(n \geq 1) PakOrder+(n+1)×100   (n1)

// IPlatformFilePak.cpp
bool FPakPlatformFile::Mount(const TCHAR* InPakFilename, uint32 PakOrder, const TCHAR* InPath /*= NULL*/, bool bLoadIndex /*= true*/)
{
	……
	if (PakFilename.EndsWith(TEXT("_P.pak")))
	{
		// Prioritize based on the chunk version number
		// Default to version 1 for single patch system
		uint32 ChunkVersionNumber = 1;
		FString StrippedPakFilename = PakFilename.LeftChop(6);
		int32 VersionEndIndex = PakFilename.Find("_", ESearchCase::CaseSensitive, ESearchDir::FromEnd);
		if (VersionEndIndex != INDEX_NONE && VersionEndIndex > 0)
		{
			int32 VersionStartIndex = PakFilename.Find("_", ESearchCase::CaseSensitive, ESearchDir::FromEnd, VersionEndIndex - 1);
			if (VersionStartIndex != INDEX_NONE)
			{
				VersionStartIndex++;
				FString VersionString = PakFilename.Mid(VersionStartIndex, VersionEndIndex - VersionStartIndex);
				if (VersionString.IsNumeric())
				{
					int32 ChunkVersionSigned = FCString::Atoi(*VersionString);
					if (ChunkVersionSigned >= 1)
					{
						// Increment by one so that the first patch file still gets more priority than the base pak file
						ChunkVersionNumber = (uint32)ChunkVersionSigned + 1;
					}
				}
			}
		}
		PakOrder += 100 * ChunkVersionNumber;
	}
	……
}

综上所述

pak优先级的确立方法:

  1. 确立pak读取优先级的基本策略是:Project/Content/Paks/ProjectName-*.pak > Project/Content/Paks/*.pak > Engine/Content/Paks/*.pak > Project/Saved/Paks/*.pak

  2. 在经过上述目录优先级的粗略处理以后,如果文件名以_n_P结尾,则将其优先级提升到 P a k O r d e r + ( n + 1 ) × 100     ( n ≥ 1 ) PakOrder + (n + 1)×100 \space\space\space(n \geq 1) PakOrder+(n+1)×100   (n1)文章来源地址https://www.toymoban.com/news/detail-418884.html

到了这里,关于【UE】pak的mount(带源码解析)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • UE4大场景解决方案 ——Pak的打包与加载

    1.cook Content烘焙uasset文件 2.UnrealPak打包Pak文件 3.FPakFile、FPakPlatformFile从Pak文件中遍历文件StaticLoadObject加载特定类型的UObject 4.SpawActor在世界中创建物体 先将我们要打包的资源放在一起,如下: 需要打包pak的内容 如果希望共享网格贴图等资源,也可以单独导出Test_01这个BP。 但

    2023年04月08日
    浏览(49)
  • UE4查看加密PAK里边的资源Android/iOS/PC方法

    我们经常会需要把1个模型进行减面然后在移动端使用,有时候会出现移动端模型和PC端模型不一致的问题,这时候就需要将移动端的模型和PC端的模型进行对比,找到问题出现的原因,检查Mesh、Normal、UV0、UV1、MaterialId、碰撞等是否一致。 如何打包Pak文件,见这篇文章:UE4打

    2024年02月14日
    浏览(54)
  • 【虚幻引擎】UE4 Windows下打包Linux版本的包

    首先上官网下载对应版本的工具链安装 官网链接;:https://docs.unrealengine.com/4.26/en-US/SharingAndReleasing/Linux/GettingStarted/ 下载完之后点击安装exe,等待安装完成  二、检查是否安装成功 在cmd中运行 %LINUX_MULTIARCH_ROOT%x86_64-unknown-linux-gnubinclang++ -v , 出现这个提示表示运行成功  三、在

    2024年02月14日
    浏览(47)
  • 【虚幻引擎UE】UE5 Pak资源分包加密打包与加载(安卓篇)

    【虚幻引擎UE】UE5 Pak分包加密及热更新(安卓篇) 相关文章: 1.介绍了安卓项目打包的基本操作: 【虚幻引擎UE】UE5仅需5个步骤快速实现AR项目调试与打包(安卓篇) https://tjgzs.blog.csdn.net/article/details/126097508 2.介绍了PAK加载的基本操作: 【虚幻引擎UE】UE5 热更新动态PAK资源加

    2024年02月08日
    浏览(53)
  • 虚幻引擎UE4源码编译安装(x86,arm64平台)

    (1)关于运行Setup.sh脚本,mono报错,详情截图如下: 分析:不能执行二进制文件mono,根据错误提示找到源码中涉及到具体执行语句为: “mono Engine/Binaries/DotNET/GitDependencies.exe $ARGS”         GitDependencies.exe可执行文件的作用在线下载UE依赖库,而mono是跨平台.net运行环境,

    2024年02月06日
    浏览(94)
  • 【程序员必备】UE4 C++ 虚幻引擎:详解JSON文件读、写、解析,打造高效开发!

    🙋‍♂️ 作者:海码007 📜 专栏:UE虚幻引擎专栏 💥 标题:【程序员必备】UE4 C++ 虚幻引擎:详解JSON文件读、写、解析,打造高效开发! ❣️ 寄语:人生的意义或许可以发挥自己全部的潜力,所以加油吧! 🎈 最后: 文章作者技术和水平有限,如果文中出现错误,希望大

    2024年02月03日
    浏览(57)
  • 【UE 插件】UE4 虚幻引擎 插件开发(带源码插件打包、无源码插件打包) 有这一篇文章就够了!!!

    🙋‍♂️ 作者:海码007 📜 专栏:UE虚幻引擎专栏 💥 标题:【UE 插件】UE4 虚幻引擎 插件开发(带源码插件打包、无源码插件打包) 有这一篇文章就够了!!! ❣️ 寄语:将来的自己肯定会感谢现在努力的你! 🎈 最后: 文章作者技术和水平有限,如果文中出现错误,希

    2024年02月08日
    浏览(57)
  • ubuntu18.04源码编译安装carla0.9.13,关联UE4.26虚幻引擎账号

    参考博客:https://www.cnblogs.com/chenjian688/p/16624095.html 查看推荐显卡 找到recommended推荐的版本,本机是470版本。 本机是470版本 如果安装失败,需要在安装之前进行 sudo apt-get update 指令 同时为了避免UE和 CARLA 依赖项之间的兼容性问题,使用相同的编译器版本和 C++ runtime library来编

    2024年02月14日
    浏览(56)
  • UE4 Unlua源码解析9 - 静态绑定和动态绑定的实现原理

    先说明白什么是静态绑定,什么是动态绑定 静态绑定就是继承了UnluaInterface的类,会在对象创建的时候绑定Lua对象 动态绑定就是没有继承UnluaInterface的类,会在Lua端通过\\\"NewObject\\\"和\\\"SpawnActor\\\"创建的时候,主动进行绑定 静态绑定 UE对象和Lua对象的时机在什么时候呢?就在UE对象

    2023年04月12日
    浏览(48)
  • blender导出UE4用的FBX骨骼动画

    blender基础准备 部分约束修改器会在导出的时候会被烘培 blender当前帧的物体状态会变成UE4的默认状态 blender导出准备 路径模式:自动 内嵌纹理:True 批量模式:关闭 选定的物体:True 活动集合:False 物体类型:所有类型 自定义属性:False 缩放:1 应用缩放:FBX全部 前进:-X前进 向上:Z向上

    2024年02月04日
    浏览(58)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包