UE5 hot update (load level resources through Pak package, and add to stream level)

Please read my last article first) UE5 hot update (Cook, pack, load, and step on some pits in the Pak package
**

The old rules, let’s talk about the pits you stepped on first. **

Loading levels is a little different than loading other Blueprint assets. To load other blueprint resources, we need to create a new FPakPlatformFile and initialize it. But this FPakPlatformFile object cannot load the level, the reason is not yet known. need

FPakPlatformFile* PakPlatformFile_ = (FPakPlatformFile*)(FPlatformFileManager::Get().FindPlatformFile(FPakPlatformFile::GetTypeName()));

Only this FPakPlatformFile object can load Level.

Now enter the text, load the level resources through the pak package, and open the map through the streaming level, there are three steps:

1. Mount the .umap in the Pak package

//由于一个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. Add the mounted .umap to the level stream

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. Load and write the level in the level stream

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);
}

Since then, the level in the pak package can be added to the flow level by calling LoadPak.
insert image description here
The level can be loaded by calling LoadMap. It
insert image description here
can be written in the level by calling UnLoadMap.
insert image description here

Guess you like

Origin blog.csdn.net/xialuhui/article/details/127447213