# Unity Core C# 事件参考

本文档列出 `cn.indiegp.sdk.unity` 0.3.4 的全部公开 C# 事件。事件是代码订阅的
`System.Action`，不会出现在 Inspector 中。自 0.3.0 起不保留旧 `on*` 事件的转发层。

所有事件都遵循以下规则：

- Runtime 先更新公开状态属性，再调用事件。
- 新订阅者不会收到历史事件；需要初始值时同时读取 Runtime 属性。
- 相同状态不会重复通知。
- 回调发生在线程模型原本所在的位置；除 `GracefulShutdownRequested` 明确在下一次 Unity
  `Update` 切到主线程外，SDK 不新增主线程切换。
- SDK 使用普通 `?.Invoke`，不会隔离接入方回调抛出的异常。

## 订阅示例

```csharp
using IGP.UnitySDK;
using UnityEngine;

public sealed class CoreEvents : MonoBehaviour
{
    [SerializeField] private IGPRuntimeManager runtime = null!;

    private void OnEnable()
    {
        runtime.ConnectionChanged += OnConnectionChanged;
        runtime.ErrorOccurred += OnError;
    }

    private void OnDisable()
    {
        runtime.ConnectionChanged -= OnConnectionChanged;
        runtime.ErrorOccurred -= OnError;
    }

    private static void OnConnectionChanged(IGPConnectionChangedEvent change)
    {
        Debug.Log($"Desktop connected={change.IsConnected}, reason={change.Reason}");
    }

    private static void OnError(IGPSDKException error)
    {
        Debug.LogError($"{error.ErrorCode}: {error.Message}");
    }
}
```

## `ConnectionChanged`

```csharp
event Action<IGPConnectionChangedEvent> ConnectionChanged;
```

含义：Core 选择的 Desktop 或 Mobile Host Session 连接可用性发生变化。

精确触发时机：

- Host attach 完成、Runtime 已写入 session、capability 和用户上下文后，触发
  `IsConnected = true`。
- 已连接的 Host Session 主动分离、通道断开或 Runtime 主动关闭连接后，触发
  `IsConnected = false`。
- Desktop 断线自愈重新 attach 成功时再次触发 `true`；Mobile 由 Flutter
  生命周期重新建立并显式 attach。

参数：

- `IsConnected`：当前 Host Session 是否已 attach。
- `Source`：Desktop 为 `desktop_session`，Mobile 为 `mobile_host_session`。
- `Reason`：attach、detach、断线或恢复原因。

真实来源：Desktop/Mobile Host Session attach/detach 生命周期。事件不表示 Hosted/KCP/UDP 状态；这些由
Multiplayer 包报告。

去重：连续写入相同 `IsConnected` 不触发。订阅时不重放。

## `AuthorizationChanged`

```csharp
event Action<IGPAuthorizationChangedEvent> AuthorizationChanged;
```

含义：游戏授权状态、是否必须授权或当前失败提示发生变化。

精确触发时机：Runtime 完成相应授权处理并更新 `AuthorizationState`、
`IsAuthorizationRequired` 和 `LastAuthorizationFailure` 后触发。状态包括 `Pending`、
`AuthorizedOnline`、`AuthorizedOffline`、`Failed` 和 `Skipped`。

参数：

- `State`：处理后的 `IGPAuthorizationState`。
- `IsRequired`：当前游戏是否必须通过授权才能继续。
- `Message`：失败时的用户可读信息；无失败时为空字符串。

真实来源：Desktop Session 授权结果、在线授权 broker、离线许可证和 Runtime 授权生命周期。

去重：`State`、`IsRequired` 和 `Message` 三者均相同时不触发。订阅时不重放。

## `AntiAddictionChanged`

```csharp
event Action<IGPAntiAddictionStatus> AntiAddictionChanged;
```

含义：Runtime 当前防沉迷判断实际发生变化。

精确触发时机：

- `RefreshAntiAddictionStatusAsync` 收到 Desktop 查询结果并更新
  `CurrentAntiAddictionStatus` 后。
- `SubmitAntiAddictionRealNameAsync` 上传成功后会主动调用上述刷新路径；刷新结果与旧状态不同时触发。
- Desktop 主动推送新的防沉迷状态，Runtime 更新状态后。

参数可读取 `enabled`、`canPlayNow`、`state`、`reasonCode`、`reasonMessage`、年龄段和各时间字段。

真实来源：Desktop Session 防沉迷查询或 notification。

去重：全部公开状态字段相同则不触发。订阅时不重放。

## `GracefulShutdownRequested`

```csharp
event Action GracefulShutdownRequested;
```

含义：Desktop 请求当前游戏执行优雅退出。

精确触发时机：Desktop Session 收到成功的保留命令结果，且 `requestId` 为
`desktop-graceful-shutdown`、`code` 为 `GRACEFUL_SHUTDOWN_REQUESTED` 后，Runtime
先将请求加入线程安全队列，再在下一次 Unity `Update` 中触发事件。

真实来源：Desktop Session 主动 notification。每个通过协议校验的请求交付一次；订阅时不重放。

## `OfflineMapLaunchRequested`

```csharp
event Action<IGPDesktopOfflineMapLaunchRequestedEvent> OfflineMapLaunchRequested;
```

含义：Desktop 请求当前游戏离线启动一个已准备好的创意工坊地图。

精确触发时机：Desktop 发出 `offline_map_launch_requested`，Runtime 确认 payload 非空，且其中
`appId` 与当前 attached appId 一致后触发。校验失败不会触发。

参数包含 `appId`、`mapPublicId`、`versionId`、`mapPath`、`title` 和 `version`。

真实来源：Desktop Session 主动 notification。订阅时不重放；每个通过校验的请求交付一次。

## `ErrorOccurred`

```csharp
event Action<IGPSDKException> ErrorOccurred;
```

含义：Core 初始化、Desktop Session、授权或协议处理失败。

精确触发时机：Runtime 已记录错误状态并安排既有恢复策略后触发；授权失败也只通过这个结构化
错误入口报告，不再同时触发单独的“授权失败”事件。

参数：

- `Message`：错误说明。
- `ErrorCode`：稳定错误码（可用时）。
- `Category`：`validation`、`authorization`、`channel` 或 `runtime`（可用时）。
- `DesktopChannelState`、`DesktopAttachState`：历史命名；Host Session 错误发生时的状态快照（可用时）。

真实来源：Core Runtime 捕获的异常、Desktop/Mobile Host Session error frame、共享协议/通道异常和授权失败。

去重：同一 Host Session error frame 只转换一次；不同失败不会按字符串全局去重。订阅时不重放。
