server | v4 switch to v3  

Photonプラグインマニュアル

Photon PluginはエンタープライズクラウドまたはセルフホスティングされたPhoton Server v4のみで利用可能です。

Photon 4では、Photon 3で継承によって行われていた、ゲーム/ルームの動作を拡張する新しい方法としてプラグインが導入されています。

目次

導入

Photon Loadbalancingは、カスタム無しのクラウド上(サーバ側のカスタムコード無し)と、カスタム動作で拡張した自己ホスト型の両方の環境で、ルームベースゲームのためのプラットフォームとして進化してきました。 数年にわたり機能セットは進化してきましたが、クライアントとサーバ間のコアフロー(ゲーム作成、参加、退室などのオペレーションとそれらのイベント)は非常に安定しているので、後方互換性は維持されています。

CPhoton 3までは、カスタマイズはソースコード (Lite & Loadbalancing)に基づいており、一般的にゲームのクラスから継承していました。 これは柔軟でしたが、クライアント、ゲームサーバとマスターとの間のフローが予期せず中断する可能性があるので(クライアントが応答またはイベントを待機して「スタック」する場合など)開発においては柔軟性に欠けより複雑でした。

Plugin APIはコアフローの近くに設計されています(ルーム作成、参加、退室など)。

  1. .高度な柔軟性を維持: その処理の前と後のコアフローにフックすることができます。
  2. フローを破壊する可能性を最小化: クライアントとサーバー上の素早く提供されるエラーの失敗。
  3. ロックフリーコードの使用を許可: プラグインのインスタンスは一度に複数のコールを受けることはありません。また、フレームワークは、基礎となるPhotonメッセージパッシングアーキテクチャ(ファイバー)に統合されるタイマーとHTTPクライアントを提供します。
  4. 複雑さを低下させ、使いやすさを上げる: "Minimal Plugin"を参照してください。

概念

カスタムのサーバロジックを追加するには、事前定義されたPhotonのserver hookにコードを注入します。 hookはルームのイベントによってトリガーされるので、現在Photon ServerはGameServerプラグインにしか対応していません。

定義により、Photonのプラグインには固有の名前があ​​り、それらのイベントコールバックを実装します。 カスタムのプラグインはplugins assemblyというDLLファイルにコンパイルされます。 その後、必要なファイルはPhotonサーバ上でデプロイされるか、エンタープライズクラウドにアップロードされます。

構成されたプラグインアセンブリは各ルームの作成で、動的に実行時に読み込まれます。 次に、プラグインのインスタンスがファクトリパターンに基づいて作成されます。

プラグインの作成をトリガするルームは「host」ゲームと呼ばれます。 後者は、直接プラグインからアクセスすることができ、どちらも同じライフサイクルを共有しています。

Webhookは、Photonプラグインの良い例です。 Webhool 1.2のソースコードは、プラグインのSDKで提供されています。 確認することをお勧めします。

基本的な流れ

Photonのhook機構には6段階のフローがあります:

  1. hookの呼び出しを遮る コー​​ルバックがトリガーされると、ホストは制御をプラグインに転送します。
  2. コー​​ル情報を変更[任意]
    処理される前に、クライアント/サーバによって送信された要求をアクセスおよび変更。
  3. カスタムコードを注入[任意] 呼び出しを処理する前に、ホストとインタラクトする(例:HTTPリクエスト、ルーム/アクターのクエリ、タイマーの設定、など)
  4. hookのコールを処理 方法を決定しリクエストを処理する(「ICallInfoの処理方法」を参照してください)
  5. カスタムコードを注入[任意] 処理された後は、クライアント/サーバーから送信されたリクエストは、「読み取り専用」となります。 しかし、処理後もプラグインはホストとインタラクトすることができます。
  6. 戻る プラグインがホストに制御を返す。

入門

最小限のプラグイン

プラグイン

プラグインの作成を行うお勧めの方法は、直接すべてのIGamePluginを実装する代わりにPluginBaseクラスを拡張することです。 こうすることにより、必要なものだけをオーバーライドすることができます。

最小限のプラグインの実装を取得するには、PluginBase.Nameプロパティをオーバーライドするだけです。これは、プラグインを識別するものです。

"デフォルト"は、プラグイン名として使用することはできません。
    namespace MyCompany.MyProject.HivePlugin
    {
      public class CustomPlugin : PluginBase
      {
        public override string Name
        {
            get
            {
                return "CustomPlugin"; // anything other than "Default"
            }
        }
      }
    }

ファクトリ

プラグインファクトリクラスはMyCompany.MyProject.HivePlugin.dllの一部として実装されるべきです。 これは、ルームごとのプラグインインスタンスの作成を行います。 簡単にするため、次のスニペットでは、ファクトリはクライアントからリクエストされたプラグイン名を確認せずに、デフォルトでCustomPluginインスタンスを返します。

プラグインのインスタンス化をトリガーするルームはIPluginFactory.CreateメソッドにIPluginHostパラメータとして渡されます。 同じパラメータは、プラグイン自体の中のゲームへの参照を保持するためにIGamePlugin.SetupInstanceに渡す必要があります。 IPluginHostはルーム状態、プロパティ、コールバックへのアクセスを提供します。

構成

Photon Enterprise Cloud:

次の方法で新しいプラグイン(カスタム拡張)を追加します: 1. 対応されているPhoton製品タイプのいずれかのダッシュボードに行きます。
2. 次に、そこに記載されているPhotonアプリケーションの管理ページの一つに移動します。
3. そこでページ下部の"新しいプラグインを作成"ボタンをクリックしてください。
4. 文字列型のキー/値のエントリを追加することによって、プラグインを設定することができるようになりました。設定は、文字列のキー/値の組を定義することによって行われます。各文字列に許可される最大長は256文字です。必要な設定は以下のとおりです:

  • AssemblyName: プラグインを含むアップロードされたDLLファイルの正式な名前。
  • Version: プラグインのバージョン。Photonが提供するPowerShellスクリプトを使用してプラグインのファイルをアップロードするときに使用または返されるのと同じバージョンの文字列。
  • Path: アセンブリファイルへのパス。次の形式を持ちます: "{customerName}\{pluginName}".
  • Type: 使用するPluginFactoryクラスの正式な名前。 次の形式を持ちます: "{plugins namespace}.{pluginfactory class name}".

Photon Server:

適切なサーバ・アプリケーションの"Photon.LoadBalancing.dll.config"ファイルに次のXMLノードを追加する必要があります。 <Plugin.../>要素の必要な属性は、例に示されています。その他の追加の属性は任意です。 <PluginSettings>要素でEnabled属性の値を変更することで、簡単にプラグインを有効化または無効化することができます。

ファクトリ

私たちのプラグインモデルはファクトリパターンを使用しています。プラグインはリクエストに応じて名前からインスタンス化されます。

単一のPhotonのプラグインアセンブリは、複数のプラグインクラスと一つのアクティブな「PluginFactory」を含むことができます。 複数の「PluginFactory」を作ることは可能ですが、特に必要はありません。 一方、複数のプラグインクラスを書くことは非常に有用です。 たとえば、ゲームのタイプ(またはモードや難易度)ごとにプラグインを持つことができます。

クライアントはroomOptions.Pluginsを使用して、プラグインの設定をリクエストするルームを作成します。 roomOptions.Pluginsstring[]であり、最初の文字列 (roomOptions.Plugins[0]) は、ファクトリに渡されるプラグインの名前であるべきです。

例:
roomOptions.Plugins = new string[] { "NameOfYourPlugin" };
または
roomOptions.Plugins = new string[] { "NameOfOtherPlugin" };

クライアントが何も送信しない場合、サーバはデフォルト(何も設定されていない場合)、または、設定されている場合はプラグインファクトリが作成時に返すものを使用します。

PluginFactory.Createで返されたプラグインの名前がクライアントによってリクエストされたものと一致しない場合は、プラグインはアンロードされ、クライアントの作成または参加オペレーションは失敗してPluginMismatch (32757)エラーとなります。
また、現在、roomOptions.Pluginsには多くても一つの要素(プラグイン名の文字列)が含まれている必要があります。 複数の要素が送信された場合(roomOptions.Plugins.Length > 1)、PluginMismatchエラーが受信され、ルームへの参加または作成は失敗します。

ファクトリでは名前を使用して対応するプラグインを読み込みます。

ICallInfo 処理メソッド

プラグインの概念は、受信リクエストを処理する前または後に、「通常」のPhotonフローにフックすることです。開発者は、リクエストのタイプに応じて次の4つのいずれかの方法を使用して何を行うかを決定します:

  1. Continue(): デフォルトのPhotonの処理を再開するために使用。
  2. Cancel(): 静かに処理をキャンセルするために使用します。例:クライアントにエラーやその他の通知を行わずに。これは、さらに処理をスキップするのと同じです。
    • OnRaiseEvent内で呼ぶと着信イベントを無視します。
    • BeforeSetProperties内で呼ぶとプロパティの変更をキャンセルします。
  3. Fail(string msg, Dictionary<byte,object> errorData): さらに処理を行いクライアントにエラー応答を返すことをキャンセルするために使用します。 クライアントからは、OperationResponse.ParametersOperationResponse.DebugMessageerrorDatamsgパラメータを取得することができます。
  4. Defer(): Photonは、制御が戻される前に、処理メソッドの一つが呼び出されることを期待します。 このメソッドは、処理を延期するために使用されます。後から継続できるようにするために使用することができます。 例:タイマーのコールバックまたは非同期HTTPリクエストを行う場合。このユースケースについては、アウトバウンドHTTPの項目をご覧ください。

補足:

  • プラグインは、デフォルトでstrictモードを有効にすべきです(UseStrictMode = true)。 strictモードではICallInfo処理方法のいずれかへの呼び出しが、各プラグインのコールバックで行われます。 利用可能なメソッドを一つも呼び出さないと、例外が発生します。
  • IGamePluginPluginBase実装のすべてのコールバックは{ICallInfo}.Continue()を呼びます。
  • Continue(), Fail()Cancel()は一度のみ呼ばれるべきです。これらのどれかを再度呼び出すと、例外が発生します。
  • Defer() と Cancel()OnRaiseEventまたはBeforeSetProperties内でのみ呼び出すことができます。
  • ICallInfoを実装するすべてのクラスは、利用可能な場合、クライアントの元のオペレーションリクエストを公開します。 {ICallInfo}.OperationRequest (またはRequest)プロパティからオペレーションコードとパラメータを取得することができます。
  • ICallInfoを実装するすべてのクラスには、オペレーションリクエストのCallStatus処理を知らせるために、ヘルパーのプロパティが含まれます。
    • IsNew: リクエストが処理や延期されたか否かを示す。
    • IsProcessed: リクエストがすでに処理されているか否かを示す(例えば、Continue, Cancel または Failメソッドが呼ばれた)。
    • IsSucceeded: リクエストが正常に処理されたか否かを示す(例えば、Continueメソッドが呼び出された)。
    • IsCanceld: リクエストがキャンセルされたか否かを示す(例えば、Cancelメソッドが呼び出された)。
    • IsDeferred: リクエストが延期されているか否かを示す(例えば、Deferメソッドが呼ばれた)。
    • IsFailed: リクエストが「失敗した」か否かを示す(例えば、Failメソッドが呼ばれた)。

プラグインのコールバック

Photon serverには9つの事前に定義されたhookがあります。明示的にコードでそれらのhookに登録する必要はありません。 デフォルトで、どのプラグインクラスも9つ全てのイベントを遮ることができます。 しかし、必要なものを実装するべきです。PluginBaseを拡張し、必要なコールバックをオーバーライドすることをお勧めします。

すべてのコアイベントコールバックは、特定のICallInfo それらのほとんどは、直接クライアントの動作によってトリガーされます。 クライアントによって送信されたオペレーションリクエストは、利用可能な場所でICallInfo.Requestに提供されます。

OnCreateGame(ICreateGameCallInfo info)

  • 前提条件: クライアントがOpCreateRoom or OpJoinOrCreateRoom or OpJoinRoomを呼び、ルームがPhotonサーバのメモリで検出できない。
  • 処理:
Continue
  • CreateGame オペレーション応答が ReturnCode == ErrorCode.Okでクライアントに送信されます。
  • SuppressRoomEvents == falseでない限り、Joinイベントはクライアントに送り返される。
  • ICreateGameCallInfo.BroadcastActorProperties == true の場合、プレイヤーのカスタムプロパティが存在すれば、イベントのパラメータに含まれます。
  • 初めて初期化した場合、ルームのオプションと初期プロパティはルームの状態に割り当てられ、 ActorList には最初のアクターとそのデフォルトプロパティ(UserIdNickName)が含まれている必要があります。 リクエストにカスタムのアクタープロパティが含まれている場合、リスト内のアクター・エントリに追加する必要があります。
  • 変更された場合を除き、 ルームの状態が読み込まれた場合はPhotonサーバのメモリからの最後の除去前と同じでなければなりません。
Fail CreateGame オペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel N/A
Defer N/A
  • 補足:
    • リクエストを処理する前、ルームの状態は初期化されず、デフォルト値が含まれています。 これは、IPluginHost.SetGameStateを呼び出すことによってルームの状態を外部ソースから読み込み、解析し、ルームに割り当てることができる唯一の​​状況です。
    • リクエストを処理する前に、PluginHost.SetPropertiesまたはPluginHost.BroadcastEventへの呼び出しは無視されます。
    • ICreateGameCallInfo.IsJoinICreateGameCallInfo.CreateIfNotExistsを使用してオペレーションリクエストの種類を知ることができます。
オペレーションメソッド IsJoin CreateIfNotExist
OpCreateRoom false false
OpJoinRoom true false
OpJoinOrCreateRoom true true

BeforeJoin(IBeforeJoinGameCallInfo info)

  • 前提条件: クライアントがOpJoinRoomOpJoinOrCreateRoomまたはOpJoinRandomRoomを呼び、ルームはPhotonサーバのメモリ内にある。
  • 処理:
Continue OnJoinコールバックをトリガー。
Fail JoinGameJoinGameオペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel N/A
Defer N/A
  • 補足:
    • IBeforeJoinGameCallInfoを処理する前、PluginHost.BroadcastEventを呼び出す場合はそれをキャッシュしない限り、参加しているアクターはイベントを受け取りません。

OnJoin(IJoinGameCallInfo info)

  • 前提条件: IBeforeJoinGameCallInfo.Continue()BeforeJoinで呼ばれます。
  • 処理:
Continue
  • 参加が許可されている場合、参加するアクターはアクターのデフォルトプロパティ(UserIdNickName)と一緒にActorListに追加されます。
  • リクエストにカスタムのアクタープロパティが含まれている場合、それらも設定する必要があります。
  • JoinGameオペレーション応答はReturnCode == ErrorCode.Okを使用してクライアントに送り返されます。
  • IJoinGameCallInfo.PublishUserId == trueの場合、他のアクターのUserIdはオペレーション応答でクライアントに送り返されます。
  • JoinイベントはSuppressRoomEvents == falseでない限り、ブロードキャストされます。
  • IJoinGameCallInfo.BroadcastActorProperties == true の場合、プレイヤーのカスタムプロパティがあれば、イベントのパラメータに含まれます。
Fail
  • JoinGameオペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
  • アクターの追加は元に戻されます。
Cancel N/A
Defer N/A

OnLeave(ILeaveGameCallInfo info)

  • 前提条件: クライアントがOpLeaveを呼び、ピアが切断するかPlayerTTLが経過 (アクターのライフサイクルを参照してください)​​。
  • 処理:
Continue
  • OpLeaveオペレーションでトリガーされた場合、その応答はReturnCode == ErrorCode.Okでクライアントに送信されます。
  • SuppressRoomEvents == falseでない限り、Leaveイベントは他のアクターに送信されます。
  • ILeaveGameCallInfo.IsInactive == trueの場合:
    • アクターは非アクティブとしてマークされます。
    • DeactivationTimeは、そのプロパティに追加されます。
  • ILeaveGameCallInfo.IsInactive == falseの場合:
    • アクターとそのプロパティはActorListから削除されます。
    • DeleteCacheOnLeave == trueの場合、相対のキャッシュされたイベントも除去することができます。
    • ActorListが空になると、BeforeCloseGameコールがEmptyRoomTTLの後、ミリ秒以内に実行されます。
Fail OpLeaveオペレーションをトリガーした場合、その応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel N/A
Defer N/A
  • 補足:
    • PlayerTTLOpCreateRoomRoomOptionsまたはOpJoinOrCreateを通じてクライアントにより設定することができます。
    • PluginHost.BroadcastEventを呼び出す場合、退去するアクターはイベントを受け取らなくなります。

OnRaiseEvent(IRaiseEventCallInfo info)

  • 前提条件: クライアントがOpRaiseEventを呼び出します。
  • 処理:
Continue
  • キャッシングオプションを使用するとルームの状態のイベントキャッシュを更新することができます。
  • カスタムイベントは、そのパラメータに応じて送信されます。
Fail RaiseEventオペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel 静かに処理をスキップします。
Defer 処理が延期されます。
  • 補足:
    • IRaiseEventCallInfoが正常に処理されている場合、オペレーション応答はクライアントに送信されません。

BeforeSetProperties(IBeforeSetPropertiesCallInfo info)

  • 前提条件: クライアントがOpSetPropertiesを呼び出します。
  • 処理:
Continue
  • ルームやアクターのプロパティが更新される。
  • SetPropertiesオペレーション応答はReturnCode == ErrorCode.Okを使用してクライアントに送り返されます。
  • PropertiesChangedイベントがブロードキャストされます。
Fail SetPropertiesオペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel 静かに処理をスキップします。
Defer 処理が延期されます。
  • 補足:
    • 変更するプロパティがルームまたはアクターに属しているかを知るためには、IBeforeSetPropertiesCallInfo.Request.ActorNumberの値を確認します。 0の場合、ルームのプロパティが更新されようとしています。それ以外の場合、プロパティの更新を必要としているターゲットアクターの番号です。
    • IBeforeSetPropertiesCallInfo.ActorNrと前述のActorNumberを混在しないように注意してください。 後者は、オペレーションリクエストを作成するアクターを指します。

OnSetProperties(ISetPropertiesCallInfo info)

  • 前提条件: BeforeSetPropertiesIBeforeSetPropertiesCallInfo.Continue()が呼ばれている。
  • 処理:
Continue nil.
Fail 失敗のみログに記録。
Cancel N/A
Defer N/A

BeforeCloseGame(IBeforeCloseGameCallInfo info)

  • 前提条件: すべてのピアが切断され、EmptyRoomTTLが経過。
  • 処理:
Continue OnCloseGameがトリガーされます。
Fail 失敗のみログに記録。
Cancel N/A
Defer N/A
  • 補足:
    • EmptyRoomTTLOpCreateRoomRoomOptions、またはOpJoinOrCreateを通じてクライアントにより設定することができます。
    • PluginHost.BroadcastEventへの如何なる呼び出しも、それがルームイベントのキャッシュを変更しない限り無視されます。

OnCloseGame(ICloseGameCallInfo info)

  • 前提条件: IBeforeCloseGameCallInfo.Continue()BeforeCloseGameで呼ばれます。
  • 処理:
Continue ルームはPhotonサーバのメモリから削除され、プラグインのインスタンスがアンロードされます。
Fail 失敗のみログに記録。
Cancel N/A
Defer N/A
  • 補足:
    • ICloseGameCallInfoを処理する前に、ルームの状態を保存するか、永久に失うことを選択することができます。 Webhookでは、ルーム内に少なくとも一人の非アクティブなアクターがいればこれを行うことができます。

上級コンセプト

アクターのライフサイクル

ピア< - >アクター< - >ルーム

アクターとはルームの中のプレーヤーです。 プレイヤーは、作成または入室することでルームに入ると、アクターで表されます。 アクターはActorNrと、それに続くUserId及びNickNameを使用して定義されます。 また、カスタムプロパティを有することができます。 プレイヤーが最初にルームに入ると他のプレイヤーが取得することのできないアクター番号をルーム内で取得します。 また、各新しいプレーヤーのアクターはルームのActorsListに追加されます。

プレイヤーが完全にルームを出るとそのアクターがリストから削除されます。 しかし、ルームのオプションにより許可されている場合、プレイヤーはルームを出ても後から戻ることができます。 この場合、プレイヤーが出るときにその対応アクターが非アクティブとしてマークされます。 イベントのタイムスタンプは、DeactivationTimeアクタープロパティに保存されます。

アクターが非アクティブの状態でルーム内に滞在できる時間を制限することができます。 ミリ秒単位で必要な値にPlayerTTLオプションを設定することで、ルーム作成時にこの時間を定義することができます。 負の値または最大のint値に等しい場合、アクターは無期限に非アクティブで滞在することができます。 それ以外の場合は、DeactivationTime後にPlayerTTLが経過すると非アクティブなアクターはルームから削除されます。 それまではプレイヤーはルームに再び戻ることができます。 アクターが再び一時的にルームを出る場合は、新しいDeactivationTimeが計算され、カウントダウンがリセットされます。 そのため、再入室の回数に制限はありません。

PhotonプラグインSDKでは、すべてのアクターが以下のプロパティの1つを任意の時点で使用できる方法を提供します:

  • IPluginHost.GameActorsActiveにはルーム内の全てのアクターが含まれています(アクティブおよび非アクティブ)。
  • IPluginHost.GameActorsActiveには現在ルームに参加している全てのアクターが含まれています。
  • IPluginHost.GameActorsInActiveにはルームを退室した(放棄せず)全ての関係者が含まれています。

プラグインからイベントを送信

PhotonプラグインSDKを使用して、ルームの中でカスタムイベントを送信することができます。 カスタムのイベントのタイプと内容はそのコードによって定義されるべきです。 また、イベントコードは200未満にとどまるべきです。

そのためには2つのオーバーロードメソッドがあります。 BroadcastEvent名前は、イベントが放送されることを示唆していますが、 フィルタに基づいてマルチキャストを行うか、単一のアクターに送信することができます。

  • 特定のアクターグループに送信:

「既知の」グループのいずれかにtarget引数を設定することができます。

  • 0: ReceiverGroup.Others
  • 1: ReceiverGroup.All
  • 2: ReceiverGroup.MasterClient

また、targetGroup引数を使用して「インタレスト・グループ」でアクターの受信をフィルタリングすることができます。 イベントは、その「インタレスト・グループ」に登録されたアクターにのみ送信されます。 デフォルトでは、すべてのアクターは「インタレスト・グループ 」0に登録されています。

  • 特定のアクターリストに送信。

Photonイベントはイベント(送信者)の原点としてアクター番号を必要とするので、2つの選択肢があります:

  • アクターを偽装:ルームに参加しているアクターのactorNumberにsenderActor引数を設定(アクティブまたは非アクティブ)。
  • 権威ルームイベントを送信:senderActor引数を0に設定します。 Since the actor number 0 is never assigned to a player. So it may be used to indicate that the event origin is not a client.

ルームのイベント・キャッシュを更新するためにいずれかの方法を使用することも可能です。 cacheOp parameterを使用して、キャッシュ・オプションを定義することができます。 Photonイベントのキャッシングについては、こちらをご覧ください。.

PluginBase(推奨)からプラグインクラスを拡張する場合、ルームに入室しているすべてのアクターにイベントをブロードキャストするために、以下のヘルパーメソッドを使用することができます。

クライアントコードを変更することなく、プラグインからイベントデータを取得し、クライアントから送信元のアクター番号を取得するには、 次のように予想されるイベントの構造にデータを送信してください:  (Dictionary<byte, object>)eventData の代わりにnew Dictionary<byte, object>(){{245,eventData },{254,senderActorNr}}

アウトバウンドのHTTP呼び出し

HttpRequestはHTTPリクエストを構築するヘルパークラスです。 このクラスを使用して、URLとHTTPメソッド(デフォルトは"GET")や、Accept及びContentTypeヘッダを設定することができます。 これらのプロパティの値は、HttpWebRequestで対応する必要があります。 また、他のカスタムHTTPヘッダをIDictionary<string, string> として指定して、HttpRequest.CustomHeadersに割り当てることができます。 また、最初にMemoryStreamオブジェクトへの変換を行い、HttpRequest.DataStreamに割り当てることによってリクエストデータを追加することができます。 詳細についてはPost JSONの例をご確認ください。

プラグインロジックに重要でPhoton限定の次の2つのプロパティがあります:
  • Async: レスポンスを受信するまでルームロジックの通常の処理を中断するかどうかを示すフラグです。 ルームのロジックがHTTPレスポンスに依存する場合、これをfalseに設定する必要があります。
  • UserState: リクエストごとにPhotonサーバによって保存され、応答のコールバックに送り返されるオブジェクト。 ユースケースの一例は、繰延ICallInfoを(OnRaiseEventまたはBeforeSetProperties)に格納することです。また、後から処理をするには(Continue()を呼びます)。

HttpRequestクラスは、次のシグネチャを持つ応答のコールバックへの参照も保持する必要があります: public delegate void HttpRequestCallback(IHttpResponse response, object userState).

リクエストオブジェクトが設定されたら、IPluginHost.HttpRequest(HttpRequest request)を呼び出すことによってそれを送ることができます。

ユースケースの例:

例:OnRaiseEventでDeferとAsyncを利用

この基本的な例では、HTTP応答を受信するまでRaiseEventオペレーションを遅延させる方法を示しています。 まず、OnRaiseEventコールバックでHTTPリクエストを送信し、その後ICallInfoを延期します。

応答が受信されると、正常にRaiseEventオペレーションを処理し続けるか、中止するかを決定する必要があります。

例:JSONを送信

例:クエリ文字列を送信

HTTPレスポンスの処理

応答コールバックでは、最初にIHttpResponse.Statusを確認するべきです。 これは、次のいずれかのHttpRequestQueueResult値を持ちます。

  • Success (0): エンドポイントがHTTPステータスコードを返すことに成功しました (例:2xxコード)。
  • RequestTimeout (1): エンドポイントは時間内に応答を返しませんでした。
  • QueueTimeout (2): リクエストがHttpRequestQueue内でタイムアウト。 リクエストがキューに登録されると、タイマが起動します。前のクエリに時間がかかりすぎるときにタイムアウトします。
  • Offline (3): アプリケーションの該当HttpRequestQueueがオフラインモードになっている。 HttpRequestQueueが再接続するのにかかる時間である10秒の間にHttpRequestは行われない。
  • QueueFull (4): HttpRequestQueueが、該当アプリケーションのための特定のしきい値に達している。
  • Error (5): リクエストのURLが解析できなかったか、ホスト名が解決できなかったか、エンドポイントに到達できなかった。 エンドポイントがエラーHTTPステータスコードを返す場合にも発生するかもしれません。 (例:400:BAD REQUEST

結果がSuccess (0)でない場合、次のプロパティを使用して問題についての詳細を取得することができます:

  • Reason: エラーの可読形式。IHttpResponse.StatusHttpRequestQueueResult.Errorに等しいときに便利です。
  • WebStatus: 如何なる最終的なWebExceptionStatusを示す WebExceptionのコードを含む。
  • HttpCode: 返されたHTTPステータスコードが含まれています。

コードでこれを行う方法の例を示します:

private void OnHttpResponse(IHttpResponse response, object userState) {
    switch(response.Status){
        case HttpRequestQueueResult.Success:
            // on success logic
            break;
        case HttpRequestQueueResult.Error:
            if (response.HttpCode <= 0) {
                PluginHost.BroadcastErrorInfoEvent(
                    string.Format("Error on web service level: WebExceptionStatus={0} Reason={1}",
                    (WebExceptionStatus)response.WebStatus, response.Reason));
            } else {
                PluginHost.BroadcastErrorInfoEvent(
                    string.Format("Error on endpoint level: HttpCode={0} Reason={1}",
                    response.HttpCode, response.Reason));
            }
            break;
        default:
            PluginHost.BroadcastErrorInfoEvent(
                string.Format("Error on HttpQueue level: {0}", response.Status));
            break;
    }
}

使いやすくするため、PhotonプラグインSDKはHTTPレスポンスからデータを取得するための二つの方法を提供します。 IHttpResponseを実装するクラスでは二つのプロパティが公開されています。

  • ResponseData: レスポンスボディのバイト配列。受信データがテキスト形式でない場合に有用です。
  • ResponseText: レスポンスボディのUTF8文字列バージョン。受信したデータがテキストである場合に役立ちます。

レスポンスクラスは、後で必要な場合のために対応するHttpRequestへの参照を保持します。 それはIHttpResponse.Requestにあります。

タイマー

タイマーは、特定のタイミングでメソッドを呼び出すために設定するオブジェクトです。 タイマーが作成されると、カウントダウンが自動的に起動します。 これは、プラグインからコード実行をスケジュールまたは遅らせるための最良の方法です。

PhotonプラグインSDKは、ユースケースに応じてタイマーの変種を提供します:

ワンタイム・タイマー

ワンタイムタイマーは期限後に一度メソッドをトリガーすることが目的です。 このようなタイマーを作成するには、2つの引数のみを受ける次のオーバーロードメソッドを使用する必要があります:
object CreateOneTimeTimer(Action callback, int dueTimeMs);
スケジュールされたアクションを発生前にキャンセルする場合を除き、この種のタイマーは停止する必要はありません。 その場合はvoid IPluginHost.StopTimer(object timer)を使用するべきです。

例:SetPropertiesの遅延

タイマーの繰り返し

繰り返しタイマーは、定期的にメソッドを呼び出します。 最初のコールバックの実行の時間と、次に続く​​実行間隔を定義することができます。 このようなタイマーを作成するには、3つの引数を取る次のオーバーロードメソッドを使用する必要があります:
object CreateTimer(Action callback, int dueTimeMs, int intervalMs);
この種のタイマーは、それが実行されていて、プラグインがに読み込まれている(ルームが閉じていない)限り、対応するメソッドを呼び出し続けます。 void IPluginHost.StopTimer(object timer)を使用して、いつでも停止することができます。

例:スケジュールされたイベント

カスタム・タイプ

Photonにカスタムクラスの直列化を対応させる場合、タイプを登録する必要があります。 手動で各タイプのコード(byte)を割り当てて、クラスのフィールドとプロパティの直列化および非直列化メソッドを提供する必要があります。 新しい型を登録する同じコードをクライアントでも使用します。 その後、登録を完了するために次のメソッドを呼び出します:

bool IPluginHost.TryRegisterType(Type type, byte typeCode, Func<object, byte[]> serializeFunction, Func<byte[], object> deserializeFunction);

例:CustomPluginTypeの登録

登録するカスタム型クラスの例:

class CustomPluginType
{
    public int intField;
    public byte byteField;
    public string stringField;
}
カスタムタイプの登録は両側で行うべきです。 つまり、Photonクライアントは同じコードと直列化メソッドのカスタムタイプを登録するべきです。

直列化メソッドは、カスタム型のオブジェクトをバイト配列に変換する必要があります。 最初に予想される型(CustomPluginType)にオブジェクトをキャストする必要があります。

非直列化の方法は、その反対です。 それはバイト配列からカスタム型オブジェクトをコンストラクトし戻します。

private object DeserializeCustomPluginType(byte[] bytes)
{
    CustomPluginType customObject = new CustomPluginType();
    using (var s = new MemoryStream(bytes)){
        using (var br = new BinaryReader(s))
        {
            customObject.intField = br.ReadInt32();
            customObject.byteField = br.ReadByte();
            customObject.stringField = br.ReadString();
        }
    }
    return customobject;
}

最後に、CustomPluginTypeを登録する必要があります。 これは、プラグインがSetupInstanceで初期化され次第行うことができます。

ログの記録

プラグインからログを記録するには、PluginHost.LogXXXのメソッドのいずれかを使用します。 デフォルトで、ログ出力はGameServerのログエントリと共に「GSGame.log」ファイルで取得することができます。 個別のログファイルを使用するには、ゲームサーバのlog4netの設定ファイル( "log4net.config」)に次のコードを追加します。

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