예제 #1
0
        /// <summary>
        /// Retrieve a player by their UDP end point.
        /// </summary>

        TcpPlayer GetPlayer(IPEndPoint ip)
        {
            TcpPlayer p = null;

            mDictionaryEP.TryGetValue(ip, out p);
            return(p);
        }
예제 #2
0
        /// <summary>
        /// Retrieve a player by their ID.
        /// </summary>

        TcpPlayer GetPlayer(int id)
        {
            TcpPlayer p = null;

            mDictionaryID.TryGetValue(id, out p);
            return(p);
        }
예제 #3
0
        /// <summary>
        /// Send the outgoing buffer to all connected players.
        /// </summary>

        void EndSend(bool reliable)
        {
            mBuffer.EndPacket();
            if (mBuffer.size > 1024)
            {
                reliable = true;
            }

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

                for (int b = 0; b < channel.players.size; ++b)
                {
                    TcpPlayer player = channel.players[b];

                    if (player.stage == TcpProtocol.Stage.Connected)
                    {
                        if (reliable || player.udpEndPoint == null || !mAllowUdp)
                        {
                            player.SendTcpPacket(mBuffer);
                        }
                        else
                        {
                            mUdp.Send(mBuffer, player.udpEndPoint);
                        }
                    }
                }
            }
            mBuffer.Recycle();
            mBuffer = null;
        }
예제 #4
0
        /// <summary>
        /// Send the outgoing buffer to all players in the specified channel.
        /// </summary>

        void SendToChannel(bool reliable, Channel channel, Buffer buffer)
        {
            mBuffer.MarkAsUsed();
            if (mBuffer.size > 1024)
            {
                reliable = true;
            }

            for (int i = 0; i < channel.players.size; ++i)
            {
                TcpPlayer player = channel.players[i];

                if (player.stage == TcpProtocol.Stage.Connected)
                {
                    if (reliable || player.udpEndPoint == null || !mAllowUdp)
                    {
                        player.SendTcpPacket(mBuffer);
                    }
                    else
                    {
                        mUdp.Send(mBuffer, player.udpEndPoint);
                    }
                }
            }
            mBuffer.Recycle();
        }
예제 #5
0
 internal NomadLivePlayer(TcpPlayer player)
 {
     this.player = player;
     Id = player.id.ToString();
     Character = this;
     Object = null; // TODO
 }
예제 #6
0
        /// <summary>
        /// Remove the specified player.
        /// </summary>

        void RemovePlayer(TcpPlayer p)
        {
            if (p != null)
            {
                SendLeaveChannel(p, false);
#if STANDALONE
                Console.WriteLine(p.address + " has disconnected");
#endif
                p.Release();
                mPlayers.Remove(p);

                if (p.udpEndPoint != null)
                {
                    mDictionaryEP.Remove(p.udpEndPoint);
                    p.udpEndPoint = null;
                }

                if (p.id != 0)
                {
                    if (mDictionaryID.Remove(p.id))
                    {
                        if (lobbyLink != null)
                        {
                            lobbyLink.SendUpdate(this);
                        }
                        if (onPlayerDisconnect != null)
                        {
                            onPlayerDisconnect(p);
                        }
                    }
                    p.id = 0;
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Remove the specified player from the channel.
        /// </summary>

        public void RemovePlayer(TcpPlayer p, List <uint> destroyedObjects)
        {
            destroyedObjects.Clear();

            if (players.Remove(p))
            {
                // When the host leaves, clear the host (it gets changed in SendLeaveChannel)
                if (p == host)
                {
                    host = null;
                }

                // Remove all of the non-persistent objects that were created by this player
                for (int i = created.size; i > 0;)
                {
                    Channel.CreatedObject obj = created[--i];

                    if (obj.playerID == p.id)
                    {
                        if (obj.type == 2)
                        {
                            if (obj.buffer != null)
                            {
                                obj.buffer.Recycle();
                            }
                            uint objID = obj.objectID;
                            created.RemoveAt(i);
                            destroyedObjects.Add(objID);
                            if (objID >= 32768)
                            {
                                mCreatedObjectDictionary.Remove(objID);
                            }
                            DestroyObjectRFCs(objID);
                        }
                        else if (players.size != 0)
                        {
                            // The same operation happens on the client as well
                            obj.playerID = players[0].id;
                        }
                    }
                }

                // Close the channel if it wasn't persistent
                if ((!persistent || playerLimit < 1) && players.size == 0)
                {
                    closed = true;

                    for (int i = 0; i < rfcs.size; ++i)
                    {
                        RFC r = rfcs[i];
                        if (r.data != null)
                        {
                            r.data.Recycle();
                        }
                    }
                    rfcs.Clear();
                }
            }
        }
예제 #8
0
        /// <summary>
        /// Add a new player entry.
        /// </summary>

        TcpPlayer AddPlayer(Socket socket)
        {
            TcpPlayer player = new TcpPlayer();

            player.StartReceiving(socket);
            mPlayers.Add(player);
            return(player);
        }
예제 #9
0
        /// <summary>
        /// Have the specified player assume control of the channel.
        /// </summary>

        void SendSetHost(TcpPlayer player)
        {
            if (player.channel != null && player.channel.host != player)
            {
                player.channel.host = player;
                BinaryWriter writer = BeginSend(Packet.ResponseSetHost);
                writer.Write(player.id);
                EndSend(true, player.channel, null);
            }
        }
예제 #10
0
        /// <summary>
        /// Change the player's UDP end point and update the local dictionary.
        /// </summary>

        void SetPlayerUdpEndPoint(TcpPlayer player, IPEndPoint udp)
        {
            if (player.udpEndPoint != null)
            {
                mDictionaryEP.Remove(player.udpEndPoint);
            }
            player.udpEndPoint = udp;
            if (udp != null)
            {
                mDictionaryEP[udp] = player;
            }
        }
예제 #11
0
        /// <summary>
        /// Leave the channel the player is in.
        /// </summary>

        void SendLeaveChannel(TcpPlayer player, bool notify)
        {
            Channel ch = player.channel;

            if (ch != null)
            {
                // Remove this player from the channel
                ch.RemovePlayer(player, mTemp);
                player.channel = null;

                // Are there other players left?
                if (ch.players.size > 0)
                {
                    BinaryWriter writer;

                    // Inform the other players that the player's objects should be destroyed
                    if (mTemp.size > 0)
                    {
                        writer = BeginSend(Packet.ResponseDestroy);
                        writer.Write((ushort)mTemp.size);
                        for (int i = 0; i < mTemp.size; ++i)
                        {
                            writer.Write(mTemp[i]);
                        }
                        EndSend(true, ch, null);
                    }

                    // If this player was the host, choose a new host
                    if (ch.host == null)
                    {
                        SendSetHost(ch.players[0]);
                    }

                    // Inform everyone of this player leaving the channel
                    writer = BeginSend(Packet.ResponsePlayerLeft);
                    writer.Write(player.id);
                    EndSend(true, ch, null);
                }
                else if (!ch.persistent)
                {
                    // No other players left -- delete this channel
                    mChannels.Remove(ch);
                }

                // Notify the player that they have left the channel
                if (notify && player.isConnected)
                {
                    BeginSend(Packet.ResponseLeaveChannel);
                    EndSend(true, player);
                }
            }
        }
예제 #12
0
        /// <summary>
        /// Remove the specified player from the channel.
        /// </summary>

        public void RemovePlayer(TcpPlayer p, List <uint> destroyedObjects)
        {
            destroyedObjects.Clear();

            if (p == host)
            {
                host = null;
            }

            if (players.Remove(p))
            {
                // Remove all of the non-persistent objects that were created by this player
                for (int i = created.size; i > 0;)
                {
                    Channel.CreatedObject obj = created[--i];

                    if (obj.type == 2 && obj.playerID == p.id)
                    {
                        if (obj.buffer != null)
                        {
                            obj.buffer.Recycle();
                        }
                        created.RemoveAt(i);
                        destroyedObjects.Add(obj.uniqueID);
                        DestroyObjectRFCs(obj.uniqueID);
                    }
                }

                // Close the channel if it wasn't persistent
                if ((!persistent || playerLimit < 1) && players.size == 0)
                {
                    closed = true;

                    for (int i = 0; i < rfcs.size; ++i)
                    {
                        RFC r = rfcs[i];
                        if (r.buffer != null)
                        {
                            r.buffer.Recycle();
                        }
                    }
                    rfcs.Clear();
                }
            }
        }
예제 #13
0
        /// <summary>
        /// Send the outgoing buffer to the specified player.
        /// </summary>

        void EndSend(bool reliable, TcpPlayer player)
        {
            mBuffer.EndPacket();
            if (mBuffer.size > 1024)
            {
                reliable = true;
            }

            if (reliable || player.udpEndPoint == null || !mAllowUdp)
            {
                player.SendTcpPacket(mBuffer);
            }
            else
            {
                mUdp.Send(mBuffer, player.udpEndPoint);
            }

            mBuffer.Recycle();
            mBuffer = null;
        }
예제 #14
0
        /// <summary>
        /// Log an error message.
        /// </summary>

        void Error(TcpPlayer p, string error)
        {
#if UNITY_EDITOR
            if (p != null)
            {
                UnityEngine.Debug.LogError(error + " (" + p.address + ")");
            }
            else
            {
                UnityEngine.Debug.LogError(error);
            }
#elif STANDALONE
            if (p != null)
            {
                Console.WriteLine(p.address + " ERROR: " + error);
            }
            else
            {
                Console.WriteLine("ERROR: " + error);
            }
#endif
        }
예제 #15
0
        /// <summary>
        /// Join the specified channel.
        /// </summary>

        void SendJoinChannel(TcpPlayer player, Channel channel)
        {
            if (player.channel == null || player.channel != channel)
            {
                // Set the player's channel
                player.channel = channel;

                // Everything else gets sent to the player, so it's faster to do it all at once
                player.FinishJoiningChannel();

                // Inform the channel that a new player is joining
                BinaryWriter writer = BeginSend(Packet.ResponsePlayerJoined);
                {
                    writer.Write(player.id);
                    writer.Write(string.IsNullOrEmpty(player.name) ? "Guest" : player.name);
                }
                EndSend(true, channel, null);

                // Add this player to the channel now that the joining process is complete
                channel.players.Add(player);
            }
        }
예제 #16
0
 /// <summary>
 /// Log an error message.
 /// </summary>
 void Error(TcpPlayer p, string error)
 {
     #if UNITY_EDITOR
     if (p != null) UnityEngine.Debug.LogError(error + " (" + p.address + ")");
     else UnityEngine.Debug.LogError(error);
     #elif STANDALONE
     if (p != null) Console.WriteLine(p.address + " ERROR: " + error);
     else Console.WriteLine("ERROR: " + error);
     #endif
 }
예제 #17
0
        /// <summary>
        /// Process a packet from the player.
        /// </summary>
        void ProcessChannelPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request)
        {
            switch (request)
            {
            case Packet.RequestCreate:
            {
                // Create a new object
                ushort objectIndex = reader.ReadUInt16();
                byte type = reader.ReadByte();
                uint uniqueID = 0;

                if (type != 0)
                {
                    uniqueID = --player.channel.objectCounter;

                    // 1-32767 is reserved for existing scene objects.
                    // 32768 - 16777215 is for dynamically created objects.
                    if (uniqueID < 32768)
                    {
                        player.channel.objectCounter = 0xFFFFFF;
                        uniqueID = 0xFFFFFF;
                    }

                    Channel.CreatedObject obj = new Channel.CreatedObject();
                    obj.playerID = player.id;
                    obj.objectID = objectIndex;
                    obj.uniqueID = uniqueID;
                    obj.type = type;

                    if (buffer.size > 0)
                    {
                        obj.buffer = buffer;
                        buffer.MarkAsUsed();
                    }
                    player.channel.created.Add(obj);
                }

                // Inform the channel
                BinaryWriter writer = BeginSend(Packet.ResponseCreate);
                writer.Write(player.id);
                writer.Write(objectIndex);
                writer.Write(uniqueID);
                if (buffer.size > 0) writer.Write(buffer.buffer, buffer.position, buffer.size);
                EndSend(true, player.channel, null);
                break;
            }
            case Packet.RequestDestroy:
            {
                // Destroy the specified network object
                uint uniqueID = reader.ReadUInt32();

                // Remove this object
                if (player.channel.DestroyObject(uniqueID))
                {
                    // Inform all players in the channel that the object should be destroyed
                    BinaryWriter writer = BeginSend(Packet.ResponseDestroy);
                    writer.Write((ushort)1);
                    writer.Write(uniqueID);
                    EndSend(true, player.channel, null);
                }
                break;
            }
            case Packet.RequestLoadLevel:
            {
                // Change the currently loaded level
                if (player.channel.host == player)
                {
                    player.channel.Reset();
                    player.channel.level = reader.ReadString();

                    BinaryWriter writer = BeginSend(Packet.ResponseLoadLevel);
                    writer.Write(string.IsNullOrEmpty(player.channel.level) ? "" : player.channel.level);
                    EndSend(true, player.channel, null);
                }
                break;
            }
            case Packet.RequestSetHost:
            {
                // Transfer the host state from one player to another
                if (player.channel.host == player)
                {
                    TcpPlayer newHost = GetPlayer(reader.ReadInt32());
                    if (newHost != null && newHost.channel == player.channel) SendSetHost(newHost);
                }
                break;
            }
            case Packet.RequestLeaveChannel:
            {
                SendLeaveChannel(player, true);
                break;
            }
            case Packet.RequestCloseChannel:
            {
                player.channel.persistent = false;
                player.channel.closed = true;
                break;
            }
            case Packet.RequestSetPlayerLimit:
            {
                player.channel.playerLimit = reader.ReadUInt16();
                break;
            }
            case Packet.RequestRemoveRFC:
            {
                uint id = reader.ReadUInt32();
                string funcName = ((id & 0xFF) == 0) ? reader.ReadString() : null;
                player.channel.DeleteRFC(id, funcName);
                break;
            }
            case Packet.RequestSetChannelData:
            {
                player.channel.data = reader.ReadString();
                BinaryWriter writer = BeginSend(Packet.ResponseSetChannelData);
                writer.Write(player.channel.data);
                EndSend(true, player.channel, null);
                break;
            }
            }
        }
예제 #18
0
        /// <summary>
        /// Join the specified channel.
        /// </summary>
        void SendJoinChannel(TcpPlayer player, Channel channel)
        {
            if (player.channel == null || player.channel != channel)
            {
            // Set the player's channel
            player.channel = channel;

            // Everything else gets sent to the player, so it's faster to do it all at once
            player.FinishJoiningChannel();

            // Inform the channel that a new player is joining
            BinaryWriter writer = BeginSend(Packet.ResponsePlayerJoined);
            {
                writer.Write(player.id);
                writer.Write(string.IsNullOrEmpty(player.name) ? "Guest" : player.name);
            }
            EndSend(true, channel, null);

            // Add this player to the channel now that the joining process is complete
            channel.players.Add(player);
            }
        }
예제 #19
0
        /// <summary>
        /// Leave the channel the player is in.
        /// </summary>
        void SendLeaveChannel(TcpPlayer player, bool notify)
        {
            Channel ch = player.channel;

            if (ch != null)
            {
            // Remove this player from the channel
            ch.RemovePlayer(player, mTemp);
            player.channel = null;

            // Are there other players left?
            if (ch.players.size > 0)
            {
                BinaryWriter writer;

                // Inform the other players that the player's objects should be destroyed
                if (mTemp.size > 0)
                {
                    writer = BeginSend(Packet.ResponseDestroy);
                    writer.Write((ushort)mTemp.size);
                    for (int i = 0; i < mTemp.size; ++i) writer.Write(mTemp[i]);
                    EndSend(true, ch, null);
                }

                // If this player was the host, choose a new host
                if (ch.host == null) SendSetHost(ch.players[0]);

                // Inform everyone of this player leaving the channel
                writer = BeginSend(Packet.ResponsePlayerLeft);
                writer.Write(player.id);
                EndSend(true, ch, null);
            }
            else if (!ch.persistent)
            {
                // No other players left -- delete this channel
                mChannels.Remove(ch);
            }

            // Notify the player that they have left the channel
            if (notify && player.isConnected)
            {
                BeginSend(Packet.ResponseLeaveChannel);
                EndSend(true, player);
            }
            }
        }
예제 #20
0
        /// <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.RequestSetTimeout:
            {
                // The passed value is in seconds, but the stored value is in milliseconds (to avoid a math operation)
                player.timeoutTime = reader.ReadInt32() * 1000;
                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;
            }
            case Packet.Broadcast:
            {
                // 4 bytes for size, 1 byte for ID
                buffer.position = buffer.position - 5;

                // Forward the packet to everyone connected to the server
                for (int i = 0; i < mPlayers.size; ++i)
                {
                    TcpPlayer tp = mPlayers[i];

                    if (reliable || tp.udpEndPoint == null || !mAllowUdp)
                    {
                        tp.SendTcpPacket(buffer);
                    }
                    else mUdp.Send(buffer, tp.udpEndPoint);
                }
                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;
        }
예제 #21
0
        /// <summary>
        /// Channel joining process involves multiple steps. It's faster to perform them all at once.
        /// </summary>

        public void FinishJoiningChannel()
        {
            Buffer buffer = Buffer.Create();

            // Step 2: Tell the player who else is in the channel
            BinaryWriter writer = buffer.BeginPacket(Packet.ResponseJoiningChannel);
            {
                writer.Write(channel.id);
                writer.Write((short)channel.players.size);

                for (int i = 0; i < channel.players.size; ++i)
                {
                    TcpPlayer tp = channel.players[i];
                    writer.Write(tp.id);
                    writer.Write(string.IsNullOrEmpty(tp.name) ? "Guest" : tp.name);
#if STANDALONE
                    if (tp.data == null)
                    {
                        writer.Write((byte)0);
                    }
                    else
                    {
                        writer.Write((byte[])tp.data);
                    }
#else
                    writer.WriteObject(tp.data);
#endif
                }
            }

            // End the first packet, but remember where it ended
            int offset = buffer.EndPacket();

            // Step 3: Inform the player of who is hosting
            if (channel.host == null)
            {
                channel.host = this;
            }
            buffer.BeginPacket(Packet.ResponseSetHost, offset);
            writer.Write(channel.host.id);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Step 4: Send the channel's data
            if (!string.IsNullOrEmpty(channel.data))
            {
                buffer.BeginPacket(Packet.ResponseSetChannelData, offset);
                writer.Write(channel.data);
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 5: Inform the player of what level we're on
            buffer.BeginPacket(Packet.ResponseLoadLevel, offset);
            writer.Write(string.IsNullOrEmpty(channel.level) ? "" : channel.level);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Step 6: Send the list of objects that have been created
            for (int i = 0; i < channel.created.size; ++i)
            {
                Channel.CreatedObject obj = channel.created.buffer[i];

                bool isPresent = false;

                for (int b = 0; b < channel.players.size; ++b)
                {
                    if (channel.players[b].id == obj.playerID)
                    {
                        isPresent = true;
                        break;
                    }
                }

                // If the previous owner is not present, transfer ownership to the host
                if (!isPresent)
                {
                    obj.playerID = channel.host.id;
                }

                buffer.BeginPacket(Packet.ResponseCreate, offset);
                writer.Write(obj.playerID);
                writer.Write(obj.objectIndex);
                writer.Write(obj.objectID);
                writer.Write(obj.buffer.buffer, obj.buffer.position, obj.buffer.size);
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 7: Send the list of objects that have been destroyed
            if (channel.destroyed.size != 0)
            {
                buffer.BeginPacket(Packet.ResponseDestroy, offset);
                writer.Write((ushort)channel.destroyed.size);
                for (int i = 0; i < channel.destroyed.size; ++i)
                {
                    writer.Write(channel.destroyed.buffer[i]);
                }
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 8: Send all buffered RFCs to the new player
            for (int i = 0; i < channel.rfcs.size; ++i)
            {
                Channel.RFC rfc = channel.rfcs[i];
                buffer.BeginWriting(offset);
                writer.Write(rfc.buffer.buffer, 0, rfc.buffer.size);
                offset = buffer.EndWriting();
            }

            // Step 9: The join process is now complete
            buffer.BeginPacket(Packet.ResponseJoinChannel, offset);
            writer.Write(true);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Send the entire buffer
            SendTcpPacket(buffer);
            buffer.Recycle();
        }
예제 #22
0
        /// <summary>
        /// Remove the specified player from the channel.
        /// </summary>
        public void RemovePlayer(TcpPlayer p, List<uint> destroyedObjects)
        {
            destroyedObjects.Clear();

            if (p == host) host = null;

            if (players.Remove(p))
            {
            // Remove all of the non-persistent objects that were created by this player
            for (int i = created.size; i > 0; )
            {
                Channel.CreatedObject obj = created[--i];

                if (obj.type == 2 && obj.playerID == p.id)
                {
                    if (obj.buffer != null) obj.buffer.Recycle();
                    created.RemoveAt(i);
                    destroyedObjects.Add(obj.uniqueID);
                    DestroyObjectRFCs(obj.uniqueID);
                }
            }

            // Close the channel if it wasn't persistent
            if ((!persistent || playerLimit < 1) && players.size == 0)
            {
                closed = true;

                for (int i = 0; i < rfcs.size; ++i)
                {
                    RFC r = rfcs[i];
                    if (r.buffer != null) r.buffer.Recycle();
                }
                rfcs.Clear();
            }
            }
        }
예제 #23
0
 /// <summary>
 /// Change the player's UDP end point and update the local dictionary.
 /// </summary>
 void SetPlayerUdpEndPoint(TcpPlayer player, IPEndPoint udp)
 {
     if (player.udpEndPoint != null) mDictionaryEP.Remove(player.udpEndPoint);
     player.udpEndPoint = udp;
     if (udp != null) mDictionaryEP[udp] = player;
 }
예제 #24
0
 /// <summary>
 /// Add a new player entry.
 /// </summary>
 TcpPlayer AddPlayer(Socket socket)
 {
     TcpPlayer player = new TcpPlayer();
     player.StartReceiving(socket);
     mPlayers.Add(player);
     return player;
 }
예제 #25
0
 internal void NotifyPlayerDisconnect(TcpPlayer player) => livePlayers.Remove(player.id.ToString());
예제 #26
0
        /// <summary>
        /// Thread that will be processing incoming data.
        /// </summary>

        void ThreadFunction()
        {
            for (; ;)
            {
                Buffer buffer;
                bool   received = false;
                mTime = DateTime.Now.Ticks / 10000;
                IPEndPoint ip;

                // Stop the listener if the port is 0 (MakePrivate() was called)
                if (mListenerPort == 0)
                {
                    if (mListener != null)
                    {
                        mListener.Stop();
                        mListener = null;
                        if (lobbyLink != null)
                        {
                            lobbyLink.Stop();
                        }
                        if (onShutdown != null)
                        {
                            onShutdown();
                        }
                    }
                }
                else
                {
                    // Add all pending connections
                    while (mListener != null && mListener.Pending())
                    {
#if STANDALONE
                        TcpPlayer p = AddPlayer(mListener.AcceptSocket());
                        Console.WriteLine(p.address + " has connected");
#else
                        AddPlayer(mListener.AcceptSocket());
#endif
                    }
                }

                // Process datagrams first
                while (mUdp.listeningPort != 0 && mUdp.ReceivePacket(out buffer, out ip))
                {
                    if (buffer.size > 0)
                    {
                        TcpPlayer player = GetPlayer(ip);

                        if (player != null)
                        {
                            try
                            {
                                if (ProcessPlayerPacket(buffer, player, false))
                                {
                                    received = true;
                                }
                            }
                            catch (System.Exception) { RemovePlayer(player); }
                        }
                    }
                    buffer.Recycle();
                }

                // Process player connections next
                for (int i = 0; i < mPlayers.size;)
                {
                    TcpPlayer player = mPlayers[i];

                    // Process up to 100 packets at a time
                    for (int b = 0; b < 100 && player.ReceivePacket(out buffer); ++b)
                    {
                        if (buffer.size > 0)
                        {
                            try
                            {
                                if (ProcessPlayerPacket(buffer, player, true))
                                {
                                    received = true;
                                }
                            }
#if STANDALONE
                            catch (System.Exception ex)
                            {
                                Console.WriteLine("ERROR (ProcessPlayerPacket): " + ex.Message);
                                RemovePlayer(player);
                            }
#else
                            catch (System.Exception) { RemovePlayer(player); }
#endif
                        }
                        buffer.Recycle();
                    }

                    // Time out -- disconnect this player
                    if (player.stage == TcpProtocol.Stage.Connected)
                    {
                        // Up to 10 seconds can go without a single packet before the player is removed
                        if (player.lastReceivedTime + 10000 < mTime)
                        {
#if STANDALONE
                            Console.WriteLine(player.address + " has timed out");
#endif
                            RemovePlayer(player);
                            continue;
                        }
                    }
                    else if (player.lastReceivedTime + 2000 < mTime)
                    {
#if STANDALONE
                        Console.WriteLine(player.address + " has timed out");
#endif
                        RemovePlayer(player);
                        continue;
                    }
                    ++i;
                }
                if (!received)
                {
                    Thread.Sleep(1);
                }
            }
        }
예제 #27
0
        /// <summary>
        /// Process a packet from the player.
        /// </summary>

        void ProcessChannelPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request)
        {
            switch (request)
            {
            case Packet.RequestCreate:
            {
                // Create a new object
                ushort objectIndex = reader.ReadUInt16();
                byte   type        = reader.ReadByte();
                uint   uniqueID    = 0;

                if (type != 0)
                {
                    uniqueID = --player.channel.objectCounter;

                    // 1-32767 is reserved for existing scene objects.
                    // 32768 - 16777215 is for dynamically created objects.
                    if (uniqueID < 32768)
                    {
                        player.channel.objectCounter = 0xFFFFFF;
                        uniqueID = 0xFFFFFF;
                    }

                    Channel.CreatedObject obj = new Channel.CreatedObject();
                    obj.playerID = player.id;
                    obj.objectID = objectIndex;
                    obj.uniqueID = uniqueID;
                    obj.type     = type;

                    if (buffer.size > 0)
                    {
                        obj.buffer = buffer;
                        buffer.MarkAsUsed();
                    }
                    player.channel.created.Add(obj);
                }

                // Inform the channel
                BinaryWriter writer = BeginSend(Packet.ResponseCreate);
                writer.Write(player.id);
                writer.Write(objectIndex);
                writer.Write(uniqueID);
                if (buffer.size > 0)
                {
                    writer.Write(buffer.buffer, buffer.position, buffer.size);
                }
                EndSend(true, player.channel, null);
                break;
            }

            case Packet.RequestDestroy:
            {
                // Destroy the specified network object
                uint uniqueID = reader.ReadUInt32();

                // Remove this object
                if (player.channel.DestroyObject(uniqueID))
                {
                    // Inform all players in the channel that the object should be destroyed
                    BinaryWriter writer = BeginSend(Packet.ResponseDestroy);
                    writer.Write((ushort)1);
                    writer.Write(uniqueID);
                    EndSend(true, player.channel, null);
                }
                break;
            }

            case Packet.RequestLoadLevel:
            {
                // Change the currently loaded level
                if (player.channel.host == player)
                {
                    player.channel.Reset();
                    player.channel.level = reader.ReadString();

                    BinaryWriter writer = BeginSend(Packet.ResponseLoadLevel);
                    writer.Write(string.IsNullOrEmpty(player.channel.level) ? "" : player.channel.level);
                    EndSend(true, player.channel, null);
                }
                break;
            }

            case Packet.RequestSetHost:
            {
                // Transfer the host state from one player to another
                if (player.channel.host == player)
                {
                    TcpPlayer newHost = GetPlayer(reader.ReadInt32());
                    if (newHost != null && newHost.channel == player.channel)
                    {
                        SendSetHost(newHost);
                    }
                }
                break;
            }

            case Packet.RequestLeaveChannel:
            {
                SendLeaveChannel(player, true);
                break;
            }

            case Packet.RequestCloseChannel:
            {
                player.channel.persistent = false;
                player.channel.closed     = true;
                break;
            }

            case Packet.RequestSetPlayerLimit:
            {
                player.channel.playerLimit = reader.ReadUInt16();
                break;
            }

            case Packet.RequestRemoveRFC:
            {
                uint   id       = reader.ReadUInt32();
                string funcName = ((id & 0xFF) == 0) ? reader.ReadString() : null;
                player.channel.DeleteRFC(id, funcName);
                break;
            }

            case Packet.RequestSetChannelData:
            {
                player.channel.data = reader.ReadString();
                BinaryWriter writer = BeginSend(Packet.ResponseSetChannelData);
                writer.Write(player.channel.data);
                EndSend(true, player.channel, null);
                break;
            }
            }
        }
예제 #28
0
        /// <summary>
        /// Process a packet that's meant to be forwarded.
        /// </summary>

        void ProcessForwardPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request, bool reliable)
        {
            // We can't send unreliable packets if UDP is not active
            if (!mUdp.isActive || buffer.size > 1024)
            {
                reliable = true;
            }

            switch (request)
            {
            case Packet.ForwardToHost:
            {
                // Reset the position back to the beginning (4 bytes for size, 1 byte for ID)
                buffer.position = buffer.position - 5;

                // Forward the packet to the channel's host
                if (reliable || player.channel.host.udpEndPoint == null || !mAllowUdp)
                {
                    player.channel.host.SendTcpPacket(buffer);
                }
                else
                {
                    mUdp.Send(buffer, player.channel.host.udpEndPoint);
                }
                break;
            }

            case Packet.ForwardToPlayerBuffered:
            {
                // 4 bytes for size, 1 byte for ID
                int origin = buffer.position - 5;

                // Figure out who the intended recipient is
                TcpPlayer targetPlayer = GetPlayer(reader.ReadInt32());

                // Save this function call
                uint   target   = reader.ReadUInt32();
                string funcName = ((target & 0xFF) == 0) ? reader.ReadString() : null;
                buffer.position = origin;
                player.channel.CreateRFC(target, funcName, buffer);

                // Forward the packet to the target player
                if (targetPlayer != null && targetPlayer.isConnected)
                {
                    if (reliable || targetPlayer.udpEndPoint == null || !mAllowUdp)
                    {
                        targetPlayer.SendTcpPacket(buffer);
                    }
                    else
                    {
                        mUdp.Send(buffer, targetPlayer.udpEndPoint);
                    }
                }
                break;
            }

            default:
            {
                // We want to exclude the player if the request was to forward to others
                TcpPlayer exclude = (
                    request == Packet.ForwardToOthers ||
                    request == Packet.ForwardToOthersSaved) ? player : null;

                // 4 bytes for size, 1 byte for ID
                int origin = buffer.position - 5;

                // If the request should be saved, let's do so
                if (request == Packet.ForwardToAllSaved || request == Packet.ForwardToOthersSaved)
                {
                    uint   target   = reader.ReadUInt32();
                    string funcName = ((target & 0xFF) == 0) ? reader.ReadString() : null;
                    buffer.position = origin;
                    player.channel.CreateRFC(target, funcName, buffer);
                }
                else
                {
                    buffer.position = origin;
                }

                // Forward the packet to everyone except the sender
                for (int i = 0; i < player.channel.players.size; ++i)
                {
                    TcpPlayer tp = player.channel.players[i];

                    if (tp != exclude)
                    {
                        if (reliable || tp.udpEndPoint == null || !mAllowUdp)
                        {
                            tp.SendTcpPacket(buffer);
                        }
                        else
                        {
                            mUdp.Send(buffer, tp.udpEndPoint);
                        }
                    }
                }
                break;
            }
            }
        }
예제 #29
0
        /// <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);
        }
예제 #30
0
        /// <summary>
        /// Channel joining process involves multiple steps. It's faster to perform them all at once.
        /// </summary>

        public void FinishJoiningChannel()
        {
            Buffer buffer = Buffer.Create();

            // Step 2: Tell the player who else is in the channel
            BinaryWriter writer = buffer.BeginPacket(Packet.ResponseJoiningChannel);
            {
                writer.Write(channel.id);
                writer.Write((short)channel.players.size);

                for (int i = 0; i < channel.players.size; ++i)
                {
                    TcpPlayer tp = channel.players[i];
                    writer.Write(tp.id);
                    writer.Write(string.IsNullOrEmpty(tp.name) ? "Guest" : tp.name);
                }
            }

            // End the first packet, but remember where it ended
            int offset = buffer.EndPacket();

            // Step 3: Inform the player of who is hosting
            if (channel.host == null)
            {
                channel.host = this;
            }
            buffer.BeginPacket(Packet.ResponseSetHost, offset);
            writer.Write(channel.host.id);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Step 4: Send the channel's data
            if (!string.IsNullOrEmpty(channel.data))
            {
                buffer.BeginPacket(Packet.ResponseSetChannelData, offset);
                writer.Write(channel.data);
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 5: Inform the player of what level we're on
            buffer.BeginPacket(Packet.ResponseLoadLevel, offset);
            writer.Write(string.IsNullOrEmpty(channel.level) ? "" : channel.level);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Step 6: Send the list of objects that have been created
            for (int i = 0; i < channel.created.size; ++i)
            {
                Channel.CreatedObject obj = channel.created.buffer[i];
                buffer.BeginPacket(Packet.ResponseCreate, offset);
                writer.Write(obj.playerID);
                writer.Write(obj.objectID);
                writer.Write(obj.uniqueID);
                writer.Write(obj.buffer.buffer, obj.buffer.position, obj.buffer.size);
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 7: Send the list of objects that have been destroyed
            if (channel.destroyed.size != 0)
            {
                buffer.BeginPacket(Packet.ResponseDestroy, offset);
                writer.Write((ushort)channel.destroyed.size);
                for (int i = 0; i < channel.destroyed.size; ++i)
                {
                    writer.Write(channel.destroyed.buffer[i]);
                }
                offset = buffer.EndTcpPacketStartingAt(offset);
            }

            // Step 8: Send all buffered RFCs to the new player
            for (int i = 0; i < channel.rfcs.size; ++i)
            {
                Buffer rfcBuff = channel.rfcs[i].buffer;
                rfcBuff.BeginReading();
                buffer.BeginWriting(offset);
                writer.Write(rfcBuff.buffer, rfcBuff.position, rfcBuff.size);
                offset = buffer.EndWriting();
            }

            // Step 9: The join process is now complete
            buffer.BeginPacket(Packet.ResponseJoinChannel, offset);
            writer.Write(true);
            offset = buffer.EndTcpPacketStartingAt(offset);

            // Send the entire buffer
            SendTcpPacket(buffer);
            buffer.Recycle();
        }
예제 #31
0
        /// <summary>
        /// Remove the specified player.
        /// </summary>
        void RemovePlayer(TcpPlayer p)
        {
            if (p != null)
            {
            SendLeaveChannel(p, false);
            #if STANDALONE
            Console.WriteLine(p.address + " has disconnected");
            #endif
            p.Release();
            mPlayers.Remove(p);

            if (p.udpEndPoint != null)
            {
                mDictionaryEP.Remove(p.udpEndPoint);
                p.udpEndPoint = null;
            }

            if (p.id != 0)
            {
                if (mDictionaryID.Remove(p.id))
                {
                    if (lobbyLink != null) lobbyLink.SendUpdate(this);
                    if (onPlayerDisconnect != null) onPlayerDisconnect(p);
                }
                p.id = 0;
            }
            }
        }
예제 #32
0
        /// <summary>
        /// Send the outgoing buffer to all players in the specified channel.
        /// </summary>
        void EndSend(bool reliable, Channel channel, TcpPlayer exclude)
        {
            mBuffer.EndPacket();
            if (mBuffer.size > 1024) reliable = true;

            for (int i = 0; i < channel.players.size; ++i)
            {
            TcpPlayer player = channel.players[i];

            if (player.stage == TcpProtocol.Stage.Connected && player != exclude)
            {
                if (reliable || player.udpEndPoint == null || !mAllowUdp)
                {
                    player.SendTcpPacket(mBuffer);
                }
                else mUdp.Send(mBuffer, player.udpEndPoint);
            }
            }

            mBuffer.Recycle();
            mBuffer = null;
        }
예제 #33
0
 /// <summary>
 /// Have the specified player assume control of the channel.
 /// </summary>
 void SendSetHost(TcpPlayer player)
 {
     if (player.channel != null && player.channel.host != player)
     {
     player.channel.host = player;
     BinaryWriter writer = BeginSend(Packet.ResponseSetHost);
     writer.Write(player.id);
     EndSend(true, player.channel, null);
     }
 }
예제 #34
0
        /// <summary>
        /// Process a packet that's meant to be forwarded.
        /// </summary>
        void ProcessForwardPacket(TcpPlayer player, Buffer buffer, BinaryReader reader, Packet request, bool reliable)
        {
            // We can't send unreliable packets if UDP is not active
            if (!mUdp.isActive || buffer.size > 1024) reliable = true;

            switch (request)
            {
            case Packet.ForwardToHost:
            {
                // Reset the position back to the beginning (4 bytes for size, 1 byte for ID)
                buffer.position = buffer.position - 5;

                // Forward the packet to the channel's host
                if (reliable || player.channel.host.udpEndPoint == null || !mAllowUdp)
                {
                    player.channel.host.SendTcpPacket(buffer);
                }
                else mUdp.Send(buffer, player.channel.host.udpEndPoint);
                break;
            }
            case Packet.ForwardToPlayerBuffered:
            {
                // 4 bytes for size, 1 byte for ID
                int origin = buffer.position - 5;

                // Figure out who the intended recipient is
                TcpPlayer targetPlayer = GetPlayer(reader.ReadInt32());

                // Save this function call
                uint target = reader.ReadUInt32();
                string funcName = ((target & 0xFF) == 0) ? reader.ReadString() : null;
                buffer.position = origin;
                player.channel.CreateRFC(target, funcName, buffer);

                // Forward the packet to the target player
                if (targetPlayer != null && targetPlayer.isConnected)
                {
                    if (reliable || targetPlayer.udpEndPoint == null || !mAllowUdp)
                    {
                        targetPlayer.SendTcpPacket(buffer);
                    }
                    else mUdp.Send(buffer, targetPlayer.udpEndPoint);
                }
                break;
            }
            default:
            {
                // We want to exclude the player if the request was to forward to others
                TcpPlayer exclude = (
                    request == Packet.ForwardToOthers ||
                    request == Packet.ForwardToOthersSaved) ? player : null;

                // 4 bytes for size, 1 byte for ID
                int origin = buffer.position - 5;

                // If the request should be saved, let's do so
                if (request == Packet.ForwardToAllSaved || request == Packet.ForwardToOthersSaved)
                {
                    uint target = reader.ReadUInt32();
                    string funcName = ((target & 0xFF) == 0) ? reader.ReadString() : null;
                    buffer.position = origin;
                    player.channel.CreateRFC(target, funcName, buffer);
                }
                else buffer.position = origin;

                // Forward the packet to everyone except the sender
                for (int i = 0; i < player.channel.players.size; ++i)
                {
                    TcpPlayer tp = player.channel.players[i];

                    if (tp != exclude)
                    {
                        if (reliable || tp.udpEndPoint == null || !mAllowUdp)
                        {
                            tp.SendTcpPacket(buffer);
                        }
                        else mUdp.Send(buffer, tp.udpEndPoint);
                    }
                }
                break;
            }
            }
        }
예제 #35
0
 internal void NotifyPlayerConnect(TcpPlayer player)
 {
     var id = player.id.ToString();
     NotifyPlayerJoin(id, player.name);
     livePlayers[id] = new NomadLivePlayer(player);
 }
예제 #36
0
        /// <summary>
        /// Send the outgoing buffer to the specified player.
        /// </summary>
        void EndSend(bool reliable, TcpPlayer player)
        {
            mBuffer.EndPacket();
            if (mBuffer.size > 1024) reliable = true;

            if (reliable || player.udpEndPoint == null || !mAllowUdp)
            {
            player.SendTcpPacket(mBuffer);
            }
            else mUdp.Send(mBuffer, player.udpEndPoint);

            mBuffer.Recycle();
            mBuffer = null;
        }