Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice

Netcode: Instantiate new entities

Discussion in 'NetCode for ECS' started by enativ, Mar 25, 2020.

  1. enativ

    enativ

    Joined:
    Nov 8, 2019
    Posts:
    1
    I've started working with the new netcode package and I was wondering about systems that Instantiate new entities.

    I was following the Unity multiplayers sampleproject and encountered with this system:

    Code (CSharp):
    1.  
    2. namespace Asteroids.Mixed
    3. {
    4.     [UpdateInGroup(typeof(GhostPredictionSystemGroup))]
    5.     public class SteeringSystem : JobComponentSystem
    6.     {
    7.         private BeginSimulationEntityCommandBufferSystem barrier;
    8.         private GhostPredictionSystemGroup predictionGroup;
    9.         private Entity bulletPrefab;
    10.         private EntityArchetype bulletSpawnArchetype;
    11.         private uint lastSpawnTick;
    12.         //[BurstCompile]
    13.         [RequireComponentTag(typeof(ShipTagComponentData), typeof(ShipCommandData))]
    14.         struct SteeringJob : IJobForEachWithEntity<Translation, Rotation, Velocity, ShipStateComponentData, PlayerIdComponentData, PredictedGhostComponent>
    15.         {
    16.             private const int k_CoolDownTicksCount = 10;
    17.             public EntityCommandBuffer.Concurrent commandBuffer;
    18.             public float deltaTime;
    19.             public float displacement;
    20.             public float playerForce;
    21.             public float bulletVelocity;
    22.             public Entity bulletPrefab;
    23.             public EntityArchetype bulletSpawnArchetype;
    24.             public uint currentTick;
    25.             [ReadOnly] public BufferFromEntity<ShipCommandData> inputFromEntity;
    26.             public void Execute(Entity entity, int index, ref Translation position, ref Rotation rotation, ref Velocity velocity,
    27.                 ref ShipStateComponentData state, [ReadOnly] ref PlayerIdComponentData playerIdData, [ReadOnly] ref PredictedGhostComponent prediction)
    28.             {
    29.                 if (!GhostPredictionSystemGroup.ShouldPredict(currentTick, prediction))
    30.                     return;
    31.                 var input = inputFromEntity[entity];
    32.                 ShipCommandData inputData;
    33.                 if (!input.GetDataAtTick(currentTick, out inputData))
    34.                     inputData.shoot = 0;
    35.                 state.State = inputData.thrust;
    36.                 if (inputData.left == 1)
    37.                 {
    38.                     rotation.Value = math.mul(rotation.Value, quaternion.RotateZ(math.radians(-displacement * deltaTime)));
    39.                 }
    40.                 if (inputData.right == 1)
    41.                 {
    42.                     rotation.Value = math.mul(rotation.Value, quaternion.RotateZ(math.radians(displacement * deltaTime)));
    43.                 }
    44.                 if (inputData.thrust == 1)
    45.                 {
    46.                     float3 fwd = new float3(0, playerForce * deltaTime, 0);
    47.                     velocity.Value += math.mul(rotation.Value, fwd).xy;
    48.                 }
    49.                 position.Value.xy += velocity.Value * deltaTime;
    50.                 var canShoot = state.WeaponCooldown == 0 || SequenceHelpers.IsNewer(currentTick, state.WeaponCooldown);
    51.                 if (inputData.shoot != 0 && canShoot)
    52.                 {
    53.                     if (bulletPrefab != Entity.Null)
    54.                     {
    55.                         var e = commandBuffer.Instantiate(index, bulletPrefab);
    56.                         commandBuffer.SetComponent(index, e, position);
    57.                         commandBuffer.SetComponent(index, e, rotation);
    58.                         var vel = new Velocity
    59.                             {Value = math.mul(rotation.Value, new float3(0, bulletVelocity, 0)).xy};
    60.                         commandBuffer.SetComponent(index, e,
    61.                             new PlayerIdComponentData {PlayerId = playerIdData.PlayerId});
    62.                         commandBuffer.SetComponent(index, e, vel);
    63.                     }
    64.                     else
    65.                     {
    66.                         var e = commandBuffer.CreateEntity(index, bulletSpawnArchetype);
    67.                         var bulletData = default(BulletSnapshotData);
    68.                         bulletData.tick = currentTick;
    69.                         bulletData.SetRotationValue(rotation.Value);
    70.                         bulletData.SetTranslationValue(position.Value);
    71.                         // Offset bullets for debugging spawn prediction
    72.                         //bulletData.SetTranslationValue(position.Value + new float3(0,10,0));
    73.                         bulletData.SetPlayerIdComponentDataPlayerId(playerIdData.PlayerId, default(GhostSerializerState));
    74.                         var bulletSnapshots = commandBuffer.SetBuffer<BulletSnapshotData>(index, e);
    75.                         bulletSnapshots.Add(bulletData);
    76.                     }
    77.                     state.WeaponCooldown = currentTick + k_CoolDownTicksCount;
    78.                 }
    79.                 else if (canShoot)
    80.                 {
    81.                     state.WeaponCooldown = 0;
    82.                 }
    83.             }
    84.         }
    85.         protected override void OnCreate()
    86.         {
    87.             barrier = World.GetOrCreateSystem<BeginSimulationEntityCommandBufferSystem>();
    88.             predictionGroup = World.GetOrCreateSystem<GhostPredictionSystemGroup>();
    89.             RequireSingletonForUpdate<LevelComponent>();
    90.         }
    91.         protected override JobHandle OnUpdate(JobHandle inputDeps)
    92.         {
    93.             if (bulletPrefab == Entity.Null && bulletSpawnArchetype == default)
    94.             {
    95.                 if (World.GetExistingSystem<ServerSimulationSystemGroup>() != null)
    96.                 {
    97.                     var prefabs = GetSingleton<GhostPrefabCollectionComponent>();
    98.                     var serverPrefabs = EntityManager.GetBuffer<GhostPrefabBuffer>(prefabs.serverPrefabs);
    99.                     for (int i = 0; i < serverPrefabs.Length; ++i)
    100.                     {
    101.                         if (EntityManager.HasComponent<BulletTagComponent>(serverPrefabs[i].Value))
    102.                             bulletPrefab = serverPrefabs[i].Value;
    103.                     }
    104.                 }
    105.                 else
    106.                 {
    107.                     bulletSpawnArchetype = EntityManager.CreateArchetype(
    108.                         ComponentType.ReadWrite<PredictedGhostSpawnRequestComponent>(),
    109.                         ComponentType.ReadWrite<BulletSnapshotData>());
    110.                 }
    111.             }
    112.             var level = GetSingleton<LevelComponent>();
    113.             var steerJob = new SteeringJob
    114.             {
    115.                 commandBuffer = barrier.CreateCommandBuffer().ToConcurrent(),
    116.                 deltaTime = Time.DeltaTime,
    117.                 displacement = 100.0f,
    118.                 playerForce = level.playerForce,
    119.                 bulletVelocity = level.bulletVelocity,
    120.                 bulletPrefab = bulletPrefab,
    121.                 bulletSpawnArchetype = bulletSpawnArchetype,
    122.                 currentTick = predictionGroup.PredictingTick,
    123.                 inputFromEntity = GetBufferFromEntity<ShipCommandData>(true)
    124.             };
    125.             var handle = steerJob.Schedule(this, inputDeps);
    126.             barrier.AddJobHandleForProducer(handle);
    127.             return handle;
    128.         }
    129.     }
    130. }
    131.  
    I did not quiet understood this code segment,
    why do this Instantiate the entity (BulletSnapshotData) in both the Server and the Client, and how does it get synchronized to be the same Bullet in both worlds?