/// <summary> /// Executed in edit mode when scripts are reloaded. /// </summary> public void InitializeRPCs() { #if UNITY_EDITOR if (m_Methods == null) { m_Methods = new List <RPCMethodInfo>(); } m_Methods.Clear(); Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (!type.IsSubclassOf(typeof(NetworkBehaviour)) || !type.IsPublic || type.IsAbstract) { continue; } MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo method in methods) { IEnumerable <Attribute> attributes = method.GetCustomAttributes(); foreach (Attribute att in attributes) { if (att is NetworkRPCAttribute rpc) { RPCMethodInfo rpcMethod = new RPCMethodInfo(type.Name, method.Name, method.GetParameters()?.Length ?? 0); m_Methods.Add(rpcMethod); break; } } } } } #endif }
/// <summary> /// Execute a remote procedure. /// </summary> /// <param name="netInstanceID">The <see cref="NetworkIdentity.InstanceID"/>.</param> /// <param name="function">The name of the function.</param> /// <param name="parameters">The function parameters.</param> public void Call(NetworkIdentity identity, RPCType type, string function, params object[] parameters) { int connectionID = NetworkController.Instance.IsServer ? identity.OwnerConnection?.ConnectionID ?? -1 : NetworkController.Instance.ConnectionID; if (!NetworkController.Instance.IsServer) { if (type == RPCType.Target) { throw new InvalidOperationException("You cannot send a targetted RPC because you are not the server."); } if (identity.OwnerConnection == null) { throw new InvalidOperationException("The network identity has no owner and cannot execute any RPCs"); } if (identity == null) { throw new InvalidOperationException("The network identity specified does not exist on this client: " + identity.InstanceID); } if (identity.OwnerConnection.ConnectionID != NetworkController.Instance.LocalConnectionID) { throw new InvalidOperationException("You are not the owner of this object and cannot execute RPCs on it."); } } int index = m_Methods?.FindIndex(x => x.m_MethodName == function) ?? -1; if (index == -1) { return; } RPCMethodInfo rpc = m_Methods[index]; if (rpc.m_ArgumentCount != parameters.Length) { throw new InvalidOperationException("Given argument count for " + function + " does not match the argument count specified."); } NetworkWriter writer = GetRPCWriter(NetworkController.Instance.LocalConnectionID, identity.InstanceID, (byte)type, index, rpc.m_ArgumentCount, parameters); byte[] data = writer.ToArray(); switch (type) { case RPCType.All: { if (NetworkController.Instance.IsServer) { NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, data); } else { NetworkController.Instance.Send(connectionID, NetworkController.ReliableSequencedChannel, RPCMsg, data); } break; } case RPCType.Others: { if (NetworkController.Instance.IsServer) { NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, data); } else { NetworkController.Instance.Send(connectionID, NetworkController.ReliableSequencedChannel, RPCMsg, data); } break; } case RPCType.ServerOnly: { if (NetworkController.Instance.IsServer) { NetworkBehaviour networkBehaviour = identity.GetComponent <NetworkBehaviour>(); networkBehaviour.InvokeRPC(function, parameters); } else { NetworkController.Instance.Send(connectionID, NetworkController.ReliableSequencedChannel, RPCMsg, data); } break; } case RPCType.AllBuffered: { if (NetworkController.Instance.IsServer) { InitBuffer(identity.InstanceID); m_BufferedMessages[identity.InstanceID].Add(new NetworkWriter(writer.ToArray())); NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, data); } else { NetworkController.Instance.Send(connectionID, NetworkController.ReliableSequencedChannel, RPCMsg, data); } break; } case RPCType.OthersBuffered: { if (NetworkController.Instance.IsServer) { InitBuffer(identity.InstanceID); m_BufferedMessages[identity.InstanceID].Add(new NetworkWriter(writer.ToArray())); NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, data); } else { NetworkController.Instance.Send(connectionID, NetworkController.ReliableSequencedChannel, RPCMsg, data); } break; } case RPCType.Target: { if (parameters.Length > 0) { NetworkConnection connection = (NetworkConnection)parameters[0]; if (connection != null) { connection.Send(NetworkController.ReliableSequencedChannel, RPCMsg, data); } } break; } } }
private void OnRPC(NetworkWriter writer) { ReadRPC(writer, out int connection, out int instanceID, out byte rpcType, out int rpcIndex, out int argumentCount, out object[] arguments); NetworkIdentity identity = NetworkIdentityManager.Instance.Get(instanceID); if (identity == null) { if (!NetworkController.Instance.IsServer) { InitBuffer(instanceID); m_BufferedMessages[instanceID].Add(new NetworkWriter(writer.ToArray())); } return; } if (rpcIndex == -1 || rpcIndex >= m_Methods.Count) { return; } if (NetworkController.Instance.IsServer) { RPCType type = (RPCType)rpcType; if (type != RPCType.ServerOnly) { if (identity.OwnerConnection == null || identity.OwnerConnection.ConnectionID != connection) { return; } if (NetworkController.Instance.GetConnection(connection) == null) { return; } } switch (type) { case RPCType.All: NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, writer.ToArray()); return; case RPCType.AllBuffered: NetworkController.Instance.SendToAll(NetworkController.ReliableSequencedChannel, RPCMsg, writer.ToArray()); InitBuffer(instanceID); m_BufferedMessages[instanceID].Add(new NetworkWriter(writer.ToArray())); return; case RPCType.Others: NetworkController.Instance.SendToAllExcluding(writer.ToArray(), NetworkController.ReliableSequencedChannel, RPCMsg, connection); return; case RPCType.OthersBuffered: NetworkController.Instance.SendToAllExcluding(writer.ToArray(), NetworkController.ReliableSequencedChannel, RPCMsg, connection); InitBuffer(instanceID); m_BufferedMessages[instanceID].Add(new NetworkWriter(writer.ToArray())); return; } } RPCMethodInfo method = m_Methods[rpcIndex]; NetworkBehaviour behaviour = (NetworkBehaviour)identity.GetComponent(method.m_TypeName); behaviour.InvokeRPC(method.m_MethodName, arguments); }