private void HandleDisconnectPacket(ref InputMemoryBitStream input, EndPoint _inEndpoint)
    {
        if (mEndpointToPlayerIdDic.ContainsKey(_inEndpoint))
        {
            int playerid = mEndpointToPlayerIdDic[_inEndpoint];
            mEndpointToPlayerIdDic.Remove(_inEndpoint);
            mPlayerIdToEndpointDic.Remove(playerid);
            mPlayerIdToName.Remove(playerid);
            mPlayerCount--;
            int mTurnDisconnect = -1;
            input.Read(ref mTurnDisconnect);
            int id = -1;
            input.Read(ref id);

            if (id != -1)
            {
                for (int i = mTurnNumber + 1; i <= mTurnDisconnect; i++)
                {
                    if (mTurnData.ContainsKey(i))
                    {
                        if (mTurnData[i].ContainsKey(id))
                        {
                            mTurnData[i].Remove(id);
                        }
                    }
                }
            }
        }
    }
 public void Read(ref InputMemoryBitStream input)
 {
     input.Read(ref mPlayerId);
     input.Read(ref mRandomValue);
     input.Read(ref mCrc);
     mCommandList = new CommandList();
     mCommandList.Read(ref input);
 }
    }                                                // được thực hiện khi 1 lệnh được thực thi.

    public static Command StaticReadAndCreate(ref InputMemoryBitStream input)
    {
        Command returnval = new Command();
        int     type      = 0;

        input.Read(ref type);
        int networkid = 0;

        input.Read(ref networkid);
        int playerid = 0;

        input.Read(ref playerid);
        CommandType mtype = (CommandType)type;

        switch (mtype)
        {
        case CommandType.CM_ATTACK:
        {
            returnval = new AttackCommand();
            returnval.SetNetworkID(networkid);
            returnval.SetPlayerID(playerid);
            returnval.Read(ref input);
            break;
        }

        case CommandType.CM_MOVE:
        {
            returnval = new MoveCommand();
            returnval.SetNetworkID(networkid);
            returnval.SetPlayerID(playerid);
            returnval.Read(ref input);
            break;
        }

        case CommandType.CM_SPAWN:
        {
            returnval = new SpawnCommand();
            returnval.SetNetworkID(networkid);
            returnval.SetPlayerID(playerid);
            returnval.Read(ref input);
            break;
        }

        case CommandType.CM_ROTATE:
        {
            break;
        }

        default: break;
        }

        return(returnval);
    }
    private void HandleHelloPacket(ref InputMemoryBitStream input, EndPoint _inEndpoint)
    {
        if (mEndpointToPlayerIdDic.ContainsKey(_inEndpoint))
        {
            return;
        }

        if (mPlayerCount >= 4)
        {
            OutputMemoryBitStream output = new OutputMemoryBitStream();
            output.Write(kNotJoinableCC);
            SendPacket(output, _inEndpoint);
            return;
        }

        if (mIsMasterPeer)
        {
            string name = " ";
            input.Read(ref name);
            // Nếu máy nhận được là 1 master peer=> cấp phát player id cho máy gửi để nó có thêm tham gia trò chơi
            OutputMemoryBitStream output = new OutputMemoryBitStream();
            output.Write(kWelcomeCC);
            mHighestPlayerId++;
            output.Write(mHighestPlayerId);

            // ghi thông tin của master peer(người chơi chính = chủ phòng chơi) và các player khác đã tham gia
            output.Write(mPlayerId);

            output.Write(mPlayerCount);
            // ghi player id + endpoint (ip address) của tất cả người chơi đã tham gia cho người chơi mới
            foreach (var pair in mPlayerIdToEndpointDic)
            {
                output.Write(pair.Key);
                WriteIPv4(ref output, pair.Value);
            }
            // gừi tên của tất cá người chơi cho người chơi mới
            foreach (var pair in mPlayerIdToName)
            {
                output.Write(pair.Key);
                output.Write(pair.Value);
            }

            SendPacket(output, _inEndpoint);

            // lưu thông tin người chơi mới.
            mPlayerCount++;
            mPlayerIdToName.Add(mHighestPlayerId, name);
            mPlayerIdToEndpointDic.Add(mHighestPlayerId, _inEndpoint);
            mEndpointToPlayerIdDic.Add(_inEndpoint, mHighestPlayerId);
        }
        else
        {
            // nếu người nhận được không phải là master peer
            // tiến hành gửi lại địa chỉ của master peer thực sự cho người gửi
            OutputMemoryBitStream output = new OutputMemoryBitStream();
            output.Write(kNotMasterPeer);
            WriteIPv4(ref output);
            SendPacket(output, _inEndpoint);
        }
    }
    /// <summary>
    /// xử lý gói tin nhận được nếu người chơi đang trong phòng đợi
    /// </summary>
    /// <param name="input"></param>
    /// <param name="_inEndPoint"></param>
    private void ProcessPacketLobby(ref InputMemoryBitStream input, EndPoint _inEndPoint)
    {
        int packetType = 0;

        input.Read(ref packetType);
        switch (packetType)
        {
        case kHellocCC:
        {
            HandleHelloPacket(ref input, _inEndPoint);
            break;
        }

        case kIntroCC:
        {
            HandleIntroPacket(ref input, _inEndPoint);
            break;
        }

        case kStartCC:
        {
            HandleStartPacket(ref input, _inEndPoint);
            break;
        }

        case kOutCC:
        {
            HandleDisconnectPacket(ref input, _inEndPoint);
            break;
        }

        default: break;
        }
    }
    private void ProcessPacketHello(ref InputMemoryBitStream input, EndPoint _inEndPoint)
    {
        int type = 0;

        input.Read(ref type);
        switch (type)
        {
        case kNotMasterPeer:
        {
            HandleNotMasterPeer(ref input);
            break;
        }

        case kWelcomeCC:
        {
            mMasterPeerEndP = _inEndPoint;
            HandleWelcomePacket(ref input);
            break;
        }

        case kNotJoinableCC:            // trường hợp này xảy ra khi game đã bắt đầu hoặc phòng đã đầy, nên người chơi không thể join.
        {
            break;
        }

        default: break;
        }
    }
    private void HandleIntroPacket(ref InputMemoryBitStream input, EndPoint _inEndpoint)
    {
        if (!mIsMasterPeer)
        {
            int    playerid = 0;
            string name     = " ";

            input.Read(ref playerid);
            input.Read(ref name);

            mPlayerCount++;
            UpdateHighestPlayerId(mPlayerId);
            mPlayerIdToName.Add(playerid, name);
            mEndpointToPlayerIdDic.Add(_inEndpoint, playerid);
            mPlayerIdToEndpointDic.Add(playerid, _inEndpoint);
        }
    }
    /// <summary>
    /// đọc địa chỉ ip
    /// </summary>
    /// <param name="input"></param>
    /// <param name="_inEndpoint"></param>
    private void ReadIPv4(ref InputMemoryBitStream input, ref EndPoint _inEndpoint)
    {
        string ip   = "";
        int    port = 0;

        input.Read(ref ip);
        input.Read(ref port);
        try
        {
            _inEndpoint = (EndPoint)(new IPEndPoint(IPAddress.Parse(ip), port));
        }
        catch
        {
            Debug.Log("error");
            return;
        }
    }
    private void HandleTurnPacket(ref InputMemoryBitStream input, EndPoint _inEndpoint)
    {
        if (mEndpointToPlayerIdDic.ContainsKey(_inEndpoint))
        {
            int id       = mEndpointToPlayerIdDic[_inEndpoint];
            int playerid = -1;
            int turnNum  = -1;
            input.Read(ref turnNum);
            input.Read(ref playerid);

            if (id != playerid)
            {
                return;
            }
            TurnData data = new TurnData();
            data.Read(ref input);
            //Debug.Log(turnNum + " " + playerid + " " + data.GetCommandList().GetCount());
            if (mTurnData.ContainsKey(turnNum))
            {
                try
                {
                    mTurnData[turnNum].Add(playerid, data);
                }
                catch (ArgumentException ex)
                {
                    mTurnData[turnNum][playerid] = data;
                }
            }
            else
            {
                mTurnData.Add(turnNum, new Dictionary <int, TurnData>());
                mTurnData[turnNum].Add(playerid, data);
            }
            //try
            //{
            //    mTurnData[turnNum].Add(playerid, data);
            //}
            //catch (ArgumentException)
            //{
            //    mTurnData[turnNum][playerid] = data;
            //}
        }
    }
    public void Read(ref InputMemoryBitStream input)
    {
        int cout = 0;

        input.Read(ref cout);
        for (int i = 0; i < cout; i++)
        {
            mCommands.Enqueue(Command.StaticReadAndCreate(ref input));
        }
    }
    private void ProcessPacketDelay(ref InputMemoryBitStream input, EndPoint _inEndPoint)
    {
        // nếu người chơi trong trang thái delay,
        // tiếp tục nhập các turn packet đến, và kiểm đã nhận đủ các packet tất cả người chơi trong turn hiện tại hay chưa
        // nếu rồi thì chuyển sang turn mới
        int packetType = -1;

        input.Read(ref packetType);
        if (packetType == kTurnCC)
        {
            HandleTurnPacket(ref input, _inEndPoint);
            TryAdvanceTurn();
        }
    }
    private void HandleStartPacket(ref InputMemoryBitStream input, EndPoint _inEndpoint)
    {
        if (mMasterPeerEndP.Equals(_inEndpoint))
        {
            int seed = 0;
            input.Read(ref seed);
            CustomRandom.mInstance.Seed(seed);

            mState = NetworkState.Starting;
            // Ở đây chính xác là phải trừ đi 1/2 RTT (round time trip), tức là bỏ qua khoảng thời gian gửi
            // nhưng mình lại trừ tạm đi 1 khoảng là delta time.
            mTimeToStart = mMaxTimeToStart - _deltatime;
        }
    }
    private void ProcessPacketPlaying(ref InputMemoryBitStream input, EndPoint _inEndPoint)
    {
        int packetType = 0;

        input.Read(ref packetType);
        switch (packetType)
        {
        case kTurnCC:
        {
            HandleTurnPacket(ref input, _inEndPoint);
            break;
        }

        case kOutCC:
        {
            HandleDisconnectPacket(ref input, _inEndPoint);
            break;
        }

        default: break;
        }
    }
 public override void Read(ref InputMemoryBitStream input)
 {
     input.Read(ref mTargetNetworkID);
 }
    /// <summary>
    /// Trường hợp xảy ra khi được chấp nhận kết nối từ master peer
    /// </summary>
    /// <param name="input"></param>
    private void HandleWelcomePacket(ref InputMemoryBitStream input)
    {
        // đọc player id được cấp phát
        int playerid = 0, masterPeerPlayerid = 0;

        input.Read(ref playerid);
        UpdateHighestPlayerId(playerid);
        mPlayerId = playerid;

        mPlayerIdToName.Add(mPlayerId, mName);

        // bây giờ đọc player id của master peer.
        input.Read(ref masterPeerPlayerid);
        UpdateHighestPlayerId(masterPeerPlayerid);
        mPlayerIdToEndpointDic.Add(masterPeerPlayerid, mMasterPeerEndP);
        mEndpointToPlayerIdDic.Add(mMasterPeerEndP, masterPeerPlayerid);

        // tiếp theo đọc thông tin của tất cả người chơi còn lại.
        int playerCount = 0;

        input.Read(ref playerCount);
        mPlayerCount = playerCount;
        EndPoint Endp = null;

        for (int i = 0; i < playerCount - 1; i++)
        {
            input.Read(ref playerid);
            UpdateHighestPlayerId(playerid);

            ReadIPv4(ref input, ref Endp);
            mPlayerIdToEndpointDic.Add(playerid, Endp);
            mEndpointToPlayerIdDic.Add(Endp, playerid);
        }

        // Đọc tên của tất cả người chơi đã tham gia trò chơi
        string name = " ";

        for (int i = 0; i < playerCount; i++)
        {
            input.Read(ref playerid);
            input.Read(ref name);
            mPlayerIdToName.Add(playerid, name);
        }

        mPlayerCount++;

        // Gửi 1 gói thông báo cho các player khác là tôi đã tham gia trò chơi
        OutputMemoryBitStream output = new OutputMemoryBitStream();

        output.Write(kIntroCC);
        output.Write(mPlayerId);
        output.Write(mName);

        foreach (var pair in mPlayerIdToEndpointDic)
        {
            SendPacket(output, pair.Value);
        }

        mPeerToPeerManager.SetInLobby(true);
        // đã vào phòng đợi để sẵn sàng tham gia trò chơi
        mState = NetworkState.Lobby;
    }