Pre-Requisites
- Unreal Engine 5.7 Source Build
- Visual Studio 2022 (Build 17.14.20)
Note for Unreal Engine 5.6 Development
The asset loading C++ code shown near the bottom of this article is the same for both 5.6 and 5.7. However, you don’t need the build target global definitions for 5.6. The editor project settings and GameEngine.ini file configuration probably work for both 5.6 and 5.7 but was not tested.
PAK Legacy - One Asset Per File PAKs
Games that require DLC remotely need a granular asset strategy. The PAK approach is ideal for doing this but its becoming a legacy approach. Epic is moving away from PAK in favor of the IO-Store chunking system. It is a totally different approach and uses pairs of ucas/toc files. In my opinion, PAK is likely to be around for a long time since there are so many games written using it and utility tools. Epic will likely need to support this for a long time. I also believe IO-Store will need to mature as the only necessary solution before PAK is finally removed.
The following sections show my cooking, server build and loading strategy that worked for me for UE5.7.
Configuration
Unreal Engine Project Settings
DefaultEngine.ini
This is the main project DefaultEngine.ini - [ ../Config/DefaultEngine.ini ]
[/Script/UnrealEd.ProjectPackagingSettings]
bUseIoStore=False
bUseZenStore=False
bUsePakFile=True
PakFileCompressionFormats=oodle
PakFileCompressionMethod=Kraken
PakFileCompressionLevel=4 ; 0 = Fast, 4 = Optimal2
[/Script/UnrealEd.CookerSettings]
bCookWithIoStore=False
bGenerateIOStoreContainerFiles=False
bCookUsingZenStore=False
CookContent.bat
Put in the main project root folder
Produces loose cooked files (uasset, ubulk, and uexp) at
This will cook files into /Saved/Cooked/WindowsClient//Content/
RunUAT.bat BuildCookRun ^
-project="<PROJECT ROOT>\<PROJECT NAME>.uproject" ^
-noP4 ^
-client ^
-target=<BUILD TARGET NAME> ^
-platform=Win64 ^
-clientconfig=Development ^
-cook ^
-skipstage ^
-nopak ^
-nostrict ^
-map=<MAP PATH>
PackageClient.bat
Put in the main project root folder
This creates a client build with PAK maps and pulls in all the asset dependencies associated with the maps.
RunUAT.bat BuildCookRun ^
-project="<PROJECT ROOT>\<PROJECT NAME>.uproject" ^
-target=<BUILD TARGET NAME> ^
-platform=Win64 ^
-client ^
-clientconfig=Development ^
-cook ^
-build ^
-stage ^
-pak ^
-noiostore ^
-archive ^
-archivedirectory="<PROJECT ROOT>\Build\WindowsClient" ^
-Map=<MAP PATH 1> ^
-Map=<MAP PATH 2>
PackageServer.bat
Put in the main project root folder
This will build the server target and configure it to load PAK files and not IO Store files.
RunUAT.bat BuildCookRun ^
-project="<PROJECT ROOT>\<PROJECT NAME>.uproject" ^
-target=<BUILD TARGET NAME> ^
-server ^
-platform=Win64 ^
-serverconfig=Development ^
-cook ^
-build ^
-stage ^
-archive ^
-archivedirectory="<PROJECT ROOT>\Build\WindowsServer" ^
-pak ^
-noiostore ^
-Map=<MAP PATH>
Build Target Global Definitions - USE_IOSTORE=0, WITH_PAKFILE=1
Define in the server build target two global definitions to ensure that the PAK gets linked into the server build and the IO Store gets excluded. Note that your also have to do this for any build target which you want to load PAK files.
In your build target cs file
// Copyright Epic Games, Inc. All Rights Reserved.
using UnrealBuildTool;
public class MyServerTarget : TargetRules
{
public MyServerTarget(TargetInfo Target) : base(Target)
{
Type = TargetType.Server;
DefaultBuildSettings = BuildSettingsVersion.V6;
IncludeOrderVersion = EngineIncludeOrderVersion.Unreal5_7;
ExtraModuleNames.AddRange(new string[] { "MyWorld" });
RegisterModulesCreatedByRider();
GlobalDefinitions.Add("USE_IOSTORE=0");
GlobalDefinitions.Add("WITH_PAKFILE=1");
}
private void RegisterModulesCreatedByRider()
{
ExtraModuleNames.AddRange(new string[]
{
});
}
}
Remove Package Dependency Warning Messages in Engine Build
If you want to remove the annoying load asset warning messages in the logs when loading the PAK files then you can do it via commenting out some code in the engine source for 5.7.
- Close Unreal Editor 5.7
- Open Engine Source *.sln file with Visual Studio 2022
- Find the AsyncLoading2.cpp
- Comment out the following code
...
/* if (Explanation.Len())
{
FMessageLog("LoadErrors").Warning(FText::FormatNamed(NSLOCTEXT("Core", "AsyncLoading_SkippedPackage_Explanation", "While trying to load package {MissingPackage}, a dependent package {DependentPackage} was not available. Additional explanatory information follows:\n{Explanation}"),
TEXT("MissingPackage"), FText::FromString(PackagePathToLoadString),
TEXT("DependentPackage"), FText::FromString(ImportedPackageNameToLoadString),
TEXT("Explanation"), FText::FromString(Explanation.ToString())));
}
else
{
FMessageLog("LoadErrors").Warning(FText::FormatNamed(NSLOCTEXT("Core", "AsyncLoading_SkippedPackage_NoExplanation", "While trying to load package {MissingPackage}, a dependent package {DependentPackage} was not available. No additional explanation was available."),
TEXT("MissingPackage"), FText::FromString(PackagePathToLoadString),
TEXT("DependentPackage"), FText::FromString(ImportedPackageNameToLoadString)));
}*/
- Open Unreal Editor Project
- Open Rider Uproject (If your using this IDE)
- Build project
Creating PAK Files From PAK Content Folder with GUID Support
If you want to create PAK files from the cooked content shown above then you can use the UnrealPak.exe utility (Source Build Version). It is very likely that you will want to associate a GUID with each content asset you cook such that when its mounted its uniquely identified. This is the best way to support lots of modders creating content for your game.
As an example we will use the mesh asset SM_Table_02.
To create the PAK for SM_Table_02mesh with a guid of 043493B94C547208621463862AE4DA16
UnrealPak.exe "<PROJECT ROOT>\webcontent\cache\043493B94C547208621463862AE4DA16.mesh" -Create="<PROJECT ROOT>/MyPakList.txt" -compressed -compressionformats=oodle
and with a MyPakList.txt
"<PROJECT ROOT>/PAKContent/WindowsClient/Content/VendorName/Meshes/Interior/Cafe/SM_Table_02.uasset" "VendorName/Meshes/Interior/Cafe/SM_Table_02.uasset"
"<PROJECT ROOT>/PAKContent/WindowsClient/Content/VendorName/Meshes/Interior/CafeSM_Table_02.uexp" "VendorName/Meshes/Interior/Cafe/SM_Table_02.uexp"
"<PROJECT ROOT>/PAKContent/WindowsClient/Content/VendorName/Meshes/Interior/CafeSM_Table_02.ubulk" "VendorName/Meshes/Interior/Cafe/SM_Table_02.ubulk"
Notice that the format is [Absolute Cooked Asset Path] [Virtual Content Path]
Also notice you DO NOT put the GUID into this MyPAKList.txt
Some assets like a mesh are made up of three separate asset files (uasset, uexp and ubulk)
Inspect PAK
UnrealPak.exe "<PROJECT ROOT>\webcontent\cache\043493B94C547208621463862AE4DA16.mesh" -list
Mounting a PAK - C++
Note : In a real game you will likely take all the generated PAK files and put them on a remote CDN server for downloading. But for simplicity we will use the /webcontent/cache folder instead.
FString PakPath = TEXT("<PROJECT ROOT>/webcontent/cache/043493B94C547208621463862AE4DA16.mesh");
// MOUNT THE PAK
if (FPakPlatformFile* PakPlatform = (FPakPlatformFile*)FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile")))
{
FString MountPoint = FPaths::ProjectContentDir() + TEXT("043493B94C547208621463862AE4DA16/");
bool bMounted = PakPlatform->Mount(*PakPath, 0, *MountPoint);
UE_LOG(LogTemp, Log, TEXT("Mount result = %d"), bMounted);
}
If the FindPlatformFile method returns nullptr then this is a big indication that you have not configured for PAK only and the IO-Store is still default. Also remember you do need to include PakFile module when using this in your public dependency list when you build your server.
Note that the mount path is composed of the project content directory and the assets guid.
Loading a PAK Asynchronously
An asset is addressed as follows
/Game/043493B94C547208621463862AE4DA16/SM_Table_02.SM_Table_02
FSoftObjectPath MeshPath(TEXT("/Game/043493B94C547208621463862AE4DA16/SM_Table_02.SM_Table_02"));
FStreamableManager& Streamable = UAssetManager::GetStreamableManager();
Streamable.RequestAsyncLoad(
MeshPath,
FStreamableDelegate::CreateLambda([MeshPath]()
{
if (UStaticMesh* Mesh = Cast<UStaticMesh>(MeshPath.ResolveObject()))
UE_LOG(LogTemp, Log, TEXT("Success: %s"), *MeshPath.ToString());
else
UE_LOG(LogTemp, Error, TEXT("Failed: %s"), *MeshPath.ToString());
}),
FStreamableManager::AsyncLoadHighPriority);
Loading a PAK Synchronously
if(UStaticMesh* Mesh = LoadObject<UStaticMesh>(nullptr, TEXT("/Game/043493B94C547208621463862AE4DA16/SM_Table_02.SM_Table_02")))
{
UE_LOG(LogTemp, Log, TEXT("Success"));
}
else
{
UE_LOG(LogTemp, Error, TEXT("Failed"));
That’s about all there is to it. Hope it helps someone.

