UE4 LoadPackageAsync

虛幻4版本:4.15

先說說最關鍵的函數LoadPackageAsync  

加載路徑 TEXT("/你的插件名字/xx“)

官網文檔是[COREUOBJECT_API](API\Runtime\CoreUObject\UObject\COREUOBJECT_API_3)int32 LoadPackageAsync
(
    const FString & InName,
    FLoadPackageAsyncDelegate InCompletionDelegate,
    TAsyncLoadPriority InPackagePriority,
    EPackageFlags InPackageFlags,
    int32 InPIEInstanceID
)

如果是直接將地圖打包進程序,這個函數還是很簡單好用的

LoadPackageAsync(TEXT(/Game/xx), FLoadPackageAsyncDelegate::CreateLambda([&](const FName& PackageName, UPackage* LoadedPackage, EAsyncLoadingResult::Type Result) {}),0,PKG_ContainsMap);

但問題就在第一個參數上,如果是加載Dlc的形式,讀取其他pak的話,這玩意填的路徑簡直逼死強迫症。需要的是TEXT("/你的插件名字/xx“)

(1)先獲取Pak的路徑

TArray<FString> GetAllFilesInDirector(const FString directory,const FString onlyFilesStartingWith,const FString extension){

    FString Directory1 =FPaths::GameDir()+ directory;

    TArray<FString> directoriesToSkip;

    IPlatformFile &PlatformFile =FPlatformFileManager::Get().GetPlatformFile();

    FLocalTimestampDirectoryVisitor Visitor(PlatformFile, directoriesToSkip, directoriesToSkip,false);

    PlatformFile.IterateDirectory(*Directory1, Visitor);

    TArray<FString> files;

    for (TMap<FString,FDateTime>::TIterator TimestampIt(Visitor.FileTimes); TimestampIt; ++TimestampIt)

  {

    const FString filePath = TimestampIt.Key();

    const FString fileName = FPaths::GetCleanFilename(filePath);

    const FString fileBaseName = FPaths::GetBaseFilename(filePath);

    bool shouldAddFile =true;

 

    if (!onlyFilesStartingWith.IsEmpty())

   {

     const FString left = fileName.Left(onlyFilesStartingWith.Len());

     if (!(fileName.Left(onlyFilesStartingWith.Len()).Equals(onlyFilesStartingWith)))

       shouldAddFile = false;

    }

 

    if (!extension.IsEmpty())

      if (!(FPaths::GetExtension(fileName,false).Equals(extension, ESearchCase::IgnoreCase)))

         shouldAddFile = false;


    if (shouldAddFile)

        files.Add(filePath);

   }

return files;

}

使用方法:

TArray<FString> PakFiles;

PakFiles= MyToolsHelper::GetAllFilesInDirector("Content/Paks/","","pak");

(2)遍歷Pak中的文件找到要加載的地圖的全路徑

先獲取Pak中的所有文件

TArray<FString> getAllFilesByPak(const FString pakPath){

IPlatformFile& PlatformFile = FPlatformFileManager::Get().GetPlatformFile();

FPakPlatformFile* PakPlatformFile = new FPakPlatformFile();

PakPlatformFile->Initialize(&PlatformFile,TEXT(""));

FPlatformFileManager::Get().SetPlatformFile(*PakPlatformFile);

 

FPakFile PakFile(&*PakPlatformFile, *pakPath, false);

if (!PakFile.IsValid())return TArray<FString>();

TArray<FString> FileList;

PakFile.SetMountPoint(*FPaths::EngineContentDir());

PakFile.FindFilesAtPath(FileList, *PakFile.GetMountPoint(),true,false,true);

return FileList;

}

使用方法:getAllFilesByPak(pakPath);

遍歷文件列表獲取想要打開的地圖全路徑

auto res=Files.FindByPredicate([&](FString str) {

         auto FileName =FPackageName::GetShortName(str);

         if (FileName.EndsWith(FPackageName::GetMapPackageExtension())){

              FString left, right;

              FileName.Split(TEXT("."), &left, &right);

              if (left.Equals(name))return true;

          }

          return false;

});

if (res)fullPath= *res

前面的結合起來就是

TArray<FString> PakFiles;

       PakFiles= getAllPaks();

       FString fullPath;

       for (FString pakPath : PakFiles) {

         auto Files = getAllFilesByPak(pakPath);

         auto res=Files.FindByPredicate([&](FString str) {

             auto FileName =FPackageName::GetShortName(str);

             if (FileName.EndsWith(FPackageName::GetMapPackageExtension())){

                 FString left, right;

                 FileName.Split(TEXT("."), &left, &right);

                 if (left.Equals(name))return true;

             }

         return false;});

        if (res) {

         fullPath= *res;

         break;

         }

}

 

如果一切沒有問題,那你獲得的路徑應該是類似這種

"../../../Engine/Content/你的項目名字/Plugins/你的DLC插件名字/Content/xx.umap"  

如果xx.umap在插件內容目錄的a/b/c/xx.umap

"../../../Engine/Content/你的項目名字/Plugins/你的DLC插件名字/Content/a/b/c/xx.umap"  

 

(3)對路徑字符串解析獲取出/DLC名字/+地圖在DLCContent中的存取路徑

FString left, right,DLCName,contentPath;

先獲取DLC名字

        fullPath.Split(TEXT("Plugins"),&left, &right);

right.Split(TEXT("Content/"), &DLCName, &left);

再獲取地圖在插件內容目錄中的路徑

left.Split(name, &contentPath, &FString());

最後再合併

auto loadPath = DLCName+ contentPath+ name;

(4)LoadPackageAsync加載資源,並在回調方法中調用加載關卡的命令

這裏就簡單多了,只要能找到路徑其他都不是問題

LoadPackageAsync(loadPath,FLoadPackageAsyncDelegate::CreateLambda([&,name](const FName&PackageName,UPackage*LoadedPackage, EAsyncLoadingResult::Type Result) {

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow,name);

if(Result== EAsyncLoadingResult::Failed)

 

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow,TEXT("Failed"));

else if(Result == EAsyncLoadingResult::Succeeded)

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow,TEXT("Succeeded"));

else

GEngine->AddOnScreenDebugMessage(-1, 15.0f, FColor::Yellow,TEXT("cancel"));

UGameplayStatics::OpenLevel(GetWorld(),*name);

}), 0,PKG_ContainsMap);

 

然後將上面的東西都寫在一個類當中,當然最好是繼承GameInstance這種

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章