> For the complete documentation index, see [llms.txt](/llms.txt)


# StateMachine Speculative Execution Session API (Unity)

APIs for calling operations, reading state, and receiving server verification from the generated C# classes



**This Session is a class for using GS2-StateMachine speculative execution from Unity.** It runs the user's progress on the client and sends the operation history to StateMachine's Report API for verification. The game screen operates through Session methods and reads the local execution results from the View.

It is not used for Realtime room connections or syncing with other players. For the mechanism that reflects shared objects in Unity, see [Unity Object Sync]().

This page describes the caller-side APIs. For the game rules format, see the [C# Definition Reference](); for the generation steps, see the [Tutorial](). The Session is generated when [`hostProfile`](#project) in the generation settings is `LocalReplayV1` (the default).

`CounterSession` is generated from the rules class `Counter`. Below, its instance is written as `game`. The state, result, and input types are generated in the `namespace` from the generation settings.

| Purpose | API |
| --- | --- |
| Operate the game | [Methods with the same names as the definition's operations](#operations) |
| Display the current state | [View / ViewChanged](#view) |
| Open a game already started on the server | [OpenAsync / OpenFuture](#open) |
| Connect to a runtime such as the preview | [FromExecutor](#executor) |
| Verify the operation history on the server | [ConfirmAsync / ConfirmFuture](#confirmation) |

## Operation Methods {#operations}

Methods with the same names as the public operations in the definition are generated. The runtime passes the state, random number, and reward arguments, so they are not included in the Session-side parameters.

```csharp
// Definition side: public static Step Add(CounterState state, int amount)
var outcome = game.Add(3);
```

The return value is `InputResult<TCode>`. `TCode` is the enum of Ignore reasons specified in the definition.

| Property | Type | Description |
| --- | --- | --- |
| `Accepted` | `bool` | Whether local execution adopted the input |
| `Ignored` | `bool` | Whether the input was rolled back by Ignore |
| `Code` | `TCode?` | The Ignore reason. null if there is no reason or the code is unknown |
| `RawCode` | `int?` | The original numeric value of the Ignore reason. null if there is no reason |

Accepted does not mean server-verified. Verification happens separately with [Confirm](#confirmation).

```csharp
var outcome = game.Add(0);
if (outcome.Ignored)
    Debug.Log("Input was not accepted: " + outcome.Code);
```

Calling an operation that is not currently accepted throws an exception. Runtime errors such as division by zero are also different from Ignore and are not returned as a normal operation result.

## View / ViewChanged {#view}

`game.View` is a snapshot of the current state. The properties of the generated state and result classes are read-only. To change the state, call operation methods.

```csharp
var count = game.View.State.Count;
var canAdd = game.View.Actions.Add;
```

| Member | Description |
| --- | --- |
| `View.State` | The current state. Its type is the generated class corresponding to the definition's TState |
| `View.Result` | The finish result. Its type is the generated class corresponding to the definition's TResult. null while there is no result |
| `View.Actions.<operation name>` | A bool indicating whether that operation is accepted at the current wait point |
| `View.Revision` | The revision of the operation history |
| `View.Status` | The execution status `ActiveStateMachineStatus` |
| `ViewChanged` | An `Action<SessionView>` notification fired when the View is updated |

`View.Actions` indicates "whether you are at a point that accepts that operation". It does not evaluate game-specific conditions checked inside the operation, such as insufficient materials.

After creating the Session, you can subscribe to update notifications as follows. ViewChanged does not fire on Ignore.

```csharp
game.ViewChanged += view => Debug.Log("Count: " + view.State.Count);
```

### Values of View.Status

| Value | Meaning |
| --- | --- |
| `Initialized` | Before execution starts |
| `Running` | Processing is running |
| `Wait` | Waiting for the next operation |
| `Pass` | Finished normally. The definition's End has been reached |
| `Error` | Stopped due to a runtime error |

You can determine normal completion of the game with `View.Status == ActiveStateMachineStatus.Pass`. This is the local execution status and does not indicate that server verification is complete.

## OpenAsync / OpenFuture {#open}

Opens a status already started on the server and creates a Session. You must first start the target user's state machine with StateMachine's [start API](#startstatemachinebyuserid) or similar.

```csharp
var game = await CounterSession.OpenAsync(
    gs2, gameSession, namespaceName, statusName);
```

| Parameter | Description |
| --- | --- |
| `gs2` | The SDK entry point `Gs2Domain` |
| `gameSession` | The logged-in user's information `IGameSession` |
| `namespaceName` | The GS2-StateMachine namespace name |
| `statusName` | The name of the started status |

The Async form returns `UniTask<CounterSession>` and requires `GS2_ENABLE_UNITASK`. If you don't use UniTask, use OpenFuture with the same arguments. Its return value is `Gs2Future<CounterSession>`.

On connection, the GSL hash is checked. If the Session and the registered definition do not match, it is an error. When you update the definition, regenerate the Session as well, and use the Session corresponding to the old definition for games in progress under the old definition.

## FromExecutor {#executor}

Connects a Session to an existing Executor. The Executor is LocalStateMachineKit's execution class that handles GSL execution and the operation history.

```csharp
var game = CounterSession.FromExecutor(executor);
```

The argument is a `LocalStateMachineExecutor`, and the return value is a `CounterSession`. This API also checks the definition hash.

For example, passing an Executor created with `LocalStateMachineExecutor.CreatePreview(gsl, "Counter")` connects to a preview without login. For a concrete creation example, see the [Tutorial](). The preview has no history to send to the server and cannot be handed over to the live service midway.

## ConfirmAsync / ConfirmFuture {#confirmation}

Sends the operation history so far to the server and waits for the verification result. You can call it during the game or after it finishes.

```csharp
await game.ConfirmAsync(gs2, gameSession);
```

The arguments are the same `Gs2Domain` and `IGameSession` as Open. The Async form returns `UniTask` and requires `GS2_ENABLE_UNITASK`. If you don't use UniTask, use ConfirmFuture. Its return value is `Gs2Future`.

Check local input acceptance, server verification, and reward application in the following ways.

| Stage | How to check | What you can confirm |
| --- | --- | --- |
| Local execution | `Accepted` in the operation result | The input was adopted locally |
| Server verification | Confirm completes successfully | The sent operation history was accepted by the server |
| Reward application | Get the state of the granting service | Asynchronous reward processing has been reflected in inventory, etc. |

A successful Confirm alone does not mean reward application is complete.

### Checking the Send State

| Property | Description |
| --- | --- |
| `PendingEventCount` | The number of pending events |
| `IsConfirming` | Whether sending and confirmation are in progress. New input is not accepted during this time |
| `RequiresReconciliation` | Whether the Session must be recreated from the latest server state |

### After Confirm Completes or Fails

| Result | How the history is handled | What to do next |
| --- | --- | --- |
| Completed successfully | The sent pending history is removed as confirmed | If the game is waiting for input, you can continue operating |
| Failed, `RequiresReconciliation` is false | The unconfirmed history is kept | Resolve the cause and run Confirm again on the same Session |
| Failed, `RequiresReconciliation` is true | Resending and new input from the same Session are not accepted | Reopen the latest server state with Open and restore the screen |

The SDK keeps the history and duplication-avoidance keys for resending. You don't need to call the operations again to reproduce them. If the resend deadline passes, RequiresReconciliation becomes true on the next Confirm, and you need to reopen.

If both IsConfirming and RequiresReconciliation are false after a failure, you can continue the currently accepted operations locally. The added history is also sent by a later Confirm. However, don't treat unconfirmed results as finalized on the server.

Pending history is kept in memory. A reopened Session does not carry over local operations not yet verified by the server. Saving across app restarts requires a separate design.

Use the Session and Executor from Unity's main thread.



