in MRTK Tutorials/Assets/Photon/PhotonUnityNetworking/Code/PhotonNetworkPart.cs [354:655]
internal static void ExecuteRpc(Hashtable rpcData, Player sender)
{
if (rpcData == null || !rpcData.ContainsKey(keyByteZero))
{
Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClassPun.DictionaryToString(rpcData));
return;
}
// ts: updated with "flat" event data
int netViewID = (int)rpcData[keyByteZero]; // LIMITS PHOTONVIEWS&PLAYERS
int otherSidePrefix = 0; // by default, the prefix is 0 (and this is not being sent)
if (rpcData.ContainsKey(keyByteOne))
{
otherSidePrefix = (short)rpcData[keyByteOne];
}
string inMethodName;
if (rpcData.ContainsKey(keyByteFive))
{
int rpcIndex = (byte)rpcData[keyByteFive]; // LIMITS RPC COUNT
if (rpcIndex > PhotonNetwork.PhotonServerSettings.RpcList.Count - 1)
{
Debug.LogError("Could not find RPC with index: " + rpcIndex + ". Going to ignore! Check PhotonServerSettings.RpcList");
return;
}
else
{
inMethodName = PhotonNetwork.PhotonServerSettings.RpcList[rpcIndex];
}
}
else
{
inMethodName = (string)rpcData[keyByteThree];
}
object[] arguments = null;
if (rpcData.ContainsKey(keyByteFour))
{
arguments = (object[])rpcData[keyByteFour];
}
PhotonView photonNetview = GetPhotonView(netViewID);
if (photonNetview == null)
{
int viewOwnerId = netViewID / PhotonNetwork.MAX_VIEW_IDS;
bool owningPv = (viewOwnerId == NetworkingClient.LocalPlayer.ActorNumber);
bool ownerSent = sender != null && viewOwnerId == sender.ActorNumber;
if (owningPv)
{
Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! View was/is ours." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender);
}
else
{
Debug.LogWarning("Received RPC \"" + inMethodName + "\" for viewID " + netViewID + " but this PhotonView does not exist! Was remote PV." + (ownerSent ? " Owner called." : " Remote called.") + " By: " + sender + " Maybe GO was destroyed but RPC not cleaned up.");
}
return;
}
if (photonNetview.Prefix != otherSidePrefix)
{
Debug.LogError("Received RPC \"" + inMethodName + "\" on viewID " + netViewID + " with a prefix of " + otherSidePrefix + ", our prefix is " + photonNetview.Prefix + ". The RPC has been ignored.");
return;
}
// Get method name
if (string.IsNullOrEmpty(inMethodName))
{
Debug.LogError("Malformed RPC; this should never occur. Content: " + SupportClassPun.DictionaryToString(rpcData));
return;
}
if (PhotonNetwork.LogLevel >= PunLogLevel.Full)
{
Debug.Log("Received RPC: " + inMethodName);
}
// SetReceiving filtering
if (photonNetview.Group != 0 && !allowedReceivingGroups.Contains(photonNetview.Group))
{
return; // Ignore group
}
Type[] argumentsTypes = null;
if (arguments != null && arguments.Length > 0)
{
argumentsTypes = new Type[arguments.Length];
int i = 0;
for (int index = 0; index < arguments.Length; index++)
{
object objX = arguments[index];
if (objX == null)
{
argumentsTypes[i] = null;
}
else
{
argumentsTypes[i] = objX.GetType();
}
i++;
}
}
int receivers = 0;
int foundMethods = 0;
if (!PhotonNetwork.UseRpcMonoBehaviourCache || photonNetview.RpcMonoBehaviours == null || photonNetview.RpcMonoBehaviours.Length == 0)
{
photonNetview.RefreshRpcMonoBehaviourCache();
}
for (int componentsIndex = 0; componentsIndex < photonNetview.RpcMonoBehaviours.Length; componentsIndex++)
{
MonoBehaviour monob = photonNetview.RpcMonoBehaviours[componentsIndex];
if (monob == null)
{
Debug.LogError("ERROR You have missing MonoBehaviours on your gameobjects!");
continue;
}
Type type = monob.GetType();
// Get [PunRPC] methods from cache
List<MethodInfo> cachedRPCMethods = null;
bool methodsOfTypeInCache = monoRPCMethodsCache.TryGetValue(type, out cachedRPCMethods);
if (!methodsOfTypeInCache)
{
List<MethodInfo> entries = SupportClassPun.GetMethods(type, typePunRPC);
monoRPCMethodsCache[type] = entries;
cachedRPCMethods = entries;
}
if (cachedRPCMethods == null)
{
continue;
}
// Check cache for valid methodname+arguments
for (int index = 0; index < cachedRPCMethods.Count; index++)
{
MethodInfo mInfo = cachedRPCMethods[index];
if (!mInfo.Name.Equals(inMethodName))
{
continue;
}
ParameterInfo[] parameters = mInfo.GetCachedParemeters();
foundMethods++;
// if we got no arguments:
if (arguments == null)
{
if (parameters.Length == 0)
{
receivers++;
object o = mInfo.Invoke((object)monob, null);
if (PhotonNetwork.RunRpcCoroutines)
{
IEnumerator ie = null;//o as IEnumerator;
if ((ie = o as IEnumerator) != null)
{
PhotonHandler.Instance.StartCoroutine(ie);
}
}
}
else if (parameters.Length == 1 && parameters[0].ParameterType == typeof(PhotonMessageInfo))
{
int sendTime = (int)rpcData[keyByteTwo];
receivers++;
object o = mInfo.Invoke((object)monob, new object[] { new PhotonMessageInfo(sender, sendTime, photonNetview) });
if (PhotonNetwork.RunRpcCoroutines)
{
IEnumerator ie = null;//o as IEnumerator;
if ((ie = o as IEnumerator) != null)
{
PhotonHandler.Instance.StartCoroutine(ie);
}
}
}
continue;
}
// if there are any arguments (in the incoming call check if the method is compatible
if (parameters.Length == arguments.Length)
{
// Normal, PhotonNetworkMessage left out
if (CheckTypeMatch(parameters, argumentsTypes))
{
receivers++;
object o = mInfo.Invoke((object)monob, arguments);
if (PhotonNetwork.RunRpcCoroutines)
{
IEnumerator ie = null;//o as IEnumerator;
if ((ie = o as IEnumerator) != null)
{
PhotonHandler.Instance.StartCoroutine(ie);
}
}
}
continue;
}
if (parameters.Length == arguments.Length + 1)
{
// Check for PhotonNetworkMessage being the last
if (parameters[parameters.Length - 1].ParameterType == typeof(PhotonMessageInfo) && CheckTypeMatch(parameters, argumentsTypes))
{
int sendTime = (int)rpcData[keyByteTwo];
object[] argumentsWithInfo = new object[arguments.Length + 1];
arguments.CopyTo(argumentsWithInfo, 0);
argumentsWithInfo[argumentsWithInfo.Length - 1] = new PhotonMessageInfo(sender, sendTime, photonNetview);
receivers++;
object o = mInfo.Invoke((object)monob, argumentsWithInfo);
if (PhotonNetwork.RunRpcCoroutines)
{
IEnumerator ie = null;//o as IEnumerator;
if ((ie = o as IEnumerator) != null)
{
PhotonHandler.Instance.StartCoroutine(ie);
}
}
}
continue;
}
if (parameters.Length == 1 && parameters[0].ParameterType.IsArray)
{
receivers++;
object o = mInfo.Invoke((object)monob, new object[] { arguments });
if (PhotonNetwork.RunRpcCoroutines)
{
IEnumerator ie = null;//o as IEnumerator;
if ((ie = o as IEnumerator) != null)
{
PhotonHandler.Instance.StartCoroutine(ie);
}
}
continue;
}
}
}
// Error handling
if (receivers != 1)
{
string argsString = string.Empty;
int argsLength = 0;
if (argumentsTypes != null)
{
argsLength = argumentsTypes.Length;
for (int index = 0; index < argumentsTypes.Length; index++)
{
Type ty = argumentsTypes[index];
if (argsString != string.Empty)
{
argsString += ", ";
}
if (ty == null)
{
argsString += "null";
}
else
{
argsString += ty.Name;
}
}
}
GameObject context = photonNetview != null ? photonNetview.gameObject : null;
if (receivers == 0)
{
if (foundMethods == 0)
{
// found no method that matches
Debug.LogErrorFormat(context, "RPC method '{0}({2})' not found on object with PhotonView {1}. Implement as non-static. Apply [PunRPC]. Components on children are not found. " +
"Return type must be void or IEnumerator (if you enable RunRpcCoroutines). RPCs are a one-way message.", inMethodName, netViewID, argsString);
}
else
{
// found a method but not the right arguments
Debug.LogErrorFormat(context, "RPC method '{0}' found on object with PhotonView {1} but has wrong parameters. Implement as '{0}({2})'. PhotonMessageInfo is optional as final parameter." +
"Return type must be void or IEnumerator (if you enable RunRpcCoroutines).", inMethodName, netViewID, argsString);
}
}
else
{
// multiple components have the same method
Debug.LogErrorFormat(context, "RPC method '{0}({2})' found {3}x on object with PhotonView {1}. Only one component should implement it." +
"Return type must be void or IEnumerator (if you enable RunRpcCoroutines).", inMethodName, netViewID, argsString, foundMethods);
}
}
}