# BD2.GameSdk
本插件不会提供任何封装的游戏 API,任何功能的 patch 等操作需要自行处理。
给 Brown Dust II 插件作者使用的 C# 开发包。通过标准 NuGet `PackageReference` 导入,自动完成 **生成可读引用程序集和全量源码导航 → 编译插件 → reobf → 验证运行 DLL**。源码可以使用可读类型和成员,字符串反射由配套的 `BD2.GameNames` 处理。转到定义可查看完整反编译方法体。
## 本发布包
| NuGet 包 | 内容 | 使用方式 |
| --- | --- | --- |
| `BD2.GameSdk` | .NET 8 构建工具、`build/*.props/targets`、压缩名字表 | 插件项目直接引用,`PrivateAssets="all"` |
| `BD2.GameNames` | `lib/netstandard2.0/BD2.GameNames.dll`、XML API 文档、同一份内嵌表 | SDK 固定依赖对应版本,自动引入;DLL 随插件部署 |
升级游戏后更新此包并重新构建插件;相同游戏版本下的不同官方 DLL 也会因指纹不同而被拒绝。
包不包含游戏 DLL 或可读壳。用官方映射生成名字表,提交为 `plugins/GameNames/Mappings/names.json.gz`,SDK 和运行时从同一文件嵌入,插件作者只需要对应游戏客户端和 BepInEx。
包当前由维护者提供 `.nupkg` 或 NuGet 源,**尚未发布到 nuget.org**。包内包含仓库 LICENSE,许可条款沿用项目现有授权,不声明为开源许可。
## 导入到自己的插件项目
前提:安装 **.NET 8 SDK**,准备与包对应版本的游戏目录,并在该目录安装 BepInEx。推荐 SDK-style `.csproj` 与 `netstandard2.1`;运行时库本身兼容 `.NET Standard 2.0`。旧式 `packages.config` 不受支持。
将维护者提供的两个 `.nupkg` 放在一个目录,例如 `D:\NuGet\BD2`,添加为本地 NuGet 源:
```powershell
dotnet nuget add source 'D:\NuGet\BD2' --name BD2
dotnet add MyPlugin.csproj package BD2.GameSdk --version 0.2.2-game.2.35.10
```
Visual Studio / Rider 也可在 NuGet 包管理界面添加该源。
简单的一个项目文件:
```xml
netstandard2.1
latest
MyPlugin
2.35.10
```
`PrivateAssets="all"` 让构建步骤只用于当前插件项目。SDK 自动引入 `BD2.GameNames`,以及游戏目录中的 `BepInEx`、`0Harmony`、`UnityEngine`、`UnityEngine.CoreModule` 引用,无需手写 ``。**不要再引用真实的 `Assembly-CSharp.dll`**,游戏 API 编译引用由 SDK 提供。
在项目旁创建仅保存在本机的 `Directory.Build.props`,并加入自己的 `.gitignore`:
```xml
E:\Games\BrownDustII
```
或者构建时传入目录:
```powershell
dotnet build MyPlugin.csproj -c Release '-p:GameDir=E:\Games\BrownDustII'
```
IDE 项目加载时构建会准备可读引用,CLI 首次构建同样会自动生成。完整示例在 [samples/ExamplePlugin](samples/ExamplePlugin)。
## 完整源码导航
导入包、设置 `GameDir` 后,先完成一次构建。SDK 会使用 ILSpy 从匹配版本的真实游戏 DLL 生成**全部类型的可读 C# 源码**,保留方法体、私有成员、嵌套类型和编译器生成实现;同步生成 Portable PDB,将源码内嵌到 PDB。
在支持外部源码导航的 IDE 中,对 `NetworkManager.Send` 等可读 API 使用“转到定义”(例如 Visual Studio 的 F12),即可打开完整方法体。重载、泛型、参数、属性、字段、事件和嵌套类型使用真实元数据及 PDB 定位。
首次全量生成会花费数分钟,且体积稍微有些许庞大。本机 2.35.10 的一次验证生成了 **24,856 个源码文件、654,265 个声明、319,350 个带方法体的符号**。生成结果按名字表、生成器及其依赖、全部游戏 Managed DLL 的指纹缓存,同一台机器上的插件项目共用。
所有依赖 SDK 的插件必须在自己的 `.csproj` 明确声明目标**游戏版本**:
```xml
2.35.10
```
构建核对声明值、SDK 内嵌表、真实游戏 DLL 指纹。缺少声明或版本不匹配会报错;不会自动选用其他版本。NuGet 项目仍需安装带对应游戏版本的包。
仓库默认缓存根为 `.build/game-sdk`,与源码位于同一盘。第三方 NuGet 项目默认使用 `%LOCALAPPDATA%\BD2\GameSdk\navigation`;可在本机 `Directory.Build.props` 设置 `BD2GameSdkCache`,或设置环境变量 `BD2_GAME_SDK_CACHE`。 `obj` 不影响共享缓存。缺失的共享源码可在下次准备时从 PDB 恢复,只有删除共享缓存才会触发重新生成。
`lib` 中的程序集仅供开发导航,**不要部署或执行**。这里展示的是当前 DLL 的反编译源码,局部变量名和语法可能与原始工程不同。导航 PDB 对应可读程序集,不能用于真实混淆游戏 DLL 的逐行调试。
公开方法调用、字段和属性访问可以直接使用可读名字,获得 IDE 补全和编译检查。需要通过反射或 Harmony 定位成员时,已知游戏类型优先使用 `typeof(GameType)`,避免用字符串查找类型,可访问的成员可以使用 `nameof` 提供经过编译检查的名字,或者通过强类型表达式取得 `MethodInfo`,让编译器检查所选重载及参数类型。表达式只用于取得方法信息,不执行方法。私有成员保留原访问性,通过已知类型和映射反射 API 查询,例如:
```csharp
using System.Reflection;
var intro = typeof(IntroUI);
var enter = intro.GetGameMethod("Enter",
BindingFlags.Instance | BindingFlags.NonPublic,
null, Type.EmptyTypes, null);
var field = typeof(IntroUI).GetGameField("_maintenanceTimeoutCts",
BindingFlags.Instance | BindingFlags.NonPublic);
// nameof 的结果仍是可读字符串,必须传给 GetGameMethod 等运行时 API。
var maintenance = typeof(IntroUI).GetGameMethod(nameof(IntroUI.SendMaintenanceInfo),
BindingFlags.Instance | BindingFlags.Public, null, new[] { typeof(bool) }, null);
// 对实际协程可读名调用 MemberName,再交给 Unity 的字符串 API。
owner.StartCoroutine(Game.MemberName(owner.GetType(), "ReadableCoroutineName"));
```
`GetGameMethod/GetGameField/GetGameProperty/GetGameEvent` 采用 .NET 反射约定:查不到返回 null,重载歧义抛出 `AmbiguousMatchException`,null 名字参数抛出 `ArgumentNullException`。`MemberName` 的成员种类使用 `GameMemberKind` 枚举。未知映射保留字面名,普通 UI 文案、`nameof` 字符串和协程常量都不会被 reobf 自动替换。
`Game.FindType` 保留给运行时才知道类型名称的查询。只做字符串反射的项目可单独安装 `BD2.GameNames`,启动时用 `Game.ValidateGame(...)`。这种方式没有可读游戏类型引用,也没有编译指纹,使用 SDK 的项目必须用 `Game.Validate(typeof(MyPlugin).Assembly, ...)`。
## 构建与部署
构建成功后,将你的插件产物和相邻的 **`BD2.GameNames.dll`** 安装到游戏 `BepInEx/plugins`。当然,客户端只需要安装一个`BD2.GameNames.dll`,`GameSdk.dll`只是编写时需要。
| MSBuild 属性 | 用途 |
| --- | --- |
| `BD2GameVersion` | 每个插件 csproj 必填的目标游戏版本,例如 `2.35.10`;不从 SDK 包版本或仓库版本自动推断 |
| `GameDir` | 游戏根目录,本机安装路径(另须在插件 csproj 声明 BD2GameVersion) |
| `BD2ManagedDir` | 自定义 Managed 路径,默认 `GameDir/BrownDust II_Data/Managed` |
| `BD2BepInExDir` | 自定义 BepInEx 路径,默认 `GameDir/BepInEx` |
| `BD2GameSdkCache` | 共享导航缓存目录,可在 `Directory.Build.props` 配置;默认取 `BD2_GAME_SDK_CACHE` 环境变量或用户缓存目录 |
| `BD2AddBepInExReferences=false` | 使用其他宿主或自己提供 BepInEx/Harmony 引用时关闭自动引用 |
| `BD2AddUnityReferences=false` | 自己提供 Unity 引用时关闭自动引用 |
| `BD2GameSdkEnabled=false` | 暂时关闭壳生成与 reobf;只适用于不依赖可读游戏 API 的项目 |