# IGP.UnitySDK

这是 Unity 适配层的运行时代码根目录。

## 当前包形态

当前目录已经具备最小 Unity package 结构：

- 包名：`cn.indiegp.sdk.unity`
- `package.json`
- `Scripts/IGP.UnitySDK.asmdef`

如果项目要把 Mirror 的传输层接到 IGP，当前另有一个可选包：

- `../IGP.UnitySDK.MirrorTransport/package.json`
- 包名：`cn.indiegp.sdk.unity.mirror-transport`

如果项目要接防沉迷合规事件，当前另有一个可选包：

- `../IGP.UnitySDK.Compliance/package.json`
- 包名：`cn.indiegp.sdk.unity.compliance`

如果项目要接 Lying Bottle，当前另有一个可选包：

- `../IGP.UnitySDK.LyingBottle/package.json`
- 包名：`cn.indiegp.sdk.unity.lying-bottle`

当前已迁入的内容：

- `IGPSDK` 对外入口
- `IIGPRuntimeClient` 运行时抽象
- `Scripts/Runtime/*` 下的 Unity runtime 基底
- desktop session attach / retry / 按需拉起相关实现
- hosted bridge / session / realtime / room lifecycle 相关实现
- 同一房间内运行中换地图事件 `onMapChanged`
- KCP `p2p_data` 统一按可靠传输处理
- achievements 相关实现
- 防沉迷底层状态由 desktop session 提供；游戏侧通过 `IGP.UnitySDK.Compliance` 读取状态，通过 `CreateAntiAddictionRealNameWebSessionAsync()` 获取游戏内 IGP 登录与实名认证入口
- Lying Bottle 由可选包 `IGP.UnitySDK.LyingBottle` 通过 desktop session 转发
- `Tests/Runtime/*` 下的 Unity runtime tests
- `Editor/*` 下的 Inspector 和 Editor-side test runner
- `Documentation~/*` 下的包内专项文档
- vendored `KCP2K` 已做内部命名空间隔离，并在 `Documentation~/THIRD-PARTY-NOTICES.md` 保留许可证说明

当前尚未完成：

- 发布脚本与完整 demo 工程
- achievements / multiplayer contract 抽离
- desktop session / hosted session 的引擎无关合同收口

## 最小接入路径

当前建议先按“最小接入”验证主链路：

1. 如果你是第一次接这套联调流程，先在 Curio desktop 里打开 `设置 -> 关于`，把 `SDK 联调 Beta` 设为开启。
2. 再看 [Documentation~/START-HERE.md](Documentation~/START-HERE.md)。
3. 再看 [Documentation~/EDITOR-DEBUG.md](Documentation~/EDITOR-DEBUG.md)。
4. 然后看 [Documentation~/QUICKSTART.md](Documentation~/QUICKSTART.md)。
5. 如果项目之前接的是 `Arena.UnitySDK`，先看 [Documentation~/START-HERE.md](Documentation~/START-HERE.md)，里面已经把最短接入和迁移入口收进去了。
6. 在干净 Unity 工程里导入正式 `.unitypackage`，或在本地开发时通过 `manifest.json` 加入源码包。
7. 在场景里挂一个 `IGPRuntimeManager`。
   SDK 会自动挂载项目里的 `IGPConfig`；如果项目里还没有配置资源，会自动创建 `Assets/IGP/IGPConfig.asset`。
   如果切场景后还要保留已建立的房间连接，这个对象必须做成跨场景常驻，并且全程只保留一个实例；对象一旦随场景被销毁，连接也会一起断开。
8. 在游戏自己的启动流程里主动调用 `IGPRuntimeManager.InitializeAsync()`。
9. 如果你只想最快看到接入结果，优先导入 `Samples~/StarterDemo`；如果你想自己先写一份最小脚本，也可以按 `QUICKSTART.md` 里的 `IGPQuickstartDriver` 走。
10. 启动时先验证 desktop session attach，再通过 Curio desktop 注入 launch ticket 参数。
11. 先验证：
   - desktop session attach
   - achievements
   - 房间加入
   - 运行中换地图事件
   - ready
   - realtime message
   - state
   - RPC

当前授权验证已经并入 SDK 主线入口。

## 安装方式

本地开发时可以作为源码包接入：

1. 打开 Unity Package Manager
2. 选择 `Add package from disk...`
3. 选择：

```text
adapters/unity/Runtime/IGP.UnitySDK/package.json
```

如果走正式发布包安装，当前发布文件名是：

- `cn.indiegp.sdk.unity-<version>.unitypackage`

如果项目已经在用 Mirror，再额外加一个可选包：

```text
adapters/unity/Runtime/IGP.UnitySDK.MirrorTransport/package.json
```

正式发布包对应：

- `cn.indiegp.sdk.unity.mirror-transport-<version>.unitypackage`

如果项目需要防沉迷合规事件，再额外加一个可选包：

```text
adapters/unity/Runtime/IGP.UnitySDK.Compliance/package.json
```

正式发布包对应：

- `cn.indiegp.sdk.unity.compliance-<version>.unitypackage`

如果项目需要 Lying Bottle，再额外加一个可选包：

```text
adapters/unity/Runtime/IGP.UnitySDK.LyingBottle/package.json
```

正式发布包对应：

- `cn.indiegp.sdk.unity.lying-bottle-<version>.unitypackage`

设计目标：

- 游戏侧看到的是 `IGPSDK`
- 运行时能力依赖 `IIGPRuntimeClient`
- `IGPRuntimeManager` 作为正式 Unity runtime 组件
- 不保留 `Arena` 兼容入口作为正式路径

接入约束：

- `IGPRuntimeManager` 不会自动启动 SDK。游戏需要在启动流程里调用 `InitializeAsync()`
- 如果游戏会切场景，但联机连接要继续保留，`IGPRuntimeManager` 所在对象必须使用 `DontDestroyOnLoad`
- 新场景里不要再放第二个 `IGPRuntimeManager`
- 只要这个对象被销毁，当前 room / realtime / KCP 连接就会断开

当前兼容目标：

- `desktop session` 已落地，游戏项目应以“直接升级 SDK”为主路径
- 不要求重写现有业务层成就调用代码
- 常规接入时，`IGPConfig` 会自动挂到 `IGPRuntimeManager` 上；开发者只需要配置 `appId`，并在启动流程里主动调用 `InitializeAsync()`
- 其余配置默认作为隐藏调试项保留

## Unity Editor 调试

当前对开发者最重要的规则：

- 平时接入配置 `appId`，并在游戏启动流程里主动调用 `InitializeAsync()`
- 如果要用桌面端的联调入口，先在 `设置 -> 关于` 打开 `SDK 联调 Beta`

Unity Editor 里直接调 desktop 能力时，不需要填写 `Desktop Executable Path Debug Override`。

不填这个路径时，SDK 会按环境启动桌面端，并把 Unity Editor 当前进程路径和 `appId` 一起交给桌面端；是否允许联调由桌面端的 SDK 联调规则判断。只有需要模拟正式安装路径或排查本地 exe 绑定时，才需要填这个路径；此时应填写这款游戏真正的 Windows 可执行文件路径，不要填桌面端路径。

注意它不是桌面端路径。SDK 需要主动拉起桌面端时，会按 `SDK Environment` 自动找对应客户端：

- `PROD` 找 IndieGamesPass
- `DEV` 找 IndieSpark

正式环境只会启动官方可信的 IndieGamesPass；开发环境才允许用 `Desktop Launch Command` 或 `INDIEGP_DESKTOP_PATH` 明确指定本机调试用桌面端。

这样可以在 Editor 里安全调试：

- desktop session attach
- unlock achievement
- report achievement progress

如果你要调完整 hosted 链路，比如：

- launch ticket
- hosted bootstrap
- 自动进房
- room lifecycle
- realtime / state / RPC / KCP（统一可靠）

仍然建议走桌面端启动的真流程；如果你的项目本来就在用 Mirror，再直接跑 `MirrorTransportDemo`。

如果你一定要在 Editor 里走这条完整链路，现在可以直接用 `IGPRuntimeManager` Inspector 里的 `Unity Editor 联调`：

1. 在 desktop 里复制 `Unity 启动包`
2. 选中 `IGPRuntimeManager`
3. 把整包 JSON 贴进 `Launch Package JSON`
4. 点击 `Apply Launch Package`
5. 进入 Play
6. 点击 `Connect Current Test Room`

这套入口对 host 和 guest 是同一套，不需要额外再配一份 guest 专用开关。

- 调 host 时填 host 那份启动信息
- 调 guest 时填 guest 那份启动信息

这样可以把完整 hosted 流程直接拉起来，用来调：

- 自动进房
- room lifecycle
- realtime / state / RPC / KCP（统一可靠）

如果还要一起调 desktop 能力，比如成就，一般也不需要额外填写 `Desktop Executable Path Debug Override`。只有要模拟正式安装路径，或排查本地 exe 绑定问题时，才填写这款游戏真正的 Windows 可执行文件路径。

## Sample

先跑通 `Documentation~/QUICKSTART.md`，再导入 package sample。

当前 package 内已提供一个最小 sample：

- `Samples~/StarterDemo/IGPUnityStarterDemo.cs`
- `Samples~/StarterDemo/README.md`

当前 package 内也保留一个 quickstart 风格 sample：

- `Samples~/HostedQuickstart/IGPHostedQuickstart.cs`
- `Samples~/HostedQuickstart/README.md`

当前 package 内也提供房间生命周期 sample：

- `Samples~/RoomLifecycle/IGPRoomLifecycleSample.cs`
- `Samples~/RoomLifecycle/README.md`

当前 package 内也提供 realtime messaging sample：

- `Samples~/RealtimeMessaging/IGPRealtimeMessagingSample.cs`
- `Samples~/RealtimeMessaging/README.md`

当前 package 内也提供 achievements sample：

- `Samples~/Achievements/IGPAchievementsSample.cs`
- `Samples~/Achievements/README.md`

当前 package 内也提供一个面向 UI / 手动联调的综合 sample：

- `Samples~/HostedPlayground/IGPHostedPlaygroundController.cs`
- `Samples~/HostedPlayground/IGPKcpConnectionExample.cs`
- `Samples~/HostedPlayground/README.md`
