So as you may know, the Asset Manager was officially taken out of early access in 4.17 as “a unique, global object that exists in the Editor as well as in packaged games, and can be overridden and customized for any project. It provides a framework for managing Assets that can divide content into chunks that make sense in the context of your project, without losing the advantages of Unreal Engine 4’s loose package architecture.”
You may read more about the Asset Manager in the official documentation, as well as in this 136465-.
If you want to be up to speed really quickly about the Asset Manager, it roughly goes like this:
You have Primary Assets and Secondary Assets.
Primary Assets are UObjects that override the GetPrimaryAssetId() function (keep that in mind, this is important), and that you may want to explicitly tell to load at some point.
Secondary Assets are the assets that are “referenced or used by” Primary Assets and that will be brought along as you load the related Primary Assets.
By default, only Maps are Primary Assets.
If you want to have more types of Primary Assets, you have to** implement the GetPrimaryAssetId() function for their class in C++.**
The only exception to this rule is for Dynamic Assets, which are Primary Assets created at runtime. For those, you provide the PrimaryAssetId when you register them in the Asset Manager, so you don’t need to override GetPrimaryAssetId(), because that’s not where it will get the id from anyway.
There is this notion of “Asset Bundles” that pops up in the documentation from time to time, which is in my opinion poorly explained. It seems that asset bundles are another way of loading a bunch of assets (the first way being loading one or more Primary Assets). You tag **UPROPERTIES **as (meta = (AssetBundles = “Something”)) to include them in a bundle, which you can then load.
You don’t load bundles directly, you give the asset manager a list of currently loaded bundle names, a list of all the bundle names that you intend to have loaded (new and remaining) in the near future, and it spits out a list of the Primary Assets that you need to load. It’s kind of the delta between the two if you wish.
What I don’t fully understand:
- Bundles seem to be an alternative implementation of Primary Assets, as they are in essence also an entity that references a bunch of Secondary Assets (but somehow you also need to associate a bundle with a primary asset?).
- The documentation even goes as far as to title a paragraph with a title involving “Primary Assets”, then switches mid paragraph to talking about Asset Bundles, which is very confusing and happens multiple times. So either they are interchangeable, or they are meant to be used together / cover the same use cases.
- Some functions take a list of primary assets and a list of bundles in order to load / unload them (also for the creation of a Dynamic Asset), and apparently some of those properties (the list of primary assets or the list of bundles) are optional, but it’s not clearly explained.
What I either don’t understand properly or is a bad implementation:
- The way the asset manager works is different in the editor and in packaged mode (and I’m not talking about cooking issues). On one hand this is great, as any differences in how to manage assets are handled for you. On the other hand, you pretty much have to package your game every time you change something, because you can’t actually be sure that what you see in the editor will still work. This is somewhat the case for all aspects of game development, but the issues seem to occur way more often here.
- The Asset Manager seems to have been created with a niche use in mind (The post linking the pre-release PDF only mentions it being useful for people building “a complex game with RPG elements”), even though it’s now presented as being more broadly useful.
- However, this usefulness is all relative, as it seems like you basically have to edit all your UPROPERTIES to include a bundle name, and/or find a way to reference all your assets from one or more types of Primary Assets.
- Artists and designers can apparently reference assets from a Primary Asset directly from the editor, which means that you have to manually enter them… one by one?? You can also implement the Primary Asset logic directly into an existing actor, etc… But then you need to revamp all your actors types, manage references, bundles, etc… Not much better.
- If your game is very static, with a bunch of assets that needs to be loaded at predictable times and in cleanly delimited predictable groups, then the Asset Manager seems to have been made for you. Otherwise… Not so much.
What I want:
I initially planned to have an Asset Management system that would simply receive an FName containing the name of the asset that I want to load, using the type-appropriate function (GetMaterial, GetTexture, etc…). I already have an implementation of that using ObjectLibraries, which at game launch scans specific folders for specific classes, and keeps maps of <FName, FAssetData> at hand, in order to provide or load assets as needed.
USoundCue* SoundCue = RessourcesManager->GetSound("UI_Click_03"); // Simple as that.
This is a synchronous call so either the assets are small enough that it doesn’t matter, or I have pre-loaded them beforehand to avoid hitches.
The issue with that is that apparently it works very poorly in the editor, as I’m having a hard time to find a system that works in PIE, out of PIE, and that keeps working in between level changes (or all of that in any order).
Using the Asset Manager to do that felt possible for about five minutes, until I realized that** UTexture2D, USoundCue, etc… Do not have an implementation of GetPrimaryAssetId()**, and so will not work as a Primary Asset. This is a shame because otherwise the asset manager would nearly be perfect for me out of the box.
Instead, I have tried to scan my folders with an object library, and create Dynamic Assets at runtime when the game starts. This may sound silly as Dynamic Assets are supposed to not have a disc representation, but this way I can specify their PrimaryAssetId without having to change the engine code for lots of base asset classes.
This works great in the editor, but in packaged game nothing loads. Or rather, between the time where the Asset Manager loads the assets, and the time where I start using them, all the FAssetData are no longer valid. (This is not a cooking issue as my .pak file size hasn’t changed since I’ve started using the asset manager)
At first it felt like my needs were being very reasonable and very common (I just want a way to load an asset on demand by giving the asset manager the asset’s name), but after seeing the way the Asset Manager is implemented, I’m starting to doubt my judgment. So:
- Is there a standard and battle-hardened way of handling the loading and unloading of assets in games?
- How are YOU doing the asset management in your game?
- Surely this problem must be common accross all platforms, game types, etc… Unless most games made around here do not have a RAM footprint worth reducing?
Thank you for your attention,