public static void Send <T>(IEnumerable <NetworkConnection> connections, T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
            {
                // pack message into byte[] once
                MessagePacker.Pack(msg, writer);
                var segment = writer.ToArraySegment();
                int count   = 0;

                foreach (NetworkConnection conn in connections)
                {
                    // send to all connections, but don't wait for them
                    _ = conn.SendAsync(segment);
                    count++;
                }

                NetworkDiagnostics.OnSend(msg, channelId, segment.Count, count);
            }
        }
Example #2
0
        public static bool SendToAll(int msgType, MessageBase msg, int channelId = Channels.DefaultReliable)
        {
            if (LogFilter.Debug)
            {
                Debug.Log("Server.SendToAll id:" + msgType);
            }

            // pack message into byte[] once
            byte[] bytes = MessagePacker.PackMessage((ushort)msgType, msg);

            // send to all
            bool result = true;

            foreach (KeyValuePair <int, NetworkConnection> kvp in connections)
            {
                result &= kvp.Value.SendBytes(bytes, channelId);
            }
            return(result);
        }
Example #3
0
        // note: original HLAPI HandleBytes function handled >1 message in a while loop, but this wasn't necessary
        //       anymore because NetworkServer/NetworkClient Update both use while loops to handle >1 data events per
        //       frame already.
        //       -> in other words, we always receive 1 message per Receive call, never two.
        //       -> can be tested easily with a 1000ms send delay and then logging amount received in while loops here
        //          and in NetworkServer/Client Update. HandleBytes already takes exactly one.
        /// <summary>
        /// This function allows custom network connection classes to process data from the network before it is passed to the application.
        /// </summary>
        /// <param name="buffer">The data received.</param>
        internal void TransportReceive(ArraySegment <byte> buffer, int channelId)
        {
            // unpack message
            using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(buffer))
            {
                try
                {
                    int msgType = MessagePacker.UnpackId(networkReader);

                    // try to invoke the handler for that message
                    InvokeHandler(msgType, networkReader, channelId);
                }
                catch (Exception ex)
                {
                    Debug.LogError("Closed connection: " + this + ". Invalid message " + ex);
                    Disconnect();
                }
            }
        }
 internal void InvokeHandler(int msgType, NetworkReader reader, int channelId)
 {
     if (messageHandlers.TryGetValue(msgType, out NetworkMessageDelegate msgDelegate))
     {
         msgDelegate(this, reader, channelId);
     }
     else
     {
         try
         {
             Type type = MessagePacker.GetMessageType(msgType);
             throw new InvalidDataException($"Unexpected message {type} received in {this}. Did you register a handler for it?");
         }
         catch (KeyNotFoundException)
         {
             throw new InvalidDataException($"Unexpected message ID {msgType} received in {this}. May be due to no existing RegisterHandler for this message.");
         }
     }
 }
Example #5
0
        /* TODO use or remove
        static void GenerateDataError(NetworkConnection conn, byte error)
        {
            NetworkError dataError = (NetworkError)error;
            Debug.LogError("Mirror Server Data Error: " + dataError);
            GenerateError(conn, error);
        }

        static void GenerateDisconnectError(NetworkConnection conn, byte error)
        {
            NetworkError disconnectError = (NetworkError)error;
            Debug.LogError("Mirror Server Disconnect Error: " + disconnectError + " conn:[" + conn + "]:" + conn.connectionId);
            GenerateError(conn, error);
        }
        */

        static void GenerateError(NetworkConnection conn, byte error)
        {
            int msgId = MessagePacker.GetId<ErrorMessage>();
            if (handlers.ContainsKey(msgId))
            {
                ErrorMessage msg = new ErrorMessage
                {
                    value = error
                };

                // write the message to a local buffer
                NetworkWriter writer = new NetworkWriter();
                msg.Serialize(writer);

                // pass a reader (attached to local buffer) to handler
                NetworkReader reader = new NetworkReader(writer.ToArray());
                conn.InvokeHandler(msgId, reader);
            }
        }
Example #6
0
        static bool SendToObservers(NetworkIdentity identity, short msgType, MessageBase msg)
        {
            if (LogFilter.Debug) Debug.Log("Server.SendToObservers id:" + msgType);

            if (identity != null && identity.observers != null)
            {
                // pack message into byte[] once
                byte[] bytes = MessagePacker.PackMessage((ushort)msgType, msg);

                // send to all observers
                bool result = true;
                foreach (KeyValuePair<int, NetworkConnection> kvp in identity.observers)
                {
                    result &= kvp.Value.SendBytes(bytes);
                }
                return result;
            }
            return false;
        }
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // pack and invoke
            int msgType = MessagePacker.GetId(msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment = writer.ToArraySegment();
            NetworkReader       reader  = NetworkReaderPool.GetReader(segment);
            bool result = InvokeHandler(msgType, reader, channelId);

            NetworkReaderPool.Recycle(reader);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
Example #8
0
        /// <summary>
        /// This function invokes the registered handler function for a message.
        /// <para>Network connections used by the NetworkClient and NetworkServer use this function for handling network messages.</para>
        /// </summary>
        /// <typeparam name="T">The message type to unregister.</typeparam>
        /// <param name="msg">The message object to process.</param>
        /// <returns></returns>
        public bool InvokeHandler <T>(T msg, int channelId) where T : IMessageBase
        {
            // get writer from pool
            NetworkWriter writer = NetworkWriterPool.GetWriter();

            // if it is a value type,  just use typeof(T) to avoid boxing
            // this works because value types cannot be derived
            // if it is a reference type (for example IMessageBase),
            // ask the message for the real type
            int msgType = MessagePacker.GetId(typeof(T).IsValueType ? typeof(T) : msg.GetType());

            MessagePacker.Pack(msg, writer);
            ArraySegment <byte> segment = writer.ToArraySegment();
            bool result = InvokeHandler(msgType, new NetworkReader(segment), channelId);

            // recycle writer and return
            NetworkWriterPool.Recycle(writer);
            return(result);
        }
Example #9
0
        public static bool SendToAll <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            if (LogFilter.Debug)
            {
                Debug.Log("Server.SendToAll id:" + typeof(T));
            }

            // pack message into byte[] once
            NetworkWriter bytes = MessagePacker.PackWriter(msg);

            bytes.recycleCount = (ushort)connections.Count;

            bool result = true;

            foreach (KeyValuePair <int, NetworkConnection> kvp in connections)
            {
                result &= kvp.Value.SendWriter(bytes, channelId);
            }
            return(result);
        }
Example #10
0
        // this is like SendToReady - but it doesn't check the ready flag on the connection.
        // this is used for ObjectDestroy messages.
        static bool SendToObservers <T>(NetworkIdentity identity, T msg) where T : IMessageBase
        {
            if (LogFilter.Debug)
            {
                Debug.Log("Server.SendToObservers id:" + typeof(T));
            }

            if (identity != null && identity.observers != null)
            {
                // pack message into byte[] once
                byte[] bytes = MessagePacker.Pack(msg);

                bool result = true;
                foreach (KeyValuePair <int, NetworkConnection> kvp in identity.observers)
                {
                    result &= kvp.Value.SendBytes(bytes);
                }
                return(result);
            }
            return(false);
        }
Example #11
0
        public static bool SendToReady<T>(NetworkIdentity identity,T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
        {
            if (LogFilter.Debug) Debug.Log("Server.SendToReady msgType:" + typeof(T));

            if (identity != null && identity.observers != null)
            {
                // pack message into byte[] once
                byte[] bytes = MessagePacker.Pack(msg);

                bool result = true;
                foreach (KeyValuePair<int, NetworkConnection> kvp in identity.observers)
                {
                    if (kvp.Value.isReady)
                    {
                        result &= kvp.Value.SendBytes(bytes, channelId);
                    }
                }
                return result;
            }
            return false;
        }
Example #12
0
        public static bool SendToReady(NetworkIdentity identity, short msgType, MessageBase msg, int channelId = Channels.DefaultReliable)
        {
            if (LogFilter.Debug) Debug.Log("Server.SendToReady msgType:" + msgType);

            if (identity != null && identity.observers != null)
            {
                // pack message into byte[] once
                byte[] bytes = MessagePacker.PackMessage((ushort)msgType, msg);

                // send to all ready observers
                bool result = true;
                foreach (KeyValuePair<int, NetworkConnection> kvp in identity.observers)
                {
                    if (kvp.Value.isReady)
                    {
                        result &= kvp.Value.SendBytes(bytes, channelId);
                    }
                }
                return result;
            }
            return false;
        }
        // handle this message
        // note: original HLAPI HandleBytes function handled >1 message in a while loop, but this wasn't necessary
        //       anymore because NetworkServer/NetworkClient.Update both use while loops to handle >1 data events per
        //       frame already.
        //       -> in other words, we always receive 1 message per Receive call, never two.
        //       -> can be tested easily with a 1000ms send delay and then logging amount received in while loops here
        //          and in NetworkServer/Client Update. HandleBytes already takes exactly one.
        public virtual void TransportReceive(byte[] buffer)
        {
            // unpack message
            NetworkReader reader = new NetworkReader(buffer);

            if (!MessagePacker.UnpackMessage(reader, out int msgType))
            {
                Debug.LogError("Closed connection: " + connectionId + ". Invalid message header.");
                Disconnect();
            }

            if (logNetworkMessages)
            {
                Debug.Log("ConnectionRecv con:" + connectionId + " msgType:" + msgType + " content:" + BitConverter.ToString(buffer));
            }

            // try to invoke the handler for that message
            if (InvokeHandler(msgType, reader))
            {
                lastMessageTime = Time.time;
            }
        }
        // connect host mode
        internal static void ConnectLocalServer()
        {
            if (LogFilter.Debug)
            {
                Debug.Log("Client Connect Local Server");
            }

            RegisterSystemHandlers(true);

            connectState = ConnectState.Connected;

            // create local connection to server
            connection = new ULocalConnectionToServer();
            connection.SetHandlers(handlers);

            // create server connection to local client
            ULocalConnectionToClient connectionToClient = new ULocalConnectionToClient();

            NetworkServer.SetLocalConnection(connectionToClient);

            localClientPacketQueue.Enqueue(new BufferHolder(MessagePacker.PackWriter(new ConnectMessage())));
        }
Example #15
0
        public virtual void TransportReceive(ArraySegment <byte> buffer)
        {
            // unpack message
            NetworkReader reader = new NetworkReader(buffer);

            if (MessagePacker.UnpackMessage(reader, out int msgType))
            {
                if (logNetworkMessages)
                {
                    Debug.Log("ConnectionRecv con:" + connectionId + " msgType:" + msgType + " content:" + BitConverter.ToString(buffer.Array, buffer.Offset, buffer.Count));
                }

                // try to invoke the handler for that message
                if (InvokeHandler(msgType, reader))
                {
                    lastMessageTime = Time.time;
                }
            }
            else
            {
                Debug.LogError("HandleBytes UnpackMessage failed for: " + BitConverter.ToString(buffer.Array, buffer.Offset, buffer.Count));
            }
        }
Example #16
0
 // helper function
 protected bool UnpackAndInvoke(NetworkReader reader, int channelId)
 {
     if (MessagePacker.Unpack(reader, out int msgType))
     {
         // try to invoke the handler for that message
         if (messageHandlers.TryGetValue(msgType, out NetworkMessageDelegate msgDelegate))
         {
             msgDelegate.Invoke(this, reader, channelId);
             lastMessageTime = Time.time;
             return(true);
         }
         else
         {
             // Debug.Log("Unknown message ID " + msgType + " " + this + ". May be due to no existing RegisterHandler for this message.");
             return(false);
         }
     }
     else
     {
         Debug.LogError("Closed connection: " + this + ". Invalid message header.");
         Disconnect();
         return(false);
     }
 }
Example #17
0
        /// <summary>
        /// Replaces a handler for a particular message type.
        /// <para>See also <see cref="RegisterHandler{T}(Action{NetworkConnection, T}, bool)">RegisterHandler(T)(Action(NetworkConnection, T), bool)</see></para>
        /// </summary>
        /// <typeparam name="T">Message type</typeparam>
        /// <param name="handler">Function handler which will be invoked when this message type is received.</param>
        /// <param name="requireAuthentication">True if the message requires an authenticated connection</param>
        public static void ReplaceHandler <T>(Action <NetworkConnection, T> handler, bool requireAuthentication = true) where T : NetworkMessage
        {
            int msgType = MessagePacker.GetId <T>();

            handlers[msgType] = MessagePacker.MessageHandler(handler, requireAuthentication);
        }
Example #18
0
        public static void UnregisterHandler <T>() where T : IMessageBase
        {
            int msgType = MessagePacker.GetId <T>();

            handlers.Remove(msgType);
        }
Example #19
0
 public virtual bool Send(int msgType, MessageBase msg, int channelId = Channels.DefaultReliable)
 {
     byte[] message = MessagePacker.PackMessage(msgType, msg);
     return(SendBytes(new ArraySegment <byte>(message), channelId));
 }
Example #20
0
 public bool Send(int msgType, MessageBase msg, int channelId = Channels.DefaultReliable)
 {
     // pack message and send
     byte[] message = MessagePacker.PackMessage(msgType, msg);
     return(Send(new ArraySegment <byte>(message), channelId));
 }
 public virtual bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
 {
     // pack message and send
     return(SendWriter(MessagePacker.PackWriter(msg), channelId));
 }
 public virtual bool Send(int msgType, MessageBase msg, int channelId = Channels.DefaultReliable)
 {
     // pack message and send
     byte[] message = MessagePacker.PackMessage(msgType, msg);
     return(SendBytes(message, channelId));
 }
Example #23
0
 /// <summary>
 /// This sends a network message with a message ID on the connection. This message is sent on channel zero, which by default is the reliable channel.
 /// </summary>
 /// <typeparam name="T">The message type to unregister.</typeparam>
 /// <param name="msg">The message to send.</param>
 /// <param name="channelId">The transport layer channel to send on.</param>
 /// <returns></returns>
 public virtual bool Send <T>(T msg, int channelId = Channels.DefaultReliable) where T : IMessageBase
 {
     // pack message and send
     byte[] message = MessagePacker.Pack(msg);
     return(SendBytes(message, channelId));
 }
        /// <summary>
        /// Unregisters a handler for a particular message type.
        /// </summary>
        /// <typeparam name="T">Message type</typeparam>
        public void UnregisterHandler <T>()
        {
            int msgType = MessagePacker.GetId <T>();

            messageHandlers.Remove(msgType);
        }