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. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

How to Create Entity from Prefab in Job?

Discussion in 'Entity Component System' started by alvinwan, May 6, 2020.

  1. alvinwan

    alvinwan

    Joined:
    Jan 21, 2018
    Posts:
    34
    On the main thread, I currently create prefabs by using a helper method like the following.
    Code (CSharp):
    1.     protected Entity GetGhostPrefab<T>() where T : struct, ISnapshotData<T>
    2.     {
    3.         var ghostCollection = GetSingleton<GhostPrefabCollectionComponent>();
    4.         var ghostId = NetCubeGhostSerializerCollection.FindGhostType<T>();
    5.         return EntityManager.GetBuffer<GhostPrefabBuffer>(ghostCollection.serverPrefabs)[ghostId].Value;
    6.     }
    7.  
    8.     protected void SpawnBox() {
    9.         Entity box = EntityManager.Instantiate(GetGhostPrefab<BoxSnapshotData>());
    10.     }

    Is it possible to similarly create entities from prefabs, from within a job? Here is my progress on this particular problem:

    - I know I'll need to create an entity using `EntityCommandBuffer` first.
    - However, `EntityCommandBuffer` requires an archetype as input.
    - Thus... is it possible to extract an archetype from a prefab? Or from a ghost? (Or, is this direction not even advisable?)

    Interested in answers but mostly looking for "what is best practice". Worst comes to worst, I could just `EntityManager.CreateArchetype` but it seems nice and clean to have prefabs.
     
  2. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    I think we're still figuring out best practice.

    So here's my … practice :) Also using NetCode.

    I have a number of helpers as well, in
    NetworkPrefabs
    :
    Code (CSharp):
    1.     public static Entity getProjectileEntity(ComponentSystemBase system)
    2.     {
    3.         var ghostCollection = system.GetSingleton<GhostPrefabCollectionComponent>();
    4.         var ghostId         = NetworkGhostSerializerCollection.FindGhostType<ProjectileSnapshotData>();
    5.         return system.EntityManager.GetBuffer<GhostPrefabBuffer>(ghostCollection.serverPrefabs)[ghostId].Value;
    6.     }

    With this, I get the prefab outside of a job and instantiate it inside a job:
    Code (CSharp):
    1. var commandBuffer    = endFrameBarrier.CreateCommandBuffer().ToConcurrent();
    2. var prefabProjectile = NetworkPrefabs.getProjectileEntity(this);
    3.  
    4. Entities.
    5.     WithNone<Reload>(). // Reloading weapons do not fire.
    6.     WithReadOnly(weaponsMap).
    7.     WithAll<Firing>().
    8.     ForEach(
    9.             // Inside the job, I then instantiate entities from the prefab entity ...
    10.             // ... gathering the necessary data for the projectile (not shown).
    11.             // then instantiating it:
    12.             NetworkPrefabs.instantiateProjectileEntity(
    13.                                                        prefabProjectile,
    14.                                                        commandBuffer,
    15.                                                        entityInQueryIndex,
    16.                                                        ref projectile,
    17.                                                        ref translation,
    18.                                                        ref rotation,
    19.                                                        ref velocity,
    20.                                                        data.soundsId
    21.                                                       );
    22.     }).
    23.     WithName("FiringJobSystem").
    24.     Schedule();
    25.  

    The instantiation helper is a simple wrapper around
    SetComponent
    etc in
    NetworkPrefabs
    :
    Code (CSharp):
    1.     public static Entity instantiateProjectileEntity(
    2.         Entity         prefabProjectile, EntityCommandBuffer.Concurrent commandBuffer, int entityInQueryIndex,
    3.         ref Projectile projectile,       ref Translation translation, ref Rotation rotation, ref Velocity velocity,
    4.         Sounds.Id      sound)
    5.     {
    6.         var projectileEntity = commandBuffer.Instantiate(entityInQueryIndex, prefabProjectile);
    7.         commandBuffer.SetComponent(
    8.                                    entityInQueryIndex,
    9.                                    projectileEntity,
    10.                                    projectile
    11.                                   );
    12.         commandBuffer.SetComponent(
    13.                                    entityInQueryIndex,
    14.                                    projectileEntity,
    15.                                    translation
    16.                                   );
    17.         commandBuffer.SetComponent(
    18.                                    entityInQueryIndex,
    19.                                    projectileEntity,
    20.                                    rotation
    21.                                   );
    22.         commandBuffer.SetComponent(
    23.                                    entityInQueryIndex,
    24.                                    projectileEntity,
    25.                                    velocity
    26.                                   );
    27.         commandBuffer.SetComponent(entityInQueryIndex, projectileEntity, new NetworkedOneShot { Value = sound });
    28.  
    29.         return projectileEntity;
    30.     }

    Curious what other people do.
     
    Last edited: May 6, 2020
    joepl, nicolasgramlich and alvinwan like this.
  3. alvinwan

    alvinwan

    Joined:
    Jan 21, 2018
    Posts:
    34
    @florianhanke Sick, thanks! Seeing your paradigm is really helpful. I can usually hack something together but I highly doubt my hacks are even close to "best practice".... so this is a step forward. :p

    For posterity: Ignore my archetype "progress" in the original post. For whatever reason, didn't occur to me the command buffer would ofc have an analog for EntityManager.Instantiate. Oops. Florian's code clears that up.
     
    florianhanke likes this.
  4. florianhanke

    florianhanke

    Joined:
    Jun 8, 2018
    Posts:
    426
    Hey cool, glad to hear it helps! :)