Skip to content

Development Guide

DNT_OF edited this page Aug 26, 2026 · 3 revisions

开发者指南(Development Guide)

面向在 SLDataAPI 代码库上开发新功能的开发者。项目为 LabAPI 原生插件(C# / .NET Framework 4.8),当前版本 v2.5.4,开发代号 GIS,GNSS,RS!

💡 开发辅助:本项目同时提供 sl-dataapi-dev 开发 skill(SKILL.md + references/),内容与本页同源,随 SLDataAPI-DevKit-v2.5.4.zip 发布包分发。

项目结构(命名空间映射)

目录 命名空间 内容
Plugin.cs SLDataAPI 入口:Enable/Disable、LabAPI 事件订阅、服务编排
Config.cs SLDataAPI 配置类(snake_case,LabAPI 自动加载)
Log.cs SLDataAPI 日志门面:Log.Info/Warn/Error/Debug
Data/ SLDataAPI.Data DTO:Models.cs(数据快照)、ControlModels.cs(控制请求体)
Control/ SLDataAPI.Control ControlController(路由+业务)、WsControlService(WS 长连接)、ControlAuth(鉴权)
Services/ SLDataAPI.Services HttpServerDataCollectorMainThreadExecutorFileServiceReportService
Voice/ SLDataAPI.Voice VoiceService(语音转发 SPY)、VoiceRecorder(录音取证)
Map/ SLDataAPI.Map 地图布局采集与导出
Integrations/ SLDataAPI.Integrations EXILED 互操作反射桥 + 第三方插件探测
Capture/ SLDataAPI.Capture Harmony 补丁:控制台输出捕获

核心约定

事件链保护(强制)

LabAPI 事件分发是裸调用——handler 里的任何异常都会传播回游戏主流程(回合初始化中断、玩家状态错乱)。所有 LabAPI 事件 handler 必须整体 try/catch,异常 Log.Error 后吞掉。范例:Plugin.OnRoundStarted

主线程派发(强制)

所有触碰游戏 / Mirror 网络状态的操作必须经 MainThreadExecutor 派发到主线程:

var (status, json) = MainThreadExecutor.RunOnMainThread(() =>
{
    // 游戏 API 只能在这里调用
    return (200, Json(true, "ok", data));
}, out var err);
if (err != null)
    return (400, Json(false, err.Message));

超时(默认 5s)后置取消标志,迟到的 action 跳过执行——防止"报超时但实际执行"导致的重试双重执行。纯文件/序列化操作不需要派发。

不向客户端回显异常细节

错误响应不得包含服务器路径等敏感信息;细节只进服务器日志。ControlController.Handle 顶层兜底统一 500 "内部错误"。

配置键名 snake_case

LabAPI 用 UnderscoredNamingConvention:C# 属性 ReportMaxRecords → 配置键 report_max_records。错误键名被静默忽略;任何一个值结构错误会导致整个文件回退默认值(启动日志会打 YamlDotNet 精确错误含行号)。

版本 / 代号注释规范

  • 版本号:Plugin.csVersion 属性
  • 每个功能区块注释标注推出/更新历史(含 preview 与 patch 版本): // ===== 功能名(vX.Y.Z 推出,代号 XXX;vX.Y.Z-Patch 加固,代号 YYY)=====
  • 历史代号:SPY(v2.3)、Yagami Light(v2.5.0/2.5.1)、Bay of Pigs Invasion(v2.5.2/2.5.3)、Apollo 11's Tapes(v2.5.3)、FI-STM(v2.5.3-Patch)、ENIGMA(v2.5.4-preview)、GIS,GNSS,RS!(v2.5.4)

添加新控制端点(完整流程)

  1. Data/ControlModels.cs 加请求类(snake_case 属性,范例 ReportRequest
  2. ControlController.Handle 的 switch 注册:"/control/xxx" => XxxAction(body),
  3. 端点方法 private static (int, string) XxxAction(string body)Parse<T> 反序列化 → 校验必填(400 明确 message)→ 游戏操作主线程派发 → (200, Json(true, "ok", data))
  4. 鉴权由 ControlAuth 统一处理,端点内不用管 token;WS call 的 path 与 HTTP 完全一致,自动兼容
  5. README「控制接口」端点表 + 本 wiki HTTP-API.md 同步
  6. 端点区块注释标注推出版本/代号

完整范例:/control/reportsReportsAction)。

SSS 游戏内 UI

模式见 Services/ReportService.cs(举报功能),命名空间 UserSettings.ServerSpecific

  • 控件:SSGroupHeader(label) / SSDropdownSetting(id, label, options, defaultIndex) / SSPlaintextSetting(id, label, placeholder, characterLimit) / SSButton(id, label, text, holdTimeSeconds)(长按按钮)
  • 下发:ServerSpecificSettingsSync.DefinedSettings = ...; SendToAll();
  • 交互:ServerOnSettingValueReceived += (hub, setting)(主线程),按 setting.SettingId 分流
  • 读值:GetSettingOfUser<T>(hub, id);热更新:dropdown.SendDropdownUpdate(...) / button.SendButtonUpdate(...)
  • 坑:DefinedSettings 全局单例(其他插件设置会覆盖);事件回调的 setting 实例与定义实例不保证同一引用(勿用引用比较过滤);SSS 面板开着时 HUD hint 被菜单挡住(面板内反馈用按钮文本)

详细 API 签名见项目 skill 的 references/sss-api.md

构建与部署

dotnet build -c Release
# 产物:bin/Release/net48/SLDataAPI.dll
  • 编译期引用本机游戏程序集:SCPSL_DIR(游戏 Managed 目录)/ LABAPI_DIR,其他机器用 -p: 覆盖
  • key.snk 存在时自动强名称签名(公钥令牌 3ec73bb20070fa9c);key.snk 不入库
  • 部署:LabAPI/plugins/global/,重启服务器生效;配置:LabAPI/configs/<端口>/SLDataAPI/config.yml

本地测试

# 控制端点
curl -s -X POST "http://127.0.0.1:8081/control/reports" \
  -H "X-Control-Token: <control_token>" -H "Content-Type: application/json" \
  -d '{"action":"list"}'
# 数据接口
curl -s "http://127.0.0.1:8081/get_sl_data?token=<verify_token>"

WS 控制:ws://127.0.0.1:8081/control?key=<control_token>control_transport: ws 模式);语音 WS:端口 8082。

Clone this wiki locally