UE5 hot update (Cook, pack, load, and step on some pits of the Pak package)

	这几天弄UE5的Pak包加载,弄得晕头转向,网上都是UE4.27以下的教程,UE4.27, UE5修改了一些东西,导致按照[虚幻官方直播第四期的教程](https://www.bilibili.com/video/BV1Ut411A7sk?spm_id_from=333.337.search-card.all.click&vd_source=f7b2defde4971310a19a6e9e40c36b90)无法成功加载,废话不多说,先说一下踩的坑。

1. The difference between UE5 loading Pak and UE4

1. Cancel the check of Use Iostore (use Io to save)

![在这里插入图片描述](https://img-blog.csdnimg.cn/15bd946face648ee80a2ad4cfc787f90.png)

UE5's packaging settings automatically check the use of Io to save, or the trial function, the engine's Mount function has a judgment on this,
insert image description here
if IO is enabled, it will detect whether there is a corresponding .utoc file, if not, return false, Mount fail.
We use UE5's Cook ourselves, and the packaging will not generate .utoc files, resulting in continuous loading failures. As for how to use Iostore correctly, I will have time to look at it later.

2. Uncheck Share Material Shader Code

UE5 starts the shared material shader code by default, resulting in the loss of the loaded Actor material, unchecking it can solve the problem.
insert image description here

3. The blueprint calls the C++ path name inexplicably with a blank character

You may not have encountered this, but I have. During debugging, I found that the parameter of type FString has a blank character inexplicably, which makes it impossible to find the Pak package. This problem does not exist in the tutorial using the command line to call the function. I wrote the parameters in C++ to avoid this problem. I will look at it later when I have time.
insert image description here
I mainly stepped on these three pits, and I will talk about the entire Pak usage process below.

2. Cook, pack and load process of UE5 Pak package

1.cook

First create the DLC folder, there is an Actor, a texture, a material, and a Mesh,
insert image description here
add the test code in the Actor, and print "Yeah, I was successfully loaded" every second
insert image description here

Add the DLC folder to the additional asset directory to be baked.
insert image description here
Enable baking in the platform. Note here that the baking button of UE4 is in the file.
insert image description here
After the baking button of UE5 is successfully baked on the platform, you can see G:\UE5Demo\PakTest \Saved\Cooked\Windows\PakTest\Content\DLC contains the .uasset file of DLC

2 dozen Pak bags

Find UnrealPak.exe in the engine directory. The tutorial says that it can be moved to any place to run without relying on UE's library. I tried it, but it doesn't work. Honestly use cmd to run, cd to the directory, and run UnrealPak.exe.
insert image description here
Then enter the command unrealpak {pak directory} -create={cook file directory} to open the pak package
unrealpak G:\dlc.pak -create=G:\UE5Demo\PakTest\Saved\Cooked\Windows\PakTest\Content\DLC
This is I will not demonstrate the ordinary way of pak, encrypt or compress the pak package.
Enter the command unrealpak {pak directory} -list to view the pak package
unrealpak G:\dlc.pak -list
insert image description here

3. Load the Pak package

Create a C++ class that inherits from Actor, and add the module "PakFile" in the project build.cs

PublicDependencyModuleNames.AddRange(new string[] 
{
    
     "Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "PakFile" });

Declare OldPlatform and PakPlatform in .h. I don’t ask for a deep understanding here. I don’t need to pay attention to what it is doing. I guess it will be forgotten in a few days after spending a lot of money to figure it out.
Declare the TestLoadPak function, here use the blueprint call, you can also learn the tutorial to use the command line call, just change UFUNCTION (BlueprintCallable) to UFUNCTION (Exec).

	TSharedPtr<class FPakPlatformFile> PakPlatform;
	class IPlatformFile* OldPlatform;
	UFUNCTION(BlueprintCallable)
	bool TestLoadPak(const FString& InPakFullPath);

Reference the header file in the .cpp file

#include "MyActor.h"
#include "IPlatformFilePak.h"
#include "HAL/PlatformFilemanager.h"
#include "Runtime/Engine/Classes/Engine/StreamableManager.h"
#include "Runtime/Engine/Classes/Engine/AssetManager.h"
#include "Runtime/Engine/Classes/Engine/StaticMeshActor.h"
#include "Kismet/KismetStringLibrary.h"

Implement the BeginPlay function and initialize

	Super::BeginPlay();
	OldPlatform = &FPlatformFileManager::Get().GetPlatformFile();
	PakPlatform = MakeShareable(new FPakPlatformFile());
	PakPlatform->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT(""));

Implement the TestLoadPak function

bool AMyActor::TestLoadPak(const FString& InPakFullPath)
{
    
    

	FPlatformFileManager::Get().SetPlatformFile(*PakPlatform.Get());

	FString PakFileFullPath = L"g:/dlc.pak";
	if (!FPlatformFileManager::Get().GetPlatformFile().FileExists(*PakFileFullPath))
		return false;
	//FString PakName = GetPakFileName(PakFileFullPath);

	TRefCountPtr<FPakFile> TmpPak = new FPakFile(PakPlatform.Get(), *PakFileFullPath, false);
	FString OldPakMountPoint = TmpPak->GetMountPoint();

	int32 ContentPos = OldPakMountPoint.Find("Content/");
	FString NewMountPath = OldPakMountPoint.RightChop(ContentPos);

	FString ProjectPath = FPaths::ProjectDir();
	//ProjectPath = "../../../PakTest/";
	NewMountPath = ProjectPath + NewMountPath;
	TmpPak->SetMountPoint(*NewMountPath);

	if (PakPlatform->Mount(*PakFileFullPath, 1, *NewMountPath))
	{
    
    
		//StaticMesh'/Game/DLC/SM_Cube.SM_Cube_C'
		//Blueprint'/Game/DLC/DLC_Cube.DLC_Cube'
		//World'/Game/ThirdPerson/Maps/ThirdPersonMap.ThirdPersonMap'
		TArray<FString> FoundFilenames;
		TmpPak->FindFilesAtPath(FoundFilenames, *TmpPak->GetMountPoint(), true, false, false);
		if (FoundFilenames.Num() > 0)
		{
    
    
			if (GetWorld()->WorldType == EWorldType::Game)
			{
    
    
				for (FString& Filename : FoundFilenames)
				{
    
    
					if (Filename.EndsWith(TEXT(".uasset")))
					{
    
    
						FString NewFileName = Filename;
						FString PathDir = FPaths::ProjectContentDir();
						NewFileName.ReplaceInline(*PathDir, TEXT("/Game/"));
						FString File = FPaths::GetBaseFilename(Filename);
						NewFileName.ReplaceInline(TEXT("uasset"), *File);
						FString blueprint = TEXT("Blueprint'");
						NewFileName.Append(TEXT("_C'"));
						GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Red, *NewFileName);

						NewFileName=UKismetStringLibrary::Concat_StrStr(TEXT("Blueprint'"), NewFileName);
						UClass* Class = LoadClass<AActor>(NULL, *NewFileName);
						//UClass* Class = LoadClass<AActor>(NULL, TEXT("Blueprint'/Game/DLC/DLC_Cube.DLC_Cube_C'"));
						if (Class == nullptr)
						{
    
    
							GEngine->AddOnScreenDebugMessage(-1, 20.0f, FColor::Red, TEXT("Load Class Error"));
						}
						else
						{
    
    
							AActor* MeshActor = GetWorld()->SpawnActor<AActor>(Class, FVector(100, 100, 400), FRotator(0, 0, 0));
						}
					}
				}
			}	
		}
	}
	//设置回原来的读取方式,不然包内的资源可能访问不了
	FPlatformFileManager::Get().SetPlatformFile(*OldPlatform);
	return true;
}

This example refers to the fact that there are three paths.
1. The path of the Pak package - PakFileFullPath. The reason why I wrote the path of the Pak package to death is that as mentioned earlier, when the blueprint is passed as a parameter, there is an extra null character for no reason, resulting in the path It's never been right. Then generate an FPakFile object. Note that UE5 privatizes the destructor of FPakFile, and cannot use shared smart pointers.

TRefCountPtr<FPakFile> TmpPak = new FPakFile(PakPlatform.Get(), *PakFileFullPath, false);

2. The path of the mount point-NewMountPath, NewMountPath=".../.../.../PakTest/Content/DLC", if you want to find a way to match this path, you need to debug it after packaging, check the values ​​​​of each path, and finally put together The structure ".../.../.../{project name}/Content/{DLC directory}" into the above value. Then set the mount point and mount

TmpPak->SetMountPoint(*NewMountPath);
PakPlatform->Mount(*PakFileFullPath, 1, *NewMountPath)

3. The virtual path of the Pak package resource - NewFileName, mine is "Blueprint'/Game/DLC/DLC_Cube.DLC_Cube_C'", when we are baking, directly select the resource in the UE5 editor - "copy reference, and add "_C", you can get the path. We also want to spell the file name read from the Pak package into such a path. Finally, load the resources of the virtual path through LoadClass and generate,

UClass* Class = LoadClass<AActor>(NULL, *NewFileName);
AActor* MeshActor = GetWorld()->SpawnActor<AActor>(Class, FVector(100, 100, 400), FRotator(0, 0, 0));

Finally, derive an Actor, call this function, put it in the scene, and delete the DLC folder of the UE5 editor. Note that every time you delete or move resources, you must right click on the content to repair the redirector in the folder, so that will be referenced, and resource processing is complete.

Finally, pack the project and run it.
insert image description here
Finally, you can see the print in the upper left corner and the small textured square in front. It is finally successful. The whole world celebrates and finishes the flowering.

If you do not see the above effect, you can attach the program to the VS process for debugging, and check whether each path is correct.

Guess you like

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