From 3a91a79e0341ad54afa396d75f0ddeae418d5a74 Mon Sep 17 00:00:00 2001 From: Doc Date: Tue, 8 Sep 2026 22:00:42 -0300 Subject: [PATCH 01/14] Start generator for BlockTransform Component --- .../item/blocktransform/DropStrategy.java | 10 ++++++++++ .../item/blocktransform/TransformParticle.java | 12 ++++++++++++ .../item/blocktransform/TransformType.java | 10 ++++++++++ .../item/blocktransform/package-info.java | 6 ++++++ .../main/java/io/papermc/generator/Rewriters.java | 6 ++++++ 5 files changed, 44 insertions(+) create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java new file mode 100644 index 000000000000..34227fb0dd36 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java @@ -0,0 +1,10 @@ +package io.papermc.paper.datacomponent.item.blocktransform; + +public enum DropStrategy { + + // Start generate - DropStrategy + CLICKED_FACE, + FROM_MIDDLE; + // End generate - DropStrategy + +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java new file mode 100644 index 000000000000..506b6ccd47b0 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java @@ -0,0 +1,12 @@ +package io.papermc.paper.datacomponent.item.blocktransform; + +public enum TransformParticle { + + // Start generate - TransformParticle + NONE, + SCRAPE, + WAX_ON, + WAX_OFF; + // End generate - TransformParticle + +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java new file mode 100644 index 000000000000..fa9ca0b55271 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java @@ -0,0 +1,10 @@ +package io.papermc.paper.datacomponent.item.blocktransform; + +public enum TransformType { + + // Start generate - TransformType + SINGLE_BLOCK, + COPPER_CHEST; + // End generate - TransformType + +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java new file mode 100644 index 000000000000..05be13806dd5 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java @@ -0,0 +1,6 @@ +@NullMarked +@MinecraftVersionDependent +package io.papermc.paper.datacomponent.item.blocktransform; + +import io.papermc.paper.annotation.MinecraftVersionDependent; +import org.jspecify.annotations.NullMarked; diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index 88adaaba7614..12c3f97f7498 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -24,6 +24,9 @@ import io.papermc.generator.types.goal.MobGoalNames; import io.papermc.generator.utils.Formatting; import io.papermc.paper.datacomponent.item.SwingAnimation; +import io.papermc.paper.datacomponent.item.blocktransform.DropStrategy; +import io.papermc.paper.datacomponent.item.blocktransform.TransformParticle; +import io.papermc.paper.datacomponent.item.blocktransform.TransformType; import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.entity.RemovalReason; @@ -180,6 +183,9 @@ protected EnumValue.Builder rewriteEnumValue(Rarity rarity) { ); } }) + .register("DropStrategy", DropStrategy.class, new EnumCloneRewriter<>(net.minecraft.core.component.BlockTransformer.DropStrategy.class)) + .register("TransformParticle", TransformParticle.class, new EnumCloneRewriter<>(net.minecraft.core.component.BlockTransformer.TransformParticle.class)) + .register("TransformType", TransformType.class, new EnumCloneRewriter<>(net.minecraft.core.component.BlockTransformer.TransformType.class)) .register(Material.class, composite( holder("Blocks", new MaterialRewriter.Blocks()), //holder("Material#isTransparent", MaterialRewriter.IsTransparent()), From 733cda3423084d6ef0c0cdaa4fcc72bb1f1cb788 Mon Sep 17 00:00:00 2001 From: Doc Date: Tue, 8 Sep 2026 22:01:29 -0300 Subject: [PATCH 02/14] Pseudo draft for implement BlockTransformer component --- .../paper/block/BlockStateProvider.java | 9 +++ .../blocktransform/BlockTransformData.java | 44 +++++++++++ .../item/blocktransform/BlockTransformer.java | 15 ++++ .../PaperBlockTransformData.java | 77 +++++++++++++++++++ .../PaperBlockTransformer.java | 21 +++++ .../item/blocktransformer/package-info.java | 7 ++ 6 files changed, 173 insertions(+) create mode 100644 paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java create mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java create mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java diff --git a/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java new file mode 100644 index 000000000000..0c1c6d452f9e --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java @@ -0,0 +1,9 @@ +package io.papermc.paper.block; + +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockStateProvider { +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java new file mode 100644 index 000000000000..0a3761f7497d --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java @@ -0,0 +1,44 @@ +package io.papermc.paper.datacomponent.item.blocktransform; + +import io.papermc.paper.block.BlockPredicate; +import java.util.List; +import net.kyori.adventure.key.Key; +import org.bukkit.block.BlockFace; +import org.checkerframework.checker.index.qual.NonNegative; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockTransformData { + + @Contract(pure = true) + BlockPredicate predicate(); + + @Contract(pure = true) + Key sound(); + + @Contract(pure = true) + TransformParticle particle(); + + @Contract(pure = true) + List disallowedFaces(); + + //Optional> loot(); + + @Contract(pure = true) + DropStrategy dropStrategy(); + + @Contract(pure = true) + boolean updateFromNeighbors(); + + @Contract(pure = true) + TransformType transformType(); + + @Contract(pure = true) + boolean consumeOnUse(); + + @Contract(pure = true) + @NonNegative int itemDamagePerUse(); +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java new file mode 100644 index 000000000000..7387dce93496 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java @@ -0,0 +1,15 @@ +package io.papermc.paper.datacomponent.item.blocktransform; + +import java.util.List; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockTransformer { + + @Contract(pure = true) + List transforms(); + +} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java new file mode 100644 index 000000000000..fef03c9e1bad --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -0,0 +1,77 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformData; +import io.papermc.paper.datacomponent.item.blocktransform.DropStrategy; +import io.papermc.paper.datacomponent.item.blocktransform.TransformParticle; +import io.papermc.paper.datacomponent.item.blocktransform.TransformType; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.PaperRegistrySets; +import java.util.List; +import net.kyori.adventure.key.Key; +import net.minecraft.core.component.BlockTransformer; +import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.util.Handleable; +import org.checkerframework.checker.index.qual.NonNegative; + +public record PaperBlockTransformData( + net.minecraft.core.component.BlockTransformer.BlockTransformData imlp +) implements BlockTransformData, Handleable { + + @Override + public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandle() { + return this.imlp; + } + + @Override + public BlockPredicate predicate() { + final BlockStateProvider blockStateProvider = this.imlp().blockStateProvider().value(); + blockStateProvider. + BlockPredicate.predicate() + .blocks(nms.blocks().map(blocks -> PaperRegistrySets.convertToApi(RegistryKey.BLOCK, blocks)).orElse(null)).build() + return null; + } + + @Override + public Key sound() { + return PaperAdventure.asAdventure(this.imlp().sound().value().location()); + } + + @Override + public TransformParticle particle() { + return TransformParticle.valueOf(this.imlp().particle().toString()); + } + + @Override + public List disallowedFaces() { + return this.imlp().disallowedFaces().stream().map(CraftBlock::notchToBlockFace).toList(); + } + + @Override + public DropStrategy dropStrategy() { + return DropStrategy.valueOf(this.imlp().dropStrategy().toString()); + } + + @Override + public boolean updateFromNeighbors() { + return this.imlp().updateFromNeighbors(); + } + + @Override + public TransformType transformType() { + return TransformType.valueOf(this.imlp().transformType().toString()); + } + + @Override + public boolean consumeOnUse() { + return this.imlp().consumeOnUse(); + } + + @Override + public @NonNegative int itemDamagePerUse() { + return this.imlp().itemDamagePerUse(); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java new file mode 100644 index 000000000000..fb254f60b02e --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java @@ -0,0 +1,21 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformData; +import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformer; +import java.util.List; +import org.bukkit.craftbukkit.util.Handleable; + +public record PaperBlockTransformer( + net.minecraft.core.component.BlockTransformer imlp +) implements BlockTransformer, Handleable { + + @Override + public net.minecraft.core.component.BlockTransformer getHandle() { + return this.imlp; + } + + @Override + public List transforms() { + return List.of(); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java new file mode 100644 index 000000000000..08508546229c --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java @@ -0,0 +1,7 @@ +/** + * Relating to block attacks for components. + */ +@NullMarked +package io.papermc.paper.datacomponent.item.blocktransformer; + +import org.jspecify.annotations.NullMarked; From 025854802a76891ed027342b329cc950db2ab32f Mon Sep 17 00:00:00 2001 From: Doc Date: Wed, 9 Sep 2026 12:47:25 -0300 Subject: [PATCH 03/14] Broken loottable --- .../item/blocktransform/BlockTransformData.java | 7 +++++-- .../blocktransformer/PaperBlockTransformData.java | 13 ++++++++++--- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java index 0a3761f7497d..95056699f7f1 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java @@ -4,10 +4,13 @@ import java.util.List; import net.kyori.adventure.key.Key; import org.bukkit.block.BlockFace; +import org.bukkit.loot.LootTable; import org.checkerframework.checker.index.qual.NonNegative; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; @NullMarked @ApiStatus.NonExtendable @@ -23,9 +26,9 @@ public interface BlockTransformData { TransformParticle particle(); @Contract(pure = true) - List disallowedFaces(); + @Unmodifiable List disallowedFaces(); - //Optional> loot(); + @Nullable LootTable lootTable(); @Contract(pure = true) DropStrategy dropStrategy(); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index fef03c9e1bad..1746b5b99a5b 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -9,12 +9,14 @@ import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.set.PaperRegistrySets; import java.util.List; +import java.util.Optional; import net.kyori.adventure.key.Key; import net.minecraft.core.component.BlockTransformer; import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.util.Handleable; +import org.bukkit.loot.LootTable; import org.checkerframework.checker.index.qual.NonNegative; public record PaperBlockTransformData( @@ -23,7 +25,7 @@ public record PaperBlockTransformData( @Override public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandle() { - return this.imlp; + return this.impl; } @Override @@ -46,8 +48,13 @@ public TransformParticle particle() { } @Override - public List disallowedFaces() { - return this.imlp().disallowedFaces().stream().map(CraftBlock::notchToBlockFace).toList(); + public @Unmodifiable List disallowedFaces() { + return this.impl.disallowedFaces().stream().map(CraftBlock::notchToBlockFace).toList(); + } + + @Override + public @Nullable LootTable lootTable() { + return this.impl.loot().map(CraftLootTable::minecraftToBukkit).orElse(null); } @Override From 6cee95a653c055fc5d3714bfe30a3be80716fc3c Mon Sep 17 00:00:00 2001 From: Doc Date: Thu, 10 Sep 2026 00:16:12 -0300 Subject: [PATCH 04/14] ReWork for move to Registry and make run --- .../registry/keys/BlockTransformerKeys.java | 61 +++++ .../paper/block/BlockStateProvider.java | 9 - .../stateprovider/BlockStateProvider.java | 28 ++ .../block/stateprovider/package-info.java | 4 + .../datacomponent/DataComponentTypes.java | 5 + .../blocktransform/BlockTransformData.java | 47 ---- .../item/blocktransform/BlockTransformer.java | 15 -- .../blocktransformer/BlockTransformData.java | 94 +++++++ .../BlockTransformTypesBridge.java | 23 ++ .../blocktransformer/BlockTransformer.java | 32 +++ .../DropStrategy.java | 2 +- .../TransformParticle.java | 2 +- .../TransformType.java | 2 +- .../package-info.java | 2 +- .../papermc/paper/registry/RegistryKey.java | 5 + .../data/BlockTransformerRegistryEntry.java | 54 ++++ .../paper/registry/event/RegistryEvents.java | 3 + .../java/io/papermc/generator/Rewriters.java | 10 +- .../generator/registry/RegistryEntries.java | 6 +- .../datacomponent/DataComponentAdapters.java | 3 +- .../BlockTransformTypesBridgeImpl.java | 17 ++ .../PaperBlockTransformData.java | 245 ++++++++++++++++-- .../PaperBlockTransformer.java | 39 ++- .../paper/registry/PaperRegistries.java | 4 + .../PaperBlockTransformerRegistryEntry.java | 59 +++++ ...blocktransformer.BlockTransformTypesBridge | 1 + 26 files changed, 659 insertions(+), 113 deletions(-) create mode 100644 paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTransformerKeys.java delete mode 100644 paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java delete mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java delete mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java rename paper-api/src/main/java/io/papermc/paper/datacomponent/item/{blocktransform => blocktransformer}/DropStrategy.java (69%) rename paper-api/src/main/java/io/papermc/paper/datacomponent/item/{blocktransform => blocktransformer}/TransformParticle.java (72%) rename paper-api/src/main/java/io/papermc/paper/datacomponent/item/{blocktransform => blocktransformer}/TransformType.java (69%) rename paper-api/src/main/java/io/papermc/paper/datacomponent/item/{blocktransform => blocktransformer}/package-info.java (70%) create mode 100644 paper-api/src/main/java/io/papermc/paper/registry/data/BlockTransformerRegistryEntry.java create mode 100644 paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridgeImpl.java create mode 100644 paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java create mode 100644 paper-server/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformTypesBridge diff --git a/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTransformerKeys.java b/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTransformerKeys.java new file mode 100644 index 000000000000..cdf0d9f5ac93 --- /dev/null +++ b/paper-api/src/generated/java/io/papermc/paper/registry/keys/BlockTransformerKeys.java @@ -0,0 +1,61 @@ +package io.papermc.paper.registry.keys; + +import static net.kyori.adventure.key.Key.key; + +import io.papermc.paper.annotation.GeneratedClass; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; +import net.kyori.adventure.key.Key; +import org.jspecify.annotations.NullMarked; + +/** + * Vanilla keys for {@link RegistryKey#BLOCK_TRANSFORMER}. + * + * @apiNote The fields provided here are a direct representation of + * what is available from the vanilla game source. They may be + * changed (including removals) on any Minecraft version + * bump, so cross-version compatibility is not provided on the + * same level as it is on most of the other API. + */ +@SuppressWarnings({ + "unused", + "SpellCheckingInspection" +}) +@NullMarked +@GeneratedClass +public final class BlockTransformerKeys { + /** + * {@code minecraft:axe} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey AXE = create(key("axe")); + + /** + * {@code minecraft:hoe} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey HOE = create(key("hoe")); + + /** + * {@code minecraft:shovel} + * + * @apiNote This field is version-dependant and may be removed in future Minecraft versions + */ + public static final TypedKey SHOVEL = create(key("shovel")); + + private BlockTransformerKeys() { + } + + /** + * Creates a typed key for {@link BlockTransformer} in the registry {@code minecraft:block_transformer}. + * + * @param key the value's key in the registry + * @return a new typed key + */ + public static TypedKey create(final Key key) { + return TypedKey.create(RegistryKey.BLOCK_TRANSFORMER, key); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java deleted file mode 100644 index 0c1c6d452f9e..000000000000 --- a/paper-api/src/main/java/io/papermc/paper/block/BlockStateProvider.java +++ /dev/null @@ -1,9 +0,0 @@ -package io.papermc.paper.block; - -import org.jetbrains.annotations.ApiStatus; -import org.jspecify.annotations.NullMarked; - -@NullMarked -@ApiStatus.NonExtendable -public interface BlockStateProvider { -} diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java new file mode 100644 index 000000000000..c0f3bab26109 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java @@ -0,0 +1,28 @@ +package io.papermc.paper.block.stateprovider; + +import org.bukkit.block.data.BlockData; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockStateProvider { + + @Contract(value = "_ -> new", pure = true) + static BlockStateProvider simple(final BlockData blockData) { + // + record SimpleProviderImpl(@Nullable BlockData blockData) implements BlockStateProvider { + @Override + public @Nullable BlockData simple() { + return this.blockData; + } + } + // + return new SimpleProviderImpl(blockData); + } + + @Nullable BlockData simple(); + +} diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java new file mode 100644 index 000000000000..f9b604448f25 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.block.stateprovider; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java index 6b0c37203bb6..1d8d4ad6bd4c 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/DataComponentTypes.java @@ -49,6 +49,7 @@ import io.papermc.paper.datacomponent.item.Weapon; import io.papermc.paper.datacomponent.item.WritableBookContent; import io.papermc.paper.datacomponent.item.WrittenBookContent; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; import io.papermc.paper.item.MapPostProcessing; import io.papermc.paper.registry.set.RegistryKeySet; import java.util.List; @@ -215,6 +216,10 @@ public final class DataComponentTypes { * Controls the behavior of the item as a tool. */ public static final DataComponentType.Valued TOOL = valued("tool"); + /** + * Controls how an item transforms blocks when used on them. + */ + public static final DataComponentType.Valued BLOCK_TRANSFORMER = valued("block_transformer"); public static final DataComponentType.Valued WEAPON = valued("weapon"); public static final DataComponentType.Valued ATTACK_RANGE = valued("attack_range"); public static final DataComponentType.Valued ENCHANTABLE = valued("enchantable"); diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java deleted file mode 100644 index 95056699f7f1..000000000000 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformData.java +++ /dev/null @@ -1,47 +0,0 @@ -package io.papermc.paper.datacomponent.item.blocktransform; - -import io.papermc.paper.block.BlockPredicate; -import java.util.List; -import net.kyori.adventure.key.Key; -import org.bukkit.block.BlockFace; -import org.bukkit.loot.LootTable; -import org.checkerframework.checker.index.qual.NonNegative; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Contract; -import org.jetbrains.annotations.Unmodifiable; -import org.jspecify.annotations.NullMarked; -import org.jspecify.annotations.Nullable; - -@NullMarked -@ApiStatus.NonExtendable -public interface BlockTransformData { - - @Contract(pure = true) - BlockPredicate predicate(); - - @Contract(pure = true) - Key sound(); - - @Contract(pure = true) - TransformParticle particle(); - - @Contract(pure = true) - @Unmodifiable List disallowedFaces(); - - @Nullable LootTable lootTable(); - - @Contract(pure = true) - DropStrategy dropStrategy(); - - @Contract(pure = true) - boolean updateFromNeighbors(); - - @Contract(pure = true) - TransformType transformType(); - - @Contract(pure = true) - boolean consumeOnUse(); - - @Contract(pure = true) - @NonNegative int itemDamagePerUse(); -} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java deleted file mode 100644 index 7387dce93496..000000000000 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/BlockTransformer.java +++ /dev/null @@ -1,15 +0,0 @@ -package io.papermc.paper.datacomponent.item.blocktransform; - -import java.util.List; -import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.Contract; -import org.jspecify.annotations.NullMarked; - -@NullMarked -@ApiStatus.NonExtendable -public interface BlockTransformer { - - @Contract(pure = true) - List transforms(); - -} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java new file mode 100644 index 000000000000..2b33bf338314 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java @@ -0,0 +1,94 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.block.stateprovider.BlockStateProvider; +import io.papermc.paper.datacomponent.BuildableDataComponent; +import io.papermc.paper.datacomponent.DataComponentBuilder; +import java.util.List; +import net.kyori.adventure.key.Key; +import org.bukkit.block.BlockFace; +import org.bukkit.loot.LootTable; +import org.checkerframework.checker.index.qual.NonNegative; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockTransformData extends BuildableDataComponent { + + @Contract(value = "_ -> new", pure = true) + static BlockTransformData.Builder blockTransformData(final BlockStateProvider blockStateProvider) { + return BlockTransformTypesBridge.bridge().blockTransformData(blockStateProvider); + } + + @Contract(value = "_, _ -> new", pure = true) + static BlockTransformData.Builder blockTransformData(final BlockPredicate predicate, final BlockStateProvider blockStateProvider) { + return BlockTransformTypesBridge.bridge().blockTransformData(predicate, blockStateProvider); + } + + @Contract(pure = true) + BlockStateProvider blockStateProvider(); + + @Contract(pure = true) + Key sound(); + + @Contract(pure = true) + TransformParticle particle(); + + @Contract(pure = true) + @Unmodifiable List disallowedFaces(); + + @Nullable LootTable lootTable(); + + @Contract(pure = true) + DropStrategy dropStrategy(); + + @Contract(pure = true) + boolean updateFromNeighbors(); + + @Contract(pure = true) + TransformType transformType(); + + @Contract(pure = true) + boolean consumeOnUse(); + + @Contract(pure = true) + @NonNegative int itemDamagePerUse(); + + @ApiStatus.NonExtendable + interface Builder extends DataComponentBuilder { + + @Contract(value = "_ -> this", mutates = "this") + Builder sound(Key sound); + + @Contract(value = "_ -> this", mutates = "this") + Builder particle(TransformParticle particle); + + @Contract(value = "_ -> this", mutates = "this") + Builder disallowedFaces(List disallowedFaces); + + @Contract(value = "_ -> this", mutates = "this") + Builder addDisallowedFace(BlockFace disallowedFace); + + @Contract(value = "_ -> this", mutates = "this") + Builder lootTable(@Nullable LootTable lootTable); + + @Contract(value = "_ -> this", mutates = "this") + Builder dropStrategy(DropStrategy dropStrategy); + + @Contract(value = "_ -> this", mutates = "this") + Builder updateFromNeighbors(boolean updateFromNeighbors); + + @Contract(value = "_ -> this", mutates = "this") + Builder transformType(TransformType transformType); + + @Contract(value = "_ -> this", mutates = "this") + Builder consumeOnUse(boolean consumeOnUse); + + @Contract(value = "_ -> this", mutates = "this") + Builder itemDamagePerUse(@NonNegative int itemDamagePerUse); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java new file mode 100644 index 000000000000..ef07508c5581 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java @@ -0,0 +1,23 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.block.stateprovider.BlockStateProvider; +import java.util.Optional; +import java.util.ServiceLoader; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.Internal +interface BlockTransformTypesBridge { + + Optional BRIDGE = ServiceLoader.load(BlockTransformTypesBridge.class, BlockTransformTypesBridge.class.getClassLoader()).findFirst(); + + static BlockTransformTypesBridge bridge() { + return BRIDGE.orElseThrow(); + } + + BlockTransformData.Builder blockTransformData(BlockStateProvider blockStateProvider); + + BlockTransformData.Builder blockTransformData(BlockPredicate predicate, BlockStateProvider blockStateProvider); +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java new file mode 100644 index 000000000000..cee737d49048 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java @@ -0,0 +1,32 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import java.util.List; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; +import org.bukkit.Keyed; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@ApiStatus.NonExtendable +public interface BlockTransformer extends Keyed { + + // Start generate - BlockTransformer + BlockTransformer AXE = getBlockTransformer("axe"); + + BlockTransformer HOE = getBlockTransformer("hoe"); + + BlockTransformer SHOVEL = getBlockTransformer("shovel"); + // End generate - BlockTransformer + + private static BlockTransformer getBlockTransformer(final @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.BLOCK_TRANSFORMER).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + + @Contract(pure = true) + @Unmodifiable List transforms(); +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/DropStrategy.java similarity index 69% rename from paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java rename to paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/DropStrategy.java index 34227fb0dd36..5ff6d50d5e59 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/DropStrategy.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/DropStrategy.java @@ -1,4 +1,4 @@ -package io.papermc.paper.datacomponent.item.blocktransform; +package io.papermc.paper.datacomponent.item.blocktransformer; public enum DropStrategy { diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformParticle.java similarity index 72% rename from paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java rename to paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformParticle.java index 506b6ccd47b0..1c7310bb5f03 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformParticle.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformParticle.java @@ -1,4 +1,4 @@ -package io.papermc.paper.datacomponent.item.blocktransform; +package io.papermc.paper.datacomponent.item.blocktransformer; public enum TransformParticle { diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformType.java similarity index 69% rename from paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java rename to paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformType.java index fa9ca0b55271..201aa18b7f6e 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/TransformType.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/TransformType.java @@ -1,4 +1,4 @@ -package io.papermc.paper.datacomponent.item.blocktransform; +package io.papermc.paper.datacomponent.item.blocktransformer; public enum TransformType { diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java similarity index 70% rename from paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java rename to paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java index 05be13806dd5..78553e87e249 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransform/package-info.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/package-info.java @@ -1,6 +1,6 @@ @NullMarked @MinecraftVersionDependent -package io.papermc.paper.datacomponent.item.blocktransform; +package io.papermc.paper.datacomponent.item.blocktransformer; import io.papermc.paper.annotation.MinecraftVersionDependent; import org.jspecify.annotations.NullMarked; diff --git a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java index 832a93327397..3821036b3800 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/RegistryKey.java @@ -2,6 +2,7 @@ import io.papermc.paper.block.pot.PotPatternType; import io.papermc.paper.datacomponent.DataComponentType; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.entity.poi.PoiType; import io.papermc.paper.registry.tag.TagKey; @@ -269,6 +270,10 @@ public sealed interface RegistryKey extends Keyed permits RegistryKeyImpl { * @see io.papermc.paper.registry.keys.DialogKeys */ RegistryKey DIALOG = create("dialog"); + /** + * Data-driven registry for block transformers. + */ + RegistryKey BLOCK_TRANSFORMER = create("block_transformer"); /* ******************* * diff --git a/paper-api/src/main/java/io/papermc/paper/registry/data/BlockTransformerRegistryEntry.java b/paper-api/src/main/java/io/papermc/paper/registry/data/BlockTransformerRegistryEntry.java new file mode 100644 index 000000000000..f765d5446f0a --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/registry/data/BlockTransformerRegistryEntry.java @@ -0,0 +1,54 @@ +package io.papermc.paper.registry.data; + +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformData; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.registry.RegistryBuilder; +import java.util.List; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; + +/** + * A data-centric version-specific registry entry for the {@link BlockTransformer} type. + */ +@ApiStatus.NonExtendable +public interface BlockTransformerRegistryEntry { + + /** + * Gets the ordered transforms for this block transformer. + * + * @return the transforms + */ + @Contract(pure = true) + @Unmodifiable List transforms(); + + /** + * A mutable builder for the {@link BlockTransformerRegistryEntry} plugins may change in applicable registry events. + *

+ * The following values are required for each builder: + *

    + *
  • {@link #addTransform(BlockTransformData)} or {@link #addTransforms(List)}
  • + *
+ */ + @ApiStatus.NonExtendable + interface Builder extends BlockTransformerRegistryEntry, RegistryBuilder { + + /** + * Adds a transform to this block transformer. + * + * @param transform transform to add + * @return this builder instance + */ + @Contract(value = "_ -> this", mutates = "this") + Builder addTransform(BlockTransformData transform); + + /** + * Adds transforms to this block transformer. + * + * @param transforms transforms to add + * @return this builder instance + */ + @Contract(value = "_ -> this", mutates = "this") + Builder addTransforms(List transforms); + } +} diff --git a/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java b/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java index ed59510b3f5d..867d1c2c0a2c 100644 --- a/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java +++ b/paper-api/src/main/java/io/papermc/paper/registry/event/RegistryEvents.java @@ -1,9 +1,11 @@ package io.papermc.paper.registry.event; import io.papermc.paper.block.pot.PotPatternType; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.data.BannerPatternRegistryEntry; +import io.papermc.paper.registry.data.BlockTransformerRegistryEntry; import io.papermc.paper.registry.data.CatTypeRegistryEntry; import io.papermc.paper.registry.data.ChickenVariantRegistryEntry; import io.papermc.paper.registry.data.CowVariantRegistryEntry; @@ -68,6 +70,7 @@ public final class RegistryEvents { public static final RegistryEventProvider ZOMBIE_NAUTILUS_VARIANT = create(RegistryKey.ZOMBIE_NAUTILUS_VARIANT); public static final RegistryEventProvider SULFUR_CUBE_ARCHETYPE = create(RegistryKey.SULFUR_CUBE_ARCHETYPE); public static final RegistryEventProvider DIALOG = create(RegistryKey.DIALOG); + public static final RegistryEventProvider BLOCK_TRANSFORMER = create(RegistryKey.BLOCK_TRANSFORMER); // End generate - RegistryEvents private RegistryEvents() { diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index 12c3f97f7498..c2bc5bf08024 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -24,9 +24,10 @@ import io.papermc.generator.types.goal.MobGoalNames; import io.papermc.generator.utils.Formatting; import io.papermc.paper.datacomponent.item.SwingAnimation; -import io.papermc.paper.datacomponent.item.blocktransform.DropStrategy; -import io.papermc.paper.datacomponent.item.blocktransform.TransformParticle; -import io.papermc.paper.datacomponent.item.blocktransform.TransformType; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.datacomponent.item.blocktransformer.DropStrategy; +import io.papermc.paper.datacomponent.item.blocktransformer.TransformParticle; +import io.papermc.paper.datacomponent.item.blocktransformer.TransformType; import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.entity.RemovalReason; @@ -255,7 +256,8 @@ protected String rewriteFieldType(Holder.Reference(Registries.BLOCK_TRANSFORMER, "getBlockTransformer")); RegistryBootstrapper.bootstrapApi(sourceSet); } diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index f4168a3f884d..91f05ff9f1c6 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -4,9 +4,11 @@ import io.papermc.paper.block.pot.PotPatternType; import io.papermc.paper.datacomponent.DataComponentType; import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.entity.poi.PoiTypes; import io.papermc.paper.registry.data.BannerPatternRegistryEntry; +import io.papermc.paper.registry.data.BlockTransformerRegistryEntry; import io.papermc.paper.registry.data.CatTypeRegistryEntry; import io.papermc.paper.registry.data.ChickenVariantRegistryEntry; import io.papermc.paper.registry.data.CowVariantRegistryEntry; @@ -69,6 +71,7 @@ import net.minecraft.world.item.Items; import net.minecraft.world.item.JukeboxSongs; import net.minecraft.world.item.alchemy.Potions; +import net.minecraft.world.item.component.BlockTransformers; import net.minecraft.world.item.enchantment.Enchantments; import net.minecraft.world.item.equipment.trim.TrimMaterials; import net.minecraft.world.item.equipment.trim.TrimPatterns; @@ -213,7 +216,8 @@ private static RegistryEntry inconsistentEntry(ResourceKey> API_ONLY = List.of( diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java index 5e4c51049e03..ae8ede87a3ef 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/DataComponentAdapters.java @@ -49,6 +49,7 @@ import io.papermc.paper.datacomponent.item.PaperWeapon; import io.papermc.paper.datacomponent.item.PaperWritableBookContent; import io.papermc.paper.datacomponent.item.PaperWrittenBookContent; +import io.papermc.paper.datacomponent.item.blocktransformer.PaperBlockTransformer; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.data.util.Conversions; import io.papermc.paper.registry.set.PaperRegistrySets; @@ -189,7 +190,7 @@ public static void bootstrap() { register(DataComponents.ATTACK_ANIMATION, PaperSwingAnimation::new); register(DataComponents.INTERACT_ANIMATION, PaperSwingAnimation::new); // registerIdentity(DataComponents.ADDITIONAL_TRADE_COST); - // block transformer + register(DataComponents.BLOCK_TRANSFORMER, PaperBlockTransformer::minecraftHolderToBukkit, PaperBlockTransformer::bukkitToMinecraftHolder); register(DataComponents.VILLAGER_FOOD, PaperVillagerFood::new); register(DataComponents.MOB_VISIBILITY, PaperMobVisibility::new); register(DataComponents.VILLAGER_VARIANT, CraftVillager.CraftType::minecraftHolderToBukkit, CraftVillager.CraftType::bukkitToMinecraftHolder); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridgeImpl.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridgeImpl.java new file mode 100644 index 000000000000..22919fb67d18 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridgeImpl.java @@ -0,0 +1,17 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.block.stateprovider.BlockStateProvider; + +public final class BlockTransformTypesBridgeImpl implements BlockTransformTypesBridge { + + @Override + public BlockTransformData.Builder blockTransformData(final BlockStateProvider blockStateProvider) { + return new PaperBlockTransformData.BuilderImpl(blockStateProvider); + } + + @Override + public BlockTransformData.Builder blockTransformData(final BlockPredicate predicate, final BlockStateProvider blockStateProvider) { + return new PaperBlockTransformData.BuilderImpl(predicate, blockStateProvider); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 1746b5b99a5b..5a9342df89b1 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -2,25 +2,37 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.block.BlockPredicate; -import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformData; -import io.papermc.paper.datacomponent.item.blocktransform.DropStrategy; -import io.papermc.paper.datacomponent.item.blocktransform.TransformParticle; -import io.papermc.paper.datacomponent.item.blocktransform.TransformType; -import io.papermc.paper.registry.RegistryKey; -import io.papermc.paper.registry.set.PaperRegistrySets; +import io.papermc.paper.registry.PaperRegistries; +import java.util.ArrayList; import java.util.List; import java.util.Optional; import net.kyori.adventure.key.Key; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.Vec3i; import net.minecraft.core.component.BlockTransformer; -import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; +import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; +import net.minecraft.world.level.levelgen.blockpredicates.MatchingBlocksPredicate; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.loot.LootTable; import org.checkerframework.checker.index.qual.NonNegative; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.Nullable; + +import static io.papermc.paper.util.BoundChecker.requireNonNegative; public record PaperBlockTransformData( - net.minecraft.core.component.BlockTransformer.BlockTransformData imlp + net.minecraft.core.component.BlockTransformer.BlockTransformData impl ) implements BlockTransformData, Handleable { @Override @@ -29,22 +41,22 @@ public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandl } @Override - public BlockPredicate predicate() { - final BlockStateProvider blockStateProvider = this.imlp().blockStateProvider().value(); - blockStateProvider. - BlockPredicate.predicate() - .blocks(nms.blocks().map(blocks -> PaperRegistrySets.convertToApi(RegistryKey.BLOCK, blocks)).orElse(null)).build() - return null; + public io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider() { + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = unwrapStateProvider(this.impl.blockStateProvider().value()); + if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { + return io.papermc.paper.block.stateprovider.BlockStateProvider.simple(CraftBlockData.createData(state)); + } + throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } @Override public Key sound() { - return PaperAdventure.asAdventure(this.imlp().sound().value().location()); + return PaperAdventure.asAdventure(this.impl.sound().value().location()); } @Override public TransformParticle particle() { - return TransformParticle.valueOf(this.imlp().particle().toString()); + return TransformParticle.valueOf(this.impl.particle().name()); } @Override @@ -59,26 +71,217 @@ public TransformParticle particle() { @Override public DropStrategy dropStrategy() { - return DropStrategy.valueOf(this.imlp().dropStrategy().toString()); + return DropStrategy.valueOf(this.impl.dropStrategy().name()); } @Override public boolean updateFromNeighbors() { - return this.imlp().updateFromNeighbors(); + return this.impl.updateFromNeighbors(); } @Override public TransformType transformType() { - return TransformType.valueOf(this.imlp().transformType().toString()); + return TransformType.valueOf(this.impl.transformType().name()); } @Override public boolean consumeOnUse() { - return this.imlp().consumeOnUse(); + return this.impl.consumeOnUse(); } @Override public @NonNegative int itemDamagePerUse() { - return this.imlp().itemDamagePerUse(); + return this.impl.itemDamagePerUse(); + } + + @Override + public Builder toBuilder() { + return new BuilderImpl(this.blockStateProvider()) + .sound(this.sound()) + .particle(this.particle()) + .disallowedFaces(this.disallowedFaces()) + .dropStrategy(this.dropStrategy()) + .updateFromNeighbors(this.updateFromNeighbors()) + .transformType(this.transformType()) + .consumeOnUse(this.consumeOnUse()) + .itemDamagePerUse(this.itemDamagePerUse()); + } + + public static net.minecraft.core.component.BlockTransformer.BlockTransformData toVanilla(final BlockTransformData data) { + if (data instanceof final PaperBlockTransformData paperBlockTransformData) { + return paperBlockTransformData.getHandle(); + } + return new net.minecraft.core.component.BlockTransformer.BlockTransformData( + Holder.direct(toVanillaStateProvider(data.blockStateProvider())), + PaperAdventure.resolveSound(data.sound()), + net.minecraft.core.component.BlockTransformer.TransformParticle.valueOf(data.particle().name()), + data.disallowedFaces().stream().map(PaperBlockTransformData::toVanillaDirection).toList(), + java.util.Optional.empty(), + net.minecraft.core.component.BlockTransformer.DropStrategy.valueOf(data.dropStrategy().name()), + data.updateFromNeighbors(), + net.minecraft.core.component.BlockTransformer.TransformType.valueOf(data.transformType().name()), + data.consumeOnUse(), + data.itemDamagePerUse() + ); + } + + private static Direction toVanillaDirection(final BlockFace blockFace) { + final Direction direction = CraftBlock.blockFaceToNotch(blockFace); + if (direction == null) { + throw new IllegalArgumentException("Unsupported block face: " + blockFace); + } + return direction; + } + + private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanillaStateProvider( + final io.papermc.paper.block.stateprovider.BlockStateProvider provider + ) { + final BlockData simple = provider.simple(); + if (simple == null) { + throw new UnsupportedOperationException("Unsupported block state provider type"); + } + if (!(simple instanceof final CraftBlockData craftBlockData)) { + throw new IllegalArgumentException("Unsupported BlockData implementation: " + simple.getClass().getName()); + } + return new SimpleStateProvider(craftBlockData.getState()); + } + + private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider unwrapStateProvider( + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider + ) { + if (provider instanceof RuleBasedStateProvider( + Holder fallback, + List rules + ) + && fallback == null + && rules.size() == 1) { + return unwrapStateProvider(rules.getFirst().then().value()); + } + return provider; + } + + static final class BuilderImpl implements Builder { + + private final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider; + private @Nullable BlockPredicate predicate; + private Key sound = Key.key("minecraft:empty"); + private TransformParticle particle = TransformParticle.NONE; + private final List disallowedFaces = new ArrayList<>(); + private Optional> lootTable = Optional.empty(); + private DropStrategy dropStrategy = DropStrategy.FROM_MIDDLE; + private boolean updateFromNeighbors = true; + private TransformType transformType = TransformType.SINGLE_BLOCK; + private boolean consumeOnUse = true; + private int itemDamagePerUse = 1; + + BuilderImpl(final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider) { + this.blockStateProvider = blockStateProvider; + } + + BuilderImpl(final BlockPredicate blockPredicate, final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider) { + this.predicate = blockPredicate; + this.blockStateProvider = blockStateProvider; + } + + @Override + public Builder sound(final Key sound) { + this.sound = sound; + return this; + } + + @Override + public Builder particle(final TransformParticle particle) { + this.particle = particle; + return this; + } + + @Override + public Builder disallowedFaces(final List disallowedFaces) { + this.disallowedFaces.clear(); + this.disallowedFaces.addAll(disallowedFaces); + return this; + } + + @Override + public Builder addDisallowedFace(final BlockFace disallowedFace) { + this.disallowedFaces.add(disallowedFace); + return this; + } + + @Override + public Builder lootTable(@Nullable final LootTable lootTable) { + this.lootTable = Optional.ofNullable(lootTable).map(CraftLootTable::bukkitToMinecraft); + return this; + } + + @Override + public Builder dropStrategy(final DropStrategy dropStrategy) { + this.dropStrategy = dropStrategy; + return this; + } + + @Override + public Builder updateFromNeighbors(final boolean updateFromNeighbors) { + this.updateFromNeighbors = updateFromNeighbors; + return this; + } + + @Override + public Builder transformType(final TransformType transformType) { + this.transformType = transformType; + return this; + } + + @Override + public Builder consumeOnUse(final boolean consumeOnUse) { + this.consumeOnUse = consumeOnUse; + return this; + } + + @Override + public Builder itemDamagePerUse(final @NonNegative int itemDamagePerUse) { + this.itemDamagePerUse = requireNonNegative(itemDamagePerUse, "itemDamagePerUse"); + return this; + } + + @Override + public BlockTransformData build() { + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = toVanillaStateProvider(this.blockStateProvider); + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = this.predicate == null + ? targetProvider + : RuleBasedStateProvider.builder().ifTrueThenProvide(toVanillaBlockPredicate(this.predicate), targetProvider).build(); + return new PaperBlockTransformData(new net.minecraft.core.component.BlockTransformer.BlockTransformData( + Holder.direct(provider), + PaperAdventure.resolveSound(this.sound), + net.minecraft.core.component.BlockTransformer.TransformParticle.valueOf(this.particle.name()), + this.disallowedFaces.stream().map(PaperBlockTransformData::toVanillaDirection).toList(), + this.lootTable, + net.minecraft.core.component.BlockTransformer.DropStrategy.valueOf(this.dropStrategy.name()), + this.updateFromNeighbors, + net.minecraft.core.component.BlockTransformer.TransformType.valueOf(this.transformType.name()), + this.consumeOnUse, + this.itemDamagePerUse + )); + } + } + + private static net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate toVanillaBlockPredicate(final BlockPredicate predicate) { + if (predicate.blocks() == null) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + } + final List> blockHolders = predicate.blocks().values().stream() + .map(PaperRegistries::toNms) + .map(key -> { + final Block block = BuiltInRegistries.BLOCK.getValue(key.identifier()); + if (block == null) { + throw new IllegalArgumentException("Unknown block key: " + key.identifier()); + } + return BuiltInRegistries.BLOCK.wrapAsHolder(block); + }) + .toList(); + return new MatchingBlocksPredicate( + Vec3i.ZERO, + HolderSet.direct(blockHolders) + ); } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java index fb254f60b02e..473fd520e552 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformer.java @@ -1,21 +1,38 @@ package io.papermc.paper.datacomponent.item.blocktransformer; -import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformData; -import io.papermc.paper.datacomponent.item.blocktransform.BlockTransformer; import java.util.List; -import org.bukkit.craftbukkit.util.Handleable; +import io.papermc.paper.registry.HolderableBase; +import net.minecraft.core.Holder; +import net.minecraft.core.registries.Registries; +import org.bukkit.craftbukkit.CraftRegistry; +import org.jetbrains.annotations.Unmodifiable; -public record PaperBlockTransformer( - net.minecraft.core.component.BlockTransformer imlp -) implements BlockTransformer, Handleable { +public final class PaperBlockTransformer extends HolderableBase implements BlockTransformer { - @Override - public net.minecraft.core.component.BlockTransformer getHandle() { - return this.imlp; + public static BlockTransformer minecraftHolderToBukkit(final Holder minecraft) { + return CraftRegistry.minecraftHolderToBukkit(minecraft, Registries.BLOCK_TRANSFORMER); + } + + public static Holder bukkitToMinecraftHolder(final BlockTransformer bukkit) { + return CraftRegistry.bukkitToMinecraftHolder(bukkit); + } + + public PaperBlockTransformer(final Holder holder) { + super(holder); } @Override - public List transforms() { - return List.of(); + public @Unmodifiable List transforms() { + return this.getHandle().transforms().stream().map(PaperBlockTransformData::new).map(BlockTransformData.class::cast).toList(); + } + + public static Holder abukkitToMinecraftHolder(final BlockTransformer blockTransformer) { + if (!(blockTransformer instanceof final PaperBlockTransformer paper)) { + throw new IllegalArgumentException("Custom block_transformer values must be registered in minecraft:block_transformer before syncing to clients"); + } + if (paper.getHolder().kind() != Holder.Kind.REFERENCE) { + throw new IllegalArgumentException("Custom block_transformer values must be registered in minecraft:block_transformer before syncing to clients"); + } + return paper.getHolder(); } } diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index cb0c47449474..b9c0ebd9732d 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -6,11 +6,14 @@ import io.papermc.paper.block.pot.PotPatternType; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.PaperDataComponentType; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.datacomponent.item.blocktransformer.PaperBlockTransformer; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.PaperDialog; import io.papermc.paper.entity.poi.PaperPoiType; import io.papermc.paper.entity.poi.PoiTypes; import io.papermc.paper.registry.data.PaperBannerPatternRegistryEntry; +import io.papermc.paper.registry.data.PaperBlockTransformerRegistryEntry; import io.papermc.paper.registry.data.PaperCatTypeRegistryEntry; import io.papermc.paper.registry.data.PaperChickenVariantRegistryEntry; import io.papermc.paper.registry.data.PaperCowVariantRegistryEntry; @@ -159,6 +162,7 @@ public final class PaperRegistries { start(Registries.ZOMBIE_NAUTILUS_VARIANT, RegistryKey.ZOMBIE_NAUTILUS_VARIANT).craft(ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant::new).writable(PaperZombieNautilusVariantRegistryEntry.PaperBuilder::new), start(Registries.SULFUR_CUBE_ARCHETYPE, RegistryKey.SULFUR_CUBE_ARCHETYPE).craft(SulfurCube.Archetype.class, CraftSulfurCube.CraftArchetype::new).writable(PaperSulfurCubeArchetypeRegistryEntry.PaperBuilder::new), start(Registries.DIALOG, RegistryKey.DIALOG).craft(Dialog.class, PaperDialog::new, true).writable(PaperDialogRegistryEntry.PaperBuilder::new), + start(Registries.BLOCK_TRANSFORMER, RegistryKey.BLOCK_TRANSFORMER).craft(BlockTransformer.class, PaperBlockTransformer::new, true).writable(PaperBlockTransformerRegistryEntry.PaperBuilder::new).delayed(), // api-only start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType), diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java new file mode 100644 index 000000000000..941dc559cab2 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java @@ -0,0 +1,59 @@ +package io.papermc.paper.registry.data; + +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformData; +import io.papermc.paper.datacomponent.item.blocktransformer.PaperBlockTransformData; +import io.papermc.paper.registry.PaperRegistryBuilder; +import io.papermc.paper.registry.data.util.Conversions; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.core.component.BlockTransformer; +import org.jspecify.annotations.Nullable; + +import static io.papermc.paper.registry.data.util.Checks.asArgument; +import static io.papermc.paper.registry.data.util.Checks.asConfigured; + +public class PaperBlockTransformerRegistryEntry implements BlockTransformerRegistryEntry { + + protected @Nullable List transforms; + + public PaperBlockTransformerRegistryEntry(final Conversions conversions, final @Nullable BlockTransformer internal) { + if (internal == null) { + return; + } + this.transforms = new ArrayList<>(internal.transforms()); + } + + @Override + public List transforms() { + return asConfigured(this.transforms, "transforms").stream().map(PaperBlockTransformData::new).map(BlockTransformData.class::cast).toList(); + } + + public static final class PaperBuilder extends PaperBlockTransformerRegistryEntry implements Builder, PaperRegistryBuilder { + + public PaperBuilder(final Conversions conversions, final @Nullable BlockTransformer internal) { + super(conversions, internal); + } + + @Override + public Builder addTransform(final BlockTransformData transform) { + if (this.transforms == null) { + this.transforms = new ArrayList<>(); + } + this.transforms.add(PaperBlockTransformData.toVanilla(asArgument(transform, "transform"))); + return this; + } + + @Override + public Builder addTransforms(final List transforms) { + for (final BlockTransformData transform : asArgument(transforms, "transforms")) { + this.addTransform(transform); + } + return this; + } + + @Override + public BlockTransformer build() { + return new BlockTransformer(List.copyOf(asConfigured(this.transforms, "transforms"))); + } + } +} diff --git a/paper-server/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformTypesBridge b/paper-server/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformTypesBridge new file mode 100644 index 000000000000..1e530aad5348 --- /dev/null +++ b/paper-server/src/main/resources/META-INF/services/io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformTypesBridge @@ -0,0 +1 @@ +io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformTypesBridgeImpl From a47a171aad98237b33cca513c51c5bc61ad894d1 Mon Sep 17 00:00:00 2001 From: Doc Date: Thu, 10 Sep 2026 11:24:57 -0300 Subject: [PATCH 05/14] Cleanup fields and conversions --- .../blocktransformer/BlockTransformData.java | 4 +- .../PaperBlockTransformData.java | 76 +++++++++---------- .../PaperBlockTransformerRegistryEntry.java | 10 +-- 3 files changed, 43 insertions(+), 47 deletions(-) diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java index 2b33bf338314..a40c900f4965 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java @@ -33,7 +33,7 @@ static BlockTransformData.Builder blockTransformData(final BlockPredicate predic BlockStateProvider blockStateProvider(); @Contract(pure = true) - Key sound(); + @Nullable Key sound(); @Contract(pure = true) TransformParticle particle(); @@ -62,7 +62,7 @@ static BlockTransformData.Builder blockTransformData(final BlockPredicate predic interface Builder extends DataComponentBuilder { @Contract(value = "_ -> this", mutates = "this") - Builder sound(Key sound); + Builder sound(@Nullable Key sound); @Contract(value = "_ -> this", mutates = "this") Builder particle(TransformParticle particle); diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 5a9342df89b1..93175d38328a 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -2,6 +2,7 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.block.stateprovider.BlockStateProvider; import io.papermc.paper.registry.PaperRegistries; import java.util.ArrayList; import java.util.List; @@ -14,6 +15,8 @@ import net.minecraft.core.component.BlockTransformer; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; @@ -29,6 +32,7 @@ import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.Nullable; +import static io.papermc.paper.registry.data.util.Checks.asArgument; import static io.papermc.paper.util.BoundChecker.requireNonNegative; public record PaperBlockTransformData( @@ -41,7 +45,7 @@ public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandl } @Override - public io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider() { + public BlockStateProvider blockStateProvider() { final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = unwrapStateProvider(this.impl.blockStateProvider().value()); if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { return io.papermc.paper.block.stateprovider.BlockStateProvider.simple(CraftBlockData.createData(state)); @@ -115,7 +119,7 @@ public static net.minecraft.core.component.BlockTransformer.BlockTransformData t Holder.direct(toVanillaStateProvider(data.blockStateProvider())), PaperAdventure.resolveSound(data.sound()), net.minecraft.core.component.BlockTransformer.TransformParticle.valueOf(data.particle().name()), - data.disallowedFaces().stream().map(PaperBlockTransformData::toVanillaDirection).toList(), + data.disallowedFaces().stream().map(CraftBlock::blockFaceToNotch).toList(), java.util.Optional.empty(), net.minecraft.core.component.BlockTransformer.DropStrategy.valueOf(data.dropStrategy().name()), data.updateFromNeighbors(), @@ -125,16 +129,8 @@ public static net.minecraft.core.component.BlockTransformer.BlockTransformData t ); } - private static Direction toVanillaDirection(final BlockFace blockFace) { - final Direction direction = CraftBlock.blockFaceToNotch(blockFace); - if (direction == null) { - throw new IllegalArgumentException("Unsupported block face: " + blockFace); - } - return direction; - } - private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanillaStateProvider( - final io.papermc.paper.block.stateprovider.BlockStateProvider provider + final BlockStateProvider provider ) { final BlockData simple = provider.simple(); if (simple == null) { @@ -162,49 +158,53 @@ private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockSt static final class BuilderImpl implements Builder { - private final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider; - private @Nullable BlockPredicate predicate; - private Key sound = Key.key("minecraft:empty"); - private TransformParticle particle = TransformParticle.NONE; - private final List disallowedFaces = new ArrayList<>(); + private static final Holder DEFAULT_SOUND = BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.EMPTY); + + private final Holder blockStateProvider; + private Holder sound = DEFAULT_SOUND; + private BlockTransformer.TransformParticle particle = BlockTransformer.TransformParticle.NONE; + private final List disallowedFaces = new ArrayList<>(); private Optional> lootTable = Optional.empty(); - private DropStrategy dropStrategy = DropStrategy.FROM_MIDDLE; + private BlockTransformer.DropStrategy dropStrategy = BlockTransformer.DropStrategy.FROM_MIDDLE; private boolean updateFromNeighbors = true; - private TransformType transformType = TransformType.SINGLE_BLOCK; + private BlockTransformer.TransformType transformType = BlockTransformer.TransformType.SINGLE_BLOCK; private boolean consumeOnUse = true; private int itemDamagePerUse = 1; - BuilderImpl(final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider) { - this.blockStateProvider = blockStateProvider; + BuilderImpl(final BlockStateProvider blockStateProvider) { + this(null, blockStateProvider); } - BuilderImpl(final BlockPredicate blockPredicate, final io.papermc.paper.block.stateprovider.BlockStateProvider blockStateProvider) { - this.predicate = blockPredicate; - this.blockStateProvider = blockStateProvider; + BuilderImpl(final @Nullable BlockPredicate blockPredicate, final BlockStateProvider blockStateProvider) { + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = toVanillaStateProvider(blockStateProvider); + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = blockPredicate == null + ? targetProvider + : RuleBasedStateProvider.builder().ifTrueThenProvide(toVanillaBlockPredicate(blockPredicate), targetProvider).build(); + this.blockStateProvider = Holder.direct(provider); } @Override - public Builder sound(final Key sound) { - this.sound = sound; + public Builder sound(final @Nullable Key sound) { + this.sound = (sound == null) ? DEFAULT_SOUND : PaperAdventure.resolveSound(sound); return this; } @Override public Builder particle(final TransformParticle particle) { - this.particle = particle; + this.particle = BlockTransformer.TransformParticle.valueOf(asArgument(particle, "particle").name()); return this; } @Override public Builder disallowedFaces(final List disallowedFaces) { this.disallowedFaces.clear(); - this.disallowedFaces.addAll(disallowedFaces); + disallowedFaces.forEach(this::addDisallowedFace); return this; } @Override public Builder addDisallowedFace(final BlockFace disallowedFace) { - this.disallowedFaces.add(disallowedFace); + this.disallowedFaces.add(CraftBlock.blockFaceToNotch(asArgument(disallowedFace, "disallowedFace"))); return this; } @@ -216,7 +216,7 @@ public Builder lootTable(@Nullable final LootTable lootTable) { @Override public Builder dropStrategy(final DropStrategy dropStrategy) { - this.dropStrategy = dropStrategy; + this.dropStrategy = BlockTransformer.DropStrategy.valueOf(asArgument(dropStrategy, "dropStrategy").name()); return this; } @@ -228,7 +228,7 @@ public Builder updateFromNeighbors(final boolean updateFromNeighbors) { @Override public Builder transformType(final TransformType transformType) { - this.transformType = transformType; + this.transformType = BlockTransformer.TransformType.valueOf(asArgument(transformType, "transformType").name()); return this; } @@ -246,19 +246,15 @@ public Builder itemDamagePerUse(final @NonNegative int itemDamagePerUse) { @Override public BlockTransformData build() { - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = toVanillaStateProvider(this.blockStateProvider); - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = this.predicate == null - ? targetProvider - : RuleBasedStateProvider.builder().ifTrueThenProvide(toVanillaBlockPredicate(this.predicate), targetProvider).build(); return new PaperBlockTransformData(new net.minecraft.core.component.BlockTransformer.BlockTransformData( - Holder.direct(provider), - PaperAdventure.resolveSound(this.sound), - net.minecraft.core.component.BlockTransformer.TransformParticle.valueOf(this.particle.name()), - this.disallowedFaces.stream().map(PaperBlockTransformData::toVanillaDirection).toList(), + this.blockStateProvider, + this.sound, + this.particle, + this.disallowedFaces, this.lootTable, - net.minecraft.core.component.BlockTransformer.DropStrategy.valueOf(this.dropStrategy.name()), + this.dropStrategy, this.updateFromNeighbors, - net.minecraft.core.component.BlockTransformer.TransformType.valueOf(this.transformType.name()), + this.transformType, this.consumeOnUse, this.itemDamagePerUse )); diff --git a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java index 941dc559cab2..6009a2f85890 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/data/PaperBlockTransformerRegistryEntry.java @@ -14,18 +14,18 @@ public class PaperBlockTransformerRegistryEntry implements BlockTransformerRegistryEntry { - protected @Nullable List transforms; + protected @Nullable List transforms; public PaperBlockTransformerRegistryEntry(final Conversions conversions, final @Nullable BlockTransformer internal) { if (internal == null) { return; } - this.transforms = new ArrayList<>(internal.transforms()); + this.transforms = new ArrayList<>(internal.transforms().stream().map(PaperBlockTransformData::new).map(BlockTransformData.class::cast).toList()); } @Override public List transforms() { - return asConfigured(this.transforms, "transforms").stream().map(PaperBlockTransformData::new).map(BlockTransformData.class::cast).toList(); + return asConfigured(this.transforms, "transforms"); } public static final class PaperBuilder extends PaperBlockTransformerRegistryEntry implements Builder, PaperRegistryBuilder { @@ -39,7 +39,7 @@ public Builder addTransform(final BlockTransformData transform) { if (this.transforms == null) { this.transforms = new ArrayList<>(); } - this.transforms.add(PaperBlockTransformData.toVanilla(asArgument(transform, "transform"))); + this.transforms.add(asArgument(transform, "transform")); return this; } @@ -53,7 +53,7 @@ public Builder addTransforms(final List transforms) { @Override public BlockTransformer build() { - return new BlockTransformer(List.copyOf(asConfigured(this.transforms, "transforms"))); + return new BlockTransformer(asConfigured(this.transforms, "transforms").stream().map(PaperBlockTransformData::toVanilla).toList()); } } } From 0af72324d3e705bc59dd43f4abf8915bb7558b26 Mon Sep 17 00:00:00 2001 From: Doc Date: Thu, 10 Sep 2026 18:24:18 -0300 Subject: [PATCH 06/14] ReWork in methods --- paper-api/.checkstyle/ignored_directories.txt | 2 ++ .../stateprovider/BlockStateProvider.java | 17 +++++++-- .../block/stateprovider/package-info.java | 3 ++ .../blocktransformer/BlockTransformData.java | 2 -- .../BlockTransformTypesBridge.java | 2 -- .../blocktransformer/BlockTransformer.java | 2 -- .../PaperBlockStateProvider.java | 25 +++++++++++++ .../block/stateprovider/package-info.java | 4 +++ .../PaperBlockTransformData.java | 35 +++++++------------ 9 files changed, 61 insertions(+), 31 deletions(-) create mode 100644 paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java create mode 100644 paper-server/src/main/java/io/papermc/paper/block/stateprovider/package-info.java diff --git a/paper-api/.checkstyle/ignored_directories.txt b/paper-api/.checkstyle/ignored_directories.txt index 2d76afe8944c..325ad84d6418 100644 --- a/paper-api/.checkstyle/ignored_directories.txt +++ b/paper-api/.checkstyle/ignored_directories.txt @@ -30,6 +30,7 @@ paper-api/src/main/java/io/papermc/paper/block/ paper-api/src/main/java/io/papermc/paper/block/bed/ paper-api/src/main/java/io/papermc/paper/block/fluid/ paper-api/src/main/java/io/papermc/paper/block/fluid/type/ +paper-api/src/main/java/io/papermc/paper/block/stateprovider/ paper-api/src/main/java/io/papermc/paper/brigadier/ paper-api/src/main/java/io/papermc/paper/chat/ paper-api/src/main/java/io/papermc/paper/command/ @@ -47,6 +48,7 @@ paper-api/src/main/java/io/papermc/paper/datacomponent/item/ paper-api/src/main/java/io/papermc/paper/datacomponent/item/attribute/ paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocksattacks/ paper-api/src/main/java/io/papermc/paper/datacomponent/item/consumable/ +paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/ paper-api/src/main/java/io/papermc/paper/datapack/ paper-api/src/main/java/io/papermc/paper/dialog/ paper-api/src/main/java/io/papermc/paper/enchantments/ diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java index c0f3bab26109..b5a05c377ecf 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java @@ -3,13 +3,20 @@ import org.bukkit.block.data.BlockData; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; -import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -@NullMarked +/** + * A provider for {@link BlockData} that can be used to provide block states for various purposes. + */ @ApiStatus.NonExtendable public interface BlockStateProvider { + /** + * Creates a simple {@link BlockStateProvider} that always provides the given {@link BlockData}. + * + * @param blockData the block data to provide + * @return a new {@link BlockStateProvider} + */ @Contract(value = "_ -> new", pure = true) static BlockStateProvider simple(final BlockData blockData) { // @@ -20,9 +27,15 @@ record SimpleProviderImpl(@Nullable BlockData blockData) implements BlockStatePr } } // + return new SimpleProviderImpl(blockData); } + /** + * Returns the simple {@link BlockData} if this provider is a simple provider, or null otherwise. + * + * @return the simple {@link BlockData} or null + */ @Nullable BlockData simple(); } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java index f9b604448f25..17e071b39aeb 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/package-info.java @@ -1,3 +1,6 @@ +/** + * This package contains classes that provide block states for various blocks in Minecraft. + */ @NullMarked package io.papermc.paper.block.stateprovider; diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java index a40c900f4965..08aea22531a0 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformData.java @@ -12,10 +12,8 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; -import org.jspecify.annotations.NullMarked; import org.jspecify.annotations.Nullable; -@NullMarked @ApiStatus.NonExtendable public interface BlockTransformData extends BuildableDataComponent { diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java index ef07508c5581..1253851641a9 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java @@ -5,9 +5,7 @@ import java.util.Optional; import java.util.ServiceLoader; import org.jetbrains.annotations.ApiStatus; -import org.jspecify.annotations.NullMarked; -@NullMarked @ApiStatus.Internal interface BlockTransformTypesBridge { diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java index cee737d49048..5588e4d059ce 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java @@ -9,9 +9,7 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Unmodifiable; -import org.jspecify.annotations.NullMarked; -@NullMarked @ApiStatus.NonExtendable public interface BlockTransformer extends Keyed { diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java new file mode 100644 index 000000000000..f58533f12440 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java @@ -0,0 +1,25 @@ +package io.papermc.paper.block.stateprovider; + +import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.block.data.CraftBlockData; + +public final class PaperBlockStateProvider { + + private PaperBlockStateProvider() { + } + + public static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanilla( + final BlockStateProvider provider + ) { + final BlockData simple = provider.simple(); + if (simple == null) { + throw new UnsupportedOperationException("Unsupported block state provider type"); + } + if (!(simple instanceof final CraftBlockData craftBlockData)) { + throw new IllegalArgumentException("Unsupported BlockData implementation: " + simple.getClass().getName()); + } + return new SimpleStateProvider(craftBlockData.getState()); + } + +} diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/package-info.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/package-info.java new file mode 100644 index 000000000000..f9b604448f25 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package io.papermc.paper.block.stateprovider; + +import org.jspecify.annotations.NullMarked; diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 93175d38328a..86c2f789e879 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -3,9 +3,12 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.block.BlockPredicate; import io.papermc.paper.block.stateprovider.BlockStateProvider; +import io.papermc.paper.block.stateprovider.PaperBlockStateProvider; import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.set.RegistryKeySet; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import net.kyori.adventure.key.Key; import net.minecraft.core.Direction; @@ -22,7 +25,7 @@ import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; import net.minecraft.world.level.levelgen.blockpredicates.MatchingBlocksPredicate; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.BlockData; +import org.bukkit.block.BlockType; import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.data.CraftBlockData; @@ -115,11 +118,12 @@ public static net.minecraft.core.component.BlockTransformer.BlockTransformData t if (data instanceof final PaperBlockTransformData paperBlockTransformData) { return paperBlockTransformData.getHandle(); } + return new net.minecraft.core.component.BlockTransformer.BlockTransformData( - Holder.direct(toVanillaStateProvider(data.blockStateProvider())), + Holder.direct(PaperBlockStateProvider.toVanilla(data.blockStateProvider())), PaperAdventure.resolveSound(data.sound()), net.minecraft.core.component.BlockTransformer.TransformParticle.valueOf(data.particle().name()), - data.disallowedFaces().stream().map(CraftBlock::blockFaceToNotch).toList(), + data.disallowedFaces().stream().map(CraftBlock::blockFaceToNotch).filter(Objects::nonNull).toList(), java.util.Optional.empty(), net.minecraft.core.component.BlockTransformer.DropStrategy.valueOf(data.dropStrategy().name()), data.updateFromNeighbors(), @@ -129,19 +133,6 @@ public static net.minecraft.core.component.BlockTransformer.BlockTransformData t ); } - private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanillaStateProvider( - final BlockStateProvider provider - ) { - final BlockData simple = provider.simple(); - if (simple == null) { - throw new UnsupportedOperationException("Unsupported block state provider type"); - } - if (!(simple instanceof final CraftBlockData craftBlockData)) { - throw new IllegalArgumentException("Unsupported BlockData implementation: " + simple.getClass().getName()); - } - return new SimpleStateProvider(craftBlockData.getState()); - } - private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider unwrapStateProvider( final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider ) { @@ -176,7 +167,7 @@ static final class BuilderImpl implements Builder { } BuilderImpl(final @Nullable BlockPredicate blockPredicate, final BlockStateProvider blockStateProvider) { - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = toVanillaStateProvider(blockStateProvider); + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = PaperBlockStateProvider.toVanilla(blockStateProvider); final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = blockPredicate == null ? targetProvider : RuleBasedStateProvider.builder().ifTrueThenProvide(toVanillaBlockPredicate(blockPredicate), targetProvider).build(); @@ -204,7 +195,7 @@ public Builder disallowedFaces(final List disallowedFaces) { @Override public Builder addDisallowedFace(final BlockFace disallowedFace) { - this.disallowedFaces.add(CraftBlock.blockFaceToNotch(asArgument(disallowedFace, "disallowedFace"))); + this.disallowedFaces.add(asArgument(CraftBlock.blockFaceToNotch(disallowedFace), "disallowedFace")); return this; } @@ -262,16 +253,14 @@ public BlockTransformData build() { } private static net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate toVanillaBlockPredicate(final BlockPredicate predicate) { - if (predicate.blocks() == null) { + RegistryKeySet blocks = predicate.blocks(); + if (blocks == null) { return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); } - final List> blockHolders = predicate.blocks().values().stream() + final List> blockHolders = blocks.values().stream() .map(PaperRegistries::toNms) .map(key -> { final Block block = BuiltInRegistries.BLOCK.getValue(key.identifier()); - if (block == null) { - throw new IllegalArgumentException("Unknown block key: " + key.identifier()); - } return BuiltInRegistries.BLOCK.wrapAsHolder(block); }) .toList(); From cb79cb256ea05903c5c4dab575c48cd6e6c04772 Mon Sep 17 00:00:00 2001 From: Doc Date: Thu, 10 Sep 2026 18:29:17 -0300 Subject: [PATCH 07/14] Fix tests --- .../test/java/org/bukkit/registry/RegistryConstantsTest.java | 1 - .../bukkit/support/provider/RegistriesArgumentProvider.java | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java index 2ebcb1f1d66e..028909c01d99 100644 --- a/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java +++ b/paper-server/src/test/java/org/bukkit/registry/RegistryConstantsTest.java @@ -58,7 +58,6 @@ public static void populateIgnored() { DataComponents.LOCK, DataComponents.CREATIVE_SLOT_LOCK, DataComponents.ADDITIONAL_TRADE_COST, - DataComponents.BLOCK_TRANSFORMER, DataComponents.COMPOSTABLE, DataComponents.COOKING_FUEL, DataComponents.BREWING_FUEL diff --git a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java index 490d53d9e8f7..b097e83aad62 100644 --- a/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java +++ b/paper-server/src/test/java/org/bukkit/support/provider/RegistriesArgumentProvider.java @@ -5,6 +5,8 @@ import io.papermc.paper.block.pot.PotPatternType; import io.papermc.paper.block.pot.PotPatternTypes; import io.papermc.paper.datacomponent.DataComponentTypes; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.datacomponent.item.blocktransformer.PaperBlockTransformer; import io.papermc.paper.dialog.Dialog; import io.papermc.paper.dialog.PaperDialog; import io.papermc.paper.entity.poi.PaperPoiType; @@ -170,6 +172,7 @@ public Object[] get() { register(Registries.GAME_RULE, GameRule.class, GameRules.class, CraftGameRule.class, net.minecraft.world.level.gamerules.GameRule.class); register(Registries.POINT_OF_INTEREST_TYPE, PoiType.class, PoiTypes.class, PaperPoiType.class, net.minecraft.world.entity.ai.village.poi.PoiType.class); register(Registries.SULFUR_CUBE_ARCHETYPE, SulfurCube.Archetype.class, CraftSulfurCube.CraftArchetype.class, SulfurCubeArchetype.class); + register(Registries.BLOCK_TRANSFORMER, BlockTransformer.class, PaperBlockTransformer.class, net.minecraft.core.component.BlockTransformer.class); } private static void register(ResourceKey> registryKey, Class api, Class impl, Class internal) { From e190eb5da45c7150e6605d933e98cbd118b5b023 Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 00:00:00 -0300 Subject: [PATCH 08/14] CopyBlockStateProvider and union of Predicates (all/any) --- .../papermc/paper/block/BlockPredicate.java | 82 ++++++++++++++++++- .../stateprovider/BlockStateProvider.java | 38 ++++----- .../CopyPropertiesBlockStateProvider.java | 15 ++++ .../SimpleBlockStateProvider.java | 15 ++++ .../BlockTransformTypesBridge.java | 1 + .../paper/block/PaperBlockPredicate.java | 60 ++++++++++++++ .../PaperBlockStateProvider.java | 21 ++--- .../PaperBlockTransformData.java | 43 +++------- 8 files changed, 211 insertions(+), 64 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java create mode 100644 paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java diff --git a/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java b/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java index 955c8257a168..cacf5cfd6e08 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java +++ b/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java @@ -1,6 +1,8 @@ package io.papermc.paper.block; import io.papermc.paper.registry.set.RegistryKeySet; +import java.util.List; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; @@ -11,14 +13,55 @@ @ApiStatus.NonExtendable public interface BlockPredicate { + @Contract(value = "_ -> new", pure = true) + static BlockPredicate matchesBlocks(final @Nullable RegistryKeySet blocks) { + return predicate().blocks(blocks).build(); + } + + @Contract(value = "_, _ -> new", pure = true) + static BlockPredicate matchesDirection(final BlockFace direction, final @Nullable RegistryKeySet blocks) { + return predicate().direction(direction).blocks(blocks).build(); + } + + @Contract(value = "_ -> new", pure = true) + static AnyOf anyOf(final List predicates) { + return () -> List.copyOf(predicates); + } + + @Contract(value = "_ -> new", pure = true) + static AnyOf anyOf(final BlockPredicate... predicates) { + return anyOf(List.of(predicates)); + } + + @Contract(value = "_ -> new", pure = true) + static AllOf allOf(final List predicates) { + return () -> List.copyOf(predicates); + } + + @Contract(value = "_ -> new", pure = true) + static AllOf allOf(final BlockPredicate... predicates) { + return allOf(List.of(predicates)); + } + static Builder predicate() { // - record BlockPredicateImpl(@Nullable RegistryKeySet blocks) implements BlockPredicate { + record BlockPredicateImpl(@Nullable RegistryKeySet blocks, @Nullable BlockFace direction) + implements BlockPredicate { + @Override + public @Nullable RegistryKeySet blocks() { + return this.blocks; + } + + @Override + public @Nullable BlockFace direction() { + return this.direction; + } } class BuilderImpl implements Builder { private @Nullable RegistryKeySet blocks; + private @Nullable BlockFace direction; @Override public Builder blocks(final @Nullable RegistryKeySet blocks) { @@ -26,9 +69,15 @@ public Builder blocks(final @Nullable RegistryKeySet blocks) { return this; } + @Override + public Builder direction(final @Nullable BlockFace direction) { + this.direction = direction; + return this; + } + @Override public BlockPredicate build() { - return new BlockPredicateImpl(this.blocks); + return new BlockPredicateImpl(this.blocks, this.direction); } } // @@ -37,12 +86,41 @@ public BlockPredicate build() { @Nullable RegistryKeySet blocks(); + default @Nullable BlockFace direction() { + return null; + } + @ApiStatus.NonExtendable interface Builder { @Contract(value = "_ -> this", mutates = "this") Builder blocks(@Nullable RegistryKeySet blocks); + @Contract(value = "_ -> this", mutates = "this") + Builder direction(@Nullable BlockFace direction); + BlockPredicate build(); } + + @ApiStatus.NonExtendable + interface AnyOf extends BlockPredicate { + + @Override + default @Nullable RegistryKeySet blocks() { + return null; + } + + List predicates(); + } + + @ApiStatus.NonExtendable + interface AllOf extends BlockPredicate { + + @Override + default @Nullable RegistryKeySet blocks() { + return null; + } + + List predicates(); + } } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java index b5a05c377ecf..c5e29d543333 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java @@ -1,41 +1,39 @@ package io.papermc.paper.block.stateprovider; -import org.bukkit.block.data.BlockData; +import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; -import org.jspecify.annotations.Nullable; -/** - * A provider for {@link BlockData} that can be used to provide block states for various purposes. - */ @ApiStatus.NonExtendable public interface BlockStateProvider { /** - * Creates a simple {@link BlockStateProvider} that always provides the given {@link BlockData}. + * Creates a simple provider that always returns the default state of the given block type. * - * @param blockData the block data to provide - * @return a new {@link BlockStateProvider} + * @param blockType block type to provide + * @return a simple block state provider */ @Contract(value = "_ -> new", pure = true) - static BlockStateProvider simple(final BlockData blockData) { + static SimpleBlockStateProvider simple(final BlockType blockType) { // - record SimpleProviderImpl(@Nullable BlockData blockData) implements BlockStateProvider { - @Override - public @Nullable BlockData simple() { - return this.blockData; - } + record SimpleProviderImpl(BlockType blockType) implements SimpleBlockStateProvider { } // - - return new SimpleProviderImpl(blockData); + return new SimpleProviderImpl(blockType); } /** - * Returns the simple {@link BlockData} if this provider is a simple provider, or null otherwise. + * Creates a provider that copies properties from the current block into the given target block type. * - * @return the simple {@link BlockData} or null + * @param blockType target block type + * @return a copy-properties block state provider */ - @Nullable BlockData simple(); - + @Contract(value = "_ -> new", pure = true) + static CopyPropertiesBlockStateProvider copyPropertiesFrom(final BlockType blockType) { + // + record CopyPropertiesProviderImpl(BlockType blockType) implements CopyPropertiesBlockStateProvider { + } + // + return new CopyPropertiesProviderImpl(blockType); + } } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java new file mode 100644 index 000000000000..7ba98994c4e3 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java @@ -0,0 +1,15 @@ +package io.papermc.paper.block.stateprovider; + +import org.bukkit.block.BlockType; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable +public interface CopyPropertiesBlockStateProvider extends BlockStateProvider { + + /** + * Target block type that receives the copied properties. + * + * @return target block type + */ + BlockType blockType(); +} diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java new file mode 100644 index 000000000000..d10d04b5af81 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java @@ -0,0 +1,15 @@ +package io.papermc.paper.block.stateprovider; + +import org.bukkit.block.BlockType; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable +public interface SimpleBlockStateProvider extends BlockStateProvider { + + /** + * Target block type whose default state will be provided. + * + * @return target block type + */ + BlockType blockType(); +} diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java index 1253851641a9..72baf562f14c 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformTypesBridge.java @@ -18,4 +18,5 @@ static BlockTransformTypesBridge bridge() { BlockTransformData.Builder blockTransformData(BlockStateProvider blockStateProvider); BlockTransformData.Builder blockTransformData(BlockPredicate predicate, BlockStateProvider blockStateProvider); + } diff --git a/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java b/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java new file mode 100644 index 000000000000..c6a660f0c303 --- /dev/null +++ b/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java @@ -0,0 +1,60 @@ +package io.papermc.paper.block; + +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.set.RegistryKeySet; +import java.util.ArrayList; +import java.util.List; +import net.minecraft.core.Direction; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; +import org.bukkit.block.BlockType; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.jspecify.annotations.Nullable; + +import static io.papermc.paper.registry.data.util.Checks.asArgument; + +public final class PaperBlockPredicate { + + private PaperBlockPredicate() { + } + + public static net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate toVanilla(final @Nullable BlockPredicate predicate) { + if (predicate == null) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + } + + if (predicate instanceof final BlockPredicate.AnyOf anyOf) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.anyOf( + anyOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() + ); + } + if (predicate instanceof final BlockPredicate.AllOf allOf) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf( + allOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() + ); + } + + final List predicates = new ArrayList<>(); + final Direction direction = predicate.direction() == null ? null : asArgument(CraftBlock.blockFaceToNotch(predicate.direction()), "direction"); + + final RegistryKeySet blocksKeySet = predicate.blocks(); + if (blocksKeySet != null) { + final List blocks = blocksKeySet.values().stream() + .map(PaperRegistries::toNms) + .map(key -> BuiltInRegistries.BLOCK.getValue(key.identifier())) + .toList(); + final Block[] array = blocks.toArray(Block[]::new); + if (direction == null) { + predicates.add(net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesBlocks(array)); + } else { + predicates.add(net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesBlocks(direction, array)); + } + } + + if (predicates.isEmpty()) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + } + + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf(predicates); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java index f58533f12440..8d2c33528cbd 100644 --- a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java @@ -1,25 +1,22 @@ package io.papermc.paper.block.stateprovider; import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; -import org.bukkit.block.data.BlockData; -import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.block.CraftBlockType; public final class PaperBlockStateProvider { private PaperBlockStateProvider() { } - public static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanilla( - final BlockStateProvider provider - ) { - final BlockData simple = provider.simple(); - if (simple == null) { - throw new UnsupportedOperationException("Unsupported block state provider type"); + public static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanilla(final BlockStateProvider provider) { + if (provider instanceof final SimpleBlockStateProvider simple) { + return new SimpleStateProvider(CraftBlockType.bukkitToMinecraftNew(simple.blockType()).defaultBlockState()); } - if (!(simple instanceof final CraftBlockData craftBlockData)) { - throw new IllegalArgumentException("Unsupported BlockData implementation: " + simple.getClass().getName()); + if (provider instanceof final CopyPropertiesBlockStateProvider copyProperties) { + return new net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider( + CraftBlockType.bukkitToMinecraftNew(copyProperties.blockType()) + ); } - return new SimpleStateProvider(craftBlockData.getState()); + throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } - } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 86c2f789e879..49c15dadaeb4 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -2,10 +2,9 @@ import io.papermc.paper.adventure.PaperAdventure; import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.block.PaperBlockPredicate; import io.papermc.paper.block.stateprovider.BlockStateProvider; import io.papermc.paper.block.stateprovider.PaperBlockStateProvider; -import io.papermc.paper.registry.PaperRegistries; -import io.papermc.paper.registry.set.RegistryKeySet; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -13,22 +12,17 @@ import net.kyori.adventure.key.Key; import net.minecraft.core.Direction; import net.minecraft.core.Holder; -import net.minecraft.core.HolderSet; -import net.minecraft.core.Vec3i; import net.minecraft.core.component.BlockTransformer; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; -import net.minecraft.world.level.levelgen.blockpredicates.MatchingBlocksPredicate; +import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; import org.bukkit.block.BlockFace; -import org.bukkit.block.BlockType; import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.loot.LootTable; import org.checkerframework.checker.index.qual.NonNegative; @@ -51,7 +45,14 @@ public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandl public BlockStateProvider blockStateProvider() { final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = unwrapStateProvider(this.impl.blockStateProvider().value()); if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { - return io.papermc.paper.block.stateprovider.BlockStateProvider.simple(CraftBlockData.createData(state)); + return io.papermc.paper.block.stateprovider.BlockStateProvider.simple(CraftBlockType.minecraftToBukkitNew(state.getBlock())); + } + if (provider instanceof net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider( + Holder source + ) + && source.value() instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState sourceState) + ) { + return io.papermc.paper.block.stateprovider.BlockStateProvider.copyPropertiesFrom(CraftBlockType.minecraftToBukkitNew(sourceState.getBlock())); } throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } @@ -168,9 +169,9 @@ static final class BuilderImpl implements Builder { BuilderImpl(final @Nullable BlockPredicate blockPredicate, final BlockStateProvider blockStateProvider) { final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = PaperBlockStateProvider.toVanilla(blockStateProvider); - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = blockPredicate == null + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = (blockPredicate == null) ? targetProvider - : RuleBasedStateProvider.builder().ifTrueThenProvide(toVanillaBlockPredicate(blockPredicate), targetProvider).build(); + : RuleBasedStateProvider.builder().ifTrueThenProvide(PaperBlockPredicate.toVanilla(blockPredicate), targetProvider).build(); this.blockStateProvider = Holder.direct(provider); } @@ -251,22 +252,4 @@ public BlockTransformData build() { )); } } - - private static net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate toVanillaBlockPredicate(final BlockPredicate predicate) { - RegistryKeySet blocks = predicate.blocks(); - if (blocks == null) { - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); - } - final List> blockHolders = blocks.values().stream() - .map(PaperRegistries::toNms) - .map(key -> { - final Block block = BuiltInRegistries.BLOCK.getValue(key.identifier()); - return BuiltInRegistries.BLOCK.wrapAsHolder(block); - }) - .toList(); - return new MatchingBlocksPredicate( - Vec3i.ZERO, - HolderSet.direct(blockHolders) - ); - } } From d7bd73959571e7b2a1b087c4a7fed3cbe778b60e Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 00:13:52 -0300 Subject: [PATCH 09/14] RandomBlockStateProvider and RotatedBlockStateProvider --- .../stateprovider/BlockStateProvider.java | 45 +++++++++++++++ .../RandomBlockStateProvider.java | 16 ++++++ .../RotatedBlockStateProvider.java | 23 ++++++++ .../PaperBlockStateProvider.java | 56 ++++++++++++++++++- .../PaperBlockTransformData.java | 15 +---- 5 files changed, 140 insertions(+), 15 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java index c5e29d543333..cd97df0e5c6e 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java @@ -1,8 +1,11 @@ package io.papermc.paper.block.stateprovider; +import io.papermc.paper.registry.set.RegistryKeySet; +import org.bukkit.block.BlockFace; import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; +import org.jspecify.annotations.Nullable; @ApiStatus.NonExtendable public interface BlockStateProvider { @@ -36,4 +39,46 @@ record CopyPropertiesProviderImpl(BlockType blockType) implements CopyProperties // return new CopyPropertiesProviderImpl(blockType); } + + /** + * Creates a provider that chooses a random block from the provided set. + * + * @param blocks candidate blocks + * @return a random block state provider + */ + @Contract(value = "_ -> new", pure = true) + static RandomBlockStateProvider randomBlock(final RegistryKeySet blocks) { + // + record RandomBlockProviderImpl(RegistryKeySet blocks) implements RandomBlockStateProvider { + } + // + return new RandomBlockProviderImpl(blocks); + } + + /** + * Creates a provider that applies a random rotation to the output of another provider. + * + * @param stateProvider source provider + * @return a rotated block state provider + */ + @Contract(value = "_ -> new", pure = true) + static RotatedBlockStateProvider rotated(final BlockStateProvider stateProvider) { + return rotated(stateProvider, null); + } + + /** + * Creates a provider that rotates the output of another provider with an optional forced direction. + * + * @param stateProvider source provider + * @param direction direction to force, or null for random direction + * @return a rotated block state provider + */ + @Contract(value = "_, _ -> new", pure = true) + static RotatedBlockStateProvider rotated(final BlockStateProvider stateProvider, final @Nullable BlockFace direction) { + // + record RotatedBlockProviderImpl(BlockStateProvider stateProvider, @Nullable BlockFace direction) implements RotatedBlockStateProvider { + } + // + return new RotatedBlockProviderImpl(stateProvider, direction); + } } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java new file mode 100644 index 000000000000..a83b94adda3b --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java @@ -0,0 +1,16 @@ +package io.papermc.paper.block.stateprovider; + +import io.papermc.paper.registry.set.RegistryKeySet; +import org.bukkit.block.BlockType; +import org.jetbrains.annotations.ApiStatus; + +@ApiStatus.NonExtendable +public interface RandomBlockStateProvider extends BlockStateProvider { + + /** + * Candidate block types used by this random provider. + * + * @return candidate blocks + */ + RegistryKeySet blocks(); +} diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java new file mode 100644 index 000000000000..4bfa1397b95d --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java @@ -0,0 +1,23 @@ +package io.papermc.paper.block.stateprovider; + +import org.bukkit.block.BlockFace; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.Nullable; + +@ApiStatus.NonExtendable +public interface RotatedBlockStateProvider extends BlockStateProvider { + + /** + * Source provider whose output is rotated. + * + * @return source provider + */ + BlockStateProvider stateProvider(); + + /** + * Forced direction for rotation, or null to pick one at random. + * + * @return forced direction, or null + */ + @Nullable BlockFace direction(); +} diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java index 8d2c33528cbd..ec370ac93395 100644 --- a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java @@ -1,8 +1,25 @@ package io.papermc.paper.block.stateprovider; +import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.set.PaperRegistrySets; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import net.minecraft.core.Direction; +import net.minecraft.core.Holder; +import net.minecraft.core.HolderSet; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider; +import net.minecraft.world.level.levelgen.feature.stateproviders.RandomBlockProvider; +import net.minecraft.world.level.levelgen.feature.stateproviders.RotatedBlockProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; +import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockType; +import static io.papermc.paper.registry.data.util.Checks.asArgument; + public final class PaperBlockStateProvider { private PaperBlockStateProvider() { @@ -13,10 +30,47 @@ public static net.minecraft.world.level.levelgen.feature.stateproviders.BlockSta return new SimpleStateProvider(CraftBlockType.bukkitToMinecraftNew(simple.blockType()).defaultBlockState()); } if (provider instanceof final CopyPropertiesBlockStateProvider copyProperties) { - return new net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider( + return new CopyPropertiesProvider( CraftBlockType.bukkitToMinecraftNew(copyProperties.blockType()) ); } + if (provider instanceof final RandomBlockStateProvider randomBlock) { + final List> blocks = new ArrayList<>(); + for (final var key : randomBlock.blocks().values()) { + final Block block = BuiltInRegistries.BLOCK.getValue(PaperRegistries.toNms(key).identifier()); + blocks.add(BuiltInRegistries.BLOCK.wrapAsHolder(block)); + } + return new RandomBlockProvider(HolderSet.direct(blocks)); + } + if (provider instanceof final RotatedBlockStateProvider rotated) { + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider source = toVanilla(rotated.stateProvider()); + final Optional direction = Optional.ofNullable(rotated.direction()) + .map(face -> asArgument(CraftBlock.blockFaceToNotch(face), "direction")); + return new RotatedBlockProvider(Holder.direct(source), direction); + } + throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); + } + + public static BlockStateProvider toApi(final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider) { + if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { + return BlockStateProvider.simple(CraftBlockType.minecraftToBukkitNew(state.getBlock())); + } + if (provider instanceof CopyPropertiesProvider(Holder source) + && source.value() instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState sourceState)) { + return BlockStateProvider.copyPropertiesFrom(CraftBlockType.minecraftToBukkitNew(sourceState.getBlock())); + } + if (provider instanceof RandomBlockProvider(HolderSet blocks)) { + return BlockStateProvider.randomBlock(PaperRegistrySets.convertToApi(RegistryKey.BLOCK, blocks)); + } + if (provider instanceof RotatedBlockProvider( + Holder state, + Optional direction + )) { + return BlockStateProvider.rotated( + toApi(state.value()), + direction.map(CraftBlock::notchToBlockFace).orElse(null) + ); + } throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 49c15dadaeb4..01bc320b9f17 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -18,11 +18,9 @@ import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; -import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.CraftBlock; -import org.bukkit.craftbukkit.block.CraftBlockType; import org.bukkit.craftbukkit.util.Handleable; import org.bukkit.loot.LootTable; import org.checkerframework.checker.index.qual.NonNegative; @@ -43,18 +41,7 @@ public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandl @Override public BlockStateProvider blockStateProvider() { - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = unwrapStateProvider(this.impl.blockStateProvider().value()); - if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { - return io.papermc.paper.block.stateprovider.BlockStateProvider.simple(CraftBlockType.minecraftToBukkitNew(state.getBlock())); - } - if (provider instanceof net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider( - Holder source - ) - && source.value() instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState sourceState) - ) { - return io.papermc.paper.block.stateprovider.BlockStateProvider.copyPropertiesFrom(CraftBlockType.minecraftToBukkitNew(sourceState.getBlock())); - } - throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); + return PaperBlockStateProvider.toApi(unwrapStateProvider(this.impl.blockStateProvider().value())); } @Override From 4f04816fc7e99f0dc9a9e6ffcb3d3b05898409e4 Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 08:56:43 -0300 Subject: [PATCH 10/14] Missing Contract annotation on stateProvider --- .../block/stateprovider/CopyPropertiesBlockStateProvider.java | 2 ++ .../paper/block/stateprovider/RandomBlockStateProvider.java | 2 ++ .../paper/block/stateprovider/RotatedBlockStateProvider.java | 3 +++ .../paper/block/stateprovider/SimpleBlockStateProvider.java | 2 ++ 4 files changed, 9 insertions(+) diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java index 7ba98994c4e3..97d7f2b6ae84 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/CopyPropertiesBlockStateProvider.java @@ -2,6 +2,7 @@ import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; @ApiStatus.NonExtendable public interface CopyPropertiesBlockStateProvider extends BlockStateProvider { @@ -11,5 +12,6 @@ public interface CopyPropertiesBlockStateProvider extends BlockStateProvider { * * @return target block type */ + @Contract(pure = true) BlockType blockType(); } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java index a83b94adda3b..656139f34f4b 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RandomBlockStateProvider.java @@ -3,6 +3,7 @@ import io.papermc.paper.registry.set.RegistryKeySet; import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; @ApiStatus.NonExtendable public interface RandomBlockStateProvider extends BlockStateProvider { @@ -12,5 +13,6 @@ public interface RandomBlockStateProvider extends BlockStateProvider { * * @return candidate blocks */ + @Contract(pure = true) RegistryKeySet blocks(); } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java index 4bfa1397b95d..74bbc5918cd9 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RotatedBlockStateProvider.java @@ -2,6 +2,7 @@ import org.bukkit.block.BlockFace; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; import org.jspecify.annotations.Nullable; @ApiStatus.NonExtendable @@ -12,6 +13,7 @@ public interface RotatedBlockStateProvider extends BlockStateProvider { * * @return source provider */ + @Contract(pure = true) BlockStateProvider stateProvider(); /** @@ -19,5 +21,6 @@ public interface RotatedBlockStateProvider extends BlockStateProvider { * * @return forced direction, or null */ + @Contract(pure = true) @Nullable BlockFace direction(); } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java index d10d04b5af81..5b61dfeb3940 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/SimpleBlockStateProvider.java @@ -2,6 +2,7 @@ import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; @ApiStatus.NonExtendable public interface SimpleBlockStateProvider extends BlockStateProvider { @@ -11,5 +12,6 @@ public interface SimpleBlockStateProvider extends BlockStateProvider { * * @return target block type */ + @Contract(pure = true) BlockType blockType(); } From f6118eff4fb00be315057515a3fa70e75eaf9e6f Mon Sep 17 00:00:00 2001 From: Bjarne Koll Date: Fri, 11 Sep 2026 08:58:18 -0300 Subject: [PATCH 11/14] Add RuleBasedBlockStateProvider and improvements --- .../stateprovider/BlockStateProvider.java | 46 ++++++++ .../RuleBasedBlockStateProvider.java | 31 ++++++ .../PaperBlockStateProvider.java | 100 +++++++++++------- .../PaperBlockTransformData.java | 29 +---- 4 files changed, 141 insertions(+), 65 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/block/stateprovider/RuleBasedBlockStateProvider.java diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java index cd97df0e5c6e..b7d1fdf91cb4 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/BlockStateProvider.java @@ -1,10 +1,13 @@ package io.papermc.paper.block.stateprovider; +import io.papermc.paper.block.BlockPredicate; import io.papermc.paper.registry.set.RegistryKeySet; +import java.util.List; import org.bukkit.block.BlockFace; import org.bukkit.block.BlockType; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; import org.jspecify.annotations.Nullable; @ApiStatus.NonExtendable @@ -81,4 +84,47 @@ record RotatedBlockProviderImpl(BlockStateProvider stateProvider, @Nullable Bloc // return new RotatedBlockProviderImpl(stateProvider, direction); } + + /** + * Creates a rule-based provider using the given rules and no fallback provider. + * + * @param rules rule list + * @return a rule-based block state provider + */ + @Contract(value = "_ -> new", pure = true) + static RuleBasedBlockStateProvider ruleBased(final List rules) { + return ruleBased(null, rules); + } + + /** + * Creates a rule-based provider using the given fallback and rules. + * + * @param fallback fallback provider when no rule matches + * @param rules rule list + * @return a rule-based block state provider + */ + @Contract(value = "_, _ -> new", pure = true) + static RuleBasedBlockStateProvider ruleBased(final @Nullable BlockStateProvider fallback, final List rules) { + // + record RuleBasedProviderImpl(@Nullable BlockStateProvider fallback, @Unmodifiable List rules) + implements RuleBasedBlockStateProvider { + RuleBasedProviderImpl { + rules = List.copyOf(rules); + } + } + // + return new RuleBasedProviderImpl(fallback, rules); + } + + /** + * Creates a rule used by {@link #ruleBased(List)} and {@link #ruleBased(BlockStateProvider, List)}. + * + * @param ifTrue predicate that must match + * @param thenProvide provider to use when the predicate matches + * @return an immutable rule + */ + @Contract(value = "_, _ -> new", pure = true) + static RuleBasedBlockStateProvider.Rule rule(final BlockPredicate ifTrue, final BlockStateProvider thenProvide) { + return new RuleBasedBlockStateProvider.Rule(ifTrue, thenProvide); + } } diff --git a/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RuleBasedBlockStateProvider.java b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RuleBasedBlockStateProvider.java new file mode 100644 index 000000000000..d8d16828570a --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/stateprovider/RuleBasedBlockStateProvider.java @@ -0,0 +1,31 @@ +package io.papermc.paper.block.stateprovider; + +import io.papermc.paper.block.BlockPredicate; +import java.util.List; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.Unmodifiable; +import org.jspecify.annotations.Nullable; + +@ApiStatus.NonExtendable +public interface RuleBasedBlockStateProvider extends BlockStateProvider { + + /** + * Fallback provider used when no rule matches, or null if absent. + * + * @return fallback provider or null + */ + @Contract(pure = true) + @Nullable BlockStateProvider fallback(); + + /** + * Ordered rules evaluated from first to last. + * + * @return immutable list of rules + */ + @Contract(pure = true) + @Unmodifiable List rules(); + + record Rule(BlockPredicate ifTrue, BlockStateProvider thenProvide) { + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java index ec370ac93395..e7f67a3f89e0 100644 --- a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java @@ -1,10 +1,12 @@ package io.papermc.paper.block.stateprovider; +import io.papermc.paper.block.PaperBlockPredicate; import io.papermc.paper.registry.PaperRegistries; import io.papermc.paper.registry.RegistryKey; import io.papermc.paper.registry.set.PaperRegistrySets; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.Optional; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -14,6 +16,7 @@ import net.minecraft.world.level.levelgen.feature.stateproviders.CopyPropertiesProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.RandomBlockProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.RotatedBlockProvider; +import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; import net.minecraft.world.level.levelgen.feature.stateproviders.SimpleStateProvider; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.CraftBlockType; @@ -26,51 +29,72 @@ private PaperBlockStateProvider() { } public static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider toVanilla(final BlockStateProvider provider) { - if (provider instanceof final SimpleBlockStateProvider simple) { - return new SimpleStateProvider(CraftBlockType.bukkitToMinecraftNew(simple.blockType()).defaultBlockState()); - } - if (provider instanceof final CopyPropertiesBlockStateProvider copyProperties) { - return new CopyPropertiesProvider( - CraftBlockType.bukkitToMinecraftNew(copyProperties.blockType()) - ); - } - if (provider instanceof final RandomBlockStateProvider randomBlock) { - final List> blocks = new ArrayList<>(); - for (final var key : randomBlock.blocks().values()) { - final Block block = BuiltInRegistries.BLOCK.getValue(PaperRegistries.toNms(key).identifier()); - blocks.add(BuiltInRegistries.BLOCK.wrapAsHolder(block)); + switch (provider) { + case final SimpleBlockStateProvider simple -> { + return new SimpleStateProvider(CraftBlockType.bukkitToMinecraftNew(simple.blockType()).defaultBlockState()); + } + case final CopyPropertiesBlockStateProvider copyProperties -> { + return new CopyPropertiesProvider( + CraftBlockType.bukkitToMinecraftNew(copyProperties.blockType()) + ); + } + case final RandomBlockStateProvider randomBlock -> { + final List> blocks = new ArrayList<>(); + for (final var key : randomBlock.blocks().values()) { + final Block block = BuiltInRegistries.BLOCK.getValue(PaperRegistries.toNms(key).identifier()); + blocks.add(BuiltInRegistries.BLOCK.wrapAsHolder(block)); + } + return new RandomBlockProvider(HolderSet.direct(blocks)); + } + case final RotatedBlockStateProvider rotated -> { + final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider source = toVanilla(rotated.stateProvider()); + final Optional direction = Optional.ofNullable(rotated.direction()) + .map(face -> asArgument(CraftBlock.blockFaceToNotch(face), "direction")); + return new RotatedBlockProvider(Holder.direct(source), direction); + } + case final RuleBasedBlockStateProvider ruleBased -> { + Holder holderFallback = null; + if (ruleBased.fallback() != null) { + holderFallback = Holder.direct(toVanilla(ruleBased.fallback())); + } + final List rules = ruleBased.rules().stream() + .map(rule -> new RuleBasedStateProvider.Rule( + PaperBlockPredicate.toVanilla(rule.ifTrue()), + Holder.direct(toVanilla(rule.thenProvide())) + )) + .toList(); + return new RuleBasedStateProvider(holderFallback, rules); + } + default -> { + throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } - return new RandomBlockProvider(HolderSet.direct(blocks)); - } - if (provider instanceof final RotatedBlockStateProvider rotated) { - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider source = toVanilla(rotated.stateProvider()); - final Optional direction = Optional.ofNullable(rotated.direction()) - .map(face -> asArgument(CraftBlock.blockFaceToNotch(face), "direction")); - return new RotatedBlockProvider(Holder.direct(source), direction); } - throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); } public static BlockStateProvider toApi(final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider) { - if (provider instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state)) { - return BlockStateProvider.simple(CraftBlockType.minecraftToBukkitNew(state.getBlock())); - } - if (provider instanceof CopyPropertiesProvider(Holder source) - && source.value() instanceof SimpleStateProvider(net.minecraft.world.level.block.state.BlockState sourceState)) { - return BlockStateProvider.copyPropertiesFrom(CraftBlockType.minecraftToBukkitNew(sourceState.getBlock())); - } - if (provider instanceof RandomBlockProvider(HolderSet blocks)) { - return BlockStateProvider.randomBlock(PaperRegistrySets.convertToApi(RegistryKey.BLOCK, blocks)); - } - if (provider instanceof RotatedBlockProvider( - Holder state, - Optional direction - )) { - return BlockStateProvider.rotated( + return switch (provider) { + case SimpleStateProvider(net.minecraft.world.level.block.state.BlockState state) -> + BlockStateProvider.simple(CraftBlockType.minecraftToBukkitNew(state.getBlock())); + case CopyPropertiesProvider( + Holder source + ) when source.value() instanceof SimpleStateProvider( + net.minecraft.world.level.block.state.BlockState sourceState + ) -> BlockStateProvider.copyPropertiesFrom(CraftBlockType.minecraftToBukkitNew(sourceState.getBlock())); + case RandomBlockProvider(HolderSet blocks) -> + BlockStateProvider.randomBlock(PaperRegistrySets.convertToApi(RegistryKey.BLOCK, blocks)); + case RotatedBlockProvider( + Holder state, + Optional direction + ) -> BlockStateProvider.rotated( toApi(state.value()), direction.map(CraftBlock::notchToBlockFace).orElse(null) ); - } - throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); + case RuleBasedStateProvider( + Holder fallback, + List rules + ) when fallback == null && rules.size() == 1 -> toApi(rules.getFirst().then().value()); + default -> + throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); + }; } } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 01bc320b9f17..12ff1cc769f9 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -1,8 +1,6 @@ package io.papermc.paper.datacomponent.item.blocktransformer; import io.papermc.paper.adventure.PaperAdventure; -import io.papermc.paper.block.BlockPredicate; -import io.papermc.paper.block.PaperBlockPredicate; import io.papermc.paper.block.stateprovider.BlockStateProvider; import io.papermc.paper.block.stateprovider.PaperBlockStateProvider; import java.util.ArrayList; @@ -17,7 +15,6 @@ import net.minecraft.resources.ResourceKey; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; -import net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider; import org.bukkit.block.BlockFace; import org.bukkit.craftbukkit.CraftLootTable; import org.bukkit.craftbukkit.block.CraftBlock; @@ -41,7 +38,7 @@ public net.minecraft.core.component.BlockTransformer.BlockTransformData getHandl @Override public BlockStateProvider blockStateProvider() { - return PaperBlockStateProvider.toApi(unwrapStateProvider(this.impl.blockStateProvider().value())); + return PaperBlockStateProvider.toApi(this.impl.blockStateProvider().value()); } @Override @@ -121,20 +118,6 @@ public static net.minecraft.core.component.BlockTransformer.BlockTransformData t ); } - private static net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider unwrapStateProvider( - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider - ) { - if (provider instanceof RuleBasedStateProvider( - Holder fallback, - List rules - ) - && fallback == null - && rules.size() == 1) { - return unwrapStateProvider(rules.getFirst().then().value()); - } - return provider; - } - static final class BuilderImpl implements Builder { private static final Holder DEFAULT_SOUND = BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.EMPTY); @@ -151,15 +134,7 @@ static final class BuilderImpl implements Builder { private int itemDamagePerUse = 1; BuilderImpl(final BlockStateProvider blockStateProvider) { - this(null, blockStateProvider); - } - - BuilderImpl(final @Nullable BlockPredicate blockPredicate, final BlockStateProvider blockStateProvider) { - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider targetProvider = PaperBlockStateProvider.toVanilla(blockStateProvider); - final net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider provider = (blockPredicate == null) - ? targetProvider - : RuleBasedStateProvider.builder().ifTrueThenProvide(PaperBlockPredicate.toVanilla(blockPredicate), targetProvider).build(); - this.blockStateProvider = Holder.direct(provider); + this.blockStateProvider = Holder.direct(PaperBlockStateProvider.toVanilla(blockStateProvider)); } @Override From 7c52105b39c58747be37642a8e567f0cb3a0501d Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 12:29:34 -0300 Subject: [PATCH 12/14] Expose a few fields --- build-data/paper.at | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build-data/paper.at b/build-data/paper.at index 9c2035671075..2643186a338a 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -625,6 +625,10 @@ public net.minecraft.world.level.dimension.end.EnderDragonFight spawnNewGateway( public net.minecraft.world.level.entity.PersistentEntitySectionManager ensureChunkQueuedForLoad(J)V public net.minecraft.world.level.entity.PersistentEntitySectionManager permanentStorage public net.minecraft.world.level.gamerules.GameRules rules +public net.minecraft.world.level.levelgen.blockpredicates.CombiningPredicate predicates +public net.minecraft.world.level.levelgen.blockpredicates.MatchingBlocksPredicate blocks +public net.minecraft.world.level.levelgen.blockpredicates.MatchingFluidsPredicate fluids +public net.minecraft.world.level.levelgen.blockpredicates.StateTestingPredicate offset public net.minecraft.world.level.levelgen.material.MaterialRuleContext context public net.minecraft.world.level.levelgen.structure.StructurePiece SHAPE_CHECK_BLOCKS public net.minecraft.world.level.levelgen.structure.placement.AbstractSpreadingStructurePlacement exclusionZone From ff41f2041c3867147e3f2098b89c72a1f9625d2c Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 12:30:47 -0300 Subject: [PATCH 13/14] Support Fluid and rework again the BlockPredicate to allow this --- .../papermc/paper/block/BlockPredicate.java | 74 ++++++----- .../paper/block/fluid/FluidPredicate.java | 40 ++++++ .../paper/block/PaperBlockPredicate.java | 124 +++++++++++++----- .../PaperBlockStateProvider.java | 13 +- .../item/PaperItemAdventurePredicate.java | 11 +- .../PaperBlockTransformData.java | 17 ++- 6 files changed, 207 insertions(+), 72 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/block/fluid/FluidPredicate.java diff --git a/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java b/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java index cacf5cfd6e08..71a3521d1580 100644 --- a/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java +++ b/paper-api/src/main/java/io/papermc/paper/block/BlockPredicate.java @@ -1,5 +1,6 @@ package io.papermc.paper.block; +import io.papermc.paper.annotation.MinecraftVersionDependent; import io.papermc.paper.registry.set.RegistryKeySet; import java.util.List; import org.bukkit.block.BlockFace; @@ -10,17 +11,21 @@ import org.jspecify.annotations.Nullable; @NullMarked +@MinecraftVersionDependent @ApiStatus.NonExtendable public interface BlockPredicate { @Contract(value = "_ -> new", pure = true) - static BlockPredicate matchesBlocks(final @Nullable RegistryKeySet blocks) { + static MatchesBlocks matchesBlocks(final @Nullable RegistryKeySet blocks) { return predicate().blocks(blocks).build(); } @Contract(value = "_, _ -> new", pure = true) - static BlockPredicate matchesDirection(final BlockFace direction, final @Nullable RegistryKeySet blocks) { - return predicate().direction(direction).blocks(blocks).build(); + static MatchesDirection matchesDirection(final BlockFace direction, final @Nullable RegistryKeySet blocks) { + record MatchesDirectionPredicateImpl(@Nullable RegistryKeySet blocks, @Nullable BlockFace direction) + implements MatchesDirection { + } + return new MatchesDirectionPredicateImpl(blocks, direction); } @Contract(value = "_ -> new", pure = true) @@ -43,22 +48,16 @@ static AllOf allOf(final BlockPredicate... predicates) { return allOf(List.of(predicates)); } - static Builder predicate() { + static DirectionalBuilder predicate() { // - record BlockPredicateImpl(@Nullable RegistryKeySet blocks, @Nullable BlockFace direction) - implements BlockPredicate { - @Override - public @Nullable RegistryKeySet blocks() { - return this.blocks; - } + record MatchesBlocksPredicateImpl(@Nullable RegistryKeySet blocks) implements MatchesBlocks { + } - @Override - public @Nullable BlockFace direction() { - return this.direction; - } + record MatchesDirectionPredicateImpl(@Nullable RegistryKeySet blocks, @Nullable BlockFace direction) + implements MatchesDirection { } - class BuilderImpl implements Builder { + class BuilderImpl implements DirectionalBuilder { private @Nullable RegistryKeySet blocks; private @Nullable BlockFace direction; @@ -70,57 +69,62 @@ public Builder blocks(final @Nullable RegistryKeySet blocks) { } @Override - public Builder direction(final @Nullable BlockFace direction) { + public DirectionalBuilder direction(final @Nullable BlockFace direction) { this.direction = direction; return this; } @Override - public BlockPredicate build() { - return new BlockPredicateImpl(this.blocks, this.direction); + public MatchesBlocks build() { + return this.direction == null + ? new MatchesBlocksPredicateImpl(this.blocks) + : new MatchesDirectionPredicateImpl(this.blocks, this.direction); } } // return new BuilderImpl(); } - @Nullable RegistryKeySet blocks(); + @ApiStatus.NonExtendable + interface MatchesBlocks extends BlockPredicate { - default @Nullable BlockFace direction() { - return null; + @Nullable RegistryKeySet blocks(); } @ApiStatus.NonExtendable - interface Builder { + interface MatchesDirection extends MatchesBlocks { + + @Override + @Nullable RegistryKeySet blocks(); + + @Nullable BlockFace direction(); + } + + @ApiStatus.NonExtendable + interface DirectionalBuilder extends Builder { @Contract(value = "_ -> this", mutates = "this") - Builder blocks(@Nullable RegistryKeySet blocks); + DirectionalBuilder direction(@Nullable BlockFace direction); + } + + @ApiStatus.NonExtendable + interface Builder { @Contract(value = "_ -> this", mutates = "this") - Builder direction(@Nullable BlockFace direction); + Builder blocks(@Nullable RegistryKeySet blocks); - BlockPredicate build(); + MatchesBlocks build(); } @ApiStatus.NonExtendable interface AnyOf extends BlockPredicate { - @Override - default @Nullable RegistryKeySet blocks() { - return null; - } - List predicates(); } @ApiStatus.NonExtendable interface AllOf extends BlockPredicate { - @Override - default @Nullable RegistryKeySet blocks() { - return null; - } - List predicates(); } } diff --git a/paper-api/src/main/java/io/papermc/paper/block/fluid/FluidPredicate.java b/paper-api/src/main/java/io/papermc/paper/block/fluid/FluidPredicate.java new file mode 100644 index 000000000000..132a7320c71a --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/block/fluid/FluidPredicate.java @@ -0,0 +1,40 @@ +package io.papermc.paper.block.fluid; + +import io.papermc.paper.annotation.MinecraftVersionDependent; +import io.papermc.paper.block.BlockPredicate; +import io.papermc.paper.registry.set.RegistryKeySet; +import org.bukkit.Fluid; +import org.bukkit.block.BlockFace; +import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.NullMarked; + +@NullMarked +@MinecraftVersionDependent +@ApiStatus.NonExtendable +public interface FluidPredicate extends BlockPredicate { + + static MatchesBlocks matchesFluids(final RegistryKeySet fluids) { + record MatchesBlocksPredicateImpl(RegistryKeySet fluids) implements MatchesBlocks { + } + return new MatchesBlocksPredicateImpl(fluids); + } + + static MatchesDirection matchesDirection(final BlockFace direction, final RegistryKeySet fluids) { + record MatchesDirectionPredicateImpl(RegistryKeySet fluids, BlockFace direction) + implements MatchesDirection { + } + return new MatchesDirectionPredicateImpl(fluids, direction); + } + + @ApiStatus.NonExtendable + interface MatchesBlocks extends FluidPredicate { + + RegistryKeySet fluids(); + } + + @ApiStatus.NonExtendable + interface MatchesDirection extends MatchesBlocks { + + BlockFace direction(); + } +} diff --git a/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java b/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java index c6a660f0c303..05ba534b68e9 100644 --- a/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java +++ b/paper-server/src/main/java/io/papermc/paper/block/PaperBlockPredicate.java @@ -1,60 +1,122 @@ package io.papermc.paper.block; +import io.papermc.paper.block.fluid.FluidPredicate; import io.papermc.paper.registry.PaperRegistries; +import io.papermc.paper.registry.RegistryKey; +import io.papermc.paper.registry.TypedKey; import io.papermc.paper.registry.set.RegistryKeySet; +import io.papermc.paper.registry.set.RegistrySet; import java.util.ArrayList; import java.util.List; import net.minecraft.core.Direction; +import net.minecraft.core.Vec3i; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.material.Fluid; +import org.bukkit.Registry; import org.bukkit.block.BlockType; import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.block.CraftBlockType; +import org.bukkit.craftbukkit.CraftFluid; import org.jspecify.annotations.Nullable; -import static io.papermc.paper.registry.data.util.Checks.asArgument; - public final class PaperBlockPredicate { private PaperBlockPredicate() { } public static net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate toVanilla(final @Nullable BlockPredicate predicate) { - if (predicate == null) { - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + switch (predicate) { + case null -> { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + } + case final FluidPredicate.MatchesDirection fluidMatchesDirection -> { + final List fluids = fluidMatchesDirection.fluids().values().stream() + .map(TypedKey::key) + .map(Registry.FLUID::get) + .filter(java.util.Objects::nonNull) + .map(CraftFluid::bukkitToMinecraft) + .toList(); + final Direction direction = Direction.valueOf(fluidMatchesDirection.direction().name()); + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesFluids( + direction.getStep(), + fluids + ); + } + case final FluidPredicate.MatchesBlocks fluidMatchesBlocks -> { + final List fluids = fluidMatchesBlocks.fluids().values().stream() + .map(TypedKey::key) + .map(Registry.FLUID::get) + .filter(java.util.Objects::nonNull) + .map(CraftFluid::bukkitToMinecraft) + .toList(); + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesFluids(Vec3i.ZERO, fluids); + } + case final BlockPredicate.AnyOf anyOf -> { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.anyOf( + anyOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() + ); + } + case final BlockPredicate.AllOf allOf -> { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf( + allOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() + ); + } + default -> { + final List predicates = new ArrayList<>(); + if (predicate instanceof final BlockPredicate.MatchesBlocks matchesBlocks) { + final RegistryKeySet blocksKeySet = matchesBlocks.blocks(); + final List blocks = blocksKeySet.values().stream() + .map(PaperRegistries::toNms) + .map(key -> BuiltInRegistries.BLOCK.getValue(key.identifier())) + .toList(); + final Block[] array = blocks.toArray(Block[]::new); + predicates.add(net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesBlocks(array)); + } + + if (predicates.isEmpty()) { + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + } + + return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf(predicates); + } } + } - if (predicate instanceof final BlockPredicate.AnyOf anyOf) { - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.anyOf( - anyOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() - ); + public static BlockPredicate toApi(final net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate predicate) { + if (predicate == net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue()) { + return BlockPredicate.predicate().build(); + } + if (predicate instanceof final net.minecraft.world.level.levelgen.blockpredicates.AnyOfPredicate anyOf) { + return BlockPredicate.anyOf(anyOf.predicates.stream().map(PaperBlockPredicate::toApi).toList()); } - if (predicate instanceof final BlockPredicate.AllOf allOf) { - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf( - allOf.predicates().stream().map(PaperBlockPredicate::toVanilla).toList() + if (predicate instanceof final net.minecraft.world.level.levelgen.blockpredicates.AllOfPredicate allOf) { + return BlockPredicate.allOf(allOf.predicates.stream().map(PaperBlockPredicate::toApi).toList()); + } + if (predicate instanceof final net.minecraft.world.level.levelgen.blockpredicates.MatchingBlocksPredicate matchingBlocks) { + final RegistryKeySet blockSet = RegistrySet.keySetFromValues( + RegistryKey.BLOCK, + matchingBlocks.blocks.stream().map(holder -> CraftBlockType.minecraftToBukkitNew(holder.value())).toList() ); + final Vec3i offset = matchingBlocks.offset; + final Direction direction = Direction.getNearest(offset, null); + return direction == null + ? BlockPredicate.matchesBlocks(blockSet) + : BlockPredicate.matchesDirection(CraftBlock.notchToBlockFace(direction), blockSet); } - - final List predicates = new ArrayList<>(); - final Direction direction = predicate.direction() == null ? null : asArgument(CraftBlock.blockFaceToNotch(predicate.direction()), "direction"); - - final RegistryKeySet blocksKeySet = predicate.blocks(); - if (blocksKeySet != null) { - final List blocks = blocksKeySet.values().stream() - .map(PaperRegistries::toNms) - .map(key -> BuiltInRegistries.BLOCK.getValue(key.identifier())) + if (predicate instanceof final net.minecraft.world.level.levelgen.blockpredicates.MatchingFluidsPredicate matchingFluids) { + final java.util.List> fluidKeys = matchingFluids.fluids.stream() + .map(holder -> PaperRegistries.fromNms(holder.unwrapKey().orElseThrow())) + .map(key -> TypedKey.create(RegistryKey.FLUID, key.key())) .toList(); - final Block[] array = blocks.toArray(Block[]::new); - if (direction == null) { - predicates.add(net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesBlocks(array)); - } else { - predicates.add(net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.matchesBlocks(direction, array)); - } - } - - if (predicates.isEmpty()) { - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue(); + final var fluidSet = RegistrySet.keySet(RegistryKey.FLUID, fluidKeys); + final Vec3i offset = matchingFluids.offset; + final Direction direction = Direction.getNearest(offset, null); + return direction == null + ? io.papermc.paper.block.fluid.FluidPredicate.matchesFluids(fluidSet) + : io.papermc.paper.block.fluid.FluidPredicate.matchesDirection(CraftBlock.notchToBlockFace(direction), fluidSet); } - return net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.allOf(predicates); + throw new UnsupportedOperationException("Unsupported block predicate type: " + predicate.getClass().getSimpleName()); } } diff --git a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java index e7f67a3f89e0..13e671cb3f23 100644 --- a/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java +++ b/paper-server/src/main/java/io/papermc/paper/block/stateprovider/PaperBlockStateProvider.java @@ -6,7 +6,6 @@ import io.papermc.paper.registry.set.PaperRegistrySets; import java.util.ArrayList; import java.util.List; -import java.util.Objects; import java.util.Optional; import net.minecraft.core.Direction; import net.minecraft.core.Holder; @@ -92,7 +91,17 @@ case RotatedBlockProvider( case RuleBasedStateProvider( Holder fallback, List rules - ) when fallback == null && rules.size() == 1 -> toApi(rules.getFirst().then().value()); + ) -> BlockStateProvider.ruleBased( + fallback == null ? null : toApi(fallback.value()), + rules.stream() + .map(rule -> BlockStateProvider.rule( + rule.ifTrue() == net.minecraft.world.level.levelgen.blockpredicates.BlockPredicate.alwaysTrue() + ? io.papermc.paper.block.BlockPredicate.predicate().build() + : PaperBlockPredicate.toApi(rule.ifTrue()), + toApi(rule.then().value()) + )) + .toList() + ); default -> throw new UnsupportedOperationException("Unsupported block state provider type: " + provider.getClass().getSimpleName()); }; diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java index 8e658a12032c..8f064dabafe4 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/PaperItemAdventurePredicate.java @@ -37,9 +37,14 @@ static final class BuilderImpl implements ItemAdventurePredicate.Builder { @Override public ItemAdventurePredicate.Builder addPredicate(final BlockPredicate predicate) { - this.predicates.add(new net.minecraft.advancements.predicates.BlockPredicate(Optional.ofNullable(predicate.blocks()).map( - blocks -> PaperRegistrySets.convertToNms(Registries.BLOCK, Conversions.global().lookup(), blocks) - ), Optional.empty(), Optional.empty(), DataComponentMatchers.ANY)); // TODO DataComponentMatchers + this.predicates.add(new net.minecraft.advancements.predicates.BlockPredicate( + Optional.ofNullable(predicate instanceof final BlockPredicate.MatchesBlocks matchesBlocks ? matchesBlocks.blocks() : null).map( + blocks -> PaperRegistrySets.convertToNms(Registries.BLOCK, Conversions.global().lookup(), blocks) + ), + Optional.empty(), + Optional.empty(), + DataComponentMatchers.ANY + )); // TODO DataComponentMatchers return this; } diff --git a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java index 12ff1cc769f9..053f96b5d8df 100644 --- a/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java +++ b/paper-server/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/PaperBlockTransformData.java @@ -1,6 +1,7 @@ package io.papermc.paper.datacomponent.item.blocktransformer; import io.papermc.paper.adventure.PaperAdventure; +import io.papermc.paper.block.BlockPredicate; import io.papermc.paper.block.stateprovider.BlockStateProvider; import io.papermc.paper.block.stateprovider.PaperBlockStateProvider; import java.util.ArrayList; @@ -123,6 +124,7 @@ static final class BuilderImpl implements Builder { private static final Holder DEFAULT_SOUND = BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvents.EMPTY); private final Holder blockStateProvider; + private final @Nullable BlockPredicate predicate; private Holder sound = DEFAULT_SOUND; private BlockTransformer.TransformParticle particle = BlockTransformer.TransformParticle.NONE; private final List disallowedFaces = new ArrayList<>(); @@ -134,6 +136,11 @@ static final class BuilderImpl implements Builder { private int itemDamagePerUse = 1; BuilderImpl(final BlockStateProvider blockStateProvider) { + this(null, blockStateProvider); + } + + BuilderImpl(final @Nullable BlockPredicate predicate, final BlockStateProvider blockStateProvider) { + this.predicate = predicate; this.blockStateProvider = Holder.direct(PaperBlockStateProvider.toVanilla(blockStateProvider)); } @@ -201,7 +208,15 @@ public Builder itemDamagePerUse(final @NonNegative int itemDamagePerUse) { @Override public BlockTransformData build() { return new PaperBlockTransformData(new net.minecraft.core.component.BlockTransformer.BlockTransformData( - this.blockStateProvider, + Holder.direct(this.predicate == null + ? this.blockStateProvider.value() + : new net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider( + null, + List.of(new net.minecraft.world.level.levelgen.feature.stateproviders.RuleBasedStateProvider.Rule( + io.papermc.paper.block.PaperBlockPredicate.toVanilla(this.predicate), + this.blockStateProvider + )) + )), this.sound, this.particle, this.disallowedFaces, From 44565729fd3e5843e981673235c2d9c2e455403e Mon Sep 17 00:00:00 2001 From: Doc Date: Fri, 11 Sep 2026 18:27:55 -0300 Subject: [PATCH 14/14] Lulu comments for move fields and not delayed thing --- .../blocktransformer/BlockTransformer.java | 16 ------------ .../blocktransformer/BlockTransformers.java | 25 +++++++++++++++++++ .../java/io/papermc/generator/Rewriters.java | 4 +-- .../generator/registry/RegistryEntries.java | 2 +- .../paper/registry/PaperRegistries.java | 2 +- 5 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformers.java diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java index 5588e4d059ce..a9ec25915d6f 100644 --- a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformer.java @@ -1,10 +1,6 @@ package io.papermc.paper.datacomponent.item.blocktransformer; -import io.papermc.paper.registry.RegistryAccess; -import io.papermc.paper.registry.RegistryKey; import java.util.List; -import net.kyori.adventure.key.Key; -import net.kyori.adventure.key.KeyPattern; import org.bukkit.Keyed; import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Contract; @@ -13,18 +9,6 @@ @ApiStatus.NonExtendable public interface BlockTransformer extends Keyed { - // Start generate - BlockTransformer - BlockTransformer AXE = getBlockTransformer("axe"); - - BlockTransformer HOE = getBlockTransformer("hoe"); - - BlockTransformer SHOVEL = getBlockTransformer("shovel"); - // End generate - BlockTransformer - - private static BlockTransformer getBlockTransformer(final @KeyPattern.Value String key) { - return RegistryAccess.registryAccess().getRegistry(RegistryKey.BLOCK_TRANSFORMER).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); - } - @Contract(pure = true) @Unmodifiable List transforms(); } diff --git a/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformers.java b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformers.java new file mode 100644 index 000000000000..26517192f0a4 --- /dev/null +++ b/paper-api/src/main/java/io/papermc/paper/datacomponent/item/blocktransformer/BlockTransformers.java @@ -0,0 +1,25 @@ +package io.papermc.paper.datacomponent.item.blocktransformer; + +import io.papermc.paper.registry.RegistryAccess; +import io.papermc.paper.registry.RegistryKey; +import net.kyori.adventure.key.Key; +import net.kyori.adventure.key.KeyPattern; + +/** + * All the vanilla block transformers. + */ +public final class BlockTransformers { + + // Start generate - BlockTransformer + public static final BlockTransformer AXE = getBlockTransformer("axe"); + + public static final BlockTransformer HOE = getBlockTransformer("hoe"); + + public static final BlockTransformer SHOVEL = getBlockTransformer("shovel"); + // End generate - BlockTransformer + + private static BlockTransformer getBlockTransformer(final @KeyPattern.Value String key) { + return RegistryAccess.registryAccess().getRegistry(RegistryKey.BLOCK_TRANSFORMER).getOrThrow(Key.key(Key.MINECRAFT_NAMESPACE, key)); + } + +} diff --git a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java index c2bc5bf08024..fd7e876486be 100644 --- a/paper-generator/src/main/java/io/papermc/generator/Rewriters.java +++ b/paper-generator/src/main/java/io/papermc/generator/Rewriters.java @@ -24,7 +24,7 @@ import io.papermc.generator.types.goal.MobGoalNames; import io.papermc.generator.utils.Formatting; import io.papermc.paper.datacomponent.item.SwingAnimation; -import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformer; +import io.papermc.paper.datacomponent.item.blocktransformer.BlockTransformers; import io.papermc.paper.datacomponent.item.blocktransformer.DropStrategy; import io.papermc.paper.datacomponent.item.blocktransformer.TransformParticle; import io.papermc.paper.datacomponent.item.blocktransformer.TransformType; @@ -257,7 +257,7 @@ protected String rewriteFieldType(Holder.Reference(Registries.BLOCK_TRANSFORMER, "getBlockTransformer")); + .register("BlockTransformer", BlockTransformers.class, new RegistryFieldRewriter<>(Registries.BLOCK_TRANSFORMER, "getBlockTransformer")); RegistryBootstrapper.bootstrapApi(sourceSet); } diff --git a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java index 91f05ff9f1c6..d6288af94670 100644 --- a/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java +++ b/paper-generator/src/main/java/io/papermc/generator/registry/RegistryEntries.java @@ -217,7 +217,7 @@ private static RegistryEntry inconsistentEntry(ResourceKey> API_ONLY = List.of( diff --git a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java index b9c0ebd9732d..6a6115aa2960 100644 --- a/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java +++ b/paper-server/src/main/java/io/papermc/paper/registry/PaperRegistries.java @@ -162,7 +162,7 @@ public final class PaperRegistries { start(Registries.ZOMBIE_NAUTILUS_VARIANT, RegistryKey.ZOMBIE_NAUTILUS_VARIANT).craft(ZombieNautilus.Variant.class, CraftZombieNautilus.CraftVariant::new).writable(PaperZombieNautilusVariantRegistryEntry.PaperBuilder::new), start(Registries.SULFUR_CUBE_ARCHETYPE, RegistryKey.SULFUR_CUBE_ARCHETYPE).craft(SulfurCube.Archetype.class, CraftSulfurCube.CraftArchetype::new).writable(PaperSulfurCubeArchetypeRegistryEntry.PaperBuilder::new), start(Registries.DIALOG, RegistryKey.DIALOG).craft(Dialog.class, PaperDialog::new, true).writable(PaperDialogRegistryEntry.PaperBuilder::new), - start(Registries.BLOCK_TRANSFORMER, RegistryKey.BLOCK_TRANSFORMER).craft(BlockTransformer.class, PaperBlockTransformer::new, true).writable(PaperBlockTransformerRegistryEntry.PaperBuilder::new).delayed(), + start(Registries.BLOCK_TRANSFORMER, RegistryKey.BLOCK_TRANSFORMER).craft(BlockTransformer.class, PaperBlockTransformer::new, true).writable(PaperBlockTransformerRegistryEntry.PaperBuilder::new), // api-only start(Registries.ENTITY_TYPE, RegistryKey.ENTITY_TYPE).apiOnly(PaperSimpleRegistry::entityType),