server | v4 switch to v3  

Photonプラグインマニュアル

PhotonプラグインはEnterprise CloudまたはセルフホスティングされたPhoton Server v4のみで利用可能です。

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

目次

ベストプラクティスや、よくある質問はPhotonプラグインFAQを参照してください。

イントロダクション

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

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

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

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

概念

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

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

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

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

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

基本フロー

Photonのhookメカニズムには、6段階のフローがあります:

  1. コールバックがトリガーされると、ホストは制御をプラグインに転送します。
  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"
        }
    }
  }
}

ファクトリ

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

プラグインのインスタンス化をトリガーするルームはIPluginFactory.Create メソッドにIPluginHostパラメータとして渡されます。 プラグイン自体の中のゲームへの参照を保持するため、同じパラメータをIGamePlugin.SetupInstanceに渡す必要があります。 IPluginHostはルームデータおよびオペレーションへのアクセスを提供します。

設定

Enterprise Cloud

新しいプラグインを追加するには: 1.サポートされている、いずれかのPhoton製品タイプのダッシュボードに 進みます。 2. そこに記載されているPhotonアプリケーションの管理ページの1つに進みます。 3. ページ下部の「Create a new Plugin」ボタンをクリックします。 4. 文字列型のキー/値のエントリーを追加して、プラグインを設定します。 設定は、文字列のキー/値のセットを定義することでおこないます。 各文字列に許可される最大長は256文字です。必要な設定は以下のとおりです:

  • AssemblyName: プラグインを含み、アップロードされたDLLファイルの正式な名前。
  • Version: プラグインのバージョン。Exit Gamesによって提供されるPowerShellスクリプトを使用してプラグインファイルをアップロードする際に使用、または返されるのと同じバージョンの文字列。
  • Path: アセンブリファイルへのパス。以下の形式にする必要があります:「{customerName}\{pluginName}」。
  • Type: 使用するPluginFactoryクラスの正式な名前。以下の形式となります:「{plugins namespace}.{pluginfactory class name}」

オンプレミス

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

プラグインファクトリ

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

単一のPhotonのプラグインアセンブリには、複数のプラグインクラスと1つのアクティブな"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には最大で1つの要素(プラグイン名の文字列)が含まれている必要があります。 複数の要素が送信された場合(roomOptions.Plugins.Length > 1)、PluginMismatchエラーが受信され、ルームへの参加または作成は失敗します。

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

ICallInfo処理メソッド

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

  1. Continue(): デフォルトのPhotonの処理を再開するために使用。
  2. Cancel(): 静かに処理をキャンセルするために使用します。つまり、クライアントにエラーやその他の通知は送信されません。 これによって、それ以降の処理がスキップされます:
    • OnRaiseEvent内で呼ばれると、受信イベントは無視されます。 * BeforeSetProperties内で呼ばれると、プロパティ変更がキャンセルされます。
  3. Fail(string msg, Dictionary<byte,object> errorData): クライアントにエラー応答を返し、それ以降の処理をキャンセルするために使用されます。 クライアントからは、OperationResponse.DebugMessagemsgパラメータ、OperationResponse.ParameterserrorDataを取得できます。
  4. Defer(): Photonは制御が返される前に処理メソッドの1つが呼ばれることを予期します。 このメソッドは処理を遅延させるために使用されます。これは、後から継続できるように使用することが可能です。

例:タイマーのコールバックまたは非同期HTTPリクエストを行う場合。この使用例については、アウトバウンドHTTPの項目をご覧ください。

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

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

Photon Serverには、あらかじめ定義されたhookが9個あります。コードでそれらのhookに明示的に登録する必要はありません。 デフォルトで、どのプラグインクラスもすべての9つのイベントを受信することができます。 ただし、必要なものを実装するべきです。PluginBaseを拡張し、必要なコールバックをオーバーライドすることをお勧めします。 すべてのコアイベントコールバックには、特定のICallInfoコントラクトがあります。 それらのほとんどは、クライアントの動作によって直接トリガーされます。 クライアントによって送信されたオペレーションリクエストは、利用可能な場所でICallInfo.Requestに提供されます。

OnCreateGame(ICreateGameCallInfo info)

  • 前提条件: クライアントがOpCreateRoomOpJoinOrCreateRoomまたは`OpJoinRoomを呼び、ルームがPhotonサーバーのメモリで検出できない。

    • 処理:
Continue
  • CreateGame オペレーション応答がReturnCode == ErrorCode.Okでクライアントに送信されます。
  • JoinイベントはSuppressRoomEvents == falseでない限り、クライアントに送り返されます。
  • もしプレイヤーのカスタムプロパティがICreateGameCallInfo.BroadcastActorProperties == trueの場合には、それらのプロパティはイベントパラメータに含まれます。
  • 初めて初期化した場合、ルームオプションと初期プロパティはルームの状態に割り当てられ、 ActorListには最初のアクターとそのデフォルトプロパティ (UserId and NickName)が含まれている必要があります。 リクエストにカスタムのアクタープロパティが含まれている場合、リスト内のアクターエントリーに追加する必要があります。
  • 変更された場合を除いてルームの状態が読み込まれた場合、ルームの状態は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 JoinGameオペレーション応答は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 はオペレーション応答で送り返されます。
  • SuppressRoomEvents == falseでない限り、Joinイベントはブロードキャストされます。
  • IJoinGameCallInfo.BroadcastActorProperties == trueの場合、プレイヤープロパティはイベントパラメータに含まれます。
Fail
  • JoinGameオペレーション応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
  • Adding of actor is reverted.アクターの追加は元に戻されます。
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の場合、相対キャッシュイベントも削除可能です。
    • ActiveActorListが空になると、EmptyRoomTTLミリ秒後にBeforeCloseGameコールが発生します。
Fail OpLeaveオペレーションでトリガーされた場合、その応答はReturnCode == ErrorCode.PluginReportedErrorでクライアントに送信されます。
Cancel N/A
Defer N/A
  • 注:
    • PlayerTTL はルーム作成中に設定できます。
      • PluginHost.BroadcastEventを呼ぶ場合、退出するアクターはイベントを受信しなくなります。

OnRaiseEvent(IRaiseEventCallInfo info)

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

BeforeSetProperties(IBeforeSetPropertiesCallInfo info)

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

OnSetProperties(ISetPropertiesCallInfo info)

  • 前提条件: IBeforeSetPropertiesCallInfo.Continue()BeforeSetPropertiesで呼ばれる。
  • 処理:
Continue nil
Fail 失敗のみログに記録します。
Cancel N/A
Defer N/A

BeforeCloseGame(IBeforeCloseGameCallInfo info)

  • 前提条件: すべてのピアが切断されます。
  • :処理:
Continue OnCloseGameをトリガーします。
Fail 失敗のみログに記録します。
Cancel N/A
Defer N/A
  • Notes: 注:
    • EmptyRoomTTLはルーム作成中にクライアントによって設定可能です。
      • ルームイベントキャッシュを変更しない限り、PluginHost.BroadcastEventへのコールはすべて無視されます。

OnCloseGame(ICloseGameCallInfo info)

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

高度なコンセプト

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

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

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

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

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

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

  • IPluginHost.GameActors にはルーム内のすべてのアクターが含まれます(アクティブおよび非アクティブ)。
  • IPluginHost.GameActorsActive には現在ルームに参加しているすべてのアクターが含まれています。
  • IPluginHost.GameActorsInActive にはルームを退出したすべてのアクター(放棄は除きます)が含まれています。

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

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

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

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

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

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

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

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

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

  • アクターになりすます: senderActor引数をルームに参加したアクター(アクティブなアクターである必要があります)のActorNumberに設定します。
  • 「オーソリテーティブ」または「グローバル」なルームイベントを送信する:senderActor引数を0に設定します。 これは、アクター番号0はプレイヤーにアサインされないためです。 このため、これはイベントの原点がクライアントでないことを示すために使用することも可能です。

ルームのイベントキャッシュを更新するために、上記のいずれかの方法を使用することも可能です。cacheOpパラメータを使用して、キャッシュオプションを定義することができます。 「Photonイベントのキャッシング」については、こちらを参照してください。

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

クライアントコードを変更することなく、プラグインから送信されたイベントデータを取得し、またクライアントから送信元のアクター番号を取得するには、 以下のように予期されるイベント構造にデータを送信してください: (Dictionary<byte, object>)eventDataでなく新たな Dictionary<byte, object>(){{245,eventData },{254,senderActorNr}}。 以下のヘルパーまたはラッパーメソッドのいずれか1つを利用できます。

アウトバウンドの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 Serverによって保存され、応答のコールバックに送り返されるオブジェクトです。 使用の一例は、延期された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を送信

例 : querystringを送信

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:結果的に生じたWebExceptionを示すWebExceptionStatus](https://msdn.microsoft.com/en-us/library/system.net.webexceptionstatus(v=vs.110).aspx)のコードを含みます。 - 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レスポンスからデータを取得するための2つの方法を提供します。 IHttpResponseを実装するクラスでは2つのプロパティが公開されています。

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

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

タイマー

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

Photon plugins SDKは、使用例に応じて2つの異なる変数を提供します:

ワンタイムタイマー

ワンタイムタイマーの目的は、期限後にメソッドを1回トリガーすることです。 このようなタイマーを作成するには、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でカスタムクラスのシリアル化をサポートするには、それらの型を登録する必要があります。 それぞれの型にコード(バイト)を割り当てて、クラスのフィールドとプロパティのシリアル化および非シリアル化のメソッドを提供する必要があります。 新しい型を登録するのと同じコードをクライアントでも使用します。 その後、登録を完了するために次のメソッドを呼び出します:

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メソッドのうちの1つを使用します。

Enterprise Cloud

弊社のサーバー上のログファイルへのアクセスは許可されていないため、ログや警告には外部サービスを使用する必要があります。 LogentriesまたはPapertrailの使用を推奨します。 このため、Enterprise Cloudを利用するユーザーは弊社までご連絡ください。ご要望に応じて、ロギングサービスを含むGMOクラウド Privateクラウドを設定いたします。 Logentries を利用したい場合には、設定されたログトークンをご連絡ください。 Papertrail を利用したい場合には、 ポートとカスタムURLをご連絡ください。

オンプレミス

デフォルトでは、ログ出力はGameServerログエントリーとともに「GSGame.log」ファイルで取得可能です。 個別のログファイルを使用するには、GameServerのlog4net設定ファイル("log4net.config")に以下のスニペットを追加します。

バージョニング

このセクションは、Photon Enterprise Cloudのユーザーにのみ関連します。

現在、Photonのプラグインはサイド・バイ・サイドのアセンブリバージョニングのみをサポートしています:AppIDごとに1つのプラグインDLLバージョンです。

新しいプラグインバージョンを展開するには、以下の2つの方法を推奨します:

A. 「互換性のある」プラグインの展開:新たなクライアントバージョンは不要です。

  1. 新しいバージョンのプラグインアセンブリをアップロードします。
  2. AppIDをステージングする際:新たなバージョンが予期されたとおりに動作している点を確認してください(推奨)。
  3. 新たなプラグインアセンブリバージョンを使用するため、本番のAppID設定を更新します。

B. 「互換性のない」プラグインの展開:新たなクライアントバージョンが必要です。

  1. プラグインアセンブリの新たなバージョンをアップロードします。
  2. 新たな本番のAppIDを設定します。
  3. 新たなプラグインアセンブリバージョンを使用するため、新たな本番のAppIDを設定します。

PUN固有のプラグイン

PUNをクライアントSDKとして使用し、これと連携するサーバー再度のプラグインを実装したい場合には以下を把握しておく必要があります。

  • PUNは、おもにUnityの基本クラスに追加のカスタム型を登録します。 これらをプラグインから処理したい場合には、プラグインからも同じカスタム型を登録する必要があります。 これらのカスタム型はすべてPUNパッケージの「CustomTypes.cs」クラスにあり、登録方法もここで参照できます。 カスタム型の登録に失敗すると、エラーや予期せぬ挙動が発生する可能性があります。 こうしたエラーや挙動を把握するため、IGamePlugin.OnUnknownType または IGamePlugin.ReportErrorを実装する必要があります。

  • PUNの固有かつ高度な機能はすべて、内部でRaiseEventを使用しています。 それぞれの機能は、1つまたは複数のイベントコードや特殊なイベントデータ構造を使用しています。 PUNに備えられたイベントのリストを取得するには、PUNパッケージ内の「PunClasses.cs」ファイルから「PunEvent」クラスを参照してください。たとえば、OnSerializeViewコールを受信するには、OnRaiseEventコールバックを実装して対応する型のイベントコードを取得する必要があります。この場合のイベントコードは「SendSerialize = 201」です。 各イベントで予期される内容を把握するには、そのイベントデータがPUNのコード内でどのように構築されているか、またはプラグイン内の受信イベントから詳細を確認してください。

AuthCookie

AuthCookieは安全なデータとも呼ばれ、認証プロバイダーとしてセットアップされたWebサービスから返されるオプションのJSONオブジェクトです。 このオブジェクトはクライアント側からはアクセスできません。 詳細な情報はカスタム認証のドキュメントページを参照してください。 プラグインからAuthCookieにアクセスする手順は、以下のとおりです:

  • ICallInfo.AuthCookie: hookをトリガーしている現在のアクターのAuthCookieを取得します。 ただし、OnBeforeCloseGameOnCloseGameでは、IBeforeCloseGameCallInfo.AuthCookieICloseGameCallInfo.AuthCookieはそれぞれ、どのような値も持ちません。これは、これらはユーザーのコンテキスト外でトリガーされるためです。

例:

    public void OnCreateGame(ICreateGameCallInfo info)
    {
        Dictionary<string, object> authCookie = info.AuthCookie;
- IActor.Secure: アクティブなアクターにAuthCookieを取得する、など。
    foreach (var actor in this.PluginHost.GameActorsActive)
    {
        var authCookie = actor.Secure as Dictionary<string, object>;
    }

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