8.3. PiaSync 応用機能

PiaSync の応用機能を利用する場合の、手順や注意事項を以下に説明します。

同期通信中の入力遅延変更

入力遅延は通常、同期通信開始時に SyncProtocol::Start で設定されますが、次のような方法により、同期通信中に入力遅延を変更することができます。この機能を使用する場合は、PiaSync の初期化時に渡す Setting 構造体の isChangeDelayEnabled を true に設定します。

コード 8-5. 同期通信中の入力遅延変更機能を使用するための設定
// 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) とする必要があります。

コード 8-6. 同期通信中の入力遅延変更依頼
// 送信する同期データを設定します
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) に示します。

図 8-4. 入力遅延変更の流れ(6→2)

 

 

図 8-5. 入力遅延変更の流れ(2→6)

  

 

このように、入力遅延が 大→小 に変更されるときには、同期データを設定できないフレームが生じ、入力遅延が 小→大 に変更されるときには、同期データを取得できないフレームが生じることに注意してください。特に、同期データを取得できないフレームでは、そのフレームで使用する入力データ等をどのように扱うか、よく検討する必要があります。そのため、同期通信中の入力遅延変更機能を使用する場合、現在のフレームが同期データを取得できないフレームではないかを確認してください。

コード 8-7. 現在のフレームが同期データを取得できないフレームかを確認
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 に遷移後、再度同期通信を開始することができますが、再度同期通信を開始、または、セッションからの離脱を行わなければ、自分以外のステーションは同期状態になることができません。

コード 8-8. 同期通信の単独終了
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 番を使用して、コントローラ情報を送受信するという使い方も可能です。