技术标签: UE4
https://arcecho.github.io/2017/07/02/UE4-Pak-%E7%9B%B8%E5%85%B3%E7%9F%A5%E8%AF%86%E6%80%BB%E7%BB%93/
Diposting di 2017-07-02 | Edited on 2019-03-08 | Di Tech
近来研究了下UE4中Pak文件的工作流程,并对UE4中的文件系统了解了下。这个过程中,我发现现有的资料讲的比较乱,且有的版本很老。遂在此按照自己理解来简单阐述下UE4中和Pak文件相关的各种知识,如果有什么错误或者不明白的地方请在下方留言或者发送Email:[email protected]。
这里根据自己的理解把使用Pak时需要的核心概念提炼出来了。
印证了《Gmae Engine Architechture》中的一些设计
之前看那本书的感触不是特别深,感觉太理论化。在研究UE4的时候,发现UE4实际上的很多设计就是那本书的一些印证。
UE4和绝大多数游戏引擎一样使用了文件系统即资源管理器的方式管理的文件和游戏资源,比如PlatformFile就是可以认为其平台独立层的File system,而使用的Package管理的方式就是对应其资源管理器的概念。
后面记《GEA》为《Gmae Engine Architechture》。
File System
书中列举的主要用途如下:
除了主要用途,文件系统还要可能需要满足资源Packaging,Patching等功能。
我所了解比较好的文件系统例子是暴雪的CASC,我们玩的WOW的更新及修复什么的,都是依靠它实现的。
UE4中的对应的一些概念
File
File在UE4中的概念,实际上和我们使用操作系统时的是基本一致的,用来记录数据信息。
Asset Package
实际上UE4中没有Asset Package这个名词,只有Package,为了区别于Packaging Project的package,这里先声明这样的记法。Asset Package,就是指的在UE4中能够在直接使用的游戏资源,比如material,map,blueprint等,每一个独立的资源的对应一个Package概念。
PlatformFile
UE4中使用使用IPlatformFile来抽象出平台无关的文件操作的接口,对应《GEA》中架构的平台独立层中的文件系统。 相对Asset Reference方式来说这是一个低层文件访问的对象。它提供了基本的文件Read,Write,Delete等等操作。比较接近std::fstream的一些操作。针对支持的各个平台都会从IPlatformFile派生出相应的具体实现的类,比如WidowsPlatformFile。除了平台相关的的派生类以外,还有IPlatformFilePak,IPlatformFileModule等,这里只介绍IPlatformFilePak。和上面FPackageName相对应的是FPaths用来处理一些PlatformFile下的文件路径的操作。
Pak PlatformFile
用以管理Pak相关操作的PlatformFile类。提供了使用.pak文件的最为核心的两个操作Mount及Unmount。
引擎提供的相关操作
需要注意的问题
下面是我在学习的时候,总结的一些知识以及容易混淆的概念。
在PIE模式下使用Pak文件的意义不大
我最开始的时候按照自己的理解,认为既然是虚拟文件系统,那么只要我正确挂载路径,那么就可以正常的访问文件数据了。按照样的说法在PIE模式下,这也应该是可行的,那么这样子我在测试Pak相关功能时是不是可以不用那么麻烦的每次都需要Pakcaging Project了呢?虽然这个问题的前半段确实可行,但是后半段的问题仍然无法避免。
区分Mount和Load的区别
Mount翻译为挂载,而Load一般被翻译为加载。Mount只是告诉了文件系统有哪些文件可以从当前挂载的Pak文件中读到,即提供了虚拟的路径来访问Pak文件包含的文件,而Load一般就是指把文件的内容加载到内存中了,当然加载一个Package不是说的这么简单的流程。另外我看很多示例上可能是没有理解这边文件系统的原理,会在挂载之后直接写一些加载的代码,并没有在此时去使用加载之后的数据。挂载pak文件之后就可以通过常规的方式来访问其中的文件了,并不需要特意的去做一次加载操作,且和使用或不使用异步加载方式没有直接的关系
注意PlatformFile是一个链状结构
如果阅读IPlaformFile相关的代码就会发现IPlatformFile实际上是一个链状的结构。在其Intialize的时候,会要求传一个IPlatformFile的指针,这个将会作为其inner lower PlatformFile存在,在通过一个PlatformFile尝试访问文件目录时,可以通过这个链自顶向下访问每个节点上所挂载的文件。
注意一个PakPlatformFile上可以挂载多个Pak文件
网上大多数挂载pak的示例中,都是直接创建新的PakPlatformFile,然后把PlatformFileManager取到的当前的topmost PlatformFile作为其inner lower PlatformFile,然后将这个PakPlatformFile指定为topmost。实际上如果没有特殊要求的话,没有必要去增长这个链,会造成内存的浪费。一个PakPlatformFile可以挂载多个Pak文件,其内部有一个记录FPakFile的List。
注意使用PackageName和Path的区别
一般来说,Path就是接近我们在操作系统中读取文件时的那种路径。而PackageName提供的字串形式,实际上是一种简写的方式。
pak文件中可以存放非Asset Package文件类型
这里的意思是在使用UnrealPak.exe可以放入类似.txt的文件,挂载后可以通过PlatformFile来访问其中的文件内容。
Pak文件大小要求
前面的文章基本上描述了pak文件的使用的基本流程,但是UE4中处理这些流程的复杂程度远不止所提到的这些。比如pak文件在使用的时候还涉及到资源缓存的问题,对应代码中的USE_PAK_CACHE。这个功能,限定了pak文件的最小size。目前4.16.2版本中这个大小被设置为64KB(PAK_CACHE_GURANLULARITY),也就是如果你的pak文件小于64KB,将无法被预缓存。这一点我通过补足pak文件大小和修改源码中的PAK_CACHE_GURANLULARITY数值两个方式进行了验证,结果都符合预期。
UE4.17.1版本中已经把这个问题修正了。
Fixed async loading from pak files < 64k.
制作pak文件的一个小技巧
UE4提供了命令行工具来生成pak文件,我们只需要编写一些脚本,就可以方便按照自己的需求来生成相应的pak文件。这里说的小技巧可以让你把某个路径下的制作成pak文件时保留你想要的部分路径。具体的脚本代码如下:
# This function accepts a short package filepath with out extension. # And when generating pak file, it will add a dummy file to the reponse file list, # in this way, the relative path to expected package root path will be saved in pak file. # For example: # If the input parameters targetPackagePathRootDir="F:\\AAA\\BBB\\" assetPackage="F:\\AAA\\BBB\\CCC\\*.*", # then in the output pak file, the file's saved path will start with "\\CCC\\" def GenerateSplitedPaks(outputPakFileDir, targetPackagePathRootDir, assetPackage): pakCmdTemplate = '"{}" "{}" {} "{}"' urealPakToolPath = GetUnrealPakToolPath() outputPakFileDir = os.path.normpath(outputPakFileDir) targetPackagePathRootDir = os.path.normpath(targetPackagePathRootDir) filesToWrite = "" for associatedFile in assetPackage.associatedFiles: filesToWrite += ' "{}"'.format(associatedFile) #Use hash pakFilename = str(hash(assetPackage.name)) # _, pakFilename = os.path.split(assetPackage.name) outputPakFilePath = os.path.join(outputPakFileDir, pakFilename + ".pak") dummyPackagePath = os.path.join(targetPackagePathRootDir, "dummy.uasset") pakCmd = pakCmdTemplate.format(urealPakToolPath, outputPakFilePath, filesToWrite, dummyPackagePath) subprocess.call(pakCmd, shell=True) |
简单来说就是以你想要相对的路径下加一个不存在的文件,上面代码中是dummy.uasset。然后作为命令行输入的时候,工具提示找不到那个文件且不会加入那个文件。但是这个时候,你要保留的路径就留下来了。可能讲的不是很直观,你可以自己尝试几次不同的组合就知道了。
注意这里是简单的技巧示例,真正使用的时候请参照编辑器中的传详细的参数来进行脚本的编写。因为生成pak文件的时候,还需要需要指定合适的patchpaddingalign等数据。详细可以参看工程的ProjectUitls下的python脚本的代码。
挂载前后的路径问题
这个问题非常重要,我也将其放在最后来说。但其实挂载前后的路径确定出乎意料的简单,就是要保证你在制作那些资源时的目录结构和你挂载后的目录结构完全一致,这样就能保证其中资源依赖没有问题。给个简单的例子说明:
图中ToPak路径下的Package我都需要放入到Pak文件中,使用UnrealPak工具,以ToPak为Root生成Pak文件。然后使用此pak文件时,只需要把pak文件在挂载在FPaths::GameContentDir()下,就可以正常使用,包括依赖关系。
核心的代码示例
工程托管在GitHub上:TestPak, 我只把使用Pak文件最核心的一些代码提炼出来了,并给予一些示例。
目前尚未解决的问题
2019 ArcEcho
Powered by Hexo v3.8.0
|
Tema – NexT.Muse v7.0.1
文章浏览阅读1k次。ListView分析学以致用篇(1)在我们查看别人的博客的时候,一个人是一个风格的.先说下我的风格,我喜欢思想类比,然后介绍知识,不太喜欢填鸭式的灌输.如果只是想单纯的从我的博客中直接看到代码,我个人建议直接到网上搜索其他的案例,我喜欢一步一步的分析,然后分析完一个过程,会有一个对应的例子这个样子(1) 什么是ListViewListView 首先就是一个View,View顾名思义,就是用来展示数
文章浏览阅读472次。DevExpress 自定义GridControl代码结构代码如下:代码结构代码如下:using System;using System.Collections.Generic;using System.Linq;using System.Text;using DevExpress.XtraGrid.Views.Grid;using DevExpress.XtraGrid;us..._devexpress.xtragrid.views.grid.viewinfo.gridviewinfo.updatecellappearance(gr
文章浏览阅读1.7w次,点赞6次,收藏23次。转自 http://blog.chinaunix.net/uid-20727076-id-3062401.html 在我的fedora11系统(linux2.6.31)下,这三个设备的具体情况如下:[root@localhost dev]# ls -l ttycrw-rw-rw- 1 root tty 5, 0 2012-01-30 17:26 tty[root@loc_/dev/tty
文章浏览阅读65次。个人背景如标题所示,我的个人背景非常简单,Java开发经验1年半,学历普通,2本本科毕业,毕业后出来就一直在Crud,在公司每天重复的工作对我的技术提升并没有什么帮助,但小镇出来的我也深知自我努力的重要性,想要改变“命运”,没有背景没有资本的人,只能通过勤奋获得。幸运女神往往会眷顾努力的人,所以当好运降临到我头上,我并不诧异,目前拿到了美团30K的offer,下文也不说废话,主要分享我这次“美团面试经历”和“个人学习方法”,希望能帮助到你们。蚂蚁金服一面:分布式架构 50分钟个人介绍加项目介绍2
文章浏览阅读1.7w次,点赞19次,收藏170次。Qt_常用控件_tablewidget_qt tablewidget
文章浏览阅读1k次。Spring整合mybats引发异常对于自己无知的记录(浪费了一天)事发现场org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name ‘studentInfoServiceImpl’: Unsatisfied dependency expressed through field ‘studentInfoMapper’; nested exception is org.sp_unsatisfied dependency expressed through field 'studentmapper'; nested excep
文章浏览阅读1.8w次,点赞4次,收藏5次。fill-rule属性规定了svg图形的填充规则 fill-rule 有效值 nonzero / evenodd / inherit 默认值 nonzero 应用于 shape形状类元素和文字内容类元素 可继承 是 比例 无 媒体 可见 动画可用 是fill-rule属性用于指定使用哪一种短发去判断画布上的某区域是否属于该图形的“内部_svg fill-rule
文章浏览阅读2.9k次。使用div和js脚本弹出一个对话框思路:div已经存在于网页当中,只是被隐藏了,当点击按钮时将其可见性设置为可见即可实现实现:在网页中设置好需要弹出的窗口,为其他控件设置一个事件,当触发该事件时将窗口设置为可见控件_js 弹出div对话框
文章浏览阅读245次。Lucene全文检索技术课程计划Lucene介绍 全文检索流程介绍 索引流程 搜索流程 Lucene入门程序 索引实现 搜索实现 分词器 分词介绍 IK分词器 搜索技术理论基础 为什么要学习Lucene 原来的方式实现搜索功能,我们的搜索流程如下图:正在上传…重新上传取消正在上传…重新上传取消上图就是原始搜索引擎技术,如果用户比较少而且数据库的数据量比较小,那么这种方式实现搜索功能在企业中是比较常见..._lucene-solr
文章浏览阅读1.5w次。http://blog.csdn.net/annkey123/article/details/8778996_ios上架苹果商店提示支付宝支付,拒绝上架
文章浏览阅读201次。Linux有150个常用指令,透过12道题去学习以及练习指令1、创建一个目录/dzqc提示: windows下的路径样式为c: \dzqc\ test,而linux下的路径样式为 /dzqc/test因此/dzqc就可以看做是c:\dzqc,不同的是 windows系统下还有D,E等盘, linux下就只有/为所有目录的顶点。英文 make directorys缩写后就是 mkdir,这..._已知有目录结构如图:已知当前工作目录为d1,要将文件f1移动到目录d2下,正确的命令
文章浏览阅读51次。每周总结1.学习总结有的题目可以转变思维来简化问题,比如vjudge上的那个骑车子的那个问题,要找最快到达终点的时间,可以直接找出最快的车辆算出最快的时间,而不必去模拟这道题的过程以简化问题,已经遇到了很多到和这种思想类似的题目,还有雷达那道题目(现在还没弄懂QAQ)也是有这种类似的思想,把范围由二维转化成一维。这种转化的思想可以把问题变得更简单,但就是有点难想。。。2.学习感受这周主要内容还是贪心,有的题目还是有一定难度的,想上半天想不出思路,感觉还是自己刷的题少,在周四的比赛中就明显的显露出来,