PiaSync の応用機能を利用する場合の、手順や注意事項を以下に説明します。
入力遅延は通常、同期通信開始時に SyncProtocol::Start で設定されますが、次のような方法により、同期通信中に入力遅延を変更することができます。この機能を使用する場合は、PiaSync の初期化時に渡す Setting 構造体の isChangeDelayEnabled を true に設定します。
// Initialize に渡す設定を用意します
nn::pia::sync::SyncProtocol::Setting setting; setting.maxDelay = 10; setting.timeoutFrame = 240; setting.dataUnitSize[0] = 16; setting.dataUnitSize[1] = 32; setting.dataUnitSize[2] = 32; // 同期通信中の入力遅延変更機能を使用できるようにします。 setting.isChangeDelayEnabled = true; // SyncProtocol の初期化 result = pTransport->GetProtocol<nn::pia::sync::SyncProtocol>(m_hSyncProtocol)->Initialize(setting); PIA_ASSERT(result.IsSuccess()); |
同期通信中に入力遅延変更依頼を行う場合は、送信する同期データの設定時に、SyncProtocol::RequestToChangeDelay を呼び出す必要があります。ここで依頼する入力遅延の値は、SyncProtocol::Setting::maxDelay で設定した値以下である必要があります。また、同フレームに複数のステーションから入力遅延変更依頼があった場合は、その中の最大値が採用されます。
同期通信中の入力遅延変更機能を使用する場合は、毎フレーム SyncProtocol::RequestToChangeDelay を呼び出す必要があります。入力遅延変更を依頼しないフレームでは、SyncProtocol::RequestToChangeDelay(0) とする必要があります。
// 送信する同期データを設定します
if (pSyncProtocol->NeedsSetData()) { // 送信する同期データを用意して SyncProtocol に設定します。 // 初期化時に SyncProtocol::Setting::dataUnitSize を設定して有効にしたデータ ID の 0 番、1 番、2 番 について確認します for (uint32_t i = 0; i < 3; ++i) { // 自分が送信対象としている同期データか確認し、対象であれば同期データを設定します // データ ID に応じて、適切な大きさの dataBuffer を用意する必要があります if (pSyncProtocol->NeedsSetData(i)) { result = pSyncProtocol->SetData(i, &dataBuffer); PIA_ASSERT(result.IsSuccess()); } } // 入力遅延変更を依頼します。 uint32_t newDelay = 4; result = pSyncProtocol->RequestToChangeDelay(newDelay); PIA_ASSERT(result.IsSuccess()); } |
入力遅延変更の流れは、入力遅延が 大→小 に変更される場合と 小→大 に変更される場合とで異なります。
入力遅延が 大→小 に変更される場合の例として、入力遅延が 6→2 に変更される場合の例を 図 8-4. 入力遅延変更の流れ(6→2) に、入力遅延が 小→大 に変更される場合の例として、入力遅延が 2→6 に変更される場合の例を 図 8-5. 入力遅延変更の流れ(2→6) に示します。
このように、入力遅延が 大→小 に変更されるときには、同期データを設定できないフレームが生じ、入力遅延が 小→大 に変更されるときには、同期データを取得できないフレームが生じることに注意してください。特に、同期データを取得できないフレームでは、そのフレームで使用する入力データ等をどのように扱うか、よく検討する必要があります。そのため、同期通信中の入力遅延変更機能を使用する場合、現在のフレームが同期データを取得できないフレームではないかを確認してください。
if (pSyncProtocol->CanGetData())
{ bool isNoDataFrame; result = pSyncProtocol->GetIsNoDataFrame(&isNoDataFrame); PIA_ASSERT(result.IsSuccess()); if (isNoDataFrame) { // 同期データを取得できないフレームです。 } } |
通常、SyncProtocol::End により 1 つのステーションが同期通信を終了すると、他のステーションも同期通信を終了しますが、次のような方法により、1 つのステーションが単独で同期通信を終了することができます。
単独で同期通信を終了するステーションは、SyncProtocol::EndAlone を呼び出す必要があります。これにより、同期通信を終了するフレームが設定され、他のステーションにもそれを通知します。終了フレームは、既に送信する同期データを設定済みの最後のフレームに設定されます。通信相手に終了フレームを通知し、全ての通信相手が終了フレームに達したことを確認した後、State_EndedAlone に遷移します。
SyncProtocol::EndAlone 呼び出し成功後は、State_Synchronized の間は SyncProtocol::Step に失敗するようになり、フレームを進めることができなくなります。そのため、これを呼び出したステーションは終了フレームに達しない点に注意してください。しかし、この場合でも SyncProtocol::Step は内部処理進行のために毎フレーム呼ぶ必要があります。
また、SyncProtocol::EndAlone を呼び出したフレームの同期データは取得できますが、呼び出し後に他のステーションが単独同期終了を行ったことが通知された場合、そのステーションが送信した同期データは取得できなくなり、同期ずれの原因となりますので、SyncProtocol::EndAlone の呼び出しは、受信した同期データを取得後に行う必要があります。
State_EndedAlone の状態で、全ての通信相手が同期通信を終了すると、State_NotSynchronized に遷移します。State_EndedAlone の状態、または、その後 State_NotSynchronized に遷移した状態で自分がセッションから離脱しても、他のステーションは同期通信を維持することができます。
ただし、新規ステーションが参加してきた場合は注意が必要です。自分が State_EndedAlone に遷移後に新規ステーションが参加し、自分以外のステーションが再度同期通信を開始しようとして State_Waiting になっているときに自分が切断すると、自分以外のステーションは同期通信を終了し、State_NotSynchronized に遷移します。
State_EndedAlone で終了したステーションは State_NotSynchronized に遷移後、再度同期通信を開始することができますが、再度同期通信を開始、または、セッションからの離脱を行わなければ、自分以外のステーションは同期状態になることができません。
result = pSyncProtocol->EndAlone();
if (result.IsFailure()) { // EndAlone の呼び出しに失敗しました。 } while (true) { if (nn::nex::Scheduler::GetInstance() != NULL) { nn::nex::Scheduler::GetInstance()->DispatchAll(); } // nn::pia::common::Scheduler::Dispatch() を定期的に呼び出す必要があります。 nn::pia::common::Scheduler::GetInstance()->Dispatch(); result = pSyncProtocol->Step(); if (result == nn::pia::ResultTemporaryUnavailable()) { // SyncProtocol::EndAlone 呼び出し後はこの Result が返ることがありますが、ハンドリングの必要はありません。 } if (pSyncProtocol->GetState() == nn::pia::sync::SyncProtocol::State_EndedAlone) { // 同期通信の単独終了が完了しました。 // 自分が離脱しても、他のステーションの同期通信は維持されます。 break; } else if (pSyncProtocol->GetState() == nn::pia::sync::SyncProtocol::State_Ending) { // 同期通信の単独終了が完了する前に、同期通信の終了処理が開始されました。 } else if (pSyncProtocol->GetState() == nn::pia::sync::SyncProtocol::State_NotSynchronized) { // 他のステーションも終了しました。 if (pSyncProtocol->GetLastEndReason() == nn::pia::sync::SyncProtocol::EndReason_EndAlone) { // 同期通信の単独終了が完了後、他のステーションも終了しました。 } else { // 同期通信の単独終了が完了する前に、同期通信が終了しました。 } break; } Sleep(33); } |
同期通信開始時に、送信する同期データのデータ ID を設定しますが、この設定はステーションごとに異なっていても構いません。例えば、データ ID の 0 番には「キーデータ」、1 番には「モーションデータ」を割り振り、ステーション A はキーデータのみを、ステーション B はモーションデータのみを送信するように設定することができます。この場合、ステーション A は、自分が設定したキーデータと、ステーション B が設定したモーションデータを取得することができます。このように、必要となる同期データのみ送受信することにより、送受信量を削減できます。
また、ステーション A ではプレイヤー 1 人が、ステーション B ではプレイヤー 2 人がプレイしており、この 2 台のステーションで 3 人分の入力データの同期通信を行う場合、ステーション A ではデータ ID の 0 番だけを、ステーション B ではデータ ID の 0 番と 1 番を使用して、コントローラ情報を送受信するという使い方も可能です。