[P1][CR-S4~S7] 锁步联机:desync 不处理、超时非按 peer、状态哈希覆盖不足、Transport 细节、net-simulation 自创数据 #519
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
S4 desync 只记录不处理;超时是全局的
StepOutcome的desync变体从来没有被产生过,全仓只有类型定义(lockstep.ts:63-66)。pump()的文档说它会返回 desync(netplay.ts:323-328)。desyncReport(lockstep.ts:204-212),世界照常运行。peer字段被忽略。远端 hash 只按 tick 存储(netplay.ts:502-504),导致:desync ??=只记第一次,一条伪造的 hash 就能永久占住报告。silentTicks都会清零(netplay.ts:469-470),超时判断(netplay.ts:515-521)因此不区分 peer。4 人局里一人掉线,只要其他人还在发消息,就永远不会超时,锁步会一直卡在等那个人。bye,整个会话就被标记为 closed(netplay.ts:506-508),但锁步仍在等那个人的输入。S5 状态哈希覆盖不足,实现重复
问题都在
computeLockstepHash(lockstep.ts:266-370)里:mix(player.hp)经& 0xFFFFFFFF截掉了小数(lockstep.ts:269-272、lockstep.ts:288),怪物 HP 也一样(lockstep.ts:297)。HP 的小数分歧检测不到。round(lockstep.ts:311-312 对比 lockstep.ts:337-338)。any:(entry.item as any).uniqueId(lockstep.ts:321),这里的类型其实可以补齐。if (inventories)这类判断(lockstep.ts:302),与 AGENTS.md §3 相悖。S6 客户端 Transport 细节
中继侧的问题见 #517。客户端这边:
error和close都会调用closeHandler(transport.ts:387-388),与接口注释的 "called once"(transport.ts:33)矛盾。send静默丢弃消息(transport.ts:391-394)。close()什么都不做(transport.ts:397),socket 之后照样会连上。S7 net-simulation 自创数据
'Act 1 H2H A'(net-simulation.ts:126-128)。DEMO_MONSTERS/DEMO_EXPERIENCE(net-simulation.ts:28-35)。widthPx: 10000(net-simulation.ts:59-61)。skill和talk字段被发送了,却被忽略。它和单机的GameEngine不是同一套代码(见 #525)。单机路径遇到未知怪物会直接 throw(engine.ts:1241),这里的策略正好相反。
修复指南
desync:
desync变体:step()比较到分歧时返回它,pump()停止推进并上报;推荐前者,并配一个 resync 策略。最简单的做法是回退到最近一次一致的快照重放;或者直接结束对局,上报 tick、双方 hash 和双方快照的 diff。
按 peer 记账:
lastHeardTick[peer]、hashes[peer][tick]、byeFrom[peer],超时按 peer 判断。bye或超时后,用确定性的规则处理:填空输入,或把它移出peers。哈希:
Fnv32工具,热路径上不新建闭包(和 #527 的 FNV 去重一起做)。loot、castRng)。这是最廉价、最早能暴露分歧的信号。然后再加 mana、投射物和状态效果。Math.round(v * 256)),背包坐标也一样。if (inventories)这类判断。Transport:
message监听器里出错时,用socket.close(1003)或socket.close(1009)关闭连接并回调会话,不要 throw。closed标志保证closeHandler只调用一次。send在连接未打开时返回false或排队,由调用方决定,不要静默丢弃。close()也要生效。net-simulation:
验收标准
pump()返回desync并停止推进;报告里包含 tick 和双方的 hash。timeoutTicks后被判超时,其他人不受影响。error和close同时发生时,closeHandler只被调用一次(有测试覆盖)。net-simulation.ts中不再有DEMO_*常量和兜底 TC。npm run typecheck0 error;npx vitest run全部通过。相关