Search Unity

Bug Hierarhy is broken when instantiating Entitity from entity prefab and one of the childs is disabled

Discussion in 'Entity Component System' started by iamarugin, Jun 1, 2020.

  1. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Entitites 0.11

    I have the following prefab structure

    -- Root
    ---- Child 1
    ---- Child 2 // Disabled

    Prefab was converted by subscene.

    When I am instantiating it using EntityCommandBuffer.Instantiate the second child is missing from Child buffer in Root entitiy.
    If I disable Root on prefab, the Child buffer is completely missing on Root entity.

    Childs is missing even if I remove Disabled component from it.

    Is this somehow intended behaviour?
     
    Last edited: Jun 1, 2020
    PublicEnumE likes this.
  2. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Also EntityCommandBuffer.SetEnabled(entity, bool) would be very usefull
     
  3. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Posted about the issue here as well:

    https://forum.unity.com/threads/sto...ng-in-referenced-prefabs.897434/#post-5896952

    Looking through the conversion world source code, it looks like referenced prefabs are never checked for ‘Covert’ or ‘StopConvert’ components. It’s just assumed everything in the prefab hierarchy should be converted to an entity.

    My best guess was that when the StopConvert component was implemented (which was a later addition to the conversion ecosystem) that prefab support was innocently missed.

    I’m using an uncomfortable workaround for this, in which I use a Conversion System to catch prefab children which should be disabled, and destroy their entities with EntityManager. I would love to not need to do this.
     
  4. PublicEnumE

    PublicEnumE

    Joined:
    Feb 3, 2019
    Posts:
    729
    Ah, my apologies - it looks like we are talking about two different bugs (disabled entities, vs StopConvert MonoBehaviours).

    Didn’t mean to hijack the topic. GL.
     
  5. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Also PreviousParent value is Entity.Null in this case.
     
  6. DreamingImLatios

    DreamingImLatios

    Joined:
    Jun 3, 2017
    Posts:
    4,264
    I can confirm this is an issue. What happens is after any hierarchical change, the transform system reacts to the changes and cleans up using change filtering. However, if the entities are disabled when the transform system runs, the transform system does not apply the necessary changes. Then by the time the entities are enabled, the parent component has not been touched for several transform system updates and the change filter ignores them. Why that happens in spite of the structural changes that should be made when enabling the entities requires way too much digging into the code for me to be bothered with right now.

    The workaround is to dirty the Parent components on each child after enabling by reading the Parent value and then setting it to the same value. You can do this in a job using ComponentDataFromEntity.
    Code (CSharp):
    1. //Todo: It seems that if you Instantiate and then immediately disable a Transform hierarchy, the disabled entities do not get their child buffers.
    2.             //This hack attempts to dirty the children so that the transform system picks up on this.
    3.             var linkedBfe  = GetBufferFromEntity<LinkedEntityGroup>(true);
    4.             var parentCdfe = GetComponentDataFromEntity<Parent>(false);
    5.             Job.WithCode(() =>
    6.             {
    7.                 for (int i = 0; i < enabledShipList.Length; i++)
    8.                 {
    9.                     var ship         = enabledShipList[i];
    10.                     var linkedBuffer = linkedBfe[ship];
    11.                     for (int j = 0; j < linkedBuffer.Length; j++)
    12.                     {
    13.                         var e = linkedBuffer[j].Value;
    14.                         if (parentCdfe.Exists(e))
    15.                         {
    16.                             var p         = parentCdfe[e];
    17.                             parentCdfe[e] = p;
    18.                         }
    19.                     }
    20.                 }
    21.             }).Run();
     
    iamarugin likes this.
  7. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883
    Thanks for suggestion. I've actually started manually adding Child buffer to parent entity and adding childs for it as a temporal workaround (for some reason just dirtying entities didn't work for me). I hope it will be fixed soon.
     
  8. iamarugin

    iamarugin

    Joined:
    Dec 17, 2014
    Posts:
    883