Esempio n. 1
0
        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}");
        }
Esempio n. 2
0
        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();
        }