GS2-StateMachine SDK for Game Engine API リファレンス

ゲームエンジン向け GS2-StateMachine SDK の モデルの仕様 と API のリファレンス

モデル

EzStatus

ステートマシンの状態

特定のユーザーに対するステートマシンの実行インスタンスを表します。変数、サブステートマシン用のコールスタック、遷移回数、乱数状態を含む現在の実行状態を追跡します。ステータスは Running、Wait、Pass(成功)、Error の状態を遷移します。

有効化条件必須デフォルト値の制限説明
statusIdstring
~ 1024文字ステートマシンの状態 GRN
※ サーバーが自動で設定
namestring
UUID~ 36文字ステータス名
ステートマシンの状態の一意な名前を保持します。
名前は UUID(Universally Unique Identifier)フォーマットで自動的に生成され、各ステートマシンの状態を識別するために使用されます。
enableSpeculativeExecution文字列列挙型
enum {
  “enable”,
  “disable”
}
“disable”投機的実行を有効にするか
有効にすると、ステートマシン定義と乱数状態がこの Status エンティティに含まれます。これによりクライアントがサーバー確認前にローカルで遷移をシミュレーションでき、体感遅延を軽減できます。
定義説明
“enable”有効
“disable”無効
stateMachineDefinitionstring{enableSpeculativeExecution} == “enable”
~ 16777216文字ステートマシン定義
投機的実行のためにこのステータスに埋め込まれた GSL 定義です。enableSpeculativeExecution が有効な場合のみ存在します。通常の API レスポンスではフィルタリングされ、クライアント側シミュレーションに必要な場合のみ含まれます。

※ enableSpeculativeExecution が “enable” であれば 有効
randomStatusEzRandomStatus{enableSpeculativeExecution} == “enable”
乱数状態
この実行インスタンスの乱数生成状態です。投機的実行時にクライアントとサーバーで決定論的な乱数動作を保証するために使用されます。enableSpeculativeExecution が有効な場合のみ存在します。

※ enableSpeculativeExecution が “enable” であれば 有効
stacksList<EzStackEntry>[]0 ~ 1024 itemsスタック
サブステートマシン呼び出しのコールスタックです。ステートマシンがサブステートマシンを呼び出すと、呼び出し元のステートマシン名と戻り先タスクがプッシュされます。サブステートマシンが完了するとエントリがポップされ、戻り先タスクから実行が再開されます。
variablesList<EzVariable>[]0 ~ 1000 itemsステートマシンごとの状態変数
コール階層内の各ステートマシンの現在の変数値です。各エントリはステートマシン名と、int、float、string、bool、array、map 型をサポートする JSON シリアライズされた値を保持します。変数は同一実行インスタンス内の状態遷移を通じて永続化されます。
status文字列列挙型
enum {
  “Running”,
  “Wait”,
  “Pass”,
  “Error”
}
“Running”ステータス
このステートマシンインスタンスの現在の実行状態です。「Running」はマシンが遷移を処理中であることを意味します。「Wait」はマシンが外部イベント(emit)を待機中であることを意味します。「Pass」は正常に完了したことを意味します。「Error」はエラーで終了したことを意味します。
定義説明
“Running”実行中
“Wait”待機中
“Pass”終了
“Error”エラー
lastErrorstring~ 1024文字最後のエラー
最後に発生したエラーのメッセージです。ステータスが「Error」に遷移した際に設定されます。ステートマシンが異常終了した原因の詳細を含みます。
transitionCountint00 ~ 2147483645遷移回数
この実行インスタンスで実行された状態遷移の合計回数です。遷移ごとに加算されます。この値が1000を超えると、無限ループを防ぐためステートマシンはエラーで終了します。

EzStackEntry

スタックエントリ

サブステートマシンのコールスタック内の1つのエントリを表します。ステートマシンがサブステートマシンを呼び出すと、呼び出し元の名前と戻り先タスクがスタックにプッシュされます。サブステートマシンが完了すると、ポップされたエントリの戻り先タスクから実行が再開されます。

有効化条件必須デフォルト値の制限説明
stateMachineNamestring
~ 128文字ステートマシン名
このスタックエントリをプッシュした呼び出し元ステートマシンの名前です。サブステートマシンから戻る際に、どのステートマシンのコンテキストを復元するかの識別に使用されます。
taskNamestring
~ 128文字タスク名
サブステートマシンが完了した際に戻るタスク(状態)の名前です。呼び出し元ステートマシンのこのタスクから実行が再開されます。

EzVariable

ステートマシンごとの状態変数

コール階層内の特定のステートマシンの現在の変数状態を保持します。値は int、float、string、bool、array、map データ型をサポートする JSON シリアライズされた表現です。

有効化条件必須デフォルト値の制限説明
stateMachineNamestring
~ 128文字ステートマシン名
これらの変数を所有するステートマシンの名前です。ネストされたコール階層では、各ステートマシンがこの名前で識別される独立した変数スコープを持ちます。
valuestring
~ 1048576文字
このステートマシンの JSON シリアライズされた変数値です。int、float、string、bool、array、map データ型をサポートします。ステートマシンが遷移やアクションを処理する際に更新されます。

EzChangeStateEvent

ステートの変更イベント

ステートマシン内で発生した状態遷移を記録します。遷移先のタスク名、整合性検証用のハッシュ、および遷移のタイムスタンプを含みます。

有効化条件必須デフォルト値の制限説明
taskNamestring
~ 128文字タスク名
ステートマシンが遷移した先のタスク(状態)の名前です。
hashstring
~ 64文字ハッシュ
状態遷移の整合性を検証するためのハッシュ値です。遷移が正しく実行され、状態が一貫していることを検証するために使用されます。
timestamplong
タイムスタンプ

EzEmitEvent

メッセージの送信イベント

外部アクションをトリガーするためにステートマシンが送信するメッセージを表します。イベント名はアクションの種類を識別し、パラメータはアクション固有のデータを提供します。

有効化条件必須デフォルト値の制限説明
eventstring
~ 128文字イベント名
送信されたイベントの種類を識別する名前です。報酬の付与やリソースの消費など、どの外部アクションを呼び出すかの判定に使用されます。
parametersstring
~ 1024文字パラメータ
送信されたイベントに渡されるパラメータです。このイベントによってトリガーされる外部アクションを設定するために使用される、アクション固有のデータをシリアライズ形式で含みます。
timestamplong
タイムスタンプ

EzEvent

イベント

ステートマシン実行中に発生したイベントを表します。ステート変更イベント(状態遷移の記録)または emit イベント(外部アクションをトリガーするメッセージの送信)のいずれかです。

有効化条件必須デフォルト値の制限説明
eventType文字列列挙型
enum {
  “change_state”,
  “emit”
}
イベントの種類
イベントの種類です。「change_state」はステートマシン内の状態遷移を記録します。「emit」は報酬の付与やリソースの消費などの外部アクションをトリガーするメッセージの送信を表します。
定義説明
“change_state”ステートの変更
“emit”メッセージの送信
changeStateEventEzChangeStateEvent{eventType} == “change_state”
✓※
ステートの変更
※ eventType が “change_state” であれば 必須
emitEventEzEmitEvent{eventType} == “emit”
✓※
メッセージの送信
※ eventType が “emit” であれば 必須

EzRandomStatus

乱数の状態

ステートマシン実行インスタンスの乱数生成状態を管理します。シード値とカテゴリごとの使用状況追跡を含みます。投機的実行時にクライアントとサーバーで決定論的な乱数動作を保証するために使用されます。

有効化条件必須デフォルト値の制限説明
seedlong
0 ~ 4294967294乱数シード
ステートマシン実行内での決定論的な乱数生成のためのシード値です。
usedList<EzRandomUsed>0 ~ 1000 items使用済み乱数リスト
カテゴリごとに消費された乱数を追跡します。各カテゴリは乱数使用の異なる目的を表し、投機的再実行時の一貫性を維持するための独立した追跡を可能にします。

EzRandomUsed

使用済み乱数

ステートマシン実行内の特定カテゴリで消費された乱数の数を追跡します。各カテゴリは異なる目的での独立した乱数追跡を可能にします。

有効化条件必須デフォルト値の制限説明
categorylong
0 ~ 4294967294カテゴリ
乱数使用カテゴリの数値識別子です。各カテゴリは乱数消費を独立して追跡し、ステートマシンが異なる目的に別々の乱数シーケンスを使用できるようにします。
usedlong
0 ~ 4294967294使用回数
このカテゴリで消費された乱数の数です。このカテゴリのシーケンスから乱数が引かれるたびに増加します。

EzVerifyActionResult

検証アクションの実行結果

有効化条件必須デフォルト値の制限説明
action文字列列挙型
enum {
"Gs2Dictionary:VerifyEntryByUserId",
"Gs2Distributor:IfExpressionByUserId",
"Gs2Distributor:AndExpressionByUserId",
"Gs2Distributor:OrExpressionByUserId",
"Gs2Enchant:VerifyRarityParameterStatusByUserId",
"Gs2Experience:VerifyRankByUserId",
"Gs2Experience:VerifyRankCapByUserId",
"Gs2Grade:VerifyGradeByUserId",
"Gs2Grade:VerifyGradeUpMaterialByUserId",
"Gs2Guild:VerifyCurrentMaximumMemberCountByGuildName",
"Gs2Guild:VerifyIncludeMemberByUserId",
"Gs2Inventory:VerifyInventoryCurrentMaxCapacityByUserId",
"Gs2Inventory:VerifyItemSetByUserId",
"Gs2Inventory:VerifyReferenceOfByUserId",
"Gs2Inventory:VerifySimpleItemByUserId",
"Gs2Inventory:VerifyBigItemByUserId",
"Gs2Limit:VerifyCounterByUserId",
"Gs2Matchmaking:VerifyIncludeParticipantByUserId",
"Gs2Mission:VerifyCompleteByUserId",
"Gs2Mission:VerifyCounterValueByUserId",
"Gs2Ranking2:VerifyGlobalRankingScoreByUserId",
"Gs2Ranking2:VerifyClusterRankingScoreByUserId",
"Gs2Ranking2:VerifySubscribeRankingScoreByUserId",
"Gs2Schedule:VerifyTriggerByUserId",
"Gs2Schedule:VerifyEventByUserId",
"Gs2SerialKey:VerifyCodeByUserId",
"Gs2Stamina:VerifyStaminaValueByUserId",
"Gs2Stamina:VerifyStaminaMaxValueByUserId",
"Gs2Stamina:VerifyStaminaRecoverIntervalMinutesByUserId",
"Gs2Stamina:VerifyStaminaRecoverValueByUserId",
"Gs2Stamina:VerifyStaminaOverflowValueByUserId",
}
検証アクションで実行するアクションの種類
verifyRequeststring
~ 524288文字アクション実行時に使用されるリクエストのJSON文字列
statusCodeint0 ~ 999ステータスコード
verifyResultstring~ 1048576文字結果内容

EzConsumeActionResult

消費アクションの実行結果

有効化条件必須デフォルト値の制限説明
action文字列列挙型
enum {
"Gs2AdReward:ConsumePointByUserId",
"Gs2Dictionary:DeleteEntriesByUserId",
"Gs2Enhance:DeleteProgressByUserId",
"Gs2Exchange:DeleteAwaitByUserId",
"Gs2Experience:SubExperienceByUserId",
"Gs2Experience:SubRankCapByUserId",
"Gs2Formation:SubMoldCapacityByUserId",
"Gs2Grade:SubGradeByUserId",
"Gs2Guild:DecreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:DecreaseMaximumIdleMinutesByUserId",
"Gs2Inbox:OpenMessageByUserId",
"Gs2Inbox:DeleteMessageByUserId",
"Gs2Inventory:ConsumeItemSetByUserId",
"Gs2Inventory:ConsumeSimpleItemsByUserId",
"Gs2Inventory:ConsumeBigItemByUserId",
"Gs2JobQueue:DeleteJobByUserId",
"Gs2Limit:CountUpByUserId",
"Gs2LoginReward:MarkReceivedByUserId",
"Gs2Mission:ReceiveByUserId",
"Gs2Mission:BatchReceiveByUserId",
"Gs2Mission:DecreaseCounterByUserId",
"Gs2Mission:ResetCounterByUserId",
"Gs2Money:WithdrawByUserId",
"Gs2Money:RecordReceipt",
"Gs2Money2:WithdrawByUserId",
"Gs2Money2:VerifyReceiptByUserId",
"Gs2Quest:DeleteProgressByUserId",
"Gs2Ranking2:CreateGlobalRankingReceivedRewardByUserId",
"Gs2Ranking2:CreateClusterRankingReceivedRewardByUserId",
"Gs2Schedule:DeleteTriggerByUserId",
"Gs2SerialKey:UseByUserId",
"Gs2Showcase:IncrementPurchaseCountByUserId",
"Gs2SkillTree:MarkRestrainByUserId",
"Gs2Stamina:DecreaseMaxValueByUserId",
"Gs2Stamina:ConsumeStaminaByUserId",
}
消費アクションで実行するアクションの種類
consumeRequeststring
~ 524288文字アクション実行時に使用されるリクエストのJSON文字列
statusCodeint0 ~ 999ステータスコード
consumeResultstring~ 1048576文字結果内容

EzAcquireActionResult

入手アクションの実行結果

有効化条件必須デフォルト値の制限説明
action文字列列挙型
enum {
"Gs2AdReward:AcquirePointByUserId",
"Gs2Dictionary:AddEntriesByUserId",
"Gs2Enchant:ReDrawBalanceParameterStatusByUserId",
"Gs2Enchant:SetBalanceParameterStatusByUserId",
"Gs2Enchant:ReDrawRarityParameterStatusByUserId",
"Gs2Enchant:AddRarityParameterStatusByUserId",
"Gs2Enchant:SetRarityParameterStatusByUserId",
"Gs2Enhance:DirectEnhanceByUserId",
"Gs2Enhance:UnleashByUserId",
"Gs2Enhance:CreateProgressByUserId",
"Gs2Exchange:ExchangeByUserId",
"Gs2Exchange:IncrementalExchangeByUserId",
"Gs2Exchange:CreateAwaitByUserId",
"Gs2Exchange:AcquireForceByUserId",
"Gs2Exchange:SkipByUserId",
"Gs2Experience:AddExperienceByUserId",
"Gs2Experience:SetExperienceByUserId",
"Gs2Experience:AddRankCapByUserId",
"Gs2Experience:SetRankCapByUserId",
"Gs2Experience:MultiplyAcquireActionsByUserId",
"Gs2Formation:AddMoldCapacityByUserId",
"Gs2Formation:SetMoldCapacityByUserId",
"Gs2Formation:AcquireActionsToFormProperties",
"Gs2Formation:SetFormByUserId",
"Gs2Formation:AcquireActionsToPropertyFormProperties",
"Gs2Friend:UpdateProfileByUserId",
"Gs2Grade:AddGradeByUserId",
"Gs2Grade:ApplyRankCapByUserId",
"Gs2Grade:MultiplyAcquireActionsByUserId",
"Gs2Guild:IncreaseMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Guild:SetMaximumCurrentMaximumMemberCountByGuildName",
"Gs2Idle:IncreaseMaximumIdleMinutesByUserId",
"Gs2Idle:SetMaximumIdleMinutesByUserId",
"Gs2Idle:ReceiveByUserId",
"Gs2Inbox:SendMessageByUserId",
"Gs2Inventory:AddCapacityByUserId",
"Gs2Inventory:SetCapacityByUserId",
"Gs2Inventory:AcquireItemSetByUserId",
"Gs2Inventory:AcquireItemSetWithGradeByUserId",
"Gs2Inventory:AddReferenceOfByUserId",
"Gs2Inventory:DeleteReferenceOfByUserId",
"Gs2Inventory:AcquireSimpleItemsByUserId",
"Gs2Inventory:SetSimpleItemsByUserId",
"Gs2Inventory:AcquireBigItemByUserId",
"Gs2Inventory:SetBigItemByUserId",
"Gs2JobQueue:PushByUserId",
"Gs2Limit:CountDownByUserId",
"Gs2Limit:DeleteCounterByUserId",
"Gs2LoginReward:DeleteReceiveStatusByUserId",
"Gs2LoginReward:UnmarkReceivedByUserId",
"Gs2Lottery:DrawByUserId",
"Gs2Lottery:ResetBoxByUserId",
"Gs2Mission:RevertReceiveByUserId",
"Gs2Mission:IncreaseCounterByUserId",
"Gs2Mission:SetCounterByUserId",
"Gs2Money:DepositByUserId",
"Gs2Money:RevertRecordReceipt",
"Gs2Money2:DepositByUserId",
"Gs2Quest:CreateProgressByUserId",
"Gs2Schedule:TriggerByUserId",
"Gs2Schedule:ExtendTriggerByUserId",
"Gs2Script:InvokeScript",
"Gs2SerialKey:RevertUseByUserId",
"Gs2SerialKey:IssueOnce",
"Gs2Showcase:DecrementPurchaseCountByUserId",
"Gs2Showcase:ForceReDrawByUserId",
"Gs2SkillTree:MarkReleaseByUserId",
"Gs2Stamina:RecoverStaminaByUserId",
"Gs2Stamina:RaiseMaxValueByUserId",
"Gs2Stamina:SetMaxValueByUserId",
"Gs2Stamina:SetRecoverIntervalByUserId",
"Gs2Stamina:SetRecoverValueByUserId",
"Gs2StateMachine:StartStateMachineByUserId",
}
入手アクションで実行するアクションの種類
acquireRequeststring
~ 524288文字アクション実行時に使用されるリクエストのJSON文字列
statusCodeint0 ~ 999ステータスコード
acquireResultstring~ 1048576文字結果内容

EzTransactionResult

トランザクション実行結果

サーバーサイドでのトランザクションの自動実行機能を利用して実行されたトランザクションの実行結果

有効化条件必須デフォルト値の制限説明
transactionIdstring
36 ~ 36文字トランザクションID
verifyResultsList<EzVerifyActionResult>0 ~ 10 items検証アクションの実行結果リスト
consumeResultsList<EzConsumeActionResult>[]0 ~ 10 items消費アクションの実行結果リスト
acquireResultsList<EzAcquireActionResult>[]0 ~ 100 items入手アクションの実行結果リスト

メソッド

emit

イベントを送信して状態遷移をトリガーする

ステートマシンに名前付きイベントを送信し、定義された遷移ルールに基づいて現在の状態から次の状態へ移行させます。

ゲームクライアントがステートマシンを進めるためのメインの方法です。たとえば:

  • プレイヤーがクエストダイアログで「受諾」をタップ → “accept” イベントを送信 → 状態が「提示中」から「進行中」に変更
  • プレイヤーがボスを倒す → “boss_defeated” イベントを送信 → 状態が「ボスステージ」から「完了」に変更
  • プレイヤーがストーリーで選択肢を選ぶ → “choose_path_a” イベントを送信 → 選択した分岐先の状態に遷移

追加データをJSON引数(args)として渡せます。たとえば “submit_answer” イベントを送信する際に、{“answer”: “B”} をargsに含めることができます。

ステートマシンは現在の状態で有効なイベントのみを受け付けます。現在の状態で定義されていないイベントを送信するとエラーが返され、遷移は発生しません。

Request

有効化条件必須デフォルト値の制限説明
namespaceNamestring
~ 128文字ネームスペース名
ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。
gameSessionGameSession
GameSession
statusNamestring
~ 36文字ステータス名
eventNamestring
~ 36文字イベントの名前
argsstring“{}”~ 4096文字ステートマシンに渡す引数

Result

説明
itemEzStatusステートマシンの状態

実装例

    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 で明示的に削除するまでシステムに残り続けます。これにより以下のことが可能です:

  • プレイヤーに完了結果を表示する(例: 「クエストクリア!」画面)
  • 最終状態と変数を読み取って報酬を決定する
  • エラー状態を処理して次にどうするか判断する

一般的な流れ:

  1. ステートマシンが終端状態に到達 → ステータスが「Pass」になる
  2. ゲームが最終状態を読み取り、プレイヤーに報酬を付与する
  3. ゲームが完了画面を表示する
  4. プレイヤーが画面を閉じる → ゲームが Exit を呼び出してクリーンアップ

Running 状態のステートマシンには Exit を呼び出せません。実行中のステートマシンを強制停止するにはサーバー側の操作が必要です。

Request

有効化条件必須デフォルト値の制限説明
namespaceNamestring
~ 128文字ネームスペース名
ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。
gameSessionGameSession
GameSession
statusNamestring
~ 36文字ステータス名

Result

説明
itemEzStatus終了したステートマシンの状態

実装例

    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

有効化条件必須デフォルト値の制限説明
namespaceNamestring
~ 128文字ネームスペース名
ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。
gameSessionGameSession
GameSession
statusNamestring
~ 36文字ステータス名

Result

説明
itemEzStatusステートマシンの状態

実装例

    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);

listStatuses

プレイヤーのステートマシンインスタンスの一覧を取得する

現在のプレイヤーに属するすべてのステートマシンインスタンスを取得します。
ステートマシンはサーバーで管理されるワークフローで、プレイヤーの一連のステップ(状態)の進行を追跡します。各ステップはアクションの実行、プレイヤー入力の待機、条件による分岐が可能です。

ステートマシンの主な使い方:

  • クエスト進行: 「クエスト受諾」→「進行中」→「ボス戦」→「完了」→「報酬受取」
  • チュートリアルフロー: 「ようこそ」→「移動チュートリアル」→「バトルチュートリアル」→「ガチャチュートリアル」→「完了」
  • 期間限定イベント: 制限時間付きの複数フェーズのイベントプロセス

各ステートマシンインスタンスは3つのステータスのいずれかを持ちます:

  • Running: ステートマシンが動作中で、次のイベントを待機している
  • Pass: ステートマシンが正常に完了した(終端状態に到達)
  • Error: ステートマシンでエラーが発生した

ステータスでフィルタリングできます。たとえばクエスト画面にアクティブ(Running)なステートマシンだけを表示したり、クリーンアップが必要な完了済みのものを見つけたりできます。

Request

有効化条件必須デフォルト値の制限説明
namespaceNamestring
~ 128文字ネームスペース名
ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。
gameSessionGameSession
GameSession
statusステータス
このステートマシンインスタンスの現在の実行状態です。「Running」はマシンが遷移を処理中であることを意味します。「Wait」はマシンが外部イベント(emit)を待機中であることを意味します。「Pass」は正常に完了したことを意味します。「Error」はエラーで終了したことを意味します。
定義説明
“Running”実行中
“Wait”待機中
“Pass”終了
“Error”エラー
pageTokenstring~ 1024文字データの取得を開始する位置を指定するトークン
limitint301 ~ 1000データの取得件数

Result

説明
itemsList<EzStatus>ステートマシンの状態のリスト
nextPageTokenstringリストの続きを取得するためのページトークン

実装例

    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);

report

クライアント側のステートマシン実行結果をサーバーに送信して検証する

ゲームクライアントでローカルに処理されたイベントのバッチをサーバーに送信し、検証を受けます。
これは「投機的実行」と呼ばれる最適化機能です。すべてのイベントで Emit を呼び出す(毎回ネットワーク遅延が発生する)代わりに、クライアントがローカルでステートマシンを実行し、複数のイベントをまとめて処理した後、結果を1回の呼び出しでサーバーに送信します。

投機的実行の仕組み:

  1. クライアントがステートマシン定義のローカルコピーを持つ
  2. イベントが連続して発生する場合(例: ゲームプレイ中)、クライアントはサーバーの応答を待たずにローカルで処理する
  3. イベントのバッチ処理後、クライアントが Report を呼び出してすべてのイベントをサーバーに送信する
  4. サーバーがイベントをリプレイし、最終状態がクライアントの報告と一致するか検証する
  5. 状態が一致すればサーバーが結果を受理する。一致しない場合(例: クライアントが改ざんされた場合)、StateMismatch エラーが返される

以下のようなパフォーマンス重視のシナリオで便利です:

  • サーバー応答を待つとラグが発生するテンポの速いゲームプレイ
  • プレイヤーが一時的に接続を失う可能性があるオフライン対応フロー
  • 多数の高速な状態遷移のバッチ処理

注意: このAPIを使用するには、ネームスペースで投機的実行が有効になっている必要があります。

Request

有効化条件必須デフォルト値の制限説明
namespaceNamestring
~ 128文字ネームスペース名
ネームスペース固有の名前。英数字および -(ハイフン) _(アンダースコア) .(ピリオド)で指定します。
gameSessionGameSession
GameSession
statusNamestring
~ 36文字ステータス名
eventsList<EzEvent>0 ~ 1000 itemsイベントのリスト

Result

説明
itemEzStatusステートマシンの状態

Error

このAPIには特別な例外が定義されています。
GS2-SDK for GameEngine ではゲーム内でハンドリングが必要そうなエラーは一般的な例外から派生した特殊化した例外を用意することでハンドリングしやすくしています。
一般的なエラーの種類や、ハンドリング方法は こちら のドキュメントを参考にしてください。

基底クラス説明
StateMismatchExceptionBadRequestExceptionレポートの検証の結果状態が不一致となりました

実装例

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();