ここでは、Roomオブジェクトの使い方を説明します。
プレイヤーまたは観戦者がWSNet2の部屋へ入室したとき、onSuccessコールバックでRoomオブジェクトが渡されます。
WSNet2での通信を受け取るには、このRoomにイベントレシーバやRPCを登録します。
イベントの処理はonSuccessが完了してからはじまります。
イベントの取りこぼしを防ぐためには、この中でイベントレシーバとRPCの登録を済ませるか、
onSuccessの中でroom.Pause()を呼んでイベント処理を一時停止しておき、
登録が済んでからroom.Restart()を呼ぶようにしてください。
どちらも部屋を特定するための情報です。
RoomのIdは全ての部屋に割り当てられる、ある程度長い一意な文字列です。
一方Number(部屋番号)は6桁程度の数値で、部屋の作成時にRoomOption.WithNumber(true)にすると割り当てられます。
この番号は同時に存在する部屋と重複することはありません。
桁数はGameサーバの設定ファイルで指定できます。
グループ検索可能フラグ。
falseの部屋はグループ検索結果に含まれず、ランダム入室の対象にはなりません。
IdやNumberによる検索や入室には影響しません。
プレイヤーとしての入室可能フラグ。
falseの部屋には入室(Join, RandomJoin)できません。
一方trueであれば、Visibleの値に関わらずIdまたはNumberで部屋を特定して入室(Join)することができます。
観戦可能フラグ。
falseの部屋は観戦(Watch)できません。
検索グループ。 サーバ側負荷軽減のため、部屋の検索(ランダム入室のための検索も含む)は検索グループ単位で行います。 検索グループの割り当てルールはプロジェクト側で設計する必要があります。 検索するときに同時に存在する同じグループの部屋数が1000件以下になるようにしてください。
PublicPropsとPrivatePropsはどちらも辞書(Dictionary<string, object>)型で、
キーは任意のUTF-8文字列、値はシリアライズ可能な型です。
どちらも部屋にいる全てのクライアント(プレイヤーと観戦者)に共有されます。
加えて、PublicPropsは部屋の検索結果にも含まれるので入室していないクライアントからも参照できるほか、
Queryによるフィルタリングにも使われます。
自分自身を表すPlayerです。
観戦者ではnullです。
現在のマスタープレイヤーです。
部屋にいる全プレイヤーです。
観戦人数です。 同期にはタイムラグがあります。
最後のメッセージからこの時間経過しても次のメッセージがサーバに届かなかった場合、 クライアントは切断しているとサーバ側で判断し、退室させます。
WSNet2のC#実装側で自動的にこの値未満の間隔でPingメッセージを送信しています。
直前のPing-Pong応答にかかった時間(ミリ秒)です。 自分自身の回線状況の参考にしてください。
サーバが各プレイヤーから受取った最後のメッセージの受信時刻です。
他のプレイヤーの接続状況の参考にできますが、 自分自身の接続状況が悪いとそもそも更新されない点には注意してください。
Roomには次のイベントレシーバのデリゲートが用意されています。
このうちOnClosedとOnErrorClosedは、部屋から退室して接続が終了したという通知になります。
もう一度同じ部屋に入りたい場合は、新しいクライアントとして、JoinまたはWatchから始める必要があります。
void OnJoined(Player me);自分自身の入室イベントです。入室して最初に届きます。
引数は自分自身を表すPlayerオブジェクトです。
これはroom.Meとしてもアクセスできます。
void OnClosed(string message);自分自身の退室によって部屋から完全に切断したときに呼ばれます。
マスターにKickされたときも、OnClosedが呼ばれます。
void OnOtherPlayerJoined(Player player);
void OnOtherPlayerLeft(Player player);他のプレイヤーの入室と退室のイベントです。観戦者では呼ばれません。
引数は入退室したプレイヤーのPlayerオブジェクトで、
退室するまではroom.Players[player.Id]でもアクセスできます。
void OnMasterPlayerSwitched(Player previousMaster, Player newMaster);マスタープレイヤーが変更されたイベントです。
これが呼ばれた時点ですでにroom.Masterは新マスターになっています。
マスタープレイヤーが退室するときには、サーバ側で新しいマスターを選出して退室と合わせて通知します。
OnOtherPlayerLeftの呼び出しより前に新マスターが設定されるので、マスターが不在になることはありません。
void OnRoomPropertyChanged(
bool? visible, bool? joinable, bool? watchable,
uint? searchGroup, uint? maxPlayers, uint? clientDeadline,
Dictionary<string, object> publicProps, Dictionary<string, object> privateProps);部屋のプロパティが変更されたイベントです。
変更された引数のみ値が入り、変更されなかったものはnullになっています。
roomオブジェクトのプロパティは既に変更されています。
変更前の値が必要な場合は、実装者側で事前に保存しておく必要があります。
void OnPlayerPropertyChanged(Player player, Dictionary<string, object> props);プレイヤーのプロパティが変更されたイベントです。
引数propsには、変更されたキーのみ含まれます。
void OnPongReceived(ulong rttMillisec, ulong watcherCount, IReadOnlyDictionary<string, ulong> lastMsgTimestamps);Pongを受信したイベントです。
room.RttMillsec, room.WatcherCount, room.LastMsgTimestamps はこのタイミングで更新されます。
これらの値は引数としても渡されます。
void OnConnectionStateChanged(bool connected);自身の接続状態が変化したイベントです(入室状態ではありません)。
引数connected:
- true: 接続した
- false: 切断した
void OnError(Exception exception);
void OnErrorClosed(Exception exception);エラーを通知するイベントです。
OnErrorは呼ばれても接続している状態を維持しています。
一方OnErrorClosedが呼ばれたときにはもう退室しています。
引数はWSNet2内部で発生した例外です。 メインスレッド以外で発生することもあるので、そのままスローせずに保持し、引数として渡しています。
WSNet2でのメッセージの送受信は基本的にはRPC(Remote Procedure Call)を利用します。
RPCを呼び出すには、最初に対象となるメソッドをRegisterRPC()でRoomに登録します。
これは全てのクライアント(プレイヤーと観戦者)で同じ順序で登録されている必要があります。
void TargetMethod(string senderId);
void TargetMethod(string senderId, T param);RPC対象メソッドの第一引数は呼び出したプレイヤーのIDです。
さらに第二引数をとることもでき、RPC呼び出し時にパラメータを渡すことができます。
第二引数の型Tはシリアライズ可能な型でなければなりません。
int RegisterRPC(Action<string> rpc);
int RegisterRPC(Action<string, T> rpc);
int RegisterRPC(Action<string, T> rpc, T cacheObject = null);RPC対象メソッドをRegisterRPC()で登録することで、呼び出し可能になります。
RPCの第二引数がプリミティブ型(真偽値、数値、文字列)以外のときはcacheObjectを割り当てることができ、
実行時の引数となるオブジェクトを使い回してメモリアロケーションを抑制できます。
RPCは登録順にIDが割り当てられ、そのIDによって対象メソッドを識別します。 このため、クライアント間で登録順が異なってしまうと正しくRPCを呼び出せなくなります。
C#のオーバーロード解決が一部不完全なため、明示的な型変換や型引数の指定が必要な場合があります。
int RPC(Action<string> rpc, params string[] targets);
int RPC(Action<string, T> rpc, T param, params string[] targets);第一引数rpcには、登録したメソッドを渡します。
対象メソッドに第二引数がある場合は、引数paramを渡し、これがそのまま登録したメソッドの第二引数になります。
引数targetsには、RPCを実行するプレイヤーを列挙します。
なにも指定しない場合は、観戦者を含む全クライアントで登録したメソッドが実行されます。
また、Room.RPCToMasterを指定することで、その時点のマスターで実行されます。
RPCの呼び出しは全てのクライアント(プレイヤーと観戦者)でできます。
void Pause();
void Restart();Pause()を呼び出すことで、受信イベントの処理を一時停止することができます。
処理を再開するにはRestart()を呼び出します。
その間に受信したイベントはバッファに蓄積され、再開後順次処理されます。
一時停止している間もPingの送信は止めないので、ClientDeadline経過による切断の心配はありません。
Unityでのシーン遷移中など、イベントを処理できない間に停止しておくことを想定しています。
他にも、CreateやJoinで入室した時のonSuccessコールバックで一時停止しておき、
イベントレシーバやRPCの登録が済んだタイミングで再開するという使い方もできます。
int ChangeMyProperty(IDictionary<string, object> props, Action<EvType, IDictionary<string, object>> onErrorResponse = null);ChangeMyProperty()で自分自身のプロパティを変更できます。
他人のプロパティは変更できません。
また、観戦者はプロパティを持たないのでこの操作はできません。
実際の変更はOnPlayerPropertyChangedが呼ばれるタイミングで適用されます。
引数の辞書には、追加、変更するキーのみ含めます。
含まれなかったキーの値はそのまま保持されます。
このためキーの削除はできないので、値をnullにするなどで対処してください。
onErrorResponseを指定しておくと、サーバ側でのエラーの通知を受け取れます。
成功したことはOnPlayerPropertyChangedで確認してください。
public int ChangeRoomProperty(
bool? visible = null,
bool? joinable = null,
bool? watchable = null,
uint? searchGroup = null,
uint? maxPlayers = null,
uint? clientDeadline = null,
IDictionary<string, object> publicProps = null,
IDictionary<string, object> privateProps = null,
Action<EvType,bool?,bool?,bool?,uint?,uint?,uint?,IDictionary<string,object>,IDictionary<string,object>> onErrorResponse = null);部屋のマスターはChangeRoomProperty()で部屋のフラグや各種プロパティを変更できます。
実際の変更はOnRoomPropertyChangedが呼ばれるタイミングで適用されます。
変更しない項目の引数はnullにします。
また、publicPropsとprivateProps引数の辞書には、追加、変更するキーのみ含めます。
含まれなかったキーの値はそのまま保持されます。
このため辞書のキーの削除はできないので、値をnullにするなどで対処してください。
onErrorResponseを指定しておくと、サーバ側でのエラーの通知を受け取れます。
成功したことはOnRoomPropertyChangedで確認してください。
int SwitchMaster(Player newMaster, Action<EvType, string> onErrorResponse = null);マスタープレイヤーは、他のプレイヤーにマスターを移譲できます。
実際の交代はOnMasterPlayerSwitchedが呼ばれるタイミングで適用されます。
onErrorResponseを指定しておくと、サーバ側でのエラーの通知を受け取れます。
成功したことはOnMasterPlayerSwitchedで確認してください。
int Leave(string message = "");部屋から退室します。
呼び出しただけではまだ退室しておらず、OnClosedが呼ばれるタイミングで退室が完了します。
それまでのイベントは届き続けます。
引数のmessageはOnClosed、OnOtherPlayerLeftの引数になります。
省略(空文字列)時はデフォルトのメッセージが生成されます。
int Kick(Player target, Action<EvType, string> onErrorResponse = null);
int Kick(Player target, string message, Action<EvType, string> onErrorResponse = null);マスタープレイヤーは、他のプレイヤーを強制退室させることができます。
引数のmessageはOnClosed、OnOtherPlayerLeftの引数になります。
省略または空文字列のときはデフォルトのメッセージが生成されます。
onErrorResponseを指定しておくと、サーバ側でのエラーの通知を受け取れます。
成功したことはOnOtherPlayerLeftで確認してください。