RPC method not found

Using RPC throws an error:

RPC method 'HandleHumanoidDead(Boolean)' not found on object with PhotonView 1018. 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.

The method is not static, there's no same named method, the parameter is correct, and photonView exists, and the script is attached in the game object that both have photonView and this script, and also has [PunRPC] attribute.

I only tested with offline mode and but it is supposed to work here too.

Here's the code:
protected override void OnDead(DamageType damageType, float damageGiverDistance) {
    base.OnDead(damageType, damageGiverDistance);

    bool carnage = damageType == DamageType.Explosive && damageGiverDistance <= 2.5f;
    photonView.RPC("HandleHumanoidDead", RpcTarget.All, carnage);
}

[PunRPC]
void HandleHumanoidDead(bool carnage) {
    if (carnage && GameSettingManager.Instance.BodyAmputation == BodyAmputation.On) {
        ExplodeBody();
    }
    else {
        PlayDead();
    }
}

Already tried to clear and refresh the RPC list, but doesn't make any change. Unity 2019.1.0f2 and PUN2 4.1.6.3.

Best Answer

  • modernator
    Accepted Answer
    I'm not sure this is the right way to do it, but actually, I found the solution.

    Changed this in HumanoidBaseController from these:
    [PunRPC]
    void HandleHumanoidDead(bool carnage) {
        if (carnage && GameSettingManager.Instance.BodyAmputation == BodyAmputation.On) {
            ExplodeBody();
        }
        else {
            PlayDead();
        }
    }
    

    To these:
    protected virtual void HandleHumanoidDead(bool carnage) {
        if (carnage && GameSettingManager.Instance.BodyAmputation == BodyAmputation.On) {
            ExplodeBody();
        }
        else {
            PlayDead();
        }
    }
    

    And then move to the child class(in my case, HumanoidCharacterController and PlayerController), add these:
    [PunRPC]
    protected override void HandleHumanoidDead(bool carnage) {
        base.HandleHumanoidDead(carnage);
    }
    

    Now calling HandleHumanoidDead as an RPC from the parent class will invoke the method in the child.

Answers

  • Only I can guess that there is a possible factor that may be related to this issue: the above script was inherited from the class that inherits MonoBehaviourPun, and the actual using component is also inherited.

    public abstract class BaseCharacterController : MonoBehaviourPun
    -> public class HumanoidBaseController : BaseCharacterController <- Above codes are here
    --> public class HumanoidCharacterController: HumanoidBaseController <- Used component in the gameobject
  • I just put the additional codes in PhotonNetworkPart.cs, after line 494
    // TODO: REMOVE
    if (inMethodName.Equals("HandleHumanoidDead")) {
        for (int i = 0; i < cachedRPCMethods.Count; i += 1) {
            Debug.Log(cachedRPCMethods[i]);
        }
    }
    

    As I expected, the RPC method wasn't there. Only the [PunRPC] method in the classes at the final level of the inheritance structure came out.

    How to fix this? HumanoidBaseController is already used in the multiple Humanoid type characters in my game, includes players, various types of AI units. The HandleHumanoidDead RPC must be invoked from the HumanoidBaseController, not the subclasses. Any ideas?
  • modernator
    Accepted Answer
    I'm not sure this is the right way to do it, but actually, I found the solution.

    Changed this in HumanoidBaseController from these:
    [PunRPC]
    void HandleHumanoidDead(bool carnage) {
        if (carnage && GameSettingManager.Instance.BodyAmputation == BodyAmputation.On) {
            ExplodeBody();
        }
        else {
            PlayDead();
        }
    }
    

    To these:
    protected virtual void HandleHumanoidDead(bool carnage) {
        if (carnage && GameSettingManager.Instance.BodyAmputation == BodyAmputation.On) {
            ExplodeBody();
        }
        else {
            PlayDead();
        }
    }
    

    And then move to the child class(in my case, HumanoidCharacterController and PlayerController), add these:
    [PunRPC]
    protected override void HandleHumanoidDead(bool carnage) {
        base.HandleHumanoidDead(carnage);
    }
    

    Now calling HandleHumanoidDead as an RPC from the parent class will invoke the method in the child.
  • If the RPC method is overridden, do not forget to add the PunRPC attribute to it. Otherwise, inherited methods not overridden that have PunRPC attribute on the base class can be used.
    from doc page
  • Thanks for the clarification.