StateMachine の投機的実行 Session API(Unity)
この Session は、GS2-StateMachine の投機的実行を Unity から使うためのクラスです。 ユーザーの進行状態をクライアントで実行し、操作履歴を StateMachine の Report API へ送って検証します。ゲームの画面は Session のメソッドで操作し、View からそのローカル実行結果を読みます。
Realtime のルーム接続や他プレイヤーとの同期には使用しません。共有オブジェクトを Unity に反映する仕組みは Unity のオブジェクト同期を参照してください。
このページは呼び出し側の API を説明します。ゲームルールの書式は C# 定義リファレンス、生成する手順はチュートリアルを参照してください。Session は、生成設定の hostProfile が LocalReplayV1(既定値)のときに生成されます。
ルールクラス Counter からは CounterSession を生成します。以下では、そのインスタンスを game と表記します。状態・結果・入力の型は、生成設定の namespace に生成します。
| 目的 | API |
|---|---|
| ゲームを操作する | 定義の操作と同名のメソッド |
| 現在の状態を表示する | View / ViewChanged |
| サーバーで開始済みのゲームを開く | OpenAsync / OpenFuture |
| プレビューなどの実行環境に接続する | FromExecutor |
| 操作履歴をサーバーで検証する | ConfirmAsync / ConfirmFuture |
操作メソッド
定義にある public な操作と同名のメソッドを生成します。状態・乱数・報酬の引数は実行環境が渡すため、Session 側の引数には含めません。
// 定義側: public static Step Add(CounterState state, int amount)
var outcome = game.Add(3);戻り値は InputResult<TCode> です。TCode は定義で指定した Ignore 理由の enum です。
| プロパティ | 型 | 内容 |
|---|---|---|
Accepted | bool | ローカル実行で入力を採用したか |
Ignored | bool | Ignore により入力を取り消したか |
Code | TCode? | Ignore の理由。理由がない場合や未知のコードは null |
RawCode | int? | Ignore 理由の元の数値。理由がない場合は null |
Accepted はサーバー検証済みという意味ではありません。Confirm で別途検証を受けます。
var outcome = game.Add(0);
if (outcome.Ignored)
Debug.Log("入力を受け付けませんでした: " + outcome.Code);現在受け付けていない操作を呼ぶと例外になります。ゼロ除算などの実行エラーも Ignore とは異なり、正常な操作結果として返りません。
View / ViewChanged
game.View は現在の状態のスナップショットです。生成する状態・結果クラスのプロパティは読み取り専用です。状態を変更するときは操作メソッドを呼びます。
var count = game.View.State.Count;
var canAdd = game.View.Actions.Add;| メンバー | 内容 |
|---|---|
View.State | 現在の状態。型は定義の TState に対応する生成クラス |
View.Result | 終了結果。型は定義の TResult に対応する生成クラス。結果がない間は null |
View.Actions.操作名 | 現在の待機場所で、その操作を受け付けるかを表す bool |
View.Revision | 操作履歴のリビジョン |
View.Status | 実行状態 ActiveStateMachineStatus |
ViewChanged | View 更新時の Action<SessionView> 通知 |
View.Actions は「その操作を受け付ける場所にいるか」を示します。素材不足など、操作内で検査するゲーム固有の条件までは判定しません。
Session を作成した後、次のように更新通知を購読できます。Ignore では ViewChanged は発火しません。
game.ViewChanged += view => Debug.Log("Count: " + view.State.Count);View.Status の値
| 値 | 意味 |
|---|---|
Initialized | 実行開始前 |
Running | 処理を実行中 |
Wait | 次の操作を待っている |
Pass | 正常終了。定義の End に到達した状態 |
Error | 実行エラーで停止した状態 |
ゲームの正常終了は View.Status == ActiveStateMachineStatus.Pass で判定できます。これはローカルの実行状態であり、サーバー検証の完了を表しません。
OpenAsync / OpenFuture
サーバーで開始済みのステータスを開き、Session を作成します。先に StateMachine の開始 APIなどで対象ユーザーのステートマシンを開始しておく必要があります。
var game = await CounterSession.OpenAsync(
gs2, gameSession, namespaceName, statusName);| 引数 | 内容 |
|---|---|
gs2 | SDK の接続窓口 Gs2Domain |
gameSession | ログイン済みユーザーの情報 IGameSession |
namespaceName | GS2-StateMachine のネームスペース名 |
statusName | 開始済みステータスの名前 |
Async 形式は UniTask<CounterSession> を返し、GS2_ENABLE_UNITASK が必要です。UniTask を使わない場合は、同じ引数の OpenFuture を使います。戻り値は Gs2Future<CounterSession> です。
接続時には GSL のハッシュを照合します。Session と登録済みの定義が一致しなければエラーです。定義を更新した場合は Session も再生成し、旧定義で進行中のゲームには旧定義に対応した Session を使用します。
FromExecutor
作成済みの Executor に Session を接続します。Executor は、GSL の実行と操作履歴を扱う LocalStateMachineKit の実行クラスです。
var game = CounterSession.FromExecutor(executor);引数は LocalStateMachineExecutor、戻り値は CounterSession です。この API でも定義のハッシュを照合します。
たとえば LocalStateMachineExecutor.CreatePreview(gsl, "Counter") で作成した Executor を渡すと、ログインなしのプレビューに接続できます。具体的な作成例はチュートリアルを参照してください。プレビューにはサーバー送信用の履歴がなく、途中から実サービスへ引き継ぐことはできません。
ConfirmAsync / ConfirmFuture
それまでの操作履歴をサーバーへ送り、検証結果を待ちます。ゲーム途中でも終了後でも呼べます。
await game.ConfirmAsync(gs2, gameSession);引数は Open と同じ Gs2Domain と IGameSession です。Async 形式は UniTask を返し、GS2_ENABLE_UNITASK が必要です。UniTask を使わない場合は ConfirmFuture を使います。戻り値は Gs2Future です。
ローカルでの入力受付、サーバー検証、報酬反映は、それぞれ次の方法で確認します。
| 段階 | 確認方法 | 確認できること |
|---|---|---|
| ローカル実行 | 操作結果の Accepted | ローカルで入力が採用された |
| サーバー検証 | Confirm の正常完了 | 送信した操作履歴がサーバーで受理された |
| 報酬反映 | 付与先サービスの状態取得 | 非同期の報酬処理が在庫などに反映された |
Confirm の成功だけでは、報酬反映まで完了したとは判断できません。
送信状態の参照
| プロパティ | 内容 |
|---|---|
PendingEventCount | 保留中のイベント数 |
IsConfirming | 送信・確認中か。この間は新しい入力を受け付けない |
RequiresReconciliation | 最新のサーバー状態から Session を作り直す必要があるか |
Confirm が完了・失敗した後
| 結果 | 履歴の扱い | 次の操作 |
|---|---|---|
| 正常完了 | 送信した保留履歴を確認済みとして取り除く | ゲームが入力待ちなら操作を続けられる |
失敗し、RequiresReconciliation が false | 未確認の履歴を保持する | 原因を解消して、同じ Session の Confirm を再実行する |
失敗し、RequiresReconciliation が true | 同じ Session からの再送・新しい入力を受け付けない | 最新のサーバー状態を Open で開き直し、画面を復元する |
再送時の履歴と重複防止キーは SDK が保持します。操作そのものをもう一度呼んで再現する必要はありません。再送期限を超えた場合は、次の Confirm で RequiresReconciliation が true になり、開き直しが必要になります。
失敗後も IsConfirming と RequiresReconciliation がともに false なら、現在受け付けている操作をローカルで続行できます。追加した履歴も後の Confirm で送ります。ただし、未確認の結果をサーバーで確定済みとして扱わないでください。
保留履歴はメモリ内に保持します。開き直した Session には、サーバーでまだ検証されていないローカルの操作は引き継がれません。アプリ終了をまたぐ保存は別途設計が必要です。
Session と Executor は Unity のメインスレッドから使用してください。