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));
    }
Exemple #2
0
        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));
        }