PhotonView with ID 7 has no method "...." marked...

Options
I'm currently trying to send and RPC from a class which is not a Mono. I am using a photonView from another GameObject in order to call the rpc.

Example

nodeCanvasPhotonView.value.RPC("FindAndSetPlayerReference", RpcTarget.All,
 PhotonNetwork.LocalPlayer.ActorNumber);

[PunRPC]
private void FindAndSetPlayerReference(int clientActorID) {
    var playerGobReference = playerRefSpawnParent.transform.GetComponentsInChildren<PhotonView>()
        .First(photonView => photonView.OwnerActorNr == clientActorID);
    matchData.value.NetworkPlayer[clientActorID].Reference = playerGobReference.gameObject;
}

From looking at the documentation I thought it didn't matter where you define an RPC as long as you have a photonView to call it from. Am i incorrect on this?

Thanks in advance!

Comments

  • KevTheUnityDev
    edited October 2018
    Options
    In PhotonNetworkPart.cs it searches the RpcList
    string inMethodName;
    if (rpcData.ContainsKey((byte)5))
    {
    int rpcIndex = (byte)rpcData[(byte)5]; // 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];
    }
    }
    for the supplied method name. It's possible you just need to RefreshRPC's on your PhotonServerSettings asset.

    Switching to Debug view on the inspector window when your PhotonServerSettings asset is selected will allow you to see the RPC methods in the list. As long as your FindAndSetPlayerReference method is in the list, you're good; maybe - see below. As far as how that list is populated (ie what all objects/types it searches), it is searching for the [PunRPC] attribute only on the internal MonoBehaviour[] RpcMonoBehaviours array. So, it looks like they all must be defined in a MonoBehaviour; but yet there's more - read on.

    Finally the binding to which method gets executed is figured out through reflection to invoke the MethodInfo of the method that is named in the string parameter passed in the RPC call ("FindAndSetPlayerReference" in your case). But what class/type is it generating the list of MethodInfo's from, you ask? It does this on a PhotonView instance that it looks up via
    int netViewID = (int)rpcData[(byte)0]; // LIMITS PHOTONVIEWS&PLAYERS
    // ...
    PhotonView photonNetview = GetPhotonView(netViewID);
    So, now we know that the lookup is somehow tied to PhotonView types - hence the calls are invoked through instances of PhotonView. The last piece of the puzzle comes together in PhotonView.RefreshRpcBehaviourCache:
    /// 
    /// Can be used to refesh the list of MonoBehaviours on this GameObject while PhotonNetwork.UseRpcMonoBehaviourCache is true.
    ///
    ///
    /// Set PhotonNetwork.UseRpcMonoBehaviourCache to true to enable the caching.
    /// Uses this.GetComponents() to get a list of MonoBehaviours to call RPCs on (potentially).
    ///
    /// While PhotonNetwork.UseRpcMonoBehaviourCache is false, this method has no effect,
    /// because the list is refreshed when a RPC gets called.
    ///
    public void RefreshRpcMonoBehaviourCache()
    {
    this.RpcMonoBehaviours = this.GetComponents();
    }
    So the end result is, not only does your RPC method need to be a Monobehaviour, it also must be attached to the same GameObject as a PhotonView that is consistent for all clients.
  • meatloaf
    Options
    Ah got it thanks so much. This clears it up 👍.