Search Unity

[Solved] Components disappear after Entity Prefab Instantiation

Discussion in 'Entity Component System' started by Satananas, Feb 4, 2020.

  1. Satananas

    Satananas

    Joined:
    Nov 29, 2018
    Posts:
    6
    I have prefabs with both custom and physics components (coming from Rigidbody).
    In my main authoring a prefab entity is created using the conversion system:

    Code (CSharp):
    1. foodPrefabEntity = conversionSystem.GetPrimaryEntity(foodPrefabs[player])
    In the Entity Debug View all components are present at the prefab entity.

    But when I instantiate the prefab

    Code (CSharp):
    1. dstManager.InstantiatePrefab(foodPrefabEntity, $"Food {player.Id} at {location}")
    the components are missing for those newly created instances.



    What am I missing?
     
    Last edited: Feb 4, 2020
  2. Roycon

    Roycon

    Joined:
    Jul 10, 2012
    Posts:
    50
    Can you share some of the missing Components?

    I've had this happen with class based IComponentData's
     
  3. Satananas

    Satananas

    Joined:
    Nov 29, 2018
    Posts:
    6
    It is my Gene Components (IComponentData) added as Authoring Components to the Prefab and the Physics Components - I tried both adding the RigidBody Monobehaviour and the DOTS Physics components directly...
     
  4. Roycon

    Roycon

    Joined:
    Jul 10, 2012
    Posts:
    50
    I mean can you share some of the code for your missing IComponentData's :)

    As for Monobehaviours/Unity Components (Like RigidBody) those are not copied with entitymanager.Instantiate as entitymanager doesn't create/link gameobjects (unless this has changed in the latest Entities package). I think the preferred hybrid flow is to Instantiate normal gameobjects that have a ConvertAndInject component on it
     
  5. Satananas

    Satananas

    Joined:
    Nov 29, 2018
    Posts:
    6
    Thank you for your response.

    What about the EntityCommandBuffers's Instantiate? Does this create the desired components?

    What would be the purpose of a Prefab, if can't instantiate it properly during runtime.
    I basically generate my Entities dynamically dependend on the number of players, so the ConvertAndInject workflow only applies to a number of static objects.

    And as for my Gene components, they are essentially IComponentDatas with the [GenerateAuthoringComponent] attribute. I could easily add those at runtime, but not the Physics Components.

    Here is the code of the GameAuthoring components, which is responsible for the generation of the game.

    Code (CSharp):
    1. public class GameAuthoring : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
    2.     {
    3.         [SerializeField] private SO.Game.GameSettings gameSettings;
    4.         [SerializeField] private TileRegistry tileRegistry;
    5.         [SerializeField] private BoardAuthoring[] Tiles;
    6.  
    7.         private Dictionary<SO.Game.Player, GameObject> pawnPrefabs = new Dictionary<SO.Game.Player, GameObject>();
    8.         private Dictionary<SO.Game.Player, GameObject> foodPrefabs = new Dictionary<SO.Game.Player, GameObject>();
    9.  
    10.         public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    11.         {
    12.             // foreach (var player in gameSettings.Players)
    13.             for (int i = 0; i < gameSettings.Players.Length; i++)
    14.             {
    15.                 var player = gameSettings.Players[i];
    16.                 pawnPrefabs.Add(player, SetPrefabColor(referencedPrefabs, player, gameSettings.PawnPrefabs[i]));
    17.                 foodPrefabs.Add(player, SetPrefabColor(referencedPrefabs, player, gameSettings.FoodPrefabs[i]));
    18.             }
    19.             foreach (var tile in Tiles)
    20.             {
    21.                 referencedPrefabs.Add(tile.gameObject);
    22.             }
    23.         }
    24.  
    25.         private GameObject SetPrefabColor(List<GameObject> referencedPrefabs, SO.Game.Player player, GameObject prefab)
    26.         {
    27.             //var result = Instantiate(prefab);
    28.             var result = prefab;
    29.             result.GetComponent<MeshRenderer>().sharedMaterial.color = player.TeamColor;
    30.             //result.name = $"{player.name}-{prefab.name}";
    31.             referencedPrefabs.Add(result);
    32.             return result;
    33.         }
    34.  
    35.         public void Convert(Entity entity, EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    36.         {
    37.             Random.InitState((int) System.Diagnostics.Stopwatch.GetTimestamp());
    38.             if (gameSettings)
    39.             {
    40.                 gameSettings.EnvironmentCardsDeck.Shuffle();
    41.  
    42.                 TimeToTick.Duration = gameSettings.TimePerTick;
    43.                 var gameBuilder = dstManager.With(entity);
    44.  
    45.                 gameBuilder.InitBuffer<PlayerOrderElement<AwaitMove>>()
    46.                     .InitBuffer<PlayerOrderElement<AwaitGeneDefects>>()
    47.                     .InitBuffer<PlayerOrderElement<AwaitNewGene>>()
    48.                     .InitBuffer<PlayerOrderElement<AwaitCellDivision>>()
    49.                     .InitBuffer<PlayerOrderElement<AwaitDeath>>()
    50.                     .InitBuffer<PlayerOrderElement<AwaitScore>>();
    51.  
    52.                 var es = dstManager.World.GetOrCreateSystem<EnvironmentSystem>();
    53.                 es.EnvironmentCardsDeck = gameSettings.EnvironmentCardsDeck;
    54.  
    55.                 var playerArchetype = dstManager.CreateArchetype(typeof(Player),
    56.                     typeof(BuildPoints),
    57.                     typeof(MutationPoints),
    58.                     typeof(NewPawnCost),
    59.                     typeof(Score),
    60.                     typeof(GeneCardElement),
    61.                     typeof(PawnsOnBoardElement),
    62.                     typeof(PawnsInStoreElement),
    63.                     typeof(Spawn));
    64.  
    65.                 Player firstPlayer = new Player();
    66.                 var players = new List<Player>();
    67.                 CreateTilesAndFood(dstManager, conversionSystem);
    68.  
    69.                 foreach (var player in gameSettings.Players)
    70.                 {
    71.                     var pawnPrefabEntity = conversionSystem.GetPrimaryEntity(pawnPrefabs[player]);
    72.                     var foodPrefabEntity = conversionSystem.GetPrimaryEntity(foodPrefabs[player]);
    73.                     var pawnSpawn = new Spawn { prefab = pawnPrefabEntity, Color = player.TeamColor };
    74.                     var foodSpawn = new Spawn { prefab = foodPrefabEntity, Color = player.TeamColor };
    75.  
    76.                     firstPlayer = new Player { IsHuman = player.IsHuman, Id = player.Id, TeamColor = player.TeamColor, Name = player.name };
    77.                     players.Add(firstPlayer);
    78.                     var playerBuilder = dstManager.Create(playerArchetype, player.name)
    79.                         .Set(firstPlayer)
    80.                         .Set<MutationPoints>(0)
    81.                         .Set<BuildPoints>(7)
    82.                         .Set<NewPawnCost>(6)
    83.                         //.Add<MovementIIGene>()
    84.                         .Set<Score>(Random.Range(0, gameSettings.Players.Length + 1))
    85.                         .Set(pawnSpawn)
    86.                         .Add<Ready>();
    87.  
    88.                     var pawnBuilder = CreatePawnOnBoard(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 1);
    89.                     if (gameSettings.Players.Length != 3) { pawnBuilder.Add<DamagePoints>(2); }
    90.                     CreatePawnOnBoard(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 2);
    91.                     CreatePawninStore(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 3);
    92.                     CreatePawninStore(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 4);
    93.                     CreatePawninStore(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 5);
    94.                     CreatePawninStore(dstManager, player, pawnPrefabEntity, foodSpawn, playerBuilder, 6);
    95.                 }
    96.  
    97.                 var phase = new AwaitMove();
    98.                 gameBuilder.Add(new GameState { PhaseName = phase.Name, Round = 1 })
    99.                     //.Add(new MoveDirection { Direction = Direction.E })
    100.                     //.Add<OzoneLayerThickness>(2)
    101.                     .Add(phase);
    102.  
    103.                 for (int i = players.Count - 1; i >= 0; i--)
    104.                 {
    105.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitNewGene>>(players[i]);
    106.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitCellDivision>>(players[i]);
    107.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitScore>>(players[i]);
    108.                 }
    109.                 foreach (var player in players)
    110.                 {
    111.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitMove>>(player);
    112.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitGeneDefects>>(player);
    113.                     gameBuilder.AddBuffer<PlayerOrderElement<AwaitDeath>>(player);
    114.  
    115.                 }
    116.  
    117.                 Debug.Log("Created Game");
    118.             }
    119.         }
    120.  
    121.         private void CreateTilesAndFood(EntityManager dstManager, GameObjectConversionSystem conversionSystem)
    122.         {
    123.             foreach (var tile in Tiles)
    124.             {
    125.                 var tileEntity = conversionSystem.GetPrimaryEntity(tile.gameObject);
    126.                 Location location = new Location
    127.                 {
    128.                     X = (int) tile.gameObject.transform.position.x + 1,
    129.                     Y = (int) tile.gameObject.transform.position.y + 1,
    130.                     N = conversionSystem.GetPrimaryEntity(tile.N),
    131.                     E = conversionSystem.GetPrimaryEntity(tile.E),
    132.                     S = conversionSystem.GetPrimaryEntity(tile.S),
    133.                     W = conversionSystem.GetPrimaryEntity(tile.W),
    134.                 };
    135.                 EntityBuilder tileBuilder = dstManager.With(tileEntity).Add(location).InitBuffer<FoodElement>();
    136.                 tileRegistry.Add(location, tileEntity);
    137.  
    138.                 foreach (var player in gameSettings.Players)
    139.                 {
    140.                     Entity foodPrefabEntity = conversionSystem.GetPrimaryEntity(foodPrefabs[player]);
    141.                     SpawnFood(dstManager, location, tileBuilder, player, foodPrefabEntity);
    142.                     SpawnFood(dstManager, location, tileBuilder, player, foodPrefabEntity);
    143.                 }
    144.             }
    145.         }
    146.  
    147.         private static void SpawnFood(EntityManager dstManager,
    148.             Location location,
    149.             EntityBuilder tileBuilder,
    150.             SO.Game.Player player,
    151.             Entity foodPrefabEntity)
    152.         {
    153.             var foodBuilder = dstManager.InstantiatePrefab(foodPrefabEntity, $"Food {player.Id} at {location}")
    154.                 .Add(new Food { ColorType = player.TeamColor })
    155.                 .Add(location.Randomize())
    156.                 .Add<Init>();
    157.             tileBuilder.AddBuffer<FoodElement>(foodBuilder.Entity);
    158.         }
    159.  
    160.         private EntityBuilder CreatePawnOnBoard(EntityManager dstManager,
    161.             SO.Game.Player player,
    162.             Entity pawnPrefabEntity,
    163.             Spawn foodSpawn,
    164.             EntityBuilder playerBuilder,
    165.             int pawnNumber)
    166.         {
    167.             var pawnBuilder = dstManager.InstantiatePrefab(pawnPrefabEntity, $"{player.name}: Pawn {pawnNumber}");
    168.             var pawn = new Pawn
    169.             {
    170.                 PlayerEntity = playerBuilder.Entity,
    171.                 Entity = pawnBuilder.Entity,
    172.                 Number = pawnNumber,
    173.                 Color = player.TeamColor
    174.             };
    175.             var tileEntity = tileRegistry[new Location { X = player.StartX + pawnNumber - 1, Y = player.StartY }];
    176.             var location = dstManager.GetComponentData<Location>(tileEntity);
    177.             pawnBuilder.Add(pawn)
    178.                 .Add(location)
    179.                 .Add<Init>()
    180.                 .Add(new AtLocation { TileEntity = tileEntity })
    181.                 .Add<PhysicsCollider>()
    182.                 .Add<DamagePointsToDie>(2)
    183.                 .Add<MovementCost>(1)
    184.                 .Add<MovementRate>(1)
    185.                 .Add(foodSpawn);
    186.             playerBuilder.AddBuffer<PawnsOnBoardElement>(pawnBuilder.Entity);
    187.             return pawnBuilder;
    188.         }
    189.  
    190.         private EntityBuilder CreatePawninStore(EntityManager dstManager,
    191.             SO.Game.Player player,
    192.             Entity pawnPrefabEntity,
    193.             Spawn foodSpawn,
    194.             EntityBuilder playerBuilder,
    195.             int pawnNumber)
    196.         {
    197.             var pawnBuilder = dstManager.InstantiatePrefab(pawnPrefabEntity, $"{player.name}: Pawn {pawnNumber}");
    198.             var pawn = new Pawn
    199.             {
    200.                 PlayerEntity = playerBuilder.Entity,
    201.                 Entity = pawnBuilder.Entity,
    202.                 Number = pawnNumber,
    203.                 Color = player.TeamColor
    204.             };
    205.             pawnBuilder
    206.                 .Add(pawn)
    207.                 .Add<PhysicsCollider>()
    208.                 .Add<DamagePointsToDie>(2)
    209.                 .Add<MovementCost>(1)
    210.                 .Add<MovementRate>(1)
    211.                 .Add(foodSpawn);
    212.             playerBuilder.AddBuffer<PawnsInStoreElement>(pawnBuilder.Entity);
    213.             return pawnBuilder;
    214.         }
    215.     }
     
  6. Roycon

    Roycon

    Joined:
    Jul 10, 2012
    Posts:
    50
    Wow thats alot, but not what I was after.
    If your prefab in the Entity window has your components, then you Instantiate it and it does not then I think your IComponentData's are Objects (Classes) not Structs. When this has happened to me that was my issue

    Also where did InstantiatePrefab come from?
     
  7. Flipps

    Flipps

    Joined:
    Jul 30, 2019
    Posts:
    51
    I also dont know where InstantiatePrefab comes from. Is it an extension method?

    But i think your problem is follows: You try to instantiate an prefab in the Convert method which is called during the conversion process. So the conversion process has not finished yet. It is pure luck which components were already converted and which weren't. (As it seems the phyiscs components are converted before your Instantiation and are therefore not available).

    I think there are two possiblities to fix this:
    - GameObjectConversionUtility.ConvertGameObjectHierarchy(gameObject, conversionSystem.ForkSettings(1)); instead of GetPrimaryEntity(gameObject) -> converts first and ensures the conversion has completed before instantiation
    - Create an Entity with a SpawnComponent on it which has the Entity Prefab on it (which you get by GetPrimaryEntity) and run a SpawnSystem on the SpawnComponent
     
  8. Satananas

    Satananas

    Joined:
    Nov 29, 2018
    Posts:
    6
    @Roycon : InstantiatePrefab is an extension method which calls
    public Entity Instantiate(Entity srcEntity);
    on the EntityManager

    All of my components are structs:
    Code (CSharp):
    1. [WriteGroup(typeof(AwaitPawnFood))]
    2.     [GenerateAuthoringComponent]
    3.     public struct AggressionGene : IGene { public int Used; }
    @Flipps: It is possible that during the conversion process the order of the instantiation is not determined. But it doesn't look like it. Before I call InstantiatePrefab the Entity of the prefab is already present with all desired components.
    And I do have a SpawnComponent. Besides, my prefab doesn't have a Convert To Entity Component. It is only declared in
    Code (CSharp):
    1. public void DeclareReferencedPrefabs(List<GameObject> referencedPrefabs)
    But I will try the GameObjectConversionUtility.
     
  9. Roycon

    Roycon

    Joined:
    Jul 10, 2012
    Posts:
    50
  10. Satananas

    Satananas

    Joined:
    Nov 29, 2018
    Posts:
    6
    GameObjectConversionUtility.ConvertGameObjectHierarchy(gameObject, conversionSystem.ForkSettings(1));
    did the trick. Now every component is being copied to the Entity.

    But I chose to take another route: I synchronize Entities and GameObjects using
    CopyTransformToGameObject.

    @Roycon and @Flipps : Thank you