# 多人状态机

每个游戏必须显式实现四个相互独立的状态机。不要用一个 `connected` 布尔值表达整个联机生命周期。

## 连接

```text
idle → connecting → connected → closing → closed
             └────→ recovering → connecting
connecting/connected/recovering → failed
```

socket open 只表示传输可用。进入业务 `active` 前还必须完成鉴权、订阅 ACK 和快照同步。每次连接拥有递增 generation，旧 generation 的回调不得修改当前状态。

## 业务

```text
idle → joining → synchronizing → active
active → recovering → synchronizing → active
active → finishing → finished
joining/synchronizing/recovering → failed
```

具体玩法可以增加 `queued`、`matched`、`countdown` 或 `roundResult`，但必须列出事件、guard、超时和清理副作用。

## 命令

```text
created → sent → accepted → applied
              ├→ retryable
              ├→ unknown
              └→ rejected
```

ACK 必须标记确认层级。超时后的写操作通常是 `unknown`，重试复用原 `requestId`。服务端保存有限期幂等收据，不能因响应丢失重复计分。

## 版本与输入

- 服务端快照包含 `stateVersion`。
- 持久变更使用事务、CAS 或 `expectedVersion`。
- 每位玩家的连续输入使用递增 `sequence`。
- 过期帧直接丢弃；恢复时请求完整快照。
- 普通实时帧不等待 ACK，不暂停权威模拟。

SDK 内部还为 P2P peer、SFU session、媒体采集和网络探针维护独立生命周期。游戏通过公开状态和错误编排 UI，不复刻这些底层状态机。
