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。
最近仕事でドキュメントとか一切作ってなかったので、説明を書くのが一番疲れました。
おしまい。