握手序列

九步 · 时间约束 · 失败排查 · 返回总条目

握手说认为拉弓包需要一个固定顺序的序列才会出现,且其中大部分步骤必须落在同一个 tick 内。本页是这个序列的完整展开。九个步骤里,第 1 至第 5 步同 tick,第 8 步打开窗口,第 9 步落在窗口内。

顺序数据包方向数量说明
0(无)本地状态— 主手持弓,等待 getTicksUsingItem() ≥ 20。
1S32服务端 → 客户端一个 序号往返的起点。它带一个 id,这个 id 就是拉弓包的 Sequence。
2C0F客户端 → 服务端一个 把 S32 的 id 原样送回。必须异步发送——走主线程队列会被挤到下一个 tick,往返就跨了 tick。
3C08客户端 → 服务端一个 重发一次使用物品,把服务端侧的 getTicksUsingItem() 归零。
4C07客户端 → 服务端半个 紧跟着发出半个 C07(RELEASE_USE_ITEM)。
5C06客户端 → 服务端一个 可选。仅在某些特殊情况下需要,用于与服务端同步位置。
6S08服务端 → 客户端一个 位置校正。收到后不立即应用,推迟 15 – 20 tick 再处理。
7ClientboundPullBowPacket服务端 → 客户端一个 序列被接受后,服务端下发首个拉弓包(俗称),同时打开 1 tick 的发送窗口。
8ServerboundPullBowPacket客户端 → 服务端半个或一个 窗口内有概率可以主动发出。字段需填写当前的 pos、rot、ground。

速查:蓄力 ≥ 20 tick → S32(收)→ 异步 C0F(发)→ C08(发)→ 半个 C07(发)→ [C06(发,可选)] → S08(收,推迟应用)→ 首包(收)→ 回发(发,概率)

约束

两处“半个”不要混淆

失败排查

症状该说法给出的原因先查哪一步
补了 C06 却没有首包 半个 C07 没和 S32、C0F、C08 落在同一个 tick 第 4 步的时序,而不是 C06 本身
首包来了,回发被丢 Charge Ticks 低于 20,或 Sequence 与窗口对不上 第 2 步的 id 是否真的回带成功
箭照常射出去了 重发的 C08 没落在释放之前,服务端计时没归零 第 3 步与第 4 步的先后
一轮成功、第三轮起全失败 位置差累积到服务端判定超限,S08 被应用 第 6 步推迟的时长是否短于滞空时间

该说法把这类失败归因于服务端实现差异:不同服务端对同一 tick 内连续包的处理窗口宽窄不一,同样的发送节奏在某些环境上成立、在另一些上不成立。这也是为什么没有一份放之四海皆准的参数表。

本页是三种理论模型里握手说的展开。若采用 C08 复合载荷说,第 1、2、6、7 步都不需要——那份说法里只有 C2S 一侧。