C#スクリプトAPIについて

Strix Unity SDKには一式のC#スクリプトAPIがあります。このページでは、スクリプトを使用する上での共通概念とヒントを説明します。

StrixBehaviourクラス

Unityでは、スクリプトコンポーネントを作成する場合、クラスをMonoBehaviourクラスから派生させます。Strix Unity SDKでは、Strixの機能を利用するスクリプトコンポーネントを作成する場合、クラスをStrixBehaviourクラスから派生させます。

StrixBehaviourMonoBehaviourの派生クラスなので、StrixBehaviourから派生したクラスはMonoBehaviourが提供する全ての機能(例えばGameObjectにアタッチできるようになること)に加えてStrixBehaviourに特有の機能が利用できます。

StrixBehaviourから派生したスクリプトをGameObjectにアタッチするときには、StrixReplicatorコンポーネントもアタッチする必要があります。StrixBehaviourにはstrixReplicatorプロパティがあり、これを使ってGameObjectにアタッチされているStrixReplicatorコンポーネントを参照できます。これはちょうど、transformプロパティを使ってTransformコンポーネントにアクセスできるのと同様です。StrixBehaviourには同様な簡略プロパティがもう2つあります。isLocalisSyncです。両者はStrixReplicatorの同じ名前のプロパティを参照します。

StrixNetworkシングルトンクラス

StrixNetworkシングルトンクラスは、StrixのスクリプトAPIへの主要なエントリポイントを提供します。通常通り、instanceプロパティを使用してこのクラスのシングルトンインスタンスを取得し、それを用いてクラスの他のメンバーにアクセスします。

このクラスはSoftGear.Strix.Unity.Runtime名前空間に属しています。

例えば:

using SoftGear.Strix.Unity.Runtime;

        // 何らかのメソッドの内部、例えば Start()

        StrixNetwork.instance.applicationId = "00000000-0000-0000-0000-000000000000";
        StrixNetwork.instance.ConnectMasterServer(
            "000000000000000000000000.game.strixcloud.net",
            OnConnectMasterCallback,
            OnConnectMasterFailedCallback
        );

非同期処理

StrixのスクリプトAPIには非同期に実行されるメソッドが多数あります。それらのメソッドはネットワーク操作を伴うため長い時間がかかることがありますが、その間Unityのメインスレッドをブロックするわけにはいかないからです。

このような非同期操作をStrix Unity SDKはコールバックハンドラーによって実現します。

sequenceDiagram participant A as スクリプト participant B as SDKライブラリ participant C as サーバー A ->> + B : メソッドの呼び出し B ->> + C : サーバーへ要求 B -->> - A : メソッドの戻り C ->> C : サーバー側処理 C -->> + B : サーバーからの応答 deactivate C B -->> - A : コールバック

注釈

Strix Unity SDKでは、これらのコールバックをしばしばイベントと呼びますが、これらは実際には単に普通のデリゲートです。C#の文法用語の「イベント」や、UnityのUnityEventと混同しないように注意してください。

なお、Strixのクラスの中には、C#の文法用語の意味でのイベントをメンバーとして持っているものもあります。

ネットワーク操作を行う一般的なStrixのメソッドは、引数リスト内にデリゲートを2つ持っています。これらのデリゲートを一般に「成功コールバックハンドラー」と「失敗コールバックハンドラー」と呼びます。そのようなメソッドを呼び出すと、メソッドはネットワーク操作の完了前に戻ります。後になって、操作が完了したときに、いずれか一方のデリゲートが起動されます。操作が成功した場合には成功コールバックが起動され、それ以外の場合には失敗コールバックが起動されます。

コールバックハンドラーのデリゲートの型はさまざまですが、それらは大抵パラメーターを1つ受け取り、その型の名前は最後がEventArgsになっています。また結果は返しません(void)。コールバックハンドラーがパラメーターとして受け取るオブジェクトには、普通(必ず、というわけではありませんが)、ネットワーク操作の結果を示す(単なる成功か失敗以上の)情報が含まれています。

例えば、ConnectMasterServerメソッドの失敗コールバックハンドラーの型はStrixNetworkConnectFailedEventHandlerですが、これは次のように定義されています。

public delegate void StrixNetworkConnectFailedEventHandler(
    StrixNetworkConnectFailedEventArgs args
);

ここに、StrixNetworkConnectFailedEventArgsは、cause(型はException)とsession(型はAbstractSession)という2つのプロパティを持つクラスです。

ダウンキャスト

Strixサーバーの特長の一つは柔軟にカスタマイズできることです。(残念ながら、Strix Cloudで動作するStrixサーバーはカスタマイズできません。カスタマイズしたStrixサーバーを利用するためにはSTRIX ENGINE製品が必要です。)カスタマイズしたサーバーを活用するためには、クライアント側にも同レベルの柔軟性が必要になります。

スクリプトAPIの多くの部分は一般的な定義になっており、しばしばジェネリックスを使用していますが、その一つの目的は柔軟性を得ることです。それらが使用する型はしばしばインターフェイス型か抽象クラスとして定義されています。ただし、そのようなオブジェクトを具象クラスにダウンキャストすることで、宣言上の型よりも多くのメンバーにアクセスすることができます。ときには、オブジェクトが具象クラスとして宣言されている場合にも同じようにダウンキャストが可能なことがあります。

例えば、失敗コールバックに渡される引数には大抵causeという名前のプロパティがあり、Exception型として定義されています。定義上はExceptionですが、これは大抵ErrorCodeException型(SoftGear.Strix.Unity.Runtime.Error名前空間に定義されています)にダウンキャストできて、こちらのクラスにはエラーの原因を示すerrorCodeプロパティがあります。

例えば:

void OnConnectMasterFailedCallback(StrixNetworkConnectFailedEventArgs args)
{
    if (args.cause is ErrorCodeException
        && ((ErrorCodeException)args.cause).errorCode == StandardErrorCode.ConnectionError)
    {
        // この特定のエラーに関する特別な処理
    }
    else
    {
        // 通常のエラー処理
    }
}

エラーコードの詳細についてはエラーコードを参照してください。

インターフェイス

Strix Unity SDKはStrix自身のインターフェイスを多数使用しますが、その中には名前が「 I 」から始まらないものがある点に注意してください。その一例はSoftGear.Strix.Client.Core.UIDインターフェイスです。これはさまざまなオブジェクトの一意識別子を表します。(RoomInfo.nodeUidプロパティの型や、IRoomMember.GetUid()メソッドの戻り値など、いくつかの場面で使われています。)これらの、名前が「 I 」以外の文字で始まるインターフェイスを意識してください。

ところで、なぜインターフェイスだと意識する必要があるのでしょうか?…それは、よく間違える落とし穴があるからです。

何らかの比較可能な値を表すクラスでは、==!=の演算子をオーバーライドして、プログラマーがそれらのオブジェクトを直観的な書き方で比較できるようにしていることがよくあります。しかし、C#言語の制約により(先頭の文字とは無関係に)、インターフェイスでは「等しい」「等しくない」の演算子をオーバーライドすることができません。

そのため、例えば2つのUIDオブジェクトを比較する際には、==演算子を使うことができません。なぜなら、この演算子は2つのオブジェクトのリファレンスが等しいかどうかを比較するので、同一のIDを表していてもUIDオブジェクトが異なるとfalseになってしまうからです。その代わりに、次の例の2番目のif文のようにEqualsメソッドを使用する必要があります。

private UID uid;

// StrixNetwork::GetRoomMembersのハンドラー。
void OnRoomMembersGot(RoomMemberGetEventArgs args)
{
    foreach (var member in args.roomMemberCollection)
    {
        UID memberUid = member.GetUid();

        // この比較は期待したようには動作しません。
        // リファレンスが等しいかどうかを比較してしまうからです。
        if (memberUid == uid)
        {
            // 何らかの処理を行う。
        }

        // 代わりにこうしてください。
        if (memberUid.Equals(uid))
        {
            // 何らかの処理を行う。
        }
    }
}