CSoundEffect::new() scales the position by * 8 to convert from
fixed-point. write_packet_data was applying * 8 a second time,
resulting in positions being multiplied by 64.
Add regression test asserting the encoded X/Y/Z are exactly
floor(input_pos * 8), preventing this bug from reappearing.
The item-stack, uuid, and event WIT modules are generated but were never
re-exported from the plugin API, so plugin authors could not name ItemStack
(needed to build GUI icons, /give, skulls) or construct a uuid. This adds them
to the public re-exports, plus EventHandler/FromIntoEvent and the command
Arg/ArgumentType/StringType helpers.
Revives the change from #2325 (closed unmerged).
The chest in the stronghold square room was placed as a bare block state,
so no chest block entity was ever created for it. Opening a chest and
resolving a double chest both go through `get_block_entity`, so the chest
could neither be opened nor paired with a chest placed next to it.
Use the existing `add_chest` helper, which writes the block state and the
matching block entity with a loot table, as the nether fortress corridors
already do. Vanilla `StrongholdPieces$RoomCrossing` uses
`chests/stronghold_crossing` at the same position.
* feat: persist runtime-set item components
They serialized to nothing before; give the remaining ones a read/write so
their data survives a save/load. Predicate-based ones keep raw NBT for now.
* refactor: remove Cow where unnecessary
Copied it over from ItemModelImpl, but it makes no sense for base_color,
note_block_sound and tooltip_style: they're only ever built at runtime, so a
plain String is enough.
Third-party auth servers (drasl, Blessing Skin, littleskin.cn) don't send the
signatureRequired field in the hasJoined texture property, so parsing the
profile failed and the player was kicked. The field is unused, so default it
when missing.
fixes#301
Replace full-block entity queries with vanilla's centered 14x4x14 pressure plate detection box. Share the bounds between normal and weighted pressure plates and cover the geometry with unit tests.
Implements the full vanilla Minecraft 26.2 mob equipment system, giving
mobs weapons, armor, enchantments, and loot-pickup flags at spawn.
Added:
- Data-driven EQUIPMENT_REGISTRY mapping 13 mob types (zombie, husk,
zombie_villager, drowned, zombified_piglin, skeleton, stray, bogged,
wither_skeleton, piglin, pillager, vindicator) to their weapon and
armor configurations, all verified against decompiled vanilla sources.
- Exact vanilla RegionalDifficulty formula from DifficultyInstance.java:
computes effective_difficulty and special_multiplier from base
difficulty, game time, chunk inhabited time, and moon phase. When
special_multiplier is 0.0 (fresh Normal/Easy worlds), equipment,
enchantments, and loot-pickup flags are suppressed, matching vanilla.
- Vanilla-accurate armor selection: random base tier (0-2) with up to 3
upgrade attempts at 10.87% each, partial armor break chance (10% on
Hard, 25% otherwise). Higher difficulty produces fewer pieces.
- Weighted enchantment selection with exclusive-set conflict resolution
and cost-based level determination. Curated flat pools per equipment
category (melee/trident/bow/crossbow/fishing_rod/head/chest/legs/feet).
- Per-slot equipment drop chances (0.085 default) with looting bonus
(+lootingLevel * 0.01 per vanilla EnchantmentHelper).
- Exact vanilla drop durability formula from Mob.dropCustomDeathLoot:
damage = maxDamage - random(1 + random(max(maxDamage-3, 1))).
- CAN_PICK_UP_LOOT mob flag (bit 3, value 8) set probabilistically at
55% * special_multiplier.
- Guard against empty equipment packets in send_equipment_changes to
prevent client decode crashes.
- Chunk inhabited_time tracking in world tick for difficulty scaling.
Integration: equip_mob_on_spawn is called from the blanket
EntityBase::init_data_tracker impl, so every mob type automatically
participates. New mobs are added by inserting a MobEquipmentDef into
the EQUIPMENT_REGISTRY with their weapon/armor config.
cargo check: passes / cargo clippy (pedantic): 0 warnings / cargo fmt: clean
* Fix egg: initialize git submodules during install
The Pumpkin repo uses pumpkin-plugin-wit as a git submodule, but the
install script only does 'git clone --depth 1' without --recurse-submodules.
Add 'git submodule update --init --recursive --depth 1' after checkout
so the WIT files required by bindgen!/wit_bindgen::generate are available.
* Potential fix for pull request finding
* feat(protocol): generate particle ID remap tables
Generate version-specific particle registry mappings from the existing ViaBackwards data for every supported Java protocol version.\n\nExpose the generated remapper through pumpkin-data and enable it for pumpkin-protocol so packet serializers can translate current registry IDs for older clients.
* fix(protocol): remap explosion particles for older clients
Translate the explosion particle registry ID for each client's negotiated Java version before serializing the explode packet.\n\nWithout this remap, 1.21.11 interpreted the 26.2 explosion-emitter ID as falling dust, consumed the following bytes as particle data, and disconnected with a decoder exception. Add packet-level coverage for both 1.21.11 and 26.2 encodings.
* fix(protocol): remap particle IDs for older clients
Level-particle packets and particle entity metadata still encoded raw 26.2 registry IDs, causing older clients to decode the wrong particle schema and disconnect. Route every active outbound particle path through the version remapper, preserve metadata payloads, and cover 1.21.11 and 26.2 encodings with regression tests.
`CommandDispatcher::find_suggestions` resolved the command tree and walked
its paths to produce server-side tab-complete suggestions without ever
checking the command's permission, unlike `dispatch`, which gates on
`self.permissions.get(key)` followed by `src.has_permission`.
Many legacy commands (e.g. pardon, deop, whitelist) register their
permission only in `self.permissions` and have no in-tree `Require` node.
Their argument consumers therefore leaked privileged data -- banned, op,
and whitelisted player names -- to unprivileged players through
tab-complete, even though those players could not execute the command.
Add the same permission gate used by `dispatch` after the command key is
resolved and before the tree is traversed: look up `self.permissions` for
the key and return an empty suggestion list if the permission is absent or
if the sender lacks it. This keeps suggestion visibility consistent with
execution authorization.
* fix(block): melt snow layers under high block light
Snow layers never melted because the block had no random_tick handler.
Mirror vanilla SnowLayerBlock.randomTick: on a random tick, remove the
layer when the block light level at its position exceeds 11 (e.g. from
a nearby torch).
Fixes#2179
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* style: apply rustfmt
Implements the vanilla /tag command (tracked in #15) along with the
entity-side storage it needs:
- Adds a scoreboard_tags: Mutex<HashSet<String>> field to Entity, with
add_scoreboard_tag / remove_scoreboard_tag helpers that enforce the
vanilla 1024-tag cap and report whether they changed anything.
- Serializes tags to/from the entity's "Tags" NBT list, matching the
vanilla format so tags round-trip through world saves.
- /tag <targets> add|remove <name> and /tag <targets> list, with the
existing commands.tag.* translation keys and single/multiple wording.
Implements the three vanilla save-control commands (tracked in #15):
- /save-all saves all online players' data and advancements, then
requests a chunk save from every world's chunk scheduler. It works
even while autosaving is disabled, matching Vanilla.
- /save-off disables periodic autosaving via a new save_enabled flag
on Level; running it again fails with commands.save.alreadyOff.
- /save-on re-enables autosaving; running it again fails with
commands.save.alreadyOn.