protected override void OnUpdate() { if (connectionGroup.IsEmptyIgnoreFilter) { predictTargetTick = 0; latestSnapshotEstimate = 0; return; } var tickRate = default(ClientServerTickRate); if (HasSingleton <ClientServerTickRate>()) { tickRate = GetSingleton <ClientServerTickRate>(); } tickRate.ResolveDefaults(); var ack = GetSingleton <NetworkSnapshotAckComponent>(); // FIXME: 根据延迟进行调整 uint interpolationTimeMS = KInterpolationTimeMS; if (interpolationTimeMS == 0) { // 2000 + 19 / 20 = 100.95ms = 100ms interpolationTimeMS = (1000 * KInterpolationTimeMS + (uint)tickRate.NetworkTickRate - 1) / (uint)tickRate.NetworkTickRate; } // 估计往返时间 float estimatedRTT = ack.EstimatedRTT; // 固定+2.5f float interpolationFrames = 0.5f + kTargetCommandSlack + ((estimatedRTT + 4 * ack.DeviationRTT + interpolationTimeMS) / 1000f) * tickRate.SimulationTickRate; if (latestSnapshotEstimate == 0) { if (ack.LastReceivedSnapshotByLocal == 0) { predictTargetTick = 0; return; } latestSnapshotEstimate = ack.LastReceivedSnapshotByLocal; // 估算出服务端tick predictTargetTick = GetCurrentPredictTick(estimatedRTT, tickRate.SimulationTickRate); currentInterpolationFrames = interpolationFrames; for (int i = 0; i < commandAgeAdjustment.Length; ++i) { commandAgeAdjustment[i] = 0; } } else { latestSnapshotEstimate = ack.LastReceivedSnapshotByLocal; } int curSlot = (int)(ack.LastReceivedSnapshotByLocal % commandAgeAdjustment.Length); // 当来一个新的数据时,清除前面的数据. if (curSlot != commandAgeAdjustmentSlot) { for (int i = (commandAgeAdjustmentSlot + 1) % commandAgeAdjustment.Length; i != (curSlot + 1) % commandAgeAdjustment.Length; i = (i + 1) % commandAgeAdjustment.Length) { commandAgeAdjustment[i] = 0; } commandAgeAdjustmentSlot = curSlot; } // 服务器输入buffer的数量 负数:没被消耗的数量 正数:服务端不够的数量 float commandAge = ack.ServerCommandAge / 256f + kTargetCommandSlack; // 估算rtt有多少个tick int rttInTicks = (int)((uint)estimatedRTT * (uint)tickRate.SimulationTickRate / 1000); if (rttInTicks > commandAgeAdjustment.Length) { rttInTicks = commandAgeAdjustment.Length; } // 因为commandAge是在服务器上计算并发送到客户端的,所以我们必须等待一个完整的RTT进行调整,直到在客户端上看到对commandAge的任何更新。 // 为了弥补这一点,我们跟踪了在一个完整的RTT(即commandAgeAdjustment循环缓冲区)期间尝试调整commandAge的量的近似值。 // 记录了在一个完整RTT中客户端自己调整commandAge的值 // 每次Update时为了从最后一次收到的commandAge(每次计算都是从最后一次收到服务端的age计算的)值中,还原客户端自己最新调整的值(为了接着上次自己调整的值继续调整)。 for (int i = 0; i < rttInTicks; ++i) { commandAge -= commandAgeAdjustment[ (commandAgeAdjustment.Length + commandAgeAdjustmentSlot - i) % commandAgeAdjustment.Length]; } // 有多少个tick 1s/50tick float deltaTicks = Time.DeltaTime * tickRate.SimulationTickRate; float predictionTimeScale = 1.0f; // 小于10个tick,就进行微调。 if (math.abs(commandAge) < 10) { predictionTimeScale = math.clamp(1.0f + 0.1f * commandAge, 0.9f, 1.1f); subPredictTargetTick += deltaTicks * predictionTimeScale; uint pdiff = (uint)subPredictTargetTick; subPredictTargetTick -= pdiff; predictTargetTick += pdiff; } else // 大于10个刻度,重新预测.直接追上最新预测. { uint curPredict = GetCurrentPredictTick(estimatedRTT, tickRate.SimulationTickRate); for (int i = 0; i < commandAgeAdjustment.Length; ++i) { commandAgeAdjustment[i] = 0; } subPredictTargetTick = 0; predictTargetTick = curPredict; return; } // 记录客户端自己对commandAge进行调整的值(在一个完整RTT期间中,客户端都是自己在尝试对commandAge进行调整.) // 以便在下一个commandAge没到之前,自行对commandAge尝试调整(每次Update调用都会进行调整,所有记录了一个完整RTT期间尝试的调整值). commandAgeAdjustment[commandAgeAdjustmentSlot] += deltaTicks * (predictionTimeScale - 1.0f); #if UNITY_EDITOR || DEVELOPMENT_BUILD NetDebug.Set(nameof(commandAge), commandAge); NetDebug.Set(nameof(predictionTimeScale), predictionTimeScale); NetDebug.Set(nameof(predictTargetTick), predictTargetTick); #endif // currentInterpolationFrames += // math.clamp((interpolationFrames - currentInterpolationFrames * 0.1f), -0.1f, 0.1f); // // var idiff = (uint) currentInterpolationFrames; // interpolateTargetTick = predictTargetTick - idiff; // var subidiff = currentInterpolationFrames - idiff; // subidiff -= subInterpolateTargetTick + subPredictTargetTick; // if (subidiff < 0) // { // ++interpolateTargetTick; // subidiff = -subidiff; // } // else if (subidiff > 0) // { // idiff = (uint) subidiff; // subidiff -= idiff; // interpolateTargetTick -= idiff; // subidiff = 1f - subidiff; // } // // subInterpolateTargetTick = subidiff; _renderTime.TickRate = tickRate; _renderTime.UpdateTime(ack.LastReceivedSnapshotByLocal, Time.DeltaTime); interpolateTargetTick = _renderTime.InterpolateTargetTick; subInterpolateTargetTick = _renderTime.InterpolateFaction; NetDebug.RenderTick = interpolateTargetTick; NetDebug.Set("lastRecvSnapDiff", $"{_renderTime.Diff}| Error:{_renderTime.Error} Min:{_renderTime.MinError} Max:{_renderTime.MaxError}"); }
protected override unsafe void OnUpdate() { var session = GetSingletonEntity <CommandTargetComponent>(); var inBuffer = EntityManager.GetBuffer <IncomingSnapshotDataStreamBufferComponent>(session); var reader = inBuffer.AsDataStreamReader(); if (reader.Length == 0) { return; } #if UNITY_EDITOR || DEVELOPMENT_BUILD NetDebug.SnapMS = reader.Length; NetDebug.DownCount += reader.Length; #endif uint serverTick = reader.ReadUInt(); var ack = EntityManager.GetComponentData <NetworkSnapshotAckComponent>(session); if (ack.IsOldWithLastReceivedSnapshotByLocal(serverTick)) { return; } ack.UpdateLocalValues(serverTick); PostUpdateCommands.SetComponent(session, ack); uint destroyLen = reader.ReadUInt(); uint len = reader.ReadUInt(); for (int i = 0; i < destroyLen; i++) { int ghostId = reader.ReadPackedInt(_networkCompressionModel); if (!_ghostEntityMap.TryGetValue(ghostId, out Entity ent)) { continue; } var s = new GhostDespawnSystem.DelayedDespawnGhost { Ghost = new SpawnedGhost { GhostId = ghostId, SpawnTick = EntityManager.GetComponentData <GhostComponent>(ent).SpawnTick }, Tick = serverTick }; _ghostEntityMap.Remove(ghostId); if (EntityManager.HasComponent <GhostPredictionComponent>(ent)) { _ghostDespawnSystem.AddToPredicted(s); } else { _ghostDespawnSystem.AddToInterpolated(s); } } var ghostSerializerCollectionSystem = World.GetExistingSystem <GhostCollectionSystem>(); var ghostSpawnEntity = GetSingletonEntity <GhostSpawnQueueComponent>(); var bufferFromEntity = GetBufferFromEntity <SnapshotDataBuffer>(); var spawnBufferFromEntity = GetBufferFromEntity <GhostSpawnBuffer>(); var compFromEntity = GetComponentDataFromEntity <SnapshotData>(); for (int i = 0; i < len; i++) { int ghostType = reader.ReadPackedInt(_networkCompressionModel); int ghostId = reader.ReadPackedInt(_networkCompressionModel); if (ghostType < 0 || ghostType >= ghostSerializerCollectionSystem.GhostTypeCollection.Length) { throw new Exception($"GhostRecvSystem:GhostType={ghostType}, GhostId={ghostId}"); } // 序列化组件信息 var typeState = ghostSerializerCollectionSystem.GhostTypeCollection[ghostType]; var baseOffset = typeState.FirstComponent; var numBaseComponents = typeState.NumComponents; byte *snapshotData; DynamicBuffer <SnapshotDataBuffer> snapshotDataBuffer; SnapshotData snapshotDataComponent; bool existingGhost = _ghostEntityMap.TryGetValue(ghostId, out Entity gent); if (existingGhost && bufferFromEntity.HasComponent(gent) && compFromEntity.HasComponent(gent)) { snapshotDataBuffer = bufferFromEntity[gent]; snapshotData = (byte *)snapshotDataBuffer.GetUnsafePtr(); snapshotDataComponent = compFromEntity[gent]; snapshotDataComponent.LatestIndex = (snapshotDataComponent.LatestIndex + 1) % GlobalConstants.SnapshotHistorySize; compFromEntity[gent] = snapshotDataComponent; } else { var ghostSpawnBuffer = spawnBufferFromEntity[ghostSpawnEntity]; snapshotDataBuffer = bufferFromEntity[ghostSpawnEntity]; var snapshotDataBufferOffset = snapshotDataBuffer.Length; ghostSpawnBuffer.Add(new GhostSpawnBuffer { GhostType = ghostType, GhostId = ghostId, ClientSpawnTick = serverTick, ServerSpawnTick = serverTick, DataOffset = snapshotDataBufferOffset }); snapshotDataBuffer.ResizeUninitialized(snapshotDataBufferOffset + typeState.SnapshotSize); snapshotData = (byte *)snapshotDataBuffer.GetUnsafePtr() + snapshotDataBufferOffset; UnsafeUtility.MemClear(snapshotData, typeState.SnapshotSize); snapshotDataComponent = new SnapshotData { SnapshotSize = typeState.SnapshotSize, LatestIndex = 0 }; } // 把快照放到对应内存中 snapshotData += typeState.SnapshotSize * snapshotDataComponent.LatestIndex; *((uint *)snapshotData) = serverTick; snapshotData += GlobalConstants.TickSize; // 放到快照对应内存位置 for (int j = 0; j < numBaseComponents; j++) { var compIdx = ghostSerializerCollectionSystem.IndexCollection[baseOffset + j].ComponentIndex; var serializer = ghostSerializerCollectionSystem.Serializers[compIdx]; serializer.Deserialize.Ptr.Invoke((IntPtr)snapshotData, ref reader, ref _networkCompressionModel); snapshotData += serializer.DataSize; } } #if UNITY_EDITOR || DEVELOPMENT_BUILD NetDebug.Set(nameof(ack.LastReceivedSnapshotByLocal), ack.LastReceivedSnapshotByLocal); NetDebug.Set(nameof(ack.EstimatedRTT), ack.EstimatedRTT); NetDebug.Set(nameof(ack.DeviationRTT), ack.DeviationRTT); NetDebug.RTT = (uint)ack.EstimatedRTT; NetDebug.Jitter = (uint)ack.DeviationRTT; #endif inBuffer.Clear(); }