private void ProcessMessage(byte[] data, int dataSize, ulong sender, TimeSpan timestamp)
        {
            Debug.Assert(data.Length >= dataSize, "Wrong size");

            MyMessageId id = (MyMessageId)data[0];

            MyPacket p = new MyPacket();

            p.Data          = data;
            p.PayloadOffset = 1; // First byte is message id
            p.PayloadLength = dataSize - p.PayloadOffset;
            p.Sender        = new VRage.Network.EndpointId(sender);
            p.Timestamp     = timestamp;

            Action <MyPacket> handler;

            if (m_handlers.TryGetValue(id, out handler))
            {
                ProfilerShort.Begin(MyEnum <MyMessageId> .GetName(id));
                NetProfiler.Begin(MyEnum <MyMessageId> .GetName(id));
                handler(p);
                NetProfiler.End(p.PayloadLength);
                ProfilerShort.End();
            }
            else
            {
                Debug.Fail("No handler for message type: " + id);
            }
        }
        /// <summary>
        /// Processes state sync sent by server.
        /// </summary>
        public void ProcessStateSync(MyPacket packet)
        {
            // Simulated packet loss
            // if (MyRandom.Instance.NextFloat() > 0.05f) return;

            m_receiveStream.ResetRead(packet);
            m_lastStateSyncPacketId = m_receiveStream.ReadByte();

            while (m_receiveStream.BytePosition < m_receiveStream.ByteLength)
            {
                NetworkId    networkID = m_receiveStream.ReadNetworkId();
                IMyNetObject obj       = GetObjectByNetworkId(networkID);

                var pos = m_receiveStream.BytePosition;
                NetProfiler.Begin(obj.GetType().Name);
                Debug.Assert(obj != null && obj is IMyStateGroup, "IMyStateGroup not found by NetworkId");
                ((IMyStateGroup)obj).Serialize(m_receiveStream, null, m_lastStateSyncPacketId, 0);

                NetProfiler.End(m_receiveStream.ByteLength - pos);
            }

            if (!m_acks.Contains(m_lastStateSyncPacketId))
            {
                m_acks.Add(m_lastStateSyncPacketId);
            }
        }
        /// <summary>
        /// Processes state sync sent by server.
        /// </summary>
        public void ProcessStateSync(MyPacket packet)
        {
            LastMessageFromServer = DateTime.UtcNow;
            // Simulated packet loss
            // if (MyRandom.Instance.NextFloat() > 0.3f) return;

            m_receiveStream.ResetRead(packet);
            bool isStreaming = m_receiveStream.ReadBool();

            m_lastStateSyncPacketId = m_receiveStream.ReadByte();
            try
            {
                while (m_receiveStream.BytePosition < m_receiveStream.ByteLength)
                {
                    NetworkId     networkID = m_receiveStream.ReadNetworkId();
                    IMyStateGroup obj       = GetObjectByNetworkId(networkID) as IMyStateGroup;

                    if (obj == null)
                    {
                        if (isStreaming == false)
                        {
                            Debug.Fail("IMyStateGroup not found by NetworkId");
                            break;
                        }
                        else
                        {
                            return;
                        }
                    }

                    if (isStreaming && obj.GroupType != StateGroupEnum.Streamining)
                    {
                        Debug.Fail("group type mismatch !");
                        MyLog.Default.WriteLine("received streaming flag but group is not streaming !");
                        return;
                    }

                    if (!isStreaming && obj.GroupType == StateGroupEnum.Streamining)
                    {
                        Debug.Fail("group type mismatch !");
                        MyLog.Default.WriteLine("received non streaming flag but group wants to stream !");
                        return;
                    }

                    var pos = m_receiveStream.BytePosition;
                    NetProfiler.Begin(obj.GetType().Name);
                    obj.Serialize(m_receiveStream, ClientState.EndpointId, 0, m_lastStateSyncPacketId, 0);
                    NetProfiler.End(m_receiveStream.ByteLength - pos);


                    if (!m_acks.Contains(m_lastStateSyncPacketId))
                    {
                        m_acks.Add(m_lastStateSyncPacketId);
                    }
                }
            }
            catch (BitStreamException)
            {
            }
        }
        /// <summary>
        /// Reads all packets and create messages
        /// </summary>
        protected void BaseHeartbeat(double now)
        {
            // discovery
            NetProfiler.BeginSample("_CheckLocalDiscovery");
            m_discovery.Heartbeat(now);
            NetProfiler.EndSample();

            // Send queued system messages
            NetProfiler.BeginSample("_SendQueuedSystemMessages");
            SendQueuedSystemMessages();
            NetProfiler.EndSample();

            // Send out-of-band messages
            NetProfiler.BeginSample("_SendQueuedUnconnectedMessages");
            SendQueuedOutOfBandMessages();
            NetProfiler.EndSample();

//#if DEBUG
            NetProfiler.BeginSample("_SendLagSimulatedPackets");
            SendDelayedPackets(now);
            NetProfiler.EndSample();
//#endif

            // TODO: move this up in order
            NetProfiler.BeginSample("_ReceivePackets");
            ReceivePackets(now);
            NetProfiler.EndSample();
        }
Beispiel #5
0
        public virtual void Tick()
        {
            FrameCounter++;

            ProfilerShort.Begin("SendElapsedGameTime");
            if (IsServer && (MySession.Static.ElapsedGameTime - m_lastSentTimeTimestamp).Seconds > 30)
            {
                m_lastSentTimeTimestamp = MySession.Static.ElapsedGameTime;
                SendElapsedGameTime();
            }
            ProfilerShort.End();

            ProfilerShort.Begin("Client kick update");
            int currentTotalTime = MySandboxGame.TotalTimeInMilliseconds;

            if (currentTotalTime - m_lastKickUpdate > 20000)
            {
                m_tmpClientList.Clear();
                foreach (var client in m_kickedClients.Keys)
                {
                    m_tmpClientList.Add(client);
                }

                foreach (var client in m_tmpClientList)
                {
                    if (currentTotalTime - m_kickedClients[client] > KICK_TIMEOUT_MS)
                    {
                        m_kickedClients.Remove(client);
                    }
                }
                m_tmpClientList.Clear();

                m_lastKickUpdate = currentTotalTime;
            }
            ProfilerShort.End();

            ProfilerShort.Begin("ReplicationLayer.SendUpdate");
            ReplicationLayer.SendUpdate();
            ProfilerShort.End();

            // TODO: Remove
            //if (IsServer)
            //{
            //    SendServerPhysicsUpdate();
            //}

            SendWorlds();
            SendProfilers();

            ProfilerShort.Begin("TransportLayer.Tick");
            Sync.Layer.TransportLayer.Tick();
            ProfilerShort.End();

            ProfilerShort.Begin("Trace, NetProfiler.Commit");
            //VRage.Trace.MyTrace.Send(VRage.Trace.TraceWindow.Multiplayer, "============ Frame end ============");
            NetProfiler.Commit();
            ProfilerShort.End();
        }
Beispiel #6
0
        public virtual void Tick()
        {
            FrameCounter++;

            if (MyFakes.ENABLE_MULTIPLAYER_CONSTRAINT_COMPENSATION && IsServer && FrameCounter % 2 == 0)
            {
                MySyncGlobal.SendSimulationInfo();
            }

            if (IsServer && (MySession.Static.ElapsedGameTime - m_lastSentTimeTimestamp).Seconds > 30)
            {
                m_lastSentTimeTimestamp = MySession.Static.ElapsedGameTime;
                MySyncGlobal.SendElapsedGameTime();
            }

            int currentTotalTime = MySandboxGame.TotalTimeInMilliseconds;

            if (currentTotalTime - m_lastKickUpdate > 20000)
            {
                m_tmpClientList.Clear();
                foreach (var client in m_kickedClients.Keys)
                {
                    m_tmpClientList.Add(client);
                }

                foreach (var client in m_tmpClientList)
                {
                    if (currentTotalTime - m_kickedClients[client] > KICK_TIMEOUT_MS)
                    {
                        m_kickedClients.Remove(client);
                    }
                }
                m_tmpClientList.Clear();

                m_lastKickUpdate = currentTotalTime;
            }

            ReplicationLayer.Update();
            if (VRageRender.Profiler.MyRenderProfiler.ProfilerVisible)
            {
                ReplicationLayer.ReportReplicatedObjects();
            }

            // TODO: Remove
            //if (IsServer)
            //{
            //    SendServerPhysicsUpdate();
            //}

            Sync.Layer.TransportLayer.Tick();

            VRage.Trace.MyTrace.Send(VRage.Trace.TraceWindow.Multiplayer, "============ Frame end ============");
            NetProfiler.Commit();
        }
        public void ReportReplicatedObjects()
        {
            foreach (var obj in m_networkIDToObject)
            {
                NetProfiler.Begin(GetGroupName(obj.Value));

                NetProfiler.Begin(obj.Value.GetType().Name);
                NetProfiler.End(1, 0, "", "{0.}", "{0}x");

                NetProfiler.End(1, 0, "", "{0.}", "{0}x");
            }
        }
        internal void Heartbeat(double now)
        {
            if (m_status == NetConnectionStatus.Disconnected)
            {
                return;
            }

            //CongestionHeartbeat(now);

            if (m_status == NetConnectionStatus.Connecting)
            {
                NetProfiler.BeginSample("_CheckHandshake");
                CheckHandshake(now);
                NetProfiler.EndSample();
            }
            else if (m_status == NetConnectionStatus.Connected)
            {
                // send ping?
                NetProfiler.BeginSample("_CheckPing");
                CheckPing(now);
                NetProfiler.EndSample();
            }

            if (m_requestDisconnect)
            {
                NetProfiler.BeginSample("_InitiateDisconnect");
                InitiateDisconnect();
                NetProfiler.EndSample();
            }

            if (now > m_futureClose)
            {
                NetProfiler.BeginSample("_FinalizeDisconnect");
                FinalizeDisconnect();
                NetProfiler.EndSample();
            }

            // Resend all packets that has reached a mature age
            NetProfiler.BeginSample("_ResendMessages");
            ResendMessages(now);
            NetProfiler.EndSample();

            // send all unsent messages
            NetProfiler.BeginSample("_SendOutgoingMessages");
            SendUnsentMessages(now);
            NetProfiler.EndSample();
        }
Beispiel #9
0
        private void ProcessMessage(byte[] data, int dataSize, ulong sender, MyTimeSpan timestamp, MyTimeSpan receivedTime)
        {
            Debug.Assert(data.Length >= dataSize, "Wrong size");

            MyMessageId id = (MyMessageId)data[0];

            if (id == MyMessageId.CLIENT_CONNNECTED)
            {
                MyNetworkClient player;
                if (Sync.Layer != null && Sync.Layer.Clients != null)
                {
                    bool playerFound = Sync.Layer.Clients.TryGetClient(sender, out player);

                    if (!playerFound)
                    {
                        Sync.Layer.Clients.AddClient(sender);
                    }
                }
            }

            MyPacket p = new MyPacket
            {
                Data = data,
                // First byte is message id
                PayloadOffset = 1,
                PayloadLength = dataSize - 1,
                Sender        = new VRage.Network.EndpointId(sender),
                Timestamp     = timestamp,
                ReceivedTime  = receivedTime
            };

            Action <MyPacket> handler;

            if (m_handlers.TryGetValue(id, out handler))
            {
                ProfilerShort.Begin(MyEnum <MyMessageId> .GetName(id));
                NetProfiler.Begin(MyEnum <MyMessageId> .GetName(id));
                handler(p);
                NetProfiler.End(p.PayloadLength);
                ProfilerShort.End();
            }
            else
            {
                Debug.Fail("No handler for message type: " + id);
            }
        }
Beispiel #10
0
        private void HandleMessage(byte[] data, int dataSize, ulong sender, MyTimeSpan timestamp, MyTimeSpan receivedTime)
        {
            if (dataSize < sizeof(byte)) // This would cause crash, message has to contain at least MyMessageId
            {
                return;
            }

            ProfilerShort.Begin("Handle message");

            if (sender != Sync.MyId)
            {
                ByteCountReceived += dataSize;
            }

            MyMessageId id = (MyMessageId)data[0];

            LogStats(ReceiveStats, "", dataSize, 1, P2PMessageEnum.Reliable);


            m_thisFrameTraffic[(int)id] += dataSize;

            if (id == MyMessageId.OLD_GAME_EVENT_FLUSH) // Flush buffer
            {
                if (m_buffer != null)
                {
                    m_buffer.Clear();
                }
            }
            else if (IsBuffering && id != MyMessageId.JOIN_RESULT && id != MyMessageId.WORLD_DATA && id != MyMessageId.WORLD_BATTLE_DATA)  // Buffer event
            {
                var buff = new Buffer();
                buff.Sender = sender;
                buff.Data   = new byte[dataSize];
                Array.Copy(data, buff.Data, dataSize);
                buff.ReceivedTime = MyTimeSpan.FromTicks(Stopwatch.GetTimestamp());
                m_buffer.Add(buff);
            }
            else // Process event
            {
                NetProfiler.Begin("Live data", 0);
                ProcessMessage(data, dataSize, sender, timestamp, receivedTime);
                NetProfiler.End();
            }

            ProfilerShort.End();
        }
 void ProcessBuffer()
 {
     try
     {
         IsProcessingBuffer = true;
         NetProfiler.Begin("Processing buffered events");
         foreach (var b in m_buffer)
         {
             ProcessMessage(b.Data, b.Data.Length, b.Sender, TimeSpan.Zero);
         }
         NetProfiler.End();
     }
     finally
     {
         IsProcessingBuffer = false;
     }
 }
Beispiel #12
0
        void ReportObjects(string name, Type baseType)
        {
            int count = 0;

            NetProfiler.Begin(name);
            foreach (var pair in m_tmpReportedObjects)
            {
                Ref <int> num = pair.Value;
                if (num.Value > 0 && baseType.IsAssignableFrom(pair.Key))
                {
                    count += num.Value;
                    NetProfiler.Begin(pair.Key.Name);
                    NetProfiler.End(num.Value, 0, "", "{0:.} x", "");
                    num.Value = 0;
                }
            }
            NetProfiler.End(count, 0, "", "{0:.} x", "");
        }
        private void HandleMessage(byte[] data, int dataSize, ulong sender, TimeSpan timestamp)
        {
            if (dataSize < sizeof(byte)) // This would cause crash, message has to contain at least MyMessageId
            {
                return;
            }

            ProfilerShort.Begin("Handle message");

            if (sender != Sync.MyId)
            {
                ByteCountReceived += dataSize;
            }

            MyMessageId id = (MyMessageId)data[0];

            m_thisFrameTraffic[(int)id] += dataSize;

            if (id == MyMessageId.OLD_GAME_EVENT_FLUSH) // Flush buffer
            {
                if (m_buffer != null)
                {
                    m_buffer.Clear();
                }
            }
            else if (IsBuffering) // Buffer event
            {
                var buff = new Buffer();
                buff.Sender = sender;
                buff.Data   = new byte[dataSize];
                Array.Copy(data, buff.Data, dataSize);
                m_buffer.Add(buff);
            }
            else // Process event
            {
                NetProfiler.Begin("Live data", 0);
                ProcessMessage(data, dataSize, sender, timestamp);
                NetProfiler.End();
            }

            ProfilerShort.End();
        }
        public void HandleOldGameEvent(MyPacket packet)
        {
            m_receiveStream.Reset(packet.Data, packet.PayloadOffset + packet.PayloadLength);
            m_receiveStream.Position = packet.PayloadOffset;

            ushort msgId = m_receiveStream.ReadUShort();

            CallbackInfo info;

            if (m_callbacks.TryGetValue(msgId, out info))
            {
                var handler = info.Callback;

                ProfilerShort.Begin(GetGroupName(handler.MessageType));
                ProfilerShort.Begin(handler.MessageType);
                NetProfiler.Begin(handler.MessageType);

                if (packet.Sender.Value != Sync.MyId)
                {
                    if (!MySandboxGame.IsDedicated)
                    {
                        LogStats(ReceiveStats, handler.MessageType, packet.PayloadOffset + packet.PayloadLength, 1, info.SendType);
                    }

                    // TODO: Log stats here
                    //info.Callback.MessageType;
                    //info.SendType;
                    //info.MessageId;
                }

                handler.Receive(m_receiveStream, packet.Sender.Value, packet.Timestamp);

                NetProfiler.End((int)m_receiveStream.Length);
                ProfilerShort.End();
                ProfilerShort.End();
            }
            else
            {
                Debug.Fail(String.Format("No handler defined for message {0}, of type {1}", msgId, FindDebugName(msgId)));
            }
        }
        public unsafe void Tick()
        {
            foreach (var steamId in m_pendingFlushes)
            {
                byte data = 0;
                if (!Peer2Peer.SendPacket(steamId, &data, 0, P2PMessageEnum.Reliable, m_channel))
                {
                    System.Diagnostics.Debug.Fail("P2P packet send fail (flush)");
                }
            }
            m_pendingFlushes.Clear();

            int totalSum = 0;

            NetProfiler.Begin("Avg per frame (60 frames window)");
            for (int i = 0; i < MessageTypeCount; i++)
            {
                var window = m_slidingWindows[i];
                window.Enqueue(m_thisFrameTraffic[i]);
                m_thisFrameTraffic[i] = 0;

                while (window.Count > 60)
                {
                    window.Dequeue();
                }

                int sum = 0;
                foreach (var item in window)
                {
                    sum += item;
                }
                if (sum > 0)
                {
                    NetProfiler.Begin(MyEnum <MyMessageId> .GetName((MyMessageId)i));
                    NetProfiler.End(sum / 60.0f, sum / 1024.0f, "{0} KB/s");
                }
                totalSum += sum;
            }
            NetProfiler.End(totalSum / 60.0f, totalSum / 1024.0f, "{0} KB/s");
        }
        /// <summary>
        /// Reads and sends messages from the network
        /// </summary>
        public override void Heartbeat()
        {
            if (!m_isBound)
            {
                return;
            }

            NetProfiler.BeginSample("_GetTime");
            double now = NetTime.Now;

            NetProfiler.EndSample();

            NetProfiler.BeginSample("_UpdateCounter");
            m_heartbeatCounter.Count(now);
            NetProfiler.EndSample();

            // read messages from network
            BaseHeartbeat(now);

            NetProfiler.BeginSample("_UpdateConnections");
            UpdateConnections(now);
            NetProfiler.EndSample();
        }
Beispiel #17
0
        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);
            }
        }
Beispiel #18
0
        //List<byte> m_alreadyReceivedPackets = new List<byte>();


        /// <summary>
        /// Processes state sync sent by server.
        /// </summary>
        public void ProcessStateSync(MyPacket packet)
        {
            LastMessageFromServer = DateTime.UtcNow;
            // Simulated packet loss
            // if (MyRandom.Instance.NextFloat() > 0.3f) return;

            ReceiveStream.ResetRead(packet);
            bool isStreaming = ReceiveStream.ReadBool();

            var packetId = ReceiveStream.ReadByte();

            //if (m_alreadyReceivedPackets.Contains(packetId))
            //{
            //}
            //if (m_alreadyReceivedPackets.Count > 128)
            //    m_alreadyReceivedPackets.RemoveAt(0);
            //m_alreadyReceivedPackets.Add(packetId);

            var serverOrder = m_serverTracker.Add(packetId);

            m_serverStats.Update(serverOrder);
            if (serverOrder == MyPacketTracker.OrderType.Duplicate)
            {
                return;
            }
            m_lastStateSyncPacketId = packetId;

            MyPacketStatistics stats = new MyPacketStatistics();

            stats.Read(ReceiveStream);
            m_clientStatsFromServer.Add(stats);

            var serverTimeStamp = MyTimeSpan.FromMilliseconds(ReceiveStream.ReadDouble());

            if (m_lastServerTimeStamp < serverTimeStamp)
            {
                m_lastServerTimeStamp = serverTimeStamp;
            }

            double lastClientRealtime = ReceiveStream.ReadDouble();

            if (lastClientRealtime > 0)
            {
                var ping = packet.ReceivedTime - MyTimeSpan.FromMilliseconds(lastClientRealtime);
                if (ping.Milliseconds < 1000)
                {
                    SetPing(ping);
                }
            }

            MyTimeSpan relevantTimeStamp = serverTimeStamp;

            m_callback.ReadCustomState(ReceiveStream);

            while (ReceiveStream.BytePosition < ReceiveStream.ByteLength)
            {
                NetworkId     networkID = ReceiveStream.ReadNetworkId();
                IMyStateGroup obj       = GetObjectByNetworkId(networkID) as IMyStateGroup;

                if (obj == null)
                {
                    if (isStreaming == false)
                    {
                        Debug.Fail("IMyStateGroup not found by NetworkId");
                        break;
                    }
                    else
                    {
                        return;
                    }
                }

                if (isStreaming && obj.GroupType != StateGroupEnum.Streaming)
                {
                    Debug.Fail("group type mismatch !");
                    MyLog.Default.WriteLine("received streaming flag but group is not streaming !");
                    return;
                }

                if (!isStreaming && obj.GroupType == StateGroupEnum.Streaming)
                {
                    Debug.Fail("group type mismatch !");
                    MyLog.Default.WriteLine("received non streaming flag but group wants to stream !");
                    return;
                }

                if (VRage.MyCompilationSymbols.EnableNetworkPacketTracking)
                {
                    Trace.MyTrace.Send(Trace.TraceWindow.MPackets, " ObjSync: " + obj.GetType().Name);
                }

                var pos = ReceiveStream.BytePosition;
                NetProfiler.Begin(obj.GetType().Name);
                obj.Serialize(ReceiveStream, ClientState.EndpointId, relevantTimeStamp, m_lastStateSyncPacketId, 0);
                NetProfiler.End(ReceiveStream.ByteLength - pos);

                if (!m_acks.Contains(m_lastStateSyncPacketId))
                {
                    m_acks.Add(m_lastStateSyncPacketId);
                }
            }
        }