public override void UpdateAfter()
        {
            if (!m_clientReady || !m_hasTypeTable || ClientState == null)
            {
                return;
            }

            NetProfiler.Begin("Replication client update", 0);

            var simulationTime = m_callback.GetUpdateTime();

            if (m_clientStartTimeStamp == MyTimeSpan.Zero)
            {
                m_clientStartTimeStamp = simulationTime; // (uint)DateTime.Now.TimeOfDay.TotalMilliseconds;
            }
            var timeStamp = simulationTime - m_clientStartTimeStamp;

            UpdatePingSmoothing();
            NetProfiler.CustomTime("Ping", (float)m_ping.Milliseconds, "{0} ms");
            NetProfiler.CustomTime("SmoothPing", (float)m_smoothPing.Milliseconds, "{0} ms");

            NetProfiler.Begin("Packet stats");
            NetProfiler.CustomTime("Server Drops", (float)m_serverStats.Drops, "{0}");
            NetProfiler.CustomTime("Server OutOfOrder", (float)m_serverStats.OutOfOrder, "{0}");
            NetProfiler.CustomTime("Server Duplicates", (float)m_serverStats.Duplicates, "{0}");
            NetProfiler.CustomTime("Client Drops", (float)m_clientStatsFromServer.Drops, "{0}");
            NetProfiler.CustomTime("Client OutOfOrder", (float)m_clientStatsFromServer.OutOfOrder, "{0}");
            NetProfiler.CustomTime("Client Duplicates", (float)m_clientStatsFromServer.Duplicates, "{0}");
            m_serverStats.Reset();
            m_clientStatsFromServer.Reset();
            NetProfiler.End();

            MyTimeSpan ping = UseSmoothPing ? m_smoothPing : m_ping;
            var        diffCorrection = -ping.Milliseconds * m_callback.GetServerSimulationRatio();
            var        diffMS = timeStamp.Milliseconds - m_lastServerTimeStamp.Milliseconds;
            var        correctionCurrent = diffMS + diffCorrection;
            int        correction = 0, nextFrameDelta = 0;
            MyTimeSpan currentTime   = MyTimeSpan.FromTicks(Stopwatch.GetTimestamp());
            MyTimeSpan realtimeDelta = currentTime - m_lastTime;

            // try to be always one simulation step ahead
            correctionCurrent -= m_simulationTimeStep;
            //if (Math.Abs(correctionCurrent) > 200)
            //  m_correctionSmooth = MyTimeSpan.FromMilliseconds(correctionCurrent);
            correctionCurrent = Math.Min(correctionCurrent, (int)(m_simulationTimeStep * 2 / m_callback.GetServerSimulationRatio()));

            if (diffMS < -MAX_TIMESTAMP_DIFF_LOW || diffMS > MAX_TIMESTAMP_DIFF_HIGH)
            {
                m_clientStartTimeStamp = MyTimeSpan.FromMilliseconds(m_clientStartTimeStamp.Milliseconds + diffMS);

                timeStamp          = simulationTime - m_clientStartTimeStamp;
                m_correctionSmooth = MyTimeSpan.Zero;
                TimestampReset();
                if (VRage.MyCompilationSymbols.EnableNetworkPositionTracking)
                {
                    Trace.MyTrace.Send(Trace.TraceWindow.MTiming, "---------------------------------------------------------------- DESYNC");
                }
            }
            else
            {
                var factor = Math.Min(realtimeDelta.Seconds / SmoothCorrectionAmplitude, 1.0);
                m_correctionSmooth = MyTimeSpan.FromMilliseconds(correctionCurrent * factor + m_correctionSmooth.Milliseconds * (1 - factor));
                // special case: we really dont want the client timestamp to fall behind
                if (diffMS < 0)
                {
                    correction = (int)correctionCurrent;
                }
                else
                {
                    correction = UseSmoothCorrection ? (int)m_correctionSmooth.Milliseconds : (int)correctionCurrent;
                }

                NetProfiler.CustomTime("Correction", (float)correctionCurrent, "{0} ms");
                NetProfiler.CustomTime("SmoothCorrection", (float)m_correctionSmooth.Milliseconds, "{0} ms");

                if (ApplyCorrectionsDebug && (LastMessageFromServer - DateTime.UtcNow).Seconds < 1.0f)
                {
                    if (diffMS < 0)
                    {
                        nextFrameDelta = correction;
                        m_callback.SetNextFrameDelayDelta(nextFrameDelta);
                    }
                    else if (Math.Abs(correction) > TimestampCorrectionMinimum)
                    {
                        nextFrameDelta = (Math.Abs(correction) - TimestampCorrectionMinimum) * Math.Sign(correction);
                        m_callback.SetNextFrameDelayDelta(nextFrameDelta);
                    }
                }
            }
            NetProfiler.CustomTime("GameTimeDelta", (float)(timeStamp - Timestamp).Milliseconds, "{0} ms");
            NetProfiler.CustomTime("RealTimeDelta", (float)realtimeDelta.Milliseconds, "{0} ms");
            Timestamp = timeStamp;

            //if (VRage.MyCompilationSymbols.EnableNetworkPositionTracking)
            {
                string trace = "realtime delta: " + realtimeDelta +
                               ", client: " + Timestamp +
                               ", server: " + m_lastServerTimeStamp +
                               ", diff: " + diffMS.ToString("##.#") + " => " + (Timestamp.Milliseconds - m_lastServerTimeStamp.Milliseconds).ToString("##.#") +
                               ", Ping: " + m_ping.Milliseconds.ToString("##.#") + " / " + m_smoothPing.Milliseconds.ToString("##.#") +
                               "ms, Correction " + correctionCurrent + " / " + m_correctionSmooth.Milliseconds + " / " + nextFrameDelta +
                               ", ratio " + m_callback.GetServerSimulationRatio();
                Trace.MyTrace.Send(Trace.TraceWindow.MTiming, trace);
                //Trace.MyTrace.Send(Trace.TraceWindow.MPositions2, trace);
            }
            m_lastTime = currentTime;

            NetProfiler.End();

            if (StressSleep.X > 0)
            {
                int sleep;
                if (StressSleep.Z == 0)
                {
                    sleep = MyRandom.Instance.Next(StressSleep.X, StressSleep.Y);
                }
                else
                {
                    sleep = (int)(Math.Sin(simulationTime.Milliseconds * Math.PI / StressSleep.Z) * StressSleep.Y + StressSleep.X);
                }
                System.Threading.Thread.Sleep(sleep);
            }
        }