Hlapiに関するよくある質問

高レベルネットワークAPIに関するよくある質問。

ネットワーク化されたUnityオブジェクト

独自のNetworkedBehaviourはどのように作成できますか?

MonoBehaviourを拡張するとスクリプトによってUnityのイベントやシステムと統合できるように、NetworkedBehaviourを拡張することでHlapiと統合できるようになります。(エディタ経由で)NetworkedUnityObjectにアタッチされ、そのオブジェクトの Behaviours リストに登録された NetworkedBehaviour はそれぞれ、そのオブジェクトがネットワークでスポーンされるたびに自動的に初期化されます。これにより、指定の Group にNetworkedDataHandlerを登録することができます。オブジェクトの寿命やタグ付けはHlapiで処理されるため、気にする必要はありません。

たとえば、次のスクリプトでは、TransformColor の複製を設定する NetworkedBehaviour を実装します。スポーンされた NetworkedUnityObject にはそれぞれ固有の NetworkGroup が割り当てられるため、これらのNetworkedDataHandlerに書き込むことで、他のデバイス上の相当するオブジェクトにのみ影響を与えます。

using System;
using Niantic.ARDK.Networking;
using Niantic.ARDK.Networking.HLAPI.Data;
using Niantic.ARDK.Networking.HLAPI.Object;
using Niantic.ARDK.Networking.HLAPI.Object.Unity;
using Niantic.ARDK.Utilities;
using UnityEngine;

[RequireComponent(typeof(AuthBehaviour))]
public sealed class SampleNetworkedBehaviour :
  NetworkedBehaviour
{
  [SerializeField]
  private TransformPiece _replicatedPieces = TransformPiece.All;

  // Reference to the material on the GameObject
  [SerializeField]
  private Material _material;

  private UnreliableBroadcastTransformPacker _transformPacker;
  private NetworkedField<Color> _networkedColorField;

  // Define an initializer that will be run as soon as the NetworkedUnityObject
  //   has been spawned
  protected override void SetupSession(out Action initializer, out int order)
  {
    initializer = () =>
    {
      NetworkedDataDescriptor authToObserverDescriptor =
        Owner.Auth.AuthorityToObserverDescriptor(TransportType.UnreliableUnordered);

      // Create an UnreliableBroadcastTransformPacker that
      //   replicates Position, Rotation, and Scale
      _transformPacker = new UnreliableBroadcastTransformPacker
      (
        "NetTransform",
        gameObject.transform,
        authToObserverDescriptor,
        _replicatedPieces,
        Owner.Group
      );

      _networkedColorField = new NetworkedField<Color>
      (
        "color",
        authToObserverDescriptor,
        Owner.Group
      );

      _networkedColorField.ValueChangedIfReceiver += OnColorFieldChanged;
    };

    order = 0;
  }

  // When this is called by the peer that has the role Authority, all
  //   Observing peers will receive a ValueChangedIfReceiver event
  private void UpdateColorForAllPeers(Color newColor)
  {
    _networkedColorField.Value = newColor;
  }

  private void OnColorFieldChanged(NetworkedFieldValueChangedArgs<Color> args)
  {
    Optional<Color> optionalValue = args.Value;
    if (!args.Value.HasValue)
    {
      return;
    }

    _material.color = args.Value.Value;
  }

  private void OnDestroy()
  {
    _transformPacker.Unregister();
    _networkedColorField.Unregister();
  }
}

NetworkedDataDescriptorは何に使用しますか?

NetworkedDataDescriptor は、認証済みの送受信者や、ネットワークプロトコルに関する情報を含む構造体です。事前に構築されたHlapiの NetworkedDataHandler の多くでは、そのハンドラが意図する送受信パターンを定義するために、構築時に NetworkedDataDescriptor が必要になります。

NetworkedDataDescriptorExtension には、よく使用されるパターン(権限者→監視者、監視者→権限者、全員→全員)を生成するためのボイラープレートメソッドがいくつか用意されています。

権限者

ピアはどのような権限を要求しますか?

権限とは、各ピアの役割について分散的に合意することです。各ピアに割り当てられる役割は、Role.AuthorityRole.ObserverRole.None のいずれかになります。一般的に、権限の各インスタンスは単一オブジェクト、またはオブジェクトの論理的なグループをカバーします。たとえば、ピアごとに制御するアバターがある場合、各ピアは自分のアバターに対して役割 Authority を要求し、それ以外のピアは、アップデートが通知されるように役割 Observer を要求します。

ピアは権限をどのように要求しますか?

デフォルトでは、権限を複製するための実装にはGreedyAuthorityReplicatorを使用します。このコンポーネントを含む NetworkedUnityObject の場合、役割 Authority では、一度に1つのピアのみが要求できるのに対し、役割 Observer は任意の数のピアを要求できます。オブジェクトの Authority を変更するには、役割が Authority の現在のピアが最初に別の役割( Observer など)を要求する必要があります。これで、その後のピアは、役割のアップデートを受け取った時点で Authority を要求できるようになります。

AuthBehaviourとGreedyAuthorityReplicatorの違いは何ですか?

AuthBehaviourコンポーネントでは、 GreedyAuthorityReplicator クラスをラップして、Authority APIとのUnity統合を行います。このコンポーネントは、一般的な役割の開始パターン(ホストが所有、またはデフォルトで監視者)の選択をサポートします。いずれも選択された場合、「ホストが所有」はホストピアの「デフォルトで監視者」よりも優先されます。

../../../_images/auth_behaviour.png

GreedyAuthorityReplicatorで十分ですか?

GreedyAuthorityReplicator を使用する場合、役割が Authority のピアは一度に1つのみ選択してください。ただし、現在、GreedyAuthorityReplicator では役割 Authority を要求する前に、ピアのローカルで既知の役割のみを確認します。2つのピアが同時に役割 Authority を要求しようとすると、セッション内のピアが実際に Authority であるピアに関する知識が矛盾する可能性があります(要求が到達する順序に関する競合状態が発生する)。

Authority がほとんど変化しないか、決定的に変化する場合(ターン制のゲームなど)には、 GreedyAuthorityReplicator で十分です。

メッセージの受け渡し

メッセージはどのように送信されますか?

Hlapiは、HlapiSessionの SendQueuedData メソッドで呼び出されます。デフォルトではUnityのUpdateループごとに1回呼び出されます。 SendQueuedData を呼び出す頻度を手動で制御するには、GetOrCreateManagedSession ではなく、コンストラクターで HlapiSession を作成します。

SendQueuedData が呼び出されると、 HlapiSession は現在登録されている NetworkedGroups に対してそれぞれクエリを実行します。これにより、グループに登録されている NetworkedDataHandler にそれぞれクエリが実行されます。そこから、 NetworkedDataHandler はそれぞれ、ネットワーク上に送信すべきアップデート(位置のアップデートや新しいメッセージなど)があるかどうかを判断し、そのデータをオブジェクト(または特定のオブジェクト NetworkedDataHandlerBase.NothingToWrite)として返します。

続いて、 NetworkGroup ごとに、データをパッケージ化して に渡します。ここで照合され、必要なメタデータを付加してシリアライズ``HlapiSession``され、ネットワークを介して関連するピアに送信されます。

上記の処理はセッション内のピアごとに1回実行され、各 NetworkedDataHandler はそのピアに送信するデータがあるかどうかを判断します。これにより、すべてのデータをすべてのピアに送信するのではなく、さまざまなピアが選択的に一部のメッセージを送受信することができます。

メッセージはどのように受け取りますか?

Hlapiは、Hlapiメッセージタグの付いたメッセージを受け取ると、そのメッセージが上記の形式でパッケージされたデータであると仮定し、メッセージに含まれるグループデータを解凍して、正しい NetworkGroup に送ります。まだ HlapiSession に登録されていない NetworkGroup 宛のメッセージを受け取った場合、そのメッセージはキャッシュに保存され、 NetworkGroup が登録されると処理されます(ただし、この処理は TransportType の信頼性が高い場合にのみ行われ、信頼性の低いメッセージは廃棄されます)。

そこから NetworkGroup は、登録した NetworkedDataHandlers に対して同様のメッセージの解凍とアドレス指定を行います(信頼性が高い場合は、未知のハンドラへのメッセージのキャッシュも行います)。最後に、 NetworkedDataHandlers は相手から送信されたメッセージを他のデバイスから受信し、そのデータで処理を行います。たとえば、UnreliableBroadcastTransformPacker は、受信するすべてのデータが PackedTransform であり、そのGameObjectの更新位置が含まれることを把握しているのに対し、 GreedyAuthorityReplicatorRole の要求をピアから受信しようとしていることを把握しています。

Hlapiのメッセージはどのようにシリアライズされますか?

Hlapiでは、ARDKに付属している GlobalSerializerシステム が使用されます。

こちらもご覧ください

低レベルネットワーク

高レベルネットワークAPI(Hlapi)