This document is about: QUANTUM 2
SWITCH TO

Game Services

Overview

A game service is a global, independent system which aims to solve one major problem / feature requirement in the game. All game services implement IGameService and there is always exactly one instance per service in use. All services live throughout the application lifetime; some of them rely on other services.

Network

The Network service maintains the connection to the Quantum application in a specific region and provides an extra layer on top of LoadBalancingClient of Photon Realtime.

The connection is maintained with a best-effort approach; as soon as the network client gets disconnected, the service tries to reconnect. The Network service only starts and stops upon receiving an explicit request.

API

  • Connect(): connects to Photon Realtime with a specific AppID, Version, Region, UserID
  • Disconnect(): disconnects from Photon Realtime
  • Pause(): pauses the service and keeps the connection alive by sending ack packets on the background thread. This has to be called before loading a scene.
  • Unpause(): resumes the sending and receiving of commands from the Network service. This has to be called after a scene has finished loading.

Messages

The Messages service maintains connection to the Photon Chat application in a specific region and provides an extra API for sending and receiving typed messages. The connection is maintained with a best-effort approach; as soon as the network client gets disconnected, the service tries to reconnect. The Messages service only starts and stops upon receiving an explicit request.

The servises comes with support for 2 types message from which new type can be derived:

  • PrivateMessage, this message is intended to be sent directly to a specific Photon User.
  • ChannelMessage, this message is intended to be sent / shared with an entire Photon Chat channel.

API

  • Connect(): connects to Photon Chat with a specific AppID, Version, Region, UserID
  • Disconnect(): disconnects from Photon Chat
  • Subscribe(): subscribes to a specific Photon Chat channel
  • Unsubscribe(): unsubscribes from a specific Photon Chat channel
  • SetProperties(): sets the properties of a specific Photon Chat channel
  • AddFriends(): receive status updates for these players
  • RemoveFriends(): stop receiving status updates for these players
  • CanChatInChannel(): returns true if you can chat in a specific Photon Chat channel
  • TryGetChannel(): returns Photon Chat channel
  • SendMessage(): sends a private or channel message to a receiver
  • Flush(): immediately send all outgoing commands
  • Pause(): pauses the service and keeps the connection alive by sending ack packets on the background thread. This has to be called before loading a scene.
  • Unpause(): resumes the sending and receiving of commands from the Network service. This has to be called after a scene has finished loading.

Example

This section present several examples on use the Messages service.

Private Message

C#

IMessage message = new PrivateMessages.Text("This is a private message");
Game.Services.Messages.SendMessage(message, "targetUserID");

Channel Message

C#

IMessage message = new ChannelMessages.Text("This is a channel message");
Game.Services.Messages.SendMessage(message, "targetChannelName");

Custom Message definition

Custom message definitions can be created by deriving from one of the base classes (PrivateMessage or ChannelMessage). The snippet below shows how to create a new type deriving from ChannelMessage.

C#

public static partial class CustomMessages
{
    public sealed class Emote : ChannelMessage
    {
        public string EmoteID { get; private set; }

        public Emote(string emoteID) {
            EmoteID = emoteID;
        }

        private Emote() {}

        protected override object Serialize() {
            return EmoteID;
        }

        protected override void Deserialize(object data) {
            EmoteID = (string)data;
        }
    }
}

Lobby

The Lobby service relies on the Messages service and is backed by a Photon Chat channel. The service provides a connection to a single lobby identified by a string. Players can send lobby messages and set their own custom properties in the LobbyPlayerData structure which is available to all other players in the same lobby.

Note: A single lobby is limited to 1000 players.

API

  • Join(): joins a specific lobby. If no lobby is specified it will join the default lobby, or create it if does not already exist.
  • Leave(): leaves current lobby
  • SetSynchronizationInterval(): sets the interval at which players synchronize the lobby's data and state.
  • GetPlayerData(): returns LobbyPlayerData of a specific player
  • GetLocalPlayer(): returns local LobbyPlayer
  • SendMessage(): sends a lobby message (must be a type deriving from ChannelMessage)

Party

The Party service relies on the Messages service and is backed by a Photon Chat channel. The service provides a basic party system. The party is identified by a string. You can send party messages and set custom player properties in the PartyPlayerData structure which is available to all other players in the same party. The player who creates the party can also set the maximum size of it.

The party always has one party leader (by default the player who creates the party). The party leader is the player who maintains it. The leader can promote another players (and demote themself) at any time. If the leader gets disconnected, other players will immediately try to take the leadership.

Note: The party system is fully client driven and the code is not burdened with security checks. Keep this in mind as it makes the solution cheatable.

API

  • AutoAcceptJoinRequest: automatically joins the party received in a Join message. True by default.
  • AllowRemotePlayerDataChange: allows to change other players data. False by default.
  • PlayerInviteTimeout: timeout of a pending invite request. 15s by default.
  • PlayerKickTimeout: the length of time until a disconnected player is kicked from the party. 30s by default.
  • Create(): creates a party with specific party ID
  • Join(): joins a party with specific party ID
  • Leave(): leaves current party
  • Invite(): invites another player to the party. The target player must have connected via the Messages service to receive the invitation.
  • Kick(): kicks a specific player from the party
  • SetLeader(): promotes another player to leader
  • SetPlayerSlot(): sets party slot of a specific player
  • ExchangePlayerSlots(): exchange party slots of 2 specific players atomically
  • GetPlayerData(): returns PartyPlayerData of a specific player
  • GetLocalPlayer(): returns local PartyPlayer
  • SendMessage(): sends a party message (must be a type deriving from ChannelMessage)

PartyPlayer Properties

  • UserID: unique for each player
  • Status: connected / disconnected
  • Slot: unique position within the party
  • Data: instance of PartyPlayerData with custom properties

MatchMaking

The Matchmaking service relies on Network and Messages services, is responsible for finding a specific / random match based on given parameters and keeps the player connected to the match with best-effort approach. The service operates with Match, MatchRequest and MatchConfig data structures.

API

MatchRequest

  • Mode: match request mode, currently supported are Join, Create, JoinOrCreate, JoinRandom, CreateRandom, JoinOrCreateRandom
  • Room: name of the room, mandatory for Join, Create and JoinOrCreate modes
  • Plugin: name of the Photon Realtime server plugin, default is “QuantumPlugin”
  • IsOpen: initial open state of the room, default is true
  • IsVisible: initial visibility state of the room, default is true
  • IsSpectator: set if the joining player is spectating (not participating in gameplay), default is false
  • AutoStart: if true, the match will be automatically started if the room is full, there are at least [MinStartPlayers] non-spectating players or after [Timeout], default is true
  • MinStartPlayers: minimum non-spectating players for the match to be automatically started (only if [AutoStart] is true), default is 0 (all players required)
  • ExpectedPlayers: number of expected players participating in gameplay, mandatory for Create, JoinOrCreate, CreateRandom and JoinOrCreateRandom modes
  • ExtraSlots: number of extra slots for players not participating in gameplay, default is 0
  • MatchTTL: how long empty room stays alive before destroyed, default is 0
  • PlayerTTL: how long player stays inactive in the room before disconnected, default is 0
  • FillTimeout: time limit for filling all room spots, the match is automatically started when reached (only if [AutoStart] is true), default is 0 (infinite timeout)
  • Config: MatchConfig instance with custom data
  • PlayerProperties: custom player properties which are set upon joining the room
  • ExpectedRoomProperties: only rooms with these properties will be selected, valid for JoinRandom and JoinOrCreateRandom modes
  • RoomProperties: custom properties which the room will be created with, valid for Create, JoinOrCreate, CreateRandom and JoinOrCreateRandom modes
  • RoomPropertiesForLobby: list of property keys, properties with these keys will be exposed to all users in Realtime lobby
  • ExpectedUserIDs: list of users expected to join the same room, this will reserve spots for all players and find only rooms with enough free spots, typically filled with party members, local player is always set as expected user
  • MatchmakingMode: defines matchmaking rules, default is FillRoom
  • TypedLobby: lobby type, default is TypedLobby.Default
  • SQLLobbyFilter : SQL filter used in combination with LobbyType.SqlLobby

Match

  • UpdateConfig: callback, executed before the match is started, intended for making final changes in MatchConfig
  • Connected: callback, executed when the player connects to a room
  • Reconnected: callback, executed when the player reconnects to the room after unexpected disconnect
  • Disconnected: callback, executed on unexpected disconnect
  • Updated: callback, executed every frame until the match is started
  • Started: callback executed when the match is started
  • Start(): explicit command to start the match, ignored if the match is already started

Matchmaking

  • Run(): starts matchmaking process for given Match / MatchRequest
  • Leave(): leaves current Match

Match Process Flow

Following diagram shows simplified process from match request to match start:

fps template match request flow diagram
FPS Template Match Request Flow Diagram.

The Matchmaking service is designed with robustness in mind, the matchmaking process should survive disconnection of any player at any time unless all players are disconnected and the room is disposed. This includes processing of party members. Evaluation of start conditions and decision when the match starts is always done by the master client. He also periodically checks for missing expected users and invites them via private message.

Remote Settings

The RemoteSettings service allows you to fetch settings from a remote server. It is backed by the Unity Remote Config.

API

  • IsLoaded: indicates if the config is already fetched from Remove Config server
  • Loaded: callback, executed when the config is fetched
  • Load(): fetch config for given User ID and and Environment ID
  • GetBool(): returns a bool value from Remote Config
  • GetInt(): returns an int value from Remote Config
  • GetFloat(): returns a float value from Remote Config
  • GetString(): returns a string value from Remote Config

Scene Loader

The SceneLoader service is responsible for initialization, deinitialization and switching Unity scenes. The FPS Template supports scene switching in the background by additively loading a loading scene in the foreground while the main scene is being loaded in the background.

Following diagram illustrates the process:

fps template scene loading
Scene Loading.
  1. SceneManager.LoadSceneAsync(LoadingScene): the scene ( LoadingScene ) is additively loaded; nothing should be visible by default to prevent visual glitches
  2. SceneLoadingDirector.Initialize(): this is used to mark all important object with DontDestroyOnLoad to prevent an invalid state of the main scene loading at later point
  3. SceneLoadingDirector.Activate(): in this coroutine the main scene is hidden by an UI or similar effects, the loading process continues after the coroutine finishes
  4. SceneDirector.Deinitialize(): the current scene ( MenuScene ) is deinitialized
  5. SceneManager.LoadSceneAsync(GameScene): the GameScene is loaded and replaces MenuScene
  6. Resources.UnloadUnusedAssets(): cleanup resources used by MenuScene
  7. SceneDirector.Initialize(): the current scene ( GameScene ) is initialized. Note: this method is a coroutine, thus allowing to postpone the loading process as long as needed
  8. SceneLoadingDirector.Deactivate(): in this coroutine the loading UI is hidden and the main scene becomes visible
  9. SceneLoadingDirector.Deinitialize(): cleanup of LoadingScene objects which were marked with DontDestroyOnLoad
Back to top