Matchmaking API
はじめに
マルチプレイヤーゲームを作る上で重要なことは、同じスキルやレベルのプレイヤー、同じゲームタイプやマップをプレイしたいプレイヤーを簡単にマッチングさせ、ゲーム内の体験を出来るだけ楽しくすることです。
この目的のために、Photon Fusionは、完璧なマッチングを求めるプレイヤーに最高の体験を提供するためのAPIコールを公開しています。
Photon Fusionは、Photon Cloudと透過的に連動しています。Photonバックエンドサービスとのやりとりは、ほとんど内部で自動的に行われます。
このページでは、Fusion Matchmaking APIについて説明します。このAPIは、プレイヤーが希望するゲームプレイ体験に基づいて最適なSessionをフィルタリング/参加するために使用するカスタムプロパティを持つGame Sessionを作成/更新するために使用されます。
用語集
以下は、このドキュメントで使用されている、Matchmaking APIの正しい使い方に直接関係する用語の説明です。
Game Session: または単にSessionは、プレイヤーがマッチをプレイするために集まる場所、またはコミュニケーションをとる場所です。これはPhoton Cloudに公開され、他のクライアントが特定のマッチを検索、フィルタリング、参加できるようにするためのものです。セッションの外でのコミュニケーションは不可能で、どのクライアントも1つのルームでしか活動できません。ゲームセッションは次のようなプロパティとメソッドを持ちます: 名前による作成と参加、カスタムプロパティ、最大プレイヤー数、非表示(Lobbyに表示しない)または表示、閉じる(誰も入れない)または開くことが可能。Lobby:Sessionの仮想的なコンテナまたは "リスト" 。複数のロビーを使って異なるゲームタイプでセッションを分割することも可能です。Fusionでは、ClientServer Mode(Server,Host,Client) でSessionを作成すると、ClientServerという特定のLobbyに作成され、Shared Modeで作成すると、SharedというLobbyに作成されることになります。プレイヤーはLobby内で通信することはできず、他のクライアントがロビーにいることも知ることはできません。クライアントは、Lobby、Session、またはそのいずれかにのみ参加することができます。
ゲームセッションの作成と参加
Game Session の作成と参加は同じ手続きの2部構成になっており、そのルールは単純です。
1. 指定した SessionName を持つ Session が存在しない場合、その SessionName で新しいセッションを作成します (以下に説明するように、すべての場合ではありません)
2. ピアがその SessionName を持つセッションに参加する。
APIに関しては、新しいFusion Simulationが開始されると、これら全てが自動的に行われます。新規にセッションを作成する際に、セッションをカスタマイズするために使用できる主な引数は、以下のとおりです。
C#
NetworkRunner.StartGame(new StartGameArgs {
// other args...
SessionName = [string]
SessionProperties = [Dictionary<string, SessionProperty>],
CustomLobbyName = [string],
PlayerCount = [int],
DisableNATPunchthrough = [bool],
CustomSTUNServer = [string],
AuthValues = [AuthenticationValues],
DisableClientSessionCreation = [bool]
});
Game Sessionに関連するすべての引数は任意であり、それぞれのデフォルト値は以下のとおりです。
- SessionName:
Game Sessionの名前です。Photon Cloud上でセッションを識別し、Region内で一意である必要があります。 デフォルトでは、Nameが設定されていない場合、Fusionはセッションを識別するためにランダムなGUIDを生成します。2つのケースが考えられます。
特定の
SessionNameで開始すると、Fusion は 常に そのNameを持つSessionを作成/参加させようとします。これはFusionの重要な要素です。クライアントピアはセッションを作成することができ、(これをlate-join-serverと呼びます)サーバはクライアントが作成したセッションに事前に参加することができます。SessionNameを指定しない場合、Fusion はHost,Server,Sharedゲームモードで起動した場合のみ、新しいセッションを作成/参加し、Clientモードで起動した場合はランダムなSessionに参加しようと試みます。
- SessionProperties:
SessionのCustom Propertiesは、ゲームモード/タイプや現在読み込まれているマップなど、Game Sessionに関するメタデータを含める方法です。このプロパティはSessionを作成する際に、常にSession Lobbyに公開されることを覚えておいてください。この引数のもう一つの使い方は、ClientがランダムなSessionに参加する際のマッチングフィルターとして使用します。トラフィックを最小限にするために、常にProperties Keysの文字列をできるだけ短く保つようにしてください。デフォルトでは、Session Custom Propertiesは空で、余分な情報は含まれていません。 - CustomLobbyName:
Lobbyとは、似たようなGame Sessionsを集約するためのもので、例えば異なるゲームタイプのセッションを分離するために使用することができます。この引数で、Sessionが関連付けられるカスタムLobby Nameを設定します。デフォルトでは、Fusion はGameModeに基づいてSessionを分離します。SessionがHost,Server,Clientゲームモードで作成された場合はClientServer Lobbyで、Sharedゲームモードで作成された場合はShared Lobbyで分離されます。 - PlayerCount: この
Sessionに接続できるクライアントの最大人数を定義します。このパラメータは新しいSessionを作成するときのみ使用され、デフォルトではNetworkProjectConfig/SimulationのDefault Players設定で設定された値が使用されます。 - DisableNATPunchthrough: Photon Fusionに実装されているNATパンチスルーシステムを無効にするためのブーリアンフラグです。これにより、クライアントとサーバ間で中継された接続が行われるようになります。ゲームサーバに
trueを設定すると、全てのクライアントがリレー接続され、Clientに設定すると、特定のピアだけがリレー接続されます。 - CustomSTUNServer: ピアのリフレクティブアドレスを解決するために使用するカスタムSTUNサーバーを指定します。
- AuthValues: 外部サービスを使用してピアを認証するために使用されるカスタム認証値です。認証は、
Photon Dashboardで特定のApplication IDに対して事前に設定されたサービスを使用して行われます。 - DisableClientSessionCreation:
Clientとして起動するピアが、SessionNameを指定しても新しいSessionを作成しないようにするためのブール型フラグです。デフォルトでは、クライアントはSessionを作成し、Serverが参加するのを待つことができますが、このフラグを使用すると、この動作を無効にすることができます。
このAPIでは、ランダムに、あるいは特定の SessionName で Game Session を作成して参加することができます。これは、たとえば Game Invitation を受け取ったときに使用することができますが、カスタムプロパティを使用して Session をフィルタリングし、特定の構成のゲームにのみ参加することもできます。
これにより、セッションを管理する際の柔軟性が格段に向上します。
以下の表は、シミュレーション開始時の SessionName と GameMode に依存する Game Session の作成と参加について、Fusionがどのように処理するかをまとめたものです。
| 有効なセッション名 | ゲームモード | 動作 |
|---|---|---|
| はい | ホスト/サーバー | セッションを作成する |
| クライアント | セッションに参加する、見つからない場合は失敗する | |
| 共有 | セッションに参加する、見つからない場合は作成する | |
| いいえ | ホスト/サーバー | ランダムな名前でセッションを作成する |
| クライアント | ランダムなセッションに参加する、見つからなければ失敗 | |
| 共有 | ランダムなセッションに参加する、見つからない場合はランダムな名前でセッションを作成する |
ゲームセッション情報の取得と更新
Fusion では、現在接続している Game Session の Name や Region など、様々な情報を提供しています。
これらのデータは、NetworkRunnerの SessionInfo プロパティから直接取得することができます。
以下に、SessionInfo タイプで利用可能な全ての欄を示します。
IsValid [bool{get}]:SessionInfoが読み込み/書き込みの準備ができているかどうかを示す。Name [string{get}]:セッション名Region [string{get}]: 現在接続しているRegionProperties [Dictionary<string, SessionProperty>{get}]: 現在のSession Custom Propertiesを含む読み込み専用の辞書。これらのプロパティを更新するには、SessionInfo.UpdateCustomProperties(Dictionary<string, SessionProperty>)メソッドを使用して、新しいプロパティセットを渡してください。IsVisible [bool{get,set}]:SessionがLobby上でVisibleであるかどうかのシグナルを返します。セッションを不可視にするには、このプロパティを変更するだけです。IsOpen [bool{get,set}]:SessionがOpenで参加できるかどうかのシグナルです。セッションを閉じたり開いたりするには、このプロパティを変更するだけでよい。PlayerCount [int{get}]:Sessionにいる現在のPlayersの数です。ロビーでのみ利用可能です。MaxPlayers [int{get}]:セッションに参加できるピアの最大数です。この値にはサーバー/ホストピアのスロットも含まれます。*ロビーでのみ利用可能です。
Session情報と、主に Custom Properties は、Matchmaking の目的のみに使用し、ゲームクライアントとゲームの状態を同期させるtためには **決して ** 使用しないでください。そのような使い方は非常にお勧めできません。
ゲームプレイに関連する情報をセッション全体で交換する必要がある場合、Fusionには、グローバルなNetworkObjectを用意したり、ワンショットのデータにはRPCを使用するなど、様々なオプションが用意されています。
また、NetworkRunnerは、ゲーム内で使用できる Session や Photon Cloud 関連のプロパティもいくつか提供しています。例えば:
NetworkRunner.IsCloudReady: ローカルピアがPhoton Cloudに接続し、ルームの作成/参加やロビーへの参加が可能かどうかのシグナル。NetworkRunner.UserId: 認証されたローカルピアのUserIdを保持。この情報は、アプリケーションで使用される認証サービスから取得されます。NetworkRunner.AuthenticationValues: Fusionの起動時にローカルピアの認証に使用されたAuthenticationValuesのリファレンスを保持。NetworkRunner.CurrentConnectionType: ピアが現在使用している Connection Type を記述します。リモートのServerとの接続はDirectまたはRelayedです。SharedModeでは、クライアントは常にリレー経由で接続することに留意してください。NetworkRunner.NATType: NAT Punchthrough Systemが有効な場合、Fusionはローカルピアが動作しているネットワークの現在のNAT Typeを判断しようとします。NAT タイプは、Invalid、UdpBlocked、OpenInternet、FullConeまたはSymmetricです。NetworkRunner.IsSharedModeMasterClient: ローカルピアがShared Game SessionのMaster Clientでもあるかどうかを表すブーリアンフラグです。これはSharedModeで動作しているときのみ有効で、他のクライアントとMaster Clientの区別に基づいて、どのピアで特定のアクションを発生させるかを決定するために使用することができます。
ロビーからゲームセッションに参加する
正しいGame Sessionを見つけるもう一つの方法は、Sessionsのリストを提供し、プレイヤーが参加するセッションを選択できるようにすることです。
この場合、ロビーに参加するのが良い方法ですが、必要でない場合はこの方法を使わないことをお勧めします。
ほとんどのゲームタイプでは、プロパティフィルタに基づいたSessionへの参加が最適ですが、FusionではSession Listingも簡単に行うことができます。
通常のフローを使い、上記のようにFusionを起動するのではなく、Session Listingは少し違ったフローをたどります。
- Join a Lobby: Fusion Runner のリファレンスを使い、
NetworkRunner.JoinSessionLobby(SessionLobby, [string])をコールするだけで、ローカルピアが Photon Cloud に接続し、特定のLobbyに入室できるようにします。このメソッドは2つの引数を受け取ります。
SessionLobby: 以下の値のいずれかを指定することができます。ClientServerで、デフォルトのClientServer Lobbyに参加。
2.SharedはデフォルトのShared Lobbyに参加。Customは、Custom Lobby Nameと共に使用。
LobbyName: これは以前のGame Sessionを作成するときに使用したCustom Lobby Nameであるべきです。
- ゲームセッションのリストを取得する: Fusion を使う場合、主な API エントリポイントの一つは
INetworkRunnerCallbacksで、これは Fusion がLobbyからのセッションリストを含む一連の異なるイベントを表示するために使用する特別なインターフェースです。OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList)コールバックは、セッションの作成/削除やセッションのプロパティが更新されるなど、セッションのリストが変更されるたびに呼び出されます。SessionInfoは上記と同じタイプです。その後、リストの表示、フィルタリング、順序付けなどを行うことができます。 - Join a Session: 参加する
Sessionを選択すると、通常のNetworkRunner.StartGame()を使って Fusion を起動することができますが、この場合、クライアントの起動に使うSessionNameはセッションのものでなければなりません。そうすれば、Clientはこの特定のGame Sessionに参加することになります。- 通常通り、正しい
GameModeを選択します。ピアはSessionに参加するので、GameMode.ClientまたはGameMode.Sharedモードのどちらかでなければなりません。
- 通常通り、正しい
SessionName欄にはSessionInfo.Nameを設定する必要があります。これはGame Sessionの識別子となるためです。- 他のすべてのパラメータは任意で、例えば
SceneObjectProviderのように、適宜初期化する必要があります。
APIの使用例
ランダムセッションにジョインする
セッションにジョインするためには(プレイヤーがゲームにさっとジョインする場合)、NetworkRunnerを開始して、パラメータを加えずに利用可能なGame Sessionを探します。
C#
public async Task StartPlayer(NetworkRunner runner) {
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.AutoHostOrClient, // or GameMode.Shared
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
こうすることで、ローカルピアがランダムなGame Sessionを開始して接続できるようになります。何も見つからない場合は、ランダムなSession Nameで新しいセッションが作成されます(GameMode.AutoHostOrClientを使用しているため)。Sharedモードのセッションでも、GameMode.Sharedを使用してNetworkRunnerを起動していた場合、こちらは有効です。
カスタムプロパティで新しいゲームセッションを開始する
この例では、Hostがいくつかのカスタムプロパティを持つ Game Session を作成します。後で Clients がこれらのプロパティを使用して Sessions をフィルタリングすることができます。
C#
// Some predefined types used as values for the Game Session Properties
public enum GameType : int {
FreeForAll,
Team,
Timed
}
public enum GameMap : int {
Forest,
City,
Desert
}
// Utility method to start a Host using a defined GameMap and GameType
public async Task StartHost(NetworkRunner runner, GameMap gameMap, GameType gameType) {
var customProps = new Dictionary<string, SessionProperty>();
customProps["map"] = (int)gameMap;
customProps["type"] = (int)gameType;
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Host,
SessionProperties = customProps,
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
サンプルコードでは Game Session の Custom Properties の値に Enums を使用していますが、これは値に意味を持たせるための一つの方法に過ぎません。
Runner.StartGame をHostとして呼び出す (GameMode = GameMode.Host) だけで、Random Name (SessionName 引数が渡されなかったため) で新しいセッションが開始され、SessionProperties 引数を使用すると、Fusion は Session にそれらのプロパティを含めることができます。
フィルタを使ってランダムセッションに参加する
上記のサンプルコードから、特定のGameTypeを持つ、任意のGameMap上の任意のゲームセッションに参加するClientを起動する方法を説明します。
スタートアップのコードは基本的に同じで、GameModeが GameMode.Client に設定され、customPropsには type キーと希望の gameType 値のみが含まれています。
C#
public async Task StartClient(NetworkRunner runner, GameType gameType) {
var customProps = new Dictionary<string, SessionProperty>() {
{ "type", (int)gameType }
};
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Client,
SessionProperties = customProps,
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
これだけで、クライアントはその特定の GameType のランダムな Session に参加できるようになります。
ロビーからセッションに参加する
Fusionをすぐに起動するのではなく、LobbyからSessionを取得するには、別のメソッドセットが必要です。
以下のサンプルコードでは、Fusion Runner が Photon Cloud に接続し、あらかじめ定義された ClientServer ロビーに参加するようにしています。
C#
// Utility method to Join the ClientServer Lobby
public async Task JoinLobby(NetworkRunner runner) {
var result = await runner.JoinSessionLobby(SessionLobby.ClientServer);
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
また、前述したように、この方法で ClientServer, Shared, Custom ロビーに Client が参加することが可能です。
以下のように、サーバ/ホストが Custom ロビーで Session を作成する場合です。
C#
public async Task StartHost(NetworkRunner runner) {
var result = await runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Host,
CustomLobbyName = "MyCustomLobby"
});
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
Client の Join Lobby リクエストを変更する必要があります。
C#
// Utility method to Join a Custom Lobby
public async Task JoinLobby(NetworkRunner runner) {
var result = await runner.JoinSessionLobby(SessionLobby.Custom, "MyCustomLobby");
if (result.Ok) {
// all good
} else {
Debug.LogError($"Failed to Start: {result.ShutdownReason}");
}
}
接続が確立すると、Fusion Runner は登録された全ての INetworkRunnerCallbacks に対して OnSessionListUpdated コールバックを呼び出します。
以下に、リストの最初の Session に参加する方法を示すサンプルコードがあります。
C#
public class MyBehaviour : Fusion.Behaviour, INetworkRunnerCallbacks {
// other callbacks...
// Receive the List of Sessions from the current Lobby
public void OnSessionListUpdated(NetworkRunner runner, List<SessionInfo> sessionList) {
Debug.Log($"Session List Updated with {sessionList.Count} session(s)");
foreach (var session in sessionList) {
Debug.Log($"Joining {session.Name}");
// This call will make Fusion join the first session as a Client
runner.StartGame(new StartGameArgs() {
GameMode = GameMode.Client, // Client GameMode
SessionName = session.Name, // Session to Join
SceneObjectProvider = GetSceneProvider(runner), // Scene Provider
DisableClientSessionCreation = true, // Make sure the client will never create a Session
});
return;
}
}
}
Back to top