protected void SendServerRpcInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId, bool requireAuthority = 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 (!Client.Active) { throw new InvalidOperationException($"ServerRpc Function {cmdName} called on server without an active client."); } // local players can always send ServerRpcs, regardless of authority, other objects must have authority. if (requireAuthority && !(IsLocalPlayer || HasAuthority)) { throw new UnauthorizedAccessException($"Trying to send ServerRpc for object without authority. {invokeClass.ToString()}.{cmdName}"); } if (Client.Connection == null) { throw new InvalidOperationException("Send ServerRpc attempted with no client running [client=" + ConnectionToServer + "]."); } // construct the message var message = new ServerRpcMessage { netId = NetId, componentIndex = ComponentIndex, // type+func so Inventory.RpcUse != Equipment.RpcUse functionHash = RemoteCallHelper.GetMethodHash(invokeClass, cmdName), // segment to avoid reader allocations payload = writer.ToArraySegment() }; _ = Client.SendAsync(message, channelId); }
/// <summary> /// Handle ServerRpc from specific player, this could be one of multiple players on a single client /// </summary> /// <param name="conn"></param> /// <param name="msg"></param> void OnServerRpcMessage(INetworkConnection conn, ServerRpcMessage msg) { if (!Spawned.TryGetValue(msg.netId, out NetworkIdentity identity) || identity == null) { logger.LogWarning("Spawned object not found when handling ServerRpc message [netId=" + msg.netId + "]"); return; } ServerRpcInfo ServerRpcInfo = identity.GetServerRpcInfo(msg.componentIndex, msg.functionHash); // ServerRpcs can be for player objects, OR other objects with client-authority // -> so if this connection's controller has a different netId then // only allow the ServerRpc if clientAuthorityOwner if (ServerRpcInfo.requireAuthority && identity.ConnectionToClient != conn) { logger.LogWarning("ServerRpc for object without authority [netId=" + msg.netId + "]"); return; } if (logger.LogEnabled()) { logger.Log("OnServerRpcMessage for netId=" + msg.netId + " conn=" + conn); } using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload)) identity.HandleRemoteCall(msg.componentIndex, msg.functionHash, MirrorInvokeType.ServerRpc, networkReader, conn); }
protected internal void SendServerRpcInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId, bool requireAuthority = true) { ValidateServerRpc(invokeClass, cmdName, requireAuthority); // construct the message var message = new ServerRpcMessage { netId = NetId, componentIndex = ComponentIndex, // 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(); }
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); }
/// <summary> /// Handle ServerRpc from specific player, this could be one of multiple players on a single client /// </summary> /// <param name="conn"></param> /// <param name="msg"></param> void OnServerRpcMessage(INetworkConnection conn, ServerRpcMessage msg) { if (!server.Spawned.TryGetValue(msg.netId, out NetworkIdentity identity) || identity is null) { if (logger.WarnEnabled()) { logger.LogWarning("Spawned object not found when handling ServerRpc message [netId=" + msg.netId + "]"); } return; } Skeleton skeleton = RemoteCallHelper.GetSkeleton(msg.functionHash); if (skeleton.invokeType != MirrorInvokeType.ServerRpc) { throw new MethodInvocationException($"Invalid ServerRpc for id {msg.functionHash}"); } // ServerRpcs can be for player objects, OR other objects with client-authority // -> so if this connection's controller has a different netId then // only allow the ServerRpc if clientAuthorityOwner if (skeleton.cmdRequireAuthority && identity.ConnectionToClient != conn) { if (logger.WarnEnabled()) { logger.LogWarning("ServerRpc for object without authority [netId=" + msg.netId + "]"); } return; } if (logger.LogEnabled()) { logger.Log("OnServerRpcMessage for netId=" + msg.netId + " conn=" + conn); } using (PooledNetworkReader networkReader = NetworkReaderPool.GetReader(msg.payload)) identity.HandleRemoteCall(skeleton, msg.componentIndex, networkReader, conn, msg.replyId); }