Pull Bow (PullBowPacket)
Composite packet · Minecraft Java 1.17+ · 中文条目
Pull Bow is a composite packet in Minecraft Java Edition 1.17+. It is not a registered packet type and has no packet ID of its own: it is a run of vanilla packets — S32/C0F sequence round trip, C08, half a C07, and the movement family — sent inside one tick and processed in arrival order. When it takes effect, the arrow that was not fired leaves the bow, and a short detection exemption follows.
What it is
Searching the official mappings for PullBow returns nothing, and that is expected. What exists there are the packets that make it up: ClientboundPingPacket, ServerboundPongPacket, ServerboundUseItemPacket, ServerboundPlayerActionPacket, ServerboundMovePlayerPacket and ClientboundPlayerPositionPacket. The server does not merge them; it decodes each frame and runs them one by one in the main-thread queue. The effect comes from that order.
The community names ClientboundPullBowPacket and ServerboundPullBowPacket follow Mojang's naming style, and PullBowS2CPacket / PullBowC2SPacket follow the older direction convention. None of the four is a real class.
Composition
| # | Packet | Class | Direction | Contributes |
|---|---|---|---|---|
| 1 | S32 | ClientboundPingPacket | S2C | Sequence |
| 2 | C0F | ServerboundPongPacket | C2S | Sequence echoed back, asynchronously |
| 3 | C08 | ServerboundUseItemPacket | C2S | Resets the server-side use timer |
| 4 | C07 | ServerboundPlayerActionPacket | C2S | RELEASE_USE_ITEM, action field only |
| 5 | C04 / C03 | ServerboundMovePlayerPacket | C2S | X, Y, Z, Yaw, Pitch, On Ground |
| 6 | S08 | ClientboundPlayerPositionPacket | S2C | Position baseline, applied late |
| 7 | local state | LivingEntity.getTicksUsingItem() | — | Charge Ticks |
Trigger
Two conditions are mandatory: the bow must be in the main hand, and the client's own getTicksUsingItem() must be at least 20 — one full second, the point where BowItem.getPowerForTime(20) returns 1.0. Two further conditions belong to the handshake: the server's first packet must arrive first, and the reply has to land within one tick (50 ms) after it. Alignment inside that tick is probabilistic; how much slack the client has left in that tick decides whether the run goes out together.
Sequence
- Charge the bow to 20 ticks.
- Receive
S32and echo its id inC0F— asynchronously, outside the main-thread queue. - Resend
C08, which zeroes the server-side timer. - Send half a
C07immediately after: action field valid, position and facing left as placeholders. - Optionally send
C06to sync position. - Receive
S08but delay applying it by 15–20 ticks; the delay is on applying, not on receiving. - The server's first packet opens the one-tick reply window.
- Reply inside the window with half or full form, Sequence matching.
Steps 1 through 5 must share one tick. Swapping the order does not work: C08 has to be processed before the release, otherwise the timer never resets and the arrow leaves immediately.
Effect
When the run takes effect, the arrow that was held back actually fires. During that tick the server's charge timer had just been reset, so the half C07 computed a power of 0 and spawned no arrow; after the reply inside the window, the arrow leaves in the same round, with the impact point computed at full charge.
A short detection exemption follows: the server's item-use state was reset inside that same tick, so the release and the movement packets are settled against the new state, and the window does not accumulate as two consecutive full-charge draws.
Versions and packet IDs
Play-state IDs are renumbered every version, so an ID quoted from an old table will not resolve. In 1.21.4 (protocol 769) the relevant serverbound IDs are 0x1C position, 0x1D position-look, 0x1F status-only, 0x27 player action, 0x2B pong and 0x3D use item; on the clientbound side 0x37 is ping and 0x42 is player position.
The S32/C0F pair only carries Ping/Pong semantics from 1.17 onward; in 1.16 and earlier the same IDs were transaction acknowledgements. That is why the discussion is scoped to 1.17+.
Capturing it
Run the server with online-mode=false, capture on the loopback adapter, filter tcp.port == 25565 && tcp.len > 0, and reassemble the byte stream rather than counting TCP segments: read a VarInt length, take that many bytes, read the packet ID as the next VarInt. Frames from the same tick are typically less than a millisecond apart; frames from different ticks are at least tens of milliseconds apart.
FAQ
- Is Pull Bow a real packet?
- No. It is a name for a run of vanilla packets sent inside one tick. There is no class and no assigned ID.
- Is it clientbound or serverbound?
- Both directions carry content: the sequence round trip and position correction on the S2C side,
C08, half aC07and the movement family on the C2S side. The C08 payload account treats only the C2S side as Pull Bow itself. - Does it work on every server?
- No. Servers differ in how they queue consecutive packets inside one tick, so the same send rhythm succeeds on some and fails on others. GrimAC also appears to detect the run.