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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question Is it possible to create new entities for a subscene during conversion?

Discussion in 'Entity Component System' started by PublicEnumE, May 22, 2021.

  1. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    I'm trying to write a ConversionSystem which can create new entities that get saved as part of a subscene - to store some metadata about the subscene.

    Here's a simple test system which attempts to create a new entity as part of the subscene, during conversion:


    Code (CSharp):
    1. [UpdateInGroup(typeof(GameObjectBeforeConversionGroup))]
    2. class SubsceneEntityCreationTestSystem : GameObjectConversionSystem
    3. {
    4.     protected override void OnUpdate()
    5.     {
    6.         Entity testEntity = DstEntityManager.CreateEntity(new ComponentType(typeof(TestComponent)));
    7.     }
    8. }
    However, when I run the subscene through conversion, the entity is not created. This error appears in the console for the subscene:


    Warning: 1 entities in the scene 'Test01' had no SceneSection and as a result were not serialized at all.


    Is it possible to create new entities for the subscene as part of conversion?

    I saw this helpful thread:

    https://forum.unity.com/threads/subscenes-help-with-live-link.699470/

    In which
    CreateAdditionalEntity()
    was discussed. But that works by cloning an existing GameObject from the scene, and then using it's resulting entity. I don't need to associate this entity with any GameObject - I'd like to create a new entity which exists independently of a GameObject in the subscene, only to store some metadata about several objects.

    Thanks for any advice.
     
    Last edited: May 22, 2021
    forteller and Tony_Max like this.
  2. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Alternately:
    • Is it possible to gain access to a ‘scene root’ entity that’s part of a Subscene, and add Components to it?
    • Or, is it possible to add new GameObjects to the subscene as part of the conversion process? And then grab their primary entity to use from there?
     
    Last edited: May 22, 2021
  3. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
  4. apaxnid

    apaxnid

    Joined:
    Nov 18, 2012
    Posts:
    34
    I think BlobAssetReferences are not supported in this type of components because there is no system that manages BlobAssets outside of subscenes.
     
    PublicEnumE likes this.
  5. Sunstrace

    Sunstrace

    Joined:
    Dec 15, 2019
    Posts:
    40
    i dont know why but better not to create entites during conversion.make it as prefab and use IDeclareReferencedPrefabs interface.
     
  6. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Thank you, but I’m not sure this is really a case that can/should be solved with Prefabs. I want to collect some metadata about many objects in the Subscene, store it in a BlobAsset, and then store a BlobAssetReference to it in a dedicated entity in the Subscene itself.

    And all of this should only happen if there are certain Component types in use in the Subscene. If not, no metadata would be collected.

    I’d really like to avoid needing to ask our devs to remember to place a “metadata” GameObject inside the Subscene before it’s converted. That seems error prone, and also shouldn’t be necessary.

    Reasonably, it should be possible to create an entity (or an external asset like a ScriptableObject or JSON file) to hold that metadata during conversion, and only if it’s needed. That kind of automated metadata collection during a ‘build’ step is a pretty common use case in game dev.

    A common use case might be:
    • You have 5 Subscenes in your game which represent parts of a farm.
    • Each Subscene can have some unbounded number of Sheep, placed by the designers.
    • You want to allocate a NativeArray at runtime, large enough to hold references to all the sheep.
    In this case you could run all of your Subscenes through a build step, collect the number of sheep in each one, and then save that data somewhere, like on an external JSON file. Then at runtime you could collect that data and use it to size your array.

    Conversion for Subscenes doesn’t seem to easily allow for writing to an external file like that. It seems to go against the grain of how Unity wants us to use Subscenes. So I’m looking for ways to store that metadata in each Subscene itself - for example, in a SheepDataBlobAsset asset. It’s an ok fallback, for us to resize the array each time one of the Subscenes is loaded, by grabbing the ‘sheepCount’ value in that blob asset.
     
    Last edited: May 23, 2021
  7. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Thanks, this makes sense. I hadn’t figured that the ‘SceneSection’ entity wasn’t saved as part of the Subscene itself.
     
  8. apaxnid

    apaxnid

    Joined:
    Nov 18, 2012
    Posts:
    34
    Your sheep case is totally doable, every scene section will have TotalSheep component which is basically a counter of how many Sheep entities are in subscene section
    Code (CSharp):
    1. using Unity.Entities;
    2.  
    3. public struct TotalSheep : IComponentData
    4. {
    5.     public int Value;
    6. }
    7. public class SheepConversionSystem : GameObjectConversionSystem
    8. {
    9.     protected override void OnUpdate()
    10.     {
    11.         var sheeps = GetEntityQuery(typeof(Sheep)).ToComponentArray<Sheep>();
    12.         foreach (var sheep in sheeps)
    13.         {
    14.             var sheepEntity = GetPrimaryEntity(sheep);
    15.             var sectionEntity = GetSceneSectionEntity(sheepEntity);
    16.             if(DstEntityManager.HasComponent<TotalSheep>(sectionEntity))
    17.             {
    18.                 var totalSheep = DstEntityManager.GetComponentData<TotalSheep>(sectionEntity);
    19.                 totalSheep.Value += 1;
    20.                 DstEntityManager.SetComponentData(sectionEntity, totalSheep);
    21.             }else
    22.             {
    23.                 DstEntityManager.AddComponentData(sectionEntity, new TotalSheep
    24.                 {
    25.                     Value = 1
    26.                 });
    27.             }
    28.         }
    29.     }
    30. }
     
  9. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    The Sheep example is not my real example. Unfortunately, the data I need to store can’t be stored in an IComponentData. It would require DynamicBuffers or BlobArrays. :/

    Any ideas?
     
  10. apaxnid

    apaxnid

    Joined:
    Nov 18, 2012
    Posts:
    34
    Every subscene has SceneGUID, you can get it at conversion time, implement your own structure, or at very least use hashmap and you can store whatever you like, your limit is your imagination;)
     
  11. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    I really appreciate your comments, and your code example before.

    About this quote - I am not so sure it’s that easy. That’s what I first set out to do. But I ran into a few unforeseen limitations, due to how Subscenes are implemented:

    Limitations if you’re looking to save a custom external file with your metadata:
    1. Subscenes are converted on an background editor thread, and AssetDatabase APIs will often fail. That rules out using ScriptableObject - not a blocker, but definitely would have been nice, given their general support inside of Unity.
    2. Writing out a JSON file using System.IO libraries is still an option. But doing it this way may mess with your ability to bundle your metadata using Addressables (which don’t work with DOTS yet anyway), or using the older Resources.Load approach. That’s because Subscenes are sometimes converted in the editor after you enter play mode.

    It seems like Unity would be much happier if you stored all data related to a Subscene inside the Subscene itself. But to do that, you’d run into these problems:

    1. No way to create and serialize new entities as part of the conversion process (without basing them on a preexisting GameObject).
    2. No way to store BlobAssetReferences in Components that are attached to the SceneSection.
    So I’m not sure it’s possible to serialize out your own structure using the sceneGUID, or to store your metadata in the Subscene itself - not without making some pretty clunky compromises.

    Did you have anything in mind that I’ve missed? I mean it - I would love to know that I’m missing an option here!

    Many thanks.