.NETプラットフォームSDK
本項はNETおよびUnity向けの、Photon Client Libraryのドキュメントとリファレンスです。
概要
Photonは、様々なプラットフォーム向けにリアルタイムのマルチプレイヤーゲームやアプリケーションを構築するための開発フレームワークです。
様々なプラットフォームに対応するServer SDKとClient SDKで構成されています。
PhotonはUDP(またはTCP)にもとづく、低レイテンシーなコミュニケーションレイヤーを提供します。
このレイヤーによって、データの高信頼/低信頼転送を「コマンド」で実施できるようになります。
さらに、オペレーションフレームワークとイベントフレームワークが確立され、ゲーム開発の負担が減少します。
Photon Cloudは、Photonで開発したゲーム用にホスティングされるサービスです。
使用するにはまず、photonengine.com)からサインアップします。その後LoadBalancing APIやデモを使って開発を始められます。
Photon ワークフロー
クライアントでの動作を理解するため、サーバーのLoadBalancing APIロジックを使用して説明します。
このアプリケーションは、ユーザーが参加を試みた場合に作成されるルームを定義します。
ルーム内の各ユーザーは、固有の番号をもつアクターとなります。
クライアントのワークフローを単純化すると、以下のようになります:
LoadBalancingClient
インスタンスを作成- この時点から: イベントとコマンドを取得するため、定期的に
Service
を呼びます (たとえば1秒間に10回) Connect
メソッドの1つを呼び、サーバーに接続します- ライブラリが
OnStatusChanged
を呼ぶまで待ちます - 返されたステータスintは、
StatusCode.Connect
と等しくする必要があります。 - ゲームに参加するため
OpJoinRoom
を呼びます - ライブラリが
OperationCode.Join
でOnOperationResponse
を呼ぶまで待ちます OpRaiseEvent
を呼んで、ゲームにデータを送信しますOnEvent
にイベントを受信します- LoadBalancing APIは、よく発生する状況下で活用できるよう複数のイベントを定義しています: たとえば、プレイヤーの参加や退出などです。
- LoadBalancing APIでは
OpRaiseEvent
を呼んで作成されるイベントは、同じルームにいる他のプレイヤーにこのメソッドで受信されます。 - 完了すると:
LoadBalancingClient.OpLeave
を呼んでゲームを停止するか、ゲームから退出します。 OperationCode.Leave
で、OnOperationResponse
内で「leave」が返されるまで待ってください。Disconnect
で切断します- statusCode:
StatusCode.Disconnect
でOnStatusChanged
に「disconnect」が返されることを確認してください。
この簡潔なワークフローをサーバーのLoadBalancingアプリケーションと組み合わせれば、ルームの使用やゲームイベントの送信が可能になります。
使用されるメソッドは3つのレイヤーに分類できます:
- 低レベル:
Service、Connect、Disconnect
とOnStatusChanged
は、サーバーへの接続を直接意味しています。
このレベルはコマンドを移送するUDP/TCPパケットとともに作動します(次に、あなたのオペレーションを転送します)。
これによって接続が維持され、RPC呼び出しやイベントがパッケージに管理されます。 - ロジックレベル: オペレーションや結果、イベントによってPhotonのロジックレベルが成り立っています。
すべてのオペレーションはサーバー上で定義され(たとえばRPC呼び出しなど)、結果が生じます。
イベントはサーバーから受信され、同じデータでクライアントをアップデートします。 - アプリケーションレベル: 特定のアプリケーションとその機能で成り立っています。
この場合、オペレーションとLoadBalancing APIのロジックが使用されます。
この特殊なケースにはルームやアクターなどが含まれます。
LoadBalancingClientはサーバー側の実装をマッチングし、すべてを包括しています。
多くの場合、低レベルの通信を管理する必要はありません。
ただしクライアントからサーバーへの通信(また、その逆も)は「コマンド」化される点に留意してください。
内部的には、コマンドはクライアントとサーバー間の接続を維持するのにも使用されます(追加データを保持することはありません)。
オペレーションであるメソッド(RPCコール)にはすべて頭に「Op」がつき、ほかのコールから区別されます。
他のサーバー側アプリケーション(MMOやユーザーが独自のアプリケーション)は異なるオペレーションを定義します。
これらは異なるパラメータを保持し、値を返します。
これらのオペレーションはクライアントライブラリの一部ではありませんが、OpCustom
を呼ぶことで実装可能です。
コールバック用にインターフェースIPhotonPeerListenerを実装する必要があります。
以下に例を示します:
OnStatusChanged
はピアのステート変更に使用します(接続、切断、エラー、StatusCode
のリストと比較してください)OnOperationResponse
はオペレーション用のコールバックです(参加、退出など)OnEvent
は受信イベントのコールバックですDebugReturn
はデバッグ出力用のコールバックです (リリースビルドによって使用されますが、使用頻度は低いです)
PhotonPeer内の下記のプロパティは特別な用途があります:TimePingInterval
はpingオペレーションの時間間隔を設定しますRoundTripTime
は、高信頼性オペレーションがサーバーに送信されてから戻るまでのラウンドトリップタイムですRoundTripTimeVariance
は上記のラウンドトリップタイムの変動を示しますServerTimeInMilliSeconds
は予測されるサーバーの継続時間です
オペレーション
オペレーションはPhotonでのリモートプロシージャーコール(RPC)を示す用語です。
これはサーバーサイドに実装されるメソッドで、クライアントに呼び出されます。
他のメソッドと同様に、オペレーションにはパラメータと戻り値があります。
Photon開発フレームワークはクライアントからサーバーへのRPCコールを考慮し、結果を返します。
サーバーサイドでは、オペレーションはPhotonの最上部で実行されるアプリケーションの一部です。
弊社が提供するデフォルトのアプリケーションは、「LoadBalancing API」と呼ばれます。
「LoadBalancingPeer」クラスは、各LoadBalancing APIオペレーション向けのメソッドによってPhotonPeer
を拡張します。
LoadBalancingClient
はLoadBalancingPeer
クラスのラッパーです。
LaodBalancing APIオペレーションの例として「Join」と「RaiseEvent」があります。
クライアント側では、これらのオペレーションはLoadBalancingClient
クラス内にメソッドとして存在しています:OpJoinRoomと
OpRaiseEvent`です。
これらのオペレーションは、PhotonとLoadBalancing APIのデフォルトの実装でただちに使用することが可能です。
カスタムオペレーション
Photonは、それぞれのゲーム固有の機能に合わせて拡張できます。
ワールドステートを保持したり、クライアントからの情報をダブルチェックすることなどが可能です。
Lite、LoadBalancing API、MMOアプリケーションロジックに含まれないオペレーションはすべて、カスタムオペレーションと呼ばれます。
これらのオペレーションの作成はサーバーサイドのタスクですが、クライアントがサーバーの新しい機能やオペレーションを使用しなければならない場合もあります。
つまり、オペレーションはクライアント側から呼び出すことのできるメソッドです。
オペレーションには任意の数のパラメータを設定でき、また任意の名前をつけられます。
トラフィックを保持するため、弊社はすべてのオペレーションとパラメータにバイトコードを割り当てました。
定義はサーバー側で実行されます。
各オペレーションには、オペレーションコード(OperationCode
)とよばれる固有の識別番号があります。
オペレーションクラスは、予測されるパラメータを定義し、それぞれにパラメータコードを割り当てます。
この定義によってクライアント側で必要な処理は、値を設定する点とオペレーションのOperationCode
であるとサーバーに通知する点のみになります。
Photonはオペレーションのリクエスト、レスポンス、イベントのパラメータを集約するため、ディクショナリを使用しています。
パラメータがディクショナリにあって、オペレーションを呼ぶ場合にはOpCustom
を使用してください。
クライアント側では、現在OperationCode
とパラメータコードはバイト型です(オーバーヘッドを最小化するため)。
オペレーションを正常に呼び出すには、サーバー側の定義と合致させる必要があります。
詳細はこちらを参照してください:
イベント
オペレーションとは異なり、イベントは受信側のクライアントがめったにトリガーすることのない「メッセージ」です。
イベントは外部から送信されます:サーバーまたはその他のクライアントです。
イベントはオペレーションから副次的に作成されるか(たとえばルームに参加する場合など)、もしくはオペレーションRaise Event
の主目的として起動されます。
ほとんどのイベントはなんらかの形式のデータを転送しますが、まれにイベントの型自体がメッセージの場合があります。
(繰り返しになりますが)イベントは、任意のコンテンツのディクショナリです。
イベントの「最上位」では、バイトは値のキーとして使用されます。
シリアル化された型ならば、値はどのようなものでも問題ありません。
たとえばLoadBalancing APIは、オペレーションRaiseEvent
内のカスタムイベントコンテンツの Hashtable
を使用します。
詳細はこちらを参照してください:
フラグメンテーションとチャネル
フラグメンテーション
大きなサイズのデータチャンクは、1つのパッケージにはおさまりません。このため、こういったデータチャンクは分割されて自動的に再構成されます。
データサイズに応じて、1つのオペレーションやイベントが複数のパッケージで構成される場合があります。
この処理によって、その他のコマンドが遅延する可能性があります。
Service
またはSendOutgoingCommands
を、必要以上に頻繁に呼び出してください。
PhotonPeer.QueuedOutgoingCommands
がゼロになっている点を定期的に確認し、すべてが確実に出力されるようにする必要があります。
時々発生するデバッグ出力「UDP package is full」を確認することも可能ですが、この現象が常に発生しているのは問題です。
最大転送ユニット
UDPパッケージの最大サイズは、PhotonPeer.MaximumTransferUnit
プロパティで設定できます。
デフォルト値は1,200バイトです。
ルーターによっては、UDPパッケージサイズがこのサイズでも分割をおこないます。
大きなサイズが不要な場合はパッケージを512バイトに設定してください。この場合、コマンドごとのオーバーヘッドは増しますが、安全性は
高まります。
この設定はTCP接続によって無視され、内部的にMTUが調整されます。
シーケンシング
プロトコルをシーケンシングする際には、受信クライアントは送信された順にアクションを送信します。
信頼性の低いデータは交換可能とみなされ、失われる可能性があります。
信頼性の高いイベントとオペレーションは必要に応じて複数回繰り返されますが、これらはすべて順番に間隔なしで送信されます。
信頼性の低いアクションは直近の信頼性の高いアクションに関連づけられ、信頼性の高いデータが送信されるまでは送信されません。
これは互いに関連したイベントの場合に有用です。
例:あなたのFPSが信頼性の低い移動アップデートと、信頼性の高いチャットメッセージを送信したとします。
移動アップデートのパッケージは失われて省略され、次の移動アップデートが受信されます。
受信側では、この処理は小さなジャンプのように見えます。
チャットメッセージをともなうパッケージが失われた場合、この処理は繰り返されます。メッセージ作成後のすべての移動アップデートに対してラグが発生する場合もあります。
この場合にはデータは関連づけられず、異なるチャネルに設定する必要があります。
チャネル
.NETクライアントとサーバーは、現在「チャネル」をサポートしています。
これによって、情報が複数のチャネルに分割され、これらのチャネルは個別にシーケンス化されます。
つまり、別のチャネルのイベントが利用できないという理由でチャネルのイベントが遅延することはありません。
デフォルトではPhotonPeerに2つのチャネルがあり、またチャネル0がオペレーションの送信をおこないます。
参加オペレーションと退出オペレーションは、常にチャネル0で送信されます(簡易化のため)。
メッセージの接続と切断には、内部的に使用される「バックグラウンド」チャネル255があります。
これはチャネルカウントでは無視されます。
チャネルには優先順位があります:まず、もっとも低いチャネル番号がUDPパッケージに入力されます。
UDPパッケージがすでにフルの場合には、より高い番号のチャネル内のデータは後で送信される可能性があります。
例:現状ではチャットメッセージはチャネル1で、移動はチャネル0で送信されるとします。
これらには関連性がなく、チャットメッセージが遅延した場合でも、チャネル0への影響はまったくありません。
また、チャネル0の方が優先順位が高いため、送信される可能性はより高くなります(パッケージがフルになった場合)。
TCPの使用
PhotonPeerは、必要に応じて下位層プロトコルとしてTCPでインスタンス化することができます。
最適な使用法ではありませんが、プラットフォームによってはUDPソケットをサポートしない場合があります。
たとえばSilverlightが常にTCPを使用するのはこのためです。
Photon Client APIは両方のプロトコルにとって同一ですが、内部的には若干の違いがあります。
低信頼と思われるオペレーションであっても、TCPで送信されるものはすべて高信頼です。
TCPクライアントのみを使用している場合には、すべてのオペレーションを低信頼性として送信してください。
これによって、下位層プロトコルでの一部の作業(およびトラフィック)を省略できます。
TCPクライアントとUDPクライアントが混在している場合には、TCPクライアント間で送信されるものは常に高信頼性として送信されます。
ただしUDPを使用するクライアントと通信する場合には、これらのクライアントはイベントを高信頼性または低信頼性として受信します。
例:
Silverlighクライアントが、チャネル1で低信頼性の移動アップデートを送信するとします。
TCP経由で送信されるため、このアップデートは高信頼性になります。
PhotonはUDPクライアントとも接続しています(たとえば、ダウンロード可能な3Dのゲームクライアント)。
この場合、移動アップデートの送信には低信頼性/高信頼性の設定が使用されます。
ネットワークシミュレーション
開発中、テストの多くはローカルネットワーク上で行われます。
リリース後にクライアントはインターネット経由で通信するため、メッセージごとに長い遅延が生じてメッセージが完全に失われる場合もあります。
ゲームを現実的な状況に即したものにするため、Photonクライアントライブラリを使用すればインターネット通信の影響をシミュレーションできます:ラグ、ジッター、パケットロスなどです。
- ラグ / レイテンシー: クライアントとサーバー間のメッセージに生じる、ある程度一定した遅延。
どちらの方向も異なる面で影響を受けますが、これらの値は互いに近いものになります。
ラウンドトリップタイムに影響します。
- ジッター: シミュレーションでのラグをランダム化します。
これは、ラウンドトリップタイムの変動に影響します。
この影響でUDPパッケージに異常が生じる可能性があり、この可能性もシミュレーションされます。
新たなラグはLag + [-JitterValue..+JitterValue]です。
これによって、ラグ平均の設定は保持されます。一部のパッケージは、ラグが示す値よりも速い場合があります。
- パケットロス: UPDパッケージが失われる可能性があります。
Photonプロトコルでは高信頼性フラグの付いたコマンドは繰り返されますが、このようにして他のコマンド(オペレーション)は失われる可能性があります。
ラグシミュレーションは、設定で定義された遅延に対応するため独自のスレッドで実行されます。
ほとんどの場合、このスレッドで遅延に対応できますが、実際の遅延には+/-20ミリ秒の変動があります。
ネットワークシミュレーションの使用
デフォルトでは、ネットワークシミュレーションはオフになっています。
オンにするにはPhotonPeer.IsSimulationEnabled
を設定します。設定はNetworkSimulationSetに集約され、ピアクラスからのアクセスが可能です(たとえば、LoadBalancingClient)。
コードサンプル:
C#
//Activate / Deactivate:
this.peer.IsSimulationEnabled = true;
//Raise Incoming Lag:
this.peer.NetworkSimulationSettings.IncomingLag = 300; //default is 100ms
//add 10% of outgoing loss:
this.peer.NetworkSimulationSettings.OutgoingLossPercentage = 10; //default is 1
//this property counts the actual simulated loss:
this.peer.NetworkSimulationSettings.LostPackagesOut;
Photon Server
Photon Serverは、すべてのクライアントが通信に利用する中心ハブです。
Photon ServerはすべてのWindowsマシンで実行可能です。クライアントのUDPおよびTCP接続を処理し、ユーザー独自のビジネスロジック、すなわちアプリケーションとともに.NETランタイムレイヤーをホスティングします。
Photon Server SDKには、複数のアプリケーションがソースや事前に構築された状態で含まれています。
これらのアプリケーションは購入後すぐに実行したり、独自のサーバーロジックの開発に利用できます。
Photon Server SDKはこちらから取得してください。
LoadBalancing API
LoadBalancing APIは、Photonでルームベースのゲームを開発するためのサンプルアプリケーションです。また、独自のゲームを開発するうえで柔軟性の高い基盤となります。
LoadBalancing APIはルーム、ルームへの参加と退出、ルーム内の他のプレイヤーへのイベントの送信、プロパティの処理などを実現します。LoadBalancing APIはクライアントライブラリと緊密に連携しており、ほとんどのPhotonドキュメントでサンプルとして使用されます。
Photonでのプロパティ
LoadBalancing APIは汎用メカニズムを実装し、サーバー側(メモリ内)でキー/値のセットの設定やフェッチをおこないます。
これらのキー/値のセットはルームやゲーム、またはルーム内のプレイヤーに関連づけられ、ゲーム内に存在するプレイヤーは全員フェッチやアップデートが可能です。
プロパティHashtableのエントリーは個々のプロパティと認識されるため、個別に上書きできます。
プロパティの値には、すべてのシリアライズ可能なデータ型を設定できます。
キーは文字列型またはバイト型のいずれかに設定する必要があります。
より好ましいのは、オーバーヘッドが少ないバイト型です。
混乱を避けるため、キーの型に文字列とバイトを混在させないでください。
キーの型を混在させるとフェッチする際に個別のリクエストが必要になります。
プロパティのブロードキャストとイベント: ゲーム内のプロパティの変更を「ブロードキャスト」することができ、ブロードキャストは他のプレイヤーがそれらのプロパティをアップデートするイベントのトリガーとなります。
プロパティを変更したプレイヤーは、同じアップデートを取得しません。
ブロードキャストオプションを使用する変更はすべて、プロパティアップデートイベントをトリガーします。
このイベントは変更されたプロパティのみを転送し、プロパティの変更元と、プロパティの所属が示されます。
クライアントは変更を「マージ」する必要があります(プロパティがキャッシュされた場合)。
プロパティは以下のメソッドで設定できます:
LoadBalancingClient.OpSetPropertiesOfActor
はアクターのプロパティを設定します。LoadBalancingClient.OpSetPropertiesOfRoom
はルームのプロパティを設定します。LoadBalancingClient.OpJoinOrCreateRoom
はルームが既存でない場合にルームの初期プロパティを設定し、参加アクターのプロパティを設定します。LoadBalancingClient.OpCreateRoom
はルームの初期プロパティや、参加アクターのプロパティを設定します。LoadBalancingClient.OpJoinRoom
は参加アクターのプロパティを設定します。
ブロードキャストオプションを使用する変更はすべて、プロパティアップデートイベントEventCode.PropertiesChanged
をトリガーします。
このイベントは、キーParameterCode.Properties
の値としてプロパティを転送します。
また、誰がプロパティを変更したかについての情報は、キーParameterCode.ActorNr
に保存されています。
キーParameterCode.TargetActorNr
は、プロパティセットが特定のプレイヤーに属する場合のみ利用可能です。
このキーが表示されない場合、プロパティはルームプロパティです。