UE-自带的HotUpdate【转】
原文链接:https://baijiahao.baidu.com/s?id=1745200406976270792&wfr=spider&for=pc
这是百度可以直接搜索到的
UE4官网针对热更新有较为详细的步骤,但是其中漏掉的几个问题导致实现不了效果。
总的来说可以分为四大步。
第一步:自己的项目设置好插件ChunkDownloader
1.新建第三人称c++项目工程,设置分块打包
2.勾选插件ChunkDownloader
3.修改项目的 Build.cs 文件
PrivateDependencyModuleNames.AddRange(
new string[]{ "ChunkDownloader"}
4.保存后重新生成项目文件。操作:右键点击你的 .uproject 文件,然后点击 生成项目文件(Generate Project Files)。
第二步:资源分块,然后打包。为了测试方便,新建三个map,分别放在不同的文件夹。我的是Test,Test2,Test3.
添加资源分块标签。
标签设置如图:红框内需必备
属性解释:
依次对自己的测试资源添加标签。
2.打包默认设置即可。这样你可以在打出的包里看到分好的pak文件。红框ID与你的标签ID对应。
第三步:构建资源清单与托管本地测试服务器
1.构建资源清单。这里注意,英文字符下 TAB建进行属性空格。
我的清单如下:
资源文件夹结构,其中Windows文件夹中放的是分块后的pak文件
稍作解释:
第1行是需要下载更新的pak数目
第2行理解为资源和清单所在的文件夹
后面的几行就是pak资源相关的。共5个属性。资源名字,资源大小(右键资源看其属性字节数),版本号,ChunkID,资源所在位置。
2.文件托管到本地测试服务器
如何创建本地测试服务器这里不啰嗦,可以参考ue4官网。
但是这里要注意:新建文件夹PatchingDemoCDN,除了上传我们前面准备好的资源和清单即PatchingDemoKey文件夹。我们还需要在PatchingDemoCDN文件夹中新建表单
这个表单中我们要写上$BUILD_ID对应的也就是资源和清单所在的文件夹PatchingDemoKey
最后我们还需要在项目的配置表DefaultGame.ini中添加用来下载资源的网站地址。这里我们是用本地服务器测试的。
[/Script/Plugins.ChunkDownloader PatchingDemoLive]
+CdnBaseUrls=127.0.0.1/PatchingDemoCDN
第三步:编辑代码和逻辑。(开始不必扩展,实现基本功能即可)
1.GameInstance不仅具有可以绑定的相应初始化和关闭函数,而且还可以在游戏运行时持续访问ChunkDownloader。
所以使用 GameInstance 作为基类创建 新C++类。将其命名为 PatchingDemoGameInstance。
最后代码为:
// Fill out your copyright notice in the Description page of Project Settings. #pragma once #include "CoreMinimal.h" #include "Engine/GameInstance.h" #include "PatchingDemoGameInstance.generated.h" /** * */ DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPatchCompleteDelegate, bool, Succeeded); UCLASS() class UPatchingDemoGameInstance : public UGameInstance { GENERATED_BODY() public: /** Overrides */ virtual void Init() override; virtual void Shutdown() override; /** Delegates */ /** Fired when the patching process succeeds or fails */ UPROPERTY(BlueprintAssignable, Category = "Patching") FPatchCompleteDelegate OnPatchComplete; /** Starts the game patching process. Returns false if the patching manifest is not up to date. */ UFUNCTION(BlueprintCallable, Category = "Patching") bool PatchGame(); UFUNCTION(BlueprintPure, Category = "Patching|Stats") void GetLoadingProgress(int32& FilesDownloaded, int32& TotalFilesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const; protected: //Tracks Whether or not our local manifest file is up to date with the one hosted on our website bool bIsDownloadManifestUpToDate; void OnManifestUpdateComplete(bool bSuccess); /** List of Chunk IDs to try and download */ UPROPERTY(EditDefaultsOnly, Category = "Patching") TArray<int32> ChunkDownloadList; /** Called when the chunk download process finishes */ void OnDownloadComplete(bool bSuccess); /** Called whenever ChunkDownloader's loading mode is finished*/ void OnLoadingModeComplete(bool bSuccess); /** Called when ChunkDownloader finishes mounting chunks */ void OnMountComplete(bool bSuccess); };
.cpp // Fill out your copyright notice in the Description page of Project Settings. #include "PatchingDemoGameInstance.h" #include "ChunkDownloader.h" #include "Misc/CoreDelegates.h" #include "AssetRegistryModule.h" void UPatchingDemoGameInstance::Init() { Super::Init(); const FString DeploymentName = "PatchingDemoLive"; const FString ContentBuildId = "PatchingDemoKey"; // initialize the chunk downloader TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetOrCreate(); // TODO 安卓下载方式 // Downloader->Initialize("Android", 8); Downloader->Initialize("Windows", 8); // load the cached build ID Downloader->LoadCachedBuild(DeploymentName); // update the build manifest file TFunction<void(bool bSuccess)> UpdateCompleteCallback = [&](bool bSuccess){bIsDownloadManifestUpToDate = true;}; Downloader->UpdateBuild(DeploymentName, ContentBuildId, UpdateCompleteCallback); } void UPatchingDemoGameInstance::Shutdown() { Super::Shutdown(); // Shut down ChunkDownloader FChunkDownloader::Shutdown(); } void UPatchingDemoGameInstance::OnManifestUpdateComplete(bool bSuccess) { bIsDownloadManifestUpToDate = bSuccess; } void UPatchingDemoGameInstance::GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const { //Get a reference to ChunkDownloader TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked(); //Get the loading stats struct FChunkDownloader::FStats LoadingStats = Downloader->GetLoadingStats(); //Get the bytes downloaded and bytes to download BytesDownloaded = LoadingStats.BytesDownloaded; TotalBytesToDownload = LoadingStats.TotalBytesToDownload; //Get the number of chunks mounted and chunks to download ChunksMounted = LoadingStats.ChunksMounted; TotalChunksToMount = LoadingStats.TotalChunksToMount; //Calculate the download and mount percent using the above stats DownloadPercent = ((float)BytesDownloaded / (float)TotalBytesToDownload)*100.0f; MountPercent = ((float)ChunksMounted / (float)TotalChunksToMount)*100.0f; } void UPatchingDemoGameInstance::OnLoadingModeComplete(bool bSuccess) { OnDownloadComplete(bSuccess); } void UPatchingDemoGameInstance::OnMountComplete(bool bSuccess) { OnPatchComplete.Broadcast(bSuccess); } bool UPatchingDemoGameInstance::PatchGame() { // make sure the download manifest is up to date if (bIsDownloadManifestUpToDate) { // get the chunk downloader TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked(); // report current chunk status for (int32 ChunkID : ChunkDownloadList) { int32 ChunkStatus = static_cast<int32>(Downloader->GetChunkStatus(ChunkID)); UE_LOG(LogTemp, Display, TEXT("Chunk %i status: %i"), ChunkID, ChunkStatus); } TFunction<void(bool bSuccess)> DownloadCompleteCallback = [&](bool bSuccess) {OnDownloadComplete(bSuccess); }; Downloader->DownloadChunks(ChunkDownloadList, DownloadCompleteCallback, 1); // start loading mode TFunction<void(bool bSuccess)> LoadingModeCompleteCallback = [&](bool bSuccess) {OnLoadingModeComplete(bSuccess); }; Downloader->BeginLoadingMode(LoadingModeCompleteCallback); return true; } // we couldn't contact the server to validate our manifest, so we can't patch UE_LOG(LogTemp, Display, TEXT("Manifest Update Failed. Can't patch the game")); return false; } void UPatchingDemoGameInstance::OnDownloadComplete(bool bSuccess) { if (bSuccess) { UE_LOG(LogTemp, Display, TEXT("Download complete")); // get the chunk downloader TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked(); FJsonSerializableArrayInt DownloadedChunks; for (int32 ChunkID : ChunkDownloadList) { DownloadedChunks.Add(ChunkID); } //Mount the chunks TFunction<void(bool bSuccess)> MountCompleteCallback = [&](bool bSuccess) {OnMountComplete(bSuccess); }; Downloader->MountChunks(DownloadedChunks, MountCompleteCallback); OnPatchComplete.Broadcast(true); } else { UE_LOG(LogTemp, Display, TEXT("Load process failed")); // call the delegate OnPatchComplete.Broadcast(false); } }
2.使用 PatchingDemoGameInstance 作为基类创建 新蓝图,命名为 CDGameInstance
3.打开CDGameInstance,添加chunk列表
4.创建名为 PatchingGameMode 的新游戏模式 蓝图
5.项目做如下设置。
6.第三人称游戏map设置gamemode为PatchingGameMode
7.打开PatchingGameMode,添加如下蓝图逻辑。
beginPlay后添加:patchGame返回值为true则进入tick即开始下载资源。否则根据资源数进行进一步检测。
tick后添加:大概意思就是资源下载并且装载完打开Test3地图。
到此代码,逻辑都写好了。
第四步:打包测试
1.直接打包。
结果是包文件夹里的Content中的paks文件夹有四个pak文件。删掉ID为1001-1003的pak。
2.运行.exe
结果如下:
下载中
下载完成,3秒后进入Test3地图。
下载的文件:
UE-自带的HotUpdate【转】的更多相关文章
- UE编辑器加载格式化代码插件astyle
UE 的格式化功能不强,自带的astyle版本陈旧,一般采用开源工具astyle来实现代码格式化. 1. 首先下载最新的astyle,因为ue自带的astyle版本太老,不支持空格.中文名等. 2. ...
- 【Tips】【UE】总结自己常用的UltraEdit使用技巧
如果您问我每天都要打开的软件是什么,那毫无疑问是UltraEdit!作为一位DBA,每天都要写各种脚本,尤其是在对具有超多行行的大文件进行精心编辑时,没有一个好的文本编辑器是不成的.掐指一算,哇塞,自 ...
- 【UE】常用的UltraEdit使用技巧
Tip 1: Alt+C 列模式可以说最初选择使用这个文本编辑软件,原因很简单,就是因为“她”具有列编辑模式.如果您还不知道什么是列编辑模式的话,我想您应该好好研究一下啦.这是一个超级“赞”的功能.在 ...
- Ultraedit中使用Astyle格式化代码
方法: 使用UE的自定义工具栏并借助开源工具astyle.exe来完成. 1. 首先下载最新的astyle,因为ue自带的astyle版本太老,不支持空格.中文名等. http://astyle.so ...
- 常用的UltraEdit使用技巧
Tip 1: Alt+C 列模式可以说最初选择使用这个文本编辑软件,原因很简单,就是因为"她"具有列编辑模式.如果您还不知道什么是列编辑模式的话,我想您应该好好研究一下啦.这是一个 ...
- org.json.JSONException: A JSONObject text must begin with '{' at character 1 of {解决方法
在使用java读取一个本地的json配置文件的时候,产生了这个异常:org.json.JSONException: A JSONObject text must begin with '{' at c ...
- ultraedit 实际应用技巧
Tip 1: Alt+C 列模式可以说最初选择使用这个文本编辑软件,原因很简单,就是因为“她”具有列编辑模式.如果您还不知道什么是列编辑模式的话,我想您应该好好研究一下啦.这是一个超级“赞”的功能.在 ...
- UltraEdit常用技巧
Tip 1: Alt+C 列模式可以说最初选择使用这个文本编辑软件,原因很简单,就是因为“她”具有列编辑模式.如果您还不知道什么是列编辑模式的话,我想您应该好好研究一下啦.这是一个超级“赞”的功能.在 ...
- 带交互的 iOS 产品原型可以用什么软件制作?
摘自知乎http://www.zhihu.com/question/20326729 来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 首先如果你小团队或者个人开发,当然 ...
- Unity外包团队:U3D与UE我选哪个好?请别再问这种问题了!
原本预先决定的两家VR游戏公司采访,思熊和星为棋,并没有发现什么共性之初.结果在采访之后却意外发现,两家的经历有着非常相似的地方.他们都是来自于开发游戏所用的引擎的原开发商,比如思熊的主力来自Epic ...
随机推荐
- Vue cli之项目目录结构
src 主开发目录,要开发的单文件组件全部在这个目录下的components目录下 static 静态资源目录,所有的css,js文件放在这个文件夹 dist 项目打包发布文件夹,最后要上线单文件项目 ...
- 8.17考试总结(NOIP模拟42)[卷·简单题·粉丝·字符串]
你的败因只有一个,就是与我为敌. T1 卷 解题思路 乍一看,简单的树形 DP . 后来一看数据范围,发现事实并非如此.(\((10^9)^{2\times 10^5}\)????) 毕竟取 \( ...
- 赛博斗地主——使用大语言模型扮演Agent智能体玩牌类游戏。
通过大模型来实现多个智能体进行游戏对局这个想对已经比较成熟了无论是去年惊艳的斯坦福小镇还是比如metaGPT或者类似的框架都是使用智能体技术让大模型来操控,从而让大模型跳出自身"预测下一个t ...
- 记一次 .NET某工控视觉自动化系统 卡死分析
一:背景 1. 讲故事 今天分享的dump是训练营里一位学员的,从一个啥也不会到现在分析的有模有样,真的是看他成长起来的,调试技术学会了就是真真实实自己的,话不多说,上windbg说话. 二:WinD ...
- php基本语法与安装
// 什么是PHP // PHP 是 后端语言的一种 // 主要作用就是实现数据交互 // ...
- 支付宝支付jemter 插件,导入到高版本jmeter 中使用
官方支付宝压力测试文档中: 蚂蚁金服开放平台 - 文档中心 (alipay.com) 有个 temp.jmx 文件(http://p.tb.cn/rmsportal_10157_temp.jmx.zi ...
- 使用 OpenTelemetry 构建可观测性 05 - 传播和行李(Propagation & Baggage)
我们开发的应用程序可能具有不同的形态和架构:有些是单体应用,有些是微服务.为单体应用程序添加遥测数据相对来说简单,因为所有数据都在同一进程中.然而对于微服务应用程序,情况可能会更具挑战性. 通常,分布 ...
- 简单的css3头像旋转与3D旋转效果
Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 简单的css3头像旋转与3D旋转效果 日期:2017-7- ...
- 01-前端开发Vscode插件配置
01 自动保存配置 02 空格渲染方式 配置好以后,可以看到代码的空格有几个,以点的方式呈现,1个点表示1个空格 03 图标插件 VSCode Great Icons 04 缩进 推荐使用2 05 v ...
- 关于c指针的理解
1 #include<stdio.h> 2 { 3 int a= 100,b=10; 4 int *p1=&a,*p2=&b; 5 *p1=b; 6 *p2=a; 7 pr ...