Async Extensions
Realtime APIのAsynch Extension(非同期拡張)は、よく知られたコールバックアプローチに加えてオプションモデルとして構築されたものです。.Net Realtime SDKs v5以降で搭載されています。
これらの非同期メソッドは、C# async/awaiとTasks (TAP)に基づくもので、しばらくの間Unityでサポートされています(詳細については、Microsoft社のTAPドキュメントをご参照ください。)
これらの非同期APIは、性能よりも使いやすさを優先しています。ゲームプレイループ(例:Quantumシミュレーションなど)には関わってこないものなので、問題はありません。
接続を成立させてオペレーションを送信すること自体は非同期プロセスであり、Taskベースの非同期パターンであればより多くの読み鷺池叶で維持可能なコードを生成します。
C#
var appSettings = new new AppSettings();
var client = new RealtimeClient();
await client.ConnectUsingSettingsAsync(appSettings);
var joinRandomRoomParams = new JoinRandomRoomArgs();
var enterRoomArgs = new EnterRoomArgs();
var result = await client.JoinRandomOrCreateRoomAsync(joinRandomRoomParams, enterRoomArgs);
ほとんどのRealtime APIのAsyncバージョンはすでに実装されています。何か足りない場合は、ローカルで簡単に追加できますし、Photonの担当者にお問い合わせいただくこともできます。コードはAsyncExtensions.csファイルにあります。
いずれの非同期メソッドも、awaitされるまでは処理や送信を開始しません。
非同期オペレーションメソッドの完了を待っている間、 RealtimeClientはアップデート (RealtimeClient.Service())の必要はありません。
エラー対処
すべての Asyncメソッドは、エラーに遭遇した場合に例外を出します。エラー対処のため、さまざまな種類の例外があります(メソッドに関するまとめをご参照ください)。
try/catchブロックでコードに手を加えるのは望ましいことではありませんが、APIがよりシンプルになります。
C#
try {
  await client.ConnectUsingSettingsAsync(appSettings);
} catch (Exception e) {
  Debug.LogException(e);
}
C#
try {
  // Disconnecting can also fail
  await client.DisconnectAsync();
} catch (Exception e) {
  Debug.LogException(e);
}
Unity と Async
Unityでasync/awaitを使用する場合、特別考慮しておくべきことがあります。
.Netとは異なり、Unityスレッドからawaitを使用するとUnityスレッド上での実行が再開されます。
- これによりUnityでのawaitの使用が無害になります。ですが、Unity外で使用する場合は、マルチスレッディングの問題を引き起こします。
新しいTasksが、Unity SynchronizationContextに応じたカスタムTaskFactoryで作成されなかった場合、スレッドプールで(Unityの多くのケースでは望ましくありません)実行されます。
- グローバルデフォルトである AsyncConfigは、タスクを作成し継続させるために内部的に使用されるTaskFactoryを作成します。
- AsyncConfig.InitForUnity()の流れを辿ってください。
C#
var taskFactory = new TaskFactory(
  CancellationToken.None,
  TaskCreationOptions.DenyChildAttach,
  TaskContinuationOptions.DenyChildAttach | TaskContinuationOptions.ExecuteSynchronously,
  TaskScheduler.FromCurrentSynchronizationContext());
プレイモードの切り替え時、UnityはTasksの実行をやめません。
- これは問題点です。AsyncSetupクラス内のグローバルなCancellationTokenSourceを使用して、プレイモード変更コールバックに反応して起動させ、これを解消します(AsyncSetup.Startup()を参照してください。)
- 全てのタスクと内部で作成された処理継続は、引数として明示的に受け渡されたAsyncConfigまたはAsyncConfig.Globalを使用します。
Tasksでの例外は、状況に応じてUnityによって抑制されることがあります。
- 簡潔に言うと、以下のパターンを使用してください。
public async void Update() {}
C#
// Does NOT log exception.
// Why? Because Unity does not handle exception inside tasks by design.
public Task Update1() {
  return Task.Run(() => throw new Exception("peng"));
}
// Does NOT log exception.
// Why? Because we return at await and continue as a task object and Unity swallows the exception.
public async Task Update3() {
  await Task.Delay(100);
  throw new Exception("peng");
}
// Logs exception.
// Why? because we unwrap the task and run it synchronously with .Wait().
public void Update2() {
  Task.Run(() => throw new Exception("peng")).Wait();
}
// Logs exception.
// Why? Because we resume the execution in this method and not return a task.
public async void Update4() {
  await Task.Delay(100);
  throw new Exception("peng");
}
// Logs exception.
// Why? We add a continuation task that logs (in any thread) when the task faulted.
public Task Update5() {
  var task = Task.Run(() => throw new Exception("peng")).ContinueWith(t => {
    if (t.IsFaulted) {
      Debug.LogException(t.Exception.Flatten().InnerException);
    };
  });
  return task;
}
WebGL要件
Realtime Async拡張はWebGLに対応しています。ブラウザでのスレッディング制限により、Task.Delay()などのマルチスレッディングコードは使用できません。
Matchmaking Async(マッチメイキング非同期)拡張
Realtime Matchmaking拡張はもっとも一般的な接続と再接続ロジックを組み合わせ、RealtimeClientクラスの2つの使いやすい拡張メソッドにしています。
ConnectToRoomAsync
C#
public Task<RealtimeClient> ConnectToRoomAsync(MatchmakingArguments arguments)
ConnectToRoomAsyncは以下を実行します。
- 提供されたPhotonSettingsおよびAuthValuesを使用したPhoton Cloudへの接続
- 設定に応じて簡単なマッチメイキングを実行
- ランダムマッチメイキング:RoomName:null,CanOnlyJoin:false
- 既存のルームに参加: RoomName:"room-name",CanOnlyJoin:false
- ルームへの参加または作成:RoomName:"room-name",CanOnlyJoin:true
- 入力したロビーの使用:Lobby:MyLobby
- ロビープロパティの使用:CustomLobbyProperties:MyLobbyProperties
 
- ランダムマッチメイキング:
これらの値は次のいずれかに設定すること:PhotonSettings, MaxPlayer, PluginName, AuthValues / UserId
MatchmakingArguments
| Property | Type | Description | 
|---|---|---|
| PhotonSettings | AppSettings | The Photon AppSetting class containing information about the AppId and Photon server addresses. | 
| PlayerTtlInSeconds | int | Player TTL, in seconds. | 
| EmptyRoomTtlInSeconds | int | Empty room TTL, in seconds. | 
| RoomName | string | Set a desired room name to create or join. If the RoomName is null, random matchmaking is used instead. | 
| MaxPlayers | int | Max clients for the Photon room. 0 = unlimited. | 
| CanOnlyJoin | bool | Configure if the connect request can also create rooms or if it only tries to join. | 
| CustomProperties | Hashtable | Custom room properties that are configured as EnterRoomArgs.RoomOptions.CustomRoomProperties. | 
| CustomLobbyProperties | string[] | List of room properties that are used for lobby matchmaking. Will be configured as EnterRoomArgs.RoomOptions.CustomRoomPropertiesForLobby. | 
| AsyncConfig | AsyncConfig | Async configuration that include TaskFactory and global cancellation support. If null, then AsyncConfig.Globalis used. | 
| NetworkClient | RealtimeClient | Optionally provide a client object. If null, a new client object is created during the matchmaking process. | 
| AuthValues | AuthenticationValues | Provide authentication values for the Photon server connection. Use this in conjunction with custom authentication. This field is created when UserIdis set. | 
| PluginName | string | Photon server plugin to connect to. | 
| ReconnectInformation | MatchmakingReconnectInformation | Optional object to save and load reconnect information. | 
| Lobby | TypedLobby | Optional Realtime lobby to use for matchmaking. | 
ReconnectToRoomAsync
C#
public Task<RealtimeClient> ReconnectToRoomAsync(MatchmakingArguments arguments)
ReconnectToRoomAsyncは、前のルームへ戻るよう試行します。
クライアントオブジェクトが再利用可能な状態(例: タイムアウト後)である場合に、ルームへの高速再接続(マスターサーバーのスキップ)を試行します。これをしないと、完全な接続シーケンスが走ってしまい、ルームへの再参加が試行されることになります。
ユーザーの前回の接続が、まだサーバーによって破棄されていない場合(例:10秒タイムアウトの間)、再参加は失敗となります。 ReconnectToRoomAsyncが自動的にこのケースをカバーし、完全に失敗するまでルームへの再参加を複数回試行します。
ReconnectToRoomAsyncは、アプリケーションの再開または新しいクライアントオブジェクトにも使用できます。これらの場合には、 MatchmakingReconnectInformationタイプのarguments.ReconnectInformationがルームへの再参加の情報を提供するような設定になっている必要があります。
Quantumでは、QuantumReconnectInformation が使用でき、これにより自動でPlayerPrefsに再参加情が保存されます。
重要: Saving the UserId to PlayerPrefsにUserIdを保存することは、セキュリティリスクとなるため、アプリを再開した後、再接続ロジックとなる前にかならずCustom Authenticationに置き換えてください。
Quantumデモメニューでは、保存したQuantumReconnectInformationを確認する設定にできます。
QuantumMenuUIMain.IsReconnectionCheckEnabledを使用してこれを有効にしてください。
Any MatchmakingReconnectInformationインスタンスには寿命があり、これによってもう存在しないセッションへの再参加試行が防がれています。オンラインゲームがこのタイムアウトを更新する間、Set(client)を繰り返し呼び出してください。接続または再接続が成功した後、マッチメイキング拡張メソッドから自動で呼び出されます。
仮想メソッドのMatchmakingReconnectInformation.Set(client)は、必要に応じて上書きできます。
C#
virtual void Set(RealtimeClient client)
MatchmakingReconnectInformation
| Property | Type | 説明 | 
|---|---|---|
| Room | string | クライアントの接続先のルーム名 | 
| Region | string | クライアントの接続先のリージョン名。 | 
| AppVersion | string | 前回の接続で使用されたアプリバージョン。 | 
| UserId | string | サーバーへの接続にクライアントだ使用したユーザーID。 | 
| TimeoutInTicks | long | この情報が使用できないものだと判断された後のタイムアウト。 Timeoutプロパティを使用してこの値を取得してください。 |