虛幻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名字/”+地圖在DLC的Content中的存取路徑
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這種