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

Question Generic bakers not supported?

Discussion in 'Entity Component System' started by CookieStealer2, Oct 3, 2022.

  1. CookieStealer2

    CookieStealer2

    Joined:
    Jun 25, 2018
    Posts:
    119
    I had a pretty handy setup using the old conversion pipeline that allowed me to easily link managed stuff (GO or components) to entities that was based on generics, but now it seems it can't work with baking since generic bakers are not supported. Is it planned to never work or will you add support for that in the future?
     
  2. bogdancoder

    bogdancoder

    Unity Technologies

    Joined:
    Feb 6, 2017
    Posts:
    29
    Can you post a code snippet illustrating your setup?
     
  3. CookieStealer2

    CookieStealer2

    Joined:
    Jun 25, 2018
    Posts:
    119
    Below is a snippet where I define a "LinkedPrefab" for UnityEngine.GameObject, but it can also use any other unity engine component by changing the alias "CompType". There are 4 classes, the first is the authoring class (monobehaviour) that can be placed on the gameobject in the editor. Then we have a managed IComponentData "GameObjectLinkedPrefab" that simply holds a reference to the prefab. Next is a managed ISystemStateComponentData "GameObjectLinkedPrefabInstance" that is the actual prefab instance associated with the entity. The fourth class is the system that automatically manages the creation/destruction of prefab instances based on if the entity has only the prefab component or only the instance component respectively.

    Code (CSharp):
    1.     using CompType = UnityEngine.GameObject;
    2.     using PrefabType = GameObjectLinkedPrefab;
    3.     using InstanceType = GameObjectLinkedPrefabInstance;
    4.  
    5.     public class GameObjectLinkedPrefabAuthoring : LinkedPrefabAuthoring<CompType, PrefabType>
    6.     {
    7.         protected override PrefabType ComponentObject => new PrefabType { prefab = this.prefab };
    8.     }
    9.  
    10.     public class GameObjectLinkedPrefab
    11.     : LinkedPrefab<CompType> {}
    12.  
    13.     public class GameObjectLinkedPrefabInstance
    14.     : LinkedInstance<CompType> {}
    15.  
    16.     public class GameObjectLinkedPrefabSystem
    17.     : LinkedPrefabSystem_Pooled<PrefabType, InstanceType, CompType> {}
    The next snippet contains the implementations of the respective classes, I have left out the instance creation/destruction system since it's pretty long, but I can post it too if needed.

    Code (CSharp):
    1.     /// <summary>
    2.     /// Authoring component, to be added to the GameObject version of the entity which should get a linked prefab.
    3.     /// </summary>
    4.     public abstract class LinkedPrefabAuthoring<TObject, TLinkedPrefab> : MonoBehaviour, IConvertGameObjectToEntity
    5.     where TObject : UnityEngine.Object
    6.     where TLinkedPrefab : LinkedPrefab<TObject>
    7.     {
    8.         public TObject prefab;
    9.         protected abstract TLinkedPrefab ComponentObject { get; }
    10.  
    11.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    12.         {
    13.             dstManager.AddComponentObject(entity, ComponentObject);
    14.         }
    15.     }
    16.  
    17.     /// <summary>
    18.     /// IComponentData with a reference to a prefab of type T.
    19.     /// </summary>
    20.     public abstract class LinkedPrefab<T> : IComponentData where T : UnityEngine.Object
    21.     {
    22.         public T prefab;
    23.     }
    24.  
    25.     /// <summary>
    26.     /// ISystemStateComponentData with a reference to an instantiated linked prefab of type T.
    27.     /// </summary>
    28.     public abstract class LinkedInstance<T> : ISystemStateComponentData where T : UnityEngine.Object
    29.     {
    30.         public T instance;
    31.     }
    32.  
     
  4. bogdancoder

    bogdancoder

    Unity Technologies

    Joined:
    Feb 6, 2017
    Posts:
    29
    To confirm understanding, you're trying to create "typed prefabs" which can be pooled together in separate lists. Is CompType ever something other than GameObject?

    At the moment the initialization code that creates the baker instances only supports instantiating bakers for known, non-generic component types. You can modify your code as follows to get around this limitation, at the cost of having to define a concrete baker in any class derived from LinkedPrefabAuthoring<TObject, TLinkedPrefab>.

    Base class:
    Code (CSharp):
    1. public abstract class LinkedPrefabAuthoring<TObject, TLinkedPrefab> : MonoBehaviour
    2.     where TObject : UnityEngine.Object
    3.     where TLinkedPrefab : LinkedPrefab<TObject>
    4. {
    5.     public TObject prefab;
    6.     protected abstract TLinkedPrefab ComponentObject { get; }
    7.  
    8.     protected abstract class LinkedPrefabBaker<TAuthoring> : Baker<TAuthoring>
    9.        where TAuthoring : LinkedPrefabAuthoring<TObject, TLinkedPrefab>
    10.     {
    11.         public override void Bake(TAuthoring authoring)
    12.         {
    13.             DependsOn(authoring.prefab);
    14.             AddComponentObject(authoring.ComponentObject);
    15.         }
    16.     }
    17. }
    Derived:
    Code (CSharp):
    1. public class GameObjectLinkedPrefabAuthoring : LinkedPrefabAuthoring<CompType, PrefabType>
    2. {
    3.     protected override PrefabType ComponentObject => new PrefabType { prefab = this.prefab };
    4.  
    5.     class GameObjectLinkedPrefabBaker : LinkedPrefabBaker<GameObjectLinkedPrefabAuthoring>
    6.     {
    7.         public override void Bake(GameObjectLinkedPrefabAuthoring authoring)
    8.         {
    9.             // implement custom baking logic or just call the base
    10.             base.Bake(authoring);
    11.         }
    12.     }
    13. }
     
    Luxxuor, CookieStealer2 and WAYNGames like this.
  5. CookieStealer2

    CookieStealer2

    Joined:
    Jun 25, 2018
    Posts:
    119
    Essentially yes, I have multiple different types of "LinkedPrefabs", one for animator, one for UI stuff etc... each pooled by a separate system. So "CompType" is not only GameObject.

    I was hoping to avoid having to define a baker for each variant to keep it concise, but maybe it's not possible. I'll see if I can do something clever with reflection otherwise I'll do like you suggested.
     
  6. Enzi

    Enzi

    Joined:
    Jan 28, 2013
    Posts:
    908
    Generic bakers do work with a bit of trickery.
    Code (CSharp):
    1. public class ScriptableObjectConverter_Baker<TAuthoringType, TSOClass, TBlobStruct, TBlobReference> : Baker<TAuthoringType>
    2.         where TAuthoringType : ScriptableObjectConverterBase
    3.         where TSOClass : ScriptableObject, IConvertToBlob<TBlobStruct>
    4.         where TBlobStruct : unmanaged
    5.         where TBlobReference : unmanaged, IComponentData, IBlobAssetReference<TBlobStruct>
    Sorry, lot going on here. The gist is to have a base which you never use. Base can have data though.
    Code (CSharp):
    1. public class ScriptableObjectConverterBase : MonoBehaviour
    and then implement:
    Code (CSharp):
    1. public class ResourceItemConverter : ScriptableObjectConverterBase { }
    2. public class ResourceItemBaker : ScriptableObjectConverter_Baker<ResourceItemConverter, SO_ResourceItem, ResourceItemBlobAsset, ResourceItemBlobReference> { }
     
    Last edited: Oct 4, 2022