Using the Asset Manager

Explanation of the purpose of the Asset Manager and tips for using it

Updated about 3 years ago Edit Page Revisions

This page was originally written as a companion to the Inside Unreal: Asset Manager Explained educational livestream by the primary presenter in that video. That video has more detail about some of the topics discussed below

What is the Asset Manager?

The Asset Manager is a tool built into the engine to help with categorizing, loading, and shipping complicated asset data. It is a singleton global UObject that works like an Engine Subsystem (but was written before those existed), so it is not map or mode specific. It categorizes and queries unloaded assets using the Asset Registry, maintains global asset loading state, integrates existing systems like cooking and async loading, and was explicitly designed to be overridden by games. The Asset Manager was originally created to help deal with managing lots of inventory item definitions for games with RPG elements. It was designed to hide blueprint class complexity, deal with long load times and high memory usage, help fix hitches caused by synchronous loading of hard references, handle different game/menu/network loading states, and set up complicated packing and chunking rules for releasing on different platforms.

There are a few primary components:

  • Primary Asset Type (FPrimaryAssetType) is a unique type like "melee weapon" that indicates a type of things that are loaded or identified at a global level in your game. A Map/Level is the only default primary asset type

  • The Primary Asset Identifier (FPrimaryAssetId) uniquely identifies a single Primary Asset instance, such as "Masterwork Axe"

  • Primary Asset Rules (FPrimaryAssetRules) describe the types of rules applied to primary assets for cooking, chunking, etc

  • The Asset Manager Settings (UAssetManagerSettings) are where type mappings are set up specifying how to search for primary asset content

  • Secondary assets are any UE4 asset that is not a Primary Asset, such as texture or static meshes

The official documentation goes into more detail about how to set up types and use the basic operations.

Example Usage

The Action RPG sample uses the Asset Manager so the examples are based off of that sample. For an example of how to use the Asset Manager from Blueprints, here is part of the BP_GameInstance blueprint:

In this example, it iterates over a list of Primary Asset Types, asks the manager for all Ids of that type, starts an async load of each id/primary asset, and when that is completed iterates over the list of loaded assets to add to an array on the game instance. This shows how you can use primary asset ids to avoid having hardcoded references to lots of items in your blueprints/code.

For an example of how to use the Asset Manager from code, here is a code snippet that could be added to the RPGAssetManager.cpp file:


void URPGAssetManager::AssetManagerExample()
{
	// Get the global Asset Manager
	URPGAssetManager& AssetManager = URPGAssetManager::Get();

	// Get a list of all weapons that can be loaded
	TArray<FPrimaryAssetId> WeaponIdList;
	AssetManager.GetPrimaryAssetIdList(WeaponItemType, WeaponIdList);

	for (const FPrimaryAssetId& WeaponId : WeaponIdList)
	{
		// Get tag/value data for an unloaded weapon
		FAssetData AssetDataToParse;
		AssetManager.GetPrimaryAssetData(WeaponId, AssetDataToParse);

		FString GameplayTagString;
		FGameplayTag LoadedTag;
		AssetDataToParse.GetTagValue(GET_MEMBER_NAME_CHECKED(URPGItem, ExampleRegistryTag), GameplayTagString);

		LoadedTag.FromExportString(GameplayTagString);

		FName QueryExample;
		AssetDataToParse.GetTagValue(GET_MEMBER_NAME_CHECKED(URPGItem, ExampleRegistryTag), QueryExample);

		UE_LOG(LogTemp, Log, TEXT("Read ExampleRegistryTag %s from Weapon %s"), *QueryExample.ToString(), *AssetDataToParse.AssetName.ToString());
	}

	// Permanently load a single item
	TArray<FName> CurrentLoadState;
	CurrentLoadState.Add(FName("Game"));

	FName WeaponName = FName("Weapon_Hammer_3");
	FPrimaryAssetId WeaponId = FPrimaryAssetId(WeaponItemType, WeaponName);
	AssetManager.LoadPrimaryAsset(WeaponId, CurrentLoadState, FStreamableDelegate::CreateUObject(&AssetManager, &URPGAssetManager::CallbackFunction, WeaponId));

	
	TArray<FPrimaryAssetId> ListOfPrimaryAssetIds;
	AssetManager.GetPrimaryAssetIdList(SkillItemType, ListOfPrimaryAssetIds);
	
	// Load a list of items as long as Handle is alive
	TSharedPtr<FStreamableHandle> Handle = AssetManager.PreloadPrimaryAssets(ListOfPrimaryAssetIds, CurrentLoadState, false);

	// Store Handle somewhere
}

void URPGAssetManager::CallbackFunction(FPrimaryAssetId WeaponId)
{
	URPGWeaponItem* Weapon = GetPrimaryAssetObject<URPGWeaponItem>(WeaponId);
	
	if (Weapon)
	{
		UE_LOG(LogTemp, Log, TEXT("Loaded Weapon %s"), *Weapon->GetName());
	}

	// Release previously loaded item
	UnloadPrimaryAsset(WeaponId);

}

That example goes through several types of operations you can do with the Asset Manager from C++

Advanced Uses

The accompanying video and documentation goes through some advanced uses in more detail, but here's a summary of other ways you can use the asset manager:

  • Use Asset Bundles to load secondary assets linked via soft references when loading in specific game modes like menu/gameplay

  • Use Primary Asset Labels to assign chunk ids to all assets managed by a specific Primary Asset

  • Override functions like ModifyCook in a game-specific subclass to override cooking behavior. Most of the functions in AssetManager.h are able to be overridden

  • Use the Reference Viewer, Asset Audit and Size Map tools to analyze your project's asset dependencies

  • Build a game-specific loading state machine into a subclass

  • Use bundles or the provided utility functions to preload assets before a static map change/reload

  • Use bShouldAcquireMissingChunksOnLoad to interface with the ChunkDownloader or game-specific patching mechanism

  • Write game-specific reports commands like DumpReferencersForPackage