Skip to content

Repository files navigation

Poltergust 3000

A Luigi's Mansion style vacuum for Minecraft Java Edition. Hold Attack to suck mobs, items, XP and soft blocks into the tank; hold Use to blast them back out like a cannon.

Status: complete on 1.21.11

Target Minecraft 1.21.11, Yarn 1.21.11+build.6, Fabric Loader 0.19.3, Fabric API 0.141.6+1.21.11, Loom 1.16.3, Java 21
src/ The full mod, ported from the reference implementation.
reference/1.21.4-yarn/ The original feature-finished mod, kept as the port's source of truth.

This is the 1.21.4 reference brought up to 1.21.11 (the last line with Yarn mappings). The mechanical renames were small (getPos -> getEntityPos, velocityModified -> velocityDirty, getWorld -> getEntityWorld, removeAllPassengers/stopRiding -> detach); the real changes were the 1.21.5 Optional-returning NBT getters, the 1.21.6 ReadView/WriteView entity serialisation redesign in StoredThing, and the HUD moving from HudRenderCallback (removed) to HudElementRegistry. Note that yarn projects need the Loom 1.16 line -- Loom 1.17+ targets the mappings-less 26.x versions and has no mappings configuration at all.

./gradlew build      # jar lands in build/libs/
./gradlew runClient  # dev run

Controls (reference implementation)

Input Effect
Hold Attack (left mouse) Suction beam. Drags nearby entities toward the nozzle and swallows them. Aim at a soft block to chew it loose.
Hold Use (right mouse) Cannon. Fires the tank contents back out, last in first out.
Sneak + Use Gentle release. Low velocity, no impact damage -- for relocating animals or placing blocks.

Both triggers leave movement completely untouched: you can sprint, swim, and fly while firing.

How it works

Why not Item#use

The obvious way to build a hold-to-act item is Item#use returning CONSUME plus usageTick. That was rejected because "using" an item applies the vanilla movement penalty -- you walk at about 20% speed, which the brief explicitly rules out. Instead:

  1. The client polls the attack/use key bindings every client tick.
  2. On a transition only, it sends a 2-byte payload (mode + sneak flag).
  3. The server drives all logic from the end-of-tick event.

Holding a button for a full minute costs two packets, not twelve hundred. As a consequence every vanilla action bound to those buttons has to be suppressed while the vacuum is held, which is done with attack/use block and entity callbacks plus a block-break guard -- no mixins anywhere in the mod.

Where the tank actually lives

The item stack carries only a TankData component: a UUID handle, a total count, and the top five groups by count for the HUD and tooltip. The real payload lives server-side in TankStore, saved to poltergust_tanks.nbt next to level.dat.

This split matters. Item stack components are re-synced to the client on every inventory change, so storing a few hundred serialised mobs on the stack would push hundreds of kilobytes down the wire repeatedly. The handle-plus-summary approach keeps the per-sync cost at a few dozen bytes while still giving the client everything it needs to draw the readout.

Everything that is not a block round-trips through one entity-serialisation path -- items, XP orbs, boats, armour stands and mobs all share it, and captured things keep their identity. Vacuum a named villager with a trade list and that same villager comes back out. (Since 1.21.6 this goes through WriteView/ReadView: the tank still stores plain NBT, and the views are built only at the capture/release boundary.)

Suction feel

Force is pullStrength * (0.22 + 0.78 * falloff^2) / resistance, where falloff goes from 1 at the nozzle to 0 at maximum range. True inverse-square was tried on paper and rejected: it makes distant targets feel dead and near ones snap in like a teleport. The squared-falloff curve keeps a long, readable drag.

resistance scales with max health and hitbox width, so a chicken skitters in instantly while an iron golem has to be wrestled. That is what produces the "fighting a big ghost" beat without bolting on a separate health-gated capture minigame.

Line of sight uses a vanilla visibility check, so you cannot vacuum through walls, but it is skipped within 2 blocks so point-blank grabs never mysteriously fail.

Cannon feel

Shots come out last-in-first-out, like a magazine. Loose items and XP orbs fire in bursts of four (configurable) so emptying a 500-item tank is a firehose rather than a chore; anything heavier goes out one per shot.

  • Mobs re-spawn at the muzzle with velocity and are tracked for 100 ticks. The first living thing they clip takes speed * 5.5 damage (capped at 14) plus knockback, and the projectile takes 40% of that itself. Creeper cannon.
  • Blocks ride out as falling block entities, which means they place themselves on landing for free, and land like anvils. If the muzzle is buried in geometry the block is ejected as an item instead, so the mod never eats terrain to make room.
  • Items get a 30-tick pickup delay so you do not immediately re-collect what you just fired.

Block whitelist

A whitelist, not a hardness threshold. A threshold sounds elegant but in practice a player sweeping the beam across a village dissolves half of it. The list is "loose material a shop-vac could plausibly inhale": sand, gravel, leaves, flowers, crops, wool, snow, torches, mud, cobwebs, ice, TNT and friends. Blocks with block entities are never touched, fluids are excluded, and build-permission checks are respected so spawn protection and claim mods still work.

Removal goes through a normal block break with drops suppressed, so multi-part blocks like tall flowers and cave vines come apart correctly without spilling items.

Configuration

config/poltergust.properties is written on first run. Everything that affects feel is exposed: range, cone angle, pull strength, beam drag, capture distance, block chew time, tank capacity, fire interval, muzzle velocity and spread, item burst size, impact damage, and toggles for sucking players, bosses, and blocks at all.

Known rough edges

  • Middle-clicking the item in creative copies the tank UUID, so two stacks share one tank. Currently treated as a feature ("linked tanks") rather than a bug.
  • Firing a mob into a wall does not damage it; only entity impacts register.
  • No custom sounds -- the suction hum is pitched-up elytra flight and the cannon is a Breeze shot.

About

Poltergust for minecraft (fabric) 1.21.11

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages