Spawning prefabs in DOTS - subscenes vs addressables

I’m posting this partially to help other people, and partially to document my findings for my future self.

**IMPORTANT EDIT: Since this post, Unity’s Content Management has replaced these approaches. Skip to this post to see discussions since: Spawning prefabs in DOTS - subscenes vs addressables - Unity Engine - Unity Discussions **

When spawning prefabs such as bullets, enemies, buildings, abilities, etc, the most obvious approach would be to place a generated authoring component on a spawner containing a list of entities to spawn such as:

public struct ThingsToSpawnData : IComponentData
{
    public FixedList128Bytes<Entity> spawnList;
}

This works just fine in the editor, but when you try to build a release version, it will likely fail if you are using subscenes because the resources for those prefabs probably won’t be loaded.

There are four ways to handle the situation that I know of:

1. The Resources folder approach is outdated and I believe that it is at or near end-of-life.

2. The custom authoring approach described here Spawn and Move Prefabs | (v0.50) DOTS Tutorial - Build a Multiplayer AR app probably works okay for small projects. The main problem is that doesn’t really provide a mapping, so it’s not particular useful when you have lots of different prefabs that you want to assign in the inspector and spawn.

3. The addressables package approach involves checking the addressable checkbox in the inspector on the prefabs that need to be spawned, and then using the addressables package for async loading those prefabs at the beginning of the scene. It is possible to build a map, but it is rather difficult because there is no easy way to fetch unique ids/keys for assets or asset references. I found an approach using the PrimaryKey with AssetReference and FixedString32Bytes to setup an ID mapping system that seems to work okay.

  • Advantage: It’s possible to display subsets of prefabs in the inspector for the game designer via AssetReferenceUILabelRestriction.
  • Disadvantage: Addressables and subscenes don’t play very nicely together so assets can get duplicated.
  • Disadvantage: There currently is no way to load a subscene with Addressables.
  • Advantage: There’s a prebuilt way to download new assets/DLC from remote servers.
  • Advantage: It’s easy to add new assets - just check the checkbox and assign a label or two.
  • Disadvantage: Loading is slower than subscenes and building for release is extremely slow.
  • Advantage: Addressables can be used to store all kinds of resources other than prefabs - like AudioClip, ParticleSystem, and Sprite. They can all be easily organized and viewed in the group window.
  • Disadvantage: fetching unique ids and/or labels at runtime is a pain in the butt and hacky. A Unity rep said they have no plans to remedy this.
  • Advantage: textures get compressed which saves disk space and reduces download sizes on mobile platforms.

After a lot of trial and error, I got this approach working.

@eizenhorn wrote about his scriptable-object + global map + addressables approach in a couple of places, although I wasn’t completely able to understand all the details. @WAYNGames used SOs + an asset GUID. I have seen some people talk about making a map via UnityEditor.AssetDatabase.AssetPathToGUID within the unity editor’s OnValidate() function.

4. The subcene+map approach seems to be pretty common in these forums. Some threads that discuss this approach can be found here:

One structure that I have seen people use for storing the map is a permanently allocated NativeHashmap. I opted to use a BlobHashMap in a singleton which makes it easy to access, fast, and easy to check if the map is ready or not via RequireSingletonForUpdate() ( GitHub - bartofzo/BlobHashMaps: Blob asset compatible hashmap and multihashmap for Unity's ECS ).

When I first started with the map method, I tried creating and filling the map during the conversion step (either via inheriting IConvertGameObjectToEntity or GameObjectConversionSystem). This had a huge problem - the IDs of entities (Entity.Index) change twice throughout the conversion process. See my post here: Need Help Understanding SubScenes . Fortunately, @Arnold_2013 tipped me off that the map needs to be built at runtime instead of conversion, which resolved the issue. I had to do some voodoo with making sure all assets were loaded first before building the map, but other than that, it’s working pretty well now.

  • Advantage: There are no duplicate items.
  • Advantage: Everything is self contained in subscenes which are super fast. Building is very fast.
  • Disadvantage: The main disadvantage is that the designer’s work is more difficult because whenever a new item needs to be added, the designer must remember to add an ID/key component to each prefab and he/she must also add the prefab to the list in the subscene. - Edit: I found out that it’s possible to add the prefab/key component automatically, so now the designer only has to add something in one place. It’s still more clumsy then checking the “is addressable” checkbox, but it’s not horrible.
  • Disadvantage: For packaging DLC one would need to develop a custom downloading/remote host mechanism. Maybe this will improve someday?
  • Disadvantage: I wasn’t able to find an easy way to display a subset of available prefabs for the designer to choose from in the inspector - for example: just the bullet prefabs, or only enemy prefabs. I believe that one would have to build a custom inspector to properly filter types for display in the inspector window like with AssetReferenceUILabelRestriction . Edit: I figured out that I can do it with Odin Attributes via [ValueDropdown] or [AssetSelector]. It works okay, but it requires a third party paid asset.
  • Disadvantage: Subscenes can only store prefabs and component types that are on prefabs, so for AudioClips, Sprites, and other types that aren’t normally placed on a prefab, you have to use addressables or find some other way to address them.
  • Disadvantage: There is no handy groups window to manage spawnable assets.
  • Disadvantage: If you want labels like with addressables, you have to build them yourself. I was able to build in labels that can even be accessed at runtime (unlike addressables), but it was rather difficult to do. Mine are more restricted because labels can’t be added or deleted in the editor - they are a mask type in code.
  • Disadvantage: textures don’t get compressed so package file sizes can be very large for mobile platforms.

My implementation with an example can be found here: https://gitlab.com/lclemens/buggy
** compile error can be solved via fixing Unity’s blob asset template bug via the instructions here: Entities 0.17 changelog page-4#post-8267412 .

Conclusion - Overall I think both the addressables and subscene+map approaches are reasonable and I don’t see any massive advantage to one over the other. It does seem like addressables is more mature and feature-complete than subscenes. Ultimately, it will be nice when addressables works with subscenes so both solutions could be combined to get the best of both worlds.

7 Likes

Since I’m currently in the process of “evaluating” ECS and am especially struggling with this topic this helps me a ton. So many thanks for taking the time to post this.

I think “ultimately” the best option would be if UT would develop/document/define a proper method. Since most games require prefabs/assets it’s pretty useless when everyone reinvents the wheel. For such basic functionality something should be built-in IMO. The whole authoring/conversion “workflow” seems pretty bloated to me.

2 Likes

I’m using addressable to delegate the unique id management to it. Having an asset reference game object instead of a game object also takes care of setting the prefab as addressable.
The idea for now is at conversion time I add a component that contains hash of the guid. The at runtime I’ll get all prefab with that component to built the map and discard any duplicate prefab (same hashed Id).
For now the update of the addressable will not trigger the update of the prefab entity since I can’t convert it at runtime (or rather it seems this will be deprecated in futur version, may have misunderstood though…)
The prefab can however be updated through live link ;).
Was planing to play with subscene but it may not be viable yet.

1 Like

How do ya’ll get around loading the different assets without hitching?
At first my idea was to use addressables to load scenes in and out of memory, but whenever assets are loaded it causes a massive spike; even loading a single item.

I’ve tried the different ways mentioned at Loading scenes at runtime | Entities | 0.50.1-preview.2 - but they all hitch the system. When simply using the Scenesystem, it also doesn’t seem to unload from memory.

Reading this and other threats, I’m to understand that assets are to be kept in a list and then spawned from there.

I saw a tut at “Entity Prefab” Management – COFFEE BRAIN GAMES which describes creating a scriptable object with references to the assets/entities. AFAIK all asset references, even in SOs, are loaded into memory at startup.

My hope was to simply have scenes that I can load in and out of memory depending on the location of the player, but without the game hitching.

Is it even feasible? Is there a way to load assets at runtime without spiking/lagging? I have tons of them, so they can’t be preloaded in memory.

@iclemens - I’ve tried opening your project, but get a compile error.

PrefabMapBuilderSystem.cs(52,9): error Assets\Scripts\PrefabMapBuilderSystem.cs(52,9): error ConstructBlobWithRefTypeViolation: You may not build a type PrefabMapBlobAsset with Construct as PrefabMapBlobAsset.map.data.values[ ] is a reference or pointer. Only non-reference types are allowed in Blobs.

I have not been using the scene system so can’t help on that.
For the blob error it exist since 0.17 more about it here
https://discussions.unity.com/t/826008

2 Likes

Yeah sorry, I forgot to mention that Unity has a blob asset template bug that has been plaguing us for over a year. The only way I know of to get around it is by editing the source code via something like the instructions here: https://discussions.unity.com/t/820107 page-4#post-8267412 (it’s the same issue WAYN_Games linked to).

I haven’t noticed any major slowdowns in scene loading, but my levels are really small and they’re not loaded in while the player is running around (only when the player clicks on a new level in the main menu).

It is my understanding that there are two main ways of loading subscenes - the normal way, and the streaming way. I think the streaming way is intended for large open-world games but it is more difficult to implement. In the documentation, there is some info on seamless subscene streaming that I think might be relevant to your situation (if you haven’t already seen it): https://docs.unity3d.com/Packages/com.unity.entities@0.51/manual/loading_scenes.html .

There is also a prefab streaming mechanism that might be be useful?
https://github.com/Unity-Technologi…aster/ECSSamples/Assets/Advanced/EntityPrefab

My main topic in this post is loading prefabs for the purpose of quickly spawning them at runtime (bullets, enemies, etc), whereas I think you’re more interested in loading entire scenes or subscenes.

4 Likes

Has this changed with DOTS 1.0 ? Like the “Content Management” workflow

1 Like

Absolutely. All of this gets thrown out the window with the new Content Management workflow.

So Addressables work with Subscene, both in Editor and at Runtime ? I am new to DOTS, and want to leverage Addressable loading in it.

They don’t. For SubScenes you should use Content Management only.

2 Likes

Do you have any tutorials on content management?

I dont’ know if some tutorial is available but this is the manual’s link:

https://docs.unity3d.com/Packages/com.unity.entities@1.0/manual/content-management-intro.html

2 Likes

I tried it when I first noticed it in the doc but there were still some internal stuff related to building the bundle that I could not make work. When I figure it out I’ll cover it in a video :wink:

6 Likes

Come on

1 Like

I tried the Content Management system and found that after building the project, Load a weakly-referenced scene at runtime will lose the reference, but it can be loaded in the editor. I don’t know if anyone has the same problem as me.

Is there a discussion group to study the use of the Content Management system after building the project

1 Like

I’ll be waiting.

2 Likes

+1

me too. Is it the same problem:
https://forum.unity.com/threads/there-is-a-problem-with-using-the-content-management-and-entityprefabreference-together.1456765/#post-9124894

1 Like