protected override JobHandle OnUpdate(JobHandle inputDeps) { EntityManager.DestroyEntity(m_DestroyGroup); EntityManager.DestroyEntity(m_InvalidGhosts); m_InvalidGhosts.Clear(); var targetTick = NetworkTimeSystem.interpolateTargetTick; m_CurrentDelayedSpawnList.Clear(); while (m_DelayedSpawnQueue.Count > 0 && !SequenceHelpers.IsNewer(m_DelayedSpawnQueue.Peek().spawnTick, targetTick)) { var ghost = m_DelayedSpawnQueue.Dequeue(); GhostEntity gent; if (m_GhostMap.TryGetValue(ghost.ghostId, out gent)) { m_CurrentDelayedSpawnList.Add(ghost); m_InvalidGhosts.Add(gent.entity); } } m_CurrentPredictedSpawnList.Clear(); while (m_PredictedSpawnQueue.Count > 0) { var ghost = m_PredictedSpawnQueue.Dequeue(); GhostEntity gent; if (m_GhostMap.TryGetValue(ghost.ghostId, out gent)) { m_CurrentPredictedSpawnList.Add(ghost); m_InvalidGhosts.Add(gent.entity); } } var delayedEntities = default(NativeArray <Entity>); delayedEntities = new NativeArray <Entity>(m_CurrentDelayedSpawnList.Length, Allocator.TempJob); if (m_CurrentDelayedSpawnList.Length > 0) { EntityManager.CreateEntity(m_Archetype, delayedEntities); } var predictedEntities = default(NativeArray <Entity>); predictedEntities = new NativeArray <Entity>(m_CurrentPredictedSpawnList.Length, Allocator.TempJob); if (m_CurrentPredictedSpawnList.Length > 0) { EntityManager.CreateEntity(m_PredictedArchetype, predictedEntities); } var predictSpawnRequests = m_SpawnRequestGroup.ToEntityArray(Allocator.TempJob); var predictSpawnEntities = new NativeArray <Entity>(predictSpawnRequests.Length, Allocator.TempJob); if (predictSpawnEntities.Length > 0) { EntityManager.CreateEntity(m_PredictedArchetype, predictSpawnEntities); } var newEntities = default(NativeArray <Entity>); newEntities = new NativeArray <Entity>(m_NewGhosts.Length, Allocator.TempJob); if (m_NewGhosts.Length > 0) { EntityManager.CreateEntity(m_InitialArchetype, newEntities); } if (m_CurrentDelayedSpawnList.Length > 0) { var delayedjob = new DelayedSpawnJob { entities = delayedEntities, delayedGhost = m_CurrentDelayedSpawnList, snapshotFromEntity = GetBufferFromEntity <T>(), ghostMap = m_GhostMap, ghostType = GhostType }; inputDeps = delayedjob.Schedule(inputDeps); inputDeps = UpdateNewInterpolatedEntities(delayedEntities, inputDeps); } // FIXME: current and predicted can run in parallel I think if (m_CurrentPredictedSpawnList.Length > 0) { var delayedjob = new DelayedSpawnJob { entities = predictedEntities, delayedGhost = m_CurrentPredictedSpawnList, snapshotFromEntity = GetBufferFromEntity <T>(), ghostMap = m_GhostMap, ghostType = GhostType }; inputDeps = delayedjob.Schedule(inputDeps); inputDeps = UpdateNewPredictedEntities(predictedEntities, inputDeps); } if (predictSpawnRequests.Length > 0) { var spawnJob = new PredictSpawnJob { requests = predictSpawnRequests, entities = predictSpawnEntities, snapshotFromEntity = GetBufferFromEntity <T>(), commandBuffer = m_Barrier.CreateCommandBuffer(), predictSpawnGhosts = m_PredictSpawnGhosts }; inputDeps = spawnJob.Schedule(inputDeps); inputDeps = UpdateNewPredictedEntities(predictSpawnEntities, inputDeps); } m_PredictionSpawnCleanupMap.Clear(); if (m_NewGhosts.Length > 0) { if (m_PredictionSpawnCleanupMap.Capacity < m_NewGhosts.Length) { m_PredictionSpawnCleanupMap.Capacity = m_NewGhosts.Length; } var predictionMask = new NativeArray <int>(m_NewGhosts.Length, Allocator.TempJob); inputDeps = MarkPredictedGhosts(m_NewGhosts, predictionMask, m_PredictSpawnGhosts, inputDeps); var job = new CopyInitialStateJob { entities = newEntities, newGhosts = m_NewGhosts, newGhostIds = m_NewGhostIds, snapshotFromEntity = GetBufferFromEntity <T>(), ghostMap = m_ConcurrentGhostMap, ghostType = GhostType, pendingSpawnQueue = m_ConcurrentDelayedSpawnQueue, predictedSpawnQueue = m_ConcurrentPredictedSpawnQueue, predictionMask = predictionMask, predictionSpawnGhosts = m_PredictSpawnGhosts, predictionSpawnCleanupMap = m_PredictionSpawnCleanupMap.ToConcurrent(), commandBuffer = m_Barrier.CreateCommandBuffer().ToConcurrent() }; inputDeps = job.Schedule(newEntities.Length, 8, inputDeps); } var spawnClearJob = new PredictSpawnCleanupJob { predictionSpawnCleanupMap = m_PredictionSpawnCleanupMap, predictionSpawnGhosts = m_PredictSpawnGhosts, interpolationTarget = targetTick, commandBuffer = m_Barrier.CreateCommandBuffer(), replicatedEntityComponentType = ComponentType.ReadWrite <ReplicatedEntityComponent>() }; inputDeps = spawnClearJob.Schedule(inputDeps); m_Barrier.AddJobHandleForProducer(inputDeps); var clearJob = new ClearNewJob { entities = newEntities, visibleEntities = delayedEntities, visiblePredictedEntities = predictedEntities, newGhosts = m_NewGhosts, newGhostIds = m_NewGhostIds, predictSpawnEntities = predictSpawnEntities, predictSpawnRequests = predictSpawnRequests }; return(clearJob.Schedule(inputDeps)); }
protected override JobHandle OnUpdate(JobHandle inputDeps) { bool didCompleteAll = false; // Entities can contain LinkedEntityGroup, so query based destruction will not always work if (!m_DestroyGroup.IsEmptyIgnoreFilter) { var destroyGroupEntities = m_DestroyGroup.ToEntityArray(Allocator.TempJob); EntityManager.DestroyEntity(destroyGroupEntities); destroyGroupEntities.Dispose(); didCompleteAll = true; } if (m_InvalidGhosts.Length > 0) { EntityManager.DestroyEntity(m_InvalidGhosts); m_InvalidGhosts.Clear(); didCompleteAll = true; } if (m_NewGhosts.Length == 0 && m_DelayedSpawnQueue.Count == 0 && m_PredictedSpawnQueue.Count == 0 && m_SpawnRequestGroup.IsEmptyIgnoreFilter) { return(inputDeps); } if (m_interpolatedPrefab == Entity.Null) { var prefabs = GetSingleton <GhostPrefabCollectionComponent>(); var interpolatedPrefabs = EntityManager.GetBuffer <GhostPrefabBuffer>(prefabs.clientInterpolatedPrefabs); var predictedPrefabs = EntityManager.GetBuffer <GhostPrefabBuffer>(prefabs.clientPredictedPrefabs); for (int i = 0; i < interpolatedPrefabs.Length; ++i) { if (EntityManager.HasComponent <T>(interpolatedPrefabs[i].Value)) { m_interpolatedPrefab = interpolatedPrefabs[i].Value; break; } } for (int i = 0; i < predictedPrefabs.Length; ++i) { if (EntityManager.HasComponent <T>(predictedPrefabs[i].Value)) { m_predictedPrefab = predictedPrefabs[i].Value; break; } } if (m_interpolatedPrefab == Entity.Null || m_predictedPrefab == Entity.Null) { throw new InvalidOperationException(String.Format( "Could not find interpolated/predicted prefabs for {0}, make sure the GhostPrefabCollectionComponent singleton is correct", typeof(T))); } } var interpolationTargetTick = m_ClientSimulationSystemGroup.InterpolationTick; var predictionTargetTick = m_ClientSimulationSystemGroup.ServerTick; m_CurrentDelayedSpawnList.Clear(); while (m_DelayedSpawnQueue.Count > 0 && !SequenceHelpers.IsNewer(m_DelayedSpawnQueue.Peek().spawnTick, interpolationTargetTick)) { if (!didCompleteAll) { // This will trigger a structural change anyway, so just complete here EntityManager.CompleteAllJobs(); didCompleteAll = true; } var ghost = m_DelayedSpawnQueue.Dequeue(); GhostEntity gent; if (m_GhostMap.TryGetValue(ghost.ghostId, out gent) && gent.entity == ghost.oldEntity) { m_CurrentDelayedSpawnList.Add(ghost); m_InvalidGhosts.Add(gent.entity); } } m_CurrentPredictedSpawnList.Clear(); while (m_PredictedSpawnQueue.Count > 0 && !SequenceHelpers.IsNewer(m_PredictedSpawnQueue.Peek().spawnTick, predictionTargetTick)) { if (!didCompleteAll) { // This will trigger a structural change anyway, so just complete here EntityManager.CompleteAllJobs(); didCompleteAll = true; } var ghost = m_PredictedSpawnQueue.Dequeue(); GhostEntity gent; if (m_GhostMap.TryGetValue(ghost.ghostId, out gent) && gent.entity == ghost.oldEntity) { m_CurrentPredictedSpawnList.Add(ghost); m_InvalidGhosts.Add(gent.entity); } } var delayedEntities = default(NativeArray <Entity>); delayedEntities = new NativeArray <Entity>(m_CurrentDelayedSpawnList.Length, Allocator.TempJob); if (m_CurrentDelayedSpawnList.Length > 0) { EntityManager.Instantiate(m_interpolatedPrefab, delayedEntities); } var predictedEntities = default(NativeArray <Entity>); predictedEntities = new NativeArray <Entity>(m_CurrentPredictedSpawnList.Length, Allocator.TempJob); if (m_CurrentPredictedSpawnList.Length > 0) { EntityManager.Instantiate(m_predictedPrefab, predictedEntities); } var predictSpawnRequests = m_SpawnRequestGroup.ToEntityArray(Allocator.TempJob); var predictSpawnEntities = new NativeArray <Entity>(predictSpawnRequests.Length, Allocator.TempJob); if (predictSpawnEntities.Length > 0) { EntityManager.Instantiate(m_predictedPrefab, predictSpawnEntities); } var newEntities = default(NativeArray <Entity>); newEntities = new NativeArray <Entity>(m_NewGhosts.Length, Allocator.TempJob); if (m_NewGhosts.Length > 0) { EntityManager.CreateEntity(m_InitialArchetype, newEntities); } if (m_CurrentDelayedSpawnList.Length > 0) { var delayedjob = new DelayedSpawnJob { entities = delayedEntities, delayedGhost = m_CurrentDelayedSpawnList, snapshotFromEntity = GetBufferFromEntity <T>(), ghostFromEntity = GetComponentDataFromEntity <GhostComponent>(), ghostMap = m_GhostMap, ghostType = GhostType }; inputDeps = delayedjob.Schedule(inputDeps); m_GhostUpdateSystemGroup.LastGhostMapWriter = inputDeps; inputDeps = UpdateNewInterpolatedEntities(delayedEntities, inputDeps); } // FIXME: current and predicted can run in parallel I think if (m_CurrentPredictedSpawnList.Length > 0) { var delayedjob = new DelayedSpawnJob { entities = predictedEntities, delayedGhost = m_CurrentPredictedSpawnList, snapshotFromEntity = GetBufferFromEntity <T>(), ghostFromEntity = GetComponentDataFromEntity <GhostComponent>(), ghostMap = m_GhostMap, ghostType = GhostType }; inputDeps = delayedjob.Schedule(inputDeps); m_GhostUpdateSystemGroup.LastGhostMapWriter = inputDeps; inputDeps = UpdateNewPredictedEntities(predictedEntities, inputDeps); } if (predictSpawnRequests.Length > 0) { var spawnJob = new PredictSpawnJob { requests = predictSpawnRequests, entities = predictSpawnEntities, snapshotFromEntity = GetBufferFromEntity <T>(), commandBuffer = m_Barrier.CreateCommandBuffer(), predictSpawnGhosts = m_PredictSpawnGhosts }; inputDeps = spawnJob.Schedule(inputDeps); inputDeps = UpdateNewPredictedEntities(predictSpawnEntities, inputDeps); } m_PredictionSpawnCleanupMap.Clear(); if (m_NewGhosts.Length > 0) { if (m_PredictionSpawnCleanupMap.Capacity < m_NewGhosts.Length) { m_PredictionSpawnCleanupMap.Capacity = m_NewGhosts.Length; } NativeArray <int> predictionMask = new NativeArray <int>(m_NewGhosts.Length, Allocator.TempJob); inputDeps = SetPredictedGhostDefaults(m_NewGhosts, predictionMask, inputDeps); inputDeps = MarkPredictedGhosts(m_NewGhosts, predictionMask, m_PredictSpawnGhosts, inputDeps); var job = new CopyInitialStateJob { entities = newEntities, newGhosts = m_NewGhosts, newGhostIds = m_NewGhostIds, snapshotFromEntity = GetBufferFromEntity <T>(), ghostMap = m_ConcurrentGhostMap, ghostType = GhostType, pendingSpawnQueue = m_ConcurrentDelayedSpawnQueue, predictedSpawnQueue = m_ConcurrentPredictedSpawnQueue, predictionMask = predictionMask, predictionSpawnGhosts = m_PredictSpawnGhosts, predictionSpawnCleanupMap = m_PredictionSpawnCleanupMap.AsParallelWriter(), commandBuffer = m_Barrier.CreateCommandBuffer().ToConcurrent() }; inputDeps = job.Schedule(newEntities.Length, 8, inputDeps); m_GhostUpdateSystemGroup.LastGhostMapWriter = inputDeps; } var spawnClearJob = new PredictSpawnCleanupJob { predictionSpawnCleanupMap = m_PredictionSpawnCleanupMap, predictionSpawnGhosts = m_PredictSpawnGhosts, interpolationTarget = interpolationTargetTick, commandBuffer = m_Barrier.CreateCommandBuffer(), ghostComponentType = ComponentType.ReadWrite <GhostComponent>() }; inputDeps = spawnClearJob.Schedule(inputDeps); m_Barrier.AddJobHandleForProducer(inputDeps); var clearJob = new ClearNewJob { entities = newEntities, visibleEntities = delayedEntities, visiblePredictedEntities = predictedEntities, newGhosts = m_NewGhosts, newGhostIds = m_NewGhostIds, predictSpawnEntities = predictSpawnEntities, predictSpawnRequests = predictSpawnRequests }; return(clearJob.Schedule(inputDeps)); }