게임에 ChunkDownloader 구현

Visual Studio 및 블루프린트를 사용하여 프로젝트에 ChunkDownloader를 통합하고 로컬 머신에서 시스템을 테스트하는 방법입니다.

Choose your operating system:

Windows

macOS

Linux

필요한 사전지식

이 페이지의 콘텐츠를 이해하고 활용하기 위해 다음 주제를 숙지해 주세요.

ChunkDownloader언리얼 엔진(UE) 의 패치 솔루션입니다. 원격 서비스로부터 에셋을 다운로드하고 게임에서 사용할 수 있도록 이를 메모리에 마운트하여 손쉽게 업데이트와 에셋을 제공할 수 있습니다. 이 가이드에서는 프로젝트에 ChunkDownloader를 구현하는 방법을 보여줍니다. 이 가이드를 완료하면 다음과 같은 작업을 할 수 있습니다.

  • Visual Studio를 사용하여 ChunkDownloader를 초기화 및 종료합니다.

  • Visual Studio를 사용하여 호스트 웹 사이트에서 패키징 파일을 다운로드합니다.

  • UE에서 ChunkDownloader를 실행하기 위해 게임 모드 블루프린트 를 구성합니다.

  • 레벨 에디터 뷰포트 또는 게임 내에서 다운로드한 콘텐츠를 표시합니다.

  • 마운트된 패키징 파일의 콘텐츠에 안전하게 액세스합니다.

  • UE 프로젝트에서 조정된 시스템을 로컬 머신에서 테스트합니다.

1. 필수 설정 및 권장 에셋

계속 진행하기 전에 다음 가이드를 검토하고 각각의 단계를 따라야 합니다.

레퍼런스 가이드에 설명된 대로 다음 단계를 따라야 합니다.

  1. 기본 템플릿(Blank template) 을 기반으로 하는 C++ 프로젝트 를 생성합니다. 이 프로젝트의 이름을 PatchingDemo 로 설정합니다.

  2. 플러그인(Plugins) 메뉴에서 ChunkDownloader 플러그인을 활성화합니다.

  3. 프로젝트 세팅(Project Settings) > 프로젝트(Project) > 패키징(Packaging) 에서 Pak 파일 사용(Use Pak File)청크 생성(Generate Chunks) 을 활성화합니다.

  4. Visual Studio 에서 프로젝트의 [프로젝트 이름]Build.cs 파일을 편집합니다.

  5. Visual Studio 프로젝트 파일을 생성합니다.

  6. Visual Studio에서 프로젝트를 빌드합니다.

  7. 이 프로젝트에 ParagonBoris, Crunch, Khaimera 에셋을 추가합니다.

  8. 추가된 에셋마다 프라이머리 에셋 라벨 을 기준으로 데이터 에셋 을 조정합니다.

  9. 프로젝트를 쿠킹 또는 패키징하고 빌드 폴더에 패키징 파일을 배치합니다.

  10. 로컬 호스팅 웹 사이트에 패키징 파일을 배포합니다.

  11. BuildManifest-Windows.txt 라는 매니페스트 파일을 생성합니다.

  12. 프로젝트에 대한 DefaultGame.ini 파일을 정의합니다.

2. ChunkDownloader 초기화 및 종료

ChunkDownloader는 FPlatformChunkInstall 인터페이스의 구현이고, 호환되는 여러 인터페이스 중 하나에서 게임이 실행 중인 플랫폼에 따라 각기 다른 모듈을 로드할 수 있습니다. 모든 모듈은 사용 전에 로드 및 초기화해야 하고, 종료 및 정리해야 합니다.

ChunkDownloader에서 이를 수행하는 가장 간단한 방법은 커스텀 GameInstance 클래스를 사용하는 것입니다. GameInstance에는 연결할 수 있는 적절한 초기화 및 종료 함수가 있을 뿐만 아니라 게임이 실행 중인 동안 ChunkDownloader에 대한 지속적인 액세스도 가능합니다. 다음 단계는 이 구현 과정을 안내합니다.

GameInstance 를 베이스 클래스로 사용하여 새 C++ 클래스 를 생성합니다. 이름은 PatchingDemoGameInstance 로 지정합니다.

이미지를 클릭하면 확대됩니다.

컴파일 프로세스가 완료되면 Visual Studio에서 PatchingDemoGameInstance.hPatchingDemoGameInstance.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()
};
  1. 스트링 class UPatchingDemoGameInstance : public UGameInstance 를 다음과 같이 변경합니다.

    PatchingDemoGameInstance.h

    class PATCHINGDEMO_API UPatchingDemoGameInstance : public UGameInstance

    PatchingDemoGameInstance.h 파일에서 선언할 모든 후속 변수, 함수 및 프로퍼티는 UPatchingDemoGameInstance 클래스 아래에 추가해야 합니다.

  2. public 헤더 아래에서 다음과 같은 함수 오버라이드를 선언합니다.

    PatchingDemoGameInstance.h

    public:
    // 오버라이드
        virtual void Init() override;
        virtual void Shutdown() override;

    Init 함수는 게임이 시작될 때 실행되므로 ChunkDownloader를 초기화할 수 있는 최적의 위치가 됩니다. 마찬가지로 Shutdown 함수는 게임이 중지될 때 실행되므로 이를 사용하여 ChunkDownloader 모듈을 종료할 수 있습니다.

  3. protected 헤더 아래에서 다음과 같은 변수를 선언합니다.

    PatchingDemoGameInstance.h

    protected:
    //로컬 매니페스트 파일이 웹사이트에 호스팅된 파일과 같은 최신 업데이트 상태인지 여부를 트래킹합니다.
    bool bIsDownloadManifestUpToDate;
  4. protected 헤더에서 다음 함수를 선언합니다.

    PatchingDemoGameInstance.h

    protected:
    // 청크 다운로드 프로세스가 완료되면 호출됩니다.
    void OnManifestUpdateComplete(bool bSuccess);

PatchingDemoGameInstance.cpp 작업

  1. PatchingDemoGameInstance.cpp 를 엽니다. #include "PatchingDemoGameInstance.h" 에 있는 파일 맨 위에 다음 #includes 를 추가합니다.

    PatchingDemoGameInstance.cpp

    #include "PatchingDemoGameInstance.h"
    
    #include "ChunkDownloader.h"
    #include "Misc/CoreDelegates.h"
    #include "AssetRegistryModule.h"

    이를 통해 ChunkDownloader와 에셋 및 델리게이트 관리에 유용한 몇 가지 툴에 액세스할 수 있습니다.

  2. 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. 함수는 DeploymentNameContentBuildID 를 정의하여 DefaultGame.ini 에서 사용되는 값을 일치시킵니다. 이 값은 현재 테스트를 위해 고정된 값이지만 전체 빌드에서는 HTTP 요청을 사용하여 ContentBuildID 를 가져옵니다. 함수는 이 변수의 정보를 사용하여 웹 사이트에 매니페스트를 요청합니다.

    2. 함수는 FChunkDownloader::GetOrCreate 를 호출하여 ChunkDownloader를 설정하고 이에 대한 레퍼런스를 가져온 뒤, TSharedRef 에 저장합니다. 비슷한 플랫폼 인터페이스에 대한 레퍼런스를 가져오는 데 있어 선호되는 방법입니다.

    3. 함수는 원하는 플랫폼 이름, 이 경우에는 Windows를 사용하여 FChunkDownloader::Initialize 를 호출합니다. 이 예시에서는 TargetDownloadsInFlight에 8 의 값을 제공하고, 이는 ChunkDownloader가 한 번에 처리하는 최대 다운로드 수를 설정합니다.

    4. 함수는 DeploymentName 을 사용하여 FChunkDownloader::LoadCachedBuild 를 호출합니다. 디스크에 이미 다운로드되어 있는 파일이 있는지 확인하고, 이를 통해 ChunkDownloader가 최신 매니페스트 파일로 업데이트된 경우 두 번째 다운로드를 건너뛸 수 있습니다.

    5. 함수는 FChunkDownloader::UpdateBuild 를 호출하여 매니페스트 파일의 업데이트된 버전을 다운로드합니다.

      • 이를 통해 완전히 새로운 실행 파일 없이도 시스템에서 패치 업데이트를 지원합니다.

      • UpdateBuild 는 작업의 성공 여부를 출력하는 콜백과 함께 DeploymentNameContentBuildID 를 가져옵니다.

      • 또한 OnManifestUpdateComplete 를 사용하여 bIsDownloadManifestUpToDate 를 설정하고, GameInstance는 이 패치 페이즈가 완료되는지 전역으로 인식할 수 있습니다.

    이 단계를 따르면 ChunkDownloader가 초기화되고 콘텐츠 다운로드를 시작할 준비가 되며, 다른 함수에 매니페스트의 상태를 알립니다.

  3. Shutdown 함수에 대해 다음 구현을 생성합니다.

    PatchingDemoGameInstance.cpp

    void UPatchingDemoGameInstance::Shutdown()
    {
        Super::Shutdown();
        // 청크 다운로더를 종료합니다
        FChunkDownloader::Shutdown();
    }

    FChunkDownloader::Shutdown 을 호출하면 ChunkDownloader에서 현재 진행 중인 모든 다운로드를 중지하고, 모듈을 정리한 다음 언로드합니다.

  4. OnManifestUpdateComplete 함수에 대해 다음 구현을 생성합니다.

    PatchingDemoGameInstance.cpp

    void UPatchingDemoGameInstance::OnManifestUpdateComplete(bool bSuccess)
    {
        bIsDownloadManifestUpToDate = bSuccess;
    }

    이 함수는 매니페스트 업데이트가 완료될 때 비동기 콜백으로 사용됩니다.

3. 패키징 파일 다운로드

이제 ChunkDownloader에 대한 적절한 초기화 및 종료 함수가 있으니 패키징 파일 다운로드를 위한 함수 기능을 노출시킬 수 있습니다.

PatchingDemoGameInstance.h 작업

  1. PatchingDemoGameInstance.h#includes 아래에서 다음 다이내믹 멀티캐스트 델리게이트를 추가합니다.

    PatchingDemoGameInstance.h

    DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FPatchCompleteDelegate, bool, Succeeded);

    이 델리게이트는 패치 다운로드 작업이 성공했는지 여부를 알리는 boolean을 출력합니다. 델리게이트는 일반적으로 파일 다운로드 또는 설치와 같은 비동기 작업에 응답하는 데 사용됩니다.

  2. 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;
  3. public 헤더 아래에 다음과 같은 델리게이트 선언을 추가합니다.

    PatchingDemoGameInstance.h

    public:
        // 델리게이트
        // 패치 프로세스가 성공 또는 실패하면 발생합니다.
        UPROPERTY(BlueprintAssignable, Category="Patching");
        FPatchCompleteDelegate OnPatchComplete;

    이를 통해 패치 작업이 완료될 때 블루프린트로 후킹할 수 있는 위치가 제공됩니다.

  4. protected 헤더 아래에 ChunkDownloadList 에 대한 다음과 같은 선언을 추가합니다.

    PatchingDemoGameInstance.h

    protected:
        // 시도 및 다운로드할 청크 ID 목록
        UPROPERTY(EditDefaultsOnly, Category="Patching")
        TArray<int32> ChunkDownloadList;

    이 목록을 사용하여 나중에 다운로드할 모든 청크 ID를 보관합니다. 개발 세팅에서는 필요에 따라 에셋 목록을 사용하여 이를 초기화하지만, 테스트 목적으로는 블루프린트 에디터 를 사용하여 단순히 디폴트를 노출시켜 채울 수 있도록 합니다.

  5. public 헤더 아래에 PatchGame 에 대한 다음과 같은 선언을 추가합니다.

    PatchingDemoGameInstance.h

    public:
        // 게임 패치 프로세스를 시작합니다. 패치 매니페스트가 최신 상태가 아닌 경우 false를 반환합니다. */
        UFUNCTION(BlueprintCallable, Category = "Patching")
        bool PatchGame();

    이 함수는 패치 프로세스 시작을 위해 블루프린트가 노출된 방법을 제공합니다. 성공 또는 실패 여부를 나타내는 boolean을 반환합니다. 다운로드 관리와 다른 종류의 비동기 작업에 있어 일반적인 패턴입니다.

  6. protected 헤더 아래에 다음과 같은 함수 선언을 추가합니다.

    PatchingDemoGameInstance.h

    protected:
        // 청크 다운로드 프로세스가 완료되면 호출됩니다.
        void OnDownloadComplete(bool bSuccess);
    
        // ChunkDownloader의 로딩 모드가 완료될 때마다 호출됩니다.
        void OnLoadingModeComplete(bool bSuccess);
    
        // ChunkDownloader가 청크 마운트를 완료하면 호출됩니다.
        void OnMountComplete(bool bSuccess);

    이를 사용하여 다운로드 프로세스에서 비동기 콜백에 응답합니다.

PatchingDemoGameInstance.cpp 작업

  1. 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;
    }
  2. 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를 반환하여 패치 시작에 실패했음을 나타냅니다.

    2. 다음으로 패치 프로세스가 계속될 수 있다면 함수는 ChunkDownloader에 대한 레퍼런스를 가져옵니다. 이후 다운로드 목록을 반복하고 각 청크의 상태를 확인합니다.

    3. 2개의 콜백이 정의됩니다.

      • 개별 청크의 다운로드가 완료되면 DownloadCompleteCallback 이 호출됩니다. 각 청크가 다운로드에 성공 또는 실패할 때마다 메시지가 출력됩니다.

      • 모든 청크가 다운로드되면 LoadingModeCompleteCallback 이 발생합니다.

    4. 함수는 FChunkDownloader::DownloadChunks 를 호출하여 원하는 청크 다운로드를 시작합니다. 청크는 ChunkDownloadList 에 나열되어 있습니다. 이 목록은 함수 호출 전에 원하는 청크 ID로 채워져 있어야 합니다. 또한 DownloadCompleteCallback 을 전달합니다.

    5. 함수는 앞서 정의한 콜백과 함께 FChunkDownloader::BeginLoadingMode 를 호출합니다.

      • Loading Mode는 ChunkDownloader에 다운로드 상태 모니터링을 시작하도록 지시합니다.

      • 청크는 Loading Mode 호출 없이 백그라운드에서 수동으로 다운로드할 수 있지만 이를 사용하면 다운로드 통계가 출력되어 사용자가 다운로드 진행 상황을 추적할 수 있는 UI를 만들 수 있습니다.

      • 콜백 함수를 사용하면 전체 청크 배치가 다운로드될 때 특정 함수 기능을 실행할 수도 있습니다.

  3. OnDownloadCompleteOnLoadingModeBegin 함수에 대해 다음과 같은 구현을 생성합니다.

    PatchingDemoGameInstance.cpp

    void UPatchingDemoGameInstance::OnLoadingModeComplete(bool bSuccess)
    {
        OnDownloadComplete(bSuccess);
    }
    
    void UPatchingDemoGameInstance::OnMountComplete(bool bSuccess)
    {
        OnPatchComplete.Broadcast(bSuccess);
    }

    OnLoadingModeCompleteOnDownloadComplete 로 패스스루하고, 이후 단계에서 청크를 마운트합니다. OnMountComplete 는 모든 청크의 마운팅이 완료되고, 콘텐츠를 사용할 준비가 되었음을 나타냅니다.

  4. 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에 대한 레퍼런스를 가져옵니다.

    2. 함수는 Json 배열을 설정하고 ChunkDownloadList 의 정보로 채웁니다. 이 정보는 요청을 수행할 때 사용됩니다.

    3. 함수는 MountCompleteCallback 을 사용하여 패치가 성공적으로 적용되었는지 여부를 출력합니다.

    4. 함수는 Json 목록과 MountCompleteCallback 을 사용하여 ChunkDownloader::MountChunks 를 호출하고 다운로드한 청크의 마운트를 시작합니다.

    5. 다운로드가 성공한 경우 함수는 OnPatchComplete 델리게이트를 true 값으로 활성화합니다. 성공하지 않은 경우 false 값으로 활성화합니다. UE_LOG 는 실패 지점에 따라 오류 메시지를 출력합니다.

4. Patching Game Mode 설정

패치 프로세스를 초기화하기 위해 레벨게임 모드 를 만들어 PatchGame 을 호출하고 화면에 패치 통계를 출력할 수 있습니다.

  1. 언리얼 에디터에서 콘텐츠 브라우저(Content Browser) 에 새로운 Blueprints 폴더를 생성합니다. 그런 다음 PatchingDemoGameInstance 를 베이스 클래스로 사용하여 새 블루프린트 를 생성합니다.

    ![](02_CDGameInstanceBPCreate.png)

    새 블루프린트 클래스 이름을 CDGameInstance 로 지정합니다.

    ![](03_CDGameInstance.png)

    세팅을 편집하고 청크 다운로드 프로세스를 추적하기 위해 더욱 액세스하기 쉬운 방법으로 이 블루프린트를 사용합니다.

  2. PatchingGameMode 라는 새 게임 모드 블루프린트를 생성합니다.

    ![](04_PatchingGameMode.png)

  3. Maps 폴더를 생성하고 이름이 PatchingDemoEntryPatchingDemoTest 인 2개의 새 레벨을 생성합니다. PatchingDemoEntry 레벨은 빈 맵을 기반으로 해야 하며, PatchingDemoTest 레벨은 Default 맵을 기반으로 해야 합니다.

    ![](05_PatchingMaps.png)

  4. 프로젝트 세팅(Project Settings) 을 열고 프로젝트(Project) > 맵 & 모드(Maps & Modes) 로 이동합니다. 다음과 같은 파라미터를 설정합니다.

    이미지를 클릭하면 확대됩니다.

    ID

    파라미터

    1

    게임 인스턴스 클래스

    CDGameInstance

    2

    에디터 시작 맵

    PatchingDemoTest

    3

    게임 기본 맵

    PatchingDemoEntry

  5. 블루프린트 에디터 에서 CDGameInstance 를 엽니다. 디폴트(Defaults) 패널에서 청크 다운로드 목록(Chunk Download List) 에 3개의 항목을 추가합니다. 항목에 1001, 1002, 1003 의 값을 제공합니다. 이러한 값이 청크 ID가 됩니다.

    ![](08_ChunkDownloadList.png)

패치 게임 모드 작업

  1. 블루프린트 에디터 에서 PatchingGameMode 를 열고 EventGraph 로 이동합니다.

  2. Get Game Instance 노드를 생성하고 CDGameInstance 로 캐스트합니다.

  3. As CDGameInstance 핀을 드래그한 다음 변수로 승격(Promote to Variable) 을 클릭하여 게임 인스턴스에 대한 레퍼런스를 생성합니다. 새 변수인 Current Game Instance 를 호출합니다.

  4. Set Current Game Instance 의 출력 핀을 드래그한 다음 Patch Game 에 대한 호출을 생성합니다.

  5. Patch Game값 반환(Return Value) 을 드래그한 다음 변수로 승격(Promote to Variable) 을 클릭하여 값을 저장할 부울을 생성합니다. 새 변수 이름을 Is Patching In Progress 로 지정합니다.

    이미지를 클릭하면 확대됩니다.

  6. 이름이 Try Patch Count 인 인티저 변수를 생성하고 Get Try Patch Count 노드를 그래프 로 드래그합니다.

  7. Get Try Patch Count 노드의 출력 핀을 드래그하여 Increament Int 노드를 생성합니다.

  8. Is Patching In Progress 의 출력 핀을 드래그하여 Branch 노드를 생성하고, 해당 노드의 False 핀을 Increament Int 노드에 연결합니다.

  9. Increament Int 노드의 출력 핀을 드래그하여 또 다른 Branch 노드를 생성하고, 해당 노드의 False 핀을 드래그하여 Delay 노드를 생성합니다.

  10. Delay 노드의 Complited 핀을 Patch Game 노드의 입력 핀에 연결합니다.

  11. Greater 노드를 생성합니다. 해당 노드의 A Input 핀을 Increament Int 노드의 Result 핀에 연결합니다. Return 입력을 두 번째 Branch 노드의 Condition 핀에 연결합니다.

    이미지를 클릭하면 확대됩니다.

  12. Tick 이벤트에서 드래그하여 새 Branch 노드를 생성합니다. Is Patching In ProgressCondition 입력에 연결합니다.

  13. True 핀을 Branch 노드에 드래그한 다음, 다운로드 퍼센트를 표시하는 데 사용할 Print String 노드 및 마운트 퍼센트를 표시하는 데 사용할 Print String 노드를 생성합니다.

  14. Get Current Game Instance 노드를 생성한 다음, 출력 핀을 드래그하여 Get Loading Progress 에 대한 호출을 생성합니다.

  15. Get Loading Progress 노드의 Download Percent 핀에서 드래그하여 Build String (float) 노드를 생성합니다.

  16. Prefix 핀의 텍스트 필드에 Current Loading Progress 를 입력하고, Suffix 핀의 텍스트 필드에 % 를 입력합니다.

  17. Get Loading Progress 노드의 Mount Percent 핀에서 드래그하여 Build String (float) 노드를 생성합니다.

  18. Prefix 핀의 텍스트 필드에 Current Mount Progress 를 입력하고, Suffix 핀의 텍스트 필드에 % 를 입력합니다.

  19. 로딩 진행 상황에 대한 Build String (Float)값 반환(Return Value) 을 첫 번째 Print String 노드에 연결합니다.

  20. 마운트 진행 상황에 대한 Build String (Float)값 반환(Return Value) 을 두 번째 Print String 노드에 연결합니다.

  21. Print String 노드에서 Branch 노드를 생성한 다음, AND 노드를 생성하여 Condition 핀에 연결합니다.

  22. Greater Equal 노드를 생성하여 Download Percent100.0 이상인지 확인하고 Mount Percent 에 대해 똑같은 작업을 반복합니다. 모두 AND 노드에 연결합니다. 두 가지 조건이 모두 true인 경우 레벨 열기(Open Level) 를 사용하여 PatchingGameTest 레벨을 엽니다.

    이미지를 클릭하면 확대됩니다.

게임이 실행되면 Entry 맵이 열리고, ChunkDownloader가 실행되며, 청크 다운로드(Chunk Download) 목록에 청크 다운로드 및 마운트 진행 상황이 표시됩니다. 다운로드가 완료되면 테스트 맵으로 전환됩니다.

에디터에서 플레이(Play In Editor) 를 사용하여 실행하려는 경우 다운로드가 시작되지 않습니다. 패키징된 빌드를 사용하여 ChunkDownloader를 테스트해야 합니다.

5. 다운로드한 콘텐츠 표시

캐릭터 메시를 표시하기 위해 이에 대한 레퍼런스를 가져와야 합니다. 이 섹션에서는 간단한 예시를 통해 액터를 스폰하는 방법을 설명합니다.

  1. PatchingDemoTest 레벨을 열고 레벨 블루프린트(Level Blueprint) 를 엽니다.

  2. Meshes 라는 새 변수를 생성합니다.

    • 변수 타입(Variable Type) 에서 스켈레탈 메시(Skeletal Mesh) 를 선택합니다.

    • 타입 목록의 엔트리로 커서를 가져가고 오브젝트 레퍼런스(Object Reference) 를 선택합니다.

    ![](12_SkeletalMeshObjectRef.png)

  3. 메시(Meshes)변수 타입(Variable Type) 옆에 있는 아이콘을 클릭하고 배열(Array) 로 변경합니다. 블루프린트를 컴파일하여 변경사항을 적용합니다.

    ![](13_ObjectArray.png)

  4. 메시(Meshes)디폴트 값(Default Value) 에서 3개의 항목을 추가하고 Boris, CrunchKhaimera 에 대한 스켈레탈 메시를 선택합니다.

    ![](14_ObjectDefaultValues.png)

  5. EventGraph 의 레벨에서 BeginPlay 이벤트로부터 드래그한 다음 For Each Loop 를 생성하고 Meshes 배열에 연결합니다.

  6. For Each LoopArray Element 핀을 드래그한 다음 Is Valid 노드를 생성합니다.

  7. Spawn Actor From Class 노드를 생성하여 Is Valid 노드의 Is Valid 핀에 연결합니다. 클래스(Class) 에서 스켈레탈 메시 액터(Skeletal Mesh Actor) 를 선택합니다.

  8. For Each Loop배열 인덱스(Array Index) 를 드래그하여 Multiply 노드를 생성합니다. Float 값을 256 으로 설정합니다.

  9. 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개 유닛만큼 떨어진 좌표를 만듭니다. 따라서 스폰할 때 각 메시에 어느 정도의 공간이 제공됩니다.

  10. 이전 단계에서의 벡터를 Make Transform 노드의 위치(Location) 로 사용하고, Spawn Actor 노드의 Spawn Transform값 반환(Return Value) 을 연결합니다.

  11. Spawn Actor 노드의 값 반환(Return Value) 을 드래그한 다음 스켈레탈 메시 컴포넌트(Skeletal Mesh Component) 에 대한 레퍼런스를 가져옵니다. 이를 사용하여 Set Skeletal Mesh 를 호출합니다.

  12. For Each Loop 노드의 Array Element 핀을 드래그하고 이 노드의 출력을 Set Skeletal Mesh 에 대한 New Mesh 입력 핀에 연결합니다.

    이미지를 클릭하면 확대됩니다.

  13. 레벨 내에 있는 플레이어 스타트(Player Start)(256.0, 800.0, 100.0) 으로 이동합니다.

    이미지를 클릭하면 확대됩니다.

  14. 진행 상황을 저장하고 블루프린트를 컴파일합니다.

레벨이 로드되면 각 캐릭터의 스켈레탈 메시가 스폰됩니다. 오브젝트 레퍼런스가 작동하지 않는 경우 각 캐릭터에 대한 청크가 아직 마운트되지 않았다는 뜻입니다. 따라서 에셋을 사용할 수 없으며, 캐릭터가 스폰되지 않습니다.

![](17_CharactersSpawned.png)

6. 게임 테스트

마지막으로 독립형 빌드에서 프로젝트를 테스트해야 합니다. pak 마운트는 PIE 모드에서 작동하지 않으므로 패치 기능을 테스트하는 데 있어 필수 단계입니다.

  1. 프로젝트를 패키징합니다.

  2. 패키징 파일 및 매니페스트를 IIS 테스트 웹 사이트 에 있는 해당 폴더에 복사합니다.

  3. IIS 프로세스와 웹 사이트 모두가 실행 중이어야 합니다.

  4. 패키징된 실행파일을 실행합니다.

최종 결과

화면 왼쪽 상단에 패치 출력이 있는 검은색 화면이 표시되고, 패치와 마운트 상태가 100%에 도달하면 게임이 디폴트 맵에 로드되고 Boris, Crunch, Khaimera가 표시될 것입니다. 패치 또는 마운트 프로세스에 문제가 있는 경우 어느 것도 표시되지 않습니다.

직접 해보기

여기에서 몇 가지 단계를 수행하여 청크 다운로드 스키마를 더욱 구체적으로 만들 수 있습니다.

  • 로딩 모드 중 표시되는 UI를 빌드하고 플레이어에게 진행률 표시줄과 프롬프트를 표시합니다.

  • 타임아웃 및 설치 실패와 같은 오류에 대한 UI 프롬프트를 빌드합니다.

  • PrimaryAssetLabel의 커스텀 서브클래스를 생성하여 에셋에 관한 추가 메타데이터를 포함합니다. 예를 들어 Battle Breakers의 커스텀 PrimaryAssetLabel 클래스에는 현재 청크 사용을 위한 전제 조건으로 로드되어야 하는 Parent Chunk가 포함되어 있습니다.