UE5热更新(通过Pak包加载关卡资源,并添加到流关卡)

请先阅读我上一篇文章)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就能写在该关卡啦
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/xialuhui/article/details/127447213