I am trying to make content (static meshes) available after my application is shipped. The plan was to
add the dynamic content to the editor
cook and pack it into a .pak file
provide the .pak file on an http server
download the pak with the shipped client
mount the pak file and instantiate the content
1-4 are easy, but I could not get 5 done. I’m aware of [this post][1], but I don’t need any streaming, and I need to store the pak files at the client for offline availability.
For now, I tried the following (error checks omitted):
IPlatformFile& InnerPlatform = FPlatformFileManager::Get().GetPlatformFile();
FPakPlatformFile* PakPlatform = new FPakPlatformFile();
PakPlatform->Initialize(&InnerPlatform, TEXT(""));
FPlatformFileManager::Get().SetPlatformFile(*PakPlatform);
PakPlatform->Mount(Text("ABS_PATH_TO_PAK_FILE"), 0, *FPaths::EngineContentDir());
// trying to load the mesh
UStaticMesh* obj = Cast<UStaticMesh>(StaticLoadObject(UStaticMesh::StaticClass(), nullptr, TEXT("/Engine/PAK_INNER_DIR")));
I am not sure if the “PAK_INNER_DIR” (this is obviously a placeholder) is incorrect, or if I just understood something wrong with mounting paks.
I’m not quite sure what you’re trying to do when you ‘mount the pak file and instantiate the content’, as that isn’t too clear to me. If you could explain this step further, I can dig deeper into our documentation and test this for you. With that being said, I’ve gathered a few AnswerHub posts and Documentation links that I feel may be helpful to what you’re trying to achieve:
The code modifies the PlatformFile-Chain, which causes issues.
Doing so, we had issues with IFileManager::FindFilesRecursive which was now returning multiples of the same file (~6 times the same file in our case) (the issue appeared only in a packaged project).
Might be there are other issues as well.
The below code is modified to first look for a PakPlatformFile already existing in the PlatformFile-Chain and take that if it exists. That solved our issue.
//Load and mount pak file
if (pakPlatformFile == nullptr)
{
// Search for an existing pakPlatformFile
IPlatformFile* existingPakPlatformFile = FPlatformFileManager::Get().FindPlatformFile(TEXT("PakFile"));
if (existingPakPlatformFile)
{
pakPlatformFile = static_cast<FPakPlatformFile*>(existingPakPlatformFile);
UE_LOG(LogTemp, Log, "Using existing PakPlatformFile");
}
else
{
// When mounting a .pak file, we need to store a references to the .pak file in the platform file system.
// To do this, we need a FPakPlatformFile that allows us to mount our .pak and keeps the information about the package.
pakPlatformFile = new FPakPlatformFile();
// But we don't want the engine to lose information of other packages
// (and what ever other stuff), thus get the current PlatformFile
IPlatformFile& platformFile = FPlatformFileManager::Get().GetPlatformFile();
// and place it into our new PlatformFile (PlatformFile-Chain).
if (!pakPlatformFile->Initialize(&platformFile, TEXT("")))
{
UE_LOG(LogTemp, Fatal, "Failed to initialize PakPlatformFile");
}
// Not sure about this, see: https://answers.unrealengine.com/questions/574388/how-to-mount-a-pak-file-at-game-content-directory.html
pakPlatformFile->InitializeNewAsyncIO();
// Now give the new PlatformFile to the engine.
FPlatformFileManager::Get().SetPlatformFile(*pakPlatformFile);
UE_LOG(LogTemp, Log, "Using our own PakPlatformFile");
}
}