C# NativeAOT 插件迁移
迁移起始记录:2026-10-23(0.5.0-dev);旧代码清理与ABI复验:2026-10-24(0.5.13-dev)。
插件业务实现已从 native/XFEEDPlugin 迁到 native/ManagedPlugin,使用 .NET 10 NativeAOT 输出 Windows x64 DLL。保留原 DLL 名称、C ABI 导出和命名管道协议;此次迁移包含插件内部实现。
源码与产物
| 原实现 | 当前 C# 实现 |
|---|---|
plugin.cpp、Diagnostics.h |
PluginLoader.cs:System32 DirectInput 转发、插件状态、显式观测启动、停用及有限日志 |
Interaction.cpp |
InteractionRuntime.cs:游戏线程采样、历史帧、收放输入、期限与回执 |
Navigation.cpp |
Navigation.State/Observation/Fsd/Protocol/Lifecycle.cs:身份、健康、控制租约、玩家接管、FSD、热量、目标及航路 |
LocalFlight.inl |
Navigation.LocalFlight.cs:星系内目标、观测、输入、原生动作及驾驶权交还 |
CommerceRead/CommerceTrade/StationServices.inl |
对应 C# 文件:市场、库存、交易防重、维护、补给与服务回执 |
GalaxyCatalog/SkyboxCapture.inl |
对应 C# 文件:星系查询、区域分页、银河概览及 D3D11 天空盒读取 |
SessionMenu.inl |
Navigation.SessionMenu.cs:原菜单观测、动作与会话租约 |
| 几何、运动、吸油、热量归一化与原自测 | 对应 C# 文件及 Navigation.SelfTests.cs |
2026-10-25 起,客户端以项目引用依赖 Bundle/Bundle.csproj,后者引用 Loader、Interaction、SessionRecovery、CruiseControl 四个生产模块;它们共同引用 Platform/Platform.csproj。平台项目按源码与头文件增量生成配置独立的静态库,NativeAOT 在项目构建内自动生成原生 DLL。Standalone 保留为独立诊断项目。
Bundle/NativeSupport.targets 在中间目录生成与当次 DLL 匹配的版本和 SHA-256 清单,将四个模块及清单作为八项资源嵌入 XFEEDToolBox.NativeSupport.dll。客户端不再复制 XFEEDToolBox/PluginPackage 中的预制文件。直接构建或发布客户端即可完成整个依赖图,无需提前运行插件打包脚本。
运行时 NativeSupportPackage 把内嵌文件校验并释放到 %LOCALAPPDATA%/XFEstudio/XFEEDToolBox/native-support/<内容哈希>;不同版本各用独立目录,缺失或损坏缓存会从当前内嵌资源恢复。游戏插件安装、按需模块加载继续使用原有清单和哈希校验。
2026-10-24已删除 native/XFEEDPlugin 下的旧 C++ 业务实现、配套内联文件、版本头和旧探针。历史实现可从 Git 查看;当前源码不保留两套驱动。原27个导出冻结在 native/ManagedPlugin/abi-exports.json,验收直接以此清单检查实际AOT DLL,不再读取旧C++源码。
必要的原生边界
Platform/Boundary.cpp、Platform/Invoke.asm 及既有第三方 MinHook 仅负责内存访问、Windows x64 调用、SEH、指令重定位、寄存器保留与展开信息,不包含游戏偏移或业务规则。该边界静态链接入 AOT DLL,无需额外部署运行时 DLL。
迁移验收发现:位于 AOT 模块中的直接内存访问违例不能依靠原 __try 继续执行。安全复制因此使用 ReadProcessMemory 的系统边界;游戏函数及动态原子指令通过带 SEH 的调用桥执行。测试覆盖不可访问页读、写、原子操作,以及故障后的再次成功调用。
NativeAOT DLL 保留到宿主进程结束,停用只停止功能和撤销租约,继续使用原管理器的退出后清理流程,不执行 FreeLibrary。参见 Microsoft 的 NativeAOT 库生命周期限制。
兼容约束
- 原有 27 个 C ABI 导出全部保留,独立验收模块另有商业和接口协议自测。
- 保留 Plugin 的 3 种文本命令、Navigation 的 42 种 JSON 操作及 Interaction 的 3 种操作,schema 仍为 1。
- 保留同一用户 SID、本机限定、消息模式、一次连接一次请求、原读取上限与回复排空。
- 保留 64 位地址字符串、Unicode、字段及错误文本;非有限遥测数值按原 JSON 实现输出
null。 - 保留游戏 EXE SHA-256、前导指令检查、所属线程、实体/组件/坐标系/sequence 校验、200/300 ms 期限、owner、generation、取消和重复订单处理。
- 保留原先关闭的能力。
supportsTrade=false;重进能力仍取决于实际菜单接口就绪状态;未接通的本地超巡、空管和降落能力不会因迁移自动启用。 DirectInput8Create先执行系统接口,再启动伴随服务;伴随功能失败保持原 HRESULT、输出和 last error。
构建与复验
需要 .NET 10 SDK、Windows SDK 和 Visual Studio x64 工具链;C++ 工具链仍用于必要边界与 NativeAOT 链接。
pwsh -File scripts/Build-Plugin.ps1
pwsh -File scripts/Test-ManagedPlugin.ps1
pwsh -File scripts/Build.ps1
pwsh -File scripts/Test.ps1
Test-ManagedPlugin.ps1 -SkipBuild 复用已有插件,重新生成隔离边界验证 DLL。验收程序只加载自己的 DLL、分配自己的内存,不连接或注入真实游戏,不卸载 AOT DLL。
以下为0.5.0迁移时的历史验收;后续游戏实测见 CG跑商实测。0.5.13删除旧源码后的隔离构建、656次原生自测及原27项ABI导出复验通过。
| 迁移时检查 | 结果与证据 |
|---|---|
| 完整 Release 解决方案 | 0 警告、0 错误;artifacts/managed-solution-build.log |
| 客户端回归 | 552 通过、0 失败、6 个显式集成测试默认跳过;artifacts/tests-csharp-interfaces-final/test-results.json |
| 真实 AOT 导出、原 ABI、x64 原生 PE、不匹配构建拒绝 | 通过;artifacts/managed-plugin-validation.json |
| 原 21 组自测及商业、接口协议自测 | 23 组 × 8 次 = 184 次通过 |
| 内存、整数/浮点/混合参数、12 参数栈、故障恢复及交互 Hook 透明性 | 2 组 × 8 次 = 16 次通过;同一份验证报告 |
| System32 DirectInput 对照 | 成功与无效版本的 HRESULT、输出存在性及 last error 均一致 |
| 插件管道与停用 | 20 次状态查询,以及显式观测拒绝、停用、停用后查询通过;artifacts/managed-plugin-handshake/result.json |
0.5.0迁移当时尚未重验实际飞行、跃迁、贸易和重进全流程,也未安装替换游戏插件;这项历史状态不代表后续版本的实机验收结果。离线结果不能替代对应功能的实际客户端验收。