protected override JobHandle OnUpdate(JobHandle inputDeps) { m_SerialSpawnChunks.Clear(); // Make sure the list of connections and connection state is up to date var connections = connectionGroup.ToEntityArray(Allocator.TempJob); var existing = new NativeHashMap <Entity, int>(connections.Length, Allocator.Temp); for (int i = 0; i < connections.Length; ++i) { existing.TryAdd(connections[i], 1); int stateIndex; if (!m_ConnectionStateLookup.TryGetValue(connections[i], out stateIndex)) { m_ConnectionStates.Add(new ConnectionStateData { Entity = connections[i], SerializationState = new NativeHashMap <ArchetypeChunk, SerializationState>(1024, Allocator.Persistent) }); m_ConnectionStateLookup.TryAdd(connections[i], m_ConnectionStates.Count - 1); } } connections.Dispose(); for (int i = 0; i < m_ConnectionStates.Count; ++i) { int val; if (!existing.TryGetValue(m_ConnectionStates[i].Entity, out val)) { m_ConnectionStateLookup.Remove(m_ConnectionStates[i].Entity); m_ConnectionStates[i].Dispose(); if (i != m_ConnectionStates.Count - 1) { m_ConnectionStates[i] = m_ConnectionStates[m_ConnectionStates.Count - 1]; m_ConnectionStateLookup.Remove(m_ConnectionStates[i].Entity); m_ConnectionStateLookup.TryAdd(m_ConnectionStates[i].Entity, i); } m_ConnectionStates.RemoveAt(m_ConnectionStates.Count - 1); } } // Find the latest tick which has been acknowledged by all clients and cleanup all ghosts destroyed ebfore that uint currentTick = m_ServerSimulation.ServerTick; var ackedByAll = new NativeArray <uint>(1, Allocator.TempJob); ackedByAll[0] = currentTick; var findAckJob = new FindAckedByAllJob { tick = ackedByAll }; inputDeps = findAckJob.ScheduleSingle(this, inputDeps); EntityCommandBuffer commandBuffer = m_Barrier.CreateCommandBuffer(); var ghostCleanupJob = new CleanupGhostJob { currentTick = currentTick, tick = ackedByAll, commandBuffer = commandBuffer.ToConcurrent(), freeGhostIds = m_FreeGhostIds.AsParallelWriter(), ghostStateType = ComponentType.ReadWrite <GhostSystemStateComponent>() }; inputDeps = ghostCleanupJob.Schedule(this, inputDeps); var entityType = GetArchetypeChunkEntityType(); var ghostSystemStateType = GetArchetypeChunkComponentType <GhostSystemStateComponent>(); serializers.BeginSerialize(this); // Extract all newly spawned ghosts and set their ghost ids JobHandle spawnChunkHandle; var spawnChunks = ghostSpawnGroup.CreateArchetypeChunkArray(Allocator.TempJob, out spawnChunkHandle); var spawnJob = new SpawnGhostJob { spawnChunks = spawnChunks, serialSpawnChunks = m_SerialSpawnChunks, entityType = entityType, serializers = serializers, freeGhostIds = m_FreeGhostIds, allocatedGhostIds = m_AllocatedGhostIds, commandBuffer = commandBuffer }; inputDeps = spawnJob.Schedule(JobHandle.CombineDependencies(inputDeps, spawnChunkHandle)); // This was the last job using the commandBuffer m_Barrier.AddJobHandleForProducer(inputDeps); JobHandle despawnChunksHandle, ghostChunksHandle; var despawnChunks = ghostDespawnGroup.CreateArchetypeChunkArray(Allocator.TempJob, out despawnChunksHandle); var ghostChunks = ghostGroup.CreateArchetypeChunkArray(Allocator.TempJob, out ghostChunksHandle); inputDeps = JobHandle.CombineDependencies(inputDeps, despawnChunksHandle, ghostChunksHandle); var serialDep = new NativeArray <JobHandle>(m_ConnectionStates.Count + 1, Allocator.Temp); // In case there are 0 connections serialDep[0] = inputDeps; for (int con = 0; con < m_ConnectionStates.Count; ++con) { var connectionEntity = m_ConnectionStates[con].Entity; var chunkSerializationData = m_ConnectionStates[con].SerializationState; var serializeJob = new SerializeJob { driver = m_ReceiveSystem.ConcurrentDriver, unreliablePipeline = m_ReceiveSystem.UnreliablePipeline, despawnChunks = despawnChunks, ghostChunks = ghostChunks, connectionEntity = connectionEntity, chunkSerializationData = chunkSerializationData, ackFromEntity = GetComponentDataFromEntity <NetworkSnapshotAckComponent>(true), connectionFromEntity = GetComponentDataFromEntity <NetworkStreamConnection>(true), serialSpawnChunks = m_SerialSpawnChunks, entityType = entityType, ghostSystemStateType = ghostSystemStateType, serializers = serializers, compressionModel = m_CompressionModel, currentTick = currentTick, localTime = NetworkTimeSystem.TimestampMS }; // FIXME: disable safety for BufferFromEntity is not working serialDep[con + 1] = serializeJob.Schedule(serialDep[con]); } inputDeps = JobHandle.CombineDependencies(serialDep); var cleanupJob = new CleanupJob { despawnChunks = despawnChunks, spawnChunks = spawnChunks, ghostChunks = ghostChunks, serialSpawnChunks = m_SerialSpawnChunks }; inputDeps = cleanupJob.Schedule(inputDeps); return(inputDeps); }
protected override void OnUpdate() { uint tick = _ghostPredictionSystemGroup.PredictingTick; // 新添加的ghost Entities.With(ghostSpawnGroup).ForEach((Entity ent, ref GhostComponent ghostComponent) => { ++_ghostInstanceId; ghostComponent.Id = _ghostInstanceId; PostUpdateCommands.AddComponent(ent, new GhostSystemStateComponent { ghostId = ghostComponent.Id }); _newGhosts.Add(ghostComponent.Id, ent); }); ClientServerTickRate tickRate = default; if (HasSingleton <ClientServerTickRate>()) { tickRate = GetSingleton <ClientServerTickRate>(); } tickRate.ResolveDefaults(); int networkTickInterval = tickRate.SimulationTickRate / tickRate.NetworkTickRate; if (tick % networkTickInterval != 0) { return; } var localTime = NetworkTimeSystem.TimestampMS; // 需要发送快照的ghost chunk // 已经按照原型分块了 NativeArray <ArchetypeChunk> ghostChunks = ghostGroup.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out JobHandle ghostChunksHandle); NativeArray <ArchetypeChunk> despawnChunks = ghostDespawnGroup.CreateArchetypeChunkArrayAsync(Allocator.TempJob, out JobHandle despawnChunksHandle); JobHandle.CompleteAll(ref ghostChunksHandle, ref despawnChunksHandle); var connections = connectionGroup.ToEntityArray(Allocator.TempJob); // 获取动态组件类型 var ghostSerializerCollectionSystem = World.GetExistingSystem <GhostCollectionSystem>(); for (int i = 0; i < connections.Length; i++) { SerializeJob serializeJob = new SerializeJob { ConnectionEntity = connections[i], ConnectionFromEntity = GetComponentDataFromEntity <NetworkStreamConnection>(), AckFromEntity = GetComponentDataFromEntity <NetworkSnapshotAckComponent>(), LocalTime = localTime, Tick = tick, NetDriver = _driver.ToConcurrent(), CompressionModel = _compressionModel, UnreliablePipeline = _unreliablePipeline, GhostChunks = ghostChunks, DespawnChunks = despawnChunks, EntityTypeHandle = GetEntityTypeHandle(), GhostTypeHandle = GetComponentTypeHandle <GhostComponent>(), GhostSystemStateTypeHandle = GetComponentTypeHandle <GhostSystemStateComponent>(), GhostTypeCollection = ghostSerializerCollectionSystem.GhostTypeCollection, GhostComponentIndex = ghostSerializerCollectionSystem.IndexCollection, GhostComponentSerializers = ghostSerializerCollectionSystem.Serializers, }; // FIXME var listLength = ghostSerializerCollectionSystem.Serializers.Length; if (listLength <= 32) { var dynamicListJob = new SerializeJob32 { Job = serializeJob }; DynamicTypeList.PopulateList(this, ghostSerializerCollectionSystem.Serializers, true, ref dynamicListJob.List); dynamicListJob.Schedule().Complete(); } } // 移除的ghost Entities.With(ghostDespawnGroup).ForEach((Entity ent, ref GhostSystemStateComponent state) => { _newGhosts.Remove(state.ghostId); PostUpdateCommands.RemoveComponent <GhostSystemStateComponent>(ent); }); connections.Dispose(); ghostChunks.Dispose(); despawnChunks.Dispose(); }