Commit Graph

2529 Commits

Author SHA1 Message Date
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
dorocha
5f127823ae feat(plugin-api): expose ItemStack, uuid, event and command arg types (#2526)
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).
2026-07-26 11:44:54 +02:00
Maxime Chaffraix
8a2075779b fix(worldgen): give the stronghold room chest a block entity (#2543)
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.
2026-07-26 11:39:46 +02:00
necko
ce4f3cc1f1 docs: fix broken chunk loading image link in README (#2547)
Signed-off-by: necko <128916594+Necko1@users.noreply.github.com>
2026-07-26 11:39:10 +02:00
Alexander Medvedev
ac89bff1ca fix: from_legacy_string 2026-07-26 10:25:13 +02:00
Alexander Medvedev
faf8c50d80 chore(mappings): add 1.7 & 1.8 2026-07-25 16:48:20 +02:00
Alexander Medvedev
40d7ed052f feat: add more mappings 2026-07-25 12:38:52 +02:00
Alexander Medvedev
25ba4c6e40 feat: added some Love 💞 2026-07-25 12:08:59 +02:00
Alexander Medvedev
cba7578e28 feat: add Leash 2026-07-25 10:51:55 +02:00
BouncingElf10
0dfaf5d213 feat(block): Added more dispenser behaviors (#2495)
* feat(block): added DispenseContext and drop_item abstractions for dispenser behavior

* feat(block): added specific arrow dispenser behavior

* feat(block): added specific spawn dispenser behavior

* docs(block): added some comments to quickly spot missing dispenser behaviors

* fix: addressed PR review feedback
2026-07-25 09:36:10 +02:00
vyPal
56de61783a fix: use networking.java.online_mode for online mode detection (#2404) 2026-07-25 09:31:39 +02:00
TheDarkSword
2d7cf40761 feat: persist item components that were only set at runtime (#2426)
* 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.
2026-07-25 09:29:46 +02:00
Maxime Chaffraix
64e9d97d7f fix(auth): don't require signatureRequired in texture profiles (#2499)
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
2026-07-25 09:28:05 +02:00
Afalinx
0d443944a7 fix(redstone): use vanilla pressure plate detection bounds (#2439)
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.
2026-07-24 19:22:19 +02:00
Redstone
6263b894ff fix(move_control): remove movement input reset while navigator owns movement (#2442) 2026-07-24 18:29:51 +02:00
Jamie Little
7552eff6b2 feat: data-driven mob spawn equipment system with vanilla-accurate gear (#2454)
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
2026-07-24 18:20:49 +02:00
MythicSorcerer
d529a6676a fix(egg): initialize git submodules during install (#2456)
* 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
2026-07-24 18:16:57 +02:00
Megalith
f676bdd222 fix(protocol): remap particle IDs for older clients (#2451)
* 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.
2026-07-24 18:14:18 +02:00
Jamie Little
3ff3eeaf74 perf(world): bulk-build generated chunk palettes (#2492) 2026-07-24 17:02:29 +02:00
dongzh1
b04471e800 fix(command): gate tab-complete suggestions on command permissions (#2312)
`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.
2026-07-24 16:36:39 +02:00
Alexander Medvedev
a956857209 readme: make vid loop 2026-07-24 12:40:59 +02:00