Search Unity

A few questions about archetypes

Discussion in 'Entity Component System' started by maikklein, Apr 1, 2018.

  1. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    What exactly is an archetype?

    I assume the layout of it is [A, A, A, B, B, B, C, C ,C]?

    Code (CSharp):
    1. PlayerArchetype = entityManager.CreateArchetype(
    2.    typeof(Position2D), typeof(Heading2D), typeof(PlayerInput),
    3.    typeof(Faction), typeof(Health), typeof(TransformMatrix));
    What happens if some components aren't set? For example you create an entity with the PlayerArchetype but only set a Position2D? Aren't there holes in the array?

    Also what happens when you add a component to an entity where the component is not contained in the archetype? Will this crash? Or will the entity be moved into a different archetype? For example
    Code (CSharp):
    1. FooArchetype = entityManager.CreateArchetype(
    2.    typeof(Position2D), typeof(Heading2D));
    Code (CSharp):
    1. BarArchetype = entityManager.CreateArchetype(
    2.    typeof(Position2D), typeof(Heading2D), typeof(Bar));
    Code (CSharp):
    1. EntityManager.AddComponent(fooEntity, new Bar());
    Will the fooEntity be moved into the BarArchetype? And what happens when an entity is created without an archetype? Will Unity just create a new archetype under the hood?

    Also is the source code for the entity component system public?
     
    Singtaa likes this.
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Code (CSharp):
    1.         public Entity CreateEntity(params ComponentType[] types)
    2.         {
    3.             return CreateEntity(CreateArchetype(types));
    4.         }
    CreateEntity will initialize all components to zero.

    AddComponent moves the entire entity data to a different chunk with a different archetype. Archetype creation happens transparently. Archetypes are cached so requesting the same ComponentType[] multiple times, returns the same Archetype
     
    maikklein likes this.
  3. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    And yes, the source is public. It's located in the package folder
     
    maikklein likes this.
  4. SubPixelPerfect

    SubPixelPerfect

    Joined:
    Oct 14, 2015
    Posts:
    224
  5. sngdan

    sngdan

    Joined:
    Feb 7, 2014
    Posts:
    1,154
    I am travelling and using a windows machine at the moment, so on windows it is:
    C:\ProgramData\Unity\cache\packages\staging-packages.unity.com\com.unity.entities@0.0.11

    The easiest way to get there, is to use one of the built-in components like gameobject entity or position. Then, open the script and it should take you to the source. You can then check the directory it is in...
     
    SubPixelPerfect likes this.
  6. maikklein

    maikklein

    Joined:
    Jun 16, 2015
    Posts:
    33
    Thanks that basically answers all my questions.

    Ah I was only looking in the git repository. Out of curiosity, is the ECS beta build planned for the linux client?
     
  7. StephanK

    StephanK

    Joined:
    Jul 10, 2012
    Posts:
    47
    How is the data layed out if you have something like this:
    Code (CSharp):
    1. public struct A : IComponentData
    2. {
    3.     public int value;
    4. }
    5.  
    6. public struct B : IComponentData
    7. {
    8.     public int value;
    9. }
    10.  
    11. entityManager.CreateArchetype(typeof(A), typeof(B));
    12. entityManager.CreateArchetype(typeof(B));
    And how does the system then resolve this:

    Code (CSharp):
    1. public struct Group
    2. {
    3.     public ComponentDataArray<B> allBs;
    4. }
    5.  
    6. [Inject] Group group;
    Is some of the data duplicated in the chunks for specific types? Or does the ComponentDataArray contain data from multiple chunks?
     
  8. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    There will be two chunks.
    One with
    a a a a
    b b b b

    another with just
    b b b b


    64kb fits approximately 8000 entities, so if you have 5000 entities of each you would have exactly one pointer jump and otherwise completely linear access to both a and b components.
     
  9. Deleted User

    Deleted User

    Guest

    I might sound stupid now but does that mean.

    AAAA
    BBBB

    BBBBBBBB

    or

    AAAA
    BBBB

    BBBB

    if we have four AB entities and four B entities?
     
  10. StephanK

    StephanK

    Joined:
    Jul 10, 2012
    Posts:
    47
    I'd say the latter, that's where the pointer jump happens.
     
  11. ParadoxSolutions

    ParadoxSolutions

    Joined:
    Jul 27, 2015
    Posts:
    325
    I have a question with:

    Code (CSharp):
    1. public Type[] myComponentArray;
    2.  
    3. //This works:
    4. entityManager.CreateArchetype(myComponentArray[0], myComponentArray[1]);
    5.  
    6. //But why can't I pass whole array?
    7. entityManager.CreateArchetype(myComponentArray);

    trying to understand the above posts, could I to a foreach loop with AddComponent to get the same effect as passing a whole array to CreateArchetype?
     
  12. StephanK

    StephanK

    Joined:
    Jul 10, 2012
    Posts:
    47
    Yes you could, but it would be a bit more unefficient since each time you add a new component the entity has to be moved to a new chunk that is specific for its new archetype.
     
  13. ParadoxSolutions

    ParadoxSolutions

    Joined:
    Jul 27, 2015
    Posts:
    325
    I wrote an editor window that lets me pick and choose from class/structs in the project that implement IComponentData, and save them to a ScriptableObject's dictionary of "archetypes" (string, Type[]). I was hoping I could load those archetypes defined in edit mode on Awake() but since I can't pass a whole array to CreateArchetype, the only option is hard code it with the array indexes which is pointless if I could just use typeof(MyType).

    The add component method really wouldn't scale well, I hope a variant of CreateArchetype is added that supports passing a whole type array. Because unless I don't know about some trick to iterate through an array inside the parameters of a method there really needs to be an option other than hard coding.
     
  14. Malmer

    Malmer

    Joined:
    Nov 10, 2013
    Posts:
    18
    The reason why it doesn't work is because CreateArchetype actually doesn't take Type as arguments, but ComponentType. When you pass Type it implicitly converts it to a ComponentType with readwrite access. Pass an array of ComponentType instead (which you can create in a loop before based on your Type array) and you should be good.
     
    Last edited: Apr 5, 2018
    ParadoxSolutions likes this.
  15. Malmer

    Malmer

    Joined:
    Nov 10, 2013
    Posts:
    18
    In code:
    Code (CSharp):
    1. var componentTypes = new ComponentType[myComponentArray.Length];
    2. for (int i = 0; i < myComponentArray.Length; ++i)
    3.     componentTypes[i] = myComponentArray[i];
    4. var archetype = EntityManager.CreateArchetype(componentTypes);
    But you might aswell use ComponentType directly in your editor thingie, and also allow setting the accessmode.
     
  16. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    What are the benefits of manually defining archetypes vs letting Unity do it implicitly in the background? Is it just so that when creating an entity, I can pass in an archetype and Unity can more easily assign the components to the correct chunks?

    In that case, in situations where you are adding/removing components from an entity (which will automatically change its archetype), rather than creating new entities (based on an archetype), is there any advantage to explicitly defining the entity archetypes beforehand?

    I assume yes, you should so that the chunk arrays can be pre-allocated? Thanks!
     
  17. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    EntityArchetype has to be used explicitly, exclusively as an argument with EntityManager/EntityCommandBuffer.CreateEntity(archetype) command. The EntityArchetype variable only helps speeding up entity creation from scratch. I believe just creating the archetype does nothing to the internal ECS system. The archetype does not get "defined" in the system after running EntityManager.CreateArchetype, "create" is in the sense of creating the template for your own use later.
     
  18. recursive

    recursive

    Joined:
    Jul 12, 2012
    Posts:
    669
    I've also noticed I can hand archetypes off to a burst enabled job that works with EntityCommandBuffer, at least only using non-SharedComponentData types. Then again the entities involved were simple (an int and a tag basically). This may only work in the latest preview package.
     
  19. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    I take it then that we should avoid including Shared Components in an archetype? I have a shared sprite component in my archetype and upon entity creation, I am using SetSharedComponent to set the shared sprite to one I have set in the inspector. It seems to be working fine, but should I be leaving the Shared component out of my archetype and using AddSharedComponent instead?

    One other thing, kind of on the same topic. Does Unity create a default shared component so it can add it to entities that have a shared component on their archetype? I ask because I only have a single shared sprite in my scene, and am only assigning it to entities, but when I use GetAllUniqueSharedComponentDatas, the cache contains two unique instances. Where is the extra one coming from?

    Thanks!
     
  20. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    Yep, as far I understood, and what I read here and there, archetypes are just for user convenience, when organizing types. Technically they can be completely avoided, as they are not required for anything else than during entity creation.

    I don't see reason why would you like, to exclude it from archetype. Unless indeed Burst don't like them.

    What if you try having two different ShaderComponents? Will result with 3, or 4 unique instances?
     
    Last edited: Aug 16, 2018
    gilley033 likes this.
  21. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    I figured out that the extra shared component was a result of having a SharedComponentDataWrapper<MyType> in the scene. Is this a bug? It seems like when you get the Value of the wrapper (which is of type MyType), it should not create a separate unique copy.
     
  22. 5argon

    5argon

    Joined:
    Jun 10, 2013
    Posts:
    1,555
    No, by "speed up" I didn't mean in convenience meaning. I mean as in less CPU time for creating the entity. Because if you create a new entity then add/set the required component one by one, which you want it to have immediately anyways, each step would require a chunk movement equal to the number of component data you want. By having them in the archetype it will go in the correct chunk from the start. The subsequent Set command to change their content from default will not cause chunk movement.

    Especially if one of them is an ISharedComponentData when you add/set a new ones it requires a memcpy for ALL of the entity's current component data. (https://github.com/Unity-Technologi...ome-important-notes-about-sharedcomponentdata) If you are going to add/change to a non-empty ISharedComponentData the less compoenent data you currently have the better.

    When you create a new entity with archetype containing IShared you will get an IShared with empty data (zero hash value) and I think tbh it is quite useless because the reason you use IShared is to put some value in and make it a different type of component.. I am not sure if having the empty ones at first then use Set or just use Add with the value you actually want is better. But from the official docs I think it would require memcpy anyways because unlike normal component data IShared with different content make 2 different hash and have to be in a different chunk. So yes maybe adding IShared to an archetype is not that useful unless you really want an empty one. (Empty IShared is better than the "empty tag IComponentData" pattern in that it does not cause memory overhead per entity, it scales better memory wise if you are planning to have a lot of entities with it)
     
    Last edited: Aug 16, 2018
  23. gilley033

    gilley033

    Joined:
    Jul 10, 2012
    Posts:
    1,191
    Awesome, thanks for the info! I will take a look at the documentation folder on the github in the future, I did not realize it had as much information as it does.

    I did understand that the archetype allows Unity to place the chunks in the right place from the get go, rather than adding the components manually one after another. This is why I assumed including the shared component in the archetype andusing SetSharedComponent would be better then not including it and adding the component using AddSharedComponent. But the Two Stick Shooter example uses the latter method and I assume they did that on purpose.
     
  24. Antypodish

    Antypodish

    Joined:
    Apr 29, 2014
    Posts:
    10,776
    Maybe I sentenced it incorrectly, as I not meant you indicated "convenience". This rather was my conclusion, from read of different sources, that it brings convince to programmers. Thx for clarification in later.


    Funny thought, of how stack overflow community could react to micro-optimization of mircroseconds, if they read this topic :p