Search Unity

Creating Generic IComponentData using SerializeReference [Solved]

Discussion in 'Entity Component System' started by toomasio, Nov 20, 2020.

  1. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    Hello,

    I made a [SelectableSubType] attribute that I used pretty frequently in Mono land since the birth of the [SerializeReference] attribute.

    looks like this:
    Screenshot 2020-11-19 123530.png

    It's an easy way to setup "Actions" patterns without putting a bunch of components in the inspector.

    Will there be support for creating generic data in DOTS? It doesn't seem to like this.

    Code (CSharp):
    1. [assembly: RegisterGenericComponentType(typeof(TestField))]
    2. [assembly: RegisterGenericComponentType(typeof(TestField2))]
    3. [assembly: RegisterGenericComponentType(typeof(TestField3))]
    4.  
    5. [DisallowMultipleComponent]
    6. public class ComponentFieldTestAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    7. {
    8.     [SerializeReference, SelectableSubType] public IFieldTest[] fieldTests;
    9.  
    10.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    11.     {
    12.         for (int i = 0; i < fieldTests.Length; i++)
    13.         {
    14.             dstManager.AddComponentData(entity, fieldTests[i]);
    15.         }
    16.     }
    17. }
    18.  
    19. public interface IFieldTest : IComponentData { }
    The error I get:

    ArgumentException: Unknown Type:`IFieldTest` All ComponentType must be 
    known at compile time. For generic components, each concrete type must be registered
    with [RegisterGenericComponentType].


    Or maybe it is possible and I am doing this wrong?

    Thanks,
     
  2. WAYNGames

    WAYNGames

    Joined:
    Mar 16, 2019
    Posts:
    992
    When using the add component the type must be defined.
    You can work around this by making your IFieldTest implement a "self register" method where you pass in the entity and entity manager. Then you can do something like this on the self registering method.

    em.AddComponentData(entity,this);

    There may be other ways to do it if you have access entity manager internal method like getting the type through the type manager an using that to set the data but I am not a fan of forcing access to internal methods...
     
    toomasio likes this.
  3. toomasio

    toomasio

    Joined:
    Nov 19, 2013
    Posts:
    199
    @WAYN_Games Thanks! It works! It's a little tedious without inheritance support but should do for now!

    new code:
    Code (CSharp):
    1. [DisallowMultipleComponent]
    2. public class ComponentFieldTestAuthoring : MonoBehaviour, IConvertGameObjectToEntity
    3. {
    4.     [SerializeReference, SelectableSubType] public IFieldTest[] fieldTests;
    5.  
    6.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    7.     {
    8.         for (int i = 0; i < fieldTests.Length; i++)
    9.         {
    10.             if (fieldTests[i] != null)
    11.                 fieldTests[i].SelfRegister(dstManager, entity);
    12.         }
    13.     }
    14. }
    15.  
    16. [System.Serializable]
    17. public struct TestField : IFieldTest
    18. {
    19.     public float testField1;
    20.     public float testField2;
    21.     public float testField3;
    22.     public float testField4;
    23.  
    24.     public void SelfRegister(EntityManager manager, Entity entity)
    25.     {
    26.         manager.AddComponentData(entity, this);
    27.     }
    28. }
    Screenshot 2020-11-19 123530.png