This document is about: SERVER 4
SWITCH TO

Frequently Asked Questions

Which Photon product is the right one for me?

The answer to this depends mostly on your project and team.
Generally, we suggest to use either Fusion or
Quantum, which are our most advanced client solutions.

For a quick overview, both product sheets contain the product picker "Quadrant":

Additionally, this page discusses using the Photon Cloud or Photon Server?.

Feel free to reach out to us for any questions.

Load Balancing

What is the maximum number of players supported by Photon rooms?

Most Photon multiplayer games have 2-16 players, but the theoretical limit of players/peers per room can be quite high.
There are Photon games live with 32 or even 64 players and in virtual conferencing scenarios it can be in the hundreds.
However, sending too many messages per second (msg/s per room) can cause performance issues depending on the client's processing power coping with data.
While high player numbers in e.g. turnbased games are totally fine, more than 32 players in a fast-paced action game likely will require you to implement interest management.
This way not every player receives every message from all the other players.

The number of players per room is the main factor for increasing data traffic inside the game room:
This is why we recommend keeping your msg/s per room count below 500.
Photon does not enforce this limit, but relies on a fair use policy.
Keeping an eye on your bandwidth usage is always important and it helps to ensure you stay within your plans included traffic range of 3GB per CCU.

Is there a limit for Photon strings?

Photon uses strings for lots of purposes: room name, lobby name, UserID, Nickname, custom property key, etc.

Technically, the Photon binary protocol can serialize strings up to 32767 one-byte-characters but it is strongly recommended to use the shortest strings possible.

For names and UserIDs 36 characters should be enough (e.g. a GUID is 36 characters).
For custom property keys, you should use shorter strings to minimize their overhead.
This is especially important for properties which are visible in the lobby, as those are part of the room lists and get sent to everyone in the lobby, not just the couple of clients in a room.

Is there a limit for the number of custom properties?

Yes, there is a limit: Each user can set 13k key-values and their total size in the room can't go over 500kB.
The more Custom Properties are set, the longer the clients take to join a room, as clients receive all of the properties.

Can I send a huge message using Photon?

We do not recommend transferring large data (i.e. files) using Photon unless you know what you are doing.
We advise you to optimize the data you exchange and get in touch with us if you really have to send a very big message.

Photon Cloud has a server side limit for client buffers which is 500KB.
So depending on the context a message could be considered:

  • "too big" for our per client buffer size on Photon Cloud > 500KB. If a client hits this limit in a short period of time, it will be disconnected by the server.
  • "too big" to be sent with UDP without resulting in an amount of fragments that might cause problems > 100KB.
  • "too big" to be sent without splitting it up into multiple UDP packets > 1.2KB (including protocols overhead).

For messages that get sent very regularly (10 times a second or even more often) we would recommend to keep their size below 1KB.

If a message only get sent rarely (for example once at the start of a match), then a size of multiple KB is still fine, but we still would recommend to keep it below 10KB.

Larger messages can be sent in a separate Enet channel (in UDP), which affects the other channels (state sync) less.

For large files, consider using a separate backend.

Which data should be sent reliable and which should be sent unreliable?

First of all, you should know reliability is an option only when the protocol used is UDP.
TCP has its own "reliability" mechanism(s) which are not covered here.

Sending something reliable means that Photon makes sure it arrives at the target client(s).
So in case clients do not receive an acknowledgment within time, they will repeat sending until the acknowledgment is received or the number of resends is exceeded.
Also, repeating reliable events may cause extra latency and make subsequent events delayed.

Examples for not using reliability:

  • player position updates in realtime games
  • voice or video chat (streaming)

Example for using reliability:

  • turn events in turn-based games
  • score updates that don't change rarely

Why do I have so many disconnects in my game?

The disconnects could be due to various reasons.
We already have this documentation page that can help you investigate the related issues: "Analyzing Disconnects".

How messages per second per room are calculated?

Photon server counts total inbound and outbound messages every second and divide it by the total number of rooms (on the same Master Server).

Any operation request or operation response or event is considered a message.
Photon operations return an optional operation response and trigger zero or more events.
Cached events are also counted as messages.

Messages cost per in-room operation:

Operation Success: Best Case Success: Average Case Success: Worst Case
Create 2
(SuppressRoomEvents=true)
3
+ Join event (SuppressRoomEvents=false, default)
3
Join 2 + k
(SuppressRoomEvents=true)
+ k * cached custom event
2 + n + k
+ n * Join event (SuppressRoomEvents=false, default)
2 + 2 * n + k
+ n * ErroInfo event (HasErrorInfo=true)
Leave 2
(SuppressRoomEvents=true)
1 + n
+ (n - 1) * Leave event (SuppressRoomEvents=false, default)
2 + (n - 1) * 2
+ (n - 1) * ErroInfo event (HasErrorInfo=true)
RaiseEvent 1
(no operation response)
(target: interest group with no subscribers)
1 + n
+ n * custom event
(target: all/broadcast)
2 + 2 * n
+ n * ErroInfo event (HasErrorInfo=true)
+ Auth event (token refresh)
SetProperties 2
Broadcast=false
2 + n
+ n * PropertiesChanged event (default: Broadcast=true, BroadcastPropertiesChangeToAll=true)
2 + 2 * n
+ n * ErrorInfo event (HasErrorInfo=true)
+ 1 in case of CAS or BroadcastPropsChangeToAll

How do I calculate traffic consumed by a user?

This is a complex topic.
First you need to know that any calculation done is just a theoretical estimation and may not reflect reality.
We recommend building a Proof-of-Concept and use it to gather real data.

That being said here is how to estimate traffic generated by a single user inside a room:

Let's assume the following:

  • a room has N players.
  • a player sends F messages per second (message send rate in Hz)
  • average message size is X (in bytes, payload (P) + protocol overhead (O))
  • an average player spends H hours per month on your game

If we do not consider ACKs, connection handling (establishment, keep alive, etc.) commands and resends.
Then we say that on average, a CCU consumes C (in bytes/month) in your game as follows:

C = X * F * N * H * 60 (minutes per hour) * 60 (seconds per minute)

How to quickly rejoin a room after disconnection?

To recover from an unexpected disconnection while joined to a room, the client can attempt to reconnect and rejoin the room.
We call this a "quick rejoin".
A quick rejoin will succeed only if:

  • the room still exits on the same server or can be loaded:
    If a player leaves a room, the latter can stay alive on Photon server if other players are still joined.
    If the player is the last one to leave and the room becomes empty then the EmptyRoomTTL is how long it will remain alive waiting for players to join or rejoin.
    If after EmptyRoomTTL the room is still empty and no one joined then it will be removed from Photon server.
    If persistence conditions are met and webhooks are setup, the room state can be saved on the configured web service to be loaded later.
  • the actor is marked as inactive inside: an actor with the same UserId exists inside the actors' list but not currently joined to the room.
    This requires PlayerTTL to be different from 0.
  • the PlayerTTL for the inactive actor did not expire: when an actor leaves a room with the option to come back we save his Deactivation timestamp.
    As long as the room is alive, if PlayerTTL milliseconds are elapsed after Deactivation time the respective actor is removed from the actors' list.
    Otherwise, when the actor tries to rejoin, if the difference in milliseconds between the time of the rejoin attempt and Deactivation time exceeds PlayerTTL then the actor is removed from the actors' list and the rejoin fails.
    So an inactive actor can rejoin a room only for PlayerTTL milliseconds after Deactivation time.

A "quick rejoin" is composed of two steps:

  • Reconnect: simply call the appropriate connect method once disconnected.
  • Rejoin: call loadBalancingClient.OpRejoin(roomName).

On-Premises

Can I run Photon Server on Linux?

No.
Photon Server is Windows only.
Read the "Requirements" for more details.

How to host Photon Server on Amazon?

Steps to host Photon Server on Amazon:

  1. Setup a new Windows Server EC2 instance
  • Create Amazon Web Services account.
  • Sign in to AWS portal.
  • Go to "Service -> EC2".
  • Click "Launch Instance" under "Create Instance" section.
  • Choose a Microsoft Windows Server edition supported by Photon Server by hitting the corresponding "Select" button.
  • "Choose an Instance Type" then jump to "6. Configure Security Group"
  • Create a new security group "Photon Server" to allow incoming ports as shown in this page.
  • Click "Review and Launch" then review and "Launch".
  • Create or select an existing key pair.
  • Tick the acknowledgment toggle and hit "Launch Instances".
  • Click "View Instances" and wait for instance to finish initialization.
  1. RDP Connect to new instance
  • Choose EC2 instance.
  • Click "Connect".
  • Click "Get Password".
  • Upload private key or copy its content then "Decrypt Password".
  • Get RDP shortcut by clicking "Download Remote Desktop File".
  • Connect to remote machine by double clicking the shortcut.
  • Enter your credentials and log in.
  1. Setup Photon Server SDK
  • Create a Photon account.
  • Download Photon Server SDK.
  • Extract package and copy files to remote machine.
  • Start Photon Control.
  • Install Photon as a service.
  • Start Photon service.
  1. Open Required Ports From Windows Firewall

What is the difference between Plugins SDK and Server SDK?

Both packages provide the same binaries ("deploy" folder) and libraries ("lib" folder) but different source code projects ("src-server").
Photon Server SDK can be used to self-host Photon Server and develop Photon Server applications. The source code inside is for example of server applications.
Photon Plugins SDK can be used to self-host Photon Server and develop custom Photon Server plugins. The source code inside is for plugins examples.

Threading

How many threads are running on a single Photon server?

The use of threads is split:

  1. Native - 9 threads
  2. Managed - based on .Net ThreadPool which uses .NET default settings

This setup has been tested quite intensively and works very well for a great variety of load profiles.

The use of managed threads (as reported by the .NET Windows Performance counters) varies:

a) ~12 on a typical Photon cloud RealTime load
b) 35 (and more) as an example of a customer cloud running a plugin with inter-plugin communication (locking), causing some higher contention (as opposed to our code)

Note: If necessary, .Net ThreadPool settings can be adjusted.
So far we've had good results with the defaults, although they may be different for each version.

How to avoid race conditions and other multithreading issues?

In Photon we did as much as possible to simplify things:

  1. You may use PhotonPeer methods from any thread.
  2. All notifications from PhotonPeer are executed in one fiber (read about fibers below).
  3. All tasks in a room are executed in one fiber.
  4. Peers send messages to room's fibers in order to protect data from multithreading issues.

A fiber is a list of tasks which are executed one by one sequentially in FIFO manner.
This does not mean that they are executed in one thread.
Actually, they are executed in many threads, but one by one.
So the first task may be executed in thread A, when it finishes, the second task may be executed in thread B and so one.
But at every given moment just one thread accesses room data.
In cases when many fibers access same data, we use locks.
For instance, in a room's cache.

You may use fibers as follows:

C#

// rooms contructor
someFiber = new PoolFiber(); // create new fiber
someFiber.Start();
someFiber.ScheduleForInterval(someRepetitiveRoutine, 0, 100); // start immediately and repeat every 100 ms, ie 10 times per second. this params may vary as you need
// at some other point, where you need to add more logic to the fiber
someFiber.Enqueue(newTask);
someFiber.Enqueue(()=>{ anotherTask(parameters);});
// from the tasks you can send messages to the room e.g. to notify the room of a result of a task
room.EnqueueMessage(new YourCustomMessage(somethingToSend));

Remember, if you use multiple custom fibers that share same code or same data, then you need synchronize access because actions in different fibers are executed concurrently.

Logging

How to write a log entry each time a client connects or disconnects?

Add this to your application's log4net.config:

XML


<logger name="Photon.SocketServer.ApplicationBase">
    <level value="DEBUG"/>
</logger>

Output from "{MyApplication}.log":

Successful connect:

2013-05-02 11:19:02,506 [23] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnInit - ConnID=17, IP 127.0.0.1 on port 4530
2013-05-02 11:19:02,506 [23] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnInit - response sent to ConnId 17 with SendResult Ok

Disconnect:

2013-05-02 11:19:07,608 [24] DEBUG Photon.SocketServer.ApplicationBase [(null)] - OnDisconnect - ConnID=17

How to write a log entry when Photon sends an operation response to a client?

Add this to your application's "log4net.config":

XML


<logger name="Photon.SocketServer.PeerBase">
    <level value="DEBUG"/>
</logger>

Output from "{MyApplication}.log":

2013-05-02 11:19:02,569 [21] DEBUG Photon.SocketServer.PeerBase [(null)] - SentOpResponse: ConnID=17, opCode=255, return=0, ChannelId=0 result=Ok size=14 bytes

How to write a log entry when Photon receives an operation request from a client?

This kind of logging is best done in your application's Peer class (which inherits from HivePeer).

XML


<logger name="Photon.Hive.HivePeer">
    <level value="DEBUG"/>
</logger>

Output from "{MyApplication}.log":

2013-05-02 11:19:02,553 [21] DEBUG Photon.Hive.HivePeer [(null)] - OnOperationRequest. Code=255

You can modify the contents of the log entry in OnOperationRequest method.

C#

protected override void OnOperationRequest(OperationRequest operationRequest, SendParameters sendParameters)
{
    if (log.IsDebugEnabled)
    {
        log.DebugFormat("OnOperationRequest. Code={0}", operationRequest.OperationCode);
    }    
    // snip
}

Why are my clients disconnecting? How can I debug timeouts?

To see why your client disconnects, configure your application to write a debug log entry when OnDisconnect is called on your Peer.

XML


<logger name="Photon.Hive.HivePeer">
    <level value="DEBUG"/>
</logger>

In your Peer class (which inherits from HivePeer), your OnDisconnect() method should look like this:

C#

protected override void OnDisconnect(DisconnectReason reasonCode, string reasonDetail)
{
    if (log.IsDebugEnabled)
    {
        log.DebugFormat("OnDisconnect: conId={0}, reason={1}, reasonDetail={2}", this.ConnectionId, reasonCode, reasonDetail);
    }
    //     
}

Output from "{MyApplication}.log":

2013-05-02 11:19:07,639 [12] DEBUG Photon.Hive.HivePeer [(null)] - OnDisconnect: conId=17, reason=ClientDisconnect, reasonDetail=

If you are using UDP: in case of "TimeoutDisconnect", the "reasonDetail" will contain the RoundTripTime history, like this:

index - sequence - rtt - variance - sentTime - recvTime - cmd_rtt

0 - 326 - 0 - 0 - 830717056 - 830728351 - 11295
1 - 325 - 89 - 19 - 830715918 - 830716042 - 124
2 - 324 - 85 - 14 - 830714826 - 830714904 - 78
3 - 323 - 86 - 17 - 830712751 - 830712813 - 62
4 - 322 - 89 - 14 - 830711659 - 830711737 - 78
5 - 321 - 90 - 16 - 830710551 - 830710645 - 94
6 - 320 - 90 - 19 - 830709428 - 830709537 - 109
7 - 319 - 88 - 19 - 830708320 - 830708414 - 94
8 - 318 - 88 - 23 - 830707197 - 830707306 - 109
9 - 317 - 86 - 24 - 830706105 - 830706183 - 78
10 - 316 - 87 - 29 - 830704701 - 830704763 - 62
... etc ... 

Each line consist of these values:

  • Index (0...49, where 0 is latest and 49 is oldest. Only the last 50 entries are shown.)
  • Sequence - an increasing sequence number
  • rtt (RoundTripTime - the current RTT in ms - available after processing the an ACK or a Timeout occurred)
  • variance (current Variance in ms)
  • sentTime (Time when command was sent)
  • recvTime (Time when ACK was recieved)
  • cmd_rtt (Timespan between the time when the command was sent and the ACK was received, in ms)

In the example above, the client had a cmd_rtt between 62ms and 124ms; it was disconnected after no ACK was received for the last command for 11 seconds.

Billing

Do you have special offers for students, hobbyists or indies?

All our products have a free tier and a one-off entry-plan.
We also usually take part in Unity's asset store sales and occasionally give vouchers to lucky ones.

Can I combine more than one 100 CCU plan for a single Photon application?

No.
The 100 CCU plans are not stackable and can be applied only once per AppId.
If you purchase multiple PUN+ asset seats then you must redeem each 100 free CCU for a separate AppId.
If you need more CCU for a single app, the next higher plan is the 500 CCU one.
If you subscribe to a monthly or yearly plan, then you will still keep the 100 CCUs for 12 months on top of / in addition to the CCU from your monthly/yearly plan.

Back to top