GS2-StateMachine SDK for Game Engine API Reference

Specifications of models and API references for GS2-StateMachine SDK for Game Engine

Models

EzStatus

State Machine Status

Represents a running instance of a state machine for a specific user. Tracks the current execution state including variables, call stack for sub-state machines, transition count, and random number state. The status transitions through Running, Wait, Pass (success), and Error states.

Type Condition Required Default Value Limits Description
statusId string
*
~ 1024 chars Status of State Machine GRN
* Set automatically by the server
name string
UUID ~ 36 chars Status name
Maintains a unique name for each status of state machine.
The name is automatically generated in UUID (Universally Unique Identifier) format and used to identify each status of state machine.
enableSpeculativeExecution string (enum)
enum {
  “enable”,
  “disable”
}
“disable” Whether to enable speculative execution
When enabled, the state machine definition and random status are included in this Status entity. This allows clients to simulate transitions locally before server confirmation, reducing perceived latency.
DefinitionDescription
“enable”Enable
“disable”Disable
stateMachineDefinition string {enableSpeculativeExecution} == “enable”
*
~ 16777216 chars State machine definition
The GSL definition embedded in this status for speculative execution. Only present when enableSpeculativeExecution is enabled. Filtered out in normal API responses and only included when needed for client-side simulation.

* Enabled only if enableSpeculativeExecution is “enable”
randomStatus EzRandomStatus {enableSpeculativeExecution} == “enable”
*
Random status
The random number generation state for this execution instance. Used for speculative execution to ensure deterministic random behavior across client and server. Only present when enableSpeculativeExecution is enabled.

* Enabled only if enableSpeculativeExecution is “enable”
stacks List<EzStackEntry> [] 0 ~ 1024 items Stack
The call stack for sub-state machine invocations. When a state machine calls a sub-state machine, an entry is pushed with the caller’s state machine name and return task. When the sub-state machine completes, the entry is popped and execution resumes at the return task.
variables List<EzVariable> [] 0 ~ 1000 items State variables for each state machine
The current variable values for each state machine in the call hierarchy. Each entry holds the state machine name and a JSON-serialized value supporting int, float, string, bool, array, and map types. Variables persist across state transitions within the same execution instance.
status string (enum)
enum {
  “Running”,
  “Wait”,
  “Pass”,
  “Error”
}
“Running” Status
The current execution status of this state machine instance. “Running” means the machine is actively processing transitions. “Wait” means the machine is waiting for an external event (emit). “Pass” means it completed successfully. “Error” means it terminated with an error.
DefinitionDescription
“Running”Running
“Wait”Wait
“Pass”Pass
“Error”Error
lastError string ~ 1024 chars Last error
The error message from the most recent failure. Set when the status transitions to “Error”. Contains details about what caused the state machine to terminate abnormally.
transitionCount int 0 0 ~ 2147483645 Number of transitions
The total number of state transitions performed in this execution instance. Incremented on each transition. If this value exceeds 1000, the state machine is terminated with an error to prevent infinite loops.

EzStackEntry

Stack Entry

Represents a single entry in the sub-state machine call stack. When a state machine invokes a sub-state machine, the caller’s name and the return task are pushed onto the stack. When the sub-state machine completes, execution resumes at the return task of the popped entry.

Type Condition Required Default Value Limits Description
stateMachineName string
~ 128 chars Name of the state machine
The name of the calling state machine that pushed this stack entry. Used to identify which state machine’s context to restore when returning from a sub-state machine.
taskName string
~ 128 chars Task name
The name of the task (state) to return to when the sub-state machine completes. Execution resumes from this task in the calling state machine.

EzVariable

State variables per state machine

Holds the current variable state for a specific state machine within the call hierarchy. The value is a JSON-serialized representation supporting int, float, string, bool, array, and map data types.

Type Condition Required Default Value Limits Description
stateMachineName string
~ 128 chars Name of the state machine
The name of the state machine that owns these variables. In a nested call hierarchy, each state machine has its own independent variable scope identified by this name.
value string
~ 1048576 chars Value
The JSON-serialized variable values for this state machine. Supports int, float, string, bool, array, and map data types. Updated as the state machine processes transitions and actions.

EzChangeStateEvent

Change state event

Records a state transition that occurred within the state machine. Contains the destination task name, a hash for integrity verification, and the timestamp of the transition.

Type Condition Required Default Value Limits Description
taskName string
~ 128 chars Task name
The name of the destination task (state) that the state machine transitioned to.
hash string
~ 64 chars Hash
A hash value for verifying the integrity of the state transition. Used to validate that the transition was performed correctly and the state is consistent.
timestamp long
Timestamp

EzEmitEvent

Send a message event

Represents a message emitted by the state machine to trigger external actions. The event name identifies the type of action, and parameters provide the action-specific data.

Type Condition Required Default Value Limits Description
event string
~ 128 chars Event name
The name identifying the type of emitted event. Used to determine which external action to invoke, such as granting rewards or consuming resources.
parameters string
~ 1024 chars Parameters
The parameters passed with the emitted event. Contains action-specific data in a serialized format that is used to configure the external action triggered by this event.
timestamp long
Timestamp

EzEvent

Event

Represents an event that occurred during state machine execution. Can be either a state change event (recording a state transition) or an emit event (sending a message to trigger external actions).

Type Condition Required Default Value Limits Description
eventType string (enum)
enum {
  “change_state”,
  “emit”
}
Event type
The type of event. “change_state” records a state transition within the state machine. “emit” represents a message sent to trigger external actions such as granting rewards or consuming resources.
DefinitionDescription
“change_state”Change state
“emit”Send a message
changeStateEvent EzChangeStateEvent {eventType} == “change_state”
✓*
Change state
* Required if eventType is “change_state”
emitEvent EzEmitEvent {eventType} == “emit”
✓*
Send a message
* Required if eventType is “emit”

EzRandomStatus

Random number status

Manages the random number generation state for a state machine execution instance. Contains a seed value and per-category usage tracking. Used for speculative execution to ensure deterministic random behavior across client and server.

Type Condition Required Default Value Limits Description
seed long
0 ~ 4294967294 Random seed
The seed value for deterministic random number generation within the state machine execution.
used List<EzRandomUsed> 0 ~ 1000 items List of used random number
Tracks random numbers consumed per category. Each category represents a distinct purpose for random number usage, allowing independent tracking to maintain consistency across speculative re-executions.

EzRandomUsed

Used random number

Tracks the number of random values consumed for a specific category within a state machine execution. Each category allows independent random number tracking for different purposes.

Type Condition Required Default Value Limits Description
category long
0 ~ 4294967294 Category
A numeric identifier for the random number usage category. Each category tracks random consumption independently, allowing the state machine to use separate random sequences for different purposes.
used long
0 ~ 4294967294 Used count
The number of random values that have been consumed in this category. Incremented each time a random number is drawn from this category’s sequence.

EzVerifyActionResult

Verify Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
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",
}
Type of Verify Action
verifyRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
verifyResult string ~ 1048576 chars Result content

EzConsumeActionResult

Consume Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
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",
}
Type of Consume Action
consumeRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
consumeResult string ~ 1048576 chars Result content

EzAcquireActionResult

Acquire Action execution result

Type Condition Required Default Value Limits Description
action string (enum)
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",
}
Type of Acquire Action
acquireRequest string
~ 524288 chars JSON string of the request used when executing the action
statusCode int 0 ~ 999 Status code
acquireResult string ~ 1048576 chars Result content

EzTransactionResult

Transaction execution result

Result of a transaction executed using the server-side automatic execution feature

Type Condition Required Default Value Limits Description
transactionId string
36 ~ 36 chars Transaction ID
verifyResults List<EzVerifyActionResult> 0 ~ 10 items List of verify action execution results
consumeResults List<EzConsumeActionResult> [] 0 ~ 10 items List of Consume Action execution results
acquireResults List<EzAcquireActionResult> [] 0 ~ 100 items List of Acquire Action execution results

Methods

emit

Send an event to trigger a state transition

Sends a named event to the state machine, causing it to move from the current state to the next state based on the defined transition rules.

This is the main way the game client drives the state machine forward. For example:

  • Player taps “Accept” on a quest dialog → Emit “accept” event → State changes from “Offered” to “InProgress”
  • Player defeats the boss → Emit “boss_defeated” event → State changes from “BossStage” to “Complete”
  • Player makes a choice in a story → Emit “choose_path_a” event → State branches to the chosen path

You can pass additional data as JSON arguments (args). For example, when emitting a “submit_answer” event, you might include {“answer”: “B”} as the args.

The state machine will only accept events that are valid for the current state. If the event is not defined for the current state, an error is returned and no transition occurs.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
statusName string
~ 36 chars Status name
eventName string
~ 36 chars Event name
args string “{}” ~ 4096 chars Arguments to be passed to the state machine

Result

Type Description
item EzStatus Status of State Machine

Implementation Example

    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

Clean up a completed state machine

Deletes a state machine instance that has finished running. This can only be called when the state machine’s status is “Pass” (completed successfully) or “Error” (failed).

After a state machine reaches its terminal state, it remains in the system until you explicitly delete it with Exit. This gives you time to:

  • Show the player the completion result (e.g., “Quest Complete!” screen)
  • Read the final state and variables to determine rewards
  • Handle any error state and decide what to do next

Typical flow:

  1. State machine reaches terminal state → status becomes “Pass”
  2. Game reads the final state and grants rewards to the player
  3. Game shows a completion screen
  4. Player dismisses the screen → game calls Exit to clean up

You cannot call Exit on a Running state machine. If you need to forcefully stop a running state machine, that requires a server-side operation.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
statusName string
~ 36 chars Status name

Result

Type Description
item EzStatus Exited state machine

Implementation Example

    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

Get the current state of a specific state machine instance

Retrieves detailed information about a specific state machine instance, including which state it’s currently in and its stored variables.

Use this to display the current progress of a workflow to the player — for example:

  • A quest tracker showing “Current step: Defeat 3 monsters (2/3)”
  • A tutorial indicator showing which step the player is on
  • A process status showing whether it’s still running, completed, or encountered an error

The response includes:

  • Current state name: Which state the machine is in right now
  • Variables: Data stored in the state machine (e.g., progress counters, choices made)
  • Status: Whether the machine is Running, Pass (completed), or Error
  • Stack trace: The history of state transitions (useful for debugging)

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
statusName string
~ 36 chars Status name

Result

Type Description
item EzStatus State Machine Status

Implementation Example

    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;
    }
Value change event handling
    var domain = gs2.StateMachine.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        statusName: "status-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    var domain = gs2.StateMachine.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    ).Status(
        statusName: "status-0001"
    );
    
    // Start event handling
    var callbackId = domain.Subscribe(
        value => {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    domain.Unsubscribe(callbackId);
    const auto Domain = Gs2->StateMachine->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    )->Status(
        "status-0001" // statusName
    );
    
    // Start event handling
    const auto CallbackId = Domain->Subscribe(
        [](TSharedPtr<Gs2::StateMachine::Model::FStatus> value) {
            // Called when the value changes
            // The "value" is passed the value after the change.
        }
    );

    // Stop event handling
    Domain->Unsubscribe(CallbackId);

listStatuses

Get a list of the player’s state machine instances

Retrieves all state machine instances belonging to the current player. A state machine is a server-managed workflow that tracks a player’s progress through a series of steps (states). Each step can trigger actions, wait for player input, or branch based on conditions.

Common use cases for state machines:

  • Quest progression: “Accept Quest” → “In Progress” → “Boss Battle” → “Complete” → “Claim Reward”
  • Tutorial flows: “Welcome” → “Move Tutorial” → “Battle Tutorial” → “Gacha Tutorial” → “Done”
  • Timed events: Multi-phase event processes with time limits

Each state machine instance has one of three statuses:

  • Running: The state machine is active and waiting for the next event
  • Pass: The state machine has completed successfully (reached a terminal state)
  • Error: The state machine encountered an error

You can filter by status — for example, to show only active (Running) state machines on the quest screen, or to find completed ones that need cleanup.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
status Status
The current execution status of this state machine instance. “Running” means the machine is actively processing transitions. “Wait” means the machine is waiting for an external event (emit). “Pass” means it completed successfully. “Error” means it terminated with an error.
DefinitionDescription
“Running”Running
“Wait”Wait
“Pass”Pass
“Error”Error
pageToken string ~ 1024 chars Token specifying the position from which to start acquiring data
limit int 30 1 ~ 1000 Number of data acquired

Result

Type Description
items List<EzStatus> List of Status of State Machine
nextPageToken string Page token to retrieve the rest of the listing

Implementation Example

    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());
    }
Value change event handling
    var domain = gs2.StateMachine.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeStatuses(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeStatuses(callbackId);
    var domain = gs2.StateMachine.Namespace(
        namespaceName: "namespace-0001"
    ).Me(
        gameSession: GameSession
    );
    
    // Start event handling
    var callbackId = domain.SubscribeStatuses(
        () => {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    domain.UnsubscribeStatuses(callbackId);
    const auto Domain = Gs2->StateMachine->Namespace(
        "namespace-0001" // namespaceName
    )->Me(
        GameSession
    );
    
    // Start event handling
    const auto CallbackId = Domain->SubscribeStatuses(
        []() {
            // Called when an element of the list changes.
        }
    );

    // Stop event handling
    Domain->UnsubscribeStatuses(CallbackId);

report

Submit client-side state machine execution results for server validation

Sends a batch of events that were processed locally on the game client to the server for validation. This is an optimization feature called “speculative execution” — instead of calling Emit for every single event (which adds network latency each time), the client runs the state machine locally, processes multiple events at once, and then sends all the results to the server in a single call.

How speculative execution works:

  1. The client has a local copy of the state machine definition
  2. When events occur rapidly (e.g., during gameplay), the client processes them locally without waiting for server responses
  3. After a batch of events, the client calls Report to send all events to the server
  4. The server replays the events and verifies that the final state matches what the client reported
  5. If the states match, the server accepts the result. If they don’t match (e.g., client was tampered with), a StateMismatch error is returned

This is useful for performance-sensitive scenarios like:

  • Fast-paced gameplay where waiting for server responses would cause lag
  • Offline-capable flows where the player might lose connection temporarily
  • Batch processing of many rapid state transitions

Note: Speculative execution must be enabled on the namespace for this API to work.

Request

Type Condition Required Default Value Limits Description
namespaceName string
~ 128 chars Namespace name
Namespace-specific name. Specified using alphanumeric characters, hyphens (-), underscores (_), and periods (.).
gameSession GameSession
GameSession
statusName string
~ 36 chars Status name
events List<EzEvent> 0 ~ 1000 items List of events

Result

Type Description
item EzStatus Status of State Machine

Error

Special exceptions are defined in this API. GS2-SDK for GameEngine provides specialized exceptions derived from general exceptions to facilitate handling of errors that may need to be handled in games. Please refer to the documentation here for more information on common error types and handling methods.

Type Base Type Description
StateMismatchException BadRequestException State of the verification result of the report is inconsistent.

Implementation Example

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