UE5分包挂载dlc

1、将需要分包挂载的资产整理到单独的插件下(方便好管理)

2、用 Primary Asset Label 标记 DLC 资产

1)开启分块功能:打开 Project Settings → Packaging,勾选 Use Pak File 和 Generate Chunks

image

 

2)创建 Primary Asset Label:在你的 DLC 插件的 Content 目录下,右键 → Miscellaneous → Data Asset → 选择 PrimaryAssetLabel 作为基类

image

 

3)配置 Label:双击打开这个新创建的 Data Asset,按以下设置

image

 4)有时打包后不能打出分块数据,按下面顺序依次尝试

      a)PrimaryAssetLabel 里手动引用一个插件的数据,让系统找到数据

image

   b)由于地图关卡地图(Map)本身也是一种 PrimaryAsset,它有自己的 ChunkID,会覆盖 PrimaryAssetLabel 的分配,必须通过 ini 配置来指定

DefaultGame.ini里增加类似如下代码

[/Script/Engine.AssetManagerSettings]
+PrimaryAssetRules=(PrimaryAssetId="Map:/TVRCharactor/Maps/testMap1",Rules=(Priority=-1,ChunkId=1001,CookRule=AlwaysCook))

c)检查PrimaryAssetLabel 是否被 AssetManager 扫描到

image

 在此处加上插件目录

3、正常打包项目

直接像平时打包基础游戏一样,用 RunUAT 或 Project Launcher 进行打包即可。打包结束后,可以看见主包和分包:

image

 4、运行时加载

分块打包生成的 pakchunk1001 默认不会被游戏自动加载。你需要在游戏启动时,用代码主动去挂载它。

官方提供的 PakDemo 示例项目展示了完整的运行时加载方案,核心逻辑是调用

主要代码在BFL_Pak中

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "BFL_Pak.generated.h"


UCLASS()
class TVRSIMDRILLLITE_API UBFL_Pak : public UBlueprintFunctionLibrary
{
    GENERATED_BODY()

public:

    UFUNCTION(BlueprintCallable, Category = "PAK")
    static void MountAndRegisterPak(FString PakFilePath,bool& bIsMountSuccessful);

    UFUNCTION(BlueprintCallable, Category = "PAK")
    static bool MountPakFile(const FString& PakFilePath, const FString& PakMountPoint);

    UFUNCTION(BlueprintCallable, Category = "PAK")
    static bool UnmountPakFile(const FString& PakFilePath);

    UFUNCTION(BlueprintCallable, Category = "PAK")
    static void RegisterMountPoint(const FString& RootPath, const FString& ContentPath);

    UFUNCTION(BlueprintCallable, Category = "PAK")
    static void UnRegisterMountPoint(const FString& RootPath, const FString& ContentPath);

    UFUNCTION(BlueprintCallable,BlueprintPure, Category = "PAK")
    static FString const GetPakMountPoint(const FString& PakFilePath);

    UFUNCTION(BlueprintCallable,BlueprintPure, Category = "PAK")
    static TArray<FString> GetPakContent(const FString& PakFilePath, bool bOnlyCooked = true);

    UFUNCTION(BlueprintCallable,BlueprintPure, Category = "PAK")
    static FString GetPakMountContentPath(const FString& PakFilePath);

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "PAK")
    static UClass* LoadPakObjClassReference(FString PakContentPath);

    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "PAK")
    static UClass* LoadPakFileClass(const FString& FileName);
   
    UFUNCTION(BlueprintCallable, BlueprintPure, Category = "PAK")
    static FString Conv_PakContentPathToReferenceString(const FString PakContentPath, const FString PakMountPath);
};
 
 
// Fill out your copyright notice in the Description page of Project Settings.


#include "BFL_Pak.h"
#include "IPlatformFilePak.h"

bool UBFL_Pak::MountPakFile(const FString& PakFilePath, const FString& PakMountPoint)
{
    int32 PakOrder = 0;
    bool bIsMounted = false;

    //Check to see if running in editor
    #if WITH_EDITOR
    return bIsMounted;
    #endif


    FString InputPath = PakFilePath;
    FPaths::MakePlatformFilename(InputPath);


    FPakPlatformFile* PakFileMgr = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")));
    if (PakFileMgr == nullptr)
    {
        UE_LOG(LogTemp, Warning, TEXT("Unable to get PakPlatformFile for pak file (mount): %s"), *(PakFilePath));
        return false;
    }
    if (!PakMountPoint.IsEmpty())
    {
        bIsMounted = PakFileMgr->Mount(*InputPath, PakOrder, *PakMountPoint);
    }
    else
    {
        bIsMounted = PakFileMgr->Mount(*InputPath, PakOrder);
    }
    return bIsMounted;
}

bool UBFL_Pak::UnmountPakFile(const FString& PakFilePath)
{
    FPakPlatformFile* PakFileMgr = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")));
    if (PakFileMgr == nullptr)
    {
        UE_LOG(LogTemp, Warning, TEXT("Unable to get PakPlatformFile for pak file (Unmount): %s"), *(PakFilePath));
        return false;
    }
    return PakFileMgr->Unmount(*PakFilePath);
}

void UBFL_Pak::RegisterMountPoint(const FString& RootPath, const FString& ContentPath)
{
    FPackageName::RegisterMountPoint(RootPath, ContentPath);
}

void UBFL_Pak::UnRegisterMountPoint(const FString& RootPath, const FString& ContentPath)
{
    FPackageName::UnRegisterMountPoint(RootPath, ContentPath);
}

FString const UBFL_Pak::GetPakMountPoint(const FString& PakFilePath)
{
    FPakFile* Pak = nullptr;
    TRefCountPtr<FPakFile> PakFile = new FPakFile(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")), *PakFilePath, false);
    Pak = PakFile.GetReference();
    if (Pak->IsValid())
    {
        return Pak->GetMountPoint();
    }
    return FString();
}

TArray<FString> UBFL_Pak::GetPakContent(const FString& PakFilePath, bool bOnlyCooked /*= true*/)
{
    FPakFile* Pak = nullptr;
    TRefCountPtr<FPakFile> PakFile = new FPakFile(FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")), *PakFilePath, false);
    Pak = PakFile.GetReference();
    TArray<FString> PakContent;

    if (Pak->IsValid())
    {
        FString ContentPath, PakAppendPath;
        FString MountPoint = GetPakMountPoint(PakFilePath);
        MountPoint.Split("/Content/", &ContentPath, &PakAppendPath);


        TArray<FPakFile::FFilenameIterator> Records;
        for (FPakFile::FFilenameIterator It(*Pak, false); It; ++It)
        {
            Records.Add(It);
        }

        for (auto& It : Records)
        {
            if (bOnlyCooked)
            {
                if (FPaths::GetExtension(It.Filename()) == TEXT("uasset"))
                {
                    PakContent.Add(FString::Printf(TEXT("%s%s"), *PakAppendPath, *It.Filename()));
                }
            }
            else
            {
                PakContent.Add(FString::Printf(TEXT("%s%s"), *PakAppendPath, *It.Filename()));
            }
        }
    }
    return PakContent;
}

FString UBFL_Pak::GetPakMountContentPath(const FString& PakFilePath)
{
    FString ContentPath, RightStr;
    bool bIsContent;
    FString MountPoint = GetPakMountPoint(PakFilePath);
    bIsContent = MountPoint.Split("/Content/", &ContentPath, &RightStr);
    if (bIsContent)
    {
        return FString::Printf(TEXT("%s/Content/"), *ContentPath);
    }
    // Check Pak Content for /Content/ Path
    else
    {
        TArray<FString> Content = GetPakContent(PakFilePath);
        if (Content.Num() > 0)
        {
            FString FullPath = FString::Printf(TEXT("%s%s"), *MountPoint, *Content[0]);
            bIsContent = FullPath.Split("/Content/", &ContentPath, &RightStr);
            if (bIsContent)
            {
                return FString::Printf(TEXT("%s/Content/"), *ContentPath);
            }
        }
    }
    //Failed to Find Content
    return FString("");
}

void UBFL_Pak::MountAndRegisterPak(FString PakFilePath, bool& bIsMountSuccessful)
{
    FString PakRootPath = "/Game/";
    if (!PakFilePath.IsEmpty())
    {
        if (MountPakFile(PakFilePath, FString()))
        {
            bIsMountSuccessful = true;
            const FString MountPoint = GetPakMountContentPath(PakFilePath);
            RegisterMountPoint(PakRootPath, MountPoint);
        }
    }
}

UClass* UBFL_Pak::LoadPakObjClassReference(FString PakContentPath)
{
    FString PakRootPath = "/Game/";
    const FString FileName = Conv_PakContentPathToReferenceString(PakContentPath, PakRootPath);
    return LoadPakFileClass(FileName);
}

UClass* UBFL_Pak::LoadPakFileClass(const FString& FileName)
{
    const FString Name = FileName + TEXT(".") + FPackageName::GetShortName(FileName) + TEXT("_C");
    return StaticLoadClass(UObject::StaticClass(), nullptr, *Name);
}

FString UBFL_Pak::Conv_PakContentPathToReferenceString(const FString PakContentPath, const FString PakMountPath)
{
    return FString::Printf(TEXT("%s%s.%s"),
        *PakMountPath, *FPaths::GetBaseFilename(PakContentPath, false), *FPaths::GetBaseFilename(PakContentPath, true));
}
View Code
在蓝图中执行挂载即可

image

 

posted @ 2026-09-21 11:08  小手一拿  阅读(34)  评论(0)    收藏  举报