GS2-StateMachine SDK for Game Engine API リファレンス
モデル
EzStatus
ステートマシンの状態
特定のユーザーに対するステートマシンの実行インスタンスを表します。変数、サブステートマシン用のコールスタック、遷移回数、乱数状態を含む現在の実行状態を追跡します。ステータスは Running、Wait、Pass(成功)、Error の状態を遷移します。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| statusId | string | ※ | ~ 1024文字 | ステートマシンの状態
GRN ※ サーバーが自動で設定 | ||||||||||||
| name | string | ✓ | UUID | ~ 36文字 | ステータス名 ステートマシンの状態の一意な名前を保持します。 名前は UUID(Universally Unique Identifier)フォーマットで自動的に生成され、各ステートマシンの状態を識別するために使用されます。 | |||||||||||
| enableSpeculativeExecution | 文字列列挙型 enum { “enable”, “disable” } | “disable” | 投機的実行を有効にするか 有効にすると、ステートマシン定義と乱数状態がこの Status エンティティに含まれます。これによりクライアントがサーバー確認前にローカルで遷移をシミュレーションでき、体感遅延を軽減できます。
| |||||||||||||
| stateMachineDefinition | string | {enableSpeculativeExecution} == “enable” | ※ | ~ 16777216文字 | ステートマシン定義 投機的実行のためにこのステータスに埋め込まれた GSL 定義です。enableSpeculativeExecution が有効な場合のみ存在します。通常の API レスポンスではフィルタリングされ、クライアント側シミュレーションに必要な場合のみ含まれます。 ※ enableSpeculativeExecution が “enable” であれば 有効 | |||||||||||
| randomStatus | EzRandomStatus | {enableSpeculativeExecution} == “enable” | ※ | 乱数状態 この実行インスタンスの乱数生成状態です。投機的実行時にクライアントとサーバーで決定論的な乱数動作を保証するために使用されます。enableSpeculativeExecution が有効な場合のみ存在します。 ※ enableSpeculativeExecution が “enable” であれば 有効 | ||||||||||||
| stacks | List<EzStackEntry> | [] | 0 ~ 1024 items | スタック サブステートマシン呼び出しのコールスタックです。ステートマシンがサブステートマシンを呼び出すと、呼び出し元のステートマシン名と戻り先タスクがプッシュされます。サブステートマシンが完了するとエントリがポップされ、戻り先タスクから実行が再開されます。 | ||||||||||||
| variables | List<EzVariable> | [] | 0 ~ 1000 items | ステートマシンごとの状態変数 コール階層内の各ステートマシンの現在の変数値です。各エントリはステートマシン名と、int、float、string、bool、array、map 型をサポートする JSON シリアライズされた値を保持します。変数は同一実行インスタンス内の状態遷移を通じて永続化されます。 | ||||||||||||
| status | 文字列列挙型 enum { “Running”, “Wait”, “Pass”, “Error” } | “Running” | ステータス このステートマシンインスタンスの現在の実行状態です。「Running」はマシンが遷移を処理中であることを意味します。「Wait」はマシンが外部イベント(emit)を待機中であることを意味します。「Pass」は正常に完了したことを意味します。「Error」はエラーで終了したことを意味します。
| |||||||||||||
| lastError | string | ~ 1024文字 | 最後のエラー 最後に発生したエラーのメッセージです。ステータスが「Error」に遷移した際に設定されます。ステートマシンが異常終了した原因の詳細を含みます。 | |||||||||||||
| transitionCount | int | 0 | 0 ~ 2147483645 | 遷移回数 この実行インスタンスで実行された状態遷移の合計回数です。遷移ごとに加算されます。この値が1000を超えると、無限ループを防ぐためステートマシンはエラーで終了します。 |
EzStackEntry
スタックエントリ
サブステートマシンのコールスタック内の1つのエントリを表します。ステートマシンがサブステートマシンを呼び出すと、呼び出し元の名前と戻り先タスクがスタックにプッシュされます。サブステートマシンが完了すると、ポップされたエントリの戻り先タスクから実行が再開されます。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| stateMachineName | string | ✓ | ~ 128文字 | ステートマシン名 このスタックエントリをプッシュした呼び出し元ステートマシンの名前です。サブステートマシンから戻る際に、どのステートマシンのコンテキストを復元するかの識別に使用されます。 | ||
| taskName | string | ✓ | ~ 128文字 | タスク名 サブステートマシンが完了した際に戻るタスク(状態)の名前です。呼び出し元ステートマシンのこのタスクから実行が再開されます。 |
EzVariable
ステートマシンごとの状態変数
コール階層内の特定のステートマシンの現在の変数状態を保持します。値は int、float、string、bool、array、map データ型をサポートする JSON シリアライズされた表現です。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| stateMachineName | string | ✓ | ~ 128文字 | ステートマシン名 これらの変数を所有するステートマシンの名前です。ネストされたコール階層では、各ステートマシンがこの名前で識別される独立した変数スコープを持ちます。 | ||
| value | string | ✓ | ~ 1048576文字 | 値 このステートマシンの JSON シリアライズされた変数値です。int、float、string、bool、array、map データ型をサポートします。ステートマシンが遷移やアクションを処理する際に更新されます。 |
EzChangeStateEvent
ステートの変更イベント
ステートマシン内で発生した状態遷移を記録します。遷移先のタスク名、整合性検証用のハッシュ、および遷移のタイムスタンプを含みます。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| taskName | string | ✓ | ~ 128文字 | タスク名 ステートマシンが遷移した先のタスク(状態)の名前です。 | ||
| hash | string | ✓ | ~ 64文字 | ハッシュ 状態遷移の整合性を検証するためのハッシュ値です。遷移が正しく実行され、状態が一貫していることを検証するために使用されます。 | ||
| timestamp | long | ✓ | タイムスタンプ |
EzEmitEvent
メッセージの送信イベント
外部アクションをトリガーするためにステートマシンが送信するメッセージを表します。イベント名はアクションの種類を識別し、パラメータはアクション固有のデータを提供します。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| event | string | ✓ | ~ 128文字 | イベント名 送信されたイベントの種類を識別する名前です。報酬の付与やリソースの消費など、どの外部アクションを呼び出すかの判定に使用されます。 | ||
| parameters | string | ✓ | ~ 1024文字 | パラメータ 送信されたイベントに渡されるパラメータです。このイベントによってトリガーされる外部アクションを設定するために使用される、アクション固有のデータをシリアライズ形式で含みます。 | ||
| timestamp | long | ✓ | タイムスタンプ |
EzEvent
イベント
ステートマシン実行中に発生したイベントを表します。ステート変更イベント(状態遷移の記録)または emit イベント(外部アクションをトリガーするメッセージの送信)のいずれかです。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| eventType | 文字列列挙型 enum { “change_state”, “emit” } | ✓ | イベントの種類 イベントの種類です。「change_state」はステートマシン内の状態遷移を記録します。「emit」は報酬の付与やリソースの消費などの外部アクションをトリガーするメッセージの送信を表します。
| |||||||||
| changeStateEvent | EzChangeStateEvent | {eventType} == “change_state” | ✓※ | ステートの変更 ※ eventType が “change_state” であれば 必須 | ||||||||
| emitEvent | EzEmitEvent | {eventType} == “emit” | ✓※ | メッセージの送信 ※ eventType が “emit” であれば 必須 |
EzRandomStatus
乱数の状態
ステートマシン実行インスタンスの乱数生成状態を管理します。シード値とカテゴリごとの使用状況追跡を含みます。投機的実行時にクライアントとサーバーで決定論的な乱数動作を保証するために使用されます。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| seed | long | ✓ | 0 ~ 4294967294 | 乱数シード ステートマシン実行内での決定論的な乱数生成のためのシード値です。 | ||
| used | List<EzRandomUsed> | 0 ~ 1000 items | 使用済み乱数リスト カテゴリごとに消費された乱数を追跡します。各カテゴリは乱数使用の異なる目的を表し、投機的再実行時の一貫性を維持するための独立した追跡を可能にします。 |
EzRandomUsed
使用済み乱数
ステートマシン実行内の特定カテゴリで消費された乱数の数を追跡します。各カテゴリは異なる目的での独立した乱数追跡を可能にします。
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| category | long | ✓ | 0 ~ 4294967294 | カテゴリ 乱数使用カテゴリの数値識別子です。各カテゴリは乱数消費を独立して追跡し、ステートマシンが異なる目的に別々の乱数シーケンスを使用できるようにします。 | ||
| used | long | ✓ | 0 ~ 4294967294 | 使用回数 このカテゴリで消費された乱数の数です。このカテゴリのシーケンスから乱数が引かれるたびに増加します。 |
EzVerifyActionResult
検証アクションの実行結果
EzConsumeActionResult
消費アクションの実行結果
EzAcquireActionResult
入手アクションの実行結果
EzTransactionResult
トランザクション実行結果
サーバーサイドでのトランザクションの自動実行機能を利用して実行されたトランザクションの実行結果
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| transactionId | string | ✓ | 36 ~ 36文字 | トランザクションID | ||
| verifyResults | List<EzVerifyActionResult> | 0 ~ 10 items | 検証アクションの実行結果リスト | |||
| consumeResults | List<EzConsumeActionResult> | [] | 0 ~ 10 items | 消費アクションの実行結果リスト | ||
| acquireResults | List<EzAcquireActionResult> | [] | 0 ~ 100 items | 入手アクションの実行結果リスト |
メソッド
emit
イベントを送信して状態遷移をトリガーする
ステートマシンに名前付きイベントを送信し、定義された遷移ルールに基づいて現在の状態から次の状態へ移行させます。
ゲームクライアントがステートマシンを進めるためのメインの方法です。たとえば:
- プレイヤーがクエストダイアログで「受諾」をタップ → “accept” イベントを送信 → 状態が「提示中」から「進行中」に変更
- プレイヤーがボスを倒す → “boss_defeated” イベントを送信 → 状態が「ボスステージ」から「完了」に変更
- プレイヤーがストーリーで選択肢を選ぶ → “choose_path_a” イベントを送信 → 選択した分岐先の状態に遷移
追加データをJSON引数(args)として渡せます。たとえば “submit_answer” イベントを送信する際に、{“answer”: “B”} をargsに含めることができます。
ステートマシンは現在の状態で有効なイベントのみを受け付けます。現在の状態で定義されていないイベントを送信するとエラーが返され、遷移は発生しません。
Request
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128文字 | ネームスペース名 ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36文字 | ステータス名 | ||
| eventName | string | ✓ | ~ 36文字 | イベントの名前 | ||
| args | string | “{}” | ~ 4096文字 | ステートマシンに渡す引数 |
Result
| 型 | 説明 | |
|---|---|---|
| item | EzStatus | ステートマシンの状態 |
実装例
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.EmitAsync(
eventName: "event-0001",
args: "{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}"
);
var item = await result.ModelAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.EmitFuture(
eventName: "event-0001",
args: "{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}"
);
yield return future;
if (future.Error != null)
{
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Emit(
"event-0001", // eventName
"{\"value1\": \"value1\", \"value2\": 2.0, \"value3\": 3}" // args
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();exit
完了したステートマシンをクリーンアップする
実行が終了したステートマシンインスタンスを削除します。ステートマシンのステータスが「Pass」(正常完了)または「Error」(失敗)の場合にのみ呼び出せます。
ステートマシンが終端状態に到達した後も、Exit で明示的に削除するまでシステムに残り続けます。これにより以下のことが可能です:
- プレイヤーに完了結果を表示する(例: 「クエストクリア!」画面)
- 最終状態と変数を読み取って報酬を決定する
- エラー状態を処理して次にどうするか判断する
一般的な流れ:
- ステートマシンが終端状態に到達 → ステータスが「Pass」になる
- ゲームが最終状態を読み取り、プレイヤーに報酬を付与する
- ゲームが完了画面を表示する
- プレイヤーが画面を閉じる → ゲームが Exit を呼び出してクリーンアップ
Running 状態のステートマシンには Exit を呼び出せません。実行中のステートマシンを強制停止するにはサーバー側の操作が必要です。
Request
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128文字 | ネームスペース名 ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36文字 | ステータス名 |
Result
| 型 | 説明 | |
|---|---|---|
| item | EzStatus | 終了したステートマシンの状態 |
実装例
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.ExitAsync(
); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ExitFuture(
);
yield return future;
if (future.Error != null)
{
onError.Invoke(future.Error, null);
yield break;
} const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Exit(
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}
const auto Result = Future->GetTask().Result();getStatus
特定のステートマシンインスタンスの現在の状態を取得する
特定のステートマシンインスタンスの詳細情報を取得します。現在どの状態にあるか、保存されている変数などが含まれます。
ワークフローの現在の進行状況をプレイヤーに表示する際に使います。たとえば:
- クエストトラッカーで「現在のステップ: モンスターを3体倒す(2/3)」を表示
- チュートリアルのインジケーターでプレイヤーがどのステップにいるかを表示
- プロセスのステータスが進行中か、完了か、エラーかを表示
レスポンスには以下が含まれます:
- 現在の状態名: マシンが今どの状態にあるか
- 変数: ステートマシンに保存されたデータ(例: 進行カウンター、選択結果)
- ステータス: マシンが Running(動作中)、Pass(完了)、Error(エラー)のいずれか
- スタックトレース: 状態遷移の履歴(デバッグに便利)
Request
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128文字 | ネームスペース名 ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36文字 | ステータス名 |
Result
| 型 | 説明 | |
|---|---|---|
| item | EzStatus | ステートマシンの状態 |
実装例
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var item = await domain.ModelAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ModelFuture();
yield return future;
var item = future.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Model();
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
return false;
}値の変更イベントハンドリング
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
// イベントハンドリングを開始
var callbackId = domain.Subscribe(
value => {
// 値が変化した時に呼び出される
// value には変更後の値が渡ってくる
}
);
// イベントハンドリングを停止
domain.Unsubscribe(callbackId); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
// イベントハンドリングを開始
var callbackId = domain.Subscribe(
value => {
// 値が変化した時に呼び出される
// value には変更後の値が渡ってくる
}
);
// イベントハンドリングを停止
domain.Unsubscribe(callbackId); const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
// イベントハンドリングを開始
const auto CallbackId = Domain->Subscribe(
[](TSharedPtr<Gs2::StateMachine::Model::FStatus> value) {
// 値が変化した時に呼び出される
// value には変更後の値が渡ってくる
}
);
// イベントハンドリングを停止
Domain->Unsubscribe(CallbackId);Warning
このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。
ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。
そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
listStatuses
プレイヤーのステートマシンインスタンスの一覧を取得する
現在のプレイヤーに属するすべてのステートマシンインスタンスを取得します。
ステートマシンはサーバーで管理されるワークフローで、プレイヤーの一連のステップ(状態)の進行を追跡します。各ステップはアクションの実行、プレイヤー入力の待機、条件による分岐が可能です。
ステートマシンの主な使い方:
- クエスト進行: 「クエスト受諾」→「進行中」→「ボス戦」→「完了」→「報酬受取」
- チュートリアルフロー: 「ようこそ」→「移動チュートリアル」→「バトルチュートリアル」→「ガチャチュートリアル」→「完了」
- 期間限定イベント: 制限時間付きの複数フェーズのイベントプロセス
各ステートマシンインスタンスは3つのステータスのいずれかを持ちます:
- Running: ステートマシンが動作中で、次のイベントを待機している
- Pass: ステートマシンが正常に完了した(終端状態に到達)
- Error: ステートマシンでエラーが発生した
ステータスでフィルタリングできます。たとえばクエスト画面にアクティブ(Running)なステートマシンだけを表示したり、クリーンアップが必要な完了済みのものを見つけたりできます。
Request
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128文字 | ネームスペース名 ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 | ||||||||||||
| gameSession | GameSession | ✓ | GameSession | |||||||||||||
| status | ステータス このステートマシンインスタンスの現在の実行状態です。「Running」はマシンが遷移を処理中であることを意味します。「Wait」はマシンが外部イベント(emit)を待機中であることを意味します。「Pass」は正常に完了したことを意味します。「Error」はエラーで終了したことを意味します。
| |||||||||||||||
| pageToken | string | ~ 1024文字 | データの取得を開始する位置を指定するトークン | |||||||||||||
| limit | int | 30 | 1 ~ 1000 | データの取得件数 |
Result
| 型 | 説明 | |
|---|---|---|
| items | List<EzStatus> | ステートマシンの状態のリスト |
| nextPageToken | string | リストの続きを取得するためのページトークン |
実装例
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var items = await domain.StatusesAsync(
status: "Running"
).ToListAsync(); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
var it = domain.Statuses(
status: "Running"
);
List<EzStatus> items = new List<EzStatus>();
while (it.HasNext())
{
yield return it.Next();
if (it.Error != null)
{
onError.Invoke(it.Error, null);
break;
}
if (it.Current != null)
{
items.Add(it.Current);
}
else
{
break;
}
} const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
const auto It = Domain->Statuses(
"Running" // status
);
TArray<Gs2::UE5::StateMachine::Model::FEzStatusPtr> Result;
for (auto Item : *It)
{
if (Item.IsError())
{
return false;
}
Result.Add(Item.Current());
}値の変更イベントハンドリング
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// イベントハンドリングを開始
var callbackId = domain.SubscribeStatuses(
() => {
// リストの要素が変化した時に呼び出される
}
);
// イベントハンドリングを停止
domain.UnsubscribeStatuses(callbackId); var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
);
// イベントハンドリングを開始
var callbackId = domain.SubscribeStatuses(
() => {
// リストの要素が変化した時に呼び出される
}
);
// イベントハンドリングを停止
domain.UnsubscribeStatuses(callbackId); const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
);
// イベントハンドリングを開始
const auto CallbackId = Domain->SubscribeStatuses(
[]() {
// リストの要素が変化した時に呼び出される
}
);
// イベントハンドリングを停止
Domain->UnsubscribeStatuses(CallbackId);Warning
このイベントはSDKがもつローカルキャッシュの値が変更された時に呼び出されます。
ローカルキャッシュは SDK が持つ API の実行、または GS2-Gateway の通知を有効にした GS2-Distributor 経由でのスタンプシートの実行、または GS2-Gateway の通知を有効にした GS2-JobQueue の実行によって変化したもののみが対象となります。
そのため、これらの方法以外で値が変更されてもコールバックは呼び出されません。
report
クライアント側のステートマシン実行結果をサーバーに送信して検証する
ゲームクライアントでローカルに処理されたイベントのバッチをサーバーに送信し、検証を受けます。
これは「投機的実行」と呼ばれる最適化機能です。すべてのイベントで Emit を呼び出す(毎回ネットワーク遅延が発生する)代わりに、クライアントがローカルでステートマシンを実行し、複数のイベントをまとめて処理した後、結果を1回の呼び出しでサーバーに送信します。
投機的実行の仕組み:
- クライアントがステートマシン定義のローカルコピーを持つ
- イベントが連続して発生する場合(例: ゲームプレイ中)、クライアントはサーバーの応答を待たずにローカルで処理する
- イベントのバッチ処理後、クライアントが Report を呼び出してすべてのイベントをサーバーに送信する
- サーバーがイベントをリプレイし、最終状態がクライアントの報告と一致するか検証する
- 状態が一致すればサーバーが結果を受理する。一致しない場合(例: クライアントが改ざんされた場合)、StateMismatch エラーが返される
以下のようなパフォーマンス重視のシナリオで便利です:
- サーバー応答を待つとラグが発生するテンポの速いゲームプレイ
- プレイヤーが一時的に接続を失う可能性があるオフライン対応フロー
- 多数の高速な状態遷移のバッチ処理
注意: このAPIを使用するには、ネームスペースで投機的実行が有効になっている必要があります。
Request
| 型 | 有効化条件 | 必須 | デフォルト | 値の制限 | 説明 | |
|---|---|---|---|---|---|---|
| namespaceName | string | ✓ | ~ 128文字 | ネームスペース名 ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。 | ||
| gameSession | GameSession | ✓ | GameSession | |||
| statusName | string | ✓ | ~ 36文字 | ステータス名 | ||
| events | List<EzEvent> | 0 ~ 1000 items | イベントのリスト |
Result
| 型 | 説明 | |
|---|---|---|
| item | EzStatus | ステートマシンの状態 |
Error
このAPIには特別な例外が定義されています。
GS2-SDK for GameEngine ではゲーム内でハンドリングが必要そうなエラーは一般的な例外から派生した特殊化した例外を用意することでハンドリングしやすくしています。
一般的なエラーの種類や、ハンドリング方法は こちら のドキュメントを参考にしてください。
| 型 | 基底クラス | 説明 |
|---|---|---|
| StateMismatchException | BadRequestException | レポートの検証の結果状態が不一致となりました |
実装例
try {
var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var result = await domain.ReportAsync(
events: new List<Gs2.Unity.Gs2StateMachine.Model.EzEvent> {
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
EventType = "emit",
EmitEvent =
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
Event = "message",
Parameters = "{\"payload\": \"Hello World\"}",
Timestamp = 1000,
},
},
}
);
var item = await result.ModelAsync();
} catch(Gs2.Gs2StateMachine.Exception.StateMismatchException e) {
// State of the verification result of the report is inconsistent.
} var domain = gs2.StateMachine.Namespace(
namespaceName: "namespace-0001"
).Me(
gameSession: GameSession
).Status(
statusName: "status-0001"
);
var future = domain.ReportFuture(
events: new List<Gs2.Unity.Gs2StateMachine.Model.EzEvent> {
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
EventType = "emit",
EmitEvent =
new Gs2.Unity.Gs2StateMachine.Model.EzEvent() {
Event = "message",
Parameters = "{\"payload\": \"Hello World\"}",
Timestamp = 1000,
},
},
}
);
yield return future;
if (future.Error != null)
{
if (future.Error is Gs2.Gs2StateMachine.Exception.StateMismatchException)
{
// State of the verification result of the report is inconsistent.
}
onError.Invoke(future.Error, null);
yield break;
}
var future2 = future.Result.ModelFuture();
yield return future2;
if (future2.Error != null)
{
onError.Invoke(future2.Error, null);
yield break;
}
var result = future2.Result; const auto Domain = Gs2->StateMachine->Namespace(
"namespace-0001" // namespaceName
)->Me(
GameSession
)->Status(
"status-0001" // statusName
);
const auto Future = Domain->Report(
[]
{
auto v = MakeShared<TArray<TSharedPtr<Gs2::UE5::StateMachine::Model::FEzEvent>>>();
v->Add(
MakeShared<Gs2::UE5::StateMachine::Model::FEzEvent>()
->WithEventType(TOptional<FString>("emit"))
->WithEmitEvent(MakeShared<Gs2::UE5::StateMachine::Model::FEzEmitEvent>()
->WithEvent(TOptional<FString>("message"))
->WithParameters(TOptional<FString>("{\"payload\": \"Hello World\"}"))
->WithTimestamp(TOptional<int32>(1000))
);
);
return v;
}() // events
);
Future->StartSynchronousTask();
if (Future->GetTask().IsError())
{
auto e = Future->GetTask().Error();
if (e->IsChildOf(Gs2::StateMachine::Error::FStateMismatchError::Class))
{
// State of the verification result of the report is inconsistent.
}
return false;
}
// obtain changed values / result values
const auto Future2 = Future->GetTask().Result()->Model();
Future2->StartSynchronousTask();
if (Future2->GetTask().IsError())
{
return Future2->GetTask().Error();
}
const auto Result = Future2->GetTask().Result();