UE4 Pak 相关知识总结_kuangben2000的博客-程序员宝宝_uexp是什么文件

技术标签: UE4  

UE4 Pak 相关知识总结

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/

每天进补一点点!

UE4 Pak 相关知识总结

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

书中列举的主要用途如下:

  • 操作文件名及路径
  • 对单独的文件进行读写等常规的文件操作
  • 扫描文件目录下内容
  • 处理异步的文件I/O请求

除了主要用途,文件系统还要可能需要满足资源Packaging,Patching等功能。
我所了解比较好的文件系统例子是暴雪的CASC,我们玩的WOW的更新及修复什么的,都是依靠它实现的。

UE4中的对应的一些概念

File

File在UE4中的概念,实际上和我们使用操作系统时的是基本一致的,用来记录数据信息。

Asset Package

实际上UE4中没有Asset Package这个名词,只有Package,为了区别于Packaging Project的package,这里先声明这样的记法。Asset Package,就是指的在UE4中能够在直接使用的游戏资源,比如material,map,blueprint等,每一个独立的资源的对应一个Package概念。

  • 一个Asset Package可能包含多个File,比如cooked之后的usset实际上可能会分离出.uexp .ubulk等文件。
  • 多个Asset Package可以称作一个Pack,比如Add Feature Pack就是提供了一系列Asset Packages。
  • Asset Package和UOject关系很紧密,直接Load的Asset Package就是一个UObject对象。
  • FPackageName就是我们通常在Load Asset时使用的路径形式。更为具体点就是FStringAssetReference。但是注意FStringAssetReference不是一个字串,不要被名字迷惑。

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了呢?虽然这个问题的前半段确实可行,但是后半段的问题仍然无法避免。

  • 虽然能够挂载pak文件,并能够加载其中的Asset Package,但是只能是未被Cooked的才可以正常使用,同理Packaging之后的Project也无法使用没有Cooked的Asset Package。

区分Mount和Load的区别

Mount翻译为挂载,而Load一般被翻译为加载。Mount只是告诉了文件系统有哪些文件可以从当前挂载的Pak文件中读到,即提供了虚拟的路径来访问Pak文件包含的文件,而Load一般就是指把文件的内容加载到内存中了,当然加载一个Package不是说的这么简单的流程。另外我看很多示例上可能是没有理解这边文件系统的原理,会在挂载之后直接写一些加载的代码,并没有在此时去使用加载之后的数据。挂载pak文件之后就可以通过常规的方式来访问其中的文件了,并不需要特意的去做一次加载操作,且和使用或不使用异步加载方式没有直接的关系

注意PlatformFile是一个链状结构

如果阅读IPlaformFile相关的代码就会发现IPlatformFile实际上是一个链状的结构。在其Intialize的时候,会要求传一个IPlatformFile的指针,这个将会作为其inner lower PlatformFile存在,在通过一个PlatformFile尝试访问文件目录时,可以通过这个链自顶向下访问每个节点上所挂载的文件。

  • 可以这样理解,每个节点都有包含一部分文件信息,整个链上节点的信息综合起来,就是你能够访问的所有文件信息。值得注意的是,这种方式是允许节点间信息冗余的。如果冗余会访问第一个找到的数据。
  • 既然是一个链状结构,UE4提供了FPlatformFileManager来方便set/get topmost PlatformFile。

注意一个PakPlatformFile上可以挂载多个Pak文件

网上大多数挂载pak的示例中,都是直接创建新的PakPlatformFile,然后把PlatformFileManager取到的当前的topmost PlatformFile作为其inner lower PlatformFile,然后将这个PakPlatformFile指定为topmost。实际上如果没有特殊要求的话,没有必要去增长这个链,会造成内存的浪费。一个PakPlatformFile可以挂载多个Pak文件,其内部有一个记录FPakFile的List。

注意使用PackageName和Path的区别

一般来说,Path就是接近我们在操作系统中读取文件时的那种路径。而PackageName提供的字串形式,实际上是一种简写的方式。

  • FPackageName提供了RegsterMountPoint和UnRegisterMountPoint函数,这个函数的作用实际上就是提供了一种重定向的方式,即你在使用”/Game/xxxx.xxxx”的PackageName时,资源管理器会翻译成文件系统所能识别的Path。注意提过一个Asset Package可能对应多个文件,这个过程可能不是简单的字符串转换。另外还需要注意的是,PIE模式下你使用这个函数的时候,会抛出事件让Content Browser去扫描改动,如果你的注册的文件是在GameDir下的话,会反映到编辑器的Content Browser中。一般来说,这个函数没必要特意去调用,如果你mount的路径在GameContentDir下的话是可以直接使用”/Game/“开头的那种方式来加载Asset Package的。

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()下,就可以正常使用,包括依赖关系。

  • 同一个文件夹目录下的的文件可以分散在不同的Pak文件中,对同一个路径mount不同的Pak文件就可以还原之前的目录结构。
  • 同时需要注意的是实际挂载时并不一定需要去指定mount point,但这个的前提是你生成pak文件的时候在response file中已经指定好了各文件的redirection path。这一点是通过阅读程序如何使用自身的paks文件下的pak文件得知的,我做了多次验证后确实如此。且不按照此种方式使用时,静态光源的构建数据可能会出现错误的带状显示效果。

核心的代码示例

工程托管在GitHub上:TestPak, 我只把使用Pak文件最核心的一些代码提炼出来了,并给予一些示例。

目前尚未解决的问题

  • 当前我测试通过的的版本是4.15.1和4.16.2,在正确生成pak文件后(正确是指使用unrealPak工具时,相关的命令行参数需要恰当),基本上能够正常运行。如果使用最简单的方式的话可能静态光源的builddata使用错误,出现带状的错误显示效果。然后就是在4.15.3版本下cook之后,只有uasset文件,而缺少uexp等文件,暂时不知道为什么,此种情况下使用时也会出现前面的错误。这个需要等我后面弄明白了再补充。

# UE4

使用C++11实现简单的delegate v0.1

UE4工程调试简易小结

  • Daftar Isi
  • Ikhtisar
  1. 1. 需要知道的核心概念
    1. 1.1. 印证了《Gmae Engine Architechture》中的一些设计
    2. 1.2. UE4中的对应的一些概念
    3. 1.3. 引擎提供的相关操作
    4. 1.4. 需要注意的问题
      1. 1.4.1. 在PIE模式下使用Pak文件的意义不大
      2. 1.4.2. 区分Mount和Load的区别
      3. 1.4.3. 注意PlatformFile是一个链状结构
      4. 1.4.4. 注意一个PakPlatformFile上可以挂载多个Pak文件
      5. 1.4.5. 注意使用PackageName和Path的区别
      6. 1.4.6. pak文件中可以存放非Asset Package文件类型
      7. 1.4.7. Pak文件大小要求
      8. 1.4.8. 制作pak文件的一个小技巧
      9. 1.4.9. 挂载前后的路径问题
    5. 1.5. 核心的代码示例
    6. 1.6. 目前尚未解决的问题

2019 ArcEcho

Powered by Hexo v3.8.0

|

Tema – NexT.Muse v7.0.1

 

 

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/kuangben2000/article/details/107500262

智能推荐

C++ close()关闭文件方法详解_luoganttcc的博客-程序员宝宝_c++ 关闭文件

《C++ open打开文件》一节中,详细介绍了文件流对象如何调用 open() 成员方法打开指定文件。相对应地,文件流对象还可以主动关闭先前打开的文件,即调用 close() 成员方法。我们知道,调用 open() 方法打开文件,是文件流对象和文件之间建立关联的过程。那么,调用 close() 方法关闭已打开的文件,就可以理解为是切断文件流对象和文件之间的关联。注意,close() 方法的功能仅是切断文件流与文件之间的关联,该文件流并会被销毁,其后续还可用于关联其它的文件。close() 方法的用法很简

Java.lang软件包中的类_有恒者Maggie的博客-程序员宝宝

java.lang软件包是java语言的核心部分,它提供了java中的基础类。java.lang.Object,这是java.lang的根类,也是所有java类的超类。在构造java类的实例时,都先调用Object中的默认构造方法。类java.lang.Class也是一个非常重要的类。Class 类的实例用来表示正在运行的 Java 应用程序中的类和接口。Class对象

Spring Boot(一)使用Spring Initializr创建项目入门+整合Mybatis_idomyway的博客-程序员宝宝

前言&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;spring boot 极大的简化了项目配置,比传统的SSM框架的开发效率更高。开发准备jdk1.8maven 3.5.0webStorm开发步骤:1. 新建Spring Boot项目&amp;amp;amp;amp;nbsp;&amp;amp;amp;amp;nbsp;&amp;am

VS2017编译opensmile具体过程和遇到的问题_wxysunshy的博客-程序员宝宝

下载最新的稳定版本openSMILEhttp://audeering.com/technology/opensmile/#download 在Windows上编译openSMILE,首选的方式(也是官方唯一支持的方式)是用Visual Studio 2010进行编译。这里我们用VS2017进行编译。 在文件ide/vs10/openSmile.sln提供的是一个Microsoft Vi...

随便推点

nginx yii2 配置_小人物大梦想的博客-程序员宝宝

# For more information on configuration, see:# * Official English Documentation: http://nginx.org/en/docs/# * Official Russian Documentation: http://nginx.org/ru/docs/user nginx;worker_proce...

01(概述)_青青草原我最狂~的博客-程序员宝宝

各位阅读本博客的朋友们,你们好。很高兴能在CSDN这个平台上能够与大家见面,首先感谢CSDN为我们计算机爱好者提供了一个能够学习,讨论,资源分享的平台。 我的博客主要以自己的学习笔记的形式来分享给大家,我是第一次撰写博客,经验不足,其中肯定会有些许的错误,我恳切的希望各位读者,大牛能够给予指正,谢谢大家。 好了,废话不多说,让我们开始吧。...

微信公众号网页开发小结_jklkjz的博客-程序员宝宝

1、只有在公众号的开发者微信号绑定了,才可以用web开发者工具进行调试2、对于同一个微信用户,不同公众号的openid是不一样的,所以要调用其他接口,前提就是要用户授权,拿到他的openid3、微信接口分两类,一类用普通的access_token,另一类需要经过用户授权后拿到的access_token(多为用户信息的接口)4、微信普通接口请求步骤:1)先用appid、Secret请...

GIS 几个先辈_weixin_34318272的博客-程序员宝宝

Michael F. GoodchildMichael Frank Goodchild教授是美国科学院地理信息科学院士,现任加州大学圣巴巴拉分校地理系教授。1965年获得剑桥大学(Cambridge University)物理学学士学位,1969年获得麦克马斯特大学(McMaster University)地理学博士学位。在加拿大西安大略大学(University of Weste...

进程管理和P V操作_zhihuiyt的博客-程序员宝宝_进程执行p操作

【版权声明:】    本文为博主原创,未经博主允许不得转载。 计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件。一、操作系统的相关定义1、操作系统的定义:操作系统是控制和管理计算机硬件和软件资源、合理的组织计算机流程以方便用户使用的程序的集合。2、操作系统的特点:(1) 并发性。 并发性和并行性是有区别的两个不同概念。...

js骚操作骂人_小鑫a的博客-程序员宝宝_js骂人

前言很多人觉得javascript很简单 但下面的这行javascript代码会让你怀疑人生(!(~+[])+{})[--[~+&quot;&quot;][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]输出的结果如下:以后遇到一些不讲道理,让你不开森的人就把这段代码发给他。那么问题来了,这段代码为什么会输出 &quot;sb&quot;呢?首先要运用到的第一个知识就是js运算符的优...

推荐文章

热门文章

相关标签