ジョイントセッション機能とは、セッション同士をマッチメイクさせることができる機能です。複数のステーションがチームとして集合した後、チームとチームがマッチメイクしてゲームを行う、というような遊びが実現できます。
ジョイントセッション機能は、インターネットマッチメイクのみサポートしています。
ジョイントセッション機能は、同じステーションから複数のプレイヤーが参加する場合に使用できません。
ジョイントセッション機能は、セッションに参加せずに直接ジョイントセッションへの参加はサポートしていません。セッション参加後にジョイントセッションに参加する必要があります。
このバージョンのジョイントセッション機能は、JoinRandomJointSessionAsync() と DestroyJointSessionAsync() のみをサポートしています。CreateJointSessionAsync(), JoinJointSessionAsync(), LeaveJointSessionAsync() はまだ用意していません。
ジョイントセッション機能の用語を以下に示します。
用語 | 説明 |
---|---|
ジョイントセッション | 複数のセッションがマッチメイクして構築される合同セッションのことを示します。 |
ジョイントセッションホスト |
ジョイントセッションの管理者権限を持つステーションのことを示します。通常はセッションホストと兼任になります。 |
チームマッチメイクの実装例は clone/TeamMatchmake サンプルデモを参照してください。
ジョイントセッション機能の非同期処理を行った際の状態遷移イメージを 図 7-10. ジョイントセッション機能使用時の状態遷移図 に示します。
上段は、各ステーションがセッションに参加していない状態です。
中段は、通常のセッションに参加した状態です。
下段は、セッション同士がマッチメイク完了し、ジョイントセッションが作られた状態です。それぞれのステーションが各セッションに参加しているという情報は残ったまま、大人数のジョイントセッションへ参加した状態になります。
ジョイントセッションから離脱する際は、セッションに参加している状態へ戻ることもできますし、一度の処理でジョイントセッションと各セッションから離脱することも可能です。
セッションからジョイントセッションに参加する、またはジョイントセッションからセッション単位で離脱する際、同じセッションに参加しているステーション間の接続情報(NATトラバーサル結果など)は保存されており、移行処理が効率よく短時間で完了します。例えば、中段と下段の移行において、ステーション A0 とステーション A1(またはステーション B0 とステーション B1)の接続情報はお互いに保存されており、両ステーション間の接続処理は短時間で完了します。
ジョイントセッション参加/構築処理もしくはジョイントセッションからの離脱処理の期間中は、送受信関連処理やステーション ID/ステーションインデックスを引数に取る API など、特定の API は使用できません。これらの API を使用禁止期間に呼び出した場合の動作はサポートされていませんので注意してください。
次の API が該当します。(その他に該当するものを含めた API リストを準備中です)
この「セッション移行処理中のため、特定の API 使用不可」の期間中かどうかをアプリケーション側で確認するには、以下の方法があります。
ジョイントセッション参加/構築処理もしくはジョイントセッションからの離脱処理の前後で、ステーション ID に対応するステーションインデックスが変化します(同じ値になることもあります)。ステーション ID とステーションインデックスの対応関係についての詳細な説明は 1.7. ステーション ID を参照してください。
以下はセッション A がジョイントセッションを構築し、セッション B がジョイントセッションに参加する場合とジョイントセッションを解散した場合のステーション ID とステーションインデックスの値についての例です。
各ステーションのステーション ID の ユニーク ID は一意であり、ジョイントセッション参加/解散の前後で変化しません。一方、ステーション ID から変換できるステーションインデックスはそれぞれのセッション内でのみ一意になるようにセッション移行時に再度割り当てするため、セッション A のステーションもセッション B のステーションもステーションインデックスの値が変わります(同じ値になる場合もあります)。
ジョイントセッション機能を使用する場合、ステーション毎のゲームオブジェクトを配列で管理するためには配列のインデックスとステーション ID を結びつける変換テーブルを用意する(または、二次元配列を用意してセッションごとに配列を分ける)などの対応が必要になります。詳しくは、 clone/TeamMatchmake サンプルデモを参照してください。
ジョイントセッション機能特有の設定は存在しませんが、PiaTransport の最大参加ステーション数設定には「ジョイントセッションに参加する最大ステーション数」(複数のセッションがマッチメイクした状態で通信する際の参加最大数)を設定します。
通常通りセッションに参加します。引数で指定する検索条件および構築するセッションの設定はチーム用(非ジョイントセッション用)の設定とします。例えば、最大参加人数はチーム人数とします。
セッションとジョイントセッションのマッチメイク条件は異なるように設定する必要があります。セッションとジョイントセッションの設定を変えて区別する際には、ゲームモード(NexCreateSessionSetting::SetGameMode())などを別の値にします。
このバージョンでは、JoinRandomJointSessionAsync() をサポートしていますが、CreateJointSessionAsync, JoinJointSessionAsync() についてはまだ用意していません。
セッションのホストがジョイントセッション構築/参加用 API を呼び出すことでジョイントセッションに参加する非同期処理を開始します。引数で指定する検索条件および構築設定はジョイントセッションの設定とします。
非同期処理中にセッションの参加募集を締め切ります。非同期処理が成功すると、ジョイントセッションに参加した状態になります。ジョイントセッションに参加した状態ではセッションを参加募集状態に変更できませんので、OpenSessionAsync() を呼び出してはいけません。
非同期処理が途中で失敗しても、参加募集状態を API 呼び出し時の状態に戻しませんので、参加募集状態が変更されている可能性があります。GetSessionOpenStatus() で状態を確認し、必要に応じて参加募集状態を変更します。
ジョイントセッションに参加した状態ではジョイントセッションホストは GetJointSessionOpenStatus() でジョイントセッションの参加募集状態の確認、OpenJointSessionAsync() や CloseJointSessionAsync() で参加募集状態の変更を行えます。必要に応じて呼び出します。
自分がジョイントセッションホストになったかチェックする際は Session::IsJointSessionHost() を使用します。
クライアントの場合は、ホストがジョイントセッション構築/参加を行った際に自動でジョイントセッションへの参加処理が行われます。クライアント側でジョイントセッションへの参加処理の進捗をチェックする際は状態変化イベント通知もしくは Session::GetStatus() を使用します。
// 作成するセッションの設定
// 通常セッションとジョイントセッションの区別には、GameMode の値を利用することをお奨めします。 nn::pia::inet::NexCreateSessionSetting createSessionSettingForJoint; createSessionSettingForJoint.SetGameMode(JointSessionGameMode); // ジョイントセッション用ゲームモードの値 createSessionSettingForJoint.SetMaxParticipantNum(JointSessionMaxEntry); // 合流後の最大参加人数設定 createSessionSettingForJoint.SetAttribute(JointSessionAttributeIndex, JointSessionAttributeValue); // ジョイントセッションの属性値 // 検索条件の設定 const uint32_t SearchCriteriaListSize = 1; // ランダムマッチメイクの場合、検索条件は最大 2 つまで設定可能です。 nn::pia::inet::NexSessionSearchCriteria searchCriteriaListForJoint[SearchCriteriaListSize]; searchCriteriaListForJoint[0].SetGameMode(JointSessionGameMode); // ジョイントセッション用ゲームモードの値 searchCriteriaListForJoint[0].SetMaxParticipantNum(JointSessionMaxEntry); // 合流後の最大参加人数設定 searchCriteriaListForJoint[0].SetAttribute(JointSessionAttributeIndex, JointSessionAttributeValue); // ジョイントセッションの属性値 // ランダムマッチメイクの設定 nn::pia::inet::NexJoinRandomSessionSetting joinRandomSessionSettingForJoint; joinRandomSessionSettingForJoint.SetCreateSessionSetting(&createSessionSettingForJoint); joinRandomSessionSettingForJoint.SetSessionSearchCriteria(searchCriteriaListForJoint, SearchCriteriaListSize); // ジョイントセッションのランダムマッチメイクの非同期処理開始 nn::pia::Result result = nn::pia::session::Session::GetInstance()->JoinRandomJointSessionAsync(&joinRandomSessionSettingForJoint); if (result.IsFailure()) { // エラー処理 // 適切なタイミングでセッションホストが呼び出している限り、失敗しません } // 非同期処理の開始に成功した場合、Dispatch 関数を定期的に呼び出して非同期処理の進行を待つ必要があります while (nn::pia::session::Session::GetInstance()->IsJoinRandomJointSessionCompleted() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // サーバーとのキープアライブ通信などのために NEX の Scheduler::Dispatch を呼ぶ必要があります nn::nex::Scheduler::GetInstance()->DispatchAll(); } // 非同期処理の結果確認 result = nn::pia::session::Session::GetInstance()->GetJoinRandomJointSessionResult(); if (result.IsFailure()) { // エラー処理 } // 非同期処理に成功した場合、自分がジョイントセッションホストになったかどうかを確認することで // 既存のジョイントセッションへ参加して別チームと合流したのか、 // 新たなジョイントセッションを構築して別チームを待ち受ける状態になったのか、を確認できます。 if (nn::pia::session::Session::GetInstance()->IsJointSessionHost()) { // 自分がジョイントセッションホスト(つまり新たなジョイントセッションを構築した) } else { // 自分はジョイントセッションホストではない(つまり既存のジョイントセッションへ参加した) } |
// 通信中の定期処理用ループであるとします
while(loopFlag) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // サーバーとのキープアライブ通信などのために NEX の Scheduler::Dispatch を呼ぶ必要があります nn::nex::Scheduler::GetInstance()->DispatchAll(); // 定期的なセッションの状態チェック nn::pia::session::Session::Status sessionStatus = nn::pia::session::Session::GetInstance()->GetStatus(); if (sessionStatus == nn::pia::session::Session::Status_DisconnectedSession || sessionStatus == nn::pia::session::Session::Status_DisconnectedNetwork) { // 通信状態に異常発生 // エラー処理 } else if (sessionStatus == nn::pia::session::Session::Status_ConnectedSession) { // 通常のセッションへ参加中の状態 } else if (sessionStatus == nn::pia::session::Session::Status_MigratingSession) { // セッション - ジョイントセッション間の移行処理中の状態 // セッションホストがジョイントセッション構築/参加処理を開始した場合、クライアント側では自動的にこの状態になります。 // この状態中は送受信処理が不可能です。 } else if (sessionStatus == nn::pia::session::Session::Status_ConnectedJointSession) { // ジョイントセッションへ参加中の状態 } } |
ジョイントセッションに参加したままの状態でセッションに新規参加させることはできません。ジョイントセッションから離脱してから新規参加させるようにする必要があります。通常通りの手順で JoinSessionAsync() で参加しようとしたセッションが既にジョイントセッションに参加していた場合、セッションへの参加に失敗します。
ジョイントセッション参加中のジョイントセッションホストは、DestroyJointSessionAsync() を呼び出すことでジョイントセッションを解散できます。ジョイントセッションに参加している各セッションのホストは、自分のセッションに参加するクライアントと共にジョイントセッションから離脱し、各セッションに参加した状態に戻ります。ジョイントセッションホスト以外が DestroyJointSessionAsync() を呼ぶと失敗します。
ジョイントセッション解散の非同期処理中にジョイントセッション、セッションの参加募集を締め切ります。非同期処理の成否に依らず、非同期処理が終了した際はセッションは参加締切状態になっています。非同期処理終了後は、GetSessionOpenStatus() で状態を確認し、必要に応じてセッションホストが OpenSessionAsync() で参加募集状態に変更します。
ジョイントセッションホスト以外のステーションでジョイントセッションからの遷移処理の進捗をチェックするには状態変化イベント通知もしくは Session::GetStatus() を使用します。
// ジョイントセッションを解散する非同期処理開始
nn::pia::Result result = nn::pia::session::Session::GetInstance()->DestroyJointSessionAsync(); if (result.IsFailure()) { // エラー処理 // 適切なタイミングでジョイントセッションホストが呼び出している限り、失敗しません。 } // 非同期処理の開始に成功した場合、Dispatch 関数を定期的に呼び出して非同期処理の進行を待つ必要があります while (nn::pia::session::Session::GetInstance()->IsDestroyJointSessionCompleted() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // サーバーとのキープアライブ通信などのために NEX の Scheduler::Dispatch を呼ぶ必要があります nn::nex::Scheduler::GetInstance()->DispatchAll(); } // 非同期処理の結果確認 result = nn::pia::session::Session::GetInstance()->GetDestroyJointSessionResult(); if (result.IsFailure()) { // エラー処理 } // 非同期処理に成功した場合、ジョイントセッションが解散されてジョイントセッションに参加していた各セッションごとに分かれた状態になります。 |
このバージョンでは、LeaveJointSessionAsync() についてはまだ用意していません。
ジョイントセッション参加中の各セッションホストは、LeaveJointSessionAsync() を呼び出すことで自分のセッションをジョイントセッションから離脱できます。同じセッションに参加するクライアントも自動的にジョイントセッションからの離脱処理を開始します。クライアントが LeaveJointSessionAsync() を呼ぶと失敗します。
クライアント側でジョイントセッションからの遷移処理の進捗をチェックするには状態変化イベント通知もしくは Session::GetStatus() を使用します。
ホストマイグレーションが無効な場合にジョイントセッションホストが LeaveJointSessionAsync() を呼び出すと、ジョイントセッション参加中の全てのステーションがジョイントセッションから離脱して各自が参加しているセッションへ戻ります。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で A0 が LeaveJointSessionAsync() を呼び出した場合には参加している全てのステーション A0、A1、B0、B1 がジョイントセッションから離脱して図の中段の状態になります。
ホストマイグレーションが有効な場合にジョイントセッションホストが LeaveJointSessionAsync() を呼び出すと、ジョイントセッションホストのホストマイグレーションが行われ、ジョイントセッションは継続します。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で A0 が LeaveJointSessionAsync() 呼び出した場合には A0、A1 はジョイントセッションから離脱して図の中段の状態になり、 B0、B1 は図の下段の状態のまま通信を継続します。この時、ジョイントセッションホストのホストマイグレーション処理により B0 はジョイントセッションホストとなります。
ジョイントセッションホストではないセッションホストが LeaveJointSessionAsync() を呼び出すと、自分のセッションに参加しているステーションはジョイントセッションから離脱してセッションへ戻りますが、ジョイントセッションは継続します。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で B0 が LeaveJointSessionAsync() を呼び出した場合には B0、B1 はジョイントセッションから離脱して図の中段の状態になり、 A0、A1 は図の下段の状態のまま通信を継続します。
// ジョイントセッションから通常セッションへ遷移する非同期処理開始
nn::pia::Result result = nn::pia::session::Session::GetInstance()->LeaveJointSessionAsync(); if (result.IsFailure()) { // エラー処理 // 適切なタイミングでセッションホストが呼び出している限り、失敗しません。 } // 非同期処理の開始に成功した場合、Dispatch 関数を定期的に呼び出して非同期処理の進行を待つ必要があります while (nn::pia::session::Session::GetInstance()->IsLeaveJointSessionCompleted() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // サーバーとのキープアライブ通信などのために NEX の Scheduler::Dispatch を呼ぶ必要があります nn::nex::Scheduler::GetInstance()->DispatchAll(); } // 非同期処理の結果確認 result = nn::pia::session::Session::GetInstance()->GetLeaveJointSessionResult(); if (result.IsFailure()) { // エラー処理 } // 非同期処理に成功した場合、ジョイントセッションから離脱して通常セッションには参加している状態になります。 |
ジョイントセッション参加中にセッションへ戻らずにジョイントセッションとセッションから一度に離脱したい場合、LeaveSessionAsync を呼び出します。
クライアントが LeaveSessionAsync を呼び出すと、ジョイントセッションとセッションから離脱し、他のステーションはジョイントセッションで通信を継続したままとなります。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で A1 が LeaveSessionAsync を呼び出して通信終了し図の上段の状態になった場合、 A0、B0、B1 は図の下段の状態のまま通信を継続します。
ホストマイグレーションが無効な場合にジョイントセッションホストが LeaveSessionAsync を呼び出すと、ジョイントセッション参加中の全てのステーションもジョイントセッションとセッションから離脱します。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で A0 が LeaveSessionAsync を呼び出した場合、参加している全てのステーション A0、A1、B0、B1 が離脱して図の上段の状態になります。
ホストマイグレーションが無効な場合にジョイントセッションホストではないセッションホストが LeaveSessionAsync を呼び出すと、そのセッションに参加中の全てのステーションがセッションから離脱しますが、ジョイントセッションは継続します。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で B0 が LeaveSessionAsync を呼び出した場合には B0、B1 が離脱して図の上段の状態になりますが、 A0、A1 は図の下段の状態のまま通信を継続します。
ホストマイグレーションが有効な場合にジョイントセッションホスト/セッションホストが LeaveSessionAsync を呼び出すと、呼び出したステーションはジョイントセッションとセッションから離脱して通信を終了し、ジョイントセッションホストおよびセッションホストのホストマイグレーションが行われ、セッションやジョイントセッションは継続します。上記、 図 7-10. ジョイントセッション機能使用時の状態遷移図 を例にすると、下段の状態で A0 が LeaveSessionAsync を呼び出して離脱し、図の上段の状態になった場合、 A1、B0、B1 は図の下段の状態で通信を継続します。この時、ホストマイグレーション処理により A1 が Session A のセッションホストかつジョイントセッションホストとなります。
// ジョイントセッションからの離脱非同期処理開始
nn::pia::Result result = nn::pia::session::Session::GetInstance()->LeaveSessionAsync(); if (result.IsFailure()) { // エラー処理 // 適切なタイミングで呼び出している限り、失敗しません。 } // 非同期処理の開始に成功した場合、Dispatch 関数を定期的に呼び出して非同期処理の進行を待つ必要があります while (nn::pia::session::Session::GetInstance()->IsLeaveSessionCompleted() == false) { nn::pia::common::Scheduler::GetInstance()->Dispatch(); // サーバーとのキープアライブ通信などのために NEX の Scheduler::Dispatch を呼ぶ必要があります nn::nex::Scheduler::GetInstance()->DispatchAll(); } // 非同期処理の結果確認 result = nn::pia::session::Session::GetInstance()->GetLeaveSessionResult(); if (result.IsFailure()) { // エラー処理 } // 非同期処理に成功した場合、ジョイントセッションおよび通常セッションから離脱して誰とも通信していない状態になります。 // LeaveSessionAsync を呼び出したステーションの役割によっては、他のステーションも通信終了することになります。 |
セッションから離脱するときは通常通りセッション API を呼び出します。
ジョイントセッションホストは OpenJointSessionAsync(), CloseJointSessionAsync() でジョイントセッションの参加募集状態を変更できます。ジョイントセッションの参加募集状態の取得は GetJointSessionOpenStatus() を行えます。
ジョイントセッション参加中、通常セッションは参加締切状態になります。OpenSessionAsync(), CloseSessionAsync() は呼び出してはいけません。
使い方は 7.7. 基本機能 - 参加募集状態の変更 の「セッションの参加募集状態の変更」を参照してください。
ジョイントセッション機能を使用してセッションからジョイントセッションへ参加したりジョイントセッションから離脱する際に、処理の開始/完了を通知するイベントが発生します。
ジョイントセッション機能関連処理で通知されるイベントは以下です。
ジョイントセッションホストの変更
上記のイベントと併せて通知される StationId は全て STATION_ID_INVALID です。
// ジョイントセッション機能使用時の状態変化イベントコールバック関数例
void sampleSessionEventCallback(nn::pia::session::Session::EventType eventType, nn::pia::StationId id) { switch (eventType) { case nn::pia::session::Session::EventType_EventJoin: { // ステーションがセッションに参加した } break; case nn::pia::session::Session::EventType_EventLeave: { // ステーションがセッションから離脱した } break; case nn::pia::session::Session::EventType_StartSessionCreateJoint: { // ジョイントセッションの構築処理とセッション移行処理が開始 } break; case nn::pia::session::Session::EventType_EndSessionCreateJoint: { // ジョイントセッションの構築処理とセッション移行処理が完了 } break; case nn::pia::session::Session::EventType_StartSessionJoinJoint: { // ジョイントセッションの参加処理とセッション移行処理が開始 } break; case nn::pia::session::Session::EventType_EndSessionJoinJoint: { // ジョイントセッションの参加処理とセッション移行処理が完了 } break; case nn::pia::session::Session::EventType_StartSessionJointRandom: { // ランダムマッチメイクによるジョイントセッションの参加処理とセッション移行処理が開始 } break; case nn::pia::session::Session::EventType_EndSessionJointRandom: { // ランダムマッチメイクによるジョイントセッションの参加処理とセッション移行処理が完了 } break; case nn::pia::session::Session::EventType_StartSessionDestroyJoint: { // ジョイントセッションを解散してセッションへ戻る処理が開始 } break; case nn::pia::session::Session::EventType_EndSessionDestroyJoint: { // ジョイントセッションを解散してセッションへ戻る処理が完了 } break; case nn::pia::session::Session::EventType_StartSessionLeaveJoint: { // ジョイントセッションから離脱してセッションへ戻る処理が開始 } break; case nn::pia::session::Session::EventType_EndSessionLeaveJoint: { // ジョイントセッションから離脱してセッションへ戻る処理が完了 } break; case nn::pia::session::Session::EventType_SessionMigrationFailed: { // セッション-ジョイントセッション間の移行処理が失敗 } break; case nn::pia::session::Session::EventType_JointSessionHostChanged: { // ホストマイグレーション処理によって id のステーションが新たなジョイントセッションホストとなった場合 } break; } } |