private void Update()
    {
        while (_eventsToHandle.TryDequeue(out var @event))
        {
            switch (@event.Type)
            {
            case EventType.Connect:
                OnConnected(@event.Peer);
                break;

            case EventType.Disconnect:
            case EventType.Timeout:
                OnDisconnected(@event.Peer);
                break;

            case EventType.Receive:
                unsafe
                {
                    _receivedUnreliable++;
                    var packet = @event.Packet;
                    var span   = new ReadOnlySpan <byte>(packet.Data.ToPointer(), packet.Length);
                    _buffer.FromSpan(ref span, packet.Length);
                    _detector.ReadHeaderOfPeerId((ushort)@event.Peer.ID, _buffer);
                    _buffer.Clear();
                    packet.Dispose();
                    break;
                }
            }
        }

        _detector.ExecuteLostPackets();
    }
        private unsafe void ExecuteState(IntPtr state)
        {
            PackedDataFlags flags;
            int             cursor;

            if (_firstPacket)
            {
                _firstPacket = false;
                flags        = PackedDataFlags.Commands | PackedDataFlags.CreatedEntities;
                cursor       = 0;
            }
            else
            {
                flags  = (PackedDataFlags)Marshal.ReadByte(state);
                cursor = 1;
            }

            #region commands

            if ((flags & PackedDataFlags.Commands) == PackedDataFlags.Commands)
            {
                var commandsHeaderSpan = new ReadOnlySpan <ushort>(IntPtr.Add(state, cursor).ToPointer(), 2);
                var commandCount       = commandsHeaderSpan[0];
                var commandLength      = commandsHeaderSpan[1];
                cursor += 4;

                if (commandCount > 0)
                {
                    var dataSpan = new ReadOnlySpan <byte>(IntPtr.Add(state, cursor).ToPointer(),
                                                           commandLength);
                    _fromServer.Clear();
                    _fromServer.FromSpan(ref dataSpan, commandLength);
                    ClientCommandExecutor.Execute(_handler, _fromServer, commandCount);
                    cursor += commandLength;
                }
            }
            #endregion

            #region created entities

            if ((flags & PackedDataFlags.CreatedEntities) == PackedDataFlags.CreatedEntities)
            {
                var createdEntitiesHeaderSpan =
                    new ReadOnlySpan <ushort>(IntPtr.Add(state, cursor).ToPointer(), 2);
                var createdEntitiesCount  = createdEntitiesHeaderSpan[0];
                var createdEntitiesLength = createdEntitiesHeaderSpan[1];
                cursor += 4;

                if (createdEntitiesCount > 0)
                {
                    var dataSpan = new ReadOnlySpan <byte>(IntPtr.Add(state, cursor).ToPointer(),
                                                           createdEntitiesLength);
                    _fromServer.Clear();
                    _fromServer.FromSpan(ref dataSpan, createdEntitiesLength);
                    UnpackEntityUtility.CreateEntities(_game, _fromServer, createdEntitiesCount);
                    cursor += createdEntitiesLength;
                }
            }

            #endregion

            #region removed entities

            if ((flags & PackedDataFlags.RemovedEntities) == PackedDataFlags.RemovedEntities)
            {
                var removedEntitiesHeaderSpan =
                    new ReadOnlySpan <ushort>(IntPtr.Add(state, cursor).ToPointer(), 2);
                var removedEntitiesCount  = removedEntitiesHeaderSpan[0];
                var removedEntitiesLength = removedEntitiesHeaderSpan[1];

                cursor += 4;

                if (removedEntitiesCount > 0)
                {
                    var dataSpan = new ReadOnlySpan <byte>(IntPtr.Add(state, cursor).ToPointer(),
                                                           removedEntitiesLength);
                    _fromServer.Clear();
                    _fromServer.FromSpan(ref dataSpan, removedEntitiesLength);
                    UnpackEntityUtility.RemoveEntities(_game, _fromServer, removedEntitiesCount);
                    cursor += removedEntitiesLength;
                }
            }

            #endregion

            #region removed components

            if ((flags & PackedDataFlags.RemovedComponents) == PackedDataFlags.RemovedComponents)
            {
                var removedComponentsHeaderSpan =
                    new ReadOnlySpan <ushort>(IntPtr.Add(state, cursor).ToPointer(), 2);
                var removedComponentsCount  = removedComponentsHeaderSpan[0];
                var removedComponentsLength = removedComponentsHeaderSpan[1];
                cursor += 4;

                if (removedComponentsCount > 0)
                {
                    var dataSpan = new ReadOnlySpan <byte>(IntPtr.Add(state, cursor).ToPointer(),
                                                           removedComponentsLength);
                    _fromServer.Clear();
                    _fromServer.FromSpan(ref dataSpan, removedComponentsLength);
                    UnpackEntityUtility.RemoveComponents(_game, _fromServer, removedComponentsCount);
                    cursor += removedComponentsLength;
                }
            }

            #endregion

            #region changed components

            if ((flags & PackedDataFlags.ChangedComponents) == PackedDataFlags.ChangedComponents)
            {
                var changedComponentsHeaderSpan =
                    new ReadOnlySpan <ushort>(IntPtr.Add(state, cursor).ToPointer(), 2);
                var changedComponentsCount  = changedComponentsHeaderSpan[0];
                var changedComponentsLength = changedComponentsHeaderSpan[1];
                cursor += 4;

                if (changedComponentsCount > 0)
                {
                    var dataSpan = new ReadOnlySpan <byte>(IntPtr.Add(state, cursor).ToPointer(),
                                                           changedComponentsLength);
                    _fromServer.Clear();
                    _fromServer.FromSpan(ref dataSpan, changedComponentsLength);
                    UnpackEntityUtility.ChangeComponents(_game, _fromServer, changedComponentsCount);
                }
            }

            #endregion

            Marshal.FreeHGlobal(state);
        }
        public void Execute()
        {
            while (_responses.TryDequeue(out var response))
            {
                switch (response)
                {
                case NetworkThreadResponse.StartSuccess:
                    Logger.I.Log(this, "Server is working");
                    State = ServerState.Working;
                    break;

                case NetworkThreadResponse.StartFailure:
                    Logger.I.Log(this, "Server start failed");
                    State = ServerState.Stopped;
                    break;

                case NetworkThreadResponse.Stoppoed:
                    Logger.I.Log(this, "Server is stopped");
                    ClearBuffers();
                    while (_eventsToHandle.TryDequeue(out _))
                    {
                    }

                    State = ServerState.Stopped;
                    break;
                }
            }

            if (State != ServerState.Working)
            {
                return;
            }
            while (_eventsToHandle.TryDequeue(out var @event))
            {
                unsafe
                {
                    switch (@event.EventType)
                    {
                    case EventType.Connect:
                        _handler.OnClientConnected(@event.Peer);
                        break;

                    case EventType.Disconnect:
                        _handler.OnClientDisconnected(@event.Peer);
                        break;

                    case EventType.Receive:
                        _currentPeerId           = (ushort)@event.Peer.ID;
                        _handler.CurrentClientId = _currentPeerId;

                        var e = _game.GetEntityWithConnection(_currentPeerId);
                        if (e == null)
                        {
                            Marshal.FreeHGlobal(@event.Data);
                            break;
                        }

                        var headerSpan    = new ReadOnlySpan <ushort>(@event.Data.ToPointer(), 2);
                        var commandCount  = headerSpan[0];
                        var commandLength = headerSpan[1];

                        if (commandCount > 0)
                        {
                            var commandsSpan =
                                new ReadOnlySpan <byte>(IntPtr.Add(@event.Data, 4).ToPointer(), commandLength);
                            _fromClients.Clear();
                            _fromClients.FromSpan(ref commandsSpan, commandLength);
                            ServerCommandExecutor.Execute(_handler, _fromClients, commandCount);
                        }

                        Marshal.FreeHGlobal(@event.Data);
                        _currentPeerId = ushort.MaxValue;
                        break;

                    case EventType.Timeout:
                        _handler.OnClientDisconnected(@event.Peer);
                        break;
                    }
                }
            }
        }