请先阅读我上一篇文章)UE5热更新(Pak包的Cook,打包,加载,踩过的一些坑
**
老规矩,还是先说踩过的坑。**
加载关卡和加载其他蓝图资源有一些不同。加载其他蓝图资源,我们要先创建一个新的FPakPlatformFile,并初始化。但是这个FPakPlatformFile对象并不能加载关卡,原因暂时还不知道。需要
FPakPlatformFile* PakPlatformFile_ = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
只有这个FPakPlatformFile对象才能加载Level。
现在进入正文,通过pak包加载关卡资源,并将其通过流关卡打开地图,有三个步骤:
1.挂载Pak包中的.umap
//由于一个pak包里可能有多个关卡,所以关卡名为数组变量
void APakManager::LoadPak(TArray<FString>& LevelNames,const FName& InPakFullPath)
{
LevelNames.Empty();
FString fullPath = InPakFullPath.ToString();
//初始化加载Pak包平台类
OldPlatform = &FPlatformFileManager::Get().GetPlatformFile();
UE_LOG(LogTemp, Warning, TEXT("LoadPakDelegate(): OnMountPak.IsBound() %s"), *fullPath);
FPakPlatformFile* PakPlatformFile_ = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));
FString PakFileFullPath = InPakFullPath.ToString();
//FString PakFileFullPath = InPakFullPath;
if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*PakFileFullPath))
return;
//FString PakName = GetPakFileName(PakFileFullPath);
TRefCountPtr<FPakFile> TmpPak = new FPakFile(OldPlatform, *PakFileFullPath, false);
FString OldPakMountPoint = TmpPak->GetMountPoint();
int32 ContentPos = OldPakMountPoint.Find("Content/");
FString NewMountPath = OldPakMountPoint.RightChop(ContentPos);
FString ProjectPath = FPaths::ProjectDir();
//判断是否是在编辑器
if (GetWorld()->WorldType == EWorldType::PIE)
ProjectPath = "../../../RobotEngine/";
NewMountPath = ProjectPath + NewMountPath;
TmpPak->SetMountPoint(*NewMountPath);
if (PakPlatformFile_->Mount(*PakFileFullPath, 1, *NewMountPath))
{
TArray<FString> FoundFilenames;
OldPakMountPoint = TmpPak->GetMountPoint();
TmpPak->FindPrunedFilesAtPath(FoundFilenames, *TmpPak->GetMountPoint(), true, false, true);
if (FoundFilenames.Num() > 0)
{
//if (GetWorld()->WorldType == EWorldType::Game)
{
for (int i = 0; i < FoundFilenames.Num(); ++i)
{
FString Filename(FoundFilenames[i]);
if (Filename.EndsWith(TEXT(".uasset")))
{
}
else if (Filename.EndsWith(TEXT(".umap")))
{
//通过一系列的String操作,从加载的关卡虚拟路径获取到关卡名
GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Red, *Filename);
FString PathDir = FPaths::ProjectContentDir();
Filename.ReplaceInline(*PathDir, TEXT("/Game/"));
FString leftName;
FString NewFileName2;
Filename.Split(TEXT("/"), &leftName, &NewFileName2, ESearchCase::Type::CaseSensitive, ESearchDir::FromEnd);
NewFileName2.RemoveFromEnd(TEXT(".umap"));
GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Red, *NewFileName2);
//调用函数,将关卡名添加到流关卡中
AddMapToWorld(NewFileName2);
LevelNames.AddUnique(NewFileName2);
}
}
}
}
}
//设置回原来的读取方式,不然包内的资源可能访问不了
FPlatformFileManager::Get().SetPlatformFile(*OldPlatform);
}
2.将挂载的.umap添加的关卡流中
void APakManager::AddMapToWorld(const FString& LevelName)
{
FString LongPackageName;
bool bOutSuccess = FPackageName::SearchForPackageOnDisk(LevelName, &LongPackageName);
if (!bOutSuccess)
{
return;
}
UWorld* world = GetWorld();
FString name = CreateStreamInstance(world, LongPackageName);
}
FString APakManager::CreateStreamInstance(UWorld* World, const FString& LongPackageName)
{
const FString ShortPackageName = FPackageName::GetShortName(LongPackageName);
const FString PackagePath = FPackageName::GetLongPackagePath(LongPackageName);
FString UniqueLevelPackageName = PackagePath + TEXT("/") + World->StreamingLevelsPrefix + ShortPackageName;
// Setup streaming level object that will load specified map
UClass* StreamingClass = ULevelStreamingDynamic::StaticClass();
ULevelStreamingDynamic* StreamingLevel = NewObject<ULevelStreamingDynamic>(World, StreamingClass, NAME_None, RF_Transient, NULL);
StreamingLevel->SetWorldAssetByPackageName(FName(*UniqueLevelPackageName));
StreamingLevel->LevelColor = FColor::MakeRandomColor();
StreamingLevel->LevelTransform = FTransform(FRotator::ZeroRotator, FVector::ZeroVector);
// Map to Load
StreamingLevel->PackageNameToLoad = FName(*LongPackageName);
StreamingLevel->SetShouldBeLoaded(false);
StreamingLevel->SetShouldBeVisible(false);
StreamingLevel->bShouldBlockOnLoad = false;
World->AddUniqueStreamingLevel(StreamingLevel);
//World->UpdateStreamingLevelShouldBeConsidered(StreamingLevel);
return UniqueLevelPackageName;
}
3.加载和写在关卡流中的关卡
void APakManager::LoadMap(const FString& LevelName, FLatentActionInfo LatentInfo)
{
FString LongPackageName;
bool bOutSuccess = FPackageName::SearchForPackageOnDisk(LevelName, &LongPackageName);
if (!bOutSuccess)
{
return;
}
UWorld* world = GetWorld();
UGameplayStatics::LoadStreamLevel(world, FName(*LevelName), true, false, LatentInfo);
}
void APakManager::UnLoadMap(const FString& LevelName, FLatentActionInfo LatentInfo)
{
FString LongPackageName;
bool bOutSuccess = FPackageName::SearchForPackageOnDisk(LevelName, &LongPackageName);
if (!bOutSuccess)
{
return;
}
UWorld* world = GetWorld();
UGameplayStatics::UnloadStreamLevel(world, FName(*LevelName), LatentInfo, false);
}
自此,通过调用LoadPak就能将pak包里的关卡添加到流关卡了
通过调用LoadMap就能加载该关卡啦
通过调用UnLoadMap就能写在该关卡啦