# GameMaker Windows API Shape

## 目标

把 GameMaker Studio 2 Windows 首期对外接法先固定下来。

这一版只覆盖：

- 授权验证
- 防沉迷状态
- 成就能力

不覆盖：

- room
- realtime
- 对战相关能力

## 设计原则

### 1. 入口数量要少

首期不追求做很多脚本入口。

目标是让开发商只需要记住少量几个入口，就能跑通：

- 初始化
- 刷新运行时
- 查询授权状态
- 主动请求授权
- 查询和刷新防沉迷状态
- 解锁成就
- 上报进度
- 读取最近结果

### 2. 不照搬 Unity 的 `onXXXX`

GameMaker 不适合走一长排 `onXXXX` 的组件事件模式。

首期建议：

- 少量直接调用入口
- 一条稳定的结果队列或事件队列

### 3. 对外数据尽量结构化

即使首期不做统一事件订阅，也要保证返回结果能稳定带出：

- 类型
- 状态
- 错误码
- 消息
- 关键业务字段

## 第一版公开入口

首期建议固定下面这组脚本入口。

### 初始化

`igp_init(app_id, options)`

用途：

- 初始化 GMS2 侧 IGP runtime
- 启动 desktop session attach
- 建立后续授权和成就能力的上下文

最小要求：

- `app_id` 必填
- `options` 可选

`options` 第一版建议只允许：

- `desktop_auto_attach`
- `desktop_pipe_endpoint`
- `desktop_launch_command`

其中：

- `desktop_pipe_endpoint` 留空时使用内置桌面端连接入口
- `desktop_launch_command` 留空时应按 Unity 当前口径自动发现 desktop 启动命令
- 只有在特殊调试或非标准发行形态下，才建议显式覆盖这两个字段

### 帧更新

`igp_update()`

用途：

- 推进本地 runtime 状态
- 拉取 desktop session 结果
- 把新事件压入队列

说明：

- 首期建议让游戏在 Step 或等价时机主动调用
- 不要求接入方理解内部线程或桥接细节

### 查询是否已初始化

`igp_is_initialized()`

返回：

- `true` / `false`

### 查询当前连接状态

`igp_get_connection_state()`

返回：

- `disconnected`
- `connecting`
- `connected`
- `failed`

### 查询最近一次错误

`igp_get_last_error()`

返回：

- 最近一次错误对象
- 或空值

### 查询最近一次结果

`igp_get_last_result()`

返回：

- 最近一次成就结果对象
- 或空值

### 查询状态快照

`igp_get_state_snapshot()`

返回：

- 当前初始化状态
- 当前连接状态
- 当前 desktop 通道状态
- 当前 attach 校验状态
- 当前授权状态
- 当前是否要求授权
- 待处理事件数
- 最近一次错误
- 最近一次结果
- 最近一次事件

### 查询是否还有待处理事件

`igp_has_pending_events()`

返回：

- `true` / `false`

### 关闭运行时

`igp_shutdown()`

用途：

- 清空本地状态
- 收尾事件队列
- 标记当前运行时退出

### 查询当前授权状态

`igp_get_authorization_state()`

返回：

- `pending`
- `authorized_online`
- `authorized_offline`
- `failed`
- `skipped`

### 查询是否要求授权

`igp_is_authorization_required()`

返回：

- `true` / `false`

### 查询 desktop capabilities

`igp_get_desktop_capabilities()`

返回：

- capabilities 对象
- 或空值，表示当前不可用

最小字段：

- `achievements`
- `userContext`
- `hostedBootstrap`
- `gameAuthorization`
- `antiAddiction`

说明：

- 这个入口直接对齐当前 desktop session bridge 里的 capability 查询能力
- 主要用于让游戏侧判断当前 desktop session 暴露了哪些能力

### 主动请求授权

`igp_request_game_authorization(app_id_override)`

说明：

- `app_id_override` 首期允许为空或缺省
- 当前先直接返回 desktop 的授权请求结果，不额外发明新的 GameMaker 事件类型

返回：

- 授权请求结果对象
- 或空值，表示当前请求失败

最小字段：

- `authorizationRequired`
- `offlineMode`
- `pipeName`

说明：

- 这个入口先对齐当前 bridge 已有的 `RequestGameAuthorization` 能力
- 当前返回的是 desktop 授权请求结果本身，不是最终授权完成态
- 最终授权状态仍以 `igp_get_authorization_state()` 和现有状态事件口径为准

### 查询当前防沉迷状态

`igp_get_current_anti_addiction_status()`

返回：

- 当前本地防沉迷状态对象

最小字段：

- `enabled`
- `canPlayNow`
- `state`
- `reasonCode`
- `reasonMessage`
- `isMinor`
- `ageBand`
- `evaluatedAt`
- `playableUntil`
- `nextPlayableAt`
- `nextStatusChangeAt`

说明：

- 这个入口只读本地最后一次状态，不会主动请求服务端
- attach 成功后如果 desktop 返回了初始状态，这里会直接读到

### 主动刷新防沉迷状态

`igp_refresh_anti_addiction_status(app_id_override)`

说明：

- `app_id_override` 允许为空或缺省
- 会通过 desktop session 拉取当前游戏的最新防沉迷状态

返回：

- 最新防沉迷状态对象
- 或空值，表示当前请求失败

事件：

- 刷新成功后会进入 `anti_addiction_state_changed` 事件队列
- 游戏收到事件后自行处理弹窗、存档、回主菜单或退出

### 解锁成就

`igp_unlock_achievement(achievement_key, event_id, occurred_at_unix_ms, app_id_override)`

说明：

- `achievement_key` 必填
- 其余参数首期都允许为空或缺省

结果：

- 调用本身只表示请求是否已发起
- 实际业务结果从事件队列读取

### 上报成就进度

`igp_report_achievement_progress(achievement_key, progress_value, progress_source_key, event_id, occurred_at_unix_ms, app_id_override)`

说明：

- `achievement_key` 必填
- `progress_value` 必填
- 其余参数首期都允许为空或缺省

结果：

- 调用本身只表示请求是否已发起
- 实际业务结果从事件队列读取

### 清除全部成就

`igp_clear_achievements(app_id_override)`

说明：

- `app_id_override` 允许为空或缺省
- 清除范围是当前游戏下当前 desktop 登录用户的全部成就

结果：

- 调用本身只表示请求是否已发起
- 实际业务结果从事件队列读取，事件类型为 `achievement_clear_result`

## 第一版结果读取方式

首期建议固定成一条事件队列：

- `igp_poll_event()`

这个入口每次调用返回：

- 一条事件对象
- 或空值，表示当前没有新事件

这样做的原因：

- 比做一排 `onXXXX` 更容易收口
- 比让游戏侧自己管理大量回调更适合首期
- 后面如果事件变多，也不需要重做整套公开接口

## 第一版事件类型

首期只允许下面几类事件进入 GameMaker 队列：

- `connection_state_changed`
- `authorization_state_changed`
- `anti_addiction_state_changed`
- `achievement_result`
- `error_reported`
- `detached`

其中：

- `authorization_state_changed` 对应 core 的 `AuthorizationStateChanged`
- `anti_addiction_state_changed` 对应 core 的 `AntiAddictionStateChanged`
- `achievement_result` 对应 core 的 `AchievementResult`
- `error_reported` 对应 core 的 `ErrorReported`
- `detached` 对应 core 的 `Detached`

## 第一版事件结构

每条事件至少包含：

- `type`
- `timestamp`

### `connection_state_changed`

最小字段：

- `type = "connection_state_changed"`
- `state`
- `connected`
- `desktop_channel_state`
- `desktop_attach_state`
- `source`
- `reason`

说明：

- `state` 用来直接对应 `igp_get_connection_state()`
- 首期推荐值包括 `disconnected`、`connecting`、`connected`、`failed`

### `authorization_state_changed`

最小字段：

- `type = "authorization_state_changed"`
- `state`
- `required`
- `message`

### `achievement_result`

最小字段：

- `type = "achievement_result"`
- `success`
- `duplicated`
- `message`
- `achievement_key`
- `operation`

### `anti_addiction_state_changed`

最小字段：

- `type = "anti_addiction_state_changed"`
- `state`
- `reason`
- `message`
- `anti_addiction_status`

说明：

- `anti_addiction_status.canPlayNow` 是当前是否可玩
- `anti_addiction_status.nextStatusChangeAt` 是下一次状态变化时间

### `error_reported`

最小字段：

- `type = "error_reported"`
- `code`
- `category`
- `message`
- `retryable`
- `source`

### `detached`

最小字段：

- `type = "detached"`
- `reason`
- `source`

## 第一版错误口径

GameMaker 首期必须直接复用当前统一错误码。

常见首批错误至少包括：

- `APP_ID_REQUIRED`
- `DESKTOP_SESSION_REQUIRED`
- `DESKTOP_USER_CONTEXT_REQUIRED`
- `DESKTOP_SESSION_CAPABILITY_MISSING`
- `EXECUTABLE_PATH_REQUIRED`
- `EXECUTABLE_PATH_NOT_ALLOWED`
- `INVALID_INPUT`
- `INTERNAL_ERROR`

不要把底层异常文本直接当对外结果。

## 第一版接入建议

推荐游戏侧最小接法：

1. 启动时调用 `igp_init(...)`
2. 每帧或固定时机调用 `igp_update()`
3. 用 `igp_poll_event()` 取走新结果
4. 需要显示状态时，再调用 `igp_get_authorization_state()`

这样做的好处是：

- 游戏代码简单
- 对授权和成就都适用
- 后面扩能力时不用推翻首期接法

## 当前不做的事情

首期明确不提供：

- room 相关脚本
- realtime 消息脚本
- 对战房间事件
- KCP 或数据面能力

如果后续有人要加这些入口，必须先回到：

- `../../../core/contracts/runtime-events.md`
- `../../../docs/architecture/runtime-events-development-flow.md`

## 下一步

在这份接口形态固定后，下一步实现顺序应是：

1. 补最小示例工程
2. 收口授权主动验证入口
3. 补对外说明和检查清单
