- Home /
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.
Answer by whydoidoit · Jul 13, 2012 at 07:02 PM
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;
}
}
You can make that server code return that it is the server if the network peer type is disconnected too - I don't need that myself.
Hmmm I'm not sure this fits my situation quit exactly but I like the pattern - having the function call ITSELF as an RPC if it's applicable might be a good solution for me. Thanks!
It works really well for me - I get to have optional parameters and never forget the parameter list for an RPC (plus like I said, all the parameters are type checked).
WOW!! This seems like black magic to me... Will have to read more about this Enabler stuff because it seems powerful (I'm still new to C#, as you might guess)
There's a lot of Unity magic with networking too - but those are extension methods - very handy, but really just "syntactic sugar"
Answer by DoomGoober · Mar 27, 2015 at 02:55 PM
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.
Your answer
![](https://koobas.hobune.stream/wayback/20220613074137im_/https://answers.unity.com/themes/thub/images/avi.jpg)