So I ran into what seems like a common problem. If you are the host and you are sending a message to yourself…
networkView.RPC("FunctionName", RPCMode.Server);
…the function, “FunctionName”, won’t be called.
Although if you used…
networkView.RPC("FunctionName", RPCMode.All);
…the server would receive it just fine and call the function named “FunctionName”. The problem is now EVERYONE will receive that call when you may only want the server to receive it.
What I don’t understand is why RPCMode.All can be used by the server to send to the server (and everyone) but RPCMode.Server can’t be used by the server to send to the server. It makes absolutely no sense.
The Workaround - Network Extensions - Pastebin.com
using UnityEngine;
using System;
using System.Reflection;
public static class NetworkExtensions {
/// <summary>
/// If the server is using RPCMode.Server to call itself it will call 'function', otherwise NetworkView.RPC will be used.
/// </summary>
public static void RPC(this NetworkView networkView, Action function, RPCMode mode, params object[] args) {
if(function == null) return;
if(mode == RPCMode.Server && Network.isServer)
function();
else
networkView.RPC(function.Method.Name, mode, args);
}
/// <summary>
/// If the server is using RPCMode.Server to call itself it will manually find the method to call, otherwise NetworkView.RPC will be used.
/// </summary>
public static void RPCDirect(this NetworkView networkView, string name, RPCMode mode, params object[] args) {
if(mode == RPCMode.Server && Network.isServer) {
object obj = null;
MethodInfo function = null;
foreach(MonoBehaviour a in networkView.GetComponents<MonoBehaviour>()) {
Type type = a.GetType();
foreach(MethodInfo method in type.GetMembers(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) {
if(Attribute.IsDefined(method, typeof(RPC)) && method.Name == name) {
ParameterInfo[] parameters = method.GetParameters();
object[] arguments = (object[])args.Clone();
Type networkMessageInfoType = typeof(NetworkMessageInfo);
if(parameters.Length > 0 && parameters[parameters.Length - 1].ParameterType == networkMessageInfoType)
if(!(arguments.Length > 0 && args[arguments.Length - 1].GetType() == networkMessageInfoType)) {
Array.Resize<object>(ref arguments, arguments.Length + 1);
arguments[parameters.Length - 1] = new NetworkMessageInfo();
}
if(parameters.Length == arguments.Length) {
bool allTypesCorrect = true;
for(int i = 0; i < parameters.Length; i++)
if(parameters[i].ParameterType != arguments[i].GetType()) {
allTypesCorrect = false;
break;
}
if(allTypesCorrect) {
obj = a;
function = method;
args = arguments;
break;
}
}
}
}
if(function != null) break;
}
if(obj != null && function != null)
function.Invoke(obj, args);
else
Debug.LogError("Method (" + name + ") not found.", networkView);
}
else
networkView.RPC(name, mode, args);
}
}
It can be used the same way as NetworkView.RPC, just a different name.
networkView.RPC(ActualFunction, RPCMode.Server);
networkView.RPCDirect("FunctionName", RPCMode.Server);
They just simply check to see if you are the server and are trying to send the RPC to yourself, if so it’ll call the function directly. The method RPCDirect is named that otherwise it will conflict with NetworkView.RPC.
NetworkMessageInfo is now accounted for using the RPCDirect function [spoiler]Note: RPCDirect will not automatically account for the NetworkMessageInfo parameter (if it is present in the function) as I cannot set the properties inside of it. http://puu.sh/dFTRz/fff19459a9.png[/spoiler]
Use case: Let’s say you’ve instantiated a new character on the network. It doesn’t matter whether you are the server or client. You then want to send a message to the server to give you a weapon to start out with. Because it’s an authoritative server you would want the server to handle giving out the weapons. But you would also want the server to handle giving out weapons to itself, but not have to use an “if” check to see if you are the server sending the RPC message to yourself.
