PUN2Rx
PUN2のコールバックをUniRXのOperatorに変換します。
MITです。
概要
PUN2のイベントはコールバックとして伝えられます。それぞれのイベントは独立ではないので、順序立ててハンドリングする必要があります。UniRxのオペレーターとして扱うことでイベントのハンドリングが簡単になります。
また、PUN2のイベントコールバックを受け取るにはMonoBehaviourPunCallbacksを継承するか、各interfaceを継承する必要があります。PUN2Rxを使うことで基底クラスを自由に変更できます。
最も重要な点として、通常イベントのオペレータはOnNext、エラーのオペレータはOnErrorのみを通知します。これによって、ひとつのSubscribeで正常系とエラーのハンドリングが可能です。
例
成功と失敗を一度にSubscribe
var successStream = this.OnCreateRoomAsObservable();
var failureStream = this.OnCreateRoomFailedAsObservable();
successStream.Merge(failureStream)
.Subscribe(
unit => { Debug.Log("success!"); },
exception => { Debug.Log("failed..."); }
);
特定のルームに接続する。途中のエラーコールバックをハンドリング
// room name you want to join
var roomName = "roomName";
// OnNext --- (ConnectedToMaster => OnJoinedRoom)
var successStream =
this.OnConnectedToMasterAsObservable().Take(1).IgnoreElements()
.DoOnCompleted(() =>
{
Debug.Log("connect finish!");
Debug.Log("join room!");
var roomOptions = new RoomOptions();
PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
}
).Concat(this.OnJoinedRoomAsObservable());
// OnError --- (OnDisconnected or OnJoinRoomFailed)
var failureStream = this.OnDisconnectedAsObservable()
.Where(cause => cause != DisconnectCause.None && cause != DisconnectCause.DisconnectByClientLogic)
.Select(cause =>
{
throw PUN2Exception.Create((short) cause, cause.ToString());
return Unit.Default;
}).Merge(this.OnCreateRoomFailedAsObservable(), this.OnJoinRoomFailedAsObservable());
Observable.Amb(successStream, failureStream)
.Subscribe(
unit => { Debug.Log("join room finish!"); },
exception => { Debug.Log(exception); })
.AddTo(this);
Debug.Log("connect!");
PhotonNetwork.ConnectUsingSettings();
Operators
PUN2のコールバックのうち、PUN2Rxが対応しているコールバックは以下の通りです。
OnNextのみを通知するのかOnErrorのみを通知するのか。
OnNextで何が流れてくるのか、も記載されています。
| Operator | Call | Type |
|---|---|---|
Photon.Realtime.IConnectionCallbacks |
- | - |
| OnConnectedAsObservable | OnNext | Unit |
| OnConnectedToMasterAsObservable | OnNext | Unit |
| OnDisconnectedAsObservable | OnNext | DisconnectCause |
| OnRegionListReceivedAsObservable | OnNext | RegionHandler |
| OnCustomAuthenticationResponseAsObservable | OnNext | Tuple<string, object> |
| OnCustomAuthenticationFailedAsObservable | OnError | Unit |
Photon.Realtime.IInRoomCallbacks |
- | - |
| OnPlayerEnteredRoomAsObservable | OnNext | Player |
| OnPlayerLeftRoomAsObservable | OnNext | Player |
| OnRoomPropertiesUpdateAsObservable | OnNext | HashTable |
| OnPlayerPropertiesUpdateAsObservable | OnNext | Tuple<PLayer, Hashtable> |
| OnMasterClientSwitchedAsObservable | OnNext | Player |
Photon.Realtime.ILobbyCallbacks |
||
| OnJoinedLobbyAsObservable | OnNext | Unit |
| OnLeftLobbyAsObservable | OnNext | Unit |
| OnRoomListUpdateAsObservable | OnNext | List<RoomInfo> |
| OnLobbyStatisticsUpdateAsObservable | OnNext | List<TypedLobbyInfo> |
Photon.Realtime.IMatchmakingCallbacks |
||
| OnFriendListUpdateAsObservable | OnNext | List<FriendInfo> |
| OnCreateRoomAsObservable | OnNext | Unit |
| OnCreateRoomFailedAsObservable | OnError | Unit |
| OnJoinedRoomAsObservable | OnNext | Unit |
| OnJoinRoomFailedAsObservable | OnError | Unit |
| OnJoinRandomFailedAsObservable | OnError | Unit |
| OnLeftRoomAsObservable | OnNext | Unit |
Photon.Pun.IPunOwnershipCallbacks |
||
| OnOwnershipRequestAsObservable | OnNext | Tuple<PhotonView, Player> |
| OnOwnershipTransferredAsObservable | OnNext | Tuple<PhotonView, Player> |
注意
typo
IPunOwnershipCallbacks.OnOwnershipTransfered
PUN1からですが1、これ多分Typoです。
「Transfer r ed」
PUN2をバージョンアップした際にエラーが出たら適宜修正してください。
DisconnectCause
IConnectionCallbacks.OnDisconnectedはこれだけなぜか正常イベントとエラーイベントをひとつのコールバックで返してきやがるので、エラーオペレータとして扱いたい場合は例のようにSelectで変換して使ってください。むちゃくちゃしてますが他の手段が思いつかない。
.Select(cause =>
{
throw PUN2Exception.Create((short) cause, cause.ToString());
return Unit.Default;
}).Merge(this.OnCreateRoomFailedAsObservable(), this.OnJoinRoomFailedAsObservable());
まとめ
試作したあとも探してたんですが、なかったので結局自分で作りました。UniRxとPUN2を併用してるプロジェクトなんていくらでもありそうですが……謎。とりあえず自分が欲しい分は作ったので、自分は満足しております。
Taskには対応してません。いまいちいい実装が思いつかないのと、あんまり自分が必要としてないので。
nullチェックのあたりをif文に書き換えれば.NET 4.6は必須じゃなくなるんですが、「PUN2とUniRX導入しといて4.6にしてない奴はおらんやろ……」という独断と偏見によってそのままにしてます。書き直すのめんどくさい。あと#ifdefはよくわからないなので定義してないです。
README.mdは最初あたりGoogle翻訳でがんばってたんですが、めんどくさかったのでもうフィーリングで書いてます。まあプログラマなら英語読まなくてもコード読めばわかるでしょう。
RaiseEventに関してはRER/RESを使ってください2。
最近仕事でドキュメントとか一切作ってなかったので、説明を書くのが一番疲れました。
おしまい。