目录
4.1.创建蓝图 Gameinstance 并继承 MyGameInstance
2.4.在右侧空白的地方: 右键 —> 点击添加,然后填入如下信息
必要说明:
本文案例仅适用于C++(加蓝图)开发的UE项目
部分代码直接拷贝官方文档的,但是会有一些避坑的修改
一、准备
1.创建一个空的C++项目(随便创建一个空的)
2.准备一个服务器,或者直接在本机上建立服务器也可以(本文使用的是Windows server 2019)
二、项目
1.打开插件
2.添加模块到 xxx(项目名字).Build.cs 文件
PrivateDependencyModuleNames.AddRange(
new string[]
{
"ChunkDownloader"
});
3.创建GameInstance(C++类)
//本文直接使用 MyGameInstance 命名
MyGameInstance实现
.h头文件
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "MyGameInstance.generated.h"
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPatchCompleteDelegate, bool, Succeeded);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FManifestUpdateDelegate, bool, Succeeded);
UCLASS()
class FILEPAKTES_API UMyGameInstance : public UGameInstance
{
GENERATED_BODY()
public:
/** Overrides */
virtual void Init() override;
virtual void Shutdown() override;
void OnManifestUpdateComplete(bool bSuccess);
//获取下载和安装进度
UFUNCTION(BlueprintPure, Category = "Patching|Stats")
void GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const;
/**启动游戏补丁过程。如果补丁清单不是最新的,则返回false。*/
UFUNCTION(BlueprintCallable, Category = "Patching")
bool PatchGame();
protected:
/**文件块下载过程完成时调用*/
void OnDownloadComplete(bool bSuccess);
/**ChunkDownloader加载模式完成时调用*/
void OnLoadingModeComplete(bool bSuccess);
/**ChunkDownloader完成挂载文件块时调用*/
void OnMountComplete(bool bSuccess);
public:
/**补丁过程成功或失败时触发*/
UPROPERTY(BlueprintAssignable, Category = "Patching");
FPatchCompleteDelegate OnPatchComplete;
//开始下载时触发
UPROPERTY(BlueprintAssignable, Category = "Patching");
FManifestUpdateDelegate OnManifestUpdateComp;
/**要尝试和下载的文件块ID列表*/
UPROPERTY(EditDefaultsOnly, Category = "Patching")
TArray<int32> ChunkDownloadList;
protected:
//Tracks Whether or not our local manifest file is up to date with the one hosted on our website
bool bIsDownloadManifestUpToDate;
};
.cpp文件
#include "MyGameInstance.h"
#include "ChunkDownloader.h"
#include "Misc/CoreDelegates.h"
#include "AssetRegistryModule.h"
void UMyGameInstance::Init()
{
Super::Init();
const FString DeploymentName = "PatchingDemoLive";
//这里是可以配置的,作为版本号使用
const FString ContentBuildId = "PatchingKey";
// initialize the chunk downloader
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetOrCreate();
Downloader->Initialize("Windows", 8);
// load the cached build ID
Downloader->LoadCachedBuild(DeploymentName);
//注意,这里官方文档是有个坑的
TFunction<void(bool bSuccess)> UpdateCompleteCallback = [&](bool bSuccess) { OnManifestUpdateComplete(bSuccess); };
Downloader->UpdateBuild(DeploymentName, ContentBuildId, UpdateCompleteCallback);
}
void UMyGameInstance::Shutdown()
{
Super::Shutdown();
// Shut down ChunkDownloader
FChunkDownloader::Shutdown();
}
void UMyGameInstance::OnManifestUpdateComplete(bool bSuccess)
{
bIsDownloadManifestUpToDate = bSuccess;
if (bIsDownloadManifestUpToDate)
{
UE_LOG(LogTemp, Display, TEXT("Patch Game to download file pak."));
PatchGame();
}
OnManifestUpdateComp.Broadcast(bSuccess);
}
//注意,这里官方文档,头文件与cpp文件的参数名字不对
void UMyGameInstance::GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const
{
//获取ChunkDownloader的引用
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
//获取加载统计结构体
FChunkDownloader::FStats LoadingStats = Downloader->GetLoadingStats();
//获取已下载和要下载的的字节
BytesDownloaded = LoadingStats.BytesDownloaded;
TotalBytesToDownload = LoadingStats.TotalBytesToDownload;
//获取已挂载文件块数和要下载的文件块数
ChunksMounted = LoadingStats.ChunksMounted;
TotalChunksToMount = LoadingStats.TotalChunksToMount;
//使用以上统计信息计算下载和挂载百分比
DownloadPercent = (float)BytesDownloaded / (float)TotalBytesToDownload;
MountPercent = (float)ChunksMounted / (float)TotalChunksToMount;
}
bool UMyGameInstance::PatchGame()
{
//确保下载清单是最新的
if (bIsDownloadManifestUpToDate)
{
//获取文件块下载器
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
//报告当前文件块状态
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);
//启动加载模式
TFunction<void(bool bSuccess)> LoadingModeCompleteCallback = [&](bool bSuccess) {OnLoadingModeComplete(bSuccess); };
Downloader->BeginLoadingMode(LoadingModeCompleteCallback);
return true;
}
//我们无法联系服务器验证清单,因此我们无法补丁
UE_LOG(LogTemp, Display, TEXT("Manifest Update Failed.Can't patch the game"));
return false;
}
void UMyGameInstance::OnDownloadComplete(bool bSuccess)
{
if (bSuccess)
{
UE_LOG(LogTemp, Display, TEXT("Download complete"));
//获取文件块下载器
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetChecked();
FJsonSerializableArrayInt DownloadedChunks;
for (int32 ChunkID : ChunkDownloadList)
{
DownloadedChunks.Add(ChunkID);
}
//挂载文件块
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"));
//调用委托
OnPatchComplete.Broadcast(false);
}
}
void UMyGameInstance::OnLoadingModeComplete(bool bSuccess)
{
OnDownloadComplete(bSuccess);
}
void UMyGameInstance::OnMountComplete(bool bSuccess)
{
OnPatchComplete.Broadcast(bSuccess);
}
4.创建和配置蓝图文件
4.1.创建蓝图 Gameinstance 并继承 MyGameInstance
//蓝图类的GameInstanc名字自定,本文使用BP_PatchGameInstance
4.2.配置下载文件块
在BP_PatchGameInstance右侧属性栏里配置
文件块的id,根据项目配置的ChunkId来配置(后面会有说明)
4.3.创建GameMode(蓝图即可)
//本文使用BP_PatchGameMode
在GameMode中添加以下蓝图
4.4.创建一个空白的关卡
名字随便,,打开关卡,并把GameMode设置为上文创建的GameMode
5.创建DataAsset
然后命名,并进行配置
前文提到的ChunkID就是在这里面进行配置的,每个DataAsset,只能配置一个ChuankID,多个DataAsset可以配置同一个ChunkID
创建了多少个ChuankID,就在GameInstance里配置多少个,当然GameInstance里的配置是可以通过外部加载的,这个根据项目自行开发
勾选LabAssetsInMyDirectory选项是关联当前文件夹下的所有资源,在打包的时候,该DataAsset文件夹里的所有资源都会被打包到该DataAsset配置的ChuankID块上
不勾选LabAssetsInMyDirectory可以在下面的列表里进行配置
在本文的案例里,仅创建了两个DataAsset,ChunkID分别为1001,1002
6.项目设置
6.1 DefaultGame.ini
添加下面的配置信息
[/Script/Plugins.ChunkDownloader PatchingDemoLive]
+CdnBaseUrls=192.168.0.31/FilePakTesCDN
其中:192.168.0.31 ip是你服务器的ip,FilePakTexCDN是服务器初始目录,名字在发布项目后是固定的(为什么配置这么写,后面创建服务器的时候会提到)
6.2 ProjectSetting
GmaeMode,GameInstance以及初始地图设置
Pakaging设置
7.项目打包设置
打开 ProjectLauncher ,添加两个新的打包配置
MainPak是打包主包的配置
其配置如下:第一个是选择当前项目,
找不到的直接选择Browse,直接通过目录去找到项目里的 .uproject 文件
编译模式,根据项目需求进行配置
烘培的平台选择 UE4 选择WindowsNoEditor, UE5 选择 Windows即可
烘培地图,把要打包的地图勾上即可
配置打包后存放的路径
Patch是打包补丁(或者DLC)的
除了以下的配置,其余配置与主包配置一致
1.不烘培地图,因为是补丁,除非是修改了地图,或者作为DLC打包,否则选择
以上就是项目的所有配置了,接着就是打包了
注意:主包的保存目录,与补丁的保存目录需要分开,不然会被覆盖的
三、服务器
Windows服务器创建(官方的方法)
托管ChunkDownloader的清单和资产 | 虚幻引擎文档 (unrealengine.com)
Windwos Server 2019
1.安装Web服务器
弹出窗口后,一直点击下一步(有修改的,我会放图)
后面都是默认,一直到可以点击安装为止,然后等待安装完成
2.配置Web服务器
2.1.打开服务器
2.2.选择刚刚创建的服务器
2.3.选择MIME类型
2.4.在右侧空白的地方: 右键 —> 点击添加,然后填入如下信息
类型为:application/octet-stream
注意:ue5 的包因为多了两个文件 .ucas 和 .utoc,使用同样的方法添加进去
3.配置Web服务器的文件夹
默认路径为 C:\inetpub\wwwroot
在 wwwroot 文件下创建一个新的文件夹,命名是第二点的6.1里的配置名字
这个一定是相同的,否则打包后,下载没法找到下载文件的
然后在此新的文件夹下创建一个新的文件夹,命名是如图
这里可以使用 1.0.1,1.0.2 ,1.0.3...等等命名,可以把每一个文件夹作为一个版本
接着在这个新文件夹里创建一个Windows文件夹(不同平台命名按照平台去命名)
同时创建一个BuildManifest-Windows.txt文件,写入如下信息
$NUM_ENTRIES = 3
$BUILD_ID = PatchingKey
pakchunk1002-Windows_0_P.pak 339 ver 1002 /Windows/pakchunk1002-Windows_0_P.pak
pakchunk1002-Windows_0_P.ucas 816 ver 1002 /Windows/pakchunk1002-Windows_0_P.ucas
pakchunk1002-Windows_0_P.utoc 409 ver 1002 /Windows/pakchunk1002-Windows_0_P.utoc
$NUM_ENTRIES 下载文件的数量
$BUILD_ID 上文提到的,可以用来作为版本的文件夹名称
ver 左边的数字是文件大小,可以通过文件属性来查看,直接复制
右边的是ChuankID,最右边的是文件下载补全路径
注意:
这几个间隔是 TAB制表键,并非空格键
最后一步就是把打包好的包文件拷贝到Windows文件夹下了,只需要拷贝要更新的文件块即可
四、启动服务器
测试服务器:在浏览器里输入地址
如果能下载指定文件,说明服务器配置成功了,如果不能,看看路径地址有没有写错
五、测试项目
我这里是使用UI作为版本显示,看看有没有更新
这里仅更新1002
使用 ProjectLauncher 先打一个主包,然后打一个补丁的包
把补丁的包上传到服务器,然后配置服务器的BuildManifest-Windows.txt文件,信息都在上文了
UI界面就一个版本号信息,主包默认是1.0.1,补丁包是1.0.2,如果更新成功,版本就会变成1.0.2
注意,补丁包是以 _p.*** 结尾的
码字不易,有大佬发现问题的,请帮忙指出,没有做视频,就不放最终效果了。