RPCとRaiseEvent

PUNを他のPhotonパッケージと区別する特徴のひとつは、Remote Procedure Calls(RPC)への対応です。

Remote Procedure Call(リモートプロシージャコール)

Remote Procedure Callはその名の通り、リモートクライアント(同じルーム内)上のメソッドの呼び出しです。

メソッドにリモートの呼び出しを有効にするには、[PunRPC]属性を適用する必要があります。

[PunRPC]
void ChatMessage(string a, string b)
{
    Debug.Log("ChatMessage " + a + " " + b);
}
Unity 5.1では、RPC属性は旧式扱いになり、削除される予定です。そのため、PUNではv1.56から始まるPunRPCという別の属性を使用しています。RPCおよび「Remote Procedure Call」の他のすべての用途には影響はありません。

RPCとしてマークされた関数を呼び出すには、PhotonViewが必要です。呼び出しの例:

PhotonView photonView = PhotonView.Get(this);
photonView.RPC("ChatMessage", PhotonTargets.All, "jup", "and jup!");

上級者へのヒント:スクリプトがPhoton.MonoBehaviourまたはPhoton.PunBehaviourの場合、this.photonView.RPC()が使用できます。

よって、直接ターゲット・メソッドを呼び出すのではなく、PhotonView上のRPC()を呼び出し、呼び出すメソッドの名前を提供してください。

ターゲットとパラメータ

PhotonViewは、RPCのための「ターゲット」のようなものです。すべてのクライアントは、その特定PhotonViewを持つネットワーク化されたGameObjectにのみメソッドを実行します。特定のオブジェクトを打ち「ApplyDamage」RPCを呼び出すと、受信クライアントは同じオブジェクトにダメージを適用します!

複数のパラメータを追加することができます(PUNでシリアル化可能であるかぎり)。そうする場合、メソッドとコールは同じパラメータを持つ必要があります。受信クライアントが一致するメソッドを見つけることができない場合は、エラーがログされます。

このルールには例外があります。RPCメソッドの最後のパラメータは、各呼び出しのコンテキストを提供するPhotonMessageInfoタイプに設定できます。呼び出し内にPhotonMessageInfoは設定しません。

[PunRPC]
void ChatMessage(string a, string b, `PhotonMessageInfo` info)
{
    // the photonView.RPC() call is the same as without the info parameter.
    // the info.sender is the player who called the RPC.
    Debug.Log(String.Format("Info: {0} {1} {2}", info.sender, info.photonView, info.timestamp));
}

送信者がPhotonMessageInfo内で、「ターゲッティング」がPhotonViewを通す場合、余分なパラメータを指定せずに誰かを打つ実装を行うことができます。誰が打たれたか、また何を打ったかを把握できます。

ターゲット、バッファリング、順番

RPCを実行するクライアントを定義することができます。これを行うには、PhotonTargetsの値を使用します。最も一般的には、AllのクライアントがRPCを呼べるようにします。Others(その他)のみの場合もあります。

PhotonTargetsにはBufferedで終わる値があります。サーバーは、これらのRPCを記憶するので、新しいプレイヤーが参加した際、以前に起こったRPCだとしても取得することができます。バッファが長いと参加する際に時間が長くなるので、注意して使用してください。

PhotonTargetsにはViaServerで終わる値があります。通常、送信クライアントがRPCを実行しなければならない場合、サーバを介してRPCを送信せずに即時に行います。ローカルでメソッドを呼び出す場合は遅れがないので、これはイベントの順序に影響を与えます!

ViaServerは、「All」ショートカットを無効にします。RPCを順番に行う必要がある場合に、これは特に興味深いです。サーバーを経由して送信されたRPCはすべての受信クライアントによって、同じ順序で実行されます。これは、サーバー上の先着順です。

例:レースゲームでは「finished」RPCをAllViaServerとして送信することができます。最初の「finished」RPCの呼び出しで誰が勝ったか確認できます。以下の「finished」呼び出しで、ランク上のプレイヤーを確認できます。

RPC名のショートカット

ネットワークを介して送信するのに、文字列は最も効果的なものではないので、PUNはそれらを短縮するためショートカットを使用します。PUNはエディタでRPCを検出し、リストをコンパイルします。各メソッドの名前は、そのリストを経由してIDを取得し、名前でRPCを呼び出すとPUNは実際IDを送信します。

このショートカットにより、ゲームの異なるビルドはRPCに同じIDを使用しないかもしれません。これが問題である場合は、ショートカットを無効にすることができます。同じビルドのクライアントがマッチングされる場合、これは問題ではありません。

RPCのリストはPhotonServerSettingsを経由して保存および管理されます。

プロジェクトの異なるビルドの間でRPCコールに問題が生じる場合は、このリストを確認して下さい。Get HashCodeボタンは、プロジェクトフォルダ間の比較が容易であるハッシュコードを計算します。

必要に応じて、リストをクリアして(Clear RPCsボタン) 、Refresh RPC Listボタンをクリックして手動でリストを更新することができます。

RaiseEvent

いくつかのケースでは、RPCが必要でないかも知れません。PhotonViewと何らかのメソッドを呼び出す必要があります。

PhotonNetwork.RaiseEventでは、ネットワーク化オブジェクトに関係なく、自身のイベントを作り送信することができます。コー​​ドとコンテンツを作成し、送信します。

byte evCode = 0;    // my event 0. could be used as "group units"
byte[] content = new byte[] { 1, 2, 5, 10 };    // e.g. selected unity 1,2,5 and 10
bool reliable = true;
PhotonNetwork.RaiseEvent(evCode, content, reliable, null);

PUNがシリアル化できれば如何なるコンテンツでも使用することができます。例えば、object[]を使用し、その目的地と選択したユニットを混在させることができます。

イベントを受信するには、スクリプトはEventCallbackを実装し、それを登録する必要があります。PUNは、パフォーマンス上の理由から、一般的なコールバックを使用していません。イベントを処理するには、MonoBehaviourでこれを実装します。

// setup our OnEvent as callback:
void Awake()
{
    PhotonNetwork.OnEventCall += this.OnEvent;
}

// handle events:
private void OnEvent(byte eventcode, object content, int senderid)
{
    if (eventcode == 0)
    {
        PhotonPlayer sender = PhotonPlayer.Find(senderid);  // who sent this?
        byte[] selected = (byte[])content;
        foreach (byte unitId in selected)
        {
            // do something
        }
    }
}

例のコードはあまり便利ではありませんが、参考にしてください。イベントコードを構成し、異なるコンテンツと異なる方法で使用することができます。

水面下では、PUNはほとんど全ての通信にRaiseEventを使用しています。

RaiseEventOptionsとキャッシング

RaiseEventOptionsパラメータを使用すると、バッファされた場合等に、どのクライアントがイベントを取得するかを定義します。

最も興味深いオプションはおそらく、イベントのキャッシュ/バッファリングです。PUNはインスタンス化のためにそれを使用し、新しい(参加する)プレイヤーがルームに入る前に起こったイベントを取得する場合に便利です。

RaiseEventOptions.EventCachingには次の3つの重要なオプションがあります:AddToRoomCacheAddToRoomCacheGlobalRemoveFromRoomCache。これらは、イベントにハッシュテーブルを送信する場合に最も効果を発揮します。

EventCaching.AddToRoomCacheでRaiseEventを呼び出すと、イベントはサーバーのキャッシュに入れられます。つまり、後から参加するプレーヤーもイベントを取得します。新しいプレーヤーは、サーバーに到着した順にキャッシュされたイベントを取得します。

プレイヤーが退室すると、キャッシュされたイベントは自動的にキャッシュから削除されます。特定のイベントでこれを回避するには、EventCaching.AddToRoomCacheGlobalでRaiseEventを呼び出します。それは「ルームのイベントキャッシュ」にイベントを置きます。

キャッシュに沢山のイベントを入れる場合、新しいプレイヤーがルームに入るとき、大量のメッセージを取得します。イベントの数が多いと時間が掛かる場合があるので、EventCaching.RemoveFromRoomCacheを使用して関連性が無くなったものをクリーンアップする必要があります。

RemoveFromRoomCacheを使用する場合は、RaiseEventのEventCodeは、フィルタとして使用されます。イベントを設定する代わりに、そのすべてのインスタンスを削除することができます。

より微細な制御を得るために、イベントのコンテンツをフィルタリングに使用することができます。そのためには、コンテンツタイプとしてハッシュテーブルを使用する必要があります。特定のイベントを識別するためのキー/値のペアを設定することができ、RemoveFromRoomCacheでRaiseEventを行う際はコンテンツフィルタにそのキー/値のペアのみがある状態になります。

この方法で個別のイベントや、オブジェクトやターンなどに属するイベントを識別できます。

 ドキュメントのトップへ戻る