オンラインセッション
概要
Quantumのオンラインサービスは、Photonのオンラインインフラ(Photon Realtime)の上に構築されています。オンラインセッションへの接続は、通常3つの接続フェーズを経て行われます。
- カスタム認証:
Photonはプレイヤーアカウントを提供していないため、独自またはサードパーティの認証プロバイダを使用してログインを確保し、Photonカスタム認証を設定することを推奨します。 - ゲームサーバー接続:
オンラインシミュレーションを始める前に、クライアントはPhoton Cloudに接続し、Photon Realtime libraryを使用してルームに入る必要があります。
初歩的なランダムマッチングを含む手順は、SDKのDemoMenu
とOfficial Photon Realtime doc Photon Matchmaking And Lobbyに記載されています。 - Quantumシミュレーションの開始シーケンス:
この段階では、Quantumシミュレーションの開始、クライアントの設定データの送信、Quantumセッションの参加とクライアント間の同期が行われます。
Quantumオンラインセッションの開始方法
参考資料
デモメニュー
SDKに含まれる DemoMenu
は、その完全なプロセスを示しています。個々のUIクラス(UIConnect
, UIConnecting
, UIReconnecting
, UIRoom
, UIGame
)をステートマシンとして捉えると、よく理解できます。上の図と類似していることがわかります。
- プレイヤーはボタンを押してPhoton Cloudに接続し、ランダムなマッチメイキングを使用して最終的にPhoton Roomに参加します。
- 他のプレイヤーを待った後、ボタンを押すとゲーム開始の合図があり、プレイヤーはそれぞれQuantumセッションを開始します。
- プレイヤーは、切断ボタンを押すか、Unityエディタを停止するか、アプリケーションを再起動して、再接続ボタンを使って、同じゲームセッションに戻ることができます。
UIConnect
DemoMenuを使い始めるにあたって、便利な開発ツールにするためのいくつかの要素がありますが、コードが読みにくくなることもあります。例えば、RegionDropdown
とAppVersionDropdown
です。
RegionDropdown
スクリプト可能なアセット (Photon/QuantumDemo/Menu/Resources/PhotonRegions.asset
) があり、メニュー実行時に素早くリージョンを変更するためにドロップダウンで選択できるリージョンのセットが含まれています。LastSelectedRegion
は PlayerPrefs
内に保存されています。
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作成方法に変更する必要があります。
QuantumLoadBalancingClient
は Nickname
をより便利に割り当てるためと、PlayerPrefs
に BestRegionSummaryFromStorage
(リージョンの 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 の PlayerPrefs
に ReconnectInformation
を使って保存されます。キャッシュするデータは RoomName
、Region
、AppVersion
、UserId
(カスタム認証が再度実行された場合は除く)、Timeout
( 保存したデータが再接続に値しない場合)です。
UIMain.Client
と AppSettings
を再設定すると、マスターサーバへの接続が開始され、再接続または結合が実行されます。再参加は、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 接続コールバック IConnectionCallbacks
と IMatchmakingCallbacks
をリッスンして、接続の進行とエラーハンドリングを行います。
OnConnectedToMaster
マスターサーバーへの接続が成功すると、すぐにランダムマッチングが開始され、 OpJoinRandomRoomParams
オブジェクトが作成されます。この例では CustomRoomProperties
を使って、ゲームルームに入った後に変更可能なマップの選択をネゴシエートしています。
RoomOptions.IsVisible
はそのルームがマッチメイキングのためにオープンであることを示します。RoomOptions.MaxPlayers
は通常Quantumのプレイヤーと同じ数を反映します。RoomOptions.Plugins
はnew string[] { "QuantumPlugin" }
でなければなりません。RoomOptions.PlayerTtl
とRoomOptions.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 はマッチメイキングと接続コールバックに加え、IInRoomCallbacks
と IOnEventCallback
をリッスンしています。
これは 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 オンラインセッションの開始
クライアントはサーバーセッションに参加し、DeterministicConfig
とSimulationConfig
をアップロードするように選択されます(エンタープライズQuantumサーバーを起動していればサーバー上で権威ある上書きが可能です)。サーバーは最初に受け取ったコンフィグを使用してシミュレーションを開始し、受け取ったコンフィグをすべてのクライアントにダウンストリームします。
クライアントでは GameStarted
コールバックが起動され、続いて OnInit()
がすべてのシステムで起動されます。
クライアントは任意で SetPlayerData()
を実行して RuntimePlayer
のデータをアップロードし、サーバーから OnPlayerDataSet
シグナルが返されます。
Quantum Online セッションへの再接続
再接続または後発組のシーケンスで、クライアントにスナップショットを送信する必要がある場合、プロトコルが変更されます。スナップショットのタイミングについて詳しくは、再接続マニュアルをご覧ください。
バディスナップショットでは、別のクライアントが最近のスナップショットをアップロードするタスクがあります。その間、再接続先のクライアントは正常に起動したことを通知され、システムのために OnInit()
が実行されます。スナップショットを受信すると、GameResynced
コールバックが実行され、最後の "秒 "に追いつくために入力が行われます。
必要であれば SetPlayerData()
を再び呼び出すことができます。
追加情報
セッションの停止と接続の解除
Quantum シミュレーションをローカルに停止するには、QuantumRunner.ShutdownAll(bool immediate)
を実行します。Quantum のコールバックから呼び出されたのではない場合のみ、immediate:true
をセットしてください。false` に設定すると、シャットダウンは次の Unity のアップデートまで延期されます。
ShutdownAll
は、ローカルの Quantum シミュレーションを停止させるトリガーとなる QuantumRunner オブジェクトを破壊します。また、StartParameters.QuitBehaviour
に設定された内容に応じて、接続の Disconnect()
や LeaveRoom()
が発生します。
もしクライアントがゲームをスムーズに終了したい場合、例えばリモートクライアントのためにプレイヤーアバターをクリーンアップする場合、シミュレーションに特別なロジックを実装する必要があります。クライアントが発行するコマンドか、プレイヤーの接続状態を監視する必要があります(PlayerConnectedSystem
を参照してください)。
プレイヤーはアプリを閉じたり、Alt+F4 でゲームを終了したりするため、常にスムーズな切断を送信するとは限りません。
Back to top