Modding FAQ for the Asset Bundle update post 0.217.40
March 12, 2024
Versions 0.217.40 and later of Valheim has moved from using Unity's standard asset management to using a custom asset management system called Soft Referencable Assets that loads assets via Asset Bundles. This enables the game to load and unload assets on the fly, rather than always keeping everything in memory, which saves massive amounts of RAM.
To assist the modding community in this transition, we've collected some common questions and answer them here.
Which assets are affected by this change?
All assets in the entire game are now stored in Asset Bundles rather than "level" and "sharedassets" files. However, this in and of itself doesn't affect when assets are loaded into memory. So far only Locations (in ZoneSystem and LocationList components) and Rooms (stored in DungeonDB, utilized in DungeonGenerator) are loaded and unloaded dynamically. ObjectDB and ZNetScene remain unaffected for now and always keep their assets in memory, just like before. The plan is to dynamically load and unload the assets in ObjectDB and ZNetScene eventually too, but that will come in a later update.
How is the new asset management system integrated into the game?
The Soft Referenceable Assets system is self-contained and included in a separate assembly. Valheim's scripts use the various types and function calls in this assembly in order to load and unload assets and scenes from the built Asset Bundles.
Assets are referenced by a 128-bit AssetID
. This ID is the same as the GUID
generated for each asset by the Unity Editor. When the Soft Referenceable Assets system builds Asset Bundles, it generates manifest files that maps each asset's AssetID
to the Asset Bundle they're stored in and their path within that Asset Bundle. The manifest files also contains dependency data for each Asset Bundle that has dependencies to other Asset Bundles.
The SoftReference<T>
struct and its member functions are used to load and unload assets. T
is the type of the object being referenced, so for example a reference to a prefab would be SoftReference<GameObject>
. The SoftReference<T>
struct doesn't hold state; it only acts as an interface to the global asset management system. In other words, if two SoftReference<T>
instances load the same asset, the asset will be loaded once and both SoftReference<T>
instances will point to the same asset. Reference counting is used to determine the lifetime of the loaded asset. More specifically:
* SoftReference<T>.Load()
- Increments the reference counter and loads the asset synchronously.
* SoftReference<T>.LoadAsync()
- Increments the reference counter and loads the asset asynchronously.
* SoftReference<T>.HoldReference()
- Increments the reference counter, but doesn't implicitly load the asset.
* SoftReference<T>.Release()
- Decrements the reference counter and, if the reference counter hits 0, unloads the asset.
When the reference counter of an asset hits 0, the asset is unloaded. For each function call incrementing the reference counter, there is exactly one matching function call decrementing the reference counter.
My mod relies on certain assets remaining loaded. How do I prevent an asset from being unloaded?
Mods can exploit the reference counting of the Soft Referenceable Assets system to keep assets loaded indefinitely. All they need to do is increment the reference counter of the asset they want to keep loaded one extra time, then never decrement it. Of course, forcing an asset to stay loaded comes at the cost of higher RAM usage.
How do I know which asset is mapped to which
AssetID
?
The SoftReferenceableAssets.Runtime
class has a function called GetAllAssetPathsInBundleMappedToAssetID()
. This function returns a dictionary with one entry for each loadable asset, where the key is the "path" of the asset in the Asset Bundle it's stored in (which is identical to the asset's path in the project) and the value is the AssetID
for that asset. You can parse the asset path to get the file name and file type of the asset.
Please note that the asset path might change during development, so if your mod relies on a certain asset having a certain path, it's likely that an update will break your mod. Names of prefabs that are synchronized across the network should stay same throughout development since the networking system uses the prefab names to identify them. The AssetID
however will always stay the same for each asset even if it's moved or renamed. If you need to reference individual assets, it's best to parse the dictionary during development to find the AssetID
's of the assets you need to reference, then store those AssetID
in your shipped mod.
A certain asset in the vanilla game is a dependency of my mod. Is it possible to individually load that asset?
Yes, we added support for invidivudally loading any asset in the game after discussing this update with the modding community. The game includes two manifest files in the Valheim_Data/StreamingAssets/SoftReferenceableAssets folder, one called manifest
and another one called manifest_extended
. The manifest
file contains all data required to load assets that are referenced by AssetID
in the vanilla game. The manifest_extended
file contains all additional data required to load any asset by AssetID
, including assets that are only dependencies of other assets.
By default, only the manifest
file is loaded, because it's the only file needed for the vanilla game. However, if you call Runtime.MakeAllAssetsLoadable()
before the Soft Referenceable Assets system is initialized (before the EntryPointSceneLoader.Start()
function in this case), the manifest_extended
file is loaded too. You can then individually load any asset using SoftReference<T>.Load()
or SoftReference<T>.LoadAsync()
(and remember to unload it using SoftReference<T>.Release()
when you no longer need it).
It's worth noting that Asset Bundles are packed in a way that is optimized for the vanilla game, so memory usage and load times are not as efficient when loading vanilla assets that are not referenced by AssetID in the vanilla game.
Can I load Asset Bundles from my mod via the Soft Referencable Assets system?
Yes! Assuming that you ship your Asset Bundles as files, you can load them via the Soft Referenceable Assets system.
Each Asset Bundle is uniquely identified internally by its file name. You can name your Asset Bundles anything you'd like; just make sure you give them names that are unlikely to conflict with the vanilla game or other mods. Vanilla assets always take precedence in case of conflicts.
Export your appropriately named Asset Bundles to a folder, packed in any way you like. The system supports any asset packing layout, since the locations of assets and bundle dependency data is specified inside of a manifest file.
The next step is to create said manifest file for your Asset Bundles. Manifest files are stored in a YAML-like text format, though in contrast to true YAML, order matters. See the manifest files included with the vanilla game and the SoftReferenceableAssets.AssetBundleManifest
classes for reference. We've explicitly included the AssetBundleManifest.SerializeToDisk(string path, SerializationFormat format)
function in the player build to make this a bit easier.
Provide the absolute path of your custom manifest file to the Soft Referenceable Assets system by calling Runtime.AddManifest(string manifestPath)
before it's initialized (before the EntryPointSceneLoader.Start()
function in this case). Manifest files added this way are then loaded alongside the vanilla manifest files when the Soft Referenceable Assets system is initialized.
After that, you can load your mod's assets by their AssetID
, with all of the same reference counting and dependency management features of the vanilla game.
Social
Community
Valheim is still growing, and the community is an important part of the development. Join the fanbase by following our social channels, joining our Discord, or signing up for our official newsletter.
Newsletter