RPC and inheritance

Hi,
I just tested something and it seems that RPCs in Unity don’t support inheritance. Is that correct?

class Unit : MonoBehaviour 
{
    [RPC] 
    public void Test () {}
}

class Melee : Unit 
{
}

If I have a unit with Melee script on it, RPC won’t be received as RPC function “Test” cannot be found.

class Unit : MonoBehaviour 
{
}

class Melee : Unit 
{
    [RPC] 
    public void Test () {}
}

On the contrary, this works and Test will be executed.

This introduces a set of new problems for us, can you please confirm that this is Unity’s standard behaviour? I hope we are doing something wrong…

We are using Photon but that should behave the same way as the integrated networking as far as I know.


EDIT:
Photon (PUN) class for the solution below:

1, in case the solution scripts are in the Plugin folder, move them out to your script folder

2, InheritableRPC.cs, replace the second class with this:

public static class InheritableRPCExtensions
{
	public class StoredPlayer
	{
		public string ipAddress, guid;
		public int port;
	}
	
	public static void RPCEx(this PhotonView view, string routineName, PhotonTargets targets, params object[] parameters)
	{
		using(var m = new MemoryStream())
		{
			var b = new BinaryFormatter();
			b.Serialize(m, parameters);
			m.Flush();
			var s = Convert.ToBase64String(m.GetBuffer());
            view.RPC("PerformRPCCall", targets, routineName, s);
		}
	}

    public static void RPCEx(this PhotonView view, string routineName, PhotonPlayer player, params object[] parameters)
	{
		using(var m = new MemoryStream())
		{
			var b = new BinaryFormatter();
			b.Serialize(m, parameters);
			m.Flush();
			var s = Convert.ToBase64String(m.GetBuffer());
			view.RPC("PerformRPCCall", player, routineName, s);
		}
	}
}

3, example code. SampleCaller.cs class:

public class SimpleCaller : MonoBehaviour {
	public PhotonView otherView;
	
	void Start ()
	{
		Network.InitializeServer(200,8081,true);
	}
	
	void OnGUI()
	{
		if(GUILayout.Button("Call Print"))
		{
			otherView.RPCEx("PrintThis", PhotonTargets.All, "Hello World");
		}
	}
}

Ok so you can’t do that normally but it is possible to create a work around that will work generically on all objects and classes. To do this you create a normal RPC script that itself defers to the base classes of the other components. This works well generically but there may be times when it would be faster to do this directly by writing code for specific instances. Presuming RPC calls are already expensive and not frequent it should be fine to do it this way.

So I’ve create a script that you attach to the game objects that have inherited scripts attached to them. This handles the real RPC call and then forwards it on to the inherited components.

To use it you use networkView.RPCEx(normal parameters) and that’s it.

You can also pass more complex objects as parameters to RPCEx - but you cannot pass NetworkPlayer or NetworkViewID so those would have to use normal RPC for setup. After that I’m presuming these parameters are not often passed in the case where you want inherited execution (it would be possible with more work to make those passable too).

You can get the code from here