Thwack — your hits land where you saw them.
In vanilla Minecraft, clicking does nothing until the server answers. Your client sends "I attacked entity 42" and waits: the sound, the red flash and the knockback only arrive one full round-trip later. At 120 ms ping that is a quarter of a second of silence after the click — and by then your target has moved, so hits you had perfectly lined up can simply not happen.
Thwack moves the impact to your machine, and makes the server agree with what you actually saw.
1. Aim at what you see. Minecraft picks your crosshair target once per tick, against the entity's tick position. The model on your screen is drawn interpolated — up to one tick ahead, about 0.28 blocks on a sprinting target. Thwack re-casts the ray at the exact moment you click, against the hitbox as it is being drawn. Same reach, same box: only the moment it is read changes.
2. The impact is instant. Sound, red flash, crit particles and knockback play immediately on your client. The strong / weak / crit / sprint-knockback rules are copied from PlayerEntity.attack, so the prediction sounds exactly like the real hit. When the server plays the same sound a round-trip later, it is swallowed — otherwise every hit would be heard twice.
3. The server rewinds. It keeps one hitbox per player per tick for one second. When your hit arrives, it looks up where the target was when you clicked, and re-runs the vanilla range check against that position.
Is this a reach hack?
No, and the design makes it impossible to turn into one:
- Validation starts with the vanilla check, unchanged (
canInteractWithEntityIn(box, 1.0)— 4 blocks from the eye) against the target's current position. Thwack can only ever make a hit land, never make one fail. - The client never sends damage. It sends a target and a position it saw. Damage is computed by
PlayerEntity.attackon the server: weapon, cooldown, crits, enchantments, invulnerability frames — all vanilla. - A made-up position is useless. The server does not trust the coordinate it receives; it only uses it to pick a snapshot from its own history. If nothing matches within 0.75 blocks, the hit is refused.
- The rewind window is capped by measured ping (
min(maxRewindMs, ping + 100)), so a 10 ms client cannot claim 400 ms of lag. - The server decides. Nothing happens until an operator installs Thwack server-side and it sends the handshake. On a vanilla server the mod is completely silent.
Installing
The same jar goes on both sides, and Fabric API is required.
| effect | |
|---|---|
| client only | nothing at all — the mod stays silent |
| server only | nothing at all — no client sends Thwack hits |
| both | screen-accurate aim + instant impact + lag compensation |
In game
- F6 — diagnostic panel: whether the server supports Thwack, your ping, the rewind window, hits sent / rescued / refused.
- F7 — turn Thwack off and on live, to compare with vanilla in the same minute.
/thwack(op) —status,on,off,reload.
Everything is configurable: config/thwack.json (server) and config/thwack-client.json (client). Each piece of the predicted impact — sound, flash, particles, knockback — can be switched off on its own.
What is tested, and what is not
- Measured with two clients on a dedicated server: handshake, hit sent, validated, 7 vanilla damage applied (20.0 → 13.0 HP), matching counters on both sides.
- Not yet measured: the rewind doing real work. Locally the ping is 0, so there is nothing to rescue and the counter stays at 0 — which is the correct result, but it is not proof. That is why this first build is marked Beta. If you run it on a real server,
/thwackwill tell you how many hits it saved, and I would genuinely like to know.
Fabric 1.21.1 · requires Fabric API · MIT · Studio Echelon

