Ejemplo n.º 1
0
        protected void SendEventInternal(Type invokeClass, string eventName, NetworkWriter writer, int channelId)
        {
            if (!NetworkServer.active)
            {
                Debug.LogWarning("SendEvent no server?");
                return;
            }

            // construct the message
            SyncEventMessage message = new SyncEventMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, eventName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()                // segment to avoid reader allocations
            };

            NetworkServer.SendToReady(netIdentity, message, channelId);
        }
Ejemplo n.º 2
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();

            // 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);
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
0
        protected void SendTargetRPCInternal(NetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            if (!NetworkServer.active)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on client.");
                return;
            }
            // connection parameter is optional. assign if null.
            if (conn == null)
            {
                conn = connectionToClient;
            }
            // this was in Weaver before
            if (conn is NetworkConnectionToServer)
            {
                Debug.LogError("TargetRPC Function " + rpcName + " called on connection to server");
                return;
            }
            // This cannot use NetworkServer.active, as that is not specific to this object.
            if (!isServer)
            {
                Debug.LogWarning("TargetRpc " + rpcName + " called on un-spawned object: " + name);
                return;
            }

            // construct the message
            RpcMessage message = new RpcMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                // type+func so Inventory.RpcUse != Equipment.RpcUse
                functionHash = GetMethodHash(invokeClass, rpcName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            if (conn != null)
            {
                conn.Send(message, channelId);
            }
        }
Ejemplo n.º 5
0
        void FixedUpdate()
        {
            if (!sendMessagesAllowed)
            {
                return;
            }

            CheckSendRate();

            if (!CheckAnimStateChanged(out int stateHash, out float normalizedTime))
            {
                return;
            }

            NetworkWriter writer = NetworkWriterPool.GetPooledWriter();

            WriteParameters(writer);

            SendAnimationMessage(stateHash, normalizedTime, writer.ToArraySegment());
            NetworkWriterPool.Recycle(writer);
        }
Ejemplo n.º 6
0
        protected internal UniTask <T> SendServerRpcWithReturn <T>(Type invokeClass, string cmdName, NetworkWriter writer, int channelId, bool requireAuthority = true)
        {
            ValidateServerRpc(invokeClass, cmdName, requireAuthority);

            (UniTask <T> task, int id) = ClientObjectManager.CreateReplyTask <T>();

            // construct the message
            var message = new ServerRpcMessage
            {
                netId          = NetId,
                componentIndex = ComponentIndex,
                replyId        = id,
                // type+func so Inventory.RpcUse != Equipment.RpcUse
                functionHash = RemoteCallHelper.GetMethodHash(invokeClass, cmdName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            Client.SendAsync(message, channelId).Forget();

            return(task);
        }
Ejemplo n.º 7
0
        protected void SendEventInternal(Type invokeClass, string eventName, NetworkWriter writer, int channelId)
        {
            if (!NetworkServer.active)
            {
                Debug.LogWarning("SendEvent no server?");
                return;
            }

            // construct the message
            SyncEventMessage message = new SyncEventMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, eventName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()                // segment to avoid reader allocations
            };

            NetworkServer.SendToReady(netIdentity, message, channelId);
#if MIRROR_PROFILING
            NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(SyncEventMessage), $"{invokeClass.GetType()}.{eventName}", 1);
#endif
        }
        internal virtual bool SendWriter(NetworkWriter writer, int channelId = Channels.DefaultReliable)
        {
            if (logNetworkMessages)
            {
                ArraySegment <byte> data = writer.ToArraySegment();
                Debug.Log("ConnectionSend con:" + connectionId + " bytes:" + BitConverter.ToString(data.Array, data.Offset, data.Count));
            }

            if (writer.Position > Transport.activeTransport.GetMaxPacketSize(channelId))
            {
                Debug.LogError("NetworkConnection.SendBytes cannot send packet larger than " + Transport.activeTransport.GetMaxPacketSize(channelId) + " bytes");
                return(false);
            }

            if (writer.Position == 0)
            {
                // zero length packets getting into the packet queues are bad.
                Debug.LogError("NetworkConnection.SendBytes cannot send zero bytes");
                return(false);
            }

            return(TransportSend(channelId, writer));
        }
Ejemplo n.º 9
0
        protected internal void SendTargetRpcInternal(INetworkConnection conn, Type invokeClass, string rpcName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            if (!Server || !Server.Active)
            {
                throw new InvalidOperationException("RPC Function " + rpcName + " called on client.");
            }

            // connection parameter is optional. assign if null.
            if (conn == null)
            {
                conn = ConnectionToClient;
            }

            // This cannot use Server.active, as that is not specific to this object.
            if (!IsServer)
            {
                if (logger.WarnEnabled())
                {
                    logger.LogWarning("ClientRpc " + rpcName + " called on un-spawned object: " + name);
                }
                return;
            }

            // construct the message
            var message = new RpcMessage
            {
                netId          = NetId,
                componentIndex = ComponentIndex,
                // type+func so Inventory.RpcUse != Equipment.RpcUse
                functionHash = RemoteCallHelper.GetMethodHash(invokeClass, rpcName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            conn.Send(message, channelId);
        }
Ejemplo n.º 10
0
        protected void SendCommandInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId)
        {
            // this was in Weaver before
            // NOTE: we could remove this later to allow calling Cmds on Server
            //       to avoid Wrapper functions. a lot of people requested this.
            if (!NetworkClient.active)
            {
                Debug.LogError("Command Function " + cmdName + " called on server without an active client.");
                return;
            }
            // local players can always send commands, regardless of authority, other objects must have authority.
            if (!(isLocalPlayer || hasAuthority))
            {
                Debug.LogWarning("Trying to send command for object without authority.");
                return;
            }

            if (ClientScene.readyConnection == null)
            {
                Debug.LogError("Send command attempted with no client running [client=" + connectionToServer + "].");
                return;
            }

            // construct the message
            CommandMessage message = new CommandMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                functionHash   = GetMethodHash(invokeClass, cmdName), // type+func so Inventory.RpcUse != Equipment.RpcUse
                payload        = writer.ToArraySegment()              // segment to avoid reader allocations
            };

            ClientScene.readyConnection.Send(message, channelId);
#if MIRROR_PROFILING
            NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(CommandMessage), $"{invokeClass.GetType()}.{cmdName}", 1);
#endif
        }
Ejemplo n.º 11
0
        protected void SendCommandInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId, bool ignoreAuthority = false)
        {
            // this was in Weaver before
            // NOTE: we could remove this later to allow calling Cmds on Server
            //       to avoid Wrapper functions. a lot of people requested this.
            if (!NetworkClient.active)
            {
                logger.LogError($"Command Function {cmdName} called without an active client.");
                return;
            }
            // local players can always send commands, regardless of authority, other objects must have authority.
            if (!(ignoreAuthority || isLocalPlayer || hasAuthority))
            {
                logger.LogWarning($"Trying to send command for object without authority. {invokeClass.ToString()}.{cmdName}");
                return;
            }

            if (ClientScene.readyConnection == null)
            {
                logger.LogError("Send command attempted with no client running [client=" + connectionToServer + "].");
                return;
            }

            // construct the message
            CommandMessage message = new CommandMessage
            {
                netId          = netId,
                componentIndex = ComponentIndex,
                // type+func so Inventory.RpcUse != Equipment.RpcUse
                functionHash = RemoteCallHelper.GetMethodHash(invokeClass, cmdName),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            ClientScene.readyConnection.Send(message, channelId);
        }
Ejemplo n.º 12
0
 internal static void Update()
 {
     // local or remote connection?
     if (isLocalClient)
     {
         // process internal messages so they are applied at the correct time
         while (localClientPacketQueue.Count > 0)
         {
             NetworkWriter writer = localClientPacketQueue.Dequeue();
             // TODO avoid serializing and deserializng the message
             // just pass it as is
             OnDataReceived(writer.ToArraySegment(), Channels.DefaultReliable);
             NetworkWriterPool.Recycle(writer);
         }
     }
     else
     {
         // only update things while connected
         if (active && connectState == ConnectState.Connected)
         {
             NetworkTime.UpdateClient();
         }
     }
 }
Ejemplo n.º 13
0
        // pass full function name to avoid ClassA.Func <-> ClassB.Func collisions
        protected void SendCommandInternal(string functionFullName, NetworkWriter writer, int channelId, bool requiresAuthority = true)
        {
            // this was in Weaver before
            // NOTE: we could remove this later to allow calling Cmds on Server
            //       to avoid Wrapper functions. a lot of people requested this.
            if (!NetworkClient.active)
            {
                Debug.LogError($"Command Function {functionFullName} called without an active client.");
                return;
            }

            // previously we used NetworkClient.readyConnection.
            // now we check .ready separately.
            if (!NetworkClient.ready)
            {
                // Unreliable Cmds from NetworkTransform may be generated,
                // or client may have been set NotReady intentionally, so
                // only warn if on the reliable channel.
                if (channelId == Channels.Reliable)
                {
                    Debug.LogWarning("Send command attempted while NetworkClient is not ready.\nThis may be ignored if client intentionally set NotReady.");
                }
                return;
            }

            // local players can always send commands, regardless of authority, other objects must have authority.
            if (!(!requiresAuthority || isLocalPlayer || hasAuthority))
            {
                Debug.LogWarning($"Trying to send command for object without authority. {functionFullName}");
                return;
            }

            // IMPORTANT: can't use .connectionToServer here because calling
            // a command on other objects is allowed if requireAuthority is
            // false. other objects don't have a .connectionToServer.
            // => so we always need to use NetworkClient.connection instead.
            // => see also: https://github.com/vis2k/Mirror/issues/2629
            if (NetworkClient.connection == null)
            {
                Debug.LogError("Send command attempted with no client running.");
                return;
            }

            // construct the message
            CommandMessage message = new CommandMessage
            {
                netId          = netId,
                componentIndex = (byte)ComponentIndex,
                // type+func so Inventory.RpcUse != Equipment.RpcUse
                functionHash = functionFullName.GetStableHashCode(),
                // segment to avoid reader allocations
                payload = writer.ToArraySegment()
            };

            // IMPORTANT: can't use .connectionToServer here because calling
            // a command on other objects is allowed if requireAuthority is
            // false. other objects don't have a .connectionToServer.
            // => so we always need to use NetworkClient.connection instead.
            // => see also: https://github.com/vis2k/Mirror/issues/2629
            NetworkClient.connection.Send(message, channelId);
        }
Ejemplo n.º 14
0
        internal static void SendSpawnMessage(NetworkIdentity identity, NetworkConnection conn)
        {
            if (identity.serverOnly)
            {
                return;
            }

            if (LogFilter.Debug)
            {
                Debug.Log("Server SendSpawnMessage: name=" + identity.name + " sceneId=" + identity.sceneId.ToString("X") + " netid=" + identity.netId);                  // for easier debugging
            }
            NetworkWriter writer = NetworkWriterPool.GetWriter();



            // convert to ArraySegment to avoid reader allocations
            // (need to handle null case too)
            ArraySegment <byte> segment = default;

            // serialize all components with initialState = true
            // (can be null if has none)
            if (identity.OnSerializeAllSafely(true, writer))
            {
                segment = writer.ToArraySegment();
            }

            // 'identity' is a prefab that should be spawned
            if (identity.sceneId == 0)
            {
                SpawnPrefabMessage msg = new SpawnPrefabMessage
                {
                    netId   = identity.netId,
                    owner   = conn?.playerController == identity,
                    assetId = identity.assetId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale,
                    payload  = segment
                };

                // conn is != null when spawning it for a client
                if (conn != null)
                {
                    conn.Send(msg);
                }
                // conn is == null when spawning it for the local player
                else
                {
                    SendToReady(identity, msg);
                }
            }
            // 'identity' is a scene object that should be spawned again
            else
            {
                SpawnSceneObjectMessage msg = new SpawnSceneObjectMessage
                {
                    netId   = identity.netId,
                    owner   = conn?.playerController == identity,
                    sceneId = identity.sceneId,
                    // use local values for VR support
                    position = identity.transform.localPosition,
                    rotation = identity.transform.localRotation,
                    scale    = identity.transform.localScale,
                    payload  = segment
                };

                // conn is != null when spawning it for a client
                if (conn != null)
                {
                    conn.Send(msg);
                }
                // conn is == null when spawning it for the local player
                else
                {
                    SendToReady(identity, msg);
                }
            }

            NetworkWriterPool.Recycle(writer);
        }