虚幻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这种