QuinnAddon · module handoff
THM-Addons' packet miner, ported to Yarn mappings and QuinnAddon's conventions, with nine defects of the original fixed.
compileJava, jar, remapJar — and the jar carries the module and both accessors.| File | What it is |
|---|---|
| port-only/ Speedmine.java | The original behaviour, only reshaped so it builds inside QuinnAddon. Keep it as the reference point. |
| fixed/ Speedmine.java | The same module with nine defects fixed. This is the one to ship. |
| changes.diff | 249 lines. Exactly what differs between the two, so the fixes can be reviewed on their own. |
| mixin/ClientPlayerInteraction ManagerAccessor.java | Required. Puts the client's prediction sequence number on the dig packets. |
| mixin/ClientWorld Accessor.java | Required. Lets a packet-triggered rebreak record what the server really has, so a rejected rebreak rolls back to the block and not to air. |
| mixin/PlayerMove C2SPacketAccessor.java | Needed only by the Air Miner group. |
Built here from the source on this site, against Minecraft 1.21.11, Yarn
1.21.11+build.3 and meteor-client:1.21.11-SNAPSHOT. The hashes are
there so you can tell the file did not change on the way to you; they say nothing about what is
inside it, which is why the source is on the same page.
| File | What it is |
|---|---|
| QuinnAddon-Test -0.1.0.jar |
For the tester. Speedmine, Inventory Cleaner and Auto Accept, nothing else. Its own
mod id (quinnaddon-test) and package, so it can sit beside the real
QuinnAddon without colliding. |
| quinnaddon-test -source.zip |
The whole project that jar was built from, Gradle files included. |
| QuinnAddon-v0.4.0 -with-speedmine.jar |
QuinnAddon at tag v0.4.0 with Speedmine and the two modules merged in —
proof the merge builds. Not a release; that is yours to cut. Its own version string
reads 0.2.3, for the reason in the next section. |
| SHA256SUMS.txt | Hashes for the three files above. |
If you are the tester: take the first jar, put it in mods beside
Meteor, and do not run the normal QuinnAddon at the same time — they share the Speedmine module
even though the ids differ. Nothing here has been run in-game, so anything you see is new
information. The part most worth hammering is speedmine, and the rebreaks in
particular: turn on debug-rebreak and it reports confirmed rebreaks per second
beside the module name, which is a number worth writing down and comparing against whatever you
normally use. Worth saying out loud: breaking is the dangerous half of a packet miner, so test
it somewhere you can afford to lose what you are standing on.
Neither of these was asked for. They are Rei's, added on his own initiative because he wanted them in the test build. Speedmine does not depend on either, so they can be dropped without touching anything else — say so and they come out.
Both arrived as finished code. Neither compiled here, and both had something worth fixing before a tester runs them. The originals are on the source page beside the fixed ones.
Category.Misc, but
Category is the class, not the list of them. Auto Accept imported an
Addon class and a utils.Utils helper that QuinnAddon does not have.
Auto Accept also called GameProfile.getName(), which is now a record accessor,
name()./tpy is a setting too — it is not universal.Still not covered: the offhand is outside the range Inventory Cleaner walks, and Auto Accept's chat check is a heuristic — a server with an unusual chat format could still get through it, which is what the player-list check is there to catch.
Both versions, the diff between them and the two mixins are on their own page, in full, with a raw link beside each for copying.
The THM file ships with this header, and it is a condition of use, not a courtesy:
Copyright (c) THM Addons contributors. Credit the devs, keep the link.
By using this code you agree to the license terms and to keep your repo public.
So the port keeps a header pointing back at Magnus-Krill/THM-Addons, and the module description credits them. QuinnAddon is already public, so the rest is satisfied. Please don't strip that header. Credit also to mushek, named in the original, and to BlackOut, whose AutoMine the target picker follows.
Four files in, two files get a line each. Take Speedmine from fixed/, not
port-only/ — same class name, so only one of them can sit in the repo at a time.
src/main/java/com/example/addon/
modules/Speedmine.java
mixin/ClientPlayerInteractionManagerAccessor.java
mixin/ClientWorldAccessor.java
mixin/PlayerMoveC2SPacketAccessor.java
// addon-template.mixins.json
"client": [
"BetterTabPlusMixin",
"ClientPlayerInteractionManagerAccessor",
"ClientWorldAccessor",
"PlayerMoveC2SPacketAccessor"
],
// QuinnAddon.java
modules.add(new Speedmine());
Two of the three mixins are required: vanilla's sendSequencedPacket is private
and ClientWorld.getPendingUpdateManager() is package-private, and the miner needs
both to put a sequence number on a dig packet and to keep rebreak rollbacks honest.
PlayerMoveC2SPacketAccessor is only for the Air Miner — drop that settings group
and you can leave it out.
THM builds against Mojang mappings; QuinnAddon uses Yarn. Every Minecraft type and method differs, so not one line compiles as-is. On top of that, THM leans on its own support classes, none of which exist here. Each one had to be replaced — this is true even of port-only.
| THM | QuinnAddon |
|---|---|
| Mojang mappings | Yarn — mc.level → mc.world, ServerboundPlayerActionPacket → PlayerActionC2SPacket |
| InventoryManager | a local server-slot tracker over UpdateSelectedSlotC2SPacket |
| RangeUtils | isInRange() / closestFace(), in the file |
| RenderUtilsTHM | Render3DEvent.renderer.box() |
| hand-written mining formula | BlockUtils.getBreakDelta(slot, state) — Meteor already had it |
| ClientLevel mixin | Meteor's BlockUpdateEvent |
| sequenced-packet accessor | same idea, our own invoker on ClientPlayerInteractionManager |
| PaketLimiter, ThmMembers, THMSystem | dropped — THM-only |
| fromTag() migration | dropped — no legacy Speedmine settings to migrate |
One of those is worth a second look. THM wrote the vanilla mining formula out by hand, in two places that had drifted apart; Meteor ships the same calculation, so the port is shorter and can't disagree with itself. The world-update mixin also disappeared, since Meteor fires BlockUpdateEvent for exactly that.
One behavioural difference to watch. THM pauses mining through its InventoryManager priority system, so eating and other modules can hold the inventory. QuinnAddon has no shared arbiter, so this port falls back to mc.player.isUsingItem(). If AutoTotemPlus and Speedmine start fighting over the hotbar slot, that's where a shared lock belongs.
All 35 settings are here; none dropped, none added. These are the behavioural differences, and each one exists because QuinnAddon does not have the system THM leans on. Worth knowing before you compare the two side by side.
isUsingItem().
If AutoTotemPlus and Speedmine end up fighting over the hotbar slot, that is where a shared
lock belongs.sendSequencedPacket and assumes success. Nothing in QuinnAddon cancels those
packets today, but a module that did would make the miner believe it had started.getBreakDelta does everything THM's
hand-written formula did except the BLOCK_BREAK_SPEED attribute, which THM
multiplied in. That attribute is 1.0 unless something changes it, so it costs nothing on a
normal server.fromTag() rewrites its own older
configs. There is nothing here to migrate.A declined click did nothing at all
The break event was cancelled before deciding whether to mine the block. With multitask off and an item in use, left-clicking a block neither packet-mined it nor fell back to vanilla mining. handleBlockClick now reports whether it took the block, and the event is cancelled only then.
requestBreak could stall the whole module
It only checked for air. An unbreakable block passed in by another module produced a context with zero progress that the removal check never cleared, so the primary slot stayed occupied forever. It now validates the block, and any context making no progress for 3s is dropped. The original's unused startMs field looks like this timeout was planned and forgotten — it is used now.
One queue insert stored a mutable BlockPos
Three of the four inserts called immutable(); one didn't. Harmless with today's callers, and silent corruption the day a MutableBlockPos reaches it.
A replaced block kept being mined as the old one
The context holds the BlockState it started on while the removal check reads the live world, so swapping the target block left it mining with the old hardness and firing the old block's break particles.
Surround ring sat one block too high
Math.round on the enemy's Y, so standing on a slab, snow layer or soul sand shifted the whole ring up. Floored now.
Dead players were still targeted
isSpectator was checked, isAlive was not, so the picker kept digging around a corpse for the whole death animation.
The tool search could never return "no tool"
It started at -1, which an empty hand already beats, making every no-tool branch dead code. Ties also went to the lowest hotbar index, so it swapped away from an equally good tool already in hand. It now starts from the selected slot, which also means fewer slot packets.
One timeout, written twice
The rebreak deadline existed as 2000 ms in one place and 2_000_000_000 ns in another. One constant now, the other derived.
Outline ignored rebreak-mode Off
Every other rebreak check tested the mode; the "last broken block" outline didn't, so it drew with rebreaks disabled.
tps-sync still defaults off. With it off, progress is timed as wall clock × 20 ticks, so STOP goes out too early on a lagging server. Deriving break-threshold from measured ping, or syncing automatically below ~19 TPS, is the real answer — but that's a feature, not a fix.Both files compile against Minecraft 1.21.11, Yarn 1.21.11+build.3 and
meteor-client:1.21.11-SNAPSHOT. gradlew build runs clean through
compileJava, jar and remapJar, and the produced jar
carries Speedmine.class and both accessors.
One real problem surfaced on the way, and it is the reason the second mixin exists:
PendingUpdateManager lives in net.minecraft.client.network, not
client.world, and ClientWorld.getPendingUpdateManager() is
package-private. The first attempt reached for it directly and could not. Everything else that
looked mapping-risky — PlayerEntity.isGliding(),
PlayerMoveC2SPacket.Full(...), PlayerInventory.getSelectedSlot() —
was right first time.
What this does not cover: nothing has been run in-game. The mixins compile and are listed in the config, but whether they apply at runtime, and how the miner behaves against a live anticheat, is still for you to test.
The idea post asked whether this is on FutureClient / Mio speedmine level, specifically at insta rebreak. Having read the whole file: the rebreak path is the most worked-on part of it.
Strict waits for server confirmation between
rebreaks. Strong skips the confirmation wait and the TPS start delay entirely.
Bypass runs Strict until one rebreak is confirmed and then switches to Strong,
which is an anticheat-aware ramp rather than a flat setting.rebreak-trigger on
OnPacket it reacts to the server's block update as it arrives instead of waiting
for the next client tick. That is where the speed comes from.debug-rebreak counts
server-confirmed rebreaks per second and shows the figure beside the module name. Whoever
wrote it was tuning against a number, not a feeling.Whether it actually matches those clients is measured, not read, and none of this has been
run in-game. But the answer is one setting away: turn on debug-rebreak, run the
others the same way, and compare.
Three things I ran into while porting. None of them block this module; the first will bite eventually.
SurroundPlus and
LogStripper each swap slots on their own, and Speedmine now tracks its own server
slot too, because there is no shared place to ask. In a fight those run at the same time —
placing while mining is the whole point of the module — so sooner or later one swaps out from
under another, and in cpvp that is a death rather than a glitch. THM handles it with a single
InventoryManager that every module asks before swapping. It is also the one difference in this
port that cannot be fixed from inside the module.fabric.mod.json carries
"id": "addon-template", so any other addon built from the unmodified Meteor
template collides with it. sources still points at
MeteorDevelopment/meteor-addon-template as well.v0.4.0 points at
eb508f9, and at that commit build.gradle.kts and
libs.versions.toml both still say 0.2.3 — so building the v0.4.0
source gives you a jar called QuinnAddon-0.2.3.jar. You have probably already
worked around it when cutting the release; it is only a problem for anyone building from
source.