feat(hunt): 《围猎》2-4人实时联机纯音频协作守卫——纯音频MMORPG第一阶段切片
- 设计:docs/design/23-hunt.md + voice-ids(84 id,166条)+ 13号断言登记,§15记录10+1条设计裁决 - 服务器:零依赖WebSocket(ws.js)+ 房间管理/服务端权威战斗/bot AI(hunt-room.js),断线30s宽限resume回槽、超时转bot;修复package.json模块类型误判的既有破坏 - 客户端:web/hunt/ 全套(教学T0-T4/听觉视野裁剪R1-R8/结算排行榜/guide接入),playtest 211断言 - 引擎:audio.js 后向兼容 opts.pan(StereoPannerNode),web-engine-api.md 同步 - 资产:166条TTS语音(QC无离群)+ 13件合成sfx(真峰值≤-3dBFS)+ 2首Mureka BGM,终检全绿 - 平衡:bot调参至挂机局71%失守/C、3bot局71% A/B(hunt-balance-scan.mjs 24种子扫描) - 接线:大厅卡片、profiles.js hunt桶、README/roadmap MMO路线条目 验证:hunt-sim 16/16 + api-smoke 12/12 + hunt playtest 211/211 + 既有10游戏与引擎回归零回退 + 真服务器WS端到端冒烟通过
This commit is contained in:
+90
-2
@@ -11,6 +11,16 @@ P1 增补**配对码跨设备**(`01 §4.2` 旅程 3):老设备在「档案
|
||||
生成 6 位配对码(逐位朗读),新设备输入即可把本机进度按桶 LWW 合并进老档案;
|
||||
token 180 天滑动过期,到期后大厅引导「重新登录或新建」。
|
||||
|
||||
23 增补**《围猎》联机 WebSocket**(设计 `docs/design/23-hunt.md` §6):同一 HTTP
|
||||
服务器、同一端口上新增 `GET /ws/hunt` 升级端点(`ws.js` 手写握手与帧编解码,零依赖),
|
||||
房间管理与服务端权威战斗模拟在 `hunt-room.js`(全内存,不落盘)。协议见下文
|
||||
[《围猎》WS 协议](#围猎wshunt-协议23-huntmd-6)。
|
||||
|
||||
> 模块格式标记:本目录 `package.json` 仅有 `{"type":"commonjs"}`(私有、零依赖、
|
||||
> 无可安装内容)——祖先目录 `AutoVideo/package.json` 带 `"type":"module"`,会把本目录
|
||||
> `.js` 误判为 ESM 导致 server.js 无法启动;该标记把本目录 `.js` 固定回 CommonJS。
|
||||
> (`test/*.mjs` 恒为 ESM,不受影响。)
|
||||
|
||||
## 启动
|
||||
|
||||
```bash
|
||||
@@ -150,6 +160,70 @@ PORT=8001 SG_DATA_DIR=/tmp/sg-data tools/node/bin/node web/server/server.js
|
||||
`{ "error": "…", "game": "rpg", "server": { "updatedAt": "…", "rev": 4, "data": { … } } }`
|
||||
——客户端应比较 `data.updatedAt` 择优后带新基线重试(大厅已实现)
|
||||
|
||||
## 《围猎》WS(/ws/hunt)协议(23-hunt.md §6)
|
||||
|
||||
联机守卫游戏《围猎》的实时通道:零依赖 WebSocket(`ws.js` 手写握手 + 帧编解码,
|
||||
仅 node:crypto/node:events)+ 房间与服务端权威战斗模拟(`hunt-room.js`,全内存
|
||||
不落盘,单实例约束不恶化)。字段级契约的唯一来源是 `docs/design/23-hunt.md` §6,
|
||||
本节是实现侧的运行/调试说明。
|
||||
|
||||
### 传输(§6.1,ws.js)
|
||||
|
||||
- 端点 `GET /ws/hunt`;其它路径的 upgrade 请求一律 404 断开。
|
||||
- 握手校验 `Upgrade: websocket` / `Connection: …upgrade…` / `Sec-WebSocket-Key` /
|
||||
`Sec-WebSocket-Version: 13`,回 `101` + `Sec-WebSocket-Accept`。
|
||||
- 帧纪律:客户端帧必须带 mask(否则 close 1002);支持 opcode 0/1/8/9/10;
|
||||
二进制帧 close 1003;单条消息 >4KB close 1009;非法 UTF-8 close 1007;
|
||||
RSV/未知 opcode/控制帧分片 close 1002。服务器帧不 mask。
|
||||
- 活性:服务器每 15s ping,**45s 无 pong 判死**(等同断线,走 §6.6 宽限)。
|
||||
- 速率帽:每连接 20 条应用消息/s,超限 err `rate`,10s 内再犯 close 1008。
|
||||
- 背压:每连接待发队列;`snap` 可丢(新顶旧),`joined/ev/err` 不丢;队列 >200 close 1013。
|
||||
- 连接后 5s 内必须发 `join`,否则 close 1008。
|
||||
|
||||
### 消息骨架
|
||||
|
||||
- C→S 三条:`join`(`{t,ver:1,room:"quick"|4位房码,name,teach?,resume?}`)、
|
||||
`act`(`{t,kind:"attack"|"callout"|"skill"|"start",dir?,seq,at}`)、`leave`。
|
||||
- S→C 四类:`joined` / `ev`(11 种 kind:spawn/kill/miss/skill/breach/wave/
|
||||
waveclear/callout/botline/roster/end,带房间单调时钟 `ts`)/ `snap`(2Hz 全量兜底:
|
||||
mobs + slots 冷却)/ `err`(code ∈ cooldown|skill_cd|bad_dir|not_ingame|room_full|
|
||||
room_gone|bad_msg|rate)。字段逐条以 23-hunt.md §6.2/§6.3 表为准。
|
||||
- `roster`(joined 内与 ev 内同构)每条目附带 `alive`(断线广播 false)——
|
||||
是 §6.3 字段表的显式超集,断线/回槽通知所必需。
|
||||
|
||||
### 房间生命周期(§6.4-§6.6 实现要点)
|
||||
|
||||
- 快速匹配复用 `phase='lobby'` 未满房;显式房码 join 不存在即以该码建房;
|
||||
对局中/教学房 join → err `room_full`。
|
||||
- lobby 上限 12s(自建房起算);任一人类 `act start` 或满 4 人立即开局;
|
||||
开局 bot 补位至 max(3, 人类数),第 4 座仅 4 人局启用(座 3 `char=null`,
|
||||
该槽喊话/呼喊由客户端哨音处理,服务器不发其 botline)。
|
||||
- 教学房:`join teach:true` → 强制单人新房、跳过 lobby 直入 TEACH(joined.state
|
||||
.phase='teach'),教学波 3 狼(方位 N,逼近 12s,突入零惩罚);狼 1 未杀则补放
|
||||
至多 2 次(对应"做错重教 ≤2 次后放过"),教学段 bot AI 挂起但呼喊必答
|
||||
help_ack;教学波出清后休整 8s 同场接续第 1 波。
|
||||
- 断线(含 45s 无 pong)→ 槽位 alive=false(roster 广播)+ 30s 宽限静默;
|
||||
宽限内带 `resume` 重连 → 重发 joined(同 slot/seed/char/resume)+ 紧随 snap;
|
||||
超时:剩余人类 ≥3 → 槽位移除,否则转 bot(不可逆,char 沿用、播 cover、
|
||||
冷却延续不清零);lobby/end 阶段超时直接移除。最后一个人类宽限耗尽 → 房灭
|
||||
(bot 不续命)。`leave` 立即按同一规则处理(无宽限)。房灭/转 bot 后迟到的
|
||||
resume → err `room_gone`。终局后房间保留 30s 再对全员 close 1000。
|
||||
- 防区:槽位号入房后不变;开局时按**在座顺序**分配 §3.3 防区表(roster ev 下发最终
|
||||
sector)——中途离开造成槽位空洞时,槽 3 玩家可能拿到 3 人局第 3 防区(char 仍 null),
|
||||
属有意的边界处理。
|
||||
- seed 建房即掷(joined.seed);刷怪剧本 `rng(wave)=mulberry32((seed^(wave*0x9E3779B9))>>>0)`
|
||||
+ 座位数轮转发牌,同 seed 同剧本;bot 反应带 rng 走独立的 seed 派生流。
|
||||
- botline/callout 喊话节流(§7.4):10s 窗氛围句(greet/cover/kill/breach/skill/wave)
|
||||
≤2 条超出丢弃;`ev callout` 与 `botline help_ack` 为优先级句永不被氛围顶掉
|
||||
(其速率由 5s/座呼喊节流与"一次呼喊一次应答"源头约束)。
|
||||
|
||||
### 时钟与测试钩子
|
||||
|
||||
房间一切时间逻辑由 `manager.tick(dtMs)` 推进(本进程 100ms setInterval 驱动);
|
||||
测试直接 import `hunt-room.js`、用 FakeConn 替身连接 + 快进 tick 即可确定性复现
|
||||
(`createManager({ rateLimit: Infinity })` 关闭墙钟速率帽,`joinTimeoutMs` 可调)。
|
||||
导出 `buildWaveScript/gradeFor/mulberry32/DIRS/LAYOUTS/WAVE_TABLE` 等供断言。
|
||||
|
||||
## 数据格式
|
||||
|
||||
```
|
||||
@@ -184,10 +258,24 @@ web/server/data/
|
||||
## 测试
|
||||
|
||||
```bash
|
||||
tools/node/bin/node web/server/test/api-smoke.mjs # API 冒烟 + 大厅分桶纯函数单测(零依赖)
|
||||
tools/node/bin/node web/server/test/api-smoke.mjs # API 冒烟 + 大厅分桶纯函数单测(零依赖)
|
||||
tools/node/bin/node web/server/test/hunt-sim.test.mjs # 《围猎》房间/战斗模拟 + WS 传输冒烟(零依赖)
|
||||
tools/node/bin/node web/server/test/hunt-balance-scan.mjs 24 # bot 难度多种子平衡扫描(开发工具)
|
||||
```
|
||||
|
||||
覆盖:device 建档/重附着、进度 PUT-GET-LWW 冲突(含 legacy 放行)、claim 命名/设 PIN/
|
||||
api-smoke 覆盖:device 建档/重附着、进度 PUT-GET-LWW 冲突(含 legacy 放行)、claim 命名/设 PIN/
|
||||
合并、旧用户登录迁移、per-IP 频控、/server/ 静态封禁、localStorage 分桶逻辑(H1-H6)、
|
||||
配对码全流程(I1:start 规约/join 桶级 LWW 合并/单次作废/无 token 转入/幂等/日志脱敏)、
|
||||
配对码防护(I2:join 5 连错封锁、start per-IP 频控)、token 过期 401 路径(J1)。
|
||||
|
||||
hunt-sim 覆盖(13-playtest-criteria.md §24 服务器侧条目;固定 seed + 快进 tick 确定性复现):
|
||||
1 真人+2 bot 打完 5 波全流程(逐波核对 §3.4 剧本、击杀账与 ev end 评级/耐久一致、
|
||||
snap 逐 tick 与房间真值一致、greet 间隔 ≥1.5s)、seed 复现、断线 30s 内 resume 回槽
|
||||
(同 slot/seed/char + 紧随 snap)、宽限超时转 bot(char 沿用、转后产出 act、cover 喊话)、
|
||||
4 人局剩余 ≥3 改槽位移除、leave 立即转 bot、出击冷却 2.5s/旋风斩 8s/呼喊 5s 与
|
||||
bad_dir/not_ingame/bad_msg、出击弧 ±45° 与 eta≤4 近战窗、突入狼 -1/熊 -2、失守立即终局
|
||||
(grade:null 即"失守不写榜"的服务器侧口径)、终局 30s 后 close 1000 房灭回收、
|
||||
教学波突入零惩罚与同场接续第 1 波、lobby 12s 自动开局/满 4 人开局/房码 join、
|
||||
呼喊→bot 补位偏置 ×2(下次出击方向落入呼喊者防区,help_ack 恰一次)、
|
||||
喊话 10s ≤2 条氛围节流与呼救优先、速率帽与 join 超时;WS 真机冒烟(手写握手/帧客户端):
|
||||
101 与 Accept 哈希、无 mask→1002、二进制→1003、ping→pong、分片拼装、静态/REST 回归。
|
||||
|
||||
Reference in New Issue
Block a user