LoginSignup
10
5

More than 5 years have passed since last update.

PUN2のコールバックをUniRxで扱うOSS「PUN2Rx」

Posted at

PUN2Rx

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

dotnet-callbacks

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

おしまい。


  1. 誰も使ってないから誰も気づいてないのでは……? ownership周りの使い所がわからん。 

  2. 結局みんな使い方がよくわからないらしいので意地になっている。 

10
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
5