Realtime Intro

en-us

Get Started

Photon Realtime is a fully managed service (SaaS) of Photon on-premises servers running in regions worldwide, ready for low latency multiplayer gaming around the globe, anytime.

Use the LoadBalancing API to match players to a shared game session (called "room") and transfer messages synchronously, in real-time, between connected players across platforms. All client SDKs can interact with each other, no matter if iOS, Android, web, console or standalone.

Connect

Photon Realtime applications need an AppId to connect to. Get yours from the Realtime Dashboard after free signup.

Simply set your AppId and pick a region to connect to. Click here for a list of available regions.

Call Service

The LoadBalancing API is built to integrate well with your game logic. You can fine-control when you want to handle incoming messages and how often you send anything. Internally, both directions are buffered until your game calls LoadBalancingClient.Service().

Games often use a game loop which calculates updates and then refreshes the screen. Call Service() 10 to 20 times per second. If you don't call it, no "network progress" gets done at all.

Disconnect

When the application is quitting or when the user logs out do not forget to disconnect.

Matchmaking

Create a Game

To create a new room, aka game, invoke "Create Room" operation on your connected LoadBalancing client.

    void MyCreateRoom(string roomName, byte maxPlayers)
    {
        this.OpCreateRoom(roomName, new RoomOptions() { MaxPlayers = maxPlayers }, TypedLobby.Default);
    }
    void createRoom(const ExitGames::Common::JString& roomName, nByte maxPlayers)
    {
        mLoadBalancingClient.opCreateRoom(roomName, ExitGames::LoadBalancing::RoomOptions().setMaxPlayers(maxPlayers));
    }

This sets the room name and amount of players that are allowed in the room. The client will enter the new room automatically. When using "Create Room" operation the room will be created before joining, if it doesn't exist. Rooms exists until the last player leaves.

You can define "Custom Room Properties" to set shared values for the room when you create it. The custom room properties can be used (e.g.) to store the map name, level or the round duration. The keys of Custom Properties have to be strings. Of course those values can be set and modified in the room as well.

You can select any of your custom properties to be shown also in the lobby, by setting the optional array with their names as "Custom Room Properties For Lobby". Properties showing in the lobby can be used for matchmaking and as filter for random matches.

Read more about matchmaking in our guide here.

Find a Game

Clients join games by name or ask Photon to find a perfect match.

Find rooms ...

  • by Random: Matches players randomly. Optionally fills rooms or distributes players evenly.
  • Use Filters in random matchmaking for better matching.
  • by Listing: The lobby lists visible rooms to let players pick and join manually.
  • that are Private: Join hidden rooms that you know the name of.
  • or Parameterized: Customize random matching by defining expected properties.

    // join random rooms easily, filtering for specific room properties, if needed
    Hashtable expectedCustomRoomProperties = new Hashtable();

    // custom props can have any name but the key must be string
    expectedCustomRoomProperties["map"] = 1; 

    // joining a random room with the map we selected before
    this.OpJoinRandomRoom(expectedCustomRoomProperties, (byte)expectedMaxPlayers);
    // join random rooms easily, filtering for specific room properties, if needed
    ExitGames::Common::Hashtable expectedCustomRoomProperties;

    // custom props can have any name but the key must be string
    expectedCustomRoomProperties.put(L"map", 1); 

    // joining a random room with the map we selected before
    mLoadBalancingClient.opJoinRandomRoom(expectedCustomRoomProperties);

Persist Games

With Photon Realtime, rooms' data can be saved and loaded easily. You need to setup webhooks to hook up Photon Cloud with an external web server.

Once setup, room states will be saved automatically for you. To rejoin rooms:

    this.OpReJoinRoom(savedRoomName);
    mLoadBalancingClient.opJoinRoom(savedRoomName, true);

This feature makes asynchronous matchmaking and gameplay possible.

Read more about how to do this in our Persistence Guide.

Gameplay

Sending Events

Whatever happens on one client can be sent as event to update everyone in the same room.

Update your players with stats, positions or your current turn. Photon will send it as fast as possible (with optional reliability).

  • Send messages/events: Send any type of data to other players.
  • Player/Room properties: Photon updates and syncs these, even to players who join later.

    byte eventCode = 1; // make up event codes at will
    Hashtable evData = new Hashtable();    // put your data into a key-value hashtable
    bool sendReliable = false; // send something reliable if it has to arrive everywhere
    this.OpRaiseEvent(eventCode, evData, sendReliable, RaiseEventOptions.Default);
    nByte eventCode = 1; // use distinct event codes to distinguish between different types of events (for example 'move', 'shoot', etc.)
    ExitGames::Common::Hashtable evData; // organize your payload data in any way you like as long as it is supported by Photons serialization
    bool sendReliable = false; // send something reliable if it has to arrive everywhere
    mLoadBalancingClient.opRaiseEvent(sendReliable, evData, eventCode);

Your event codes should stay below 200. Each code should define the type of event and the content it carries.

The event data in the example above is a Hashtable. It can be a byte[] or basically any data type supported by Photon's serialization (a string, float[], etc.). See Serialization in Photon for more information.

Receiving Events

Whenever an event is dispatched a handler is called. An example is shown below.

    public override void OnEvent(EventData photonEvent)
    {
        // important to call, to keep state up to date
        base.OnEvent(photonEvent);
        // we have defined two event codes, let's determine what to do
        switch (photonEvent.Code)
        {
            case 1:
                // do something
                break;
            case 2:
                // do something else
                break;
        }
    }
    void NetworkLogic::customEventAction(int playerNr, nByte eventCode, const ExitGames::Common::Object& eventContent)
    {
        // logging the string representation of the eventContent can be really useful for debugging, but use with care: for big events this might get expensive
        EGLOG(ExitGames::Common::DebugLevel::ALL, L"an event of type %d from player Nr %d with the following content has just arrived: %ls", eventCode, playerNr, eventContent.toString(true).cstr());

        switch(eventCode)
        {
        case 1:
            {
                // you can access the content as a copy (might be a bit expensive for really big data constructs)
                ExitGames::Common::Hashtable content = ExitGames::Common::ValueObject<ExitGames::Common::Hashtable>(eventContent).getDataCopy();
                // or you access it by address (it will become invalid as soon as this function returns, so (any part of the) data that you need to continue having access to later on needs to be copied)
                ExitGames::Common::Hashtable* pContent = ExitGames::Common::ValueObject<ExitGames::Common::Hashtable>(eventContent).getDataAddress();
            }
            break;
        case 2:
            {
                // of course the payload does not need to be a Hashtable - how about just sending around for example a plain 64bit integer?
                long long content = ExitGames::Common::ValueObject<long long>(eventContent).getDataCopy();
            }
            break;
        case 3:
            {
                // or an array of floats?
                float* pContent = ExitGames::Common::ValueObject<float*>(eventContent).getDataCopy();
                float** ppContent = ExitGames::Common::ValueObject<float*>(eventContent).getDataAddress();
                short contentElementCount = *ExitGames::Common::ValueObject<float*>(eventContent).getSizes();
                // when calling getDataCopy() on Objects that hold an array as payload, then you must deallocate the copy of the array yourself using deallocateArray()!
                ExitGames::Common::MemoryManagement::deallocateArray(pContent);
            }
            break;
        default:
            {
                // have a look at demo_typeSupport inside the C++ client SDKs for example code on how to send and receive more fancy data types
            }
            break;
        }
    }

Each event carries its code and data in the way your client sent them. Your application knows which content to expect by the code passed (see above).

For an up-to-date list of default event codes look for the event codes constants in your SDK, e.g. within ExitGames.Client.Photon.LoadBalancing.EventCode for C#.

Custom or Authoritative Server Logic

As is, without authoritative logic, Photon Cloud products already allow for a broad range of game types.

  • First Person Shooters
  • Racing Games
  • Minecraft type of games
  • Casual real-time games
  • Asynchronous and synchronous games
  • ...

Use Photon Server or Photon Plugins to implement your own custom logic.

 To Document Top