Unreal Engine - The Asset Manager, Primary Assets and Asset Bundles
Loading only the desired assets
Introduction
As the data for a game grows in size and complexity, it is important to load only what is needed given the player’s context. For the assets that won’t be managed automatically, Unreal Engine provides an Asset Manager that facilitates loading and unloading of assets manually. Combining the concepts of Primary Assets and Asset Bundles, subsets of these assets can also be loaded depending on the context.
Example
Consider a game that has dozens of characters from which a player can choose. Characters could be described by a data asset. This data asset could have a texture of the character’s portrait to display in a lobby screen, a localized name, a blueprint to use as a pawn in game, and dozens of additional pieces of data and assets. The following code is an example of how that might be set up:
Asset Bundles
Whenever a data asset of this type is loaded, it is also going to load every asset it references, even in a context where those assets might not be used. For example, the game may be designed such that the pawn blueprint isn’t used in the lobby. To address this wasteful loading time and memory usage, assets can be associated with Asset Bundles within Primary Assets. Here is the same object definition using Asset Bundles that adds context to the different assets to be loaded


The three different ways the data will be loaded are:
CharacterLobbyPortrait is only loaded if the Data Asset is loaded with the Lobby Asset Bundle
CharacterGamePawnClass is only loaded if the Data Asset is loaded with the Game Asset Bundle
CharacterName is not an asset and will always be loaded
Notice the property types of the objects that are associated with Asset Bundles. Instead of being TObjectPtr and TSubclassOf, they are now TSoftObjectPtr and TSoftClassPtr respectively. Internally, these contain paths to the asset and a pointer to that asset in memory if valid. TObjectPtr and TSubclassOf are ‘Hard’ references, and will always be loaded when their owning assets are loaded.
In order for the Asset Manager to load the Asset Bundles requested, the owning object must be a Primary Asset.
Primary Assets
In order for AssetBundlesCharacterData to be considered a Primary Asset and discovered by the Asset Manager, the following must be done:
Overload the GetPrimaryAssetId function from UObject and return a unique Id based on the type and asset
This is handled automatically when deriving from UPrimaryDataAsset instead of UDataAsset
Note: Deriving from UPrimaryDataAsset also adds support for Asset Bundles
Add the new Asset Type in Project Settings → Game → Asset Manager
Interacting with the Asset Manager
Here is an example of a ViewModel that loads all of the AssetBundlesCharacterData Data Assets with different Asset Bundles.


Note: The ClearCharacterData function forces garbage collection for demonstration purposes so that all assets that are no longer referenced are immediately deleted.
Asset Bundles in Action
Here is an example instance of an AssetBundlesCharacterData instance and the results of running a UI with the ViewModel above.
Conclusion
Loading data when it’s not needed will increase loading times, memory footprint, and negatively affect players. It is important to understand what is loaded and when. Using the Asset Manager correctly is specific to each game and a necessary tool for the engineers to learn.
Example code can be found here.
Example assets can be found here.
Did you order the pizza yet?