ChunkDownloader 는 언리얼 엔진(UE) 의 패치 솔루션입니다. 원격 서비스로부터 에셋을 다운로드하고 게임에서 사용할 수 있도록 이를 메모리에 마운트하여 손쉽게 업데이트와 에셋을 제공할 수 있습니다. 이 가이드에서는 프로젝트에 ChunkDownloader를 구현하는 방법을 보여줍니다. 이 가이드를 완료하면 다음과 같은 작업을 할 수 있습니다.
- Visual Studio를 사용하여 ChunkDownloader를 초기화 및 종료합니다.
- Visual Studio를 사용하여 호스트 웹 사이트에서 패키징 파일을 다운로드합니다.
- UE에서 ChunkDownloader를 실행하기 위해 게임 모드 블루프린트 를 구성합니다.
- 레벨 에디터 뷰포트 또는 게임 내에서 다운로드한 콘텐츠를 표시합니다.
- 마운트된 패키징 파일의 콘텐츠에 안전하게 액세스합니다.
- UE 프로젝트에서 조정된 시스템을 로컬 머신에서 테스트합니다.
1. 필수 설정 및 권장 에셋
계속 진행하기 전에 다음 가이드를 검토하고 각각의 단계를 따라야 합니다.
레퍼런스 가이드에 설명된 대로 다음 단계를 따라야 합니다.
-
기본 템플릿(Blank template) 을 기반으로 하는 C++ 프로젝트 를 생성합니다. 이 프로젝트의 이름을 PatchingDemo 로 설정합니다.
-
플러그인(Plugins) 메뉴에서 ChunkDownloader 플러그인을 활성화합니다.
-
프로젝트 세팅(Project Settings) > 프로젝트(Project) > 패키징(Packaging) 에서 Pak 파일 사용(Use Pak File) 및 청크 생성(Generate Chunks) 을 활성화합니다.
-
Visual Studio 에서 프로젝트의
[프로젝트 이름]Build.cs파일을 편집합니다. -
Visual Studio 프로젝트 파일을 생성합니다.
-
Visual Studio에서 프로젝트를 빌드합니다.
-
이 프로젝트에 Paragon 의 Boris, Crunch, Khaimera 에셋을 추가합니다.
-
추가된 에셋마다 프라이머리 에셋 라벨 을 기준으로 데이터 에셋 을 조정합니다.
-
프로젝트를 쿠킹 또는 패키징하고 빌드 폴더에 패키징 파일을 배치합니다.
-
로컬 호스팅 웹 사이트에 패키징 파일을 배포합니다.
-
BuildManifest-Windows.txt라는 매니페스트 파일을 생성합니다. -
프로젝트에 대한
DefaultGame.ini파일을 정의합니다.
2. ChunkDownloader 초기화 및 종료
ChunkDownloader는 FPlatformChunkInstall 인터페이스의 구현이고, 호환되는 여러 인터페이스 중 하나에서 게임이 실행 중인 플랫폼에 따라 각기 다른 모듈을 로드할 수 있습니다. 모든 모듈은 사용 전에 로드 및 초기화해야 하고, 종료 및 정리해야 합니다.
ChunkDownloader에서 이를 수행하는 가장 간단한 방법은 커스텀 GameInstance 클래스를 사용하는 것입니다. GameInstance에는 연결할 수 있는 적절한 초기화 및 종료 함수가 있을 뿐만 아니라 게임이 실행 중인 동안 ChunkDownloader에 대한 지속적인 액세스도 가능합니다. 다음 단계는 이 구현 과정을 안내합니다.
GameInstance 를 베이스 클래스로 사용하여 새 C++ 클래스 를 생성합니다. 이름은 PatchingDemoGameInstance 로 지정합니다.
이미지를 클릭하면 확대됩니다.
컴파일 프로세스가 완료되면 Visual Studio에서 PatchingDemoGameInstance.h 및 PatchingDemoGameInstance.cpp 파일이 자동으로 열립니다.
PatchingDemoGameInstance.h 작업
파일이 열리면 PatchingDemoGameInstance.h 의 코드는 다음과 같아야 합니다.
PatchingDemoGameInstance.h
#pragma once
#include "CoreMinimal.h"
#include "Engine/GameInstance.h"
#include "PatchingDemoGameInstance.generated.h"
UCLASS()
class UPatchingDemoGameInstance : public UGameInstance
{
GENERATED_BODY()
};
-
스트링
class UPatchingDemoGameInstance : public UGameInstance를 다음과 같이 변경합니다.PatchingDemoGameInstance.h
class PATCHINGDEMO_API UPatchingDemoGameInstance : public UGameInstance
PatchingDemoGameInstance.h 파일에서 선언할 모든 후속 변수, 함수 및 프로퍼티는 UPatchingDemoGameInstance 클래스 아래에 추가해야 합니다.
-
public헤더 아래에서 다음과 같은 함수 오버라이드를 선언합니다.PatchingDemoGameInstance.h
public:
// 오버라이드
virtual void Init() override;
virtual void Shutdown() override;
Init 함수는 게임이 시작될 때 실행되므로 ChunkDownloader를 초기화할 수 있는 최적의 위치가 됩니다. 마찬가지로 Shutdown 함수는 게임이 중지될 때 실행되므로 이를 사용하여 ChunkDownloader 모듈을 종료할 수 있습니다.
-
protected헤더 아래에서 다음과 같은 변수를 선언합니다.PatchingDemoGameInstance.h
protected:
//로컬 매니페스트 파일이 웹사이트에 호스팅된 파일과 같은 최신 업데이트 상태인지 여부를 트래킹합니다.
bool bIsDownloadManifestUpToDate;
-
protected헤더에서 다음 함수를 선언합니다.PatchingDemoGameInstance.h
protected:
// 청크 다운로드 프로세스가 완료되면 호출됩니다.
void OnManifestUpdateComplete(bool bSuccess);
PatchingDemoGameInstance.cpp 작업
-
PatchingDemoGameInstance.cpp를 엽니다.#include "PatchingDemoGameInstance.h"에 있는 파일 맨 위에 다음#includes를 추가합니다.PatchingDemoGameInstance.cpp
#include "PatchingDemoGameInstance.h"
#include "ChunkDownloader.h"
#include "Misc/CoreDelegates.h"
#include "AssetRegistryModule.h"
이를 통해 ChunkDownloader와 에셋 및 델리게이트 관리에 유용한 몇 가지 툴에 액세스할 수 있습니다.
-
Init함수에 대해 다음 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::Init()
{
Super::Init();
const FString DeploymentName = "PatchingDemoLive";
const FString ContentBuildId = "PatchingDemoKey";
// 선택한 플랫폼에서 청크 다운로더를 초기화합니다.
TSharedRef<FChunkDownloader> Downloader = FChunkDownloader::GetOrCreate();
Downloader->Initialize("Windows", 8);
// 캐싱된 빌드 ID를 로딩합니다
Downloader->LoadCachedBuild(DeploymentName);
// 빌드 매니페스트 파일을 업데이트합니다
TFunction<void(bool bSuccess)> UpdateCompleteCallback = [&](bool bSuccess) {bIsDownloadManifestUpToDate = true; };
Downloader->UpdateBuild(DeploymentName, ContentBuildId, UpdateCompleteCallback);
}
이 코드의 역할을 다음과 같이 요약해 보겠습니다.
1. 함수는 DeploymentName 및 ContentBuildID 를 정의하여 DefaultGame.ini 에서 사용되는 값을 일치시킵니다. 이 값은 현재 테스트를 위해 고정된 값이지만 전체 빌드에서는 HTTP 요청을 사용하여 ContentBuildID 를 가져옵니다. 함수는 이 변수의 정보를 사용하여 웹 사이트에 매니페스트를 요청합니다.
1. 함수는 FChunkDownloader::GetOrCreate 를 호출하여 ChunkDownloader를 설정하고 이에 대한 레퍼런스를 가져온 뒤, TSharedRef 에 저장합니다. 비슷한 플랫폼 인터페이스에 대한 레퍼런스를 가져오는 데 있어 선호되는 방법입니다.
1. 함수는 원하는 플랫폼 이름, 이 경우에는 Windows를 사용하여 FChunkDownloader::Initialize 를 호출합니다. 이 예시에서는 TargetDownloadsInFlight에 8 의 값을 제공하고, 이는 ChunkDownloader가 한 번에 처리하는 최대 다운로드 수를 설정합니다.
1. 함수는 DeploymentName 을 사용하여 FChunkDownloader::LoadCachedBuild 를 호출합니다. 디스크에 이미 다운로드되어 있는 파일이 있는지 확인하고, 이를 통해 ChunkDownloader가 최신 매니페스트 파일로 업데이트된 경우 두 번째 다운로드를 건너뛸 수 있습니다.
1. 함수는 FChunkDownloader::UpdateBuild 를 호출하여 매니페스트 파일의 업데이트된 버전을 다운로드합니다.
이를 통해 완전히 새로운 실행 파일 없이도 시스템에서 패치 업데이트를 지원합니다.
UpdateBuild 는 작업의 성공 여부를 출력하는 콜백과 함께 DeploymentName 및 ContentBuildID 를 가져옵니다.
* 또한 OnManifestUpdateComplete 를 사용하여 bIsDownloadManifestUpToDate 를 설정하고, GameInstance는 이 패치 페이즈가 완료되는지 전역으로 인식할 수 있습니다.
이 단계를 따르면 ChunkDownloader가 초기화되고 콘텐츠 다운로드를 시작할 준비가 되며, 다른 함수에 매니페스트의 상태를 알립니다.
-
Shutdown함수에 대해 다음 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::Shutdown()
{
Super::Shutdown();
// 청크 다운로더를 종료합니다
FChunkDownloader::Shutdown();
}
FChunkDownloader::Shutdown 을 호출하면 ChunkDownloader에서 현재 진행 중인 모든 다운로드를 중지하고, 모듈을 정리한 다음 언로드합니다.
-
OnManifestUpdateComplete함수에 대해 다음 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::OnManifestUpdateComplete(bool bSuccess)
{
bIsDownloadManifestUpToDate = bSuccess;
}
이 함수는 매니페스트 업데이트가 완료될 때 비동기 콜백으로 사용됩니다.
3. 패키징 파일 다운로드
이제 ChunkDownloader에 대한 적절한 초기화 및 종료 함수가 있으니 패키징 파일 다운로드를 위한 함수 기능을 노출시킬 수 있습니다.
PatchingDemoGameInstance.h 작업
-
PatchingDemoGameInstance.h의#includes아래에서 다음 다이내믹 멀티캐스트 델리게이트를 추가합니다.PatchingDemoGameInstance.h
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPatchCompleteDelegate, bool, Succeeded);
이 델리게이트는 패치 다운로드 작업이 성공했는지 여부를 알리는 boolean을 출력합니다. 델리게이트는 일반적으로 파일 다운로드 또는 설치와 같은 비동기 작업에 응답하는 데 사용됩니다.
-
UPatchingDemoGameInstance클래스에서public헤더 아래에GetLoadingProgress에 대한 다음과 같은 함수 선언을 추가합니다.PatchingDemoGameInstance.h
public:
UFUNCTION(BlueprintPure, Category = "Patching|Stats")
void GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const;
-
public헤더 아래에 다음과 같은 델리게이트 선언을 추가합니다.PatchingDemoGameInstance.h
public:
// 델리게이트
// 패치 프로세스가 성공 또는 실패하면 발생합니다.
UPROPERTY(BlueprintAssignable, Category="Patching");
FPatchCompleteDelegate OnPatchComplete;
이를 통해 패치 작업이 완료될 때 블루프린트로 후킹할 수 있는 위치가 제공됩니다.
-
protected헤더 아래에ChunkDownloadList에 대한 다음과 같은 선언을 추가합니다.PatchingDemoGameInstance.h
protected:
// 시도 및 다운로드할 청크 ID 목록
UPROPERTY(EditDefaultsOnly, Category="Patching")
TArray<int32> ChunkDownloadList;
이 목록을 사용하여 나중에 다운로드할 모든 청크 ID를 보관합니다. 개발 세팅에서는 필요에 따라 에셋 목록을 사용하여 이를 초기화하지만, 테스트 목적으로는 블루프린트 에디터 를 사용하여 단순히 디폴트를 노출시켜 채울 수 있도록 합니다.
-
public헤더 아래에PatchGame에 대한 다음과 같은 선언을 추가합니다.PatchingDemoGameInstance.h
public:
// 게임 패치 프로세스를 시작합니다. 패치 매니페스트가 최신 상태가 아닌 경우 false를 반환합니다. */
UFUNCTION(BlueprintCallable, Category = "Patching")
bool PatchGame();
이 함수는 패치 프로세스 시작을 위해 블루프린트가 노출된 방법을 제공합니다. 성공 또는 실패 여부를 나타내는 boolean을 반환합니다. 다운로드 관리와 다른 종류의 비동기 작업에 있어 일반적인 패턴입니다.
-
protected헤더 아래에 다음과 같은 함수 선언을 추가합니다.PatchingDemoGameInstance.h
protected:
// 청크 다운로드 프로세스가 완료되면 호출됩니다.
void OnDownloadComplete(bool bSuccess);
// ChunkDownloader의 로딩 모드가 완료될 때마다 호출됩니다.
void OnLoadingModeComplete(bool bSuccess);
// ChunkDownloader가 청크 마운트를 완료하면 호출됩니다.
void OnMountComplete(bool bSuccess);
이를 사용하여 다운로드 프로세스에서 비동기 콜백에 응답합니다.
PatchingDemoGameInstance.cpp 작업
-
GetLoadingProgress함수에 대해 다음과 같은 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::GetLoadingProgress(int32& BytesDownloaded, int32& TotalBytesToDownload, float& DownloadPercent, int32& ChunksMounted, int32& TotalChunksToMount, float& MountPercent) const
{
// 청크 다운로더의 레퍼런스를 구합니다.
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) * 100.0f;
MountPercent = ((float)ChunksMounted / (float)TotalChunksToMount) * 100.0f;
}
-
PatchGame에 대해 다음 구현을 생성합니다.PatchingDemoGameInstance.cpp
bool UPatchingDemoGameInstance::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;
}
이 함수는 다음 단계를 거칩니다.
1. 먼저 매니페스트가 최신 상태인지 확인합니다. ChunkDownloader를 초기화하지 않고 성공적으로 새 매니페스트 복사본을 가져온 경우 bIsDownloadManifestUpToDate 는 false가 되고, 이 함수는 false를 반환하여 패치 시작에 실패했음을 나타냅니다.
1. 다음으로 패치 프로세스가 계속될 수 있다면 함수는 ChunkDownloader에 대한 레퍼런스를 가져옵니다. 이후 다운로드 목록을 반복하고 각 청크의 상태를 확인합니다.
1. 2개의 콜백이 정의됩니다.
개별 청크의 다운로드가 완료되면 DownloadCompleteCallback 이 호출됩니다. 각 청크가 다운로드에 성공 또는 실패할 때마다 메시지가 출력됩니다.
모든 청크가 다운로드되면 LoadingModeCompleteCallback 이 발생합니다.
1. 함수는 FChunkDownloader::DownloadChunks 를 호출하여 원하는 청크 다운로드를 시작합니다. 청크는 ChunkDownloadList 에 나열되어 있습니다. 이 목록은 함수 호출 전에 원하는 청크 ID로 채워져 있어야 합니다. 또한 DownloadCompleteCallback 을 전달합니다.
1. 함수는 앞서 정의한 콜백과 함께 FChunkDownloader::BeginLoadingMode 를 호출합니다.
Loading Mode는 ChunkDownloader에 다운로드 상태 모니터링을 시작하도록 지시합니다.
청크는 Loading Mode 호출 없이 백그라운드에서 수동으로 다운로드할 수 있지만 이를 사용하면 다운로드 통계가 출력되어 사용자가 다운로드 진행 상황을 추적할 수 있는 UI를 만들 수 있습니다.
* 콜백 함수를 사용하면 전체 청크 배치가 다운로드될 때 특정 함수 기능을 실행할 수도 있습니다.
-
OnDownloadComplete및OnLoadingModeBegin함수에 대해 다음과 같은 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::OnLoadingModeComplete(bool bSuccess)
{
OnDownloadComplete(bSuccess);
}
void UPatchingDemoGameInstance::OnMountComplete(bool bSuccess)
{
OnPatchComplete.Broadcast(bSuccess);
}
OnLoadingModeComplete 는 OnDownloadComplete 로 패스스루하고, 이후 단계에서 청크를 마운트합니다. OnMountComplete 는 모든 청크의 마운팅이 완료되고, 콘텐츠를 사용할 준비가 되었음을 나타냅니다.
-
OnDownloadComplete함수에 대해 다음과 같은 구현을 생성합니다.PatchingDemoGameInstance.cpp
void UPatchingDemoGameInstance::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);
}
}
또 다른 복잡한 함수이므로 역할별로 나눠서 살펴보겠습니다. 패키징 파일이 사용자 디바이스에 성공적으로 다운로드되면 실행됩니다.
1. 이 함수는 ChunkDownloader에 대한 레퍼런스를 가져옵니다.
1. 함수는 Json 배열을 설정하고 ChunkDownloadList 의 정보로 채웁니다. 이 정보는 요청을 수행할 때 사용됩니다.
1. 함수는 MountCompleteCallback 을 사용하여 패치가 성공적으로 적용되었는지 여부를 출력합니다.
1. 함수는 Json 목록과 MountCompleteCallback 을 사용하여 ChunkDownloader::MountChunks 를 호출하고 다운로드한 청크의 마운트를 시작합니다.
1. 다운로드가 성공한 경우 함수는 OnPatchComplete 델리게이트를 true 값으로 활성화합니다. 성공하지 않은 경우 false 값으로 활성화합니다. UE_LOG 는 실패 지점에 따라 오류 메시지를 출력합니다.
4. Patching Game Mode 설정
패치 프로세스를 초기화하기 위해 레벨 과 게임 모드 를 만들어 PatchGame 을 호출하고 화면에 패치 통계를 출력할 수 있습니다.
-
언리얼 에디터에서 콘텐츠 브라우저(Content Browser) 에 새로운 Blueprints 폴더를 생성합니다. 그런 다음 PatchingDemoGameInstance 를 베이스 클래스로 사용하여 새 블루프린트 를 생성합니다.
새 블루프린트 클래스 이름을 CDGameInstance 로 지정합니다.
세팅을 편집하고 청크 다운로드 프로세스를 추적하기 위해 더욱 액세스하기 쉬운 방법으로 이 블루프린트를 사용합니다.
-
PatchingGameMode 라는 새 게임 모드 블루프린트를 생성합니다.
-
Maps 폴더를 생성하고 이름이 PatchingDemoEntry 및 PatchingDemoTest 인 2개의 새 레벨을 생성합니다. PatchingDemoEntry 레벨은 빈 맵을 기반으로 해야 하며, PatchingDemoTest 레벨은 Default 맵을 기반으로 해야 합니다.
-
프로젝트 세팅(Project Settings) 을 열고 프로젝트(Project) > 맵 & 모드(Maps & Modes) 로 이동합니다. 다음과 같은 파라미터를 설정합니다.
이미지를 클릭하면 확대됩니다.
ID 파라미터 값 1 게임 인스턴스 클래스 CDGameInstance 2 에디터 시작 맵 PatchingDemoTest 3 게임 기본 맵 PatchingDemoEntry -
블루프린트 에디터 에서 CDGameInstance 를 엽니다. 디폴트(Defaults) 패널에서 청크 다운로드 목록(Chunk Download List) 에 3개의 항목을 추가합니다. 항목에 1001, 1002, 1003 의 값을 제공합니다. 이러한 값이 청크 ID가 됩니다.
패치 게임 모드 작업
-
블루프린트 에디터 에서 PatchingGameMode 를 열고 EventGraph 로 이동합니다.
-
Get Game Instance 노드를 생성하고 CDGameInstance 로 캐스트합니다.
-
As CDGameInstance 핀을 드래그한 다음 변수로 승격(Promote to Variable) 을 클릭하여 게임 인스턴스에 대한 레퍼런스를 생성합니다. 새 변수인 Current Game Instance 를 호출합니다.
-
Set Current Game Instance 의 출력 핀을 드래그한 다음 Patch Game 에 대한 호출을 생성합니다.
-
Patch Game 의 값 반환(Return Value) 을 드래그한 다음 변수로 승격(Promote to Variable) 을 클릭하여 값을 저장할 부울을 생성합니다. 새 변수 이름을 Is Patching In Progress 로 지정합니다.
이미지를 클릭하면 확대됩니다.
-
이름이 Try Patch Count 인 인티저 변수를 생성하고 Get Try Patch Count 노드를 그래프 로 드래그합니다.
-
Get Try Patch Count 노드의 출력 핀을 드래그하여 Increament Int 노드를 생성합니다.
-
Is Patching In Progress 의 출력 핀을 드래그하여 Branch 노드를 생성하고, 해당 노드의 False 핀을 Increament Int 노드에 연결합니다.
-
Increament Int 노드의 출력 핀을 드래그하여 또 다른 Branch 노드를 생성하고, 해당 노드의 False 핀을 드래그하여 Delay 노드를 생성합니다.
-
Delay 노드의 Complited 핀을 Patch Game 노드의 입력 핀에 연결합니다.
-
Greater 노드를 생성합니다. 해당 노드의 A Input 핀을 Increament Int 노드의 Result 핀에 연결합니다. Return 입력을 두 번째 Branch 노드의 Condition 핀에 연결합니다.
이미지를 클릭하면 확대됩니다.
-
Tick 이벤트에서 드래그하여 새 Branch 노드를 생성합니다. Is Patching In Progress 를 Condition 입력에 연결합니다.
-
True 핀을 Branch 노드에 드래그한 다음, 다운로드 퍼센트를 표시하는 데 사용할 Print String 노드 및 마운트 퍼센트를 표시하는 데 사용할 Print String 노드를 생성합니다.
-
Get Current Game Instance 노드를 생성한 다음, 출력 핀을 드래그하여 Get Loading Progress 에 대한 호출을 생성합니다.
-
Get Loading Progress 노드의 Download Percent 핀에서 드래그하여 Build String (float) 노드를 생성합니다.
-
Prefix 핀의 텍스트 필드에 Current Loading Progress 를 입력하고, Suffix 핀의 텍스트 필드에 % 를 입력합니다.
-
Get Loading Progress 노드의 Mount Percent 핀에서 드래그하여 Build String (float) 노드를 생성합니다.
-
Prefix 핀의 텍스트 필드에 Current Mount Progress 를 입력하고, Suffix 핀의 텍스트 필드에 % 를 입력합니다.
-
로딩 진행 상황에 대한 Build String (Float) 의 값 반환(Return Value) 을 첫 번째 Print String 노드에 연결합니다.
-
마운트 진행 상황에 대한 Build String (Float) 의 값 반환(Return Value) 을 두 번째 Print String 노드에 연결합니다.
-
Print String 노드에서 Branch 노드를 생성한 다음, AND 노드를 생성하여 Condition 핀에 연결합니다.
-
Greater Equal 노드를 생성하여 Download Percent 가 100.0 이상인지 확인하고 Mount Percent 에 대해 똑같은 작업을 반복합니다. 모두 AND 노드에 연결합니다. 두 가지 조건이 모두 true인 경우 레벨 열기(Open Level) 를 사용하여 PatchingGameTest 레벨을 엽니다.
이미지를 클릭하면 확대됩니다.
게임이 실행되면 Entry 맵이 열리고, ChunkDownloader가 실행되며, 청크 다운로드(Chunk Download) 목록에 청크 다운로드 및 마운트 진행 상황이 표시됩니다. 다운로드가 완료되면 테스트 맵으로 전환됩니다.
에디터에서 플레이(Play In Editor) 를 사용하여 실행하려는 경우 다운로드가 시작되지 않습니다. 패키징된 빌드를 사용하여 ChunkDownloader를 테스트해야 합니다.
5. 다운로드한 콘텐츠 표시
캐릭터 메시를 표시하기 위해 이에 대한 레퍼런스를 가져와야 합니다. 이 섹션에서는 간단한 예시를 통해 액터를 스폰하는 방법을 설명합니다.
-
PatchingDemoTest 레벨을 열고 레벨 블루프린트(Level Blueprint) 를 엽니다.
- Meshes 라는 새 변수를 생성합니다.
- 변수 타입(Variable Type) 에서 스켈레탈 메시(Skeletal Mesh) 를 선택합니다.
- 타입 목록의 엔트리로 커서를 가져가고 오브젝트 레퍼런스(Object Reference) 를 선택합니다.

-
메시(Meshes) 의 변수 타입(Variable Type) 옆에 있는 아이콘을 클릭하고 배열(Array) 로 변경합니다. 블루프린트를 컴파일하여 변경사항을 적용합니다.
-
메시(Meshes) 의 디폴트 값(Default Value) 에서 3개의 항목을 추가하고 Boris, Crunch 및 Khaimera 에 대한 스켈레탈 메시를 선택합니다.
-
EventGraph 의 레벨에서 BeginPlay 이벤트로부터 드래그한 다음 For Each Loop 를 생성하고 Meshes 배열에 연결합니다.
-
For Each Loop 의 Array Element 핀을 드래그한 다음 Is Valid 노드를 생성합니다.
-
Spawn Actor From Class 노드를 생성하여 Is Valid 노드의 Is Valid 핀에 연결합니다. 클래스(Class) 에서 스켈레탈 메시 액터(Skeletal Mesh Actor) 를 선택합니다.
-
For Each Loop 의 배열 인덱스(Array Index) 를 드래그하여 Multiply 노드를 생성합니다. Float 값을 256 으로 설정합니다.
- Multiply 노드를 하나 더 생성합니다. 이전 Multiply 노드의 Return value 핀을 생성된 Multiply 노드 의 B Input Value 핀에 연결합니다. B Input Value 핀을 우클릭하고 변환 대상(Convert to) > 벡터(Vector) 를 선택하여 이 Multiply 노드의 B Input Value 핀을 Vector 로 변환합니다. 벡터에 (1.0, 0.0, 0.0) 값을 부여합니다.
- 이를 통해 For Each Loop 를 거칠 때마다 원점에서 256개 유닛만큼 떨어진 좌표를 만듭니다. 따라서 스폰할 때 각 메시에 어느 정도의 공간이 제공됩니다.
-
이전 단계에서의 벡터를 Make Transform 노드의 위치(Location) 로 사용하고, Spawn Actor 노드의 Spawn Transform 에 값 반환(Return Value) 을 연결합니다.
-
Spawn Actor 노드의 값 반환(Return Value) 을 드래그한 다음 스켈레탈 메시 컴포넌트(Skeletal Mesh Component) 에 대한 레퍼런스를 가져옵니다. 이를 사용하여 Set Skeletal Mesh 를 호출합니다.
-
For Each Loop 노드의 Array Element 핀을 드래그하고 이 노드의 출력을 Set Skeletal Mesh 에 대한 New Mesh 입력 핀에 연결합니다.
이미지를 클릭하면 확대됩니다.
-
레벨 내에 있는 플레이어 스타트(Player Start) 를 (256.0, 800.0, 100.0) 으로 이동합니다.
이미지를 클릭하면 확대됩니다.
- 진행 상황을 저장하고 블루프린트를 컴파일합니다.
레벨이 로드되면 각 캐릭터의 스켈레탈 메시가 스폰됩니다. 오브젝트 레퍼런스가 작동하지 않는 경우 각 캐릭터에 대한 청크가 아직 마운트되지 않았다는 뜻입니다. 따라서 에셋을 사용할 수 없으며, 캐릭터가 스폰되지 않습니다.
6. 게임 테스트
마지막으로 독립형 빌드에서 프로젝트를 테스트해야 합니다. pak 마운트는 PIE 모드에서 작동하지 않으므로 패치 기능을 테스트하는 데 있어 필수 단계입니다.
-
프로젝트를 패키징합니다.
-
패키징 파일 및 매니페스트를 IIS 테스트 웹 사이트 에 있는 해당 폴더에 복사합니다.
-
IIS 프로세스와 웹 사이트 모두가 실행 중이어야 합니다.
-
패키징된 실행파일을 실행합니다.
최종 결과
화면 왼쪽 상단에 패치 출력이 있는 검은색 화면이 표시되고, 패치와 마운트 상태가 100%에 도달하면 게임이 디폴트 맵에 로드되고 Boris, Crunch, Khaimera가 표시될 것입니다. 패치 또는 마운트 프로세스에 문제가 있는 경우 어느 것도 표시되지 않습니다.
직접 해보기
여기에서 몇 가지 단계를 수행하여 청크 다운로드 스키마를 더욱 구체적으로 만들 수 있습니다.
-
로딩 모드 중 표시되는 UI를 빌드하고 플레이어에게 진행률 표시줄과 프롬프트를 표시합니다.
-
타임아웃 및 설치 실패와 같은 오류에 대한 UI 프롬프트를 빌드합니다.
-
PrimaryAssetLabel의 커스텀 서브클래스를 생성하여 에셋에 관한 추가 메타데이터를 포함합니다. 예를 들어 Battle Breakers의 커스텀 PrimaryAssetLabel 클래스에는 현재 청크 사용을 위한 전제 조건으로 로드되어야 하는 Parent Chunk가 포함되어 있습니다.