Am I Understanding Asset Bundles Correctly? (Asset Manager/Primary Data Assets)

I’m trying to wrap my head around Asset Bundles when using the Asset Manager and Primary Assets. There seems to be very little information about this system (most of what I find just tells me that “Asset Bundles” exist and a string can be passed to UAssetManager::LoadPrimaryAsset, but not what that does exactly.)

My current understanding is that you can tag soft object/class pointer member variables with a “bundle” tag, and when you pass the respective bundle tag while loading that asset through UAssetManager::LoadPrimaryAsset, it will go through the primary data asset and only load variables that are tagged with the matching bundle(s) – effectively only partially loading the primary data asset.

Is this correct? Or is this a gross misunderstanding of the system?

If it is correct, how do I go about retrieving the data of those particular member variables without async loading them again? When the Primary Data Asset is loaded, I’d like to use the data that was requested with it and not have to daisy-chain delegate calls to retrieve each individual asset. Is it safe to perform a blocking load at that point to dereference the soft path into its contents?

Thank you!

2 Likes

You’re mostly there. There are two different things going on: Loading a primary asset, and requesting bundle changes.

So three different things could be happening:

  1. LoadPrimaryAsset( X ) - Loading of a primary asset
  2. LoadPrimaryAsset( X, { "bundlename1", ... } ) - Loading of a primary asset & requesting bundles
  3. ChangeBundleStateForPrimaryAssets( { X, ... }, { "bundlename1", ... } ) - Requesting bundles on an already loaded primary asset.

In any case the Primary Asset X is completely loaded, either because it’s loaded already or it was loaded with a call to LoadPrimaryAsset. Some of the soft pointer members may be null. Calling this partially loaded might be a misnomer. I prefer to say that X is loaded but it’s assets or content are not. This means that every non-pointer and hard-reference pointer will be loaded and filled in.

If you provide any bundles to LoadPrimaryAsset or ChangeState then it will load all the assets referred to by soft pointers with that bundle metadata.

Both LoadPrimaryAsset and ChangeState take delegates and return streamable handles. You can use either one to check if the loading is finished. When it is, the content referenced by the soft pointers should be loaded and you should be able to access them with simple calls to Get. If they’re still null then they’re probably None in the actual data.

If you’re trying to access a soft pointer that wasn’t in one of the bundles that you’ve specified, then you’d have to either manually async load it or load whatever bundle it’s in.

One major difference between the two options is that when loading a soft object yourself (either synchronously or asynchronously) you’ll have to stash the pointer to the loaded asset somewhere to prevent the garbage collector from getting rid of it. However when you load those assets through bundles, the AssetManager keeps that reference for you until you call ChangeState to unload that bundle on that asset. I think unloading the primary asset will also unload any bundles it had loaded, it would make sense, but I’m not 100% sure since I don’t really use them that way.

7 Likes

There is difference between loading PrimaryAsset and whatever is contained within.

Example - you have one int and one hard reference UObject pointer as member variables of said asset.

Loading this kind of asset means ue will fill your int variable and pointer variable with valid values.

But bundles allow you to specify which soft pointers should be filled in with valid values as well.

So the answer, how to load PrimaryAssets differs depending on the usage. If you want to have all of the data available everytime you load an asset you want to have hard references and non pointers as members.

If you want to load only some data which will help you during filtering or something and load an actual object/actor/class later, then bundles or manual loading is the way to go. Keep in mind that loading PrimaryAsset with e.g. FSoftObjectPath will fill this variable with valid values, but object which it points to won’t be loaded until it is either within a bundle or loaded manually.

4 Likes

Thank you both! That does clear up a lot of the questions I had regarding the system!

This actually addresses another question I had and was going to ask! Thank you very much!