aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-vineflower-stripped/net/minecraft/world/item
diff options
context:
space:
mode:
authorMiniDigger | Martin <[email protected]>2024-01-14 11:04:49 +0100
committerMiniDigger | Martin <[email protected]>2024-01-14 11:04:49 +0100
commitbee74680e607c2e29b038329f62181238911cd83 (patch)
tree708fd1a4a0227d9071243adf2a42d5e9e96cde4a /patch-remap/mache-vineflower-stripped/net/minecraft/world/item
parent0a44692ef6ff6e255d48eb3ba1bb114166eafda9 (diff)
downloadPaper-softspoon.tar.gz
Paper-softspoon.zip
add remapped patches as a testsoftspoon
Diffstat (limited to 'patch-remap/mache-vineflower-stripped/net/minecraft/world/item')
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorItem.java.patch64
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorStandItem.java.patch27
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BlockItem.java.patch159
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoatItem.java.patch43
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoneMealItem.java.patch47
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BowItem.java.patch34
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BucketItem.java.patch138
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ChorusFruitItem.java.patch30
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/CrossbowItem.java.patch34
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DebugStickItem.java.patch1
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DyeItem.java.patch38
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EggItem.java.patch42
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EndCrystalItem.java.patch33
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderEyeItem.java.patch32
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderpearlItem.java.patch37
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FireChargeItem.java.patch47
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FishingRodItem.java.patch42
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FlintAndSteelItem.java.patch70
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/HangingEntityItem.java.patch44
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ItemStack.java.patch327
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/LeadItem.java.patch99
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MapItem.java.patch14
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MilkBucketItem.java.patch11
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MinecartItem.java.patch90
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/PotionItem.java.patch11
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/RecordItem.java.patch36
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SignItem.java.patch42
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SnowballItem.java.patch41
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SpawnEggItem.java.patch13
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/StandingAndWallBlockItem.java.patch34
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/TridentItem.java.patch100
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/BlastingRecipe.java.patch35
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch35
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CustomRecipe.java.patch29
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Ingredient.java.patch35
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Recipe.java.patch9
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeHolder.java.patch22
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeManager.java.patch165
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapedRecipe.java.patch86
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch39
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch35
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch60
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch37
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmokingRecipe.java.patch35
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch34
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch20
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch36
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/Merchant.java.patch9
-rw-r--r--patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/MerchantOffer.java.patch73
49 files changed, 2574 insertions, 0 deletions
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorItem.java.patch
new file mode 100644
index 0000000000..0074fd1f09
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorItem.java.patch
@@ -0,0 +1,64 @@
+--- a/net/minecraft/world/item/ArmorItem.java
++++ b/net/minecraft/world/item/ArmorItem.java
+@@ -25,6 +26,11 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.DispenserBlock;
+ import net.minecraft.world.phys.AABB;
++// CraftBukkit start
++import org.bukkit.craftbukkit.block.CraftBlock;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.event.block.BlockDispenseArmorEvent;
++// CraftBukkit end
+
+ public class ArmorItem extends Item implements Equipable {
+ private static final EnumMap<ArmorItem.Type, UUID> ARMOR_MODIFIER_UUID_PER_TYPE = Util.make(new EnumMap<>(ArmorItem.Type.class), map -> {
+@@ -55,15 +60,42 @@
+ if (entitiesOfClass.isEmpty()) {
+ return false;
+ } else {
+- LivingEntity livingEntity = entitiesOfClass.get(0);
+- EquipmentSlot equipmentSlotForItem = Mob.getEquipmentSlotForItem(itemStack);
+- ItemStack itemStack1 = itemStack.split(1);
+- livingEntity.setItemSlot(equipmentSlotForItem, itemStack1);
+- if (livingEntity instanceof Mob) {
+- ((Mob)livingEntity).setDropChance(equipmentSlotForItem, 2.0F);
+- ((Mob)livingEntity).setPersistenceRequired();
++ LivingEntity entityliving = (LivingEntity) list.get(0);
++ EquipmentSlot enumitemslot = Mob.getEquipmentSlotForItem(itemstack);
++ ItemStack itemstack1 = itemstack.split(1);
++ // CraftBukkit start
++ Level world = sourceblock.level();
++ org.bukkit.block.Block block = CraftBlock.at(world, sourceblock.pos());
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
++
++ BlockDispenseArmorEvent event = new BlockDispenseArmorEvent(block, craftItem.clone(), (org.bukkit.craftbukkit.entity.CraftLivingEntity) entityliving.getBukkitEntity());
++ if (!DispenserBlock.eventFired) {
++ world.getCraftServer().getPluginManager().callEvent(event);
+ }
+
++ if (event.isCancelled()) {
++ itemstack.grow(1);
++ return false;
++ }
++
++ if (!event.getItem().equals(craftItem)) {
++ itemstack.grow(1);
++ // Chain to handler for new item
++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
++ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != ArmorItem.DISPENSE_ITEM_BEHAVIOR) {
++ idispensebehavior.dispense(sourceblock, eventStack);
++ return true;
++ }
++ }
++
++ entityliving.setItemSlot(enumitemslot, CraftItemStack.asNMSCopy(event.getItem()));
++ // CraftBukkit end
++ if (entityliving instanceof Mob) {
++ ((Mob) entityliving).setDropChance(enumitemslot, 2.0F);
++ ((Mob) entityliving).setPersistenceRequired();
++ }
++
+ return true;
+ }
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorStandItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorStandItem.java.patch
new file mode 100644
index 0000000000..4c3a37c97b
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ArmorStandItem.java.patch
@@ -0,0 +1,27 @@
+--- a/net/minecraft/world/item/ArmorStandItem.java
++++ b/net/minecraft/world/item/ArmorStandItem.java
+@@ -44,13 +50,17 @@
+ return InteractionResult.FAIL;
+ }
+
+- float f = (float)Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F;
+- armorStand.moveTo(armorStand.getX(), armorStand.getY(), armorStand.getZ(), f, 0.0F);
+- serverLevel.addFreshEntityWithPassengers(armorStand);
+- level.playSound(
+- null, armorStand.getX(), armorStand.getY(), armorStand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F
+- );
+- armorStand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer());
++ float f = (float) Mth.floor((Mth.wrapDegrees(context.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F;
++
++ entityarmorstand.moveTo(entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), f, 0.0F);
++ // CraftBukkit start
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityarmorstand).isCancelled()) {
++ return InteractionResult.FAIL;
++ }
++ // CraftBukkit end
++ worldserver.addFreshEntityWithPassengers(entityarmorstand);
++ world.playSound((Player) null, entityarmorstand.getX(), entityarmorstand.getY(), entityarmorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F);
++ entityarmorstand.gameEvent(GameEvent.ENTITY_PLACE, context.getPlayer());
+ }
+
+ itemInHand.shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BlockItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BlockItem.java.patch
new file mode 100644
index 0000000000..d8963fdd26
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BlockItem.java.patch
@@ -0,0 +1,159 @@
+--- a/net/minecraft/world/item/BlockItem.java
++++ b/net/minecraft/world/item/BlockItem.java
+@@ -29,6 +32,10 @@
+ import net.minecraft.world.level.block.state.properties.Property;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.shapes.CollisionContext;
++import org.bukkit.craftbukkit.block.CraftBlock;
++import org.bukkit.craftbukkit.block.data.CraftBlockData;
++import org.bukkit.event.block.BlockCanBuildEvent;
++// CraftBukkit end
+
+ public class BlockItem extends Item {
+ public static final String BLOCK_ENTITY_TAG = "BlockEntityTag";
+@@ -62,38 +74,53 @@
+ if (blockPlaceContext == null) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockState placementState = this.getPlacementState(blockPlaceContext);
+- if (placementState == null) {
++ IBlockData iblockdata = this.getPlacementState(blockactioncontext1);
++ // CraftBukkit start - special case for handling block placement with water lilies and snow buckets
++ org.bukkit.block.BlockState blockstate = null;
++ if (this instanceof PlaceOnWaterBlockItem || this instanceof SolidBucketItem) {
++ blockstate = org.bukkit.craftbukkit.block.CraftBlockStates.getBlockState(blockactioncontext1.getLevel(), blockactioncontext1.getClickedPos());
++ }
++ // CraftBukkit end
++
++ if (iblockdata == null) {
+ return InteractionResult.FAIL;
+ } else if (!this.placeBlock(blockPlaceContext, placementState)) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockPos clickedPos = blockPlaceContext.getClickedPos();
+- Level level = blockPlaceContext.getLevel();
+- Player player = blockPlaceContext.getPlayer();
+- ItemStack itemInHand = blockPlaceContext.getItemInHand();
+- BlockState blockState = level.getBlockState(clickedPos);
+- if (blockState.is(placementState.getBlock())) {
+- blockState = this.updateBlockStateFromTag(clickedPos, level, itemInHand, blockState);
+- this.updateCustomBlockEntityTag(clickedPos, level, player, itemInHand, blockState);
+- blockState.getBlock().setPlacedBy(level, clickedPos, blockState, player, itemInHand);
+- if (player instanceof ServerPlayer) {
+- CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, clickedPos, itemInHand);
++ BlockPos blockposition = blockactioncontext1.getClickedPos();
++ Level world = blockactioncontext1.getLevel();
++ Player entityhuman = blockactioncontext1.getPlayer();
++ ItemStack itemstack = blockactioncontext1.getItemInHand();
++ IBlockData iblockdata1 = world.getBlockState(blockposition);
++
++ if (iblockdata1.is(iblockdata.getBlock())) {
++ iblockdata1 = this.updateBlockStateFromTag(blockposition, world, itemstack, iblockdata1);
++ this.updateCustomBlockEntityTag(blockposition, world, entityhuman, itemstack, iblockdata1);
++ iblockdata1.getBlock().setPlacedBy(world, blockposition, iblockdata1, entityhuman, itemstack);
++ // CraftBukkit start
++ if (blockstate != null) {
++ org.bukkit.event.block.BlockPlaceEvent placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent((ServerLevel) world, entityhuman, blockactioncontext1.getHand(), blockstate, blockposition.getX(), blockposition.getY(), blockposition.getZ());
++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
++ blockstate.update(true, false);
++
++ if (this instanceof SolidBucketItem) {
++ ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541
++ }
++ return InteractionResult.FAIL;
++ }
+ }
++ // CraftBukkit end
++ if (entityhuman instanceof ServerPlayer) {
++ CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) entityhuman, blockposition, itemstack);
++ }
+ }
+
+- SoundType soundType = blockState.getSoundType();
+- level.playSound(
+- player,
+- clickedPos,
+- this.getPlaceSound(blockState),
+- SoundSource.BLOCKS,
+- (soundType.getVolume() + 1.0F) / 2.0F,
+- soundType.getPitch() * 0.8F
+- );
+- level.gameEvent(GameEvent.BLOCK_PLACE, clickedPos, GameEvent.Context.of(player, blockState));
+- if (player == null || !player.getAbilities().instabuild) {
+- itemInHand.shrink(1);
++ SoundType soundeffecttype = iblockdata1.getSoundType();
++
++ // world.playSound(entityhuman, blockposition, this.getPlaceSound(iblockdata1), SoundCategory.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
++ world.gameEvent(GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(entityhuman, iblockdata1));
++ if ((entityhuman == null || !entityhuman.getAbilities().instabuild) && itemstack != ItemStack.EMPTY) { // CraftBukkit
++ itemstack.shrink(1);
+ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide);
+@@ -128,13 +153,10 @@
+ CompoundTag compound = tag.getCompound("BlockStateTag");
+ StateDefinition<Block, BlockState> stateDefinition = state.getBlock().getStateDefinition();
+
+- for (String string : compound.getAllKeys()) {
+- Property<?> property = stateDefinition.getProperty(string);
+- if (property != null) {
+- String asString = compound.get(string).getAsString();
+- blockState = updateState(blockState, property, asString);
+- }
+- }
++ if (nbttagcompound != null) {
++ CompoundTag nbttagcompound1 = nbttagcompound.getCompound("BlockStateTag");
++ // CraftBukkit start
++ iblockdata1 = getBlockState(iblockdata1, nbttagcompound1);
+ }
+
+ if (blockState != state) {
+@@ -144,8 +166,25 @@
+ return blockState;
+ }
+
+- private static <T extends Comparable<T>> BlockState updateState(BlockState state, Property<T> property, String valueIdentifier) {
+- return property.getValue(valueIdentifier).map(comparable -> state.setValue(property, comparable)).orElse(state);
++ public static IBlockData getBlockState(IBlockData iblockdata, CompoundTag nbttagcompound1) {
++ IBlockData iblockdata1 = iblockdata;
++ {
++ // CraftBukkit end
++ StateDefinition<Block, IBlockData> blockstatelist = iblockdata.getBlock().getStateDefinition();
++ Iterator iterator = nbttagcompound1.getAllKeys().iterator();
++
++ while (iterator.hasNext()) {
++ String s = (String) iterator.next();
++ Property<?> iblockstate = blockstatelist.getProperty(s);
++
++ if (iblockstate != null) {
++ String s1 = nbttagcompound1.get(s).getAsString();
++
++ iblockdata1 = updateState(iblockdata1, iblockstate, s1);
++ }
++ }
++ }
++ return iblockdata1;
+ }
+
+ protected boolean canPlace(BlockPlaceContext context, BlockState state) {
+@@ -155,6 +193,20 @@
+ && context.getLevel().isUnobstructed(state, context.getClickedPos(), collisionContext);
+ }
+
++ protected boolean canPlace(BlockPlaceContext context, IBlockData state) {
++ Player entityhuman = context.getPlayer();
++ CollisionContext voxelshapecollision = entityhuman == null ? CollisionContext.empty() : CollisionContext.of(entityhuman);
++ // CraftBukkit start - store default return
++ boolean defaultReturn = (!this.mustSurvive() || state.canSurvive(context.getLevel(), context.getClickedPos())) && context.getLevel().isUnobstructed(state, context.getClickedPos(), voxelshapecollision);
++ org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
++
++ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(context.getLevel(), context.getClickedPos()), player, CraftBlockData.fromData(state), defaultReturn);
++ context.getLevel().getCraftServer().getPluginManager().callEvent(event);
++
++ return event.isBuildable();
++ // CraftBukkit end
++ }
++
+ protected boolean mustSurvive() {
+ return true;
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoatItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoatItem.java.patch
new file mode 100644
index 0000000000..28d2866305
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoatItem.java.patch
@@ -0,0 +1,43 @@
+--- a/net/minecraft/world/item/BoatItem.java
++++ b/net/minecraft/world/item/BoatItem.java
+@@ -51,16 +59,32 @@
+ }
+ }
+
+- if (playerPOVHitResult.getType() == HitResult.Type.BLOCK) {
+- Boat boat = this.getBoat(level, playerPOVHitResult, itemInHand, player);
+- boat.setVariant(this.type);
+- boat.setYRot(player.getYRot());
+- if (!level.noCollision(boat, boat.getBoundingBox())) {
+- return InteractionResultHolder.fail(itemInHand);
++ if (movingobjectpositionblock.getType() == HitResult.EnumMovingObjectType.BLOCK) {
++ // CraftBukkit start - Boat placement
++ org.bukkit.event.player.PlayerInteractEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerInteractEvent(player, org.bukkit.event.block.Action.RIGHT_CLICK_BLOCK, movingobjectpositionblock.getBlockPos(), movingobjectpositionblock.getDirection(), itemstack, false, hand, movingobjectpositionblock.getLocation());
++
++ if (event.isCancelled()) {
++ return InteractionResultHolder.pass(itemstack);
++ }
++ // CraftBukkit end
++ Boat entityboat = this.getBoat(level, movingobjectpositionblock, itemstack, player);
++
++ entityboat.setVariant(this.type);
++ entityboat.setYRot(player.getYRot());
++ if (!level.noCollision(entityboat, entityboat.getBoundingBox())) {
++ return InteractionResultHolder.fail(itemstack);
+ } else {
+ if (!level.isClientSide) {
+- level.addFreshEntity(boat);
+- level.gameEvent(player, GameEvent.ENTITY_PLACE, playerPOVHitResult.getLocation());
++ // CraftBukkit start
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(level, movingobjectpositionblock.getBlockPos(), movingobjectpositionblock.getDirection(), player, entityboat, hand).isCancelled()) {
++ return InteractionResultHolder.fail(itemstack);
++ }
++
++ if (!level.addFreshEntity(entityboat)) {
++ return InteractionResultHolder.pass(itemstack);
++ }
++ // CraftBukkit end
++ level.gameEvent((Entity) player, GameEvent.ENTITY_PLACE, movingobjectpositionblock.getLocation());
+ if (!player.getAbilities().instabuild) {
+ itemInHand.shrink(1);
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoneMealItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoneMealItem.java.patch
new file mode 100644
index 0000000000..8dec6340c2
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BoneMealItem.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/BoneMealItem.java
++++ b/net/minecraft/world/item/BoneMealItem.java
+@@ -34,23 +34,31 @@
+
+ @Override
+ public InteractionResult useOn(UseOnContext context) {
+- Level level = context.getLevel();
+- BlockPos clickedPos = context.getClickedPos();
+- BlockPos blockPos = clickedPos.relative(context.getClickedFace());
+- if (growCrop(context.getItemInHand(), level, clickedPos)) {
+- if (!level.isClientSide) {
+- context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+- level.levelEvent(1505, clickedPos, 0);
++ // CraftBukkit start - extract bonemeal application logic to separate, static method
++ return applyBonemeal(context);
++ }
++
++ public static InteractionResult applyBonemeal(UseOnContext itemactioncontext) {
++ // CraftBukkit end
++ Level world = itemactioncontext.getLevel();
++ BlockPos blockposition = itemactioncontext.getClickedPos();
++ BlockPos blockposition1 = blockposition.relative(itemactioncontext.getClickedFace());
++
++ if (growCrop(itemactioncontext.getItemInHand(), world, blockposition)) {
++ if (!world.isClientSide) {
++ if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
++ world.levelEvent(1505, blockposition, 0);
+ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide);
+ } else {
+- BlockState blockState = level.getBlockState(clickedPos);
+- boolean isFaceSturdy = blockState.isFaceSturdy(level, clickedPos, context.getClickedFace());
+- if (isFaceSturdy && growWaterPlant(context.getItemInHand(), level, blockPos, context.getClickedFace())) {
+- if (!level.isClientSide) {
+- context.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+- level.levelEvent(1505, blockPos, 0);
++ IBlockData iblockdata = world.getBlockState(blockposition);
++ boolean flag = iblockdata.isFaceSturdy(world, blockposition, itemactioncontext.getClickedFace());
++
++ if (flag && growWaterPlant(itemactioncontext.getItemInHand(), world, blockposition1, itemactioncontext.getClickedFace())) {
++ if (!world.isClientSide) {
++ if (itemactioncontext.getPlayer() != null) itemactioncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH); // CraftBukkit - SPIGOT-7518
++ world.levelEvent(1505, blockposition1, 0);
+ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BowItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BowItem.java.patch
new file mode 100644
index 0000000000..9c7d43a137
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BowItem.java.patch
@@ -0,0 +1,34 @@
+--- a/net/minecraft/world/item/BowItem.java
++++ b/net/minecraft/world/item/BowItem.java
+@@ -56,13 +64,30 @@
+ if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.FLAMING_ARROWS, stack) > 0) {
+ abstractArrow.setSecondsOnFire(100);
+ }
++ // CraftBukkit start
++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(entityhuman, stack, itemstack1, entityarrow, entityhuman.getUsedItemHand(), f, !flag1);
++ if (event.isCancelled()) {
++ event.getProjectile().remove();
++ return;
++ }
++ flag1 = !event.shouldConsumeItem();
++ // CraftBukkit end
+
+ stack.hurtAndBreak(1, player, player1 -> player1.broadcastBreakEvent(player.getUsedItemHand()));
+ if (flag1 || player.getAbilities().instabuild && (projectile.is(Items.SPECTRAL_ARROW) || projectile.is(Items.TIPPED_ARROW))) {
+ abstractArrow.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
+ }
+
+- level.addFreshEntity(abstractArrow);
++ // CraftBukkit start
++ if (event.getProjectile() == entityarrow.getBukkitEntity()) {
++ if (!level.addFreshEntity(entityarrow)) {
++ if (entityhuman instanceof net.minecraft.server.level.ServerPlayer) {
++ ((net.minecraft.server.level.ServerPlayer) entityhuman).getBukkitEntity().updateInventory();
++ }
++ return;
++ }
++ }
++ // CraftBukkit end
+ }
+
+ level.playSound(
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BucketItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BucketItem.java.patch
new file mode 100644
index 0000000000..744bc0754d
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/BucketItem.java.patch
@@ -0,0 +1,138 @@
+--- a/net/minecraft/world/item/BucketItem.java
++++ b/net/minecraft/world/item/BucketItem.java
+@@ -27,6 +30,12 @@
+ import net.minecraft.world.level.material.Fluids;
+ import net.minecraft.world.phys.BlockHitResult;
+ import net.minecraft.world.phys.HitResult;
++import org.bukkit.craftbukkit.event.CraftEventFactory;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.util.DummyGeneratorAccess;
++import org.bukkit.event.player.PlayerBucketEmptyEvent;
++import org.bukkit.event.player.PlayerBucketFillEvent;
++// CraftBukkit end
+
+ public class BucketItem extends Item implements DispensibleContainerItem {
+ private final Fluid content;
+@@ -47,27 +56,39 @@
+ } else if (playerPOVHitResult.getType() != HitResult.Type.BLOCK) {
+ return InteractionResultHolder.pass(itemInHand);
+ } else {
+- BlockPos blockPos = playerPOVHitResult.getBlockPos();
+- Direction direction = playerPOVHitResult.getDirection();
+- BlockPos blockPos1 = blockPos.relative(direction);
+- if (!level.mayInteract(player, blockPos) || !player.mayUseItemAt(blockPos1, direction, itemInHand)) {
+- return InteractionResultHolder.fail(itemInHand);
+- } else if (this.content == Fluids.EMPTY) {
+- BlockState blockState = level.getBlockState(blockPos);
+- if (blockState.getBlock() instanceof BucketPickup bucketPickup) {
+- ItemStack itemStack = bucketPickup.pickupBlock(player, level, blockPos, blockState);
+- if (!itemStack.isEmpty()) {
+- player.awardStat(Stats.ITEM_USED.get(this));
+- bucketPickup.getPickupSound().ifPresent(soundEvent -> player.playSound(soundEvent, 1.0F, 1.0F));
+- level.gameEvent(player, GameEvent.FLUID_PICKUP, blockPos);
+- ItemStack itemStack1 = ItemUtils.createFilledResult(itemInHand, player, itemStack);
+- if (!level.isClientSide) {
+- CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)player, itemStack);
++ BlockPos blockposition = movingobjectpositionblock.getBlockPos();
++ Direction enumdirection = movingobjectpositionblock.getDirection();
++ BlockPos blockposition1 = blockposition.relative(enumdirection);
++
++ if (level.mayInteract(player, blockposition) && player.mayUseItemAt(blockposition1, enumdirection, itemstack)) {
++ IBlockData iblockdata;
++
++ if (this.content == Fluids.EMPTY) {
++ iblockdata = level.getBlockState(blockposition);
++ Block block = iblockdata.getBlock();
++
++ if (block instanceof BucketPickup) {
++ BucketPickup ifluidsource = (BucketPickup) block;
++ // CraftBukkit start
++ ItemStack dummyFluid = ifluidsource.pickupBlock(player, DummyGeneratorAccess.INSTANCE, blockposition, iblockdata);
++ if (dummyFluid.isEmpty()) return InteractionResultHolder.fail(itemstack); // Don't fire event if the bucket won't be filled.
++ PlayerBucketFillEvent event = CraftEventFactory.callPlayerBucketFillEvent((ServerLevel) level, player, blockposition, blockposition, movingobjectpositionblock.getDirection(), itemstack, dummyFluid.getItem(), hand);
++
++ if (event.isCancelled()) {
++ ((ServerPlayer) player).connection.send(new ClientboundBlockUpdatePacket(level, blockposition)); // SPIGOT-5163 (see PlayerInteractManager)
++ ((ServerPlayer) player).getBukkitEntity().updateInventory(); // SPIGOT-4541
++ return InteractionResultHolder.fail(itemstack);
+ }
++ // CraftBukkit end
++ ItemStack itemstack1 = ifluidsource.pickupBlock(player, level, blockposition, iblockdata);
+
+- return InteractionResultHolder.sidedSuccess(itemStack1, level.isClientSide());
+- }
+- }
++ if (!itemstack1.isEmpty()) {
++ player.awardStat(Stats.ITEM_USED.get(this));
++ ifluidsource.getPickupSound().ifPresent((soundeffect) -> {
++ player.playSound(soundeffect, 1.0F, 1.0F);
++ });
++ level.gameEvent((Entity) player, GameEvent.FLUID_PICKUP, blockposition);
++ ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, player, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit
+
+ return InteractionResultHolder.fail(itemInHand);
+ } else {
+@@ -82,7 +100,20 @@
+ player.awardStat(Stats.ITEM_USED.get(this));
+ return InteractionResultHolder.sidedSuccess(getEmptySuccessItem(itemInHand, player), level.isClientSide());
+ } else {
+- return InteractionResultHolder.fail(itemInHand);
++ iblockdata = level.getBlockState(blockposition);
++ BlockPos blockposition2 = iblockdata.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? blockposition : blockposition1;
++
++ if (this.emptyContents(player, level, blockposition2, movingobjectpositionblock, movingobjectpositionblock.getDirection(), blockposition, itemstack, hand)) { // CraftBukkit
++ this.checkExtraContent(player, level, itemstack, blockposition2);
++ if (player instanceof ServerPlayer) {
++ CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) player, blockposition2, itemstack);
++ }
++
++ player.awardStat(Stats.ITEM_USED.get(this));
++ return InteractionResultHolder.sidedSuccess(getEmptySuccessItem(itemstack, player), level.isClientSide());
++ } else {
++ return InteractionResultHolder.fail(itemstack);
++ }
+ }
+ }
+ }
+@@ -98,7 +130,15 @@
+
+ @Override
+ public boolean emptyContents(@Nullable Player player, Level level, BlockPos pos, @Nullable BlockHitResult result) {
+- if (!(this.content instanceof FlowingFluid flowingFluid)) {
++ // CraftBukkit start
++ return emptyContents(player, level, pos, result, null, null, null, EnumHand.MAIN_HAND);
++ }
++
++ public boolean emptyContents(Player entityhuman, Level world, BlockPos blockposition, @Nullable BlockHitResult movingobjectpositionblock, Direction enumdirection, BlockPos clicked, ItemStack itemstack, EnumHand enumhand) {
++ // CraftBukkit end
++ Fluid fluidtype = this.content;
++
++ if (!(fluidtype instanceof FlowingFluid)) {
+ return false;
+ } else {
+ Block block;
+@@ -134,9 +173,22 @@
+ player, pos, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.8F
+ );
+
+- for (int i = 0; i < 8; i++) {
+- level.addParticle(ParticleTypes.LARGE_SMOKE, (double)x + Math.random(), (double)y + Math.random(), (double)z + Math.random(), 0.0, 0.0, 0.0);
++ // CraftBukkit start
++ if (flag2 && entityhuman != null) {
++ PlayerBucketEmptyEvent event = CraftEventFactory.callPlayerBucketEmptyEvent((ServerLevel) world, entityhuman, blockposition, clicked, enumdirection, itemstack, enumhand);
++ if (event.isCancelled()) {
++ ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, blockposition)); // SPIGOT-4238: needed when looking through entity
++ ((ServerPlayer) entityhuman).getBukkitEntity().updateInventory(); // SPIGOT-4541
++ return false;
+ }
++ }
++ // CraftBukkit end
++ if (!flag2) {
++ return movingobjectpositionblock != null && this.emptyContents(entityhuman, world, movingobjectpositionblock.getBlockPos().relative(movingobjectpositionblock.getDirection()), (BlockHitResult) null, enumdirection, clicked, itemstack, enumhand); // CraftBukkit
++ } else if (world.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
++ int i = blockposition.getX();
++ int j = blockposition.getY();
++ int k = blockposition.getZ();
+
+ return true;
+ } else {
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ChorusFruitItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ChorusFruitItem.java.patch
new file mode 100644
index 0000000000..b5bec9cc49
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ChorusFruitItem.java.patch
@@ -0,0 +1,30 @@
+--- a/net/minecraft/world/item/ChorusFruitItem.java
++++ b/net/minecraft/world/item/ChorusFruitItem.java
+@@ -33,11 +33,22 @@
+ entityLiving.stopRiding();
+ }
+
+- Vec3 vec3 = entityLiving.position();
+- if (entityLiving.randomTeleport(d, d1, d2, true)) {
+- level.gameEvent(GameEvent.TELEPORT, vec3, GameEvent.Context.of(entityLiving));
+- SoundSource soundSource;
+- SoundEvent soundEvent;
++ Vec3 vec3d = entityLiving.position();
++
++ // CraftBukkit start - handle canceled status of teleport event
++ java.util.Optional<Boolean> status = entityLiving.randomTeleport(d0, d1, d2, true, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.CHORUS_FRUIT);
++
++ if (!status.isPresent()) {
++ // teleport event was canceled, no more tries
++ break;
++ }
++
++ if (status.get()) {
++ // CraftBukkit end
++ level.gameEvent(GameEvent.TELEPORT, vec3d, GameEvent.Context.of((Entity) entityLiving));
++ SoundEvent soundeffect;
++ SoundSource soundcategory;
++
+ if (entityLiving instanceof Fox) {
+ soundEvent = SoundEvents.FOX_TELEPORT;
+ soundSource = SoundSource.NEUTRAL;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/CrossbowItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/CrossbowItem.java.patch
new file mode 100644
index 0000000000..49ad59c5bf
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/CrossbowItem.java.patch
@@ -0,0 +1,34 @@
+--- a/net/minecraft/world/item/CrossbowItem.java
++++ b/net/minecraft/world/item/CrossbowItem.java
+@@ -234,10 +236,28 @@
+ Vector3f vector3f = viewVector.toVector3f().rotate(quaternionf);
+ projectile.shoot((double)vector3f.x(), (double)vector3f.y(), (double)vector3f.z(), velocity, inaccuracy);
+ }
++ // CraftBukkit start
++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(shooter, crossbowStack, ammoStack, (Entity) object, shooter.getUsedItemHand(), soundPitch, true);
++ if (event.isCancelled()) {
++ event.getProjectile().remove();
++ return;
++ }
++ // CraftBukkit end
+
+- crossbowStack.hurtAndBreak(isFireworkRocket ? 3 : 1, shooter, contextEntity -> contextEntity.broadcastBreakEvent(hand));
+- level.addFreshEntity(projectile);
+- level.playSound(null, shooter.getX(), shooter.getY(), shooter.getZ(), SoundEvents.CROSSBOW_SHOOT, SoundSource.PLAYERS, 1.0F, soundPitch);
++ crossbowStack.hurtAndBreak(flag1 ? 3 : 1, shooter, (entityliving1) -> {
++ entityliving1.broadcastBreakEvent(hand);
++ });
++ // CraftBukkit start
++ if (event.getProjectile() == ((Entity) object).getBukkitEntity()) {
++ if (!level.addFreshEntity((Entity) object)) {
++ if (shooter instanceof ServerPlayer) {
++ ((ServerPlayer) shooter).getBukkitEntity().updateInventory();
++ }
++ return;
++ }
++ }
++ // CraftBukkit end
++ level.playSound((Player) null, shooter.getX(), shooter.getY(), shooter.getZ(), SoundEvents.CROSSBOW_SHOOT, SoundSource.PLAYERS, 1.0F, soundPitch);
+ }
+ }
+
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DebugStickItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DebugStickItem.java.patch
new file mode 100644
index 0000000000..8b13789179
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DebugStickItem.java.patch
@@ -0,0 +1 @@
+
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DyeItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DyeItem.java.patch
new file mode 100644
index 0000000000..0d41c2aec7
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/DyeItem.java.patch
@@ -0,0 +1,38 @@
+--- a/net/minecraft/world/item/DyeItem.java
++++ b/net/minecraft/world/item/DyeItem.java
+@@ -11,7 +12,7 @@
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.entity.SignBlockEntity;
+-import net.minecraft.world.level.block.entity.SignText;
++import org.bukkit.event.entity.SheepDyeWoolEvent; // CraftBukkit
+
+ public class DyeItem extends Item implements SignApplicator {
+ private static final Map<DyeColor, DyeItem> ITEM_BY_COLOR = Maps.newEnumMap(DyeColor.class);
+@@ -32,7 +30,25 @@
+ stack.shrink(1);
+ }
+
+- return InteractionResult.sidedSuccess(player.level().isClientSide);
++ if (entitysheep.isAlive() && !entitysheep.isSheared() && entitysheep.getColor() != this.dyeColor) {
++ entitysheep.level().playSound(player, (Entity) entitysheep, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1.0F, 1.0F);
++ if (!player.level().isClientSide) {
++ // CraftBukkit start
++ byte bColor = (byte) this.dyeColor.getId();
++ SheepDyeWoolEvent event = new SheepDyeWoolEvent((org.bukkit.entity.Sheep) entitysheep.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData(bColor), (org.bukkit.entity.Player) player.getBukkitEntity());
++ entitysheep.level().getCraftServer().getPluginManager().callEvent(event);
++
++ if (event.isCancelled()) {
++ return InteractionResult.PASS;
++ }
++
++ entitysheep.setColor(DyeColor.byId((byte) event.getColor().getWoolData()));
++ // CraftBukkit end
++ stack.shrink(1);
++ }
++
++ return InteractionResult.sidedSuccess(player.level().isClientSide);
++ }
+ }
+
+ return InteractionResult.PASS;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EggItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EggItem.java.patch
new file mode 100644
index 0000000000..07e2bf1538
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EggItem.java.patch
@@ -0,0 +1,42 @@
+--- a/net/minecraft/world/item/EggItem.java
++++ b/net/minecraft/world/item/EggItem.java
+@@ -15,23 +16,23 @@
+ }
+
+ @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
+- ItemStack itemInHand = player.getItemInHand(hand);
+- level.playSound(
+- null,
+- player.getX(),
+- player.getY(),
+- player.getZ(),
+- SoundEvents.EGG_THROW,
+- SoundSource.PLAYERS,
+- 0.5F,
+- 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
+- );
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++
++ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.EGG_THROW, SoundCategory.PLAYERS, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F)); // CraftBukkit - moved down
+ if (!level.isClientSide) {
+- ThrownEgg thrownEgg = new ThrownEgg(level, player);
+- thrownEgg.setItem(itemInHand);
+- thrownEgg.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
+- level.addFreshEntity(thrownEgg);
++ ThrownEgg entityegg = new ThrownEgg(level, player);
++
++ entityegg.setItem(itemstack);
++ entityegg.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
++ // CraftBukkit start
++ if (!level.addFreshEntity(entityegg)) {
++ if (player instanceof net.minecraft.server.level.ServerPlayer) {
++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().updateInventory();
++ }
++ return InteractionResultHolder.fail(itemstack);
++ }
++ // CraftBukkit end
+ }
+
+ player.awardStat(Stats.ITEM_USED.get(this));
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EndCrystalItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EndCrystalItem.java.patch
new file mode 100644
index 0000000000..d755b53015
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EndCrystalItem.java.patch
@@ -0,0 +1,33 @@
+--- a/net/minecraft/world/item/EndCrystalItem.java
++++ b/net/minecraft/world/item/EndCrystalItem.java
+@@ -38,15 +42,22 @@
+ if (!entities.isEmpty()) {
+ return InteractionResult.FAIL;
+ } else {
+- if (level instanceof ServerLevel) {
+- EndCrystal endCrystal = new EndCrystal(level, d + 0.5, d1, d2 + 0.5);
+- endCrystal.setShowBottom(false);
+- level.addFreshEntity(endCrystal);
+- level.gameEvent(context.getPlayer(), GameEvent.ENTITY_PLACE, blockPos);
+- EndDragonFight dragonFight = ((ServerLevel)level).getDragonFight();
+- if (dragonFight != null) {
+- dragonFight.tryRespawn();
++ if (world instanceof ServerLevel) {
++ EndCrystal entityendercrystal = new EndCrystal(world, d0 + 0.5D, d1, d2 + 0.5D);
++
++ entityendercrystal.setShowBottom(false);
++ // CraftBukkit start
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityendercrystal).isCancelled()) {
++ return InteractionResult.FAIL;
+ }
++ // CraftBukkit end
++ world.addFreshEntity(entityendercrystal);
++ world.gameEvent((Entity) context.getPlayer(), GameEvent.ENTITY_PLACE, blockposition1);
++ EndDragonFight enderdragonbattle = ((ServerLevel) world).getDragonFight();
++
++ if (enderdragonbattle != null) {
++ enderdragonbattle.tryRespawn();
++ }
+ }
+
+ context.getItemInHand().shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderEyeItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderEyeItem.java.patch
new file mode 100644
index 0000000000..3d409494f3
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderEyeItem.java.patch
@@ -0,0 +1,32 @@
+--- a/net/minecraft/world/item/EnderEyeItem.java
++++ b/net/minecraft/world/item/EnderEyeItem.java
+@@ -71,14 +79,21 @@
+ return InteractionResultHolder.pass(itemInHand);
+ } else {
+ player.startUsingItem(hand);
+- if (level instanceof ServerLevel serverLevel) {
+- BlockPos blockPos = serverLevel.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, player.blockPosition(), 100, false);
+- if (blockPos != null) {
+- EyeOfEnder eyeOfEnder = new EyeOfEnder(level, player.getX(), player.getY(0.5), player.getZ());
+- eyeOfEnder.setItem(itemInHand);
+- eyeOfEnder.signalTo(blockPos);
+- level.gameEvent(GameEvent.PROJECTILE_SHOOT, eyeOfEnder.position(), GameEvent.Context.of(player));
+- level.addFreshEntity(eyeOfEnder);
++ if (level instanceof ServerLevel) {
++ ServerLevel worldserver = (ServerLevel) level;
++ BlockPos blockposition = worldserver.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, player.blockPosition(), 100, false);
++
++ if (blockposition != null) {
++ EyeOfEnder entityendersignal = new EyeOfEnder(level, player.getX(), player.getY(0.5D), player.getZ());
++
++ entityendersignal.setItem(itemstack);
++ entityendersignal.signalTo(blockposition);
++ level.gameEvent(GameEvent.PROJECTILE_SHOOT, entityendersignal.position(), GameEvent.Context.of((Entity) player));
++ // CraftBukkit start
++ if (!level.addFreshEntity(entityendersignal)) {
++ return new InteractionResultHolder(InteractionResult.FAIL, itemstack);
++ }
++ // CraftBukkit end
+ if (player instanceof ServerPlayer) {
+ CriteriaTriggers.USED_ENDER_EYE.trigger((ServerPlayer)player, blockPos);
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderpearlItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderpearlItem.java.patch
new file mode 100644
index 0000000000..4851eaadc8
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/EnderpearlItem.java.patch
@@ -0,0 +1,37 @@
+--- a/net/minecraft/world/item/EnderpearlItem.java
++++ b/net/minecraft/world/item/EnderpearlItem.java
+@@ -15,19 +16,10 @@
+ }
+
+ @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
+- ItemStack itemInHand = player.getItemInHand(hand);
+- level.playSound(
+- null,
+- player.getX(),
+- player.getY(),
+- player.getZ(),
+- SoundEvents.ENDER_PEARL_THROW,
+- SoundSource.NEUTRAL,
+- 0.5F,
+- 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
+- );
+- player.getCooldowns().addCooldown(this, 20);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++
++ // CraftBukkit start - change order
+ if (!level.isClientSide) {
+ ThrownEnderpearl thrownEnderpearl = new ThrownEnderpearl(level, player);
+ thrownEnderpearl.setItem(itemInHand);
+@@ -35,6 +33,10 @@
+ level.addFreshEntity(thrownEnderpearl);
+ }
+
++ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENDER_PEARL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
++ player.getCooldowns().addCooldown(this, 20);
++ // CraftBukkit end
++
+ player.awardStat(Stats.ITEM_USED.get(this));
+ if (!player.getAbilities().instabuild) {
+ itemInHand.shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FireChargeItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FireChargeItem.java.patch
new file mode 100644
index 0000000000..3db64e44df
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FireChargeItem.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/FireChargeItem.java
++++ b/net/minecraft/world/item/FireChargeItem.java
+@@ -26,18 +29,35 @@
+ BlockPos clickedPos = context.getClickedPos();
+ BlockState blockState = level.getBlockState(clickedPos);
+ boolean flag = false;
+- if (!CampfireBlock.canLight(blockState) && !CandleBlock.canLight(blockState) && !CandleCakeBlock.canLight(blockState)) {
+- BlockPos var6 = clickedPos.relative(context.getClickedFace());
+- if (BaseFireBlock.canBePlacedAt(level, var6, context.getHorizontalDirection())) {
+- this.playSound(level, var6);
+- level.setBlockAndUpdate(var6, BaseFireBlock.getState(level, var6));
+- level.gameEvent(context.getPlayer(), GameEvent.BLOCK_PLACE, var6);
++
++ if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
++ blockposition = blockposition.relative(context.getClickedFace());
++ if (BaseFireBlock.canBePlacedAt(world, blockposition, context.getHorizontalDirection())) {
++ // CraftBukkit start - fire BlockIgniteEvent
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
++ if (!context.getPlayer().getAbilities().instabuild) {
++ context.getItemInHand().shrink(1);
++ }
++ return InteractionResult.PASS;
++ }
++ // CraftBukkit end
++ this.playSound(world, blockposition);
++ world.setBlockAndUpdate(blockposition, BaseFireBlock.getState(world, blockposition));
++ world.gameEvent((Entity) context.getPlayer(), GameEvent.BLOCK_PLACE, blockposition);
+ flag = true;
+ }
+ } else {
+- this.playSound(level, clickedPos);
+- level.setBlockAndUpdate(clickedPos, blockState.setValue(BlockStateProperties.LIT, Boolean.valueOf(true)));
+- level.gameEvent(context.getPlayer(), GameEvent.BLOCK_CHANGE, clickedPos);
++ // CraftBukkit start - fire BlockIgniteEvent
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FIREBALL, context.getPlayer()).isCancelled()) {
++ if (!context.getPlayer().getAbilities().instabuild) {
++ context.getItemInHand().shrink(1);
++ }
++ return InteractionResult.PASS;
++ }
++ // CraftBukkit end
++ this.playSound(world, blockposition);
++ world.setBlockAndUpdate(blockposition, (IBlockData) iblockdata.setValue(BlockStateProperties.LIT, true));
++ world.gameEvent((Entity) context.getPlayer(), GameEvent.BLOCK_CHANGE, blockposition);
+ flag = true;
+ }
+
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FishingRodItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FishingRodItem.java.patch
new file mode 100644
index 0000000000..cc2d211ac0
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FishingRodItem.java.patch
@@ -0,0 +1,42 @@
+--- a/net/minecraft/world/item/FishingRodItem.java
++++ b/net/minecraft/world/item/FishingRodItem.java
+@@ -11,7 +11,13 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+-public class FishingRodItem extends Item implements Vanishable {
++// CraftBukkit start
++import org.bukkit.event.player.PlayerFishEvent;
++import org.bukkit.craftbukkit.CraftEquipmentSlot;
++// CraftBukkit end
++
++public class FishingRodItem extends Item implements ItemVanishable {
++
+ public FishingRodItem(Item.Properties properties) {
+ super(properties);
+ }
+@@ -48,9 +40,21 @@
+ 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
+ );
+ if (!level.isClientSide) {
+- int i = EnchantmentHelper.getFishingSpeedBonus(itemInHand);
+- int fishingLuckBonus = EnchantmentHelper.getFishingLuckBonus(itemInHand);
+- level.addFreshEntity(new FishingHook(player, level, fishingLuckBonus, i));
++ i = EnchantmentHelper.getFishingSpeedBonus(itemstack);
++ int j = EnchantmentHelper.getFishingLuckBonus(itemstack);
++
++ // CraftBukkit start
++ FishingHook entityfishinghook = new FishingHook(player, level, j, i);
++ PlayerFishEvent playerFishEvent = new PlayerFishEvent((org.bukkit.entity.Player) player.getBukkitEntity(), null, (org.bukkit.entity.FishHook) entityfishinghook.getBukkitEntity(), CraftEquipmentSlot.getHand(hand), PlayerFishEvent.State.FISHING);
++ level.getCraftServer().getPluginManager().callEvent(playerFishEvent);
++
++ if (playerFishEvent.isCancelled()) {
++ player.fishing = null;
++ return InteractionResultHolder.pass(itemstack);
++ }
++ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.FISHING_BOBBER_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
++ level.addFreshEntity(entityfishinghook);
++ // CraftBukkit end
+ }
+
+ player.awardStat(Stats.ITEM_USED.get(this));
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FlintAndSteelItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FlintAndSteelItem.java.patch
new file mode 100644
index 0000000000..33db34830e
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/FlintAndSteelItem.java.patch
@@ -0,0 +1,70 @@
+--- a/net/minecraft/world/item/FlintAndSteelItem.java
++++ b/net/minecraft/world/item/FlintAndSteelItem.java
+@@ -24,34 +26,47 @@
+
+ @Override
+ public InteractionResult useOn(UseOnContext context) {
+- Player player = context.getPlayer();
+- Level level = context.getLevel();
+- BlockPos clickedPos = context.getClickedPos();
+- BlockState blockState = level.getBlockState(clickedPos);
+- if (!CampfireBlock.canLight(blockState) && !CandleBlock.canLight(blockState) && !CandleCakeBlock.canLight(blockState)) {
+- BlockPos blockPos = clickedPos.relative(context.getClickedFace());
+- if (BaseFireBlock.canBePlacedAt(level, blockPos, context.getHorizontalDirection())) {
+- level.playSound(player, blockPos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F);
+- BlockState state = BaseFireBlock.getState(level, blockPos);
+- level.setBlock(blockPos, state, 11);
+- level.gameEvent(player, GameEvent.BLOCK_PLACE, clickedPos);
+- ItemStack itemInHand = context.getItemInHand();
+- if (player instanceof ServerPlayer) {
+- CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)player, blockPos, itemInHand);
+- itemInHand.hurtAndBreak(1, player, contextPlayer -> contextPlayer.broadcastBreakEvent(context.getHand()));
++ Player entityhuman = context.getPlayer();
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
++
++ if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
++ BlockPos blockposition1 = blockposition.relative(context.getClickedFace());
++
++ if (BaseFireBlock.canBePlacedAt(world, blockposition1, context.getHorizontalDirection())) {
++ // CraftBukkit start - Store the clicked block
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition1, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, entityhuman).isCancelled()) {
++ context.getItemInHand().hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(context.getHand());
++ });
++ return InteractionResult.PASS;
+ }
++ // CraftBukkit end
++ world.playSound(entityhuman, blockposition1, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.4F + 0.8F);
++ IBlockData iblockdata1 = BaseFireBlock.getState(world, blockposition1);
+
+ return InteractionResult.sidedSuccess(level.isClientSide());
+ } else {
+ return InteractionResult.FAIL;
+ }
+ } else {
+- level.playSound(player, clickedPos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F);
+- level.setBlock(clickedPos, blockState.setValue(BlockStateProperties.LIT, Boolean.valueOf(true)), 11);
+- level.gameEvent(player, GameEvent.BLOCK_CHANGE, clickedPos);
+- if (player != null) {
+- context.getItemInHand().hurtAndBreak(1, player, contextPlayer -> contextPlayer.broadcastBreakEvent(context.getHand()));
++ // CraftBukkit start - Store the clicked block
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(world, blockposition, org.bukkit.event.block.BlockIgniteEvent.IgniteCause.FLINT_AND_STEEL, entityhuman).isCancelled()) {
++ context.getItemInHand().hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(context.getHand());
++ });
++ return InteractionResult.PASS;
+ }
++ // CraftBukkit end
++ world.playSound(entityhuman, blockposition, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, world.getRandom().nextFloat() * 0.4F + 0.8F);
++ world.setBlock(blockposition, (IBlockData) iblockdata.setValue(BlockStateProperties.LIT, true), 11);
++ world.gameEvent((Entity) entityhuman, GameEvent.BLOCK_CHANGE, blockposition);
++ if (entityhuman != null) {
++ context.getItemInHand().hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(context.getHand());
++ });
++ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide());
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/HangingEntityItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/HangingEntityItem.java.patch
new file mode 100644
index 0000000000..af58c26e59
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/HangingEntityItem.java.patch
@@ -0,0 +1,44 @@
+--- a/net/minecraft/world/item/HangingEntityItem.java
++++ b/net/minecraft/world/item/HangingEntityItem.java
+@@ -22,6 +21,11 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
++// CraftBukkit start
++import org.bukkit.entity.Player;
++import org.bukkit.event.hanging.HangingPlaceEvent;
++// CraftBukkit end
++
+ public class HangingEntityItem extends Item {
+ private static final Component TOOLTIP_RANDOM_VARIANT = Component.translatable("painting.random").withStyle(ChatFormatting.GRAY);
+ private final EntityType<? extends HangingEntity> type;
+@@ -65,11 +74,24 @@
+ EntityType.updateCustomEntityTag(level, player, hangingEntity, tag);
+ }
+
+- if (hangingEntity.survives()) {
+- if (!level.isClientSide) {
+- hangingEntity.playPlacementSound();
+- level.gameEvent(player, GameEvent.ENTITY_PLACE, hangingEntity.position());
+- level.addFreshEntity(hangingEntity);
++ if (((HangingEntity) object).survives()) {
++ if (!world.isClientSide) {
++ // CraftBukkit start - fire HangingPlaceEvent
++ Player who = (context.getPlayer() == null) ? null : (Player) context.getPlayer().getBukkitEntity();
++ org.bukkit.block.Block blockClicked = world.getWorld().getBlockAt(blockposition.getX(), blockposition.getY(), blockposition.getZ());
++ org.bukkit.block.BlockFace blockFace = org.bukkit.craftbukkit.block.CraftBlock.notchToBlockFace(enumdirection);
++ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(context.getHand());
++
++ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) ((HangingEntity) object).getBukkitEntity(), who, blockClicked, blockFace, hand, org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(itemstack));
++ world.getCraftServer().getPluginManager().callEvent(event);
++
++ if (event.isCancelled()) {
++ return InteractionResult.FAIL;
++ }
++ // CraftBukkit end
++ ((HangingEntity) object).playPlacementSound();
++ world.gameEvent((Entity) entityhuman, GameEvent.ENTITY_PLACE, ((HangingEntity) object).position());
++ world.addFreshEntity((Entity) object);
+ }
+
+ itemInHand.shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ItemStack.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ItemStack.java.patch
new file mode 100644
index 0000000000..e318ac0812
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/ItemStack.java.patch
@@ -0,0 +1,327 @@
+--- a/net/minecraft/world/item/ItemStack.java
++++ b/net/minecraft/world/item/ItemStack.java
+@@ -81,6 +82,41 @@
+ import net.minecraft.world.level.block.state.pattern.BlockInWorld;
+ import org.slf4j.Logger;
+
++// CraftBukkit start
++import com.mojang.serialization.Dynamic;
++import java.util.Map;
++import java.util.Objects;
++import net.minecraft.server.MinecraftServer;
++import net.minecraft.server.level.ServerLevel;
++import net.minecraft.server.level.ServerPlayer;
++import net.minecraft.sounds.SoundEvent;
++import net.minecraft.sounds.SoundSource;
++import net.minecraft.stats.Stats;
++import net.minecraft.util.datafix.fixes.DataConverterTypes;
++import net.minecraft.world.level.block.Blocks;
++import net.minecraft.world.level.block.SaplingBlock;
++import net.minecraft.world.level.block.SignBlock;
++import net.minecraft.world.level.block.SoundType;
++import net.minecraft.world.level.block.WitherSkullBlock;
++import net.minecraft.world.level.block.entity.BlockEntity;
++import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
++import net.minecraft.world.level.block.entity.SignBlockEntity;
++import net.minecraft.world.level.block.entity.SkullBlockEntity;
++import net.minecraft.world.level.gameevent.GameEvent;
++import org.bukkit.Location;
++import org.bukkit.TreeType;
++import org.bukkit.block.BlockState;
++import org.bukkit.craftbukkit.block.CraftBlock;
++import org.bukkit.craftbukkit.block.CraftBlockState;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.util.CraftLocation;
++import org.bukkit.craftbukkit.util.CraftMagicNumbers;
++import org.bukkit.entity.Player;
++import org.bukkit.event.block.BlockFertilizeEvent;
++import org.bukkit.event.player.PlayerItemDamageEvent;
++import org.bukkit.event.world.StructureGrowEvent;
++// CraftBukkit end
++
+ public final class ItemStack {
+ public static final Codec<ItemStack> CODEC = RecordCodecBuilder.create(
+ instance -> instance.group(
+@@ -181,11 +211,22 @@
+ this.item = null;
+ }
+
+- private ItemStack(CompoundTag compoundTag) {
+- this.item = BuiltInRegistries.ITEM.get(new ResourceLocation(compoundTag.getString("id")));
+- this.count = compoundTag.getByte("Count");
+- if (compoundTag.contains("tag", 10)) {
+- this.tag = compoundTag.getCompound("tag").copy();
++ // Called to run this stack through the data converter to handle older storage methods and serialized items
++ public void convertStack(int version) {
++ if (0 < version && version < CraftMagicNumbers.INSTANCE.getDataVersion()) {
++ CompoundTag savedStack = new CompoundTag();
++ this.save(savedStack);
++ savedStack = (CompoundTag) MinecraftServer.getServer().fixerUpper.update(DataConverterTypes.ITEM_STACK, new Dynamic(NbtOps.INSTANCE, savedStack), version, CraftMagicNumbers.INSTANCE.getDataVersion()).getValue();
++ this.load(savedStack);
++ }
++ }
++
++ // CraftBukkit - break into own method
++ private void load(CompoundTag nbttagcompound) {
++ this.item = (Item) BuiltInRegistries.ITEM.get(new ResourceLocation(nbttagcompound.getString("id")));
++ this.count = nbttagcompound.getByte("Count");
++ if (nbttagcompound.contains("tag", 10)) {
++ this.tag = nbttagcompound.getCompound("tag").copy();
+ this.getItem().verifyTagAfterLoad(this.tag);
+ }
+
+@@ -194,6 +236,11 @@
+ }
+ }
+
++ private ItemStack(CompoundTag compoundTag) {
++ this.load(compoundTag);
++ // CraftBukkit end
++ }
++
+ public static ItemStack of(CompoundTag compoundTag) {
+ try {
+ return new ItemStack(compoundTag);
+@@ -270,12 +318,169 @@
+ return InteractionResult.PASS;
+ } else {
+ Item item = this.getItem();
+- InteractionResult interactionResult = item.useOn(context);
+- if (player != null && interactionResult.shouldAwardStats()) {
+- player.awardStat(Stats.ITEM_USED.get(item));
++ // CraftBukkit start - handle all block place event logic here
++ CompoundTag oldData = this.getTagClone();
++ int oldCount = this.getCount();
++ ServerLevel world = (ServerLevel) context.getLevel();
++
++ if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket
++ world.captureBlockStates = true;
++ // special case bonemeal
++ if (item == Items.BONE_MEAL) {
++ world.captureTreeGeneration = true;
++ }
+ }
+
+- return interactionResult;
++ BlockFertilizeEvent fertilizeEvent = new BlockFertilizeEvent(CraftBlock.at(world, blockposition), (Player) entityhuman.getBukkitEntity(), (List< BlockState>) (List<? extends BlockState>) blocks);
++ fertilizeEvent.setCancelled(structureEvent != null && structureEvent.isCancelled());
++ org.bukkit.Bukkit.getPluginManager().callEvent(fertilizeEvent);
++
++ if (!fertilizeEvent.isCancelled()) {
++ // Change the stack to its new contents if it hasn't been tampered with.
++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) {
++ this.setTag(newData);
++ this.setCount(newCount);
++ }
++ for (CraftBlockState blockstate : blocks) {
++ world.setBlock(blockstate.getPosition(),blockstate.getHandle(), blockstate.getFlag()); // SPIGOT-7248 - manual update to avoid physics where appropriate
++ }
++ entityhuman.awardStat(Stats.ITEM_USED.get(item)); // SPIGOT-7236 - award stat
++ }
++
++ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return
++ return enuminteractionresult;
++ }
++ world.captureTreeGeneration = false;
++
++ if (entityhuman != null && enuminteractionresult.shouldAwardStats()) {
++ EnumHand enumhand = context.getHand();
++ org.bukkit.event.block.BlockPlaceEvent placeEvent = null;
++ List<BlockState> blocks = new java.util.ArrayList<>(world.capturedBlockStates.values());
++ world.capturedBlockStates.clear();
++ if (blocks.size() > 1) {
++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockMultiPlaceEvent(world, entityhuman, enumhand, blocks, blockposition.getX(), blockposition.getY(), blockposition.getZ());
++ } else if (blocks.size() == 1) {
++ placeEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callBlockPlaceEvent(world, entityhuman, enumhand, blocks.get(0), blockposition.getX(), blockposition.getY(), blockposition.getZ());
++ }
++
++ if (placeEvent != null && (placeEvent.isCancelled() || !placeEvent.canBuild())) {
++ enuminteractionresult = InteractionResult.FAIL; // cancel placement
++ // PAIL: Remove this when MC-99075 fixed
++ placeEvent.getPlayer().updateInventory();
++ // revert back all captured blocks
++ world.preventPoiUpdated = true; // CraftBukkit - SPIGOT-5710
++ for (BlockState blockstate : blocks) {
++ blockstate.update(true, false);
++ }
++ world.preventPoiUpdated = false;
++
++ // Brute force all possible updates
++ BlockPos placedPos = ((CraftBlock) placeEvent.getBlock()).getPosition();
++ for (Direction dir : Direction.values()) {
++ ((ServerPlayer) entityhuman).connection.send(new ClientboundBlockUpdatePacket(world, placedPos.relative(dir)));
++ }
++ SignItem.openSign = null; // SPIGOT-6758 - Reset on early return
++ } else {
++ // Change the stack to its new contents if it hasn't been tampered with.
++ if (this.getCount() == oldCount && Objects.equals(this.tag, oldData)) {
++ this.setTag(newData);
++ this.setCount(newCount);
++ }
++
++ for (Map.Entry<BlockPos, BlockEntity> e : world.capturedTileEntities.entrySet()) {
++ world.setBlockEntity(e.getValue());
++ }
++
++ for (BlockState blockstate : blocks) {
++ int updateFlag = ((CraftBlockState) blockstate).getFlag();
++ IBlockData oldBlock = ((CraftBlockState) blockstate).getHandle();
++ BlockPos newblockposition = ((CraftBlockState) blockstate).getPosition();
++ IBlockData block = world.getBlockState(newblockposition);
++
++ if (!(block.getBlock() instanceof BaseEntityBlock)) { // Containers get placed automatically
++ block.getBlock().onPlace(block, world, newblockposition, oldBlock, true);
++ }
++
++ world.notifyAndUpdatePhysics(newblockposition, null, oldBlock, block, world.getBlockState(newblockposition), updateFlag, 512); // send null chunk as chunk.k() returns false by this point
++ }
++
++ // Special case juke boxes as they update their tile entity. Copied from ItemRecord.
++ // PAIL: checkme on updates.
++ if (this.item instanceof RecordItem) {
++ BlockEntity tileentity = world.getBlockEntity(blockposition);
++
++ if (tileentity instanceof JukeboxBlockEntity) {
++ JukeboxBlockEntity tileentityjukebox = (JukeboxBlockEntity) tileentity;
++
++ // There can only be one
++ ItemStack record = this.copy();
++ if (!record.isEmpty()) {
++ record.setCount(1);
++ }
++
++ tileentityjukebox.setTheItem(record);
++ world.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entityhuman, world.getBlockState(blockposition)));
++ }
++
++ this.shrink(1);
++ entityhuman.awardStat(Stats.PLAY_RECORD);
++ }
++
++ if (this.item == Items.WITHER_SKELETON_SKULL) { // Special case skulls to allow wither spawns to be cancelled
++ BlockPos bp = blockposition;
++ if (!world.getBlockState(blockposition).canBeReplaced()) {
++ if (!world.getBlockState(blockposition).isSolid()) {
++ bp = null;
++ } else {
++ bp = bp.relative(context.getClickedFace());
++ }
++ }
++ if (bp != null) {
++ BlockEntity te = world.getBlockEntity(bp);
++ if (te instanceof SkullBlockEntity) {
++ WitherSkullBlock.checkSpawn(world, bp, (SkullBlockEntity) te);
++ }
++ }
++ }
++
++ // SPIGOT-4678
++ if (this.item instanceof SignItem && SignItem.openSign != null) {
++ try {
++ if (world.getBlockEntity(SignItem.openSign) instanceof SignBlockEntity tileentitysign) {
++ if (world.getBlockState(SignItem.openSign).getBlock() instanceof SignBlock blocksign) {
++ blocksign.openTextEdit(entityhuman, tileentitysign, true, org.bukkit.event.player.PlayerSignOpenEvent.Cause.PLACE); // Craftbukkit
++ }
++ }
++ } finally {
++ SignItem.openSign = null;
++ }
++ }
++
++ // SPIGOT-7315: Moved from BlockBed#setPlacedBy
++ if (placeEvent != null && this.item instanceof BedItem) {
++ BlockPos position = ((CraftBlock) placeEvent.getBlock()).getPosition();
++ IBlockData blockData = world.getBlockState(position);
++
++ if (blockData.getBlock() instanceof BedBlock) {
++ world.blockUpdated(position, Blocks.AIR);
++ blockData.updateNeighbourShapes(world, position, 3);
++ }
++ }
++
++ // SPIGOT-1288 - play sound stripped from ItemBlock
++ if (this.item instanceof BlockItem) {
++ SoundType soundeffecttype = ((BlockItem) this.item).getBlock().defaultBlockState().getSoundType(); // TODO: not strictly correct, however currently only affects decorated pots
++ world.playSound(entityhuman, blockposition, soundeffecttype.getPlaceSound(), SoundSource.BLOCKS, (soundeffecttype.getVolume() + 1.0F) / 2.0F, soundeffecttype.getPitch() * 0.8F);
++ }
++
++ entityhuman.awardStat(Stats.ITEM_USED.get(item));
++ }
++ }
++ world.capturedTileEntities.clear();
++ world.capturedBlockStates.clear();
++ // CraftBukkit end
++
++ return enuminteractionresult;
+ }
+ }
+
+@@ -349,7 +581,22 @@
+ }
+ }
+
+- amount -= i;
++ amount -= k;
++ // CraftBukkit start
++ if (user != null) {
++ PlayerItemDamageEvent event = new PlayerItemDamageEvent(user.getBukkitEntity(), CraftItemStack.asCraftMirror(this), amount);
++ event.getPlayer().getServer().getPluginManager().callEvent(event);
++
++ if (amount != event.getDamage() || event.isCancelled()) {
++ event.getPlayer().updateInventory();
++ }
++ if (event.isCancelled()) {
++ return false;
++ }
++
++ amount = event.getDamage();
++ }
++ // CraftBukkit end
+ if (amount <= 0) {
+ return false;
+ }
+@@ -371,6 +618,12 @@
+ if (this.hurt(amount, entity.getRandom(), entity instanceof ServerPlayer ? (ServerPlayer)entity : null)) {
+ onBroken.accept(entity);
+ Item item = this.getItem();
++ // CraftBukkit start - Check for item breaking
++ if (this.count == 1 && entity instanceof net.minecraft.world.entity.player.Player) {
++ org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerItemBreakEvent((net.minecraft.world.entity.player.Player) entity, this);
++ }
++ // CraftBukkit end
++
+ this.shrink(1);
+ if (entity instanceof Player) {
+ ((Player)entity).awardStat(Stats.ITEM_BROKEN.get(item));
+@@ -513,6 +775,17 @@
+ return this.tag;
+ }
+
++ // CraftBukkit start
++ @Nullable
++ private CompoundTag getTagClone() {
++ return this.tag == null ? null : this.tag.copy();
++ }
++
++ private void setTagClone(@Nullable CompoundTag nbtttagcompound) {
++ this.setTag(nbtttagcompound == null ? null : nbtttagcompound.copy());
++ }
++ // CraftBukkit end
++
+ public CompoundTag getOrCreateTag() {
+ if (this.tag == null) {
+ this.setTag(new CompoundTag());
+@@ -925,6 +1210,13 @@
+ list.add(compoundTag);
+ }
+
++ // CraftBukkit start
++ @Deprecated
++ public void setItem(Item item) {
++ this.item = item;
++ }
++ // CraftBukkit end
++
+ public Component getDisplayName() {
+ MutableComponent mutableComponent = Component.empty().append(this.getHoverName());
+ if (this.hasCustomHoverName()) {
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/LeadItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/LeadItem.java.patch
new file mode 100644
index 0000000000..db1ad8e4ff
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/LeadItem.java.patch
@@ -0,0 +1,99 @@
+--- a/net/minecraft/world/item/LeadItem.java
++++ b/net/minecraft/world/item/LeadItem.java
+@@ -11,6 +14,10 @@
+ import net.minecraft.world.level.block.state.BlockState;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.AABB;
++// CraftBukkit start
++import org.bukkit.craftbukkit.CraftEquipmentSlot;
++import org.bukkit.event.hanging.HangingPlaceEvent;
++// CraftBukkit end
+
+ public class LeadItem extends Item {
+ public LeadItem(Item.Properties properties) {
+@@ -19,13 +27,15 @@
+
+ @Override
+ public InteractionResult useOn(UseOnContext context) {
+- Level level = context.getLevel();
+- BlockPos clickedPos = context.getClickedPos();
+- BlockState blockState = level.getBlockState(clickedPos);
+- if (blockState.is(BlockTags.FENCES)) {
+- Player player = context.getPlayer();
+- if (!level.isClientSide && player != null) {
+- bindPlayerMobs(player, level, clickedPos);
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
++
++ if (iblockdata.is(BlockTags.FENCES)) {
++ Player entityhuman = context.getPlayer();
++
++ if (!world.isClientSide && entityhuman != null) {
++ bindPlayerMobs(entityhuman, world, blockposition, context.getHand()); // CraftBukkit - Pass hand
+ }
+
+ return InteractionResult.sidedSuccess(level.isClientSide);
+@@ -34,24 +44,41 @@
+ }
+ }
+
+- public static InteractionResult bindPlayerMobs(Player player, Level level, BlockPos pos) {
+- LeashFenceKnotEntity leashFenceKnotEntity = null;
++ public static InteractionResult bindPlayerMobs(Player entityhuman, Level world, BlockPos blockposition, net.minecraft.world.EnumHand enumhand) { // CraftBukkit - Add EnumHand
++ LeashFenceKnotEntity entityleash = null;
+ boolean flag = false;
+ double d = 7.0;
+ int x = pos.getX();
+ int y = pos.getY();
+ int z = pos.getZ();
+
+- for (Mob mob : level.getEntitiesOfClass(
+- Mob.class, new AABB((double)x - 7.0, (double)y - 7.0, (double)z - 7.0, (double)x + 7.0, (double)y + 7.0, (double)z + 7.0)
+- )) {
+- if (mob.getLeashHolder() == player) {
+- if (leashFenceKnotEntity == null) {
+- leashFenceKnotEntity = LeashFenceKnotEntity.getOrCreateKnot(level, pos);
+- leashFenceKnotEntity.playPlacementSound();
++ while (iterator.hasNext()) {
++ Mob entityinsentient = (Mob) iterator.next();
++
++ if (entityinsentient.getLeashHolder() == entityhuman) {
++ if (entityleash == null) {
++ entityleash = LeashFenceKnotEntity.getOrCreateKnot(world, blockposition);
++
++ // CraftBukkit start - fire HangingPlaceEvent
++ org.bukkit.inventory.EquipmentSlot hand = CraftEquipmentSlot.getHand(enumhand);
++ HangingPlaceEvent event = new HangingPlaceEvent((org.bukkit.entity.Hanging) entityleash.getBukkitEntity(), entityhuman != null ? (org.bukkit.entity.Player) entityhuman.getBukkitEntity() : null, world.getWorld().getBlockAt(i, j, k), org.bukkit.block.BlockFace.SELF, hand);
++ world.getCraftServer().getPluginManager().callEvent(event);
++
++ if (event.isCancelled()) {
++ entityleash.discard();
++ return InteractionResult.PASS;
++ }
++ // CraftBukkit end
++ entityleash.playPlacementSound();
+ }
+
+- mob.setLeashedTo(leashFenceKnotEntity, true);
++ // CraftBukkit start
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callPlayerLeashEntityEvent(entityinsentient, entityleash, entityhuman, enumhand).isCancelled()) {
++ continue;
++ }
++ // CraftBukkit end
++
++ entityinsentient.setLeashedTo(entityleash, true);
+ flag = true;
+ }
+ }
+@@ -62,4 +91,10 @@
+
+ return flag ? InteractionResult.SUCCESS : InteractionResult.PASS;
+ }
++
++ // CraftBukkit start
++ public static InteractionResult bindPlayerMobs(Player player, Level level, BlockPos pos) {
++ return bindPlayerMobs(player, level, pos, net.minecraft.world.EnumHand.MAIN_HAND);
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MapItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MapItem.java.patch
new file mode 100644
index 0000000000..06b6d7d15a
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MapItem.java.patch
@@ -0,0 +1,14 @@
+--- a/net/minecraft/world/item/MapItem.java
++++ b/net/minecraft/world/item/MapItem.java
+@@ -64,8 +67,9 @@
+
+ @Nullable
+ public static Integer getMapId(ItemStack stack) {
+- CompoundTag tag = stack.getTag();
+- return tag != null && tag.contains("map", 99) ? tag.getInt("map") : null;
++ CompoundTag nbttagcompound = stack.getTag();
++
++ return nbttagcompound != null && nbttagcompound.contains("map", 99) ? nbttagcompound.getInt("map") : -1; // CraftBukkit - make new maps for no tag
+ }
+
+ private static int createNewSavedData(
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MilkBucketItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MilkBucketItem.java.patch
new file mode 100644
index 0000000000..45e78e72b9
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MilkBucketItem.java.patch
@@ -0,0 +1,11 @@
+--- a/net/minecraft/world/item/MilkBucketItem.java
++++ b/net/minecraft/world/item/MilkBucketItem.java
+@@ -28,7 +31,7 @@
+ }
+
+ if (!level.isClientSide) {
+- entityLiving.removeAllEffects();
++ entityLiving.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit
+ }
+
+ return stack.isEmpty() ? new ItemStack(Items.BUCKET) : stack;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MinecartItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MinecartItem.java.patch
new file mode 100644
index 0000000000..5c82298462
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/MinecartItem.java.patch
@@ -0,0 +1,90 @@
+--- a/net/minecraft/world/item/MinecartItem.java
++++ b/net/minecraft/world/item/MinecartItem.java
+@@ -17,6 +18,11 @@
+ import net.minecraft.world.level.block.state.properties.RailShape;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.Vec3;
++// CraftBukkit start
++import org.bukkit.craftbukkit.block.CraftBlock;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.event.block.BlockDispenseEvent;
++// CraftBukkit end
+
+ public class MinecartItem extends Item {
+ private static final DispenseItemBehavior DISPENSE_ITEM_BEHAVIOR = new DefaultDispenseItemBehavior() {
+@@ -58,12 +63,40 @@
+ }
+ }
+
+- AbstractMinecart abstractMinecart = AbstractMinecart.createMinecart(
+- serverLevel, d, d1 + d3, d2, ((MinecartItem)itemStack.getItem()).type, itemStack, null
+- );
+- serverLevel.addFreshEntity(abstractMinecart);
+- itemStack.shrink(1);
+- return itemStack;
++ // CraftBukkit start
++ // EntityMinecartAbstract entityminecartabstract = EntityMinecartAbstract.createMinecart(worldserver, d0, d1 + d3, d2, ((ItemMinecart) itemstack.getItem()).type);
++ ItemStack itemstack1 = itemstack.split(1);
++ org.bukkit.block.Block block2 = CraftBlock.at(worldserver, sourceblock.pos());
++ CraftItemStack craftItem = CraftItemStack.asCraftMirror(itemstack1);
++
++ BlockDispenseEvent event = new BlockDispenseEvent(block2, craftItem.clone(), new org.bukkit.util.Vector(d0, d1 + d3, d2));
++ if (!DispenserBlock.eventFired) {
++ worldserver.getCraftServer().getPluginManager().callEvent(event);
++ }
++
++ if (event.isCancelled()) {
++ itemstack.grow(1);
++ return itemstack;
++ }
++
++ if (!event.getItem().equals(craftItem)) {
++ itemstack.grow(1);
++ // Chain to handler for new item
++ ItemStack eventStack = CraftItemStack.asNMSCopy(event.getItem());
++ DispenseItemBehavior idispensebehavior = (DispenseItemBehavior) DispenserBlock.DISPENSER_REGISTRY.get(eventStack.getItem());
++ if (idispensebehavior != DispenseItemBehavior.NOOP && idispensebehavior != this) {
++ idispensebehavior.dispense(sourceblock, eventStack);
++ return itemstack;
++ }
++ }
++
++ itemstack1 = CraftItemStack.asNMSCopy(event.getItem());
++ AbstractMinecart entityminecartabstract = AbstractMinecart.createMinecart(worldserver, event.getVelocity().getX(), event.getVelocity().getY(), event.getVelocity().getZ(), ((MinecartItem) itemstack1.getItem()).type, itemstack1, (Player) null);
++
++ if (!worldserver.addFreshEntity(entityminecartabstract)) itemstack.grow(1);
++ // itemstack.shrink(1); // CraftBukkit - handled during event processing
++ // CraftBukkit end
++ return itemstack;
+ }
+
+ @Override
+@@ -97,19 +132,15 @@
+ d = 0.5;
+ }
+
+- AbstractMinecart abstractMinecart = AbstractMinecart.createMinecart(
+- serverLevel,
+- (double)clickedPos.getX() + 0.5,
+- (double)clickedPos.getY() + 0.0625 + d,
+- (double)clickedPos.getZ() + 0.5,
+- this.type,
+- itemInHand,
+- context.getPlayer()
+- );
+- serverLevel.addFreshEntity(abstractMinecart);
+- serverLevel.gameEvent(
+- GameEvent.ENTITY_PLACE, clickedPos, GameEvent.Context.of(context.getPlayer(), serverLevel.getBlockState(clickedPos.below()))
+- );
++ AbstractMinecart entityminecartabstract = AbstractMinecart.createMinecart(worldserver, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.0625D + d0, (double) blockposition.getZ() + 0.5D, this.type, itemstack, context.getPlayer());
++
++ // CraftBukkit start
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPlaceEvent(context, entityminecartabstract).isCancelled()) {
++ return InteractionResult.FAIL;
++ }
++ // CraftBukkit end
++ if (!worldserver.addFreshEntity(entityminecartabstract)) return InteractionResult.PASS; // CraftBukkit
++ worldserver.gameEvent(GameEvent.ENTITY_PLACE, blockposition, GameEvent.Context.of(context.getPlayer(), worldserver.getBlockState(blockposition.below())));
+ }
+
+ itemInHand.shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/PotionItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/PotionItem.java.patch
new file mode 100644
index 0000000000..fce2791a33
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/PotionItem.java.patch
@@ -0,0 +1,11 @@
+--- a/net/minecraft/world/item/PotionItem.java
++++ b/net/minecraft/world/item/PotionItem.java
+@@ -51,7 +60,7 @@
+ if (mobEffectInstance.getEffect().isInstantenous()) {
+ mobEffectInstance.getEffect().applyInstantenousEffect(player, player, entityLiving, mobEffectInstance.getAmplifier(), 1.0);
+ } else {
+- entityLiving.addEffect(new MobEffectInstance(mobEffectInstance));
++ entityLiving.addEffect(new MobEffectInstance(mobeffect), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_DRINK); // CraftBukkit
+ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/RecordItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/RecordItem.java.patch
new file mode 100644
index 0000000000..d1ff6cdcae
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/RecordItem.java.patch
@@ -0,0 +1,36 @@
+--- a/net/minecraft/world/item/RecordItem.java
++++ b/net/minecraft/world/item/RecordItem.java
+@@ -36,16 +38,23 @@
+
+ @Override
+ public InteractionResult useOn(UseOnContext context) {
+- Level level = context.getLevel();
+- BlockPos clickedPos = context.getClickedPos();
+- BlockState blockState = level.getBlockState(clickedPos);
+- if (blockState.is(Blocks.JUKEBOX) && !blockState.getValue(JukeboxBlock.HAS_RECORD)) {
+- ItemStack itemInHand = context.getItemInHand();
+- if (!level.isClientSide) {
+- Player player = context.getPlayer();
+- if (level.getBlockEntity(clickedPos) instanceof JukeboxBlockEntity jukeboxBlockEntity) {
+- jukeboxBlockEntity.setTheItem(itemInHand.copy());
+- level.gameEvent(GameEvent.BLOCK_CHANGE, clickedPos, GameEvent.Context.of(player, blockState));
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
++
++ if (iblockdata.is(Blocks.JUKEBOX) && !(Boolean) iblockdata.getValue(JukeboxBlock.HAS_RECORD)) {
++ ItemStack itemstack = context.getItemInHand();
++
++ if (!world.isClientSide) {
++ if (true) return InteractionResult.SUCCESS; // CraftBukkit - handled in ItemStack
++ Player entityhuman = context.getPlayer();
++ BlockEntity tileentity = world.getBlockEntity(blockposition);
++
++ if (tileentity instanceof JukeboxBlockEntity) {
++ JukeboxBlockEntity tileentityjukebox = (JukeboxBlockEntity) tileentity;
++
++ tileentityjukebox.setTheItem(itemstack.copy());
++ world.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entityhuman, iblockdata));
+ }
+
+ itemInHand.shrink(1);
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SignItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SignItem.java.patch
new file mode 100644
index 0000000000..686ee12c1c
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SignItem.java.patch
@@ -0,0 +1,42 @@
+--- a/net/minecraft/world/item/SignItem.java
++++ b/net/minecraft/world/item/SignItem.java
+@@ -11,6 +12,9 @@
+ import net.minecraft.world.level.block.state.BlockState;
+
+ public class SignItem extends StandingAndWallBlockItem {
++
++ public static BlockPos openSign; // CraftBukkit
++
+ public SignItem(Item.Properties properties, Block standingBlock, Block wallBlock) {
+ super(standingBlock, wallBlock, properties, Direction.DOWN);
+ }
+@@ -22,12 +26,23 @@
+ @Override
+ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, BlockState state) {
+ boolean flag = super.updateCustomBlockEntityTag(pos, level, player, stack, state);
+- if (!level.isClientSide
+- && !flag
+- && player != null
+- && level.getBlockEntity(pos) instanceof SignBlockEntity signBlockEntity
+- && level.getBlockState(pos).getBlock() instanceof SignBlock signBlock) {
+- signBlock.openTextEdit(player, signBlockEntity, true);
++
++ if (!level.isClientSide && !flag && player != null) {
++ BlockEntity tileentity = level.getBlockEntity(pos);
++
++ if (tileentity instanceof SignBlockEntity) {
++ SignBlockEntity tileentitysign = (SignBlockEntity) tileentity;
++ Block block = level.getBlockState(pos).getBlock();
++
++ if (block instanceof SignBlock) {
++ SignBlock blocksign = (SignBlock) block;
++
++ // CraftBukkit start - SPIGOT-4678
++ // blocksign.openTextEdit(entityhuman, tileentitysign, true);
++ SignItem.openSign = pos;
++ // CraftBukkit end
++ }
++ }
+ }
+
+ return flag;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SnowballItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SnowballItem.java.patch
new file mode 100644
index 0000000000..84d40286bb
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SnowballItem.java.patch
@@ -0,0 +1,41 @@
+--- a/net/minecraft/world/item/SnowballItem.java
++++ b/net/minecraft/world/item/SnowballItem.java
+@@ -15,28 +16,24 @@
+ }
+
+ @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand hand) {
+- ItemStack itemInHand = player.getItemInHand(hand);
+- level.playSound(
+- null,
+- player.getX(),
+- player.getY(),
+- player.getZ(),
+- SoundEvents.SNOWBALL_THROW,
+- SoundSource.NEUTRAL,
+- 0.5F,
+- 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F)
+- );
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++
++ // CraftBukkit - moved down
++ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.SNOWBALL_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
+ if (!level.isClientSide) {
+ Snowball snowball = new Snowball(level, player);
+ snowball.setItem(itemInHand);
+ snowball.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
+ level.addFreshEntity(snowball);
+ }
++ // CraftBukkit end
+
+ player.awardStat(Stats.ITEM_USED.get(this));
+- if (!player.getAbilities().instabuild) {
+- itemInHand.shrink(1);
++ // CraftBukkit start - moved up
++ /*
++ if (!entityhuman.getAbilities().instabuild) {
++ itemstack.shrink(1);
+ }
+
+ return InteractionResultHolder.sidedSuccess(itemInHand, level.isClientSide());
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SpawnEggItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SpawnEggItem.java.patch
new file mode 100644
index 0000000000..dad4efbbc6
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/SpawnEggItem.java.patch
@@ -0,0 +1,13 @@
+--- a/net/minecraft/world/item/SpawnEggItem.java
++++ b/net/minecraft/world/item/SpawnEggItem.java
+@@ -176,8 +179,8 @@
+ if (!breedOffspring.isBaby()) {
+ return Optional.empty();
+ } else {
+- breedOffspring.moveTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F);
+- serverLevel.addFreshEntityWithPassengers(breedOffspring);
++ ((Mob) object).moveTo(pos.x(), pos.y(), pos.z(), 0.0F, 0.0F);
++ serverLevel.addFreshEntityWithPassengers((Entity) object, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER_EGG); // CraftBukkit
+ if (stack.hasCustomHoverName()) {
+ breedOffspring.setCustomName(stack.getHoverName());
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/StandingAndWallBlockItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/StandingAndWallBlockItem.java.patch
new file mode 100644
index 0000000000..5c47dd78db
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/StandingAndWallBlockItem.java.patch
@@ -0,0 +1,34 @@
+--- a/net/minecraft/world/item/StandingAndWallBlockItem.java
++++ b/net/minecraft/world/item/StandingAndWallBlockItem.java
+@@ -9,6 +11,10 @@
+ import net.minecraft.world.level.block.Block;
+ import net.minecraft.world.level.block.state.BlockState;
+ import net.minecraft.world.phys.shapes.CollisionContext;
++import org.bukkit.craftbukkit.block.CraftBlock;
++import org.bukkit.craftbukkit.block.data.CraftBlockData;
++import org.bukkit.event.block.BlockCanBuildEvent;
++// CraftBukkit end
+
+ public class StandingAndWallBlockItem extends BlockItem {
+ protected final Block wallBlock;
+@@ -42,7 +54,19 @@
+ }
+ }
+
+- return blockState != null && level.isUnobstructed(blockState, clickedPos, CollisionContext.empty()) ? blockState : null;
++ // CraftBukkit start
++ if (iblockdata1 != null) {
++ boolean defaultReturn = world.isUnobstructed(iblockdata1, blockposition, CollisionContext.empty());
++ org.bukkit.entity.Player player = (context.getPlayer() instanceof ServerPlayer) ? (org.bukkit.entity.Player) context.getPlayer().getBukkitEntity() : null;
++
++ BlockCanBuildEvent event = new BlockCanBuildEvent(CraftBlock.at(world, blockposition), player, CraftBlockData.fromData(iblockdata1), defaultReturn);
++ context.getLevel().getCraftServer().getPluginManager().callEvent(event);
++
++ return (event.isBuildable()) ? iblockdata1 : null;
++ } else {
++ return null;
++ }
++ // CraftBukkit end
+ }
+
+ @Override
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/TridentItem.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/TridentItem.java.patch
new file mode 100644
index 0000000000..e2792900ad
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/TridentItem.java.patch
@@ -0,0 +1,100 @@
+--- a/net/minecraft/world/item/TridentItem.java
++++ b/net/minecraft/world/item/TridentItem.java
+@@ -62,39 +68,70 @@
+ int riptide = EnchantmentHelper.getRiptide(stack);
+ if (riptide <= 0 || player.isInWaterOrRain()) {
+ if (!level.isClientSide) {
+- stack.hurtAndBreak(1, player, contextEntity -> contextEntity.broadcastBreakEvent(entityLiving.getUsedItemHand()));
+- if (riptide == 0) {
+- ThrownTrident thrownTrident = new ThrownTrident(level, player, stack);
+- thrownTrident.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 2.5F + (float)riptide * 0.5F, 1.0F);
+- if (player.getAbilities().instabuild) {
+- thrownTrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
++ // CraftBukkit - moved down
++ /*
++ itemstack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(entityliving.getUsedItemHand());
++ });
++ */
++ if (k == 0) {
++ ThrownTrident entitythrowntrident = new ThrownTrident(level, entityhuman, stack);
++
++ entitythrowntrident.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, 1.0F);
++ if (entityhuman.getAbilities().instabuild) {
++ entitythrowntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
+ }
+
+- level.addFreshEntity(thrownTrident);
+- level.playSound(null, thrownTrident, SoundEvents.TRIDENT_THROW, SoundSource.PLAYERS, 1.0F, 1.0F);
+- if (!player.getAbilities().instabuild) {
+- player.getInventory().removeItem(stack);
++ // CraftBukkit start
++ if (!level.addFreshEntity(entitythrowntrident)) {
++ if (entityhuman instanceof net.minecraft.server.level.ServerPlayer) {
++ ((net.minecraft.server.level.ServerPlayer) entityhuman).getBukkitEntity().updateInventory();
++ }
++ return;
+ }
++
++ stack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(entityLiving.getUsedItemHand());
++ });
++ entitythrowntrident.pickupItemStack = stack.copy(); // SPIGOT-4511 update since damage call moved
++ // CraftBukkit end
++
++ level.playSound((Player) null, (Entity) entitythrowntrident, SoundEvents.TRIDENT_THROW, SoundSource.PLAYERS, 1.0F, 1.0F);
++ if (!entityhuman.getAbilities().instabuild) {
++ entityhuman.getInventory().removeItem(stack);
++ }
++ // CraftBukkit start - SPIGOT-5458 also need in this branch :(
++ } else {
++ stack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(entityLiving.getUsedItemHand());
++ });
++ // CraftBukkkit end
+ }
+ }
+
+- player.awardStat(Stats.ITEM_USED.get(this));
+- if (riptide > 0) {
+- float yRot = player.getYRot();
+- float xRot = player.getXRot();
+- float f = -Mth.sin(yRot * (float) (Math.PI / 180.0)) * Mth.cos(xRot * (float) (Math.PI / 180.0));
+- float f1 = -Mth.sin(xRot * (float) (Math.PI / 180.0));
+- float f2 = Mth.cos(yRot * (float) (Math.PI / 180.0)) * Mth.cos(xRot * (float) (Math.PI / 180.0));
+- float squareRoot = Mth.sqrt(f * f + f1 * f1 + f2 * f2);
+- float f3 = 3.0F * ((1.0F + (float)riptide) / 4.0F);
+- f *= f3 / squareRoot;
+- f1 *= f3 / squareRoot;
+- f2 *= f3 / squareRoot;
+- player.push((double)f, (double)f1, (double)f2);
+- player.startAutoSpinAttack(20);
+- if (player.onGround()) {
+- float f4 = 1.1999999F;
+- player.move(MoverType.SELF, new Vec3(0.0, 1.1999999F, 0.0));
++ entityhuman.awardStat(Stats.ITEM_USED.get(this));
++ if (k > 0) {
++ // CraftBukkit start
++ org.bukkit.event.player.PlayerRiptideEvent event = new org.bukkit.event.player.PlayerRiptideEvent((org.bukkit.entity.Player) entityhuman.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(stack));
++ event.getPlayer().getServer().getPluginManager().callEvent(event);
++ // CraftBukkit end
++ float f = entityhuman.getYRot();
++ float f1 = entityhuman.getXRot();
++ float f2 = -Mth.sin(f * 0.017453292F) * Mth.cos(f1 * 0.017453292F);
++ float f3 = -Mth.sin(f1 * 0.017453292F);
++ float f4 = Mth.cos(f * 0.017453292F) * Mth.cos(f1 * 0.017453292F);
++ float f5 = Mth.sqrt(f2 * f2 + f3 * f3 + f4 * f4);
++ float f6 = 3.0F * ((1.0F + (float) k) / 4.0F);
++
++ f2 *= f6 / f5;
++ f3 *= f6 / f5;
++ f4 *= f6 / f5;
++ entityhuman.push((double) f2, (double) f3, (double) f4);
++ entityhuman.startAutoSpinAttack(20);
++ if (entityhuman.onGround()) {
++ float f7 = 1.1999999F;
++
++ entityhuman.move(EnumMoveType.SELF, new Vec3(0.0D, 1.1999999284744263D, 0.0D));
+ }
+
+ SoundEvent soundEvent;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/BlastingRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
new file mode 100644
index 0000000000..f73982496b
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/BlastingRecipe.java
++++ b/net/minecraft/world/item/crafting/BlastingRecipe.java
+@@ -3,6 +3,14 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftBlastingRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class BlastingRecipe extends AbstractCookingRecipe {
+ public BlastingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+ super(RecipeType.BLASTING, string, cookingBookCategory, ingredient, itemStack, f, i);
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.BLASTING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftBlastingRecipe recipe = new CraftBlastingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
new file mode 100644
index 0000000000..c33d2d4a9b
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
++++ b/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
+@@ -3,6 +3,14 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftCampfireRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class CampfireCookingRecipe extends AbstractCookingRecipe {
+ public CampfireCookingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+ super(RecipeType.CAMPFIRE_COOKING, string, cookingBookCategory, ingredient, itemStack, f, i);
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.CAMPFIRE_COOKING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftCampfireRecipe recipe = new CraftCampfireRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CustomRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CustomRecipe.java.patch
new file mode 100644
index 0000000000..0a032bd01d
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/CustomRecipe.java.patch
@@ -0,0 +1,29 @@
+--- a/net/minecraft/world/item/crafting/CustomRecipe.java
++++ b/net/minecraft/world/item/crafting/CustomRecipe.java
+@@ -3,7 +3,13 @@
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.world.item.ItemStack;
+
+-public abstract class CustomRecipe implements CraftingRecipe {
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
++public abstract class CustomRecipe implements RecipeCrafting {
++
+ private final CraftingBookCategory category;
+
+ public CustomRecipe(CraftingBookCategory craftingBookCategory) {
+@@ -24,4 +30,11 @@
+ public CraftingBookCategory category() {
+ return this.category;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ return new org.bukkit.craftbukkit.inventory.CraftComplexRecipe(id, this);
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Ingredient.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Ingredient.java.patch
new file mode 100644
index 0000000000..17af072826
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Ingredient.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/Ingredient.java
++++ b/net/minecraft/world/item/crafting/Ingredient.java
+@@ -34,6 +35,7 @@
+ private ItemStack[] itemStacks;
+ @Nullable
+ private IntList stackingIds;
++ public boolean exact; // CraftBukkit
+ public static final Codec<Ingredient> CODEC = codec(true);
+ public static final Codec<Ingredient> CODEC_NONEMPTY = codec(false);
+
+@@ -60,8 +67,22 @@
+ } else if (this.isEmpty()) {
+ return stack.isEmpty();
+ } else {
+- for (ItemStack itemStack : this.getItems()) {
+- if (itemStack.is(stack.getItem())) {
++ ItemStack[] aitemstack = this.getItems();
++ int i = aitemstack.length;
++
++ for (int j = 0; j < i; ++j) {
++ ItemStack itemstack1 = aitemstack[j];
++
++ // CraftBukkit start
++ if (exact) {
++ if (itemstack1.getItem() == stack.getItem() && ItemStack.isSameItemSameTags(stack, itemstack1)) {
++ return true;
++ }
++
++ continue;
++ }
++ // CraftBukkit end
++ if (itemstack1.is(stack.getItem())) {
+ return true;
+ }
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Recipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Recipe.java.patch
new file mode 100644
index 0000000000..00d4c5ced3
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/Recipe.java.patch
@@ -0,0 +1,9 @@
+--- a/net/minecraft/world/item/crafting/Recipe.java
++++ b/net/minecraft/world/item/crafting/Recipe.java
+@@ -62,4 +67,6 @@
+ NonNullList<Ingredient> ingredients = this.getIngredients();
+ return ingredients.isEmpty() || ingredients.stream().anyMatch(ingredient -> ingredient.getItems().length == 0);
+ }
++
++ org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeHolder.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeHolder.java.patch
new file mode 100644
index 0000000000..d7bfcda029
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeHolder.java.patch
@@ -0,0 +1,22 @@
+--- a/net/minecraft/world/item/crafting/RecipeHolder.java
++++ b/net/minecraft/world/item/crafting/RecipeHolder.java
+@@ -1,9 +1,17 @@
+ package net.minecraft.world.item.crafting;
+
+ import net.minecraft.resources.ResourceLocation;
++// CraftBukkit start
++import org.bukkit.craftbukkit.util.CraftNamespacedKey;
++import org.bukkit.inventory.Recipe;
+
+-public record RecipeHolder<T extends Recipe<?>>(ResourceLocation id, T value) {
+- @Override
++public record RecipeHolder<T extends net.minecraft.world.item.crafting.Recipe<?>>(ResourceLocation id, T value) {
++
++ public final Recipe toBukkitRecipe() {
++ return this.value.toBukkitRecipe(CraftNamespacedKey.fromMinecraft(this.id));
++ }
++ // CraftBukkit end
++
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeManager.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeManager.java.patch
new file mode 100644
index 0000000000..ea766ea2ff
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/RecipeManager.java.patch
@@ -0,0 +1,165 @@
+--- a/net/minecraft/world/item/crafting/RecipeManager.java
++++ b/net/minecraft/world/item/crafting/RecipeManager.java
+@@ -23,6 +24,15 @@
+ import javax.annotation.Nullable;
+ import net.minecraft.Util;
+ import net.minecraft.core.NonNullList;
++import net.minecraft.world.Container;
++import net.minecraft.world.item.ItemStack;
++import net.minecraft.world.level.Level;
++import org.slf4j.Logger;
++
++// CraftBukkit start
++import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
++import net.minecraft.core.registries.BuiltInRegistries;
++// CraftBukkit end
+ import net.minecraft.resources.ResourceLocation;
+ import net.minecraft.server.packs.resources.ResourceManager;
+ import net.minecraft.server.packs.resources.SimpleJsonResourceReloadListener;
+@@ -36,7 +43,7 @@
+ public class RecipeManager extends SimpleJsonResourceReloadListener {
+ private static final Gson GSON = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().create();
+ private static final Logger LOGGER = LogUtils.getLogger();
+- private Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>> recipes = ImmutableMap.of();
++ public Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> recipes = ImmutableMap.of(); // CraftBukkit
+ private Map<ResourceLocation, RecipeHolder<?>> byName = ImmutableMap.of();
+ private boolean hasErrors;
+
+@@ -47,32 +53,63 @@
+ @Override
+ protected void apply(Map<ResourceLocation, JsonElement> object, ResourceManager resourceManager, ProfilerFiller profiler) {
+ this.hasErrors = false;
+- Map<RecipeType<?>, Builder<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap();
++ // CraftBukkit start - SPIGOT-5667 make sure all types are populated and mutable
++ Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> map1 = Maps.newHashMap();
++ for (RecipeType<?> recipeType : BuiltInRegistries.RECIPE_TYPE) {
++ map1.put(recipeType, new Object2ObjectLinkedOpenHashMap<>());
++ }
++ // CraftBukkit end
+ Builder<ResourceLocation, RecipeHolder<?>> builder = ImmutableMap.builder();
+
+ for (Entry<ResourceLocation, JsonElement> entry : object.entrySet()) {
+ ResourceLocation resourceLocation = entry.getKey();
+
+ try {
+- RecipeHolder<?> recipeHolder = fromJson(resourceLocation, GsonHelper.convertToJsonObject(entry.getValue(), "top element"));
+- map.computeIfAbsent(recipeHolder.value().getType(), type -> ImmutableMap.builder()).put(resourceLocation, recipeHolder);
+- builder.put(resourceLocation, recipeHolder);
+- } catch (IllegalArgumentException | JsonParseException var10) {
+- LOGGER.error("Parsing error loading recipe {}", resourceLocation, var10);
++ RecipeHolder<?> recipeholder = fromJson(minecraftkey, GsonHelper.convertToJsonObject((JsonElement) entry.getValue(), "top element"));
++
++ // CraftBukkit start
++ (map1.computeIfAbsent(recipeholder.value().getType(), (recipes) -> {
++ return new Object2ObjectLinkedOpenHashMap<>();
++ // CraftBukkit end
++ })).put(minecraftkey, recipeholder);
++ builder.put(minecraftkey, recipeholder);
++ } catch (IllegalArgumentException | JsonParseException jsonparseexception) {
++ RecipeManager.LOGGER.error("Parsing error loading recipe {}", minecraftkey, jsonparseexception);
+ }
+ }
+
+- this.recipes = map.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, entry1 -> entry1.getValue().build()));
+- this.byName = builder.build();
+- LOGGER.info("Loaded {} recipes", map.size());
++ this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> {
++ return (entry1.getValue()); // CraftBukkit
++ }));
++ this.byName = Maps.newHashMap(builder.build()); // CraftBukkit
++ RecipeManager.LOGGER.info("Loaded {} recipes", map1.size());
+ }
+
++ // CraftBukkit start
++ public void addRecipe(RecipeHolder<?> irecipe) {
++ Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>> map = this.recipes.get(irecipe.value().getType()); // CraftBukkit
++
++ if (byName.containsKey(irecipe.id()) || map.containsKey(irecipe.id())) {
++ throw new IllegalStateException("Duplicate recipe ignored with ID " + irecipe.id());
++ } else {
++ map.putAndMoveToFirst(irecipe.id(), irecipe); // CraftBukkit - SPIGOT-4638: last recipe gets priority
++ byName.put(irecipe.id(), irecipe);
++ }
++ }
++ // CraftBukkit end
++
+ public boolean hadErrorsLoading() {
+ return this.hasErrors;
+ }
+
+ public <C extends Container, T extends Recipe<C>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> recipeType, C inventory, Level level) {
+- return this.byType(recipeType).values().stream().filter(recipeHolder -> recipeHolder.value().matches(inventory, level)).findFirst();
++ // CraftBukkit start
++ Optional<RecipeHolder<T>> recipe = this.byType(recipeType).values().stream().filter((recipeholder) -> {
++ return recipeholder.value().matches(inventory, level);
++ }).findFirst();
++ inventory.setCurrentRecipe(recipe.orElse(null)); // CraftBukkit - Clear recipe when no recipe is found
++ return recipe;
++ // CraftBukkit end
+ }
+
+ public <C extends Container, T extends Recipe<C>> Optional<Pair<ResourceLocation, RecipeHolder<T>>> getRecipeFor(
+@@ -107,7 +145,7 @@
+ }
+
+ private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, RecipeHolder<T>> byType(RecipeType<T> recipeType) {
+- return (Map<ResourceLocation, RecipeHolder<T>>) ((Map<ResourceLocation, ?>) this.recipes.getOrDefault(recipeType, Collections.emptyMap()));
++ return (Map) this.recipes.getOrDefault(recipeType, new Object2ObjectLinkedOpenHashMap<>()); // CraftBukkit
+ }
+
+ public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> recipeType, C inventory, Level level) {
+@@ -144,21 +188,45 @@
+
+ public void replaceRecipes(Iterable<RecipeHolder<?>> recipes) {
+ this.hasErrors = false;
+- Map<RecipeType<?>, Map<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap();
++ Map<RecipeType<?>, Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>>> map = Maps.newHashMap(); // CraftBukkit
+ Builder<ResourceLocation, RecipeHolder<?>> builder = ImmutableMap.builder();
+- recipes.forEach(recipeHolder -> {
+- Map<ResourceLocation, RecipeHolder<?>> map1 = map.computeIfAbsent(recipeHolder.value().getType(), recipeType -> Maps.newHashMap());
+- ResourceLocation resourceLocation = recipeHolder.id();
+- RecipeHolder<?> recipeHolder1 = map1.put(resourceLocation, (RecipeHolder<?>)recipeHolder);
+- builder.put(resourceLocation, (RecipeHolder<?>)recipeHolder);
+- if (recipeHolder1 != null) {
+- throw new IllegalStateException("Duplicate recipe ignored with ID " + resourceLocation);
++
++ recipes.forEach((recipeholder) -> {
++ Map<ResourceLocation, RecipeHolder<?>> map1 = (Map) map.computeIfAbsent(recipeholder.value().getType(), (recipes) -> {
++ return new Object2ObjectLinkedOpenHashMap<>(); // CraftBukkit
++ });
++ ResourceLocation minecraftkey = recipeholder.id();
++ RecipeHolder<?> recipeholder1 = (RecipeHolder) map1.put(minecraftkey, recipeholder);
++
++ builder.put(minecraftkey, recipeholder);
++ if (recipeholder1 != null) {
++ throw new IllegalStateException("Duplicate recipe ignored with ID " + minecraftkey);
+ }
+ });
+ this.recipes = ImmutableMap.copyOf(map);
+- this.byName = builder.build();
++ this.byName = Maps.newHashMap(builder.build()); // CraftBukkit
+ }
+
++ // CraftBukkit start
++ public boolean removeRecipe(ResourceLocation mcKey) {
++ for (Object2ObjectLinkedOpenHashMap<ResourceLocation, RecipeHolder<?>> recipes : recipes.values()) {
++ recipes.remove(mcKey);
++ }
++
++ return byName.remove(mcKey) != null;
++ }
++
++ public void clearRecipes() {
++ this.recipes = Maps.newHashMap();
++
++ for (RecipeType<?> recipeType : BuiltInRegistries.RECIPE_TYPE) {
++ this.recipes.put(recipeType, new Object2ObjectLinkedOpenHashMap<>());
++ }
++
++ this.byName = Maps.newHashMap();
++ }
++ // CraftBukkit end
++
+ public static <C extends Container, T extends Recipe<C>> RecipeManager.CachedCheck<C, T> createCheck(final RecipeType<T> recipeType) {
+ return new RecipeManager.CachedCheck<C, T>() {
+ @Nullable
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapedRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
new file mode 100644
index 0000000000..f5537291f4
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
@@ -0,0 +1,86 @@
+--- a/net/minecraft/world/item/crafting/ShapedRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapedRecipe.java
+@@ -10,6 +9,13 @@
+ import net.minecraft.world.inventory.CraftingContainer;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftShapedRecipe;
++import org.bukkit.inventory.RecipeChoice;
++// CraftBukkit end
+
+ public class ShapedRecipe implements CraftingRecipe {
+ final ShapedRecipePattern pattern;
+@@ -30,7 +37,69 @@
+ this(string, craftingBookCategory, shapedRecipePattern, itemStack, true);
+ }
+
++ // CraftBukkit start
+ @Override
++ public org.bukkit.inventory.ShapedRecipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++ CraftShapedRecipe recipe = new CraftShapedRecipe(id, result, this);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ switch (this.pattern.height()) {
++ case 1:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a");
++ break;
++ case 2:
++ recipe.shape("ab");
++ break;
++ case 3:
++ recipe.shape("abc");
++ break;
++ }
++ break;
++ case 2:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a","b");
++ break;
++ case 2:
++ recipe.shape("ab","cd");
++ break;
++ case 3:
++ recipe.shape("abc","def");
++ break;
++ }
++ break;
++ case 3:
++ switch (this.pattern.width()) {
++ case 1:
++ recipe.shape("a","b","c");
++ break;
++ case 2:
++ recipe.shape("ab","cd","ef");
++ break;
++ case 3:
++ recipe.shape("abc","def","ghi");
++ break;
++ }
++ break;
++ }
++ char c = 'a';
++ for (Ingredient list : this.pattern.ingredients()) {
++ RecipeChoice choice = CraftRecipe.toBukkit(list);
++ if (choice != null) {
++ recipe.setIngredient(c, choice);
++ }
++
++ c++;
++ }
++ return recipe;
++ }
++ // CraftBukkit end
++
++ @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SHAPED_RECIPE;
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
new file mode 100644
index 0000000000..97a06c348e
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
@@ -0,0 +1,39 @@
+--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
+@@ -13,6 +13,12 @@
+ import net.minecraft.world.inventory.CraftingContainer;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftShapelessRecipe;
++// CraftBukkit end
+
+ public class ShapelessRecipe implements CraftingRecipe {
+ final String group;
+@@ -27,7 +34,23 @@
+ this.ingredients = list;
+ }
+
++ // CraftBukkit start
++ @SuppressWarnings("unchecked")
+ @Override
++ public org.bukkit.inventory.ShapelessRecipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++ CraftShapelessRecipe recipe = new CraftShapelessRecipe(id, result, this);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ for (Ingredient list : this.ingredients) {
++ recipe.addIngredient(CraftRecipe.toBukkit(list));
++ }
++ return recipe;
++ }
++ // CraftBukkit end
++
++ @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SHAPELESS_RECIPE;
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
new file mode 100644
index 0000000000..352ab54802
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/SmeltingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmeltingRecipe.java
+@@ -3,6 +3,14 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftFurnaceRecipe;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class SmeltingRecipe extends AbstractCookingRecipe {
+ public SmeltingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+ super(RecipeType.SMELTING, string, cookingBookCategory, ingredient, itemStack, f, i);
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMELTING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftFurnaceRecipe recipe = new CraftFurnaceRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
new file mode 100644
index 0000000000..1928a3054d
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
@@ -0,0 +1,60 @@
+--- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
+@@ -10,6 +9,13 @@
+ import net.minecraft.world.Container;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmithingTransformRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
+
+ public class SmithingTransformRecipe implements SmithingRecipe {
+ final Ingredient template;
+@@ -70,17 +78,33 @@
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTransformRecipe> {
+- private static final Codec<SmithingTransformRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- Ingredient.CODEC.fieldOf("template").forGetter(smithingTransformRecipe -> smithingTransformRecipe.template),
+- Ingredient.CODEC.fieldOf("base").forGetter(smithingTransformRecipe -> smithingTransformRecipe.base),
+- Ingredient.CODEC.fieldOf("addition").forGetter(smithingTransformRecipe -> smithingTransformRecipe.addition),
+- ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter(smithingTransformRecipe -> smithingTransformRecipe.result)
+- )
+- .apply(instance, SmithingTransformRecipe::new)
+- );
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
+
++ CraftSmithingTransformRecipe recipe = new CraftSmithingTransformRecipe(id, result, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition));
++
++ return recipe;
++ }
++ // CraftBukkit end
++
++ public static class a implements RecipeSerializer<SmithingTransformRecipe> {
++
++ private static final Codec<SmithingTransformRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
++ return instance.group(Ingredient.CODEC.fieldOf("template").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.template;
++ }), Ingredient.CODEC.fieldOf("base").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.base;
++ }), Ingredient.CODEC.fieldOf("addition").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.addition;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((smithingtransformrecipe) -> {
++ return smithingtransformrecipe.result;
++ })).apply(instance, SmithingTransformRecipe::new);
++ });
++
++ public a() {}
++
+ @Override
+ public Codec<SmithingTransformRecipe> codec() {
+ return CODEC;
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
new file mode 100644
index 0000000000..400058b878
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
@@ -0,0 +1,37 @@
+--- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
+@@ -18,6 +17,12 @@
+ import net.minecraft.world.item.armortrim.TrimPattern;
+ import net.minecraft.world.item.armortrim.TrimPatterns;
+ import net.minecraft.world.level.Level;
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmithingTrimRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
+
+ public class SmithingTrimRecipe implements SmithingRecipe {
+ final Ingredient template;
+@@ -99,15 +113,12 @@
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTrimRecipe> {
+- private static final Codec<SmithingTrimRecipe> CODEC = RecordCodecBuilder.create(
+- instance -> instance.group(
+- Ingredient.CODEC.fieldOf("template").forGetter(smithingTrimRecipe -> smithingTrimRecipe.template),
+- Ingredient.CODEC.fieldOf("base").forGetter(smithingTrimRecipe -> smithingTrimRecipe.base),
+- Ingredient.CODEC.fieldOf("addition").forGetter(smithingTrimRecipe -> smithingTrimRecipe.addition)
+- )
+- .apply(instance, SmithingTrimRecipe::new)
+- );
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ return new CraftSmithingTrimRecipe(id, CraftRecipe.toBukkit(this.template), CraftRecipe.toBukkit(this.base), CraftRecipe.toBukkit(this.addition));
++ }
++ // CraftBukkit end
+
+ @Override
+ public Codec<SmithingTrimRecipe> codec() {
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmokingRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
new file mode 100644
index 0000000000..8ca8e06845
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/SmokingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmokingRecipe.java
+@@ -3,6 +3,14 @@
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftSmokingRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class SmokingRecipe extends AbstractCookingRecipe {
+ public SmokingRecipe(String string, CookingBookCategory cookingBookCategory, Ingredient ingredient, ItemStack itemStack, float f, int i) {
+ super(RecipeType.SMOKING, string, cookingBookCategory, ingredient, itemStack, f, i);
+@@ -17,4 +26,17 @@
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMOKING_RECIPE;
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftSmokingRecipe recipe = new CraftSmokingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient), this.experience, this.cookingTime);
++ recipe.setGroup(this.group);
++ recipe.setCategory(CraftRecipe.getCategory(this.category()));
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
new file mode 100644
index 0000000000..3d3dd4157c
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
@@ -0,0 +1,34 @@
+--- a/net/minecraft/world/item/crafting/StonecutterRecipe.java
++++ b/net/minecraft/world/item/crafting/StonecutterRecipe.java
+@@ -5,6 +5,14 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.Blocks;
+
++// CraftBukkit start
++import org.bukkit.NamespacedKey;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.craftbukkit.inventory.CraftRecipe;
++import org.bukkit.craftbukkit.inventory.CraftStonecuttingRecipe;
++import org.bukkit.inventory.Recipe;
++// CraftBukkit end
++
+ public class StonecutterRecipe extends SingleItemRecipe {
+ public StonecutterRecipe(String string, Ingredient ingredient, ItemStack itemStack) {
+ super(RecipeType.STONECUTTING, RecipeSerializer.STONECUTTER, string, ingredient, itemStack);
+@@ -19,4 +28,16 @@
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.STONECUTTER);
+ }
++
++ // CraftBukkit start
++ @Override
++ public Recipe toBukkitRecipe(NamespacedKey id) {
++ CraftItemStack result = CraftItemStack.asCraftMirror(this.result);
++
++ CraftStonecuttingRecipe recipe = new CraftStonecuttingRecipe(id, result, CraftRecipe.toBukkit(this.ingredient));
++ recipe.setGroup(this.group);
++
++ return recipe;
++ }
++ // CraftBukkit end
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch
new file mode 100644
index 0000000000..e89dde3451
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch
@@ -0,0 +1,20 @@
+--- a/net/minecraft/world/item/enchantment/DamageEnchantment.java
++++ b/net/minecraft/world/item/enchantment/DamageEnchantment.java
+@@ -62,9 +57,14 @@
+
+ @Override
+ public void doPostAttack(LivingEntity user, Entity target, int level) {
+- if (target instanceof LivingEntity livingEntity && this.type == 2 && level > 0 && livingEntity.getMobType() == MobType.ARTHROPOD) {
+- int i = 20 + user.getRandom().nextInt(10 * level);
+- livingEntity.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, i, 3));
++ if (target instanceof LivingEntity) {
++ LivingEntity entityliving1 = (LivingEntity) target;
++
++ if (this.type == 2 && level > 0 && entityliving1.getMobType() == EnumMonsterType.ARTHROPOD) {
++ int j = 20 + user.getRandom().nextInt(10 * level);
++
++ entityliving1.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, j, 3), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
++ }
+ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch
new file mode 100644
index 0000000000..89a7a488e8
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch
@@ -0,0 +1,36 @@
+--- a/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java
++++ b/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java
+@@ -41,17 +44,22 @@
+ int min = Math.min(16, 2 + levelConflicting);
+ BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+
+- for (BlockPos blockPos : BlockPos.betweenClosed(pos.offset(-min, -1, -min), pos.offset(min, -1, min))) {
+- if (blockPos.closerToCenterThan(living.position(), (double)min)) {
+- mutableBlockPos.set(blockPos.getX(), blockPos.getY() + 1, blockPos.getZ());
+- BlockState blockState1 = level.getBlockState(mutableBlockPos);
+- if (blockState1.isAir()) {
+- BlockState blockState2 = level.getBlockState(blockPos);
+- if (blockState2 == FrostedIceBlock.meltsInto()
+- && blockState.canSurvive(level, blockPos)
+- && level.isUnobstructed(blockState, blockPos, CollisionContext.empty())) {
+- level.setBlockAndUpdate(blockPos, blockState);
+- level.scheduleTick(blockPos, Blocks.FROSTED_ICE, Mth.nextInt(living.getRandom(), 60, 120));
++ while (iterator.hasNext()) {
++ BlockPos blockposition1 = (BlockPos) iterator.next();
++
++ if (blockposition1.closerToCenterThan(living.position(), (double) j)) {
++ blockposition_mutableblockposition.set(blockposition1.getX(), blockposition1.getY() + 1, blockposition1.getZ());
++ IBlockData iblockdata1 = level.getBlockState(blockposition_mutableblockposition);
++
++ if (iblockdata1.isAir()) {
++ IBlockData iblockdata2 = level.getBlockState(blockposition1);
++
++ if (iblockdata2 == FrostedIceBlock.meltsInto() && iblockdata.canSurvive(level, blockposition1) && level.isUnobstructed(iblockdata, blockposition1, CollisionContext.empty())) {
++ // CraftBukkit Start - Call EntityBlockFormEvent for Frost Walker
++ if (org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(level, blockposition1, iblockdata, living)) {
++ level.scheduleTick(blockposition1, Blocks.FROSTED_ICE, Mth.nextInt(living.getRandom(), 60, 120));
++ }
++ // CraftBukkit End
+ }
+ }
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/Merchant.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/Merchant.java.patch
new file mode 100644
index 0000000000..75f2487c54
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/Merchant.java.patch
@@ -0,0 +1,9 @@
+--- a/net/minecraft/world/item/trading/Merchant.java
++++ b/net/minecraft/world/item/trading/Merchant.java
+@@ -49,4 +52,6 @@
+ }
+
+ boolean isClientSide();
++
++ org.bukkit.craftbukkit.inventory.CraftMerchant getCraftMerchant(); // CraftBukkit
+ }
diff --git a/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/MerchantOffer.java.patch b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/MerchantOffer.java.patch
new file mode 100644
index 0000000000..260f3829e8
--- /dev/null
+++ b/patch-remap/mache-vineflower-stripped/net/minecraft/world/item/trading/MerchantOffer.java.patch
@@ -0,0 +1,73 @@
+--- a/net/minecraft/world/item/trading/MerchantOffer.java
++++ b/net/minecraft/world/item/trading/MerchantOffer.java
+@@ -5,6 +5,8 @@
+ import net.minecraft.util.Mth;
+ import net.minecraft.world.item.ItemStack;
+
++import org.bukkit.craftbukkit.inventory.CraftMerchantRecipe; // CraftBukkit
++
+ public class MerchantOffer {
+ private final ItemStack baseCostA;
+ private final ItemStack costB;
+@@ -17,6 +9,33 @@
+ private float priceMultiplier;
+ private int xp = 1;
+
++ public ItemStack baseCostA;
++ public ItemStack costB;
++ public final ItemStack result;
++ public int uses;
++ public int maxUses;
++ public boolean rewardExp;
++ public int specialPriceDiff;
++ public int demand;
++ public float priceMultiplier;
++ public int xp;
++ // CraftBukkit start
++ private CraftMerchantRecipe bukkitHandle;
++
++ public CraftMerchantRecipe asBukkit() {
++ return (bukkitHandle == null) ? bukkitHandle = new CraftMerchantRecipe(this) : bukkitHandle;
++ }
++
++ public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, ItemStack itemstack2, int uses, int maxUses, int experience, float priceMultiplier, CraftMerchantRecipe bukkit) {
++ this(itemstack, itemstack1, itemstack2, uses, maxUses, experience, priceMultiplier, 0, bukkit);
++ }
++
++ public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, ItemStack itemstack2, int uses, int maxUses, int experience, float priceMultiplier, int demand, CraftMerchantRecipe bukkit) {
++ this(itemstack, itemstack1, itemstack2, uses, maxUses, experience, priceMultiplier, demand);
++ this.bukkitHandle = bukkit;
++ }
++ // CraftBukkit end
++
+ public MerchantOffer(CompoundTag compoundTag) {
+ this.baseCostA = ItemStack.of(compoundTag.getCompound("buy"));
+ this.costB = ItemStack.of(compoundTag.getCompound("buyB"));
+@@ -88,9 +113,11 @@
+ if (this.baseCostA.isEmpty()) {
+ return ItemStack.EMPTY;
+ } else {
+- int count = this.baseCostA.getCount();
+- int max = Math.max(0, Mth.floor((float)(count * this.demand) * this.priceMultiplier));
+- return this.baseCostA.copyWithCount(Mth.clamp(count + max + this.specialPriceDiff, 1, this.baseCostA.getItem().getMaxStackSize()));
++ int i = this.baseCostA.getCount();
++ if (i <= 0) return ItemStack.EMPTY; // CraftBukkit - SPIGOT-5476
++ int j = Math.max(0, Mth.floor((float) (i * this.demand) * this.priceMultiplier));
++
++ return this.baseCostA.copyWithCount(Mth.clamp(i + j + this.specialPriceDiff, 1, this.baseCostA.getItem().getMaxStackSize()));
+ }
+ }
+
+@@ -210,7 +235,11 @@
+ if (!this.satisfiedBy(playerOfferA, playerOfferB)) {
+ return false;
+ } else {
+- playerOfferA.shrink(this.getCostA().getCount());
++ // CraftBukkit start
++ if (!this.getCostA().isEmpty()) {
++ playerOfferA.shrink(this.getCostA().getCount());
++ }
++ // CraftBukkit end
+ if (!this.getCostB().isEmpty()) {
+ playerOfferB.shrink(this.getCostB().getCount());
+ }