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); }
/// <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); }
/// <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); }
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); } }
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); }
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); }
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)); }
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); }
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 }
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); }
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(); } } }
// 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); }
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); }