Howdy @Sith_Handbuilt!
This has been a surprisingly tricky topic to build documentation for due to the varying methods for delivering patches and DLC. The process of developing these docs started with exploring a fully implemented system, and from there I’ve worked my way down to the building blocks we ship with the engine and the base interfaces they’re built on top of. It’s surfaced enough usability concerns that we are working towards a consolidated patching system that should be more user-friendly and easy to integrate compared with current options, and I’ve been assisting with research on that front. When that solution rolls out in a future engine version, full documentation will be available alongside it. However, I doubt that’s a satisfying answer given your immediate needs, so I’ll try and share as much information as I can to help you on the right track.
Currently, the most up-to-date patching doc we’ve got published is for Google PAD. This method requires you to use an Android App Bundle build to use it, which means you must also distribute your project on the Google Play store, which itself serves as the back-end for hosting the asset packs. However, this at least gives you a rundown of the principles behind patching and a thorough walkthrough for generating your chunks; if you understand how to implement this system, you’ll have a good idea of how the others work. I’ve written a revised version of the Cooking and Chunking page which should go up sometime next week, which will have more thorough information about chunks/paks and clearer instructions about how to work with them. I hope to follow with an updated doc for HTTPChunkInstaller shortly after, which is the legacy patching plugin that currently ships with the engine.
In essence, patching involves the following steps:
- Initialize the patching system. This is usually done in GameInstance, in the Initialize function, which runs when the application starts. Similarly, the GameInstance shutdown function is used for shutting down the patching system.
- Connect to the remote service and download a manifest file containing a list of what paks users should have. Manifest entries should have enough information to discern not only whether a pak is present, but also if the pak on the user’s local device matches the pak on the remote server, and necessary progress information. This might include a friendly name for the pak, its file size in bytes, and its chunk index.
- After updating the manifest, delete any paks from disc that aren’t supposed to still be around.
- Check the manifest for what paks do need to be downloaded, and queue up downloads for them. These should be tracked asynchronously, and once the download is done, they need to be written to local storage. Monitoring downloads, queuing them up at appropriate times, and error handling are the bulk of what you need to concern yourself with.
- Once a pak is downloaded and installed to local storage, it is available to be mounted. Mounting a chunk means that you are putting it in memory and telling the engine that its files and directories are available to be accessed. In other words, once a chunk is mounted, you can access its information like you would any asset in the Content Browser. When a chunk is unmounted, it is freed up from memory, and its contents are no longer accessible. Because you need a chunk mounted in memory, you should be judicious when organizing chunks and their contents accordingly.
Under the hood, two major components are involved in this process:
- UAssetManager - A singleton for accessing game assets.
- FGenericPlatformChunkInstall - An interface that’s used as the base for installing and mounting chunks – any chunk install plugin will implement this.
The Asset Manager will look for the chunk that an asset belongs to when you try to load it. It incorporates the GenericPlatformChunkInstall interface when it looks for chunks, and if you enable **bShouldAcquireMissingChunksOnLoad, **it will make a call to your chunk installer to download missing chunks when needed. It’s more ideal to know upfront which chunks you’re going to need and have them downloaded and mounted ahead of time, but for really piecemeal loading it can be helpful. You can extend both AssetManager and PrimaryAssetLabels to add custom logic and data for how you want to load chunks.
If it sounds like a lot of this depends on game-specific or platform-specific implementation, it’s because it does. Google PAD manages to automate a lot of the more basic features, natively includes asset pack types, and includes a Blueprint function library that makes its patching more accessible, but it’s specific to Google’s platform. HTTPChunkInstaller is more generic, so you need to fill in a lot more blanks in terms of accessing the remote service for your patches, monitoring progress, and organizing chunks.
Both Google PAD and HTTPChunkInstaller are “some assembly required;” they offer libraries of utility functions, and it’s up to you to decide where you should implement your solution and how to organize it, which is admittedly not super-easy without an example to follow. GameInstance makes for a place where you can handle universal or startup patching needs, while a Game Mode that implements requests for chunk downloads could act as a middleman for loading screens and the like. It’s helpful in those instances to implement a custom AssetManager class that can discern what chunks are necessary when you want to load a new level or do anything similar, then transition to the “loading mode,” then transition to the desired map once all necessary information is loaded. However your game is organized, though, that can vary quite a lot.
Hopefully that at least gives you an idea of where to start looking! In the meantime, I’m going to keep working on this and see if I can provide a more thorough walkthrough with HTTPChunkInstaller soon.