淘先锋技术网

首页 1 2 3 4 5 6 7

目录

必要说明:

一、准备

二、项目

1.打开插件

2.添加模块到 xxx(项目名字).Build.cs 文件

3.创建GameInstance(C++类)

4.创建和配置蓝图文件

4.1.创建蓝图 Gameinstance 并继承 MyGameInstance

4.2.配置下载文件块

4.3.创建GameMode(蓝图即可)

 4.4.创建一个空白的关卡

5.创建DataAsset

6.项目设置

 6.1 DefaultGame.ini

6.2 ProjectSetting

7.项目打包设置

三、服务器

1.安装Web服务器

2.配置Web服务器

2.1.打开服务器

2.2.选择刚刚创建的服务器

2.3.选择MIME类型

2.4.在右侧空白的地方: 右键 —> 点击添加,然后填入如下信息

3.配置Web服务器的文件夹

四、启动服务器

五、测试项目


必要说明:

 本文案例仅适用于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 选择WindowsNoEditorUE5 选择 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.*** 结尾的

码字不易,有大佬发现问题的,请帮忙指出,没有做视频,就不放最终效果了。