/// <summary>
        /// Receive and process a single incoming packet.
        /// Returns 'true' if a packet was received, 'false' otherwise.
        /// </summary>

        bool ProcessPlayerPacket(Buffer buffer, TcpPlayer player, bool reliable)
        {
            BinaryReader reader  = buffer.BeginReading();
            Packet       request = (Packet)reader.ReadByte();

//#if UNITY_EDITOR // DEBUG
//		if (request != Packet.RequestPing) UnityEngine.Debug.Log("Server: " + request + " " + buffer.position + " " + buffer.size);
//#else
//		if (request != Packet.RequestPing) Console.WriteLine("Server: " + request + " " + buffer.position + " " + buffer.size);
//#endif

            // If the player has not yet been verified, the first packet must be an ID request
            if (player.stage == TcpProtocol.Stage.Verifying)
            {
                if (player.VerifyRequestID(request, reader, true))
                {
                    mDictionaryID.Add(player.id, player);
                    if (lobbyLink != null)
                    {
                        lobbyLink.SendUpdate(this);
                    }
                    if (onPlayerConnect != null)
                    {
                        onPlayerConnect(player);
                    }
                    return(true);
                }
#if STANDALONE
                Console.WriteLine(player.address + " has failed the verification step");
#endif
                RemovePlayer(player);
                return(false);
            }

            switch (request)
            {
            case Packet.Empty:
            {
                break;
            }

            case Packet.Error:
            {
                Error(player, reader.ReadString());
                break;
            }

            case Packet.Disconnect:
            {
                RemovePlayer(player);
                break;
            }

            case Packet.RequestPing:
            {
                // Respond with a ping back
                BeginSend(Packet.ResponsePing);
                EndSend(true, player);
                break;
            }

            case Packet.RequestSetUDP:
            {
                int port = reader.ReadUInt16();

                if (port != 0)
                {
                    IPAddress ip = new IPAddress(player.tcpEndPoint.Address.GetAddressBytes());
                    SetPlayerUdpEndPoint(player, new IPEndPoint(ip, port));
                }
                else
                {
                    SetPlayerUdpEndPoint(player, null);
                }

                // Let the player know if we are hosting an active UDP connection
                ushort udp = mUdp.isActive ? (ushort)mUdp.listeningPort : (ushort)0;
                BeginSend(Packet.ResponseSetUDP).Write(udp);
                EndSend(true, player);

                // Send an empty packet to the target player to open up UDP for communication
                if (player.udpEndPoint != null)
                {
                    mUdp.SendEmptyPacket(player.udpEndPoint);
                }
                break;
            }

            case Packet.RequestJoinChannel:
            {
                // Join the specified channel
                int    channelID   = reader.ReadInt32();
                string pass        = reader.ReadString();
                string levelName   = reader.ReadString();
                bool   persist     = reader.ReadBoolean();
                ushort playerLimit = reader.ReadUInt16();

                // Join a random existing channel or create a new one
                if (channelID == -2)
                {
                    bool randomLevel = string.IsNullOrEmpty(levelName);
                    channelID = -1;

                    for (int i = 0; i < mChannels.size; ++i)
                    {
                        Channel ch = mChannels[i];

                        if (ch.isOpen && (randomLevel || levelName.Equals(ch.level)) &&
                            (string.IsNullOrEmpty(ch.password) || (ch.password == pass)))
                        {
                            channelID = ch.id;
                            break;
                        }
                    }

                    // If no level name has been specified and no channels were found, we're done
                    if (randomLevel && channelID == -1)
                    {
                        BinaryWriter writer = BeginSend(Packet.ResponseJoinChannel);
                        writer.Write(false);
                        writer.Write("No suitable channels found");
                        EndSend(true, player);
                        break;
                    }
                }

                // Join a random new channel
                if (channelID == -1)
                {
                    channelID = mRandom.Next(100000000);

                    for (int i = 0; i < 1000; ++i)
                    {
                        if (!ChannelExists(channelID))
                        {
                            break;
                        }
                        channelID = mRandom.Next(100000000);
                    }
                }

                if (player.channel == null || player.channel.id != channelID)
                {
                    bool    isNew;
                    Channel channel = CreateChannel(channelID, out isNew);

                    if (channel == null || !channel.isOpen)
                    {
                        BinaryWriter writer = BeginSend(Packet.ResponseJoinChannel);
                        writer.Write(false);
                        writer.Write("The requested channel is closed");
                        EndSend(true, player);
                    }
                    else if (isNew)
                    {
                        channel.password    = pass;
                        channel.persistent  = persist;
                        channel.level       = levelName;
                        channel.playerLimit = playerLimit;

                        SendLeaveChannel(player, false);
                        SendJoinChannel(player, channel);
                    }
                    else if (string.IsNullOrEmpty(channel.password) || (channel.password == pass))
                    {
                        SendLeaveChannel(player, false);
                        SendJoinChannel(player, channel);
                    }
                    else
                    {
                        BinaryWriter writer = BeginSend(Packet.ResponseJoinChannel);
                        writer.Write(false);
                        writer.Write("Wrong password");
                        EndSend(true, player);
                    }
                }
                break;
            }

            case Packet.RequestSetName:
            {
                // Change the player's name
                player.name = reader.ReadString();

                BinaryWriter writer = BeginSend(Packet.ResponseRenamePlayer);
                writer.Write(player.id);
                writer.Write(player.name);

                if (player.channel != null)
                {
                    EndSend(true, player.channel, null);
                }
                else
                {
                    EndSend(true, player);
                }
                break;
            }

            case Packet.RequestSaveFile:
            {
                string fileName = reader.ReadString();
                byte[] data     = reader.ReadBytes(reader.ReadInt32());
                SaveFile(fileName, data);
                break;
            }

            case Packet.RequestLoadFile:
            {
                string fn   = reader.ReadString();
                byte[] data = LoadFile(fn);

                BinaryWriter writer = BeginSend(Packet.ResponseLoadFile);
                writer.Write(fn);

                if (data != null)
                {
                    writer.Write(data.Length);
                    writer.Write(data);
                }
                else
                {
                    writer.Write(0);
                }
                EndSend(true, player);
                break;
            }

            case Packet.RequestDeleteFile:
            {
                DeleteFile(reader.ReadString());
                break;
            }

            case Packet.RequestNoDelay:
            {
                player.noDelay = reader.ReadBoolean();
                break;
            }

            case Packet.RequestChannelList:
            {
                BinaryWriter writer = BeginSend(Packet.ResponseChannelList);

                int count = 0;
                for (int i = 0; i < mChannels.size; ++i)
                {
                    if (!mChannels[i].closed)
                    {
                        ++count;
                    }
                }

                writer.Write(count);

                for (int i = 0; i < mChannels.size; ++i)
                {
                    Channel ch = mChannels[i];

                    if (!ch.closed)
                    {
                        writer.Write(ch.id);
                        writer.Write((ushort)ch.players.size);
                        writer.Write(ch.playerLimit);
                        writer.Write(!string.IsNullOrEmpty(ch.password));
                        writer.Write(ch.persistent);
                        writer.Write(ch.level);
                        writer.Write(ch.data);
                    }
                }
                EndSend(true, player);
                break;
            }

            case Packet.ForwardToPlayer:
            {
                // Forward this packet to the specified player
                TcpPlayer target = GetPlayer(reader.ReadInt32());

                if (target != null && target.isConnected)
                {
                    // Reset the position back to the beginning (4 bytes for size, 1 byte for ID, 4 bytes for player)
                    buffer.position = buffer.position - 9;
                    target.SendTcpPacket(buffer);
                }
                break;
            }

            default:
            {
                if (player.channel != null && (int)request <= (int)Packet.ForwardToPlayerBuffered)
                {
                    // Other packets can only be processed while in a channel
                    if ((int)request >= (int)Packet.ForwardToAll)
                    {
                        ProcessForwardPacket(player, buffer, reader, request, reliable);
                    }
                    else
                    {
                        ProcessChannelPacket(player, buffer, reader, request);
                    }
                }
                else if (onCustomPacket != null)
                {
                    onCustomPacket(player, buffer, reader, request, reliable);
                }
                break;
            }
            }
            return(true);
        }
示例#2
0
        /// <summary>
        /// Process a single incoming packet. Returns whether we should keep processing packets or not.
        /// </summary>

        bool ProcessPacket(Buffer buffer, IPEndPoint ip)
        {
            mPacketSource = ip;
            BinaryReader reader = buffer.BeginReading();

            if (buffer.size == 0)
            {
                return(true);
            }

            int    packetID = reader.ReadByte();
            Packet response = (Packet)packetID;

            // Verification step must be passed first
            if (mTcp.stage == TcpProtocol.Stage.Verifying)
            {
                if (mTcp.VerifyResponseID(response, reader))
                {
#if !UNITY_WEBPLAYER
                    if (mUdp.isActive)
                    {
                        // If we have a UDP listener active, tell the server
                        BeginSend(Packet.RequestSetUDP).Write(mUdp.isActive ? (ushort)mUdp.listeningPort : (ushort)0);
                        EndSend();
                    }
#endif
                    mCanPing = true;
                    if (onConnect != null)
                    {
                        onConnect(true, null);
                    }
                }
                else if (onConnect != null)
                {
                    onConnect(false, "Protocol version mismatch!");
                }
                return(true);
            }

//#if !UNITY_EDITOR // DEBUG
//        if (response != Packet.ResponsePing) Console.WriteLine("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)"));
//#else
//        if (response != Packet.ResponsePing) UnityEngine.Debug.Log("Client: " + response + " " + buffer.position + " of " + buffer.size + ((ip == null) ? " (TCP)" : " (UDP)"));
//#endif

            switch (response)
            {
            case Packet.Empty: break;

            case Packet.ForwardToAll:
            case Packet.ForwardToOthers:
            case Packet.ForwardToAllSaved:
            case Packet.ForwardToOthersSaved:
            case Packet.ForwardToHost:
            {
                if (onForwardedPacket != null)
                {
                    onForwardedPacket(reader);
                }
                break;
            }

            case Packet.ForwardToPlayer:
            {
                // Skip the player ID
                reader.ReadInt32();
                if (onForwardedPacket != null)
                {
                    onForwardedPacket(reader);
                }
                break;
            }

            case Packet.ResponsePing:
            {
                mPing    = (int)(mTime - mPingTime);
                mCanPing = true;
                break;
            }

            case Packet.ResponseSetUDP:
            {
#if !UNITY_WEBPLAYER
                // The server has a new port for UDP traffic
                ushort port = reader.ReadUInt16();

                if (port != 0)
                {
                    IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes());
                    mServerUdpEndPoint = new IPEndPoint(ipa, port);
                    // Send an empty packet to the server, opening up the communication channel
                    if (mUdp.isActive)
                    {
                        mUdp.SendEmptyPacket(mServerUdpEndPoint);
                    }
                }
                else
                {
                    mServerUdpEndPoint = null;
                }
#endif
                break;
            }

            case Packet.ResponseJoiningChannel:
            {
                mIsInChannel = true;
                mDictionary.Clear();
                players.Clear();

                mChannelID = reader.ReadInt32();
                int count = reader.ReadInt16();

                for (int i = 0; i < count; ++i)
                {
                    Player p = new Player();
                    p.id   = reader.ReadInt32();
                    p.name = reader.ReadString();
                    mDictionary.Add(p.id, p);
                    players.Add(p);
                }
                break;
            }

            case Packet.ResponseLoadLevel:
            {
                // Purposely return after loading a level, ensuring that all future callbacks happen after loading
                if (onLoadLevel != null)
                {
                    onLoadLevel(reader.ReadString());
                }
                return(false);
            }

            case Packet.ResponsePlayerLeft:
            {
                Player p = GetPlayer(reader.ReadInt32());
                if (p != null)
                {
                    mDictionary.Remove(p.id);
                }
                players.Remove(p);
                if (onPlayerLeft != null)
                {
                    onPlayerLeft(p);
                }
                break;
            }

            case Packet.ResponsePlayerJoined:
            {
                Player p = new Player();
                p.id   = reader.ReadInt32();
                p.name = reader.ReadString();
                mDictionary.Add(p.id, p);
                players.Add(p);
                if (onPlayerJoined != null)
                {
                    onPlayerJoined(p);
                }
                break;
            }

            case Packet.ResponseSetHost:
            {
                mHost = reader.ReadInt32();
                if (onSetHost != null)
                {
                    onSetHost(isHosting);
                }
                break;
            }

            case Packet.ResponseSetChannelData:
            {
                mData = reader.ReadString();
                if (onSetChannelData != null)
                {
                    onSetChannelData(mData);
                }
                break;
            }

            case Packet.ResponseJoinChannel:
            {
                mIsInChannel = reader.ReadBoolean();
                if (onJoinChannel != null)
                {
                    onJoinChannel(mIsInChannel, mIsInChannel ? null : reader.ReadString());
                }
                break;
            }

            case Packet.ResponseLeaveChannel:
            {
                mData        = "";
                mChannelID   = 0;
                mIsInChannel = false;
                mDictionary.Clear();
                players.Clear();
                if (onLeftChannel != null)
                {
                    onLeftChannel();
                }
                break;
            }

            case Packet.ResponseRenamePlayer:
            {
                Player p       = GetPlayer(reader.ReadInt32());
                string oldName = p.name;
                if (p != null)
                {
                    p.name = reader.ReadString();
                }
                if (onRenamePlayer != null)
                {
                    onRenamePlayer(p, oldName);
                }
                break;
            }

            case Packet.ResponseCreate:
            {
                if (onCreate != null)
                {
                    int   playerID = reader.ReadInt32();
                    short index    = reader.ReadInt16();
                    uint  objID    = reader.ReadUInt32();
                    onCreate(playerID, index, objID, reader);
                }
                break;
            }

            case Packet.ResponseDestroy:
            {
                if (onDestroy != null)
                {
                    int count = reader.ReadUInt16();
                    for (int i = 0; i < count; ++i)
                    {
                        onDestroy(reader.ReadUInt32());
                    }
                }
                break;
            }

            case Packet.Error:
            {
                if (mTcp.stage != TcpProtocol.Stage.Connected && onConnect != null)
                {
                    onConnect(false, reader.ReadString());
                }
                else if (onError != null)
                {
                    onError(reader.ReadString());
                }
                break;
            }

            case Packet.Disconnect:
            {
                mData = "";
                if (isInChannel && onLeftChannel != null)
                {
                    onLeftChannel();
                }
                players.Clear();
                mDictionary.Clear();
                mTcp.Close(false);
                if (onDisconnect != null)
                {
                    onDisconnect();
                }
                break;
            }

            default:
            {
                OnPacket callback;

                if (packetHandlers.TryGetValue((byte)response, out callback))
                {
                    if (callback != null)
                    {
                        callback(response, reader, ip);
                    }
                }
                break;
            }
            }
            return(true);
        }