Managing Persistent Game State with Photon Room Properties
Learn how to use Photon Room Properties to synchronize persistent game state, manage trust boundaries via the Master Client, and avoid common bandwidth pitfalls.
02 Apr 2026, 18:11 UTC

The Problem: State Synchronization Overhead
In multiplayer games, synchronizing state like a flag location, match timer, or team score often leads to two inefficient patterns: constant RPC updates or forcing new players to request a full state dump.
The takeaway is to use Room Properties as a shared, synchronized key‑value store. The Photon server distributes the current state to existing clients and automatically synchronizes it to any client that joins the room late, eliminating custom catch‑up logic.
The Minimal Architecture: Buffered Cache
Room Properties act as a persistent record of the room's current truth.
- Key‑Value Store: State is stored as a dictionary of string keys and supported values (int, float, string, bool, Hashtable).
- Delta Updates: Only the keys that change are transmitted, not the entire state.
- Automatic Join‑Sync: When a client joins, the server sends the current set of Room Properties as part of the join sequence.
Trust Boundaries and Data Mutation
Room Properties are visible to all clients, so a trust boundary is needed to prevent cheating. In Photon Realtime the Master Client acts as the authoritative source for state changes.
- The client requests a change via an RPC to the Master Client.
- The Master Client validates the request (for example, checking that the player actually touched the flag).
- The Master Client updates the Room Property, which then propagates to all other clients.
Implementation Example: Game Timer
To implement a synchronized match timer, call SetCustomProperties on the Master Client.
// Run this on the Master Client (Permission: MasterClient)
ExitGames.Client.Photon.Hashtable props = new ExitGames.Client.Photon.Hashtable();
props.Add("MatchTimer", currentTimerValue);
PhotonNetwork.CustomProperties.SetCustomProperties(props);
Remote clients listen for changes using the OnRoomPropertiesUpdate callback. This ensures the UI updates only when the value actually changes on the server.
Diagnostic Check: Verifying Synchronization
To verify synchronization, add a debug log inside OnRoomPropertiesUpdate. Connect a second client after the timer has started; if the second client immediately displays the correct remaining time without a manual request, the buffered synchronization is working.
Operational Limits and Failure Modes
Room Properties are not meant for high‑frequency data such as player positions; using them for that will saturate bandwidth and cause fragmentation.
| Constraint | Risk | Mitigation |
|---|---|---|
| Property Size | Increased Join Time / Buffer Overflow | Keep keys short; avoid storing large strings. |
| Update Frequency | Network Congestion | Use Unreliable UDP or Interest Groups for positions. |
| Network Spikes | State Divergence | Implement a periodic heartbeat full‑sync for critical values. |
When to Change This Design
This architecture fits small‑to‑medium state sets. Move to an external database or custom binary serialization if:
- The total size of Room Properties exceeds the maximum UDP packet payload.
- Persistence beyond the room lifetime is required (Room Properties are cleared when the last player leaves).
- The state needs relational queries that a simple key‑value store cannot provide.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.