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 Dots ScriptableObject with prefabs

Discussion in 'Entity Component System' started by goldendonut, Sep 16, 2022.

  1. goldendonut

    goldendonut

    Joined:
    Dec 27, 2017
    Posts:
    7
    I am building a factory game and I can't figure out how to get a prefab/ mesh in a scriptable object.

    Currently, I am using scriptable objects for the recipe that I convert to blob assets. and use these to spawn the entities, but currently, they are just cubes and I need them to have a mesh.

    I want the assembler that holds the scriptable, to be switchable and easy to edit in the editor. Is there a way to add mesh data or prefab data in Blob assets that are converted from scribbles or is there another way?

    here is the code for the recipe.
    Code (CSharp):
    1.  
    2. [CreateAssetMenu(fileName = "Recipe", menuName = "RecipeScriptable", order = 3)]
    3.  
    4. public class Recipe : ScriptableObject
    5. {
    6.     static Dictionary<string, BlobAssetReference<RecipeBlobAsset>> Allocations = new Dictionary<string, BlobAssetReference<RecipeBlobAsset>>();
    7.     [SerializeField] [Min(0.1f)] float _batchDuration = 1.5f;
    8.     [SerializeField] int _product;
    9.     //[SerializeField] product[] _ProductModel;
    10.     [SerializeField] InventoryItem[] _ingredients;
    11.  
    12.     public BlobAssetReference<RecipeBlobAsset> ToBlobAssetReference()
    13.     {
    14.         if (Allocations.ContainsKey(this.name))
    15.         {
    16.             return Allocations[this.name];
    17.         }
    18.         else
    19.         {
    20.             BlobAssetReference<RecipeBlobAsset> recipe;
    21.             {
    22.                 var builder = new BlobBuilder(Allocator.Temp);
    23.                 ref var root = ref builder.ConstructRoot<RecipeBlobAsset>();
    24.                 {
    25.                     root.Product = _product;
    26.                 }              
    27.                 {
    28.                     root.BatchDuration = _batchDuration;
    29.                 }
    30.                 //{
    31.                     //int numProducts = _ProductModel.Length;
    32.                     //var arr = builder.Allocate(ref root.ProductModel, numProducts);
    33.                     //for (int i = 0; i < numProducts; i++) arr[i] = _ProductModel[i];
    34.                //}
    35.                 {
    36.                     int numIngredients = _ingredients.Length;
    37.                     var arr = builder.Allocate(ref root.Ingredients, numIngredients);
    38.                     for (int i = 0; i < numIngredients; i++) arr[i] = _ingredients[i];
    39.                 }
    40.                 recipe = builder.CreateBlobAssetReference<RecipeBlobAsset>(Allocator.Persistent);
    41.                 builder.Dispose();
    42.             }
    43.  
    44.             Allocations.Add(this.name, recipe);
    45.  
    46.             return recipe;
    47.         }
    48.     }
    49. }
    50. //[InternalBufferCapacity(3)]
    51. [System.Serializable]
    52. public struct product
    53. {
    54.     //public int Id;
    55.     public Entity prefab;
    56. }
    57. [System.Serializable]
    58. public struct RecipeBlobAsset
    59. {
    60.     public int Product;
    61.     public float BatchDuration;
    62.     //public BlobArray<product> ProductModel;
    63.     public BlobArray<InventoryItem> Ingredients;
    64. }
    and the code for the holder of the scriptable:
    Code (CSharp):
    1. [DisallowMultipleComponent]
    2. [RequireComponent(typeof(InventoryComponent))]
    3. public class AssemblerComponent : MonoBehaviour, IConvertGameObjectToEntity
    4. {
    5.     [SerializeField] Recipe _recipeAsset;
    6.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    7.     {
    8.         dstManager.AddComponentData(entity, new Transmuter
    9.         {
    10.             RecipeData = _recipeAsset.ToBlobAssetReference()
    11.         });
    12.     }
    13. }
    14.  
    15. public struct Transmuter : IComponentData
    16. {
    17.     public BlobAssetReference<RecipeBlobAsset> RecipeData;
    18.     public bool BatchStarted;
    19.     public float BatchTime;
    20.     public int Product;
    21.     public int Quantity;
    22. }
    23.  
     
  2. Chris-Herold

    Chris-Herold

    Joined:
    Nov 14, 2011
    Posts:
    115
    Winging it a bit, but here's my 2 cents:

    Recipe references a mesh and material.
    At conversion create an Entity with a RenderMesh component for the desired mesh&material combination.
    Use a <int, Entity> dictionary to see if desired combination already exists (combined hash of Mesh/Material.GetInstanceID).
    Add Entity reference to RecipeBlobAsset. Grab its RenderMesh when needed.

    Or shorter:
    Make your meshes prefabs.
    Recipe references prefab.
    At conversion convert prefab to entity.
    Assign to RecipeBlobAsset.
     
  3. goldendonut

    goldendonut

    Joined:
    Dec 27, 2017
    Posts:
    7
    Ok, I did that, I think.

    the code is this now:
    Code (CSharp):
    1. public class Recipe : ScriptableObject
    2. {
    3.     static Dictionary<string, BlobAssetReference<RecipeBlobAsset>> Allocations = new Dictionary<string, BlobAssetReference<RecipeBlobAsset>>();
    4.     [SerializeField] [Min(0.1f)] float _batchDuration = 1.5f;
    5.     [SerializeField] int _product;
    6.     [SerializeField] GameObject _Prefab;
    7.     [SerializeField] InventoryItem[] _ingredients;
    8.     BlobAssetStore blobAsset;
    9.  
    10.     public BlobAssetReference<RecipeBlobAsset> ToBlobAssetReference()
    11.     {
    12.         if (Allocations.ContainsKey(this.name))
    13.         {
    14.             return Allocations[this.name];
    15.         }
    16.         else
    17.         {
    18.             BlobAssetReference<RecipeBlobAsset> recipe;
    19.             {
    20.                 var builder = new BlobBuilder(Allocator.Temp);
    21.                 ref var root = ref builder.ConstructRoot<RecipeBlobAsset>();
    22.                 {
    23.                     root.Product = _product;
    24.                 }              
    25.                 {
    26.                     root.BatchDuration = _batchDuration;
    27.                 }
    28.                 {
    29.                     blobAsset  = new BlobAssetStore();
    30.                     GameObjectConversionSettings settings = GameObjectConversionSettings.FromWorld(World.DefaultGameObjectInjectionWorld, blobAsset);
    31.                     root.prefab = GameObjectConversionUtility.ConvertGameObjectHierarchy(_Prefab, settings);
    32.                     blobAsset.Dispose();
    33.                     //Destroy(_Prefab);
    34.                 }
    35.                 {
    36.                     int numIngredients = _ingredients.Length;
    37.                     var arr = builder.Allocate(ref root.Ingredients, numIngredients);
    38.                     for (int i = 0; i < numIngredients; i++) arr[i] = _ingredients[i];
    39.                 }
    40.                 recipe = builder.CreateBlobAssetReference<RecipeBlobAsset>(Allocator.Persistent);
    41.                 builder.Dispose();
    42.             }
    43.  
    44.             Allocations.Add(this.name, recipe);
    45.  
    46.             return recipe;
    47.         }
    48.     }
    49.  
    50.     //private void OnDestroy()
    51.    // {
    52.     //    blobAsset.Dispose();
    53.     //}
    54. }
    55. [System.Serializable]
    56. public struct RecipeBlobAsset
    57. {
    58.     public int Product;
    59.     public float BatchDuration;
    60.     public Entity prefab;
    61.     public BlobArray<InventoryItem> Ingredients;
    62. }
    But on the component the entity for the prefab is null.

    here is the component:
    Code (CSharp):
    1. [DisallowMultipleComponent]
    2. [RequireComponent(typeof(InventoryComponent))]
    3. public class AssemblerComponent : MonoBehaviour, IConvertGameObjectToEntity
    4. {
    5.     [SerializeField] Recipe _recipeAsset;
    6.     public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    7.     {
    8.         dstManager.AddComponentData(entity, new Transmuter
    9.         {
    10.             RecipeData = _recipeAsset.ToBlobAssetReference()
    11.         });
    12.     }
    13. }
    14.  
    15. public struct Transmuter : IComponentData
    16. {
    17.     public BlobAssetReference<RecipeBlobAsset> RecipeData;
    18.     public bool BatchStarted;
    19.     public float BatchTime;
    20.     public int Product;
    21.     public int Quantity;
    22.     public Entity Prefab;
    23. }
    24.  
     
  4. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    3,983
    Not sure if this is related to your problem at all, but you can't store an entity inside a blob asset. Sometimes you might get lucky and it will work. But for many workflows it doesn't.
     
  5. goldendonut

    goldendonut

    Joined:
    Dec 27, 2017
    Posts:
    7
    Ok, well then is there any other way to do, or a way to get this workflow working?
     
  6. Chris-Herold

    Chris-Herold

    Joined:
    Nov 14, 2011
    Posts:
    115
    Do you really need these to be BlobAssets?
    Since BlobAssets are built for serialization - and you're recreating the data on startup anyways -
    perhaps BlobAssets aren't needed here.

    You could use a singleton Entity for static data with an off-chunk DynamicBuffer<Recipe> instead, for example.
    The upside being that this data is mutable at runtime.
     
  7. goldendonut

    goldendonut

    Joined:
    Dec 27, 2017
    Posts:
    7
    How would I accomplish this and would it be more performant and still be easily modifiable in the editor?