This document is about: PUN 2
SWITCH TO

PUN Classic (v1)、PUN 2、Boltはメンテナンスモードとなっております。Unity2022についてはPUN 2でサポートいたしますが、新機能が追加されることはありません。お客様のPUNプロジェクトおよびBoltプロジェクトが停止することはなく、将来にわたってパフォーマンス性能が落ちることはありません。 今後の新しいプロジェクトについては、Photon FusionまたはQuantumへ切り替えていただくようよろしくお願いいたします。

WebRPC

WebRPCを使用すれば、Photon Cloudに柔軟に外部サービスを統合することができます。 たとえば、WebRPCによってPhotonクライアントが外部Webサービスからデータをフェッチするようサーバーにリクエストすることができます。

Webサービスの基礎

Photon Serverは、クライアントとWebサーバー間で プロキシ または リレー の役割を果たします。
WebRPCはWebhookの拡張、またはクライアント主導のWebhookと考えることができます。

WebRPCを使用するには、HTTPベースのサービスを実装し、アプリケーションのWebhookセクション内でBaseURLを設定する必要があります。
Photon WebhookとWebRPCは、同一のBaseURLを共有しています。

開発の際には、以下のヒントを参照してください:

  • WebRPCにサービスを実装するには、あらゆる言語、フレームワーク、Webサーバーを使用することができます。
  • すべての場合において、送信するデータは最小化し、プレイヤーへの負荷を抑えてください。

リクエスト

Photon WebRPCはマスターサーバーまたはゲームサーバーに接続した際に、クライアント側から許可されるPhotonオペレーションです。 Photon WebRPCにはURIパス文字列(別名:WebRPCメソッド名)が必要です。また、オプションでWebサービスに送信されるデータを含む2番目の引数が必要となります(別名:WebRPCパラメータ)。 これら2つの引数は PhotonNetwork.WebRPCメソッドに渡すことが可能です。

UriPathはWebRPCの相対パスで、リモートプロシージャ名と合致する必要があります。
URL自体でパラメータを送信することも可能です。 この場合、クエリ文字列 はプロシージャ名に含め、相対パスに加える必要があります。

リクエストがPhoton Serverに受信されると、プロシージャ名はBaseURLに連結されて、同一のURLのWebサービスに送信される前にWebRPCのURLの絶対パスが生成されます。

使用されるHTPPリクエストメソッドがPOSTであるため、クライアントによって送信されるパラメータがある場合、PhotonはこれらのパラメータをデフォルトのプロパティとともにJSON POSTデータとして渡します:

  • AppId: ゲームクライアントで設定される、アプリケーションのAppID。ダッシュボードで参照できます。

  • AppVersion: ゲームクライアントで設定される、アプリケーションのバージョン。

  • Region: ゲームクライアントが接続するリージョン。

  • UserId: WebRPCを作成するアクターのID。

その他のプロパティは、クライアントから送信されるパラメータの一部です。

クライアントで使用されるWebRpcParameters型がDictionary<string, object> の場合、すべてのキー/値のセットはポストデータのルートオブジェクトに送信されます。
もし、その他のJSON有効型の場合には、その型は新たなプロパティRpcParamsの値として含まれます。

例 1

BaseURLはhttps://my.service.orgで、クライアントはWebRPC("method?id=1", parameters)を呼びます。
パラメータは、{{"key1": 1}, {"key2": "yx"}, {"key3": true}}をコンテンツとして持つDictionary<string, object>です。
この場合、Photonはhttps://my.service.org/method?id=1を呼び、さらにJSONをPOSTします:

JSON

{
    "AppId": "00000000-0000-0000-0000-000000000000",
    "AppVersion": "client-x.y.z",
    "Region": "EU",
    "UserId": "userXYZ",
    "key1": 1,
    "key2": "yx",
    "key3": true
}

例 2

BaseURLはhttps://my.service.orgで、クライアントはWebRPC("method?id=1", parameters)を呼びます。
パラメータはオブジェクトの配列です:object[] { 0, "xy", false }
この場合、Photonはhttps://my.service.org/method?id=1を呼び、さらにJSONをPOSTします:

JSON

{
    "AppId": "00000000-0000-0000-0000-000000000000",
    "AppVersion": "client-x.y.z",
    "Region": "EU",
    "UserId": "userXYZ",
    "RpcParams": [0, "xy", false]
}

例 3

BaseURLはhttps://my.service.orgで、クライアントはWebRPC("method?id=1", parameters)を呼びます。
パラメータは初歩的で単純な型です。文字列は「test」としましょう。
この場合、Photonはhttps://my.service.org/method?id=1を呼び、さらにJSONをPOSTします:

JSON

{
    "AppId": "00000000-0000-0000-0000-000000000000",
    "AppVersion": "client-x.y.z",
    "Region": "EU",
    "UserId": "userXYZ",
    "RpcParams": "test"
}

安全なデータを送信

WebRPCには利用可能な場合に、暗号化されたオブジェクトAuthCookieをWebサービスに安全に送信するオプションがあります。
これは、クライアントコードからWebRPCオペレーションメソッドを呼び出す際、適切なWebフラグ (SendAuthCookie = 0x02)を設定することで実行できます。

AuthCookie は、カスタム認証プロバイダに対する認証が成功した後に取得できます。
詳細は、

カスタム認証のドキュメントページ
を参照してください。

レスポンス

WebRPCのためのWebサービスは、Photonがクライアントに結果を返送できるようにJSONオブジェクトでレスポンスする必要があります。
予期されるレスポンスにはResultCodeData、または任意でMessage.を含める必要があります。

ResultCodeはO​​Kの場合は0、エラーの場合はその他のコードにしてください。 クライアントがエラーを処理できるよう、設定してください。
また、読み取り可能な文字列メッセージを追加することがベストプラクティスです。

Dataは空にすることが可能ですが、何かを送信する場合は有効なJSONオブジェクトでなければなりません。

例 1<!--

JSON

{
    "ResultCode": "0"
}

例 2<!--

JSON

{
    "ResultCode": "1",
    "Message": "Self-explanatory error message"
}

例 3<!--

JSON

{
    "ResultCode": "1",
    "Data": {
        "Key1": "V",
        "Key2": 1,
        "Key3": true
    }
}

URLタグ

ダッシュボードからwebhookまたはWebRpcのベースURLを設定する場合、必要に応じて、クエリ文字列の一部として1つ以上の動的変数 を設定することができます。
これらの変数は、リクエストを送信する前に、バックエンドでそれぞれの値に置き換えられます。

それぞれのアプリケーションのユーザー・セグメントを個別に処理したい場合は、URLのタグを使用します。
Photonは、次のURLのタグに対応しています:

  • {AppVersion} クライアントによって設定されたアプリケーションのバージョンを渡します。
  • {AppId} アプリケーションのIDを渡します。
  • {Region} トリガークライアントが接続されているクラウドリージョンのトークンを渡します。例:"eu"
  • {Cloud} は、トリガークライアントが接続されているクラウドの名前を渡します。例:「public」または「enigmaticenterprise」

URLタグの例

  1. https://{Region}.mydomain.com/{AppId}?version={AppVersion}&cloud={Cloud} 例:パラメータとして渡される異なるホスト、バージョン、およびクラウドに各リージョンをルート。
  2. https://mydomain.com/{Cloud}/{Region}/{AppId}/{AppVersion} 構造化されたURIとしてすべてのタグを渡します。

WebRPCを選択する理由

HTTPリクエストの送信は、Photonなしでも実行できます。
HTTPクライアントは自分で記述することができ、またはSDKやライブラリから利用することも可能です。
ただし、Photon WebRPCの機能はそれだけにとどまりません。
以下が、Photon WebRPCを利用する利点です:

  • すべてのロジックを単独の接続されたクライアント内に保持して、単独の「ライフサイクル」と「ステートマシン」を処理することを推奨します。Photonクライアントならば、これらをすべて実現できます。
  • WebRPCオペレーションは、2つの方法でJSON直列化を考慮します。
    -「BaseURL」とメソッド名はURLタグ機能をサポートします。
  • AuthCookieを使用してWebRPCに送信するか、またはさらに機密性の高いデータをサーバー間で送受信して、クライアントの正当性を確認できます。この機能の詳細についてはこちらを参照してください。

トラブルシューティング

以下に、WebRPCコールを作成した際に発生する可能性があるエラーコードと、その対処法を記載します。

  • OperationInvalid (-2)

通常、このエラーはアプリケーションにサーバー側でWebRPCが設定されていないか、または有効化されていないことを示しています。

  • HttpLimitReached (32745)

このエラーは、1秒間に作成するWebRPCリクエストが多すぎることを示しています。
エラーメッセージを確認し、上限数を確認してください。

  • ExternalHttpCallFailed (32744)

このエラーは、設定された外部ウェブサービスと通信する際に問題が発生していることを示しています。
エラーメッセージで詳細を確認し、対処してください。

GetGameList

この部分は、Photon製品には組み込まれていない特定な機能の例、GetGameListについて説明します。
私達のGitHubページで提供されているサンプルの1つを使用する場合は、リモート・プロシージャ名のスペルに注意してください。GetGamesListに「s」は含まれません。
または、任意の名前、あるいは任意のWebRPC実装を自由に選択できます。

GetGameListは、PhotonのWebRPC機能を実証するための「メモリデモ」で紹介した通り、特殊なWebRPCです。
ほとんどすべてのゲームは、以前に保存したゲームの一覧を取得する必要があるため、とても重要です。

その基本的な方法は、ウェブサービスにリクエストを送信し、発信ユーザが再参加し、プレイを継続するためのゲームリストを取得することです。
これは、アプリケーションが適切にダッシュボードから構成されることを前提としています。
BaseUrlはWebサービスを指し、ゲームデータを維持するためにはisPersistenttrueに設定し、[PathClose](~~~/gameplay/web-extensions/webhooks#close

Webhookを有効化する必要があります。
ウェブサービスに返されるべきゲームデータはPhotonの直列化されたルーム状態に依存しているので、後者は重要です。

一方、ウェブサービスは保存されたゲームデータへのアクセス権を持つべきであり、WebRPCのパスに送信されたプロセスHTTP POSTリクエストを受信および処理する準備ができている必要があります (ここではGetGameList)。

PhotonはすべてのWebRPCリクエストデータにUserIDを送信しているので、カスタムパラメータを追加する必要はありません。リクエストは、追加の引数なしで送信されます。

ウェブサービスは、JSONオブジェクトとしてDataに保存されたゲームのリストを返すべきです。保存された各ゲームのGameIdはキーを持ちます。それぞれの値は、2つのプロパティで構成されるJSONオブジェクトです。

  • ActorNr:WebRPCを呼び出すアクターが最初にそのルームに参加したときに割り当てられものと全く同じActorNr。これは、以前、意図的に個別で保存された場合、簡単に読み込むことができます。また、ActorListにループしてUserIdを比較することにより、それぞれのルームの保存されたStateオブジェクトから取得できます。

  • Properties:それぞれのルームの保存されたStateに含まれるCustomPropertiesプロパティから取得可能なロビーに表示されるCustomRoomPropertiesのキー:値ペア。

JavaScript

{
   "ResultCode":0,
   "Message":"",
   "Data":{
      "RoomA":{
         "ActorNr":3,
         "Properties":{  
            "Map":"USA",
            "Mode":"FFA",
            "Respawn":true
         }
      },
      "RoomB":{
         "ActorNr":5,
         "Properties":{  
            "Map":"Germany",
            "Mode":"TDM",
            "TeamA":1,
            "TeamB":5
         }
      },
      "RoomC":{
         "ActorNr":1,
         "Properties":{  
            "Map":"Russia",
            "Mode":"CTF",
            "TeamA":1,
            "TeamB":5,
            "Flag":20
         }
      }
   }
}

WebRPCの呼び出しはマスターとゲームサーバーの両方に許可されますが、ルームに参加していない場合はGetGameListを呼び出す方がより理にかなっています。例:Masterサーバから。

ウェブサービスへのデータの受け渡し

WebRPCは、クライアントからウェブサービスににデータを渡す3つの異なる方法を提供します。3つの異なるタイプを別々に使用するか、組み合わせることができます。
例えば、GetGameListを拡張し、特定の相手に基づいて保存したゲームのフィルタリングされたリストを取得する場合、3つの異なる方法で行うことができます:

  1. RESTfulの方法:

    相対 URI: /GetGameList/{opponentId}

  2. POSTデータ:

    相対 URI: /GetGameList

    Request data:

    Plain Old Text

    {
      "AppId": "00000000-0000-0000-0000-000000000000",
      "AppVersion": "client-x.y.z",
      "Region": "EU",
      "UserId": "userXYZ",
      "OpponentId": "opponentId"
    }
    
  3. Query string (a.k.a. GET parameters):

    相対 URI: /GetGameList?opponentId={opponentId}

もちろん、ウェブサービスは、選択された方法に従って更新する必要があります。

データ型の変換

ここでは、Photon ServerとWebサービス間で通信するデータ型のみを説明します。
クライアントとPhoton Server間で通信するデータ型の詳細は、Photonのシリアライゼーションをご覧ください。

Photon Server -> Webサービス

C# / .NET (Photon supported types) JavaScript / JSON
byte number
short
int
long
double
bool bool
string string
byte[] (byte array length < short.MaxValue) string (Base64 encoded)
T[] (array of supported type T, length < short.MaxValue) array
Hashtable (of supported types, count < short.MaxValue, preferably Photon implementation) object
Dictionary (keys and values of supported types, count < short.MaxValue) object
null null

リクエストデータ(型を連結済み)のサンプル

Photon Serverからの送信

JSON

{
    "(Dictionary<String,Object>)Dictionary":{
        "(Int32)dk_int":"1",
        "(String)dk_str":"dv2",
        "(Boolean)dk_bool":"True"
    },
    "(Hashtable)Hashtable":{
        "(Byte)hk_byte":"255",
        "(Object[])hk_array":[
            "(Int32)0",
            "(String)xy",
            "(Boolean)False"
        ],
        "hk_null":"null"
    },
    "null":"null",
    "(String[])string[]":[
        "PUN",
        "TB",
        "RT",
        "Bolt",
        "Chat"
    ],
    "(Byte[])byte[]":[
        "255",
        "0"
    ],
    "(Int16[])short[]":[
        "-32768",
        "32767"
    ],
    "(Int32[])int[]":[
        "-2147483648",
        "2147483647"
    ],
    "(Int64[])long[]":[
        "-9223372036854775808",
        "9223372036854775807"
    ],
    "(Single[])float[]":[
        "-3.402823E+38",
        "3.402823E+38"
    ],
    "(Double[])double[]":[
        "-1.79769313486232E+308",
        "1.79769313486232E+308"
    ],
    "(Boolean[])bool[]":[
        "True",
        "False"
    ]
}

Webサービスでの読み込み

JSON

{
    "(object)Dictionary":{
        "dk_int":"(number)1",
        "dk_str":"(string)dv2",
        "dk_bool":"(boolean)true"
    },
    "(object)Hashtable":{
        "(number)hk_byte":"255",
        "(array)hk_array":[
            "(number)0",
            "(string)xy",
            "(boolean)false"
        ],
        "hk_null":null
    },
    "null":null,
    "(array)string[]":[
        "(string)PUN",
        "(string)TB",
        "(string)RT",
        "(string)Bolt",
        "(string)Chat"
    ],
    "byte[]":"(string)/wA=",
    "(array)short[]":[
        "(number)-32768",
        "(number)32767"
    ],
    "(array)int[]":[
        "(number)-2147483648",
        "(number)2147483647"
    ],
    "(array)long[]":[
        "(number)-9223372036854776000",
        "(number)9223372036854776000"
    ],
    "(array)float[]":[
        "(number)-3.40282347e+38",
        "(number)3.40282347e+38"
    ],
    "(array)double[]":[
        "(number)-1.7976931348623157e+308",
        "(number)1.7976931348623157e+308"
    ],
    "(array)bool[]":[
        "(boolean)true",
        "(boolean)false"
    ]
}

Webサービス -> Photon Server

JavaScript/JSONの型と、C#/.Netの型との対応表は、以下の通りです。

JavaScript / JSON C# / .Net
object Dictionary
array object[] (array of objects)
number (integral) long
number (floating) double
string string
boolean bool
null (not a type) null
undefined (when sent) null

レスポンスデータ(型を連結済み)のサンプル

Webサービスからの送信

JSON

{
    "(object)number": {
        "(number)MAX_VALUE": "1.7976931348623157e+308",
        "(number)MIN_VALUE": "5e-324"
    },
    "(object)object": {
        "(string)string": "xyz",
        "null": null,
        "(boolean)bool": "false",
        "(undefined)undefined": "undefined",
        "(number)float": "-3.14",
        "(number)integer": "123456"
    },
    "(array)array": [
        "(string)xyz",
        "(number)0",
        "(boolean)true",
        null,
        "(undefined)undefined"
    ]
}

Photon Serverでの読み込み

JSON

{
    "(Dictionary<String,Object>)number":{
        "(Double)MAX_VALUE":"1.79769313486232E+308",
        "(Double)MIN_VALUE":"4.94065645841247E-324"
    },
    "(Dictionary<String,Object>)object":{
        "(String)string":"xyz",
        "null":"null",
        "(Boolean)bool":"False",
        "(Double)float":"-3.14",
        "(Int64)integer":"123456"
    },
    "(Object[])array":[ 
        "(String)xyz",
        "(Int64)0",
        "(Boolean)True",
        "null",
        "null"
    ]
}
Back to top