Trying to build a standalone MOD/DLC pak file

Hello,

Here is my loooong question post.

I spend a good amount of time and finally could successfully confirmed that Tom Looman’s MOD example works as described with 4.19.2 on Windows 10 64 bit. (I created my own project with 4.19.2 rather than converting his project. So the filenames are slightly different from his)

http://www.tomlooman.com/add-mod-support-to-your-unreal-engine-4-game/

The trick I found is that his tutorial enables the MOD plugin both when I cook the executable and when I cook the MOD plugin. With this process, I confirmed that NewMapMod.uplugin file is cooked in executable’s pak file and the rest of Plugin contents are cooked in plugin’s pak file. (I used “UnrealPak.exe [pakfilename] -List” command to confirm that) And after I put the plugin .pak file next to the executable’s .pak file, I could run the game and load the DLC map. Nice.

Then I looked for if there is a way to include NewMapMod.uplugin in the plugin’s pak file and make the MOD plugin independent from specific executable build. According to engine source, it seems the key is “DLCPakPluginFile” option for the cooker. So I tried to use the option and failed. I like to know how to use the option correctly.

Let me explain my failed attempt in detail below.

First, I disabled the MOD plugin when I cooked the executable then enabled the MOD plugin when I cooked the plugin and check which file is in each pak. In this way, NewMapMod.uplugin isn’t in the executable anymore as expected. But NewMapMod.uplugin is not in plugin pak file either. Loading NewMap.umap from with “open NewMap” command in the game fails. (I guess it’s because UE doesn’t recognize the plugin due to lack of .uplugin file. This implies MOD plugin must be recognized as a valid plugin on Windows)

Then, I looked for the reason why NewMapMod.uplugin isn’t in the plugin’s .pak file. And I found the line 283 of https://github.com/EpicGames/UnrealEngine/blob/8e4560b8c22b309e73ff0ce90377742c3dfe13cc/Engine/Source/Programs/AutomationTool/Scripts/CopyBuildToStagingDirectory.Automation.cs excludes any .uplugin file from the .pak file by default.

And I learned that I can add “-DLCPakPluginFile” as Additional Cooker Options from Project Launcher to forcefully include .uplugin file to the plugin pak. (See https://github.com/EpicGames/UnrealEngine/blob/8e4560b8c22b309e73ff0ce90377742c3dfe13cc/Engine/Source/Programs/AutomationTool/AutomationUtils/ProjectParams.cs) I also add “-CookAll” option just in case.

After cooking the executable and the plugin with those options, I confirmed NewMapMod.uplugin is in the plugin .pak file. So I thought I should be able to load the DLC map finally. But I have no luck… Putting the plugin .pak file next to the executable .pak, then running “open NewMap” command in the game doesn’t load the map. I hope someone can give me some advice.

(Especially I want to know to what extent did I come. Is the pak file properly mounted? Is it working as a plugin already? If so, why loading map fails? How can I effectively debug this .pak loading process?)

The project file I used is here. I included the Launcher profile in the UnrealFrontend directory. I also included Pak file comparison with each different build method in PakFileExaminationResult.

1 Like

Did you make any progress on this?

Hi there! I have the same issue. Any progress?

Hi! I’m using UE 4.20, but I was having the same problem as you: “how to load DLC pak when base game doesn’t know about its plugin?”

After fiddling for days on the engine source, here are my findings (and I made it work \o/).

The uplugin file doesn’t work after base game is built

There’s a part of the engine called PluginManager that creates the plugin content root when the game starts. For it to happen, the plugin must be part of the game. So, if you build the game without the plugin and load a pak file made with that plugin (let’s call it DLCPlugin), Unreal won’t create the /DLCPlugin/ content root and, even though you mounted the DLCPlugin pak, the engine has no idea of how to find its files. They are on there on the drive, but their path is unknown to the engine PackageName class, that takes care of converting logical paths to files on the hard drive. This will happen even if you let the engine mount the pak by having it on the right folder at startup. It mounts the pak, but doesn’t add its root content path to the engine, because that’s the PluginManager’s job. And it doesn’t mater if you add the plugin file to the pak. The PluginManager doesn’t seem to search for plugins on mounted paks.

Making Unreal find the DLC plugin pak contents

After your mount pak code or, if you are letting the engine load the pak by itself, on some BeginPlay event (to do it as soon as possible), you need to register the DLC root path together with its content path.

The root path is the logical path, stored on PackageName. It’ll be /DLCPluginName/. Just like /Game/, /Engine/ etc. These are logical paths that Unreal redirects to some path on the hard drive.

The content path is the hardware one. It’s the one root path will redirect to. So, if you manually mounted the pak in FPaths::ProjectDir(), for instance, that’s what you’ll use as content path for your root.

The function to register the new root is FPackageName::RegisterMountPoint(RootPath, ContentPath)

Keeping DLC content references

After mounting the pak and registering its root, Unreal will see the pak’s files as /RootPath/Path/Relative/ToContentPath/File. So, let’s say you have a DLC plugin called DLCPlugin with a Maps folder and a DLCMap file and another Meshes folder with a Sphere asset. Then you add that Sphere to your map. The map expects to find the sphere in /DLCPlugin/Meshes/Sphere, because that’s the path in the editor. BUT, with Project Launcher built DLC paks there’s a catch!

Inside the DLC plugin pak, the path for those two files will be /Content/Maps/DLCMap for the map and /Content/Meshes/Sphere for the sphere. So the reference the map has to the sphere will be broken, because with the root registered like I said before, its path would become /DLCPlugin/Content/Meshes/Sphere.

Now, you can’t change the paths of the files inside the mounted pak to fix that. But you can map the root to the Content folder after mounting the pak. After all, its contents are in the hard drive with all its folders in it!

So, in order to keep the same paths as they were in the editor (like /DLCName/Meshes/Sphere), do as below (depending on how you mount the pak). The RootPath will always be /[DLCName]/. The ContentPath is the one that changes.

If you mount the pak using FPakPlatformFile::Mount

You’ll have a mount point. Let’s call it MountPoint. When you call FPackageName::RegisterMountPoint, you’ll use MountPoint + TEXT("Content/") as ContentPath.

If you let the engine mount for you or use FCoreDelegates:OnMount

Or if you’re using FPakPlatformFile::Mount without a MountPoint, the default mount point will be ../../../[ProjectName]/Plugins/[DLCName]/. So use FPaths::ProjectDir() + TEXT("Plugins") / DLCName / TEXT("Content/") as ContentPath.

Always check if FPaths::ProjectDir() is returning a / at the end to avoid missing it or having it doubled.

I have only tested this information on Windows. So I don’t know yet about other systems.

Hello RVillani, I’ve found one of your answers here and tried the method you implement there. The case I’m trying to work out is a bit different, but i understand the same principles should apply.

I have two projects with the same exact name, one has no content and the other has all the content. I’m manually creating the paks and downloading them to my projects folder (right now, for the sake of simplicity im trying with the starter content as a package). The function you posted there mounts the package but its not really reading the contents of the package (probably because im doing something wrong).

You see, i changed where you define the PackageMount point from:

FString PakMountPoint = FPaths::Combine(FPaths::GameContentDir(), TEXT("DLC"), PakName);

to

FString PakMountPoint = FPaths::Combine(FPaths::ProjectContentDir(), PakName);

And where you define the virtual pak mount from:

FString VirtualMountPoint(FString::Printf(TEXT("/Game/DLC/%s/"), *PakName));

to

FString VirtualMountPoint(FString::Printf(TEXT("/Game/%s/"), *PakName));

Since I don’t have a DLC folder. The mounting of the package seems to work, but when the function registers the mount point i get this message:

LogDirectoryWatcher: A directory notification for “DIRECTORY” was aborted.

Considering that the starter content of the game truly is in /Game/StarterContent, shouldn’t this be working? Did I miss something?

Thank you for your very detailed responses, they’ve been very helpful.

As a follow-up to this, you can find out the paths of things in any given Pak file using UnrealPak. In my case, UnrealPak is at UE_4.21\Engine\Binaries\Win64\UnrealPak.exe. You can open a command prompt and type UnrealPak.exe "Path\To\The\Pak\File.pak" -list and get a list of all files in that Pak. This is helpful in seeing both what files are actually in the Pak as well as verifying your mount points are set up correctly.

Hello. Tom’s example works for me.
I have two paks Main.pak and DLC.pak.
Main.pak build with the exception of the folder with DLС.
DLС pak I build without any exceptions folders.
Objects in Main.pak and DLC.pak refer to each other.
I build with “Project Launcher”.

I am new to this and want to figure it out.
Where should I start in order to register objects among themselves?

  1. I don’t understand where is the first entry point in the code for registering paks (is this a game instance?).
    In which class do I need to add code and what type?

P.S. I reviewed a large number of answers on the forum and was completely confused, please help me figure it out.
Thanks.