RPC inheritance

Can you use inheritance with methods marked as RPC?

I am getting error with this simple example because the child method is for some reason called in loop.

This is a stripped down example of the code:

public abstract class TestBase : NetworkBehaviour
{
    [Rpc(SendTo.Server)]
    public virtual void TestRpc()
    {
        Debug.Log("parent");
    }
}
public class TestChild : TestBase
{
    [Rpc(SendTo.Server)]
    public override void TestRpc()
    {
        base.TestRpc();
        Debug.Log("child");
    }
}
public class SampleUser : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            var o = FindObjectOfType<TestBase>();
            o.TestRpc();
        }
    }
}

Output is only “child” over again until stack overflows.

Could someone provide a simple example of inheritance with RPC or state if it is even possible?

Edit 1

As @Pangamini suggested It is enough to put only one attribute in the base class and it indeed works in this simple scenario.

[Rpc(SendTo.Server)]
public virtual void TestRpc() {...}
...
public override void TestRpc() {... base.TestRpc(); ...}

But there is a problem with this approach. The child method is then executed on both client and server because it lack the RPC attribute. If you reverse the attribute then both methods are executed on server correctly:

public virtual void TestRpc() {...}
...
[Rpc(SendTo.Server)]
public override void TestRpc() {... base.TestRpc(); ...}

But this just delays the problem on the next child class of TestChild.

Edit 2 (Possible solution 1)

I found a workaround. You can create an UnityEvent in the base class and invoke it in the base method. In the child class you can add a listener (the fake override method) to this event:

public abstract class TestBase : NetworkBehaviour
{
    protected UnityEvent myCallbacks = new UnityEvent(); 
    [Rpc(SendTo.Server)]
    public void TestRpc()
    {
        Debug.Log("parent");
        myCallbacks.Invoke();
    }
}
public class TestChild : TestBase
{
    private void Start()
    {
        myCallbacks.AddListener(FakeTestRpc);
    }
    private void FakeTestRpc() //Fake override method
    {
        Debug.Log("child");
    }
}

This way the callback is invoked on the server.

Edit 3 (Possible solution 2)

You can keep your inheritance as at the top of this post but instead marking the methods with RPC attribute you just create another class RpcInvoker which invoker you methods via its own RPC:

public abstract class TestBase : NetworkBehaviour
{
    // Now without RPC attribute
    public virtual void Test()
    {
        Debug.Log("parent");
    }
}
public class TestChild : TestBase
{
    public override void Test()
    {
        base.Test();
        Debug.Log("child");
    }
}

//The RPC invoker class
public class RpcInvoker : NetworkBehaviour
{
    [Rpc(SendTo.Server)]
    public void InvokeMyMethodsRpc()
    {
        Debug.Log("invoking on server");
        GetComponent<TestBase>().Test(); // Or you can use UnityEvent to make it more generic
    }
}

// And modify the input logic like this
public class SampleUser : MonoBehaviour
{
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.T))
        {
            // we look for RpcInvoker instead of the base class
            var o = FindObjectOfType<RpcInvoker>();
            o.InvokeMyMethodsRpc();
        }
    }
}

Still if anyone know how to make a proper inheritance with RPC feel free to share.

Could you have a non-virtual RPC method that simply calls the virtual one that doesn’t have the attribute?

Like @Pangamini said, you should not use polymorphic methods as RPC calls. RPC methods are heavily altered by some post process magic. So calls to the method are actually replaced with actual network messaging. So when a client “calls” the method, the call is essentially replaced / patched with the proper network message.

Inheritance in general should be kept to a minimum as Unity is component based. If you really need / want to use polymorphism, using interfaces is usually the better approach. The solution Pangamini suggested should work because the “MyRpc” method is the classical RPC method which gets altered and mangled by the postprocessor and all it does is calling your virtual method. So this method call should work properly as this method itself is not an RPC