This document is about: QUANTUM 2
SWITCH TO

オンラインセッション

概要

Quantumのオンラインサービスは、Photonのオンラインインフラ(Photon Realtime)の上に構築されています。オンラインセッションへの接続は、通常3つの接続フェーズを経て行われます。

  1. カスタム認証:
    Photonはプレイヤーアカウントを提供していないため、独自またはサードパーティの認証プロバイダを使用してログインを確保し、Photonカスタム認証を設定することを推奨します。
  2. ゲームサーバー接続:
    オンラインシミュレーションを始める前に、クライアントはPhoton Cloudに接続し、Photon Realtime libraryを使用してルームに入る必要があります。
    初歩的なランダムマッチングを含む手順は、SDKのDemoMenuとOfficial Photon Realtime doc Photon Matchmaking And Lobbyに記載されています。
  3. Quantumシミュレーションの開始シーケンス:
    この段階では、Quantumシミュレーションの開始、クライアントの設定データの送信、Quantumセッションの参加とクライアント間の同期が行われます。

Quantumオンラインセッションの開始方法

Starting Online Session: Connection Sequence
オンラインセッションを開始:Photonに接続

参考資料

デモメニュー

SDKに含まれる DemoMenu は、その完全なプロセスを示しています。個々のUIクラス(UIConnect, UIConnecting, UIReconnecting, UIRoom, UIGame)をステートマシンとして捉えると、よく理解できます。上の図と類似していることがわかります。

  • プレイヤーはボタンを押してPhoton Cloudに接続し、ランダムなマッチメイキングを使用して最終的にPhoton Roomに参加します。
  • 他のプレイヤーを待った後、ボタンを押すとゲーム開始の合図があり、プレイヤーはそれぞれQuantumセッションを開始します。
  • プレイヤーは、切断ボタンを押すか、Unityエディタを停止するか、アプリケーションを再起動して、再接続ボタンを使って、同じゲームセッションに戻ることができます。
Demo Menu
デモメニューのフローチャート

UIConnect

DemoMenuを使い始めるにあたって、便利な開発ツールにするためのいくつかの要素がありますが、コードが読みにくくなることもあります。例えば、RegionDropdownAppVersionDropdownです。

RegionDropdown

スクリプト可能なアセット (Photon/QuantumDemo/Menu/Resources/PhotonRegions.asset) があり、メニュー実行時に素早くリージョンを変更するためにドロップダウンで選択できるリージョンのセットが含まれています。LastSelectedRegionPlayerPrefs 内に保存されています。

AppVersionDropdown

AppVersion (接続時に AppSettings で設定) は、マッチメイキングを行う際にユーザーを区別するためのものです。これは、同じAppIdを使用するライブゲームに使用できますが、テスト/開発中にも使用できます。この実装は、2つのケースをカバーしています。

  • 開発者は、自身のマシンでアプリを複数回実行し、他の人が自分のゲームに参加することを望まない場合があります。この場合、Photon/QuantumDemo/Menu/Resources/PhotonPrivateAppVersion.asset に格納されている Guid を使用した Private AppVersion の使用をお勧めします(バージョン管理から除外されます)。自分のマシンでビルドされたものだけが一緒に遊べます。
  • フォーカステストやQAテストでは、特定のグループに所属する必要があります。Photon/QuantumDemo/Menu/Resources/PhotonAppVersions.assetにリストされた名前はメニューのドロップダウンリストから選択できます。

AppSettings

Photon Cloud に接続するには、AppSettings という設定が必要です。Quantumとの統合では、通常シングルトンパターンでアクセスします: PhotonServerSettings.Instance.AppSettings もちろん、正しいデータを注入する別の方法で交換することができます。

設定オブジェクトがコピーされることに注意してください。そうしないと、アセットへの変更を保存する際にリスクが発生します。

C#

var appSettings = PhotonServerSettings.CloneAppSettings(PhotonServerSettings.Instance.AppSettings);

QuantumLoadBalancingClient

接続クラス QuantumLoadBalancingClient の一つの インスタンスUIMain.Client に静的参照として格納されています。UI開発には様々な種類がありますが、シングルトンやステートマシンは最もシンプルな方法であり、開発者はメニューフローを自分のUI作成方法に変更する必要があります。

QuantumLoadBalancingClientNickname をより便利に割り当てるためと、PlayerPrefsBestRegionSummaryFromStorage (リージョンの Ping 結果)をキャッシュするためだけに存在しています。Quantum を起動するには、継承したクラス LoadBalancingClient のみが必要です。

ConnectUsingSettings

デモメニューでは、認証処理を行わず、Photon Cloudに接続し、クライアント用のユーザIDを生成します。

ConnectUsingSettings() は、リージョンとAppVersionの選択によって拡張された AppSettings を使用して、Photonマスターサーバに接続します。 を使用して、Photon Master Server に接続します。HideScreen()UIConnecting.ShowScreen() は状態遷移を発行するために使用されます。

C#

if (UIMain.Client.ConnectUsingSettings(appSettings, Username.text)) {
    HideScreen();
    UIConnecting.ShowScreen();
}

OnReconnectClicked

このサンプルでは、3つの再接続シナリオを示します。

  • 接続オブジェクト(UIMain.Client)は有効で、PlayerTtlInSecondsが設定されています。

この場合、クライアントは UIMain.Client.ReconnectAndRejoin() を使って "高速再接続" を試みることができます。ここで、PlayerTtlInSecondsをチェックする必要はありません。再接続は、サーバーがクライアントの残留物をルームから削除する前に10秒間のタイムアウト内に行う必要があり、高速再接続はもう不可能です。

ReconnectAndRejoin()はクライアントを元のルームに送り返します。

  • 接続オブジェクト (UIMain.Client) は有効ですが、クライアントが10秒以上オフラインになっています (または PlayerTtlInSeconds) 。

クライアントはマスターサーバーに再接続し、 UIMain.Client.ReconnectToMaster() からルームに参加します(ルーム情報は ReconnectInformation に保存されます)。

  • 接続オブジェクトは、おそらくアプリの再起動によって失われます。

再接続のためのデータは Unity の PlayerPrefsReconnectInformation を使って保存されます。キャッシュするデータは RoomNameRegionAppVersionUserId (カスタム認証が再度実行された場合は除く)、Timeout( 保存したデータが再接続に値しない場合)です。

UIMain.ClientAppSettings を再設定すると、マスターサーバへの接続が開始され、再接続または結合が実行されます。再参加は、UserIdが同じ場合にのみ機能します。

C#

if (UIMain.Client == null && ReconnectInformation.Instance.IsValid) {
    UIMain.Client = new QuantumLoadBalancingClient(PhotonServerSettings.Instance.AppSettings.Protocol);
    UIMain.Client.UserId = ReconnectInformation.Instance.UserId;

    var appSettings = PhotonServerSettings.CloneAppSettings(PhotonServerSettings.Instance.AppSettings);
    appSettings.FixedRegion = ReconnectInformation.Instance.Region;
    appSettings.AppVersion = ReconnectInformation.Instance.AppVersion;

    if (UIMain.Client.ConnectUsingSettings(appSettings, LastUsername)) {
        HideScreen();
        UIReconnecting.ShowScreen();
    }
}
参考文献

UIConnecting

この状態は、Photon 接続コールバック IConnectionCallbacksIMatchmakingCallbacks をリッスンして、接続の進行とエラーハンドリングを行います。

OnConnectedToMaster

マスターサーバーへの接続が成功すると、すぐにランダムマッチングが開始され、 OpJoinRandomRoomParams オブジェクトが作成されます。この例では CustomRoomProperties を使って、ゲームルームに入った後に変更可能なマップの選択をネゴシエートしています。

  • RoomOptions.IsVisible はそのルームがマッチメイキングのためにオープンであることを示します。
  • RoomOptions.MaxPlayersは通常Quantumのプレイヤーと同じ数を反映します。
  • RoomOptions.Pluginsnew string[] { "QuantumPlugin" } でなければなりません。
  • RoomOptions.PlayerTtlRoomOptions.Emtl の2つがあります。
  • RoomOptions.EmptyRoomTtl は PhotonServerSettings の設定を反映します。

C#

var joinRandomParams = new OpJoinRandomRoomParams();
_enterRoomParams = new EnterRoomParams();
_enterRoomParams.RoomOptions = new RoomOptions();
_enterRoomParams.RoomOptions.IsVisible  = true;
_enterRoomParams.RoomOptions.MaxPlayers = Input.MAX_COUNT;
_enterRoomParams.RoomOptions.Plugins    = new string[] { "QuantumPlugin" };
_enterRoomParams.RoomOptions.CustomRoomProperties = new Hashtable {
    { "HIDE-ROOM", false },
    { "MAP-GUID", defaultMapGuid },
};
_enterRoomParams.RoomOptions.PlayerTtl = PhotonServerSettings.Instance.PlayerTtlInSeconds * 1000;
_enterRoomParams.RoomOptions.EmptyRoomTtl = PhotonServerSettings.Instance.EmptyRoomTtlInSeconds * 1000;

if (!UIMain.Client.OpJoinRandomOrCreateRoom(joinRandomParams, _enterRoomParams)) {
    UIMain.Client.Disconnect();
}

OpJoinRandomOrCreateRoom() はランダムマッチングとゲームサーバへの接続を開始します。

OnJoinRandomFailed

新しいルームを作成するだけで、ErrorCode.NoRandomMatchFoundを緩和する方法があります。

OnJoinedRoom

ルームへの参加が成功すると、ステートは UIRoom に進行します。

その他のエラーコールバックは報告し、ダイアログを表示してクライアントを切断し、プレーヤーをメインメニューに返します。

UIReconnecting

OnConnectedToMaster

ReconnectAndRejoin() を実行する場合、これはスキップされ、 OnJoinedRoom() が直接呼び出されます。

その他の再接続のケースでは、2つのパスが考えられます。

  • UIMain.Client.OpJoinRoom()
  • UIMain.Client.OpRejoinRoom()

違いは、Rejoinはクライアントがまだサーバー上でアクティブであるとみなされる必要があることです(10秒間のタイムアウトと追加のPlayerTTLに基づいて)。どちらも OnJoinRoomFailed() でエラーハンドリングを行います。

OnJoinedRoom

成功、UIRoomの状態を継続する。

OnJoinRoomFailed()

ここで扱うべきエラーは2つで、非常に一般的です。

  • ErrorCode.JoinFailedFoundActiveJoiner:
    参加しようとしたが、クライアントはまだルーム内でアクティブとマークされている(サーバーは切断されたことを知らない)。緩和策:10秒が経過するまで再試行。
  • ErrorCode.JoinFailedWithRejoinerNotFound:
    再参加しようとしたが、そのルームでアクティブにマークされているクライアントがいない。緩和策:正常に参加する。

UIRoom

UIRoom はマッチメイキングと接続コールバックに加え、IInRoomCallbacksIOnEventCallback をリッスンしています。

これは Quantum シミュレーションの前の状態であり、クライアントはすでに Photon Room にいます。このサンプルでは、ルームのプロパティを使用してゲームのマスタークライアントだけが設定を変更することができます。

Quantumのセッションを開始するには、通常、各ゲームのカスタム設定を含むRuntimeConfigが必要です。デフォルトでは、Menu.scene(メニュー > RuntimeConfig)の中で変更することができます。

Start The Game

このサンプルでは、Photonのコミュニケーションツールである OpRaiseEvent(UIMain.PhotonEventCode.StartGame) を使ってゲームの開始を伝え、それをすべてのクライアントが OnEvent() でディスパッチしています。

C#

    public void OnEvent(EventData photonEvent) {
      switch (photonEvent.Code) {
        case (byte)UIMain.PhotonEventCode.StartGame:

ゲーム開始後に来たクライアントや再参加したクライアントの場合、ゲームが開始された情報はルームプロパティに保存されます。

C#

var ht = new ExitGames.Client.Photon.Hashtable {{"STARTED", true}};
UIMain.Client.CurrentRoom.SetCustomProperties(ht);

ルームに戻ったクライアントは、最初にゲームが既に始まっているかどうかを確認します。

C#

UIMain.Client.CurrentRoom.CustomProperties.TryGetValue("MAP-GUID", out mapGuidValue)
UIMain.Client.CurrentRoom.CustomProperties.TryGetValue("STARTED",  out var started))

Quantum セッションの開始や再起動は StartQuantumGame() の中で行われます。

初期状態では、誤ってソースに書き込まないように FromByteArray(ToByteArray()) を用いて RuntimeConfig がコピーされ、マップの guid が設定されます。

C#

var config = RuntimeConfigContainer != null ? RuntimeConfig.FromByteArray(RuntimeConfig.ToByteArray(RuntimeConfigContainer.Config)) : new RuntimeConfig();
config.Map.Id = mapGuid;

StartParametersが設定されています。観戦者として参加する場合は異なる設定があり、再参加者の場合はオプションでローカルスナップショットを送信することができます(UIGameで再コーディングが行われます)。

C#

var param = new QuantumRunner.StartParameters {
RuntimeConfig             = config,
DeterministicConfig       = DeterministicSessionConfigAsset.Instance.Config,
ReplayProvider            = null,
GameMode                  = Spectate ? Photon.Deterministic.DeterministicGameMode.Spectating : Photon.Deterministic.DeterministicGameMode.Multiplayer,
FrameData                 = IsRejoining ? UIGame.Instance?.FrameSnapshot : null,
InitialFrame              = IsRejoining ? (UIGame.Instance?.FrameSnapshotNumber).Value : 0,
PlayerCount               = UIMain.Client.CurrentRoom.MaxPlayers,
LocalPlayerCount          = Spectate ? 0 : 1,
RecordingFlags            = RecordingFlags.None,
NetworkClient             = UIMain.Client,
StartGameTimeoutInSeconds = 10.0f
};

Quantumのゲームを開始するときに使用する clientId は、通常Photonの UserId です。同じQuantumプレイヤースロットにアサインされるために、再接続の際に同じであることが重要です。メニューシーンにある ClientIdProvider スクリプト(Menu > UICanvas > Menu > IdProvider)をテストするために、異なるソースを使用するように設定することが可能です。

C#

var clientId = ClientIdProvider.CreateClientId(IdProvider, UIMain.Client);
QuantumRunner.StartGame(clientId, param);

QuantumRunner.StartGame() を呼び出した後、Quantum の起動シーケンスが自動的に実行されます。また、SimulationConfig で設定したマップシーンの読み込みがトリガーされます。デモメニューの状態は UIGame に遷移します。

UIGame

ゲーム UI の状態を処理します。

  • 切断ボタンの表示とリスニング
  • OnDisconnected() コールバックでのスナップショットの記録
  • 切断時に QuantumRunner.ShutdownAll(true) を呼び出してQuantumシミュレーションを停止。

切断のテスト

OnLeaveClicked() の内部で、 UIMain.Client.Disconnect() を他のものに変更して、ネットワーキングスレッドでより自然な切断や例外をシミュレートしてください。

C#

public void OnLeaveClicked() {
    UIMain.Client.Disconnect();
    // Debugging: use these instead of UIMain.Client.Disconnect()
    //UIMain.Client.SimulateConnectionLoss(true);
    //UIMain.Client.LoadBalancingPeer.StopThread();
}

Quantum スタート配列

QuantumRunner.StartGame()が呼ばれた後はどうなるのでしょうか?次の図は、コールバックのプロトコルと順序を視覚化したものです。

Quantum オンラインセッションの開始

クライアントはサーバーセッションに参加し、DeterministicConfigSimulationConfigをアップロードするように選択されます(エンタープライズQuantumサーバーを起動していればサーバー上で権威ある上書きが可能です)。サーバーは最初に受け取ったコンフィグを使用してシミュレーションを開始し、受け取ったコンフィグをすべてのクライアントにダウンストリームします。

クライアントでは GameStarted コールバックが起動され、続いて OnInit() がすべてのシステムで起動されます。

クライアントは任意で SetPlayerData() を実行して RuntimePlayer のデータをアップロードし、サーバーから OnPlayerDataSet シグナルが返されます。

Online Session: Start Sequence
オンラインセッション:開始シーケンス

Quantum Online セッションへの再接続

再接続または後発組のシーケンスで、クライアントにスナップショットを送信する必要がある場合、プロトコルが変更されます。スナップショットのタイミングについて詳しくは、再接続マニュアルをご覧ください。

バディスナップショットでは、別のクライアントが最近のスナップショットをアップロードするタスクがあります。その間、再接続先のクライアントは正常に起動したことを通知され、システムのために OnInit() が実行されます。スナップショットを受信すると、GameResyncedコールバックが実行され、最後の "秒 "に追いつくために入力が行われます。

必要であれば SetPlayerData() を再び呼び出すことができます。

Online Session: Restart Sequence
オンラインセッション:リスタートシーケンス

追加情報

セッションの停止と接続の解除

Quantum シミュレーションをローカルに停止するには、QuantumRunner.ShutdownAll(bool immediate)を実行します。Quantum のコールバックから呼び出されたのではない場合のみ、immediate:true をセットしてください。false` に設定すると、シャットダウンは次の Unity のアップデートまで延期されます。

ShutdownAll は、ローカルの Quantum シミュレーションを停止させるトリガーとなる QuantumRunner オブジェクトを破壊します。また、StartParameters.QuitBehaviour に設定された内容に応じて、接続の Disconnect()LeaveRoom() が発生します。

もしクライアントがゲームをスムーズに終了したい場合、例えばリモートクライアントのためにプレイヤーアバターをクリーンアップする場合、シミュレーションに特別なロジックを実装する必要があります。クライアントが発行するコマンドか、プレイヤーの接続状態を監視する必要があります(PlayerConnectedSystemを参照してください)。

プレイヤーはアプリを閉じたり、Alt+F4 でゲームを終了したりするため、常にスムーズな切断を送信するとは限りません。

Back to top