这几天弄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. UE5 ロード Pak と UE4 の違い
1. Use Iostore のチェックを外す (Io を使って保存する)
![在这里插入图片描述](https://img-blog.csdnimg.cn/15bd946face648ee80a2ad4cfc787f90.png)
UE5 のパッケージング設定は、Io を使用して保存するか、試用機能を自動的にチェックします。エンジンの Mount 関数はこれを判断し、
IO が有効になっている場合は、対応する .utoc ファイルがあるかどうかを検出し、そうでない場合は false を返します。マウント失敗。
私たちは UE5 のクックを使用していますが、パッケージングで .utoc ファイルが生成されないため、ロードが継続的に失敗します。Iostore を正しく使用する方法については、後で確認する時間があります。
2. マテリアル シェーダー コードの共有のチェックを外す
UE5 はデフォルトで共有マテリアル シェーダー コードを開始するため、読み込まれた Actor マテリアルが失われます。チェックを外すと問題を解決できます。
3. ブループリントが C++ パス名を不可解に空白文字で呼び出している
デバッグ中に、型 FString のパラメーターに不可解な空白文字が含まれていることがわかりました。これにより、Pak パッケージを見つけることができなくなります。この問題は、コマンドラインを使用して関数を呼び出すチュートリアルには存在しません. この問題を回避するために C++ でパラメーターを記述しました. 時間があるときに後で見ていきます.
主にこの 3 つの穴を踏んだので、Pak の使用プロセス全体について説明します。
2. UE5 Pak パッケージのクック、パック、ロードのプロセス
1.料理する
最初に DLC フォルダを作成します。そこにはアクター、テクスチャ、マテリアル、メッシュがあり、
テスト コードをアクターに追加し、毎秒 "Yeah, I was successfully loaded" を出力します。
ベイクする追加アセット ディレクトリに DLC フォルダを追加します.
プラットフォームでベイクを有効にします. ここで UE4 のベイク ボタンがファイルにあることに注意してください.
UE5 のベイク ボタンがプラットフォーム上で正常にベイクされると, G: が表示されます. \UE5Demo\PakTest \Saved\Cooked\Windows\PakTest\Content\DLC には DLC の .uasset ファイルが含まれています
2ダースのパックバッグ
engine ディレクトリにある UnrealPak.exe を見つけてください.UE のライブラリに依存せずに任意の場所に移動して実行できるとチュートリアルに書かれています.試してみましたが,動作しません. 正直なところ、cmd を使用して実行し、cd でディレクトリに移動し、UnrealPak.exe を実行します。
次に、コマンド unrealpak {pak directory} -create={cook file directory} を入力して pak パッケージ
unrealpak G:\dlc.pak -create=G:\UE5Demo\PakTest\Saved\Cooked\Windows\PakTest\Content\DLC を開きます
これは、pak パッケージの通常のパック、暗号化、または圧縮の方法を示すものではありません。
コマンド unrealpak {pak directory} -list を入力して、pak パッケージ
unrealpak G:\dlc.pak -listを表示します。
3. Pak パッケージをロードする
Actor から継承する C++ クラスを作成し、プロジェクト build.cs にモジュール「PakFile」を追加します。
PublicDependencyModuleNames.AddRange(new string[]
{
"Core", "CoreUObject", "Engine", "InputCore", "HeadMountedDisplay", "PakFile" });
OldPlatform と PakPlatform を .h に宣言します. ここで深い理解は求めません. 何をしているかに注意を払う必要はありません. たくさんのお金を使って数日で忘れられると思います.それを理解してください。
TestLoadPak 関数を宣言します。ここでは blueprint 呼び出しを使用します。コマンド ライン呼び出しを使用するチュートリアルも学習できます。UFUNCTION (BlueprintCallable) を UFUNCTION (Exec) に変更するだけです。
TSharedPtr<class FPakPlatformFile> PakPlatform;
class IPlatformFile* OldPlatform;
UFUNCTION(BlueprintCallable)
bool TestLoadPak(const FString& InPakFullPath);
.cpp ファイルでヘッダー ファイルを参照する
#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"
BeginPlay 関数を実装して初期化する
Super::BeginPlay();
OldPlatform = &FPlatformFileManager::Get().GetPlatformFile();
PakPlatform = MakeShareable(new FPakPlatformFile());
PakPlatform->Initialize(&FPlatformFileManager::Get().GetPlatformFile(), TEXT(""));
TestLoadPak 関数を実装する
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;
}
この例では、3 つのパスがあることを示しています.
1. Pak パッケージのパス - PakFileFullPath. Pak パッケージのパスをデスに書いた理由は、前述のように、ブループリントがパラメーターとして渡されるときに、理由もなく余分なヌル文字があり、その結果、パスは正しくありませんでした. 次に、FPakFile オブジェクトを生成します。UE5 は FPakFile のデストラクタをプライベート化し、共有スマート ポインタを使用できないことに注意してください。
TRefCountPtr<FPakFile> TmpPak = new FPakFile(PakPlatform.Get(), *PakFileFullPath, false);
2. マウント ポイントのパス - NewMountPath、NewMountPath=".../.../.../PakTest/Content/DLC"。このパスに一致する方法を見つけたい場合は、デバッグする必要があります。パッケージング後、各パスの値を確認し、最後に「.../.../.../{プロジェクト名}/Content/{DLCディレクトリ}」という構造を上記の値にまとめます。次に、マウントポイントとマウントを設定します
TmpPak->SetMountPoint(*NewMountPath);
PakPlatform->Mount(*PakFileFullPath, 1, *NewMountPath)
3. Pak パッケージ リソースの仮想パス - NewFileName、私の場合は「Blueprint'/Game/DLC/DLC_Cube.DLC_Cube_C'」です。ベイクするときは、UE5 エディタでリソースを直接選択し、「参照をコピーして」を追加します。 _C」で、パスを取得できます。また、Pak パッケージから読み取ったファイル名をそのようなパスに綴りたいと考えています。最後に、LoadClass を介して仮想パスのリソースをロードし、生成します。
UClass* Class = LoadClass<AActor>(NULL, *NewFileName);
AActor* MeshActor = GetWorld()->SpawnActor<AActor>(Class, FVector(100, 100, 400), FRotator(0, 0, 0));
最後に、Actor を派生させ、この関数を呼び出してシーンに配置し、UE5 エディタの DLC フォルダを削除します.リソースを削除または移動するたびに、コンテンツを右クリックして、フォルダ内のリダイレクタを修復する必要があることに注意してください. 、それが参照されるようになり、リソースの処理が完了します。
最後に, プロジェクトをパックして実行します.
最後に, 左上隅に印刷物が表示され、前面に小さなテクスチャ付きの正方形が表示されます. 最終的に成功しました. 全世界が祝い、開花を終えます.
上記の効果が見られない場合は、デバッグのためにプログラムを VS プロセスにアタッチし、各パスが正しいかどうかを確認できます。