Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Prefab References in Blob Assets Created in Bakers

Discussion in 'Entity Component System' started by JohnnyTurbo, Nov 24, 2022.

  1. JohnnyTurbo

    JohnnyTurbo

    Joined:
    May 17, 2017
    Posts:
    36
    Hello All! I recently noticed some interesting behavior when creating a blob asset with an entity prefab reference in a baker. Not sure if this is a bug, a limitation, or if I just am doing something incorrectly.

    I can create the blob asset without any issue, but when I go to spawn the referenced prefab, it instead spawns another instance of some arbitrary system entity. Change out the referenced prefab and a different arbitrary system entity. Here is what the entity hierarchy looks like after I try to spawn a few of the referenced prefabs:
    upload_2022-11-23_19-44-15.png

    Here is the code to reproduce:

    Code (CSharp):
    1. public struct PrefabReference : IComponentData
    2. {
    3.     public BlobAssetReference<Entity> Value;
    4. }
    5.  
    6. public class BlobAssetMono : MonoBehaviour
    7. {
    8.     public GameObject Prefab;
    9. }
    10.  
    11. public class BlobAssetBaker : Baker<BlobAssetMono>
    12. {
    13.     public override void Bake(BlobAssetMono authoring)
    14.     {
    15.         var builder = new BlobBuilder(Allocator.Temp);
    16.         ref Entity prefab = ref builder.ConstructRoot<Entity>();
    17.         prefab = GetEntity(authoring.Prefab);
    18.         var prefabReference = builder.CreateBlobAssetReference<Entity>(Allocator.Persistent);
    19.         builder.Dispose();
    20.          
    21.         AddComponent(new PrefabReference{Value = prefabReference});
    22.     }
    23. }
    Then to test I just have a super simple system to spawn referenced entities:

    Code (CSharp):
    1. public partial class TestSpawner : SystemBase
    2. {
    3.     protected override void OnUpdate()
    4.     {
    5.         if (!Input.GetKeyDown(KeyCode.Space)) return;
    6.         var prefab = SystemAPI.GetSingleton<PrefabReference>().Value.Value;
    7.         EntityManager.Instantiate(prefab);
    8.     }
    9. }
    Creating the blob asset through a baking system yields the same result. In that case I first use the baker to populate a data component with the entity reference then create the blob asset in the baking system.

    Code (CSharp):
    1. public struct PrefabReference : IComponentData
    2. {
    3.     public BlobAssetReference<Entity> Value;
    4. }
    5.  
    6. public struct PrefabData : IComponentData
    7. {
    8.     public Entity Value;
    9. }
    10.  
    11. public class BlobAssetMono : MonoBehaviour
    12. {
    13.     public GameObject Prefab;
    14. }
    15.  
    16. public class BlobAssetBaker : Baker<BlobAssetMono>
    17. {
    18.     public override void Bake(BlobAssetMono authoring)
    19.     {
    20.         AddComponent(new PrefabData{Value = GetEntity(authoring.Prefab)});
    21.     }
    22. }
    23.  
    24. [WorldSystemFilter(WorldSystemFilterFlags.BakingSystem)]
    25. public partial class BlobBakerSystem : SystemBase
    26. {
    27.     protected override void OnUpdate()
    28.     {
    29.         var builder = new BlobBuilder(Allocator.Temp);
    30.         ref Entity prefab = ref builder.ConstructRoot<Entity>();
    31.         var entity = GetSingletonEntity<PrefabData>();
    32.         prefab = GetSingleton<PrefabData>().Value;
    33.         var prefabReference = builder.CreateBlobAssetReference<Entity>(Allocator.Persistent);
    34.         builder.Dispose();
    35.  
    36.         EntityManager.AddComponentData(entity, new PrefabReference { Value = prefabReference });
    37.     }
    38. }

    This case it was creating system entities for the Export Physics World:
    upload_2022-11-23_20-10-11.png

    Any thoughts on this? Thanks and happy Thanksgiving!
     
    Emanx140 likes this.
  2. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    939
    The entity in the baking system is not the same entity you have in runtime.
    There is a behind the scene remapping there is a behind the scene remapping that happens for components that have an entity reference but that does not work for blobasset since they are read only after the creation of the reference.
    So your Entity in you blob asset is just any 2 int and you end up with that entity at runtime and not the one you expect.

    You can log the entity while baking to see that you don't have the same reference as your runtime prefab.

    I actually cover this has the number 1 caveats of blob assets in my video
     
    Last edited: Mar 1, 2023
    JohnnyTurbo likes this.
  3. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    You can't store Entities inside blobs, as entities remapping wouldn't affect them, as result it will leads to behaviour you see (under Index:Version of your entity in blob there is already entity in the World which will be spawned) or Entity does not exist error.
     
    JohnnyTurbo likes this.
  4. davenirline

    davenirline

    Joined:
    Jul 7, 2010
    Posts:
    943
    I had this problem. The solution is to store the entity in ECS whether in components or dynamic buffer. We are using a custom fixed length hashmap that can be declared in a component.
     
    JohnnyTurbo likes this.
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    Related because I saw someone run into this yesterday, you also can't store Entities in SharedComponents in baking.

    I believe only IComponentData and IBufferElement supports entity remapping.
     
    JohnnyTurbo, toomasio and WAYNGames like this.
  6. JohnnyTurbo

    JohnnyTurbo

    Joined:
    May 17, 2017
    Posts:
    36
    Great thank you for the responses all - that is very helpful! Now if I generate the blob asset at runtime, I can spawn the desired prefab from the blob asset no problem. Is that fine or something I should avoid as that could lead to other problems down the line?
     
  7. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    939
    As long as you only store prefab entities you should be fine.
    There is no reason for a prefab entity to change so the index and version will remain the same for the whole application life time.

    For any other entity any structural change (add/remove component) will invalidate the index and version leading to issues.

    Same goes for destruction of the entity.

    I don't think you are using it but for NetCode your entity will also naturally be different in the server world and client World.
     
  8. JohnnyTurbo

    JohnnyTurbo

    Joined:
    May 17, 2017
    Posts:
    36
    Roger that, thanks for the confirmation!!
     
  9. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    254
    Do you know why SharedComponents can't store Entity references? Is there a reason they can't participate in entity remapping, or is it just not implemented?
     
  10. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,626
    I believe it's probably just because ISharedComponent used to always be managed. I don't think it'd be too hard to make unmanaged ISC remap, probably just overlooked. The TypeManager basically has all the information for handling this which is nice.
     
    Last edited: Nov 27, 2022
  11. Kleptine

    Kleptine

    Joined:
    Dec 23, 2013
    Posts:
    254
    Worth noting that managed components do support Entity Remapping now. Except in Dictionary<K, V> types (although that can be fixed with a simple patch, if you need it).