single call to RPC or Local function?

I find myself writing a lot of code like this:

public void SelectActionNA(int actionIdx, int actingIdx, )
{
 if(Network.peerType == NetworkPeerType.Disconnected)
      SelectAction(actionIdx, actingIdx);
 else
      networkView.RPC ("SelectAction", RPCMode.All, actionIdx, actingIdx);
}

For every action that I want to call either in single player or as an RPC when in an online setting I write an intermediate (non-RPC) function that checks the network status and then calls an RPC or another local function as appropriate.

It feels like there has to be a better way to do that.

Is there a simple straightforward way to write “Do this as an RPC but only if you’re connected to the network” without writing a bunch of helper functions to always check the network status and then call it manually?

I feel like networkView.RPC should just call the function locally if not connected, but instead it errors out.

Well I write my code like this, so I always call the local function (type safe etc etc):

 [RPC]
 public void SetScore(int score)
 {
 //Run this on everything
 networkView.Others("SetScore", score);
 CurrentScore = score;
 }

Or

void SetPosition(Vector3 pos, Quaternion rot)
 {
 //Only run on others
 if (!networkView.Others("SetPosition", pos, rot))
     return;
 
 var time = _lastRPCtime = Time.time - _lastSetPosition;
 _lastSetPosition = Time.time;
 position.Duration = Mathf.Min(time, 2f);
 rotation.Duration = position.Duration;
 position.Value = pos;
 rotation.Value = rot;

 }

And

[RPC]
 public void Ready(NetworkViewID viewId)
 {
   //Only run on the server
   if (!networkView.Server("Ready", viewId))
      return;
   ...     
 }

This is the supporting code:

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System;
using System.Linq;
using Serialization;

public static class RPCEnabler
{
 
 
 public static bool Others(this NetworkView networkView, string routineName, params object[] parameters)
 {
 
 if (networkView.isMine)
 {
 
 networkView.RPC(routineName, RPCMode.Others, parameters);
 }
 return !networkView.isMine;
 
 }
 
 public static bool Server(this NetworkView networkView, string routineName, params object[] parameters)
 {
 if(!Network.isServer)
 networkView.RPC(routineName, RPCMode.Server, parameters);
 return Network.isServer;
 }
 

}

Here’s a solution that doesn’t require you to modify every RPC method. If you’re not connected (ie, single player) it will call the method directly. Otherwise, it will try to RPC the call. Put this in a source code file somewhere in your Unity project:

using UnityEngine;
using System.Collections;
using System;
using System.Reflection;

public static class NetworkViewExtensionMethods
{
    public static void LocalOrRPC(this MonoBehaviour monoBehaviour, string name, RPCMode mode, params object[] args)
    {
        if (Network.peerType == NetworkPeerType.Disconnected)
        {
            Type type = monoBehaviour.GetType();
            MethodInfo methodInfo = type.GetMethod(name, BindingFlags.NonPublic | BindingFlags.InvokeMethod | BindingFlags.Instance);
            methodInfo.Invoke(monoBehaviour, args);
        } 
        else
        {
            monoBehaviour.networkView.RPC(name, mode, args);
        }
    }
}

Usage is identical to a call to NetworkView.RPC:

//Call from some MonoBehaviour that has a NetworkView sibling.
this.LocalOrRPC("SomeMethod", RPCMode.All, "SomeArg", "SomeArg"); //RPCMode.All and RPCMode.AllBuffered are the only two that make sense.

Might be slower than the other solution since it uses reflection but: 1) It’s a bit easier to use. 2) The multiplayer RPC call uses reflection anyway! So, if you’re calling the function so much that perf is an issue, you’re going to run into WORSE problems during multiplayer when the function call overhead will be even higher so you’re going to have to fix it anyway.