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

How do we deal with nested data ?

Discussion in 'Entity Component System' started by genaray, Mar 10, 2022.

  1. genaray

    genaray

    Joined:
    Feb 8, 2017
    Posts:
    191
    One think that feels like a punch in my face is that we simply cant put NativeLists into struct Components and that UnsafeLists cant accept another UnsafeList as a generic parameter.

    Thats why i come up with this question... how do we deal with nested data ?

    Following example... Recipes. A recipe in any game looks like this.

    Code (CSharp):
    1.        
    2. /// <summary>
    3.     /// Represents an ingredient.
    4.     /// </summary>
    5.     public struct Ingredient {
    6.        
    7.         public FixedString32 type;    // The item type... 3:1 is wood for example
    8.         public byte icon;      // Its icon
    9.         public uint amount;
    10.         public bool consume;
    11.  
    12.         public Ingredient(FixedString32 type, byte icon, uint amount, bool consume) {
    13.             this.type = type;
    14.             this.icon = icon;
    15.             this.amount = amount;
    16.             this.consume = consume;
    17.         }
    18.     }
    19.  
    20.     /// <summary>
    21.     /// The craftable result
    22.     /// </summary>
    23.     public struct Craftable {
    24.  
    25.         public FixedString32 type;   // The item type... 2:1 is gold for example
    26.         public byte icon;
    27.         public uint amount;
    28.  
    29.         public Craftable(FixedString32 type, byte icon, uint amount) {
    30.             this.type = type;
    31.             this.icon = icon;
    32.             this.amount = amount;
    33.         }
    34.     }
    35.  
    36.     /// <summary>
    37.     /// The recipe, containing ingredients and a craftable result.
    38.     /// </summary>
    39.     public struct Recipe {
    40.  
    41.         public UnsafeList<Ingredient> ingredients;
    42.         public UnsafeList<Craftable> craftables;
    43.         public byte describtion;
    44.  
    45.         public Recipe(UnsafeList<Ingredient> ingredients, UnsafeList<Craftable> craftables, byte describtion) {
    46.             this.ingredients = ingredients;
    47.             this.craftables = craftables;
    48.             this.describtion = describtion;
    49.         }
    50.     }
    But once we wanna give the player a list of recipes... for example `public struct Recipes{ public UnsafeList<Recipe> recipes... other stuff}` it does not work, because UnsafeLists dont accept structs with other unsafelists in it.

    We could use a DynamicBuffer, but that sucks with networking and is also very limiting... imagine that the ingredients could also have a list in it... broken. Well we could make each recipe into an entity on their own, eliminating the need of nested data... but even then we have the problem that it may contain another list and we run into the same problem and at some point it doesnt make sense to split everything into entities...

    Imagine one entity for recipe, one for each ingredient and so on... that just doesnt make sense anymore and is hard to network.

    So how the heck do we implement such nested structures in that ecs environment ? What are common techniques ? And why the heck doesnt UnsafeList accept another UnsafeList ?
     
  2. Krajca

    Krajca

    Joined:
    May 6, 2014
    Posts:
    347
    tl;dr I don't. Almost always I just flat out my nested arrays and just like in databases use some sort of key to connect the data.

    To give an example:
    -an entity with a couple of DynamicBuffers to be used as a RecipeBook: one for every ingredient, result, and recipe there is in the game (this is all read-only so safe for parallel)
    - and a DynamicBuffer on the player itself to keep IDs of known recipes

    This way you don't need to send your recipes over the internet as they are not-mutable data. If you need a short list I would recommend FixedList. And fill it with ID instead of whole structs of recipe/ingredient definition.

    As I'm writing this I wonder why you send recipe/ingredient data over the network at all. Is that something the player can change?
     
    genaray likes this.
  3. desertGhost_

    desertGhost_

    Joined:
    Apr 12, 2018
    Posts:
    258
    If your data is read-only, you can use Blob Assets and nest blob arrays.
     
    Krajca likes this.
  4. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Incorrect. You can nest UnsafeList inside UnsafeList.
     
    bb8_1 likes this.
  5. genaray

    genaray

    Joined:
    Feb 8, 2017
    Posts:
    191
    How ? I tried it multiple times, but it always told me it only allows nested unmanaged structs with primitives in it.
     
  6. genaray

    genaray

    Joined:
    Feb 8, 2017
    Posts:
    191
    Thanks ! Well i had those dynamic buffers in mind, but those are uncompatible with my network solution atm. However i look into them ^^
     
  7. eizenhorn

    eizenhorn

    Joined:
    Oct 17, 2016
    Posts:
    2,653
    Just... use them?

    upload_2022-3-11_15-14-44.png

    upload_2022-3-11_15-21-13.png

    upload_2022-3-11_15-22-2.png
     
    Last edited: Mar 11, 2022
    bb8_1 likes this.