/// <summary>
        /// Keep receiving incoming packets.
        /// </summary>

        void Update()
        {
            Buffer buffer;
            bool   changed = false;
            long   time    = System.DateTime.UtcNow.Ticks / 10000;

            // Automatically try to connect and reconnect if not connected
            if (mRemoteAddress != null && mTcp.stage == TcpProtocol.Stage.NotConnected && mNextConnect < time)
            {
                mNextConnect = time + 5000;
                mTcp.Connect(mRemoteAddress);
            }

            // TCP-based lobby
            while (mTcp.ReceivePacket(out buffer))
            {
                if (buffer.size > 0)
                {
                    try
                    {
                        BinaryReader reader   = buffer.BeginReading();
                        Packet       response = (Packet)reader.ReadByte();

                        if (response == Packet.ResponseID)
                        {
                            if (mTcp.VerifyResponseID(response, reader))
                            {
                                isActive = true;

                                // Request the server list -- with TCP this only needs to be done once
                                mTcp.BeginSend(Packet.RequestServerList).Write(GameServer.gameID);
                                mTcp.EndSend();
                            }
                        }
                        else if (response == Packet.Disconnect)
                        {
                            knownServers.Clear();
                            isActive    = false;
                            changed     = true;
                            errorString = "";
                        }
                        else if (response == Packet.ResponseServerList)
                        {
                            lock (knownServers.list) knownServers.list.Clear();
                            knownServers.ReadFrom(reader, time);
                            changed     = true;
                            errorString = "";
                        }
                        else if (response == Packet.Error)
                        {
                            errorString = reader.ReadString();
                            Debug.LogWarning(errorString);
                            changed = true;
                        }
                    }
                    catch (System.Exception ex)
                    {
                        errorString = ex.Message;
                        Debug.LogWarning(ex.Message);
                        mTcp.Close(false);
                    }
                }
                buffer.Recycle();
            }

            // Trigger the listener callback
            if (changed && onChange != null)
            {
                onChange();
            }
        }
예제 #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;

#if DEBUG_PACKETS && !STANDALONE
            if (response != Packet.ResponsePing && response != Packet.Broadcast)
            {
                UnityEngine.Debug.Log("Client: " + response + " (" + buffer.size + " bytes) " + ((ip == null) ? "(TCP)" : "(UDP)"));
            }
#endif
            // Verification step must be passed first
            if (response == Packet.ResponseID || mTcp.stage == TcpProtocol.Stage.Verifying)
            {
                if (mTcp.VerifyResponseID(response, reader))
                {
                    mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000);

#if !UNITY_WEBPLAYER
                    if (mUdp.isActive)
                    {
                        // If we have a UDP listener active, tell the server
                        BeginSend(Packet.RequestSetUDP).Write((ushort)mUdp.listeningPort);
                        EndSend();
                    }
#endif
                    mCanPing = true;
                    if (onConnect != null)
                    {
                        onConnect(true, null);
                    }
                }
                return(true);
            }

            OnPacket callback;

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

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

            case Packet.ForwardToAll:
            case Packet.ForwardToOthers:
            case Packet.ForwardToAllSaved:
            case Packet.ForwardToOthersSaved:
            case Packet.ForwardToHost:
            case Packet.BroadcastAdmin:
            case Packet.Broadcast:
            {
                packetSourceID = reader.ReadInt32();
                int channelID = reader.ReadInt32();
                if (onForwardedPacket != null)
                {
                    onForwardedPacket(channelID, reader);
                }
                break;
            }

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

            case Packet.ForwardByName:
            {
                packetSourceID = reader.ReadInt32();
                reader.ReadString();                 // Skip the player name
                int channelID = reader.ReadInt32();
                if (onForwardedPacket != null)
                {
                    onForwardedPacket(channelID, reader);
                }
                break;
            }

            case Packet.ResponseSetPlayerData:
            {
                int    pid    = reader.ReadInt32();
                Player target = GetPlayer(pid);

                if (target != null)
                {
                    string   path = reader.ReadString();
                    DataNode node = target.Set(path, reader.ReadObject());
                    if (onSetPlayerData != null)
                    {
                        onSetPlayerData(target, path, node);
                    }
                }
                else
                {
                    UnityEngine.Debug.LogError("Not found: " + pid);
                }
                break;
            }

            case Packet.ResponsePing:
            {
                int ping = (int)(mMyTime - mPingTime);

                if (ip != null)
                {
                    if (onPing != null && ip != null)
                    {
                        onPing(ip, ping);
                    }
                }
                else
                {
                    mCanPing = true;
                    mPing    = ping;
                }
                break;
            }

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

                if (port != 0 && mTcp.tcpEndPoint != null)
                {
                    IPAddress ipa = new IPAddress(mTcp.tcpEndPoint.Address.GetAddressBytes());
                    mServerUdpEndPoint = new IPEndPoint(ipa, port);

                    // Send the first UDP packet to the server
                    if (mUdp.isActive)
                    {
                        mBuffer = Buffer.Create();
                        mBuffer.BeginPacket(Packet.RequestActivateUDP).Write(playerID);
                        mBuffer.EndPacket();
                        mUdp.Send(mBuffer, mServerUdpEndPoint);
                        mBuffer.Recycle();
                        mBuffer = null;
                    }
                }
                else
                {
                    mServerUdpEndPoint = null;
                }
#endif
                break;
            }

            case Packet.ResponseJoiningChannel:
            {
                int     channelID = reader.ReadInt32();
                int     count     = reader.ReadInt16();
                Channel ch        = GetChannel(channelID, true);

                for (int i = 0; i < count; ++i)
                {
                    int    pid = reader.ReadInt32();
                    Player p   = GetPlayer(pid, true);

                    if (reader.ReadBoolean())
                    {
                        p.name     = reader.ReadString();
                        p.dataNode = reader.ReadDataNode();
                    }
                    ch.players.Add(p);
                }
                break;
            }

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

            case Packet.ResponsePlayerJoined:
            {
                int channelID = reader.ReadInt32();

                Channel ch = GetChannel(channelID);

                if (ch != null)
                {
                    Player p = GetPlayer(reader.ReadInt32(), true);

                    if (reader.ReadBoolean())
                    {
                        p.name     = reader.ReadString();
                        p.dataNode = reader.ReadDataNode();
                    }

                    ch.players.Add(p);
                    if (onPlayerJoin != null)
                    {
                        onPlayerJoin(channelID, p);
                    }
                }
                break;
            }

            case Packet.ResponsePlayerLeft:
            {
                int channelID = reader.ReadInt32();
                int playerID  = reader.ReadInt32();

                Channel ch = GetChannel(channelID);

                if (ch != null)
                {
                    Player p = ch.GetPlayer(playerID);
                    ch.players.Remove(p);
                    RebuildPlayerDictionary();
                    if (onPlayerLeave != null)
                    {
                        onPlayerLeave(channelID, p);
                    }
                }
                break;
            }

            case Packet.ResponseSetHost:
            {
                int channelID = reader.ReadInt32();
                int hostID    = reader.ReadInt32();

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

                    if (ch.id == channelID)
                    {
                        ch.host = GetPlayer(hostID);
                        if (onHostChanged != null)
                        {
                            onHostChanged(ch);
                        }
                        break;
                    }
                }
                break;
            }

            case Packet.ResponseSetChannelData:
            {
                int     channelID = reader.ReadInt32();
                Channel ch        = GetChannel(channelID);

                if (ch != null)
                {
                    string   path = reader.ReadString();
                    DataNode node = ch.Set(path, reader.ReadObject());
                    if (onSetChannelData != null)
                    {
                        onSetChannelData(ch, path, node);
                    }
                }
                break;
            }

            case Packet.ResponseJoinChannel:
            {
                int    channelID = reader.ReadInt32();
                bool   success   = reader.ReadBoolean();
                string msg       = success ? null : reader.ReadString();

                // mJoining can contain -2 and -1 when joining random channels
                if (!mJoining.Remove(channelID))
                {
                    for (int i = 0; i < mJoining.size; ++i)
                    {
                        int id = mJoining[i];

                        if (id < 0)
                        {
                            mJoining.RemoveAt(i);
                            break;
                        }
                    }
                }
#if UNITY_EDITOR
                if (!success)
                {
                    UnityEngine.Debug.LogError("ResponseJoinChannel: " + success + ", " + msg);
                }
#endif
                if (onJoinChannel != null)
                {
                    onJoinChannel(channelID, success, msg);
                }
                break;
            }

            case Packet.ResponseLeaveChannel:
            {
                int channelID = reader.ReadInt32();

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

                    if (ch.id == channelID)
                    {
                        mChannels.RemoveAt(i);
                        break;
                    }
                }

                RebuildPlayerDictionary();
                if (onLeaveChannel != null)
                {
                    onLeaveChannel(channelID);
                }

                // Purposely exit after receiving a "left channel" notification so that other packets get handled in the next frame.
                return(false);
            }

            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.ResponseCreateObject:
            {
                if (onCreate != null)
                {
                    int  playerID  = reader.ReadInt32();
                    int  channelID = reader.ReadInt32();
                    uint objID     = reader.ReadUInt32();
                    onCreate(channelID, playerID, objID, reader);
                }
                break;
            }

            case Packet.ResponseDestroyObject:
            {
                if (onDestroy != null)
                {
                    int channelID = reader.ReadInt32();
                    int count     = reader.ReadUInt16();

                    for (int i = 0; i < count; ++i)
                    {
                        uint val = reader.ReadUInt32();
                        onDestroy(channelID, val);
                    }
                }
                break;
            }

            case Packet.ResponseTransferObject:
            {
                if (onTransfer != null)
                {
                    int  from = reader.ReadInt32();
                    int  to   = reader.ReadInt32();
                    uint id0  = reader.ReadUInt32();
                    uint id1  = reader.ReadUInt32();
                    onTransfer(from, to, id0, id1);
                }
                break;
            }

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

            case Packet.Disconnect:
            {
                if (onLeaveChannel != null)
                {
                    while (mChannels.size > 0)
                    {
                        int     index = mChannels.size - 1;
                        Channel ch    = mChannels[index];
                        mChannels.RemoveAt(index);
                        onLeaveChannel(ch.id);
                    }
                }

                mChannels.Clear();
                mGetChannelsCallbacks.Clear();
                mDictionary.Clear();
                mTcp.Close(false);
                mLoadFiles.Clear();
                mGetFiles.Clear();
                mJoining.Clear();
                mIsAdmin = false;

                if (mLocalServer != null)
                {
                    mLocalServer.localClient = null;
                    mLocalServer             = null;
                }

                if (onDisconnect != null)
                {
                    onDisconnect();
                }
                mConfig = new DataNode("Version", Player.version);
                break;
            }

            case Packet.ResponseGetFileList:
            {
                string   filename = reader.ReadString();
                int      size     = reader.ReadInt32();
                string[] files    = null;

                if (size > 0)
                {
                    files = new string[size];
                    for (int i = 0; i < size; ++i)
                    {
                        files[i] = reader.ReadString();
                    }
                }

                OnGetFiles cb = null;
                if (mGetFiles.TryGetValue(filename, out cb))
                {
                    mGetFiles.Remove(filename);
                }

                if (cb != null)
                {
                    try
                    {
                        cb(filename, files);
                    }
#if UNITY_EDITOR
                    catch (System.Exception ex)
                    {
                        Debug.LogError(ex.Message + ex.StackTrace);
                    }
#else
                    catch (System.Exception) {}
#endif
                }
                break;
            }

            case Packet.ResponseLoadFile:
            {
                string     filename = reader.ReadString();
                int        size     = reader.ReadInt32();
                byte[]     data     = reader.ReadBytes(size);
                OnLoadFile cb       = null;

                if (mLoadFiles.TryGetValue(filename, out cb))
                {
                    mLoadFiles.Remove(filename);
                }

                if (cb != null)
                {
                    try
                    {
                        cb(filename, data);
                    }
#if UNITY_EDITOR
                    catch (System.Exception ex)
                    {
                        Debug.LogError(ex.Message + ex.StackTrace);
                    }
#else
                    catch (System.Exception) {}
#endif
                }
                break;
            }

            case Packet.ResponseVerifyAdmin:
            {
                int    pid = reader.ReadInt32();
                Player p   = GetPlayer(pid);
                if (p == player)
                {
                    mIsAdmin = true;
                }
                if (onSetAdmin != null)
                {
                    onSetAdmin(p);
                }
                break;
            }

            case Packet.ResponseSetServerData:
            {
                string path = reader.ReadString();
                object obj  = reader.ReadObject();

                if (obj != null)
                {
                    DataNode node = mConfig.SetHierarchy(path, obj);
                    if (onSetServerData != null)
                    {
                        onSetServerData(path, node);
                    }
                }
                else
                {
                    DataNode node = mConfig.RemoveHierarchy(path);
                    if (onSetServerData != null)
                    {
                        onSetServerData(path, node);
                    }
                }
                break;
            }

            case Packet.ResponseChannelList:
            {
                if (mGetChannelsCallbacks.Count != 0)
                {
                    OnGetChannels       cb       = mGetChannelsCallbacks.Dequeue();
                    List <Channel.Info> channels = new List <Channel.Info>();
                    int count = reader.ReadInt32();

                    for (int i = 0; i < count; ++i)
                    {
                        Channel.Info info = new Channel.Info();
                        info.id           = reader.ReadInt32();
                        info.players      = reader.ReadUInt16();
                        info.limit        = reader.ReadUInt16();
                        info.hasPassword  = reader.ReadBoolean();
                        info.isPersistent = reader.ReadBoolean();
                        info.level        = reader.ReadString();
                        info.data         = reader.ReadDataNode();
                        channels.Add(info);
                    }

                    if (cb != null)
                    {
                        cb(channels);
                    }
                }
                break;
            }

            case Packet.ResponseLockChannel:
            {
                int     channelID = reader.ReadInt32();
                bool    isLocked  = reader.ReadBoolean();
                Channel ch        = GetChannel(channelID);
                if (ch != null)
                {
                    ch.isLocked = isLocked;
                }
                if (onLockChannel != null)
                {
                    onLockChannel(channelID, isLocked);
                }
                break;
            }
            }
            return(true);
        }
예제 #3
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 (response == Packet.ResponseID || mTcp.stage == TcpProtocol.Stage.Verifying)
            {
                if (mTcp.VerifyResponseID(response, reader))
                {
                    mTimeDifference = reader.ReadInt64() - (System.DateTime.UtcNow.Ticks / 10000);

#if !UNITY_WEBPLAYER
                    if (mUdp.isActive)
                    {
                        // If we have a UDP listener active, tell the server
                        BeginSend(Packet.RequestSetUDP).Write((ushort)mUdp.listeningPort);
                        EndSend();
                    }
#endif
                    mCanPing = true;
                    if (onConnect != null)
                    {
                        onConnect(true, null);
                    }
                }
                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

            OnPacket callback;

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

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

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

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

            case Packet.ForwardByName:
            {
                // Skip the player name
                reader.ReadString();
                if (onForwardedPacket != null)
                {
                    onForwardedPacket(reader);
                }
                break;
            }

            case Packet.SyncPlayerData:
            {
                Player target = GetPlayer(reader.ReadInt32());

                if (target != null)
                {
                    target.data = reader.ReadObject();
                    if (onPlayerSync != null)
                    {
                        onPlayerSync(target);
                    }
                }
                break;
            }

            case Packet.ResponsePing:
            {
                int ping = (int)(mMyTime - mPingTime);

                if (ip != null)
                {
                    if (onPing != null && ip != null)
                    {
                        onPing(ip, ping);
                    }
                }
                else
                {
                    mCanPing = true;
                    mPing    = ping;
                }
                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 the first UDP packet to the server
                    if (mUdp.isActive)
                    {
                        mBuffer = Buffer.Create();
                        mBuffer.BeginPacket(Packet.RequestActivateUDP).Write(playerID);
                        mBuffer.EndPacket();
                        mUdp.Send(mBuffer, mServerUdpEndPoint);
                        mBuffer.Recycle();
                        mBuffer = null;
                    }
                }
                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();
                    p.data = reader.ReadObject();
                    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();
                p.data = reader.ReadObject();
                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();
                    ushort index    = reader.ReadUInt16();
                    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);
                mLoadFiles.Clear();
                if (onDisconnect != null)
                {
                    onDisconnect();
                }
                break;
            }

            case Packet.ResponseLoadFile:
            {
                string     filename = reader.ReadString();
                int        size     = reader.ReadInt32();
                byte[]     data     = reader.ReadBytes(size);
                OnLoadFile lfc      = mLoadFiles.Pop();
                if (lfc != null)
                {
                    lfc(filename, data);
                }
                break;
            }
            }
            return(true);
        }
예제 #4
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);
        }