Skip to content

HTTP API

DNT_OF edited this page Oct 18, 2026 · 15 revisions

HTTP / 控制 API

现行接口文档,适用于 main 上的当前稳定版(最新 Release)。

内测端点(默认关闭)见 Beta-Features。节日版本相关字段与节日专属功能的概览见 Holiday-Features。

下文示例用 http://;tls_mode 为 optional 时同一端口也可用 https:// / wss://,为 required 时必须用 https:// / wss://(明文返回 426),见下文「TLS」。

旧版接口(control_token + 旧扁平路径)见 Old-HTTP-API。


鉴权(双轨)

通道 凭据 配置
GET /get_sl_data、GET /plugins/adapted 等数据口 verify_token config.yml
/control/*、控制 WS、语音 :8082 API Key apikey.config(与 config.yml 同目录)

数据口(verify_token)

推荐请求头:

Authorization: Bearer <verify_token>
X-SLDataAPI-Token: <verify_token>
X-SLDataAPI-Verify-Token: <verify_token>

?token= 仍兼容但已弃用(会入访问日志),后续版本将移除。

出厂 / 弱 verify_token(空、默认 your_secret_token、或不满足强度:长度 ≥8 且同时含大写/小写/数字/特殊符号)→ fail-closed:数据口拒绝;若控制面也未启用则不绑定 HTTP 端口。详见 Security-Model。

控制 / 语音(API Key)

Authorization: Bearer <api_key>
X-SLDataAPI-Key: <api_key>

不再接受: control_token、X-Control-Token、控制面 ?key= / ?token= → 401。
config.yml 里若仍写 control_token,启动仅警告后忽略,不作为鉴权。

HTTP 含义
401 Key 缺失 / 错误 / 锁定
403 Key 有效但被拒绝(ACL、远程执行 sldataapi、无权限路径等)
404 control_enabled: false、传输模式互斥、未知路径、内测开关未开
405 非 POST
413 body > 64KB
426 tls_mode: required 下的明文请求(data.code = "tls_required"),见下文「TLS」
501 已知占位(dummies);或当前游戏版本缺少功能所需类型(feature_unavailable)

响应体统一:{ "success", "message", "data" }。

Key 生命周期

sldataapi apikey create <id> <duty|admin> [note]
sldataapi apikey list
sldataapi apikey revoke <id>
  • 仅服务器本地控制台可执行;经 /control/console/command 或控制 WS 一律拒绝。
  • 落盘只存 SHA-256 指纹;明文写入一次性文件(约 5 分钟自动删),命令输出只回路径。
  • 审计 control_log 的 actor 为 Key 的 id。
  • 模板 duty / admin 影响默认 ACL(duty 默认不可全量读审计 body)。模板在 create 时确定,duty Key 前缀 sld_duty_、admin 为 sld_live_;要换角色请新建 Key 再吊销旧的,详见 Configuration、Q&A。

TLS(同端口自签)

tls_mode 数据口 / 控制 / 语音
off 仅明文
optional(默认) 明文与 TLS 同端口并存
required 仅 TLS;明文 → 426
sldataapi cert show     # 显示模式、SHA-256 指纹、有效期、文件路径(别名 info)
sldataapi cert regen    # 重新生成证书(别名 regenerate / rotate),客户端须重新固定指纹

cert 命令(别名 tls)仅本地控制台可执行。证书为自签,客户端请固定指纹而不是关闭证书校验。完整说明与 426 响应体见 Security-Model「传输(TLS)」。


只读数据

curl -s "http://<host>:8081/get_sl_data" \
  -H "Authorization: Bearer YOUR_VERIFY_TOKEN"

# 兼容(已弃用)
curl -s "http://<host>:8081/get_sl_data?token=YOUR_VERIFY_TOKEN"

快照字段说明可参考 Old-HTTP-API 中「只读数据」一节(字段大体连续;现行版另含 adapted_plugins 等扩展)。

适配插件发现

其他 LabAPI 插件可经 PluginEndpointRegistry 登记自身能力(插件侧用法见 Development-Guide · 适配插件集成)。两个只读入口,鉴权同数据口(verify_token),仅 GET(其他方法 405):

GET /plugins/adapted——全量列表(与 get_sl_data.adapted_plugins 同结构):

{"success":true,"adapted_plugins":[
  {"id":"dntof.sample_adapted","name":"Adapted Plugin Sample","version":"1.1.0",
   "capabilities":["sample.hello"],"routes":["hello"],
   "status":{"ok":true,"message":"sample online","bumps":0}}
]}
字段 说明
id 插件 id(^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$,建议反向域名)
name / version 展示名 / 版本
capabilities 能力标签(≤32)
routes 只读子路径名(≤16)
actions 仅 beta_adapted_plugin_actions: true 时出现:写 / 动作名,见 Beta-Features
status 插件状态回调返回的 JSON(≤4KB;超限为 {"error":"status_too_large"},回调异常为 {"error":"status_failed"},无回调为 null)

列表取自主线程快照(随 push_interval_seconds 刷新),status 可能略有滞后。内置条目 dntof.sl_player、dntof.omega_warhead 为 SLDataAPI 自带的探测包装。

GET /plugins/<plugin_id>/<route>——调用插件登记的只读子路径:

项 说明
路径 恰好两段;route 形如 ^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$;含 .. → 400
执行 主线程,超时 3s(超时 → 504)
响应 插件返回的 JSON 原样返回;返回 null → {};非 JSON 文本 → {"ok":true,"data":"<文本>"};>64KB → 413
错误 未注册 → 404 plugin not registered;无此路由 → 404 route not found;处理器异常 → 500
curl -s "http://<host>:8081/plugins/dntof.sample_adapted/hello" \
  -H "Authorization: Bearer YOUR_VERIFY_TOKEN"

控制端点(POST + JSON)

control_transport: ws 时 HTTP /control/* → 404 + transport_mismatch。

curl -s -X POST "http://<host>:8081/control/map/layout" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'

路径一览

分组 路径 备注
Player /control/player/data · role · effects · inventory · candy inventory / candy 见下文
Moderation /control/moderation/kick · ban · mute · msg · ban_list · ban/add · ban/revoke
Admin /control/admin/teleport · state
Broadcast /control/broadcast · /control/staffchat 已实现;admin 默认开,duty 默认关
Round /control/round · round/warhead · round/wave
Map /control/map/facility · layout · export · seed · status status 只读
Other /control/cassie · /control/dummies dummies → 501
扩展 /control/console/command · plugins · plugins/slplayer · files/* · logs · reports · audit/list console / plugins / files 默认不授予(含 admin)
内测 /control/adapted/<plugin_id>/<action> · files/stat · files/read_chunk · files/write_chunk 默认关闭 + 默认拒绝,见 Beta-Features

默认 ACL 要点

admin 模板(及 all_control_true)按端点目录展开,但目录里以下条目为 false,admin 也不会自动获得:

键 覆盖
/control/console/ console/command(等同本机控制台)
/control/plugins、/control/plugins/ 插件列表 / 启停、plugins/slplayer
/control/files/ 全部文件端点
/control/adapted/ 适配插件动作(内测)

需要时对单把 Key 用 endpoints_override 显式放开(写法见 Beta-Features「权限(ACL)」一节 与 Configuration)。ACL 为最长前缀匹配:以 / 结尾的键同时覆盖不带斜杠的同名路径,因此放开插件管理时请把 /control/plugins 与 /control/plugins/ 一起设为 true(只设前者会被后者的 false 盖住)。

插件管理 /control/plugins

body 作用 ACL 读写
{} 列表 读
{"action":"stage","name":"<插件名>","enabled":true} 暂存启停(不写文件;不能禁用 SLDataAPI 自身) 写
{"action":"clear"} 清空暂存 写
{"action":"apply"} 写入全部暂存:LabAPI 插件写各自的 LabAPI/configs/<端口>/<插件名>/properties.yml,重启服务器后生效;EXILED 插件立即重载 写
{"action":"reload"} 热重载其他插件的配置文件(不含 SLDataAPI 自身,不重载 DLL、不应用启停) 写

带任何非空 action(包括 "list")都按写计入 ACL 与审计;只想列表请发空对象 {}。

列表响应 data:

{"count":2,"plugins":[
  {"name":"SLDataAPI","author":"DNT_OF","version":"<插件版本>","prefix":"","priority":"Medium",
   "enabled":true,"self":true,"staged":null,"source":"labapi"}
]}

enabled 读自配置文件(LabAPI properties.yml / EXILED is_enabled),不是运行时状态;staged 为暂存的目标值(无则 null);source 为 labapi 或 exiled。

文件 /control/files/list|read|write

需配置 file_root(为空 → 404)。路径相对 file_root,防线见 Security-Model「文件端点」一节。

端点 body data
files/list {"path":""}(空 = 根) {"path","count","entries":[{"name","type":"dir|file","size","modified","protected"}]}
files/read {"path":"a.yml"} {"path","size","modified","content"}(文件 ≤1MB)
files/write {"path":"a.yml","content":"..."} {"path","bytes"}(内容 ≤512K 字符;HTTP 请求体另受 64KB 限制)

大文件请用 分块端点(Beta-Features)。

全服广播

curl -s -X POST "http://<host>:8081/control/broadcast" \
  -H "Authorization: Bearer YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"服务器维护通知","duration_seconds":10,"clear_previous":true}'
字段 说明
message 必填,≤500
duration_seconds 可选,默认 5,上限 60
clear_previous 可选 bool

管理聊天(RA AdminChat)

curl -s -X POST "http://<host>:8081/control/staffchat" \
  -H "Authorization: Bearer YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"message":"值班备注","is_silent":false}'
字段 说明
message 必填,≤500
is_silent 可选 bool

自旧版(control_token)升级:路径对照

旧版 现行
/control/command /control/console/command
/control/player/kick 等 /control/moderation/...
/control/player/teleport /control/admin/teleport
/control/player/effect /control/player/effects
/control/player/state /control/admin/state
/control/map(混用) map/facility(写)+ layout / export / seed(读)
/control/warhead / wave /control/round/warhead / wave
/control/ban_* /control/moderation/ban_*
/control/slplayer /control/plugins/slplayer

无兼容别名;旧 path → 404 或 403。


物品栏、糖果、设施状态与节日门控

统一错误码(data.code)

这些端点的业务失败仍用统一信封 { "success": false, "message", "data" },data.code 为机器可读码:

HTTP data.code 含义
400 invalid_item / invalid_candy / invalid_color / invalid_flicker / amount_exceeds_limit / ammo_not_supported 参数非法(invalid_candy 附 valid 列表,amount_exceeds_limit 附 max)
409 holiday_inactive 节日功能未开启(见下文「节日门控」)
409 inventory_full / add_failed / candy_bag_full 物品栏 / 糖果袋已满,或游戏拒绝添加
501 feature_unavailable 当前游戏版本没有该功能所需的类型 / 成员

节日门控

节日专属功能(节日物品、节日效果、节日糖果)在运行时判定是否可用:以游戏自身的可用性(IHolidayItem / IHolidayEffect.IsAvailable、当前糖果池)和当前节日(GameCore.Version.ActiveHoliday)为准。游戏下次开启同一节日时无需改插件即自动可用;节日结束后调用不会报 500,而是:

HTTP 409
{"success":false,"message":"节日功能未开启:candy:Evil 需要 Halloween,当前节日 None",
 "data":{"code":"holiday_inactive","feature":"candy:Evil","active_holiday":"None","required":["Halloween"]}}
字段 说明
feature item:<ItemType> / effect:<效果类名> / candy:<CandyKindID>
active_holiday 当前节日(None / Christmas / Halloween / AprilFools)
required 任一满足即可的节日列表
simulated 仅测试钩子开启时出现,值为 true

未来游戏版本删除或改名相关类型时,插件按名称反射查找失败 → 501 feature_unavailable(fail-closed),不会加载失败。

测试辅助:服务器进程环境变量 SLDATAAPI_HOLIDAY_OVERRIDE=None(或 Christmas / Halloween / AprilFools)让门控按该节日模拟判定,只收紧不放宽(游戏本身不可用的功能不会因此变为可用),不改游戏;启动时告警,勿用于生产服。

/control/player/inventory

body 作用 ACL 读写
{"target":"2"} 或 "action":"list" 物品与弹药 读
{"target":"2","action":"add","item":"Lantern","amount":2} 发放物品,amount 默认 1、上限 8 写
{"target":"2","action":"remove","item":"Medkit","amount":3} 移除同类物品,上限 8 写
{"target":"2","action":"clear","clear_ammo":false} 清空物品(clear_ammo: true 同时清弹药) 写

item 为 ItemType 枚举名(大小写不敏感);弹药类型(Ammo*)→ 400 ammo_not_supported。add 遇物品栏满时停止,返回实际发放数;一个都没发出 → 409 inventory_full。节日物品(如 MarshmallowItem、圣诞的 Coal / Snowball)未开启 → 409 holiday_inactive;Lantern 不受节日限制。

{"success":true,"message":"已发放 2/2 个 Lantern","data":{"requested":2,
 "added":[{"type":"Lantern","serial":498},{"type":"Lantern","serial":499}],
 "inventory":{"nickname":"Dum1","player_id":2,"count":3,"capacity":8,
   "items":[{"type":"SCP330","serial":497},{"type":"Lantern","serial":498},{"type":"Lantern","serial":499}],"ammo":{}}}}

/control/player/candy

curl -s -X POST "http://<host>:8081/control/player/candy" \
  -H "Authorization: Bearer YOUR_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target":"2","candy":"Evil","amount":1}'
字段 说明
candy CandyKindID 名(Rainbow / Yellow / Purple / Red / Green / Blue / Pink / Black;万圣节另有 Orange / White / Gray / Brown / Evil);空或 "random" = 从当前糖果池随机
amount 默认 1,上限 6(糖果袋容量);袋满时停止,返回实际数量
{"success":true,"message":"已发放 1/1 颗糖果","data":{"requested":1,"given":["Evil"],"bag":["Evil"],
 "candy_pool":"haunted","active_holiday":"Halloween"}}

糖果池随游戏节日切换:万圣节为 13 种闹鬼糖果(candy_pool: haunted),否则 8 种普通糖果(normal)。节日专属糖果在节日外 → 409 holiday_inactive(data.available_candies 列出当前可用糖果)。注意游戏本身的副作用:万圣节版本中部分糖果(如 Gray、Orange)会造成友伤。

棉花糖人(MarshmallowEffect)

经现有 /control/player/effects 开启,不另设端点:

{"target":"2","effect":"MarshmallowEffect","effect_duration":30,"effect_intensity":1}

游戏行为:开启时玩家丢出全部物品并获得 MarshmallowItem;effect_intensity: 0 关闭。万圣节 / 圣诞节以外 → 409 holiday_inactive;关闭效果永远允许。

/control/map/status(只读)

body {}。各段读取失败(如大厅阶段尚未生成地图)时为 null。

{"success":true,"message":"ok","data":{
 "round":{"started":true,"ended":false,"duration_seconds":33,"locked":false,"lobby_locked":false,"players":1,
   "total_deaths":0,"killed_by_scps":0,"escaped_class_d":0,"escaped_scientists":0,"surviving_scps":0,"changed_into_zombies":0},
 "decontamination":{"status":"None","is_decontaminating":false,"server_time":33.2},
 "generators":{"total":3,"engaged":0,"list":[{"room":"HczWarhead","engaged":false,"activating":false,"remaining_time":125,"is_open":false,"is_unlocked":false}]},
 "warhead":{"exists":true,"lever":false,"locked":false,"authorized":false,"in_progress":false,"detonated":false,"time_until_detonation":null},
 "scp914":{"knob":"Rough","is_upgrading":false},
 "holiday":{"active_holiday":"Halloween","game_version":"<游戏版本>","candy_pool":"haunted","candy_kinds":["Green","…"],"test_override":null}}}

decontamination.status:None(正常倒计时)/ Disabled / Forced。

/control/map/facility 灯光参数

字段 说明
color #RGB / #RRGGBB / #RRGGBBAA;"reset" 清除覆盖色;非法 → 400 invalid_color
flicker_seconds 闪烁(短暂熄灯)秒数,钳制到 0.1-300;与 lights_off: true 同给时以 lights_off 为准
scope "all" = 全部房间(忽略 room_type)
{"action":"lights","scope":"all","color":"#FF6A00"}

只给 room_type 而不给 color / flicker_seconds / lights_off 时与旧行为一致(立即恢复照明)。

/control/player/data 扩展字段

max_health、artificial_health / max_artificial_health、hume_shield / max_hume_shield、stamina(0-1)、items([{type,serial}])、ammo({类型:数量})、group(徽章文本)、godmode、noclip、bypass、overwatch、spectating({nickname,userid,player_id} 或 null)、zone、is_speaking、is_muted、is_intercom_muted、voice_channel、is_dummy。逐项容错,读取失败为 null;不含 IP。target 先按 UserId 精确匹配,未命中再按 PlayerId → UserId(忽略大小写)→ 昵称解析,不按 IP 匹配(其他玩家端点仍支持 IP)。

这些端点的 ACL

键 admin duty
/control/player/inventory 默认开(读写) 默认拒绝
/control/player/candy 默认开 默认拒绝
/control/map/status 开(/control/map/) 可读(/control/map/)

旧版生成的 apikey.config(没有 endpoint_catalog_version 行)在 endpoint_catalog 中写有 /control/player/inventory: false(当时是 501 占位)。加载时会自动按 true 处理并打一行 info 日志;文件不改写,只迁移这一项,模板与 endpoints_override 不动。新生成 / 保存的文件带 endpoint_catalog_version: 2,此后显式写 false 会被尊重;也可以用 endpoints_override 对单把 Key 关闭。inventory 的 list(或不带 action)按读计入 ACL,不写审计;其余写操作写入 control_log。


语音口(8082)

鉴权同控制面(Bearer / X-SLDataAPI-Key)。不要在 URL 带 key。tls_mode 同样作用于语音口(wss://<host>:8082/ws)。

路径 说明
GET /ws(升级 WS) 语音流
GET /status 说话状态

帧格式见 Voice-Forwarding。可选 WebDAV 定稿 zip(仅 https://)见 Configuration。


迁移清单

  1. 设置强 verify_token;数据口改用请求头,少用 ?token=
  2. 控制 / 语音 / 控制 WS:改用 API Key 头;删除 X-Control-Token / control_token
  3. 按上表改 path;broadcast / staffchat 已可用
  4. 按需要创建多把 Key(duty / admin)
  5. 丢失 Key:本地 revoke + create(无法找回明文)

SLDataAPI Wiki

Releases · Issues

Clone this wiki locally