- Performance Optimization
- Network Traffic Optimization
- Other Tips
Pool Objects For Instantiation
PUN has a built-in option to instantiate objects from a pool, rather than from a loaded resource (which is kept in-memory to speed up things). Read Using the PrefabPool in the Instantiation doc page.
Cache RPC Targets
In some cases, you might use a lot of RPCs in your game. Any Component on the target GameObject may implement RPCs, so PUN will use reflection to find the fitting methods. Of course, this is expensive and even wasteful, if the components don't change.
By default, PUN caches a MethodInfo list per Type of script. It does not cache which MonoBehaviours are on the GameObject as potential target.
You can set
PhotonNetwork.UseRpcMonoBehaviourCache = true, to cache the MonoBehaviours per PhotonView for RPCs.
This speeds up finding the components to call.
Should the scripts on a GameObject change, call
photonView.RefreshRpcMonoBehaviourCache() to update as needed.
Network Traffic Optimization
You can optimize traffic quite a bit by having a closer look at what you are sending and how. This can be done later in the development, without a lot of extra hassle. As usual with optimization, start with the most frequently sent messages first.
Often, values and objects are sent with more values than needed to share the state. If your character can't scale, don't sync scale! If your character is never leaning to a side, rotation could be a single float. Actually, a byte may be enough for the rotation without much precision loss. This is fine for non-physical objects.
In general, have a look at what you do in
OnPhotonSerializeView and RPCs. You can send a variable amount of values per
OnPhotonSerializeView. Sending compact byte arrays is often leaner than registering and sending a lot of Custom Types.
There are some tools that may make your life easier without much hassle. Have a look at the Network Transform Sync package, which provides advanced Transform synchronization with optimized traffic. The Transform Crusher - Free is an option if you just streamline what you send.
Another library that can help with serialization is NetStack. It comes with various other useful features, too.
Network Culling And Interest Groups
Send Right Away
RPCs and events raised are not sent at the same moment of the method calls
The same applies to other operation requests like
Instead, all these messages are queued until a periodic routine is called by the
PhotonHandler (frequency is set using
This aggregates messages into fewer packages to avoid traffic overhead but introduces some variable lag.
To avoid this lag and you want to send the RPC or event right away call
PhotonNetwork.SendAllOutgoingCommands in the next line.
This makes sense when your game relies on the timing of those messages, examples:
- timed competitive trivia or quiz games, the quicker the better
- the opponent is waiting for your turn
However, there are other uses cases for this, like sending a message:
- before disconnecting
- before leaving the room
- before quitting the app (inside
- before the app is moved to the background or loses focus (inside
For these cases, you should know that:
OnApplicationQuitwill not be called on all platforms, on Android for example, this will not be called when the application is terminated by the system. You could use
- Average package loss is typically 1.2%. Even if sent reliable there is no guarantee that what you sent will arrive to destination since the client will be unresponsive or disconnected or no longer joined to the room in case a retry attempt is needed.
- A message sent in these cases should be relatively small to fit into one package as the client may not have enough time to send multiple fragments.
Do Not "pause" PUN While
Time.timeScale == 0
To allow dispatching received messages in PUN even if
Time.timeScale is zero or low, set
PhotonNetwork.MinimalTimeScaleToDispatchInFixedUpdate to a value equal or higher than
By default, it's set to -1 which means received events (including RPCs) or operations responses will not be processed (no callbacks and no operation can finish execution) if
Time.timeScale is equal to 0.