[{"data":1,"prerenderedAt":530},["ShallowReactive",2],{"\u002F2017-05-01-ue4-patch-release-dlc":3},{"id":4,"title":5,"body":6,"date":503,"description":12,"extension":504,"meta":505,"navigation":508,"path":520,"seo":521,"stem":522,"tags":523,"__hash__":529},"blogs\u002F_legacy\u002F2017\u002F2017-05-01-ue4-patch-release-dlc.md","UE4补丁与DLC",{"type":7,"value":8,"toc":486},"minimark",[9,13,16,19,24,35,38,41,47,50,55,58,63,66,74,79,82,88,97,100,105,108,113,116,121,124,127,130,137,142,145,148,151,156,159,164,167,171,174,177,188,191,194,199,203,206,211,214,219,222,227,230,233,253,256,260,263,266,269,277,280,283,286,291,294,300,303,306,309,312,316,319,322,325,328,339,342,345,348,352,355,361,364,369,372,377,380,383,386,389,394,397,401,404,410,413,416,421,424,427,430,436,439,444,447,450,455,458,461,466,469,474,477,480,483],[10,11,12],"p",{},"UE4的打包操作本身还是比较简单的，但是考虑到发布之后的升级与补丁，却还是有一些麻烦。",[10,14,15],{},"当前UE4版本为4.16 P1。",[10,17,18],{},"在动手做东西之前，先了解一下UE4本身对于打包系统的架构是很重要的，否则如果到了Release的阶段发现代码设计上很多地方与系统有冲突的话就会很麻烦。就像是等到开始做联网版本的游戏时才发现很多机制、功能的设计都与UE4的Replication架构不符的话就会需要大幅度的代码变更。",[20,21,23],"h2",{"id":22},"unreal-frontend","Unreal Frontend",[10,25,26,27,34],{},"虚幻的打包操作在[",[28,29,33],"a",{"href":30,"rel":31},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FEngine\u002FDeployment\u002Findex.html",[32],"nofollow","官方文档","]中有进行描述，一切打包相关的工作，都以Unreal Frontend为核心进行。当然，Unreal Frontend还提供了部署、自动化测试等功能。",[10,36,37],{},"总体而言，Unreal Frontend的功能还不成熟，很多选项的设定让人费解，也没有提供足够的文档说明，所以可能会遇到一些奇怪的BUG。最麻烦的是，到目前为止，DLC系统依然处于WIP状态，使用起来有很多的不便。",[10,39,40],{},"目前主要会使用到的是Project Launcher模块，在下方的Custom Lanch Profiles区域的右边有加号按钮，可以在那里添加自定义的打包配置。配置大致分为以下区域：",[10,42,43],{},[44,45,46],"strong",{},"Project",[10,48,49],{},"选择打包操作的目标项目，由于Unreal Frontend的设置是全局的，所以在一个项目中配置了之后在其他项目中也可以使用。",[10,51,52],{},[44,53,54],{},"Build",[10,56,57],{},"选择是否构建，以及构建的模式，并提供了是否构建UAT（Unreal Automation Tool）的选项。UAT主要提供一些自动化测试方面的功能，根据社区一些用户的反馈来看，需要源码版本引擎才能正常的使用。",[10,59,60],{},[44,61,62],{},"Cook",[10,64,65],{},"烘焙相关选项，一般都是用By the book选项然后勾选相关目标平台。",[10,67,68,69,73],{},"进行Release\u002FPatch\u002FDLC打包的操作都在By the book选项下。其他的一些详细的可选项功能可以参考[",[28,70,33],{"href":71,"rel":72},"https:\u002F\u002Fdocs.unrealengine.com\u002Flatest\u002FCHN\u002FEngine\u002FDeployment\u002FCooking\u002Findex.html",[32],"]。",[10,75,76],{},[44,77,78],{},"Package",[10,80,81],{},"是否打包以及如何打包，这里需要注意的是当前版本下对DLC进行打包是会出现BUG的，报错如下：",[83,84,85],"blockquote",{},[10,86,87],{},"Program.Main: ERROR: AutomationTool terminated with exception: System.Exception: Couldn't update resource",[10,89,90,91,96],{},"搜索之后发现似乎是一个[",[28,92,95],{"href":93,"rel":94},"https:\u002F\u002Fissues.unrealengine.com\u002Fissue\u002FUE-42880",[32],"BUG","]，因此目前对DLC可以不需要打包，而是自己将生成的文件进行拷贝就可以了。",[10,98,99],{},"打包的生成目录在Saved\\StagedBuilds\\中。",[10,101,102],{},[44,103,104],{},"Archive",[10,106,107],{},"归档，引擎会在打包后将打包好的内容拷贝到指定的目录去。不使用的话不要勾选就可以了。",[10,109,110],{},[44,111,112],{},"Deploy",[10,114,115],{},"部署，提供了几种部署渠道，可以部署到目前可用的设备上。不使用的话可以直接选中Not Deploy。",[10,117,118],{},[44,119,120],{},"Launch",[10,122,123],{},"测试运行的形式，可以对服务端模式、语言环境、初始地图等进行设置。",[20,125,126],{"id":126},"打包模式",[10,128,129],{},"打包模式目前有Release、Patch、DLC三种，其中DLC处于WIP状态，并没有足够的文档支持，而且今后可能会有不少变动。",[10,131,132],{},[133,134],"img",{"alt":135,"src":136},"image","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb.png",[138,139,141],"h3",{"id":140},"release-version","Release Version",[10,143,144],{},"UE4提供的Release的概念是通常的发行版本控制，勾选Create a release version of the game for distribution就可以开启了。而Patch与DLC都是以某个Release版本为基础进行打包的。",[10,146,147],{},"因此使用Release打包的时候就必须填Name of the new release to create，而Path与DLC则必须填写Release version this is based on。",[10,149,150],{},"DLC是不可以选中Create a release version这个选项的，会报错：",[83,152,153],{},[10,154,155],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Can't create a release version at the same time as creating dlc.",[10,157,158],{},"而选中了这个选项还填写based on version的话也会报错：",[83,160,161],{},[10,162,163],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Only staged builds can be paked, use -stage or -skipstage.",[10,165,166],{},"这个错误也会出现在使用Iterative cooking选项时，如果使用这个选项同时又勾选使用Pak的话，根据当前烘焙缓存的状况不同，也会报这个错。",[138,168,170],{"id":169},"generate-patch","Generate patch",[10,172,173],{},"生成补丁，目前一个Release下只能有一个补丁，对于生成的pak文件，补丁中带后缀_P，会被优先加载并覆盖。同样的pak文件，多加一个_P的话优先级就会更高。",[10,175,176],{},"在Mount函数中，可以看到",[178,179,184],"pre",{"className":180,"code":182,"language":183},[181],"language-text","if ( PakFilename.EndsWith(TEXT(\"_P.pak\")) )\n{\n  PakOrder += 100;\n}\n","text",[185,186,182],"code",{"__ignoreMap":187},"",[10,189,190],{},"凡是以_P结尾的pak文件，会获得额外的100优先级。在进行Patch打包时，引擎也会自动的加上这个后缀。",[10,192,193],{},"这里有一个问题，如果勾选了Store all content in a single file的情况下，即便是在不同的Release版本之间，_P的patch也会被优先加载。还没有测试过如果去除了Save package without versions选项是否会有这样的现象。",[10,195,196],{},[133,197],{"alt":135,"src":198},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-1.png",[138,200,202],{"id":201},"iterative-cooking","Iterative cooking",[10,204,205],{},"增量烘焙必须去掉勾选Save package without versions，否则launch按钮会变成灰色，提示：",[83,207,208],{},[10,209,210],{},"unversioned build cannot be incremental",[10,212,213],{},"这里面的Iterative cooking目前只能在同一个Release版本中进行增量烘焙，如果Releasse的版本迁移了的话，是不能在版本之间进行增量烘焙的，强行勾选会被拒绝操作：",[83,215,216],{},[10,217,218],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.AutomationException: Can't use iterative cooking \u002F deploy on dlc or patching or creating a release",[10,220,221],{},"官方的说明是这样的：",[83,223,224],{},[10,225,226],{},"The asset registry and pak file will be needed for any future patches or DLC to check against.",[10,228,229],{},"也就是说保存的content注册关系是为了DLC和patch而存在的，并没有说可以作为Release之间的版本迁移的依据。",[10,231,232],{},"使用Iterative cooking时还有一点需要注意，那就是引擎当前无法区分Ship和DevelopMent之间的烘焙结果，如果切换Build模式时没有去掉这个选项的话，就会导致烘焙资源的混杂，出现类似如下错误：",[83,234,235,250],{},[10,236,237,238,242,243,246,247],{},"Assertion failed: GDefaultMaterials",[239,240,241],"span",{},"Domain"," != NULL ",[239,244,245],{},"File:D:\\Build++UE4+Release-4.16+Compile\\Sync\\Engine\\Source\\Runtime\\Engine\\Private\\Materials\\Material.cpp"," ",[239,248,249],{},"Line: 429",[10,251,252],{},"Cannot load default material 'engine-ini:\u002FScript\u002FEngine.Engine.DefaultMaterialName'",[10,254,255],{},"另外，使用增量会导致不在当前选择的地图内容也会被Build进来，但是无论如何，项目设定中的默认地图都是会别build进来的。",[138,257,259],{"id":258},"build-dlc","Build DLC",[10,261,262],{},"UE4中的DLC是以Plugin的形式进行实现的，DLC Name那里填写的就是插件的名称，是不能随便乱填的。",[10,264,265],{},"插件的话在Plugins窗口直接新建就可以了，如果是蓝图项目的话，只会有一个Content Plugin，选择他就可以了。另外，似乎在打包时如果有地图存在的话，没有被地图引用的资源就不会被打包，需要注意。",[10,267,268],{},"打包DLC中如果出现",[83,270,271,274],{},[10,272,273],{},"Cook: LogInit:Display: LogCook:Error: Engine or Game content ..\u002F..\u002F..\u002FEngine\u002FContent\u002FTutorial\u002FFoliage\u002FFoliage_Intro_Tutorial.uasset is being referenced by DLC!",[10,275,276],{},"Cook: LogInit:Display: LogCook:Error: Engine or Game content ..\u002F..\u002F..\u002FEngine\u002FContent\u002FTutorial\u002FSubEditors\u002FDestructibleMeshEditorTutorial.uasset is being referenced by DLC!",[10,278,279],{},"之类的BUG，可以尝试勾选Include engine content。",[10,281,282],{},"关于DLC，一些旧的资料中会提到Plugin形式无法被引擎自动加载，目前测试过已经没有这个现象了。即便是在Release之后添加的Plugin，在做DLC的打包之后，直接扔到项目目录中也会被自动加载。不知是否是因为使用DevelopMent打包的关系。",[10,284,285],{},"由于当前Package DLC不知为何会报错，类似这样",[83,287,288],{},[10,289,290],{},"UATHelper: Packaging (Windows (64-bit)): Program.Main: ERROR: AutomationTool terminated with exception: System.Exception: Couldn't update resource",[10,292,293],{},"其实Pak已经打包成功了，直接Achive即可。",[10,295,296],{},[133,297],{"alt":298,"src":299},"msohtmlclipclip_image0014","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0014_thumb.png",[10,301,302],{},"将生成的内容直接复制到打包程序里面，就会被自动加载了，即便Release打包的时候并没有这个DLC的Plugin也是可以的。",[20,304,305],{"id":305},"补丁形式",[10,307,308],{},"官方在Patch的文档中有提到补丁的覆盖优先，由于Patch是从Release的版本开始进行差分的，如果两个Patch都是针对整个游戏的话，那么前一个Patch就没有意义了，可以删除。",[10,310,311],{},"这样一来，为了防止每次更新的内容过大，我们就必须对项目的组织进行设计，目前我们可以通过Maps或者Chunks来做内容差分管理。",[138,313,315],{"id":314},"maps","Maps",[10,317,318],{},"在进行打包时，被打包地图及其所引用的资源有改变的都会被打包，只是是否会被游戏采用取决于Pak的加载优先级。",[10,320,321],{},"而不被选中的地图中，即便相关资源有变动，也不会被打包到Patch中去，但是DefaultMap始终都会被打包。",[10,323,324],{},"各个地图打包之后除了DefaultMap之外都是独立的，无论命名成什么都会被自动加载，而_P的优先级会被应用到整个Pak文件上。",[10,326,327],{},"而目前，只要在扫描目录里面的pak文件，都会被自动加载。从FPakPlatformFile::Initialize的调用中看到，除了在SHIPPING模式下提供的命令行外，有如下的目录会被添加到扫描中：",[83,329,330,333,336],{},[10,331,332],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::GameContentDir()));",[10,334,335],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::GameSavedDir()));",[10,337,338],{},"OutPakFolders.Add(FString::Printf(TEXT(\"%sPaks\u002F\"), *FPaths::EngineContentDir()));",[10,340,341],{},"也就是说，可以在一开始打包时，只选中Default地图，之后其他的地图可以每个或每组地图单独选中，然后打包成Patch改成地图名称的形式添加到游戏中去。",[10,343,344],{},"这样一来，就可以很方便的添加后续的地图内容到发布版本中去了，只是多少还需要维护一个文件列表。",[10,346,347],{},"总体而言，使用一个空地图作为程序本体，将通用的逻辑、材质放到其中，其他地图大致保持各自独立。这样每次就可以对对应的模块进行更新替换就行了。",[138,349,351],{"id":350},"chunks","Chunks",[10,353,354],{},"Chunks这个功能可以在编辑器中指定内容将会被打包到哪一个Patch中去，但是这个功能必须在编辑器设定中Genera>Experiment中打开：",[10,356,357],{},[133,358],{"alt":359,"src":360},"msohtmlclipclip_image001","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image001_thumb.png",[10,362,363],{},"打开选项之后，就可以在内容管理器的右键菜单中看到：",[10,365,366],{},[133,367],{"alt":135,"src":368},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-6.png",[10,370,371],{},"Chunk相关的选项了。对不同的资源设定了Chunk之后就可以在打包时选中这个功能，打包之后就会有不同的分包了。",[10,373,374],{},[133,375],{"alt":135,"src":376},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-7.png",[10,378,379],{},"Chunk功能必须在Pak开启时使用，因为不Pak打包的话，原本的项目文件就已经足够Chunk了。",[10,381,382],{},"另外，如果要使用Http chunk install功能的话，不要将Default Map放到Chunk中去，否则由于本地不会保留那些Chunk，程序将会由于没有Default Map而无法开启。",[10,384,385],{},"如果对在Patch的时候也使用chunk的话，将会对不同的chunk包生成Patch，但是即使该chunk包的内容没有改变，也依然会生成一个1K的Dammy。",[10,387,388],{},"不过这其中最大的限制是，对chunk进行patch时只能针对Release时在AssetRegistry注册过的地图，如果添加没有注册过的地图则无法打包成功。",[83,390,391],{},[10,392,393],{},"Program.Main: ERROR: AutomationTool terminated with exception: AutomationTool.CommandUtils+CommandFailedException: Command failed (Result:3): D:\\Code\\UE_4.16\\Engine\\Binaries\\Win64\\UnrealPak.exe F:\\Ue_Patch\\1.0_nomap\\WindowsNoEditor\\P001\\Content\\Paks\\P001-WindowsNoEditor_P.pak -create=\"C:\\Users\\Admin\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakList_P001-WindowsNoEditor_P.txt\" -encryptionini -enginedir=\"D:\\Code\\UE_4.16\\Engine\" -projectdir=\"E:\\Ues\\P001\" -platform=Windows -abslog=\"C:\\Users\\Admin\\AppData\\Roaming\\Unreal Engine\\AutomationTool\\Logs\\D+Code+UE_4.16\\PakLog_P001-WindowsNoEditor_P.log\" -installed -order=E:\\Ues\\P001\\Build\\WindowsNoEditor\\FileOpenOrder\\CookerOpenOrder.log -UTF8Output -generatepatch=E:\\Ues\\P001\\Releases\\5.0\\WindowsNoEditor\\P001-WindowsNoEditor.pak -tempfiles=D:\\Code\\UE_4.16\\TempFiles -multiprocess -patchpaddingalign=2048. See logfile for details: 'UnrealPak-2017.05.07-11.00.34.txt'",[10,395,396],{},"会出现类似这样的错误。",[138,398,400],{"id":399},"http-chunks-install","Http Chunks Install",[10,402,403],{},"在使用Chunk的基础上，还可以进一步的使用Http Chunks Install功能，这个功能通常被用于移动端的碎片化安装功能",[10,405,406],{},[133,407],{"alt":408,"src":409},"msohtmlclipclip_image0016","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0016_thumb.png",[10,411,412],{},"不过在桌面端也可以进行使用。其实实现中并没有支持断点续传，不过事实上，分块下载本身就在一定程度上充当了断点续传的功能。",[10,414,415],{},"使用起来也比较简单，直接勾选并填写输出路径、版本名称之类的就可以了。",[10,417,418],{},[133,419],{"alt":135,"src":420},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-13.png",[10,422,423],{},"不过要注意确保其输出目录是确实存在的，和其他的目录设定不同，这里是会进行写入检测的。",[10,425,426],{},"另外，在Chunk Version Name里面输入之后记得敲回车才能确认输入。这里的输入框功能有点奇怪，直接填完之后点别的地方不会确认输入，会直接清空。",[10,428,429],{},"如果是移动端打包的话，无需添加配置文件，直接点击添加按钮盘的下拉三角即可：",[10,431,432],{},[133,433],{"alt":434,"src":435},"msohtmlclipclip_image0011","\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fmsohtmlclipclip_image0011_thumb.png",[10,437,438],{},"打包成功的话会在输出目录输出类似这样的内容：",[10,440,441],{},[133,442],{"alt":135,"src":443},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-8.png",[10,445,446],{},"Http chunk install的功能也是以一个chunk为目标进行的，只是每个chunk会被分成更小的块，方便传输。也就是说，要使用这个功能，还是需要有一个自行设计的文件列表来进行版本管理的。",[10,448,449],{},"要进行碎片安装，直接对某个文件执行Request Content：",[10,451,452],{},[133,453],{"alt":135,"src":454},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-9.png",[10,456,457],{},"这里面填写的URL对应的就是上面生成的那些内容，需要自行部署到服务器上。",[10,459,460],{},"如果Success的话，会返回一个Mobile Pending Content的引用，继续",[10,462,463],{},[133,464],{"alt":135,"src":465},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-10.png",[10,467,468],{},"如果成功的话就可以对这个引用进行Mount了",[10,470,471],{},[133,472],{"alt":135,"src":473},"\u002Fwp-content\u002Fuploads\u002F2017\u002F05\u002Fimage_thumb-11.png",[10,475,476],{},"这样就可以使用这个包的内容了，这套函数本身会检测本地有没有pak文件，有的话就不会进行下载了。",[10,478,479],{},"上面填写的Install Directory在windows下是以项目内容目录下的PersistentDownloadDir为基础的，所以填写..\u002FContent\u002FPaks\u002F的话就可以到达自动加载目录，下次游戏运行时包中的内容就可以直接使用了。不过要留意的是，如果被自动加载了的话，那个文件就无法被直接替换掉了。",[20,481,482],{"id":482},"总结",[10,484,485],{},"由于UE4并未提供Release版本之间的增量功能，要实现地图下载之类的功能的话，可以使用DLC或者分Map打包。如果现在的打包实在无法满足需求的话，也可以选择自己用UnreakPack进行打包并自行进行Mount管理来进行补正，有这个需求的话可能会遇到FPackageName::RegisterMountPoint之类函数的使用。不过相信打包功能在之后的版本更新中会有所增强，如果不是有紧急的打包需求的话，不建议跳这个坑。",{"title":187,"searchDepth":487,"depth":488,"links":489},2,3,[490,491,497,502],{"id":22,"depth":487,"text":23},{"id":126,"depth":487,"text":126,"children":492},[493,494,495,496],{"id":140,"depth":488,"text":141},{"id":169,"depth":488,"text":170},{"id":201,"depth":488,"text":202},{"id":258,"depth":488,"text":259},{"id":305,"depth":487,"text":305,"children":498},[499,500,501],{"id":314,"depth":488,"text":315},{"id":350,"depth":488,"text":351},{"id":399,"depth":488,"text":400},{"id":482,"depth":487,"text":482},"2017-05-01","md",{"layout":506,"status":507,"published":508,"author":509,"author_login":511,"author_email":512,"wordpress_id":513,"wordpress_url":514,"date_gmt":515,"excerpt":516},"post","publish",true,{"display_name":510,"login":511,"email":512,"url":187},"风铃","flinkor","flinkor@foxmail.com",1646,"\u002F\u002F?p=1646","2017-05-01 10:32:13 +0000",{"type":7,"value":517},[518],[10,519,12],{},"\u002F2017-05-01-ue4-patch-release-dlc",{"title":5,"description":12},"_legacy\u002F2017\u002F2017-05-01-ue4-patch-release-dlc",[524,525,526,527,528],"UE4","Release","Patch","DLC","UnrealPak","cJwigzRyewKqORjMzLTqhnQa8zSJWqk_pxLSbY0jaAA",1788763180130]