One feature that sets PUN aside from other Photon packages is the support for
Remote Procedure Calls (RPCs).
Remote Procedure Calls
Remote Procedure Calls are exactly what the name implies: Method-calls on remote clients (in the same room).
To enable remote calling for some method, you must apply the attribute:
To call the functions marked as RPC, you need a
PhotonView. Example call:
Pro tip: If your script is a
Photon.PunBehaviour you can use: this.photonView.RPC().
So, instead of directly calling the target method, call RPC() on a PhotonView and provide the name of the method to call.
Targets and Parameters
The PhotonView is like a "target" for the RPC: All clients execute the method only on the networked GameObject with that specific PhotonView. If you hit a specific object and call "ApplyDamage" RPC, then the receiving clients will apply the damage to the same object!
You can add multiple parameters (provided PUN can serialize them). When you do, the method and the call must have the same parameters. If the receiving client can’t find a matching method, it will log an error.
There is one exception to this rule: The last parameter of a RPC method can be of type
which will provide the context for each call. You don't set the PhotonMessageInfo in the call.
With the sender being in the PhotonMessageInfo and the "targetting" via PhotonView, you can implement shooting someone without extra parameters. You know who shot and what was hit.
Targets, Buffering and Order
You can define which clients execute an RPC. To do that, use the values of
PhotonTargets. Most commonly, you want
All clients to call the RPC. Sometimes only
PhotonTargets has some values ending on
Buffered. The server will remember those RPCs and when a new player joins, it gets the RPC, even though it happened earlier. Use this with care, as the a long buffer causes longer join times.
PhotonTargets has values ending on
ViaServer. Usually, when the sending client has to execute an RPC, it does so immediately - without sending the RPC through the server. This, however, affects the order of events, because there is no lag when you call a method locally!
ViaServer disables the "All" shortcut. This is especially interesting when RPCs should be done in order: RPCs sent through the server are executed in the same order by all receiving clients. It is the order of arrival on the server.
Example: In a racing game you could send the RPC "finished" as
AllViaServer. The first "finished" RPC call will tell you who won. The following "finished" calls will tell you who's on the ranks.
Shortcuts for RPC Names
Because strings are not the most effective piece to send via network, PUN uses a trick to cut them short. PUN detects RPCs in the Editor and compiles a list. Each method name gets an ID via that list and when you call an RPC by name, PUN will silently just send the ID.
Due to this shortcut, different builds of games maybe don't use the same IDs for RPCs. If this is a problem, you can disable the shortcut. However, if clients of the same build are matched, this is not a problem.
The list of RPCs is stored and managed via the
If RPC calls go wrong between different builds of a project, check this list. The Get HashCode button calculates a hashcode, which is easy to compare between project folders.
If required, you can clear the list (Clear RPCs button) and refresh the list manually by clicking Refresh RPC List button.
In some cases, RPCs are not exactly what you need. They need a PhotonView and some method to be called.
PhotonNetwork.RaiseEvent, you can make up your own events and send them without relation to some networked object. Make up a code and some content and send it:
The content can be anything that PUN can serialize. You can use an object and mix selected units with their destination, e.g..
To receive the event, a script needs to implement an
EventCallback and register it. PUN does not use a general callback for performance reasons. Implement this in a MonoBehaviour to handle events:
The example code is not very useful, but you get the idea. You can make up event codes and use each in a different way with different content.
Under the hood, PUN also uses RaiseEvent for pretty much all communication.
RaiseEventOptions And Caching
RaiseEventOptions parameter, you define which clients get the event, if it's buffered and more.
The most interesting option is probably the event cache / buffering. PUN uses that for Instantiate and it can be useful when new (joining) players should get events that happened even before they were in the room.
RaiseEventOptions.EventCaching has three important options:
RemoveFromRoomCache. These work best when you send a Hashtable in an event.
Calling RaiseEvent with
EventCaching.AddToRoomCache, the event will be put into the server's cache. That means, any player who joins later on, will also get the event. New players get cached events in the order they arrived on the server.
When a player leaves, the cached events get automatically removed from the cache. To avoid this for specific events, call RaiseEvent with
EventCaching.AddToRoomCacheGlobal. That puts the event into the "room's event cache".
If you put a lot of events into the cache, new players will get a lot of messages when they get into the room. This can take a moment for larger numbers of events, so you should clean up stuff that's no longer relevant, which is done with
When you use
RemoveFromRoomCache, the EventCode of RaiseEvent will be used as filter. So instead of setting some event, you can remove all instances of it.
To get more fine control, the content of an event can be used for filtering. For that, you have to use a Hashtable as content type. You can set a key/value pair to identify a specific event and when you RaiseEvent with
RemoveFromRoomCache, you only have that key/value pair in the content filter.
You can identify individual events this way, or events belonging to some object or turn or whatever.
Read more about events cache here.