Commit Graph

2549 Commits

Author SHA1 Message Date
Alexander Medvedev
7c3177b404 feat: some more plugin api functions 2026-08-04 20:54:55 +02:00
Alexander Medvedev
460cb9b01c Update pumpkin-plugin-wit 2026-08-04 15:00:44 +02:00
Alexander Medvedev
42d9391804 feat: add some more events 2026-08-04 14:57:33 +02:00
Alexander Medvedev
9ececd9eca chore: add more chunk tests 2026-08-04 10:38:27 +02:00
Alexander Medvedev
e1117ce4a6 chore: nicer event firing 2026-08-03 21:16:07 +02:00
Missing_Love
5eaf550a4c fix(core): fix skin metadata parsing and player info protocol version compatibility (#2525)
- Parse the `model` field for skin textures in `player.rs` to support the hat skin model
- Update `player_info_update.rs` to mask unsupported action flags based on the Minecraft version (e.g., ignore `UPDATE_LIST_PRIORITY` for versions prior to 1.21.2)
- Add the `UPDATE_HAT` flag in `world/mod.rs` and send it alongside `UPDATE_LIST_PRIORITY`
- Sync multi-version `tracked_data` JSON files to reflect the protocol changes

Signed-off-by: Missing_Love <42416195+Q2297045667@users.noreply.github.com>
2026-08-03 00:20:49 -04:00
Maxime Chaffraix
44b7cccc45 fix(entity): feeding a parrot a cookie poisons and kills it (#2564)
`ParrotEntity` had no interact handler, so a cookie used on a parrot did
nothing at all. Vanilla `Parrot.mobInteract` consumes the cookie, applies
poison for 900 ticks and then kills the parrot.

The branch is gated on the `parrot_poisonous_food` item tag rather than on
the cookie id, matching vanilla. Anything else falls through to the default
mob interaction, so leashing and name tags keep working.
2026-08-02 23:47:39 -04:00
Tomislav
ba95a301c1 feat: add hr_hr translation (#2529)
Co-authored-by: Tomislav Andric <tomo@Tomislavs-MacBook-Pro.local>
2026-08-02 23:35:49 -04:00
BitForge
d1aba46e48 fix(entity): reset fall distance on Spectator/Creative gamemode switch (#2382)
* fix(entity): reset fall distance on Spectator/Creative gamemode switch

Prevents fall damage when a player switches to Spectator mid-fall and
then back to Survival before landing.

This is a pragmatic workaround — vanilla achieves this through multiple
independent defense layers (noPhysics, per-tick reset, on_ground force,
mayfly check) rather than an explicit reset. The TODOs in the code
track the remaining gaps for a full vanilla-faithful implementation.

Fixes #2372

* docs(entity): document Creative fall-distance over-forgiveness edge case

Add TODO clarifying that once vanilla fall-damage layers 1-4 are
implemented, the reset should be restricted to Spectator only. In
vanilla a non-flying Creative player keeps fallDistance across a
Survival switch (guarded by abilities.mayfly in causeFallDamage);
resetting here over-forgives that edge case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* docs: condense fall damage comment to reference vanilla methods

Reduced comment from 23 lines to 6 by:
- Removing detailed explanations of vanilla defense layers
- Directly referencing Player.aiStep() and Player.causeFallDamage()
- Keeping only actionable TODOs
- Switching to /* */ style

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-08-02 23:23:53 -04:00
MythicSorcerer
3b0fdfa4f8 fix: persist air supply across relog (#2646)
Air was not saved to NBT, causing it to reset to full on every
login. This allowed players to exploit drowning by relogging to
restore lost air bubbles.
2026-08-02 20:11:53 +02:00
MythicSorcerer
28eefe7518 fix(combat): apply vanilla fist damage and attack speed modifiers (#2659)
The player attack function used base_damage (2.0) + add_damage (0.0) = 2.0
when attacking with an empty hand, but vanilla applies -1.0 base_attack_damage
and -2.4 base_attack_speed for the fist, resulting in 1.0 damage and 1.6
attack speed. This caused entities like cows (10 HP) to die in 5 hits
instead of 10.

Also fix the cooldown scaling formula to match vanilla: the entire
(base + modifier) should be scaled by cooldown, not just the modifier.
2026-08-02 20:11:08 +02:00
Eshan I.
b4aa65b4e9 fix(item): apply data-driven consumable effects (#2688) 2026-08-02 20:09:13 +02:00
Eshan I.
0b2ed1af38 fix(projectile): preserve arrow payloads (#2710) 2026-08-02 20:08:10 +02:00
Eshan I.
7844590958 fix(ai): damage endermen in rain (#2714) 2026-08-02 20:07:35 +02:00
Alexander Medvedev
f474756b16 fix: ci 2026-08-02 12:42:21 +02:00
Alexander Medvedev
98d4451fc9 chore: some fixes 2026-08-02 10:49:37 +02:00
Alexander Medvedev
141b49f973 chore: some more tests 2026-08-02 08:31:01 +02:00
Dark Star
b7ccef5b2f feat: add item frame entity and real comparator analog output (#2461)
* feat: add item frame entity and real comparator analog output

Item frames had no entity implementation, so frames loaded from
vanilla worlds fell into the generic entity fallback and lost their
Item, ItemRotation and Facing NBT on the next save. The comparator
also returned a hardcoded 1 for any attached frame.

Adds ItemFrameEntity (item frame + glow item frame) with vanilla NBT
round-trip, and makes the comparator return the vanilla signal:
0 when the frame is empty, otherwise rotation % 8 + 1. The frame
lookup now also includes glow item frames and matches on the frame's
stored facing instead of the yaw-derived horizontal facing.

* fix: mirror the default item frame facing into the entity data field

A frame created without NBT set facing to south but left the entity
data field at 0, which the spawn packet reads as down, so the frame
spawned facing the wrong way. Store the default in both places.
2026-08-02 00:26:17 -04:00
Oswald
c14d946a74 fix: transposed heightmap restore left resumed chunks with stone surfaces (#2448) 2026-08-02 00:03:30 -04:00
necko
038d467bfa fix: restore main hand and skin customization metadata across versions (#2630)
* fix(data): map missing main arm and skin tracked IDs for 1.21-1.21.6

* fix(player): send main hand and skin customisation metadata across versions

* fix(data): map missing main arm and skin tracked IDs in source JSON
2026-08-01 23:07:26 -04:00
PilkeySEK
f0c7332f05 perf: Make WasmPlugins be Arc<WasmPlugin> instead of Box<Arc<WasmPlugin>> (#2631)
* Make Plugin trait use &self instead of &mut self, don't make WasmPlugin be Box<Arc<T>>

* fix git thing
2026-08-01 15:02:36 +02:00
Alexander Medvedev
db1678e16f fix: ci 2026-08-01 12:33:02 +02:00
Alexander Medvedev
e74a3d4dda feat: handle signed plugins 2026-08-01 12:29:26 +02:00
Jamie Little
75994f3302 feat: /place command (#2473)
* Add /place template command with BlockPlacer trait and tab-completion support

- Add BlockPlacer trait to abstract block placement over ProtoChunk (worldgen)
  and WorldBlockPlacer (live command), used by place_template()
- Implement BlockPlacer for ProtoChunk (pumpkin-world) and WorldBlockPlacer
  (pumpkin crate)
- Add World::queue_block_updates() to insert into unsent_block_changes
  without triggering full set_block_state callbacks
- Generate _generated_all_template_names() at build time from structure
  assets for use in tab-completion suggestions
- Add TemplateNameArgumentType for the new command system with
  list_suggestions() using all_template_names()
- Implement /place template <template> [pos] in the new command system
  (CommandDispatcher, CommandExecutor, ArgumentBuilder)
- Fix borrow-across-await: clone template name to owned String early

* feat: add /place structure and /place jigsaw commands

Adds /place structure <id> [pos] for all structure types with two placement paths:
- Jigsaw structures (ancient_city, bastion_remnant, etc.): fast path using
  JigsawPlacement::add_pieces directly at the target position
- Non-jigsaw structures (desert_pyramid, end_city, etc.): generate pieces
  via dispatch, place into synthetic ProtoChunks with pre-seeded heightmaps
  and a stone floor so pieces can detect terrain, then delta-apply only
  changed blocks to the world via WorldBlockPlacer

Also adds /place jigsaw <pool> <target> <depth> [pos] for manual jigsaw
template placement.

Architecture:
- generate_structure_position() extracts the shared generator dispatch
  from try_generate_structure / lazily_generate_structure (both now
  delegate to it, eliminating ~150 lines of duplicated match arms)
- place_pool_element_templates() extracted from PoolElementStructurePiece
  for reuse by the command with WorldBlockPlacer
- StructureKeys gains from_name()/to_name()/all_names() via codegen
- StructureNameArgumentType and PoolNameArgumentType for tab-completion
- flat_ocean_floor_height_map made pub in ProtoChunk for heightmap seeding

* feat: add /place feature command

Adds /place feature <feature> [pos] for placing configured features
at a specific position. Resolves the PlacedFeature name via from_name(),
resolves the inner ConfiguredFeature from PLACED_FEATURES /
CONFIGURED_FEATURES, then calls ConfiguredFeature::generate() directly
at the target position -- skipping placement modifiers so the feature
appears exactly where specified.

Also adds /place structure improvements:
- Synthetic chunk terrain fill: stone below surface + grass on top, so
  pieces that carve through solid terrain (stronghold corridors, etc.)
  find material to work with. Snapshot/delta ensures only structure
  blocks reach the world.
- Shared snapshot_blocks() and apply_delta() helpers eliminate ~30 lines
  of duplicated diff logic between structure and feature paths.
- ground_y() and chunk_population_seed() helpers replace magic numbers.
- Structure success message now reports the structure name instead of
  the piece count.

Infrastructure:
- PlacedFeature::all_names() generated via pumpkin-codegen for
  tab-completion suggestions in PlacedFeatureNameArgumentType.
- GenerationCache trait implemented for ProtoChunk (single-chunk
  delegation) so ConfiguredFeature::generate() works without the full
  chunk-generation cache system.
- flat_ocean_floor_height_map made pub in ProtoChunk for heightmap
  seeding.
- configured_features and feature modules made pub for access from
  the command crate.

* fix(command): use world settings for place

* docs(place): clarify synthetic terrain delta behavior
2026-07-31 11:45:23 +02:00
Jamie Little
732aa24fe3 fix: persist block entity data on chunk save (#2452)
* feat(command): add /reload command

* feat: campfire cooking + block entity persistence for all entity types

- Implement full campfire cooking: 4-slot cooking, recipe lookup,
  auto-pop-off as ItemEntity or hopper insertion, config-gated manual
  pickup, Inventory/Clearable traits, tick with particle effects
- Add sync_write_items_to_nbt() utility for sync-safe inventory NBT
  serialization via try_lock()
- Extend add_block_entity() and update_block_entity() to persist NBT
  with id/x/y/z fields to pending_block_entities
- Fix migrate_pending_block_entities(): run once per chunk activation
  in update_active_chunks(), add already_loaded guard
- Add chunk_data_nbt() overrides to 35 block entity types — every
  entity with persistent state now correctly sends data to clients
  and survives chunk unload/reload

* style: cargo fmt

* rename: auto_pop_off -> campfire_auto_pop_off for clarity

* fix(persistence): report contended inventory slots

* refactor: split campfire cooking from persistence

* fix(command): remove stale reload registration
2026-07-31 11:44:42 +02:00
ZlordHUN
dfbf44805b feat: implement woodland mansion generation (#2654)
Co-authored-by: Zoltán Virágh <zoltan.viragh@cloudtalk.io>
2026-07-31 11:31:15 +02:00
Colin
938a627218 fix(item): prevent stacking items with different components (#2624) 2026-07-31 01:22:31 -04:00
Colin
bc61503db0 fix(block): correct berry bush and nether wart growth rates (#2621) 2026-07-31 01:13:57 -04:00
Owenn
3190f9ea72 fix: giving not working for numbers greater than 99 (#2596) 2026-07-31 01:07:30 -04:00
Roman Chebykin
4c0a40499e fix: use wolf-specific entity metadata tracker id (#2407) 2026-07-30 23:53:17 -04:00
Indrajeeth
4b1479607a fix: send correct block state ID when cancelling interact event (#2405)
The cancelled handler in handle_use_item_on sent block.id (BlockId)
instead of the actual BlockStateId, causing clients to see wrong
block states (e.g. stone appearing as snow) when plugins cancel
PlayerInteractEvent on right-click.
2026-07-30 23:18:49 -04:00
yhypno
f65b50d50f fix: prevent ender pearl teleport while sleeping (#2634) 2026-07-30 23:16:27 -04:00
yhypno
bd7a1a2126 fix(inventory): enchanting table offers and lapis validation (#2374)
* fix(inventory): match applied enchantments with table preview

* fix(inventory): require lapis for enchanting purchases
2026-07-30 23:08:38 -04:00
ZlordHUN
a3b66be27b feat: Implement pillager outpost structures (#2470) 2026-07-30 14:27:00 +02:00
Maxime Chaffraix
b024c3ae3a fix(entity): apply knockback resistance to living entities (#2498)
* fix(entity): apply knockback resistance to living entities

Vanilla LivingEntity.knockback scales strength by 1.0 - KNOCKBACK_RESISTANCE,
but Pumpkin never applied it, so mobs with high resistance (iron golem,
warden, ravager) were knocked back like any other mob.

Scale both knockback paths by the victim's resistance: the base hit knockback
in LivingEntity, and the sprint/enchant bonus in handle_knockback, which now
takes the victim as &dyn EntityBase so it can read the attribute.

Fixes #1761

* docs(entity): clarify knockback resistance is not applied in apply_knockback

The previous note read as if every caller had to pre-scale strength. Ender
dragon knockback mirrors vanilla Entity.push, which ignores resistance, so
spell out which callers scale and which don't.
2026-07-30 14:25:36 +02:00
Mettwasser
98fd79b57e feat(plugin-api): add display impl for uuid (#2497) 2026-07-30 14:24:19 +02:00
Eshan I.
cbc8af5d2d fix(block): bleach fire coral blocks when they dry out (#2571)
get_dead_coral_block_type mapped FIRE_CORAL_BLOCK to itself rather than
to DEAD_FIRE_CORAL_BLOCK, so a fire coral block left out of water stayed
alive forever while the other four colours bleached normally. The two
sibling tables for fans and plants both map it correctly.

The same table feeds BlockMetadata::ids, so this also stops the block
being registered twice and registers DEAD_FIRE_CORAL_BLOCK, which was
missing from the list.
2026-07-30 14:22:40 +02:00
Eshan I.
fe0c442a02 fix(player): apply food exhaustion when attacking and mining (#2578)
Vanilla Player#attack ends its successful-hit branch with
causeFoodExhaustion(0.1F), and Block#playerDestroy calls
player.causeFoodExhaustion(0.005F) for every block destroyed.

Pumpkin never called add_exhaustion from either path: the only callers
were the Hunger status effect in entity/living.rs and jump/sprint
movement in entity/player.rs. Combat and mining were therefore free, so
the hunger bar was effectively cosmetic for a player who was not
sprinting.

Player::attack now adds 0.1 exhaustion at the end of the hit path,
after the damage_with_context early-return, so only hits that actually
deal damage cost hunger. The Java and Bedrock block-break handlers now
add MINE_BLOCK_EXHAUSTION (0.005) per block broken.

Mining exhaustion is gated exactly where vanilla gates
Block#playerDestroy: ServerPlayerGameMode#destroyBlock skips it in
creative and when the block was broken without a tool that can harvest
it, so the call sites reuse the existing can_harvest / block_drop
checks rather than adding new conditions. Creative and spectator
players are additionally covered by the existing abilities.invulnerable
guard in Player::add_exhaustion, which mirrors vanilla
Player#causeFoodExhaustion.

Limitation: swimming exhaustion (0.01 per metre) is still missing.
Player::progress_motion only implements the onGround branch of vanilla
ServerPlayer#checkMovementStatistics; adding the swimming and in-water
branches requires the whole else-if chain plus movement-state plumbing
(Player::is_swimming is itself still an inferred approximation carrying
a TODO), so it is deliberately left out of this change.
2026-07-30 14:21:39 +02:00
Eshan I.
0be7e49e52 fix: let console and RCON run /fill and /setworldspawn (#2583)
CommandSender::world() returns None for console and RCON, so the two
commands that call it via ok_or(InvalidRequirement) fail there while
/setblock at the same coordinates succeeds. Five other call sites had
each grown their own inline fallback to the first world, which is also
what vanilla does for server-console commands.

Add world_or_first(server) with that fallback and use it, and fold the
duplicated logic in setblock and teleport into it. world() is left
unchanged because it is part of the versioned WASM plugin ABI.
2026-07-30 14:20:02 +02:00
yhypno
35de5d4e89 fix(block): damage shears when carving pumpkins (#2644) 2026-07-30 14:14:57 +02:00
Hugo Planque
f29a762ee7 feat(block): implement bubble columns (#2633) 2026-07-30 14:14:20 +02:00
Giovanni Giordano
0fe896892f docs: document pumpkin-nbt (#2648) 2026-07-30 14:13:47 +02:00
Alexander Medvedev
a2263c55cc chore: update bug report template 2026-07-30 12:55:41 +02:00
Eshan I.
27d485a934 fix: four item interaction bugs (#2610)
Flint and steel and fire charge lit any block carrying a lit property,
because can_be_lit searched the property list by name rather than checking
the block. That covers furnaces, smokers, blast furnaces, redstone lamps,
redstone torches, redstone ore and every copper bulb. Redstone lamps have
no use handler so the click fell straight through, and furnaces were
reachable by sneaking, which skips the block use handler. Gate on the
campfire, candle and candle cake tags, matching the three canLight
predicates vanilla checks. The extinguished branch above it was dead, as
no block in the generated data has that property, so it is removed.

The hoe called set_block_state outside its changed guard, so a click that
tilled nothing still rewrote the block to its default state. On a grass
block under a snow layer that cleared snowy and turned the block green.
Vanilla returns PASS and touches nothing.

Bone meal on bamboo could never grow it: the air check read the topmost
bamboo block rather than the space above it, so it always returned on the
first iteration. It also rolled 1 to 3 where vanilla rolls 1 to 2, and
grew from the original position rather than the top stalk.

The axe could not strip crimson and warped stems and hyphae, or bamboo
blocks. Bamboo is not in the logs tag, so the axis copy is extended to
cover it or a sideways bamboo block would snap upright when stripped.
2026-07-30 12:35:29 +02:00
Rito
f2ca934a7b fix(plugin): read native plugin metadata through its LazyLock (#2561)
The native loader reads METADATA as a `*const PluginMetadata`, but since
#1675 gave PluginMetadata owned String and Vec fields, `#[plugin_impl]`
has to export it as a `LazyLock` — a const can't allocate. The loader was
therefore reinterpreting the LazyLock's internals as a PluginMetadata.

Every native plugin ends up with an empty name and version. That alone
puts the data folder at plugins/ instead of plugins/<name>/ and makes
Context::register_permission reject every node, since it validates against
the plugin's namespace. And when the garbage string length happens not to
be zero, cloning the metadata takes the server down with a multi-terabyte
allocation request, which is what #2434 reports.

Go through a `*const LazyLock<PluginMetadata>` and deref it, which forces
the lock before the metadata is read.
2026-07-30 12:01:27 +02:00
Demetrius Kanios
5cb537dcba plugin-api: Improve PluginInitError messages (#2647) 2026-07-30 10:18:32 +02:00
Andbix
2577cfa3c9 feat(server): support F3+2 tick debug sample chart (#2636) 2026-07-29 19:59:08 +02:00
Demetrius Kanios
ef325c459e plugin-api: Rework filesystem permissions and move data folders. (#2643) 2026-07-29 09:36:22 +02:00
Missing_Love
8db9c013b1 docs: add description for Redundancy in contributing guidelines (#2556)
* Add Redundancy description

Signed-off-by: Missing_Love <42416195+Q2297045667@users.noreply.github.com>

* Update

Signed-off-by: Missing_Love <42416195+Q2297045667@users.noreply.github.com>

---------

Signed-off-by: Missing_Love <42416195+Q2297045667@users.noreply.github.com>
2026-07-26 23:20:32 -04:00
Jamie Little
ad31ce9889 fix: correct sound packet position encoding (was multiplied by 8 twice) (#2440)
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.
2026-07-26 23:06:00 -04:00