aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower/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-spigotflower/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-spigotflower/net/minecraft/world/item')
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorItem.java.patch187
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorStandItem.java.patch85
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/BlockItem.java.patch398
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/BoatItem.java.patch118
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/BoneMealItem.java.patch260
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/BowItem.java.patch190
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/BucketItem.java.patch275
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/ChorusFruitItem.java.patch86
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/CrossbowItem.java.patch538
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/DebugStickItem.java.patch155
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/DyeItem.java.patch87
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/EggItem.java.patch52
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/EndCrystalItem.java.patch96
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/EnderEyeItem.java.patch136
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/EnderpearlItem.java.patch55
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/FireChargeItem.java.patch89
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/FishingRodItem.java.patch80
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/FlintAndSteelItem.java.patch104
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/HangingEntityItem.java.patch157
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/ItemStack.java.patch1314
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/LeadItem.java.patch119
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/MapItem.java.patch548
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/MilkBucketItem.java.patch74
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/MinecartItem.java.patch195
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/PotionItem.java.patch185
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/RecordItem.java.patch99
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/SignItem.java.patch55
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/SnowballItem.java.patch63
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/SpawnEggItem.java.patch232
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/StandingAndWallBlockItem.java.patch103
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/TridentItem.java.patch245
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch47
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch47
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch46
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Ingredient.java.patch278
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Recipe.java.patch30
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch35
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeManager.java.patch274
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch235
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch204
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch47
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch159
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch178
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch47
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch48
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch90
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch98
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/trading/Merchant.java.patch32
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/item/trading/MerchantOffer.java.patch261
49 files changed, 8536 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorItem.java.patch
new file mode 100644
index 0000000000..5157e1a538
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorItem.java.patch
@@ -0,0 +1,187 @@
+--- a/net/minecraft/world/item/ArmorItem.java
++++ b/net/minecraft/world/item/ArmorItem.java
+@@ -9,11 +9,11 @@
+ import net.minecraft.Util;
+ import net.minecraft.core.BlockPos;
+ import net.minecraft.core.Direction;
+-import net.minecraft.core.dispenser.BlockSource;
+ import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
+ import net.minecraft.core.dispenser.DispenseItemBehavior;
++import net.minecraft.core.dispenser.SourceBlock;
+ import net.minecraft.sounds.SoundEvent;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.EntitySelector;
+ import net.minecraft.world.entity.EquipmentSlot;
+@@ -26,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 {
+
+@@ -37,9 +42,8 @@
+ });
+ public static final DispenseItemBehavior DISPENSE_ITEM_BEHAVIOR = new DefaultDispenseItemBehavior() {
+ @Override
+- @Override
+- protected ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
+- return ArmorItem.dispenseArmor(blocksource, itemstack) ? itemstack : super.execute(blocksource, itemstack);
++ protected ItemStack execute(SourceBlock sourceblock, ItemStack itemstack) {
++ return ArmorItem.dispenseArmor(sourceblock, itemstack) ? itemstack : super.execute(sourceblock, itemstack);
+ }
+ };
+ protected final ArmorItem.Type type;
+@@ -49,41 +53,67 @@
+ protected final ArmorMaterial material;
+ private final Multimap<Attribute, AttributeModifier> defaultModifiers;
+
+- public static boolean dispenseArmor(BlockSource blocksource, ItemStack itemstack) {
+- BlockPos blockpos = blocksource.pos().relative((Direction) blocksource.state().getValue(DispenserBlock.FACING));
+- List<LivingEntity> list = blocksource.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockpos), EntitySelector.NO_SPECTATORS.and(new EntitySelector.MobCanWearArmorEntitySelector(itemstack)));
++ public static boolean dispenseArmor(SourceBlock sourceblock, ItemStack itemstack) {
++ BlockPos blockposition = sourceblock.pos().relative((Direction) sourceblock.state().getValue(DispenserBlock.FACING));
++ List<LivingEntity> list = sourceblock.level().getEntitiesOfClass(LivingEntity.class, new AABB(blockposition), EntitySelector.NO_SPECTATORS.and(new EntitySelector.MobCanWearArmorEntitySelector(itemstack)));
+
+ if (list.isEmpty()) {
+ return false;
+ } else {
+- LivingEntity livingentity = (LivingEntity) list.get(0);
+- EquipmentSlot equipmentslot = Mob.getEquipmentSlotForItem(itemstack);
++ 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);
+
+- livingentity.setItemSlot(equipmentslot, itemstack1);
+- if (livingentity instanceof Mob) {
+- ((Mob) livingentity).setDropChance(equipmentslot, 2.0F);
+- ((Mob) livingentity).setPersistenceRequired();
++ 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;
+ }
+ }
+
+- public ArmorItem(ArmorMaterial armormaterial, ArmorItem.Type armoritem_type, Item.Properties item_properties) {
+- super(item_properties.defaultDurability(armormaterial.getDurabilityForType(armoritem_type)));
+- this.material = armormaterial;
+- this.type = armoritem_type;
+- this.defense = armormaterial.getDefenseForType(armoritem_type);
+- this.toughness = armormaterial.getToughness();
+- this.knockbackResistance = armormaterial.getKnockbackResistance();
++ public ArmorItem(ArmorMaterial material, ArmorItem.Type type, Item.Properties properties) {
++ super(properties.defaultDurability(material.getDurabilityForType(type)));
++ this.material = material;
++ this.type = type;
++ this.defense = material.getDefenseForType(type);
++ this.toughness = material.getToughness();
++ this.knockbackResistance = material.getKnockbackResistance();
+ DispenserBlock.registerBehavior(this, ArmorItem.DISPENSE_ITEM_BEHAVIOR);
+ Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
+- UUID uuid = (UUID) ArmorItem.ARMOR_MODIFIER_UUID_PER_TYPE.get(armoritem_type);
++ UUID uuid = (UUID) ArmorItem.ARMOR_MODIFIER_UUID_PER_TYPE.get(type);
+
+ builder.put(Attributes.ARMOR, new AttributeModifier(uuid, "Armor modifier", (double) this.defense, AttributeModifier.Operation.ADDITION));
+ builder.put(Attributes.ARMOR_TOUGHNESS, new AttributeModifier(uuid, "Armor toughness", (double) this.toughness, AttributeModifier.Operation.ADDITION));
+- if (armormaterial == ArmorMaterials.NETHERITE) {
++ if (material == ArmorMaterials.NETHERITE) {
+ builder.put(Attributes.KNOCKBACK_RESISTANCE, new AttributeModifier(uuid, "Armor knockback resistance", (double) this.knockbackResistance, AttributeModifier.Operation.ADDITION));
+ }
+
+@@ -95,7 +125,6 @@
+ }
+
+ @Override
+- @Override
+ public int getEnchantmentValue() {
+ return this.material.getEnchantmentValue();
+ }
+@@ -105,21 +134,18 @@
+ }
+
+ @Override
+- @Override
+- public boolean isValidRepairItem(ItemStack itemstack, ItemStack itemstack1) {
+- return this.material.getRepairIngredient().test(itemstack1) || super.isValidRepairItem(itemstack, itemstack1);
++ public boolean isValidRepairItem(ItemStack toRepair, ItemStack repair) {
++ return this.material.getRepairIngredient().test(repair) || super.isValidRepairItem(toRepair, repair);
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- return this.swapWithEquipmentSlot(this, level, player, interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ return this.swapWithEquipmentSlot(this, level, player, hand);
+ }
+
+ @Override
+- @Override
+- public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot equipmentslot) {
+- return equipmentslot == this.type.getSlot() ? this.defaultModifiers : super.getDefaultAttributeModifiers(equipmentslot);
++ public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot equipmentSlot) {
++ return equipmentSlot == this.type.getSlot() ? this.defaultModifiers : super.getDefaultAttributeModifiers(equipmentSlot);
+ }
+
+ public int getDefense() {
+@@ -131,13 +157,11 @@
+ }
+
+ @Override
+- @Override
+ public EquipmentSlot getEquipmentSlot() {
+ return this.type.getSlot();
+ }
+
+ @Override
+- @Override
+ public SoundEvent getEquipSound() {
+ return this.getMaterial().getEquipSound();
+ }
+@@ -149,8 +173,8 @@
+ private final EquipmentSlot slot;
+ private final String name;
+
+- private Type(EquipmentSlot equipmentslot, String s) {
+- this.slot = equipmentslot;
++ private Type(EquipmentSlot enumitemslot, String s) {
++ this.slot = enumitemslot;
+ this.name = s;
+ }
+
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorStandItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorStandItem.java.patch
new file mode 100644
index 0000000000..cb1b5174b4
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/ArmorStandItem.java.patch
@@ -0,0 +1,85 @@
+--- a/net/minecraft/world/item/ArmorStandItem.java
++++ b/net/minecraft/world/item/ArmorStandItem.java
+@@ -10,7 +10,7 @@
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntityType;
+-import net.minecraft.world.entity.MobSpawnType;
++import net.minecraft.world.entity.EnumMobSpawn;
+ import net.minecraft.world.entity.decoration.ArmorStand;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.item.context.BlockPlaceContext;
+@@ -22,45 +22,49 @@
+
+ public class ArmorStandItem extends Item {
+
+- public ArmorStandItem(Item.Properties item_properties) {
+- super(item_properties);
++ public ArmorStandItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Direction direction = useoncontext.getClickedFace();
++ public InteractionResult useOn(UseOnContext context) {
++ Direction enumdirection = context.getClickedFace();
+
+- if (direction == Direction.DOWN) {
++ if (enumdirection == Direction.DOWN) {
+ return InteractionResult.FAIL;
+ } else {
+- Level level = useoncontext.getLevel();
+- BlockPlaceContext blockplacecontext = new BlockPlaceContext(useoncontext);
+- BlockPos blockpos = blockplacecontext.getClickedPos();
+- ItemStack itemstack = useoncontext.getItemInHand();
+- Vec3 vec3 = Vec3.atBottomCenterOf(blockpos);
+- AABB aabb = EntityType.ARMOR_STAND.getDimensions().makeBoundingBox(vec3.x(), vec3.y(), vec3.z());
++ Level world = context.getLevel();
++ BlockPlaceContext blockactioncontext = new BlockPlaceContext(context);
++ BlockPos blockposition = blockactioncontext.getClickedPos();
++ ItemStack itemstack = context.getItemInHand();
++ Vec3 vec3d = Vec3.atBottomCenterOf(blockposition);
++ AABB axisalignedbb = EntityType.ARMOR_STAND.getDimensions().makeBoundingBox(vec3d.x(), vec3d.y(), vec3d.z());
+
+- if (level.noCollision((Entity) null, aabb) && level.getEntities((Entity) null, aabb).isEmpty()) {
+- if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) level;
+- Consumer<ArmorStand> consumer = EntityType.createDefaultStackConfig(serverlevel, itemstack, useoncontext.getPlayer());
+- ArmorStand armorstand = (ArmorStand) EntityType.ARMOR_STAND.create(serverlevel, itemstack.getTag(), consumer, blockpos, MobSpawnType.SPAWN_EGG, true, true);
++ if (world.noCollision((Entity) null, axisalignedbb) && world.getEntities((Entity) null, axisalignedbb).isEmpty()) {
++ if (world instanceof ServerLevel) {
++ ServerLevel worldserver = (ServerLevel) world;
++ Consumer<ArmorStand> consumer = EntityType.createDefaultStackConfig(worldserver, itemstack, context.getPlayer());
++ ArmorStand entityarmorstand = (ArmorStand) EntityType.ARMOR_STAND.create(worldserver, itemstack.getTag(), consumer, blockposition, EnumMobSpawn.SPAWN_EGG, true, true);
+
+- if (armorstand == null) {
++ if (entityarmorstand == null) {
+ return InteractionResult.FAIL;
+ }
+
+- float f = (float) Mth.floor((Mth.wrapDegrees(useoncontext.getRotation() - 180.0F) + 22.5F) / 45.0F) * 45.0F;
++ 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((Player) null, armorstand.getX(), armorstand.getY(), armorstand.getZ(), SoundEvents.ARMOR_STAND_PLACE, SoundSource.BLOCKS, 0.75F, 0.8F);
+- armorstand.gameEvent(GameEvent.ENTITY_PLACE, useoncontext.getPlayer());
++ 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());
+ }
+
+ itemstack.shrink(1);
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.FAIL;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/BlockItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/BlockItem.java.patch
new file mode 100644
index 0000000000..fff559072b
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/BlockItem.java.patch
@@ -0,0 +1,398 @@
+--- a/net/minecraft/world/item/BlockItem.java
++++ b/net/minecraft/world/item/BlockItem.java
+@@ -12,9 +12,9 @@
+ import net.minecraft.nbt.ListTag;
+ import net.minecraft.network.chat.Component;
+ 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.world.InteractionResult;
+ import net.minecraft.world.entity.item.ItemEntity;
+ import net.minecraft.world.entity.player.Player;
+@@ -27,11 +27,15 @@
+ import net.minecraft.world.level.block.SoundType;
+ import net.minecraft.world.level.block.entity.BlockEntity;
+ import net.minecraft.world.level.block.entity.BlockEntityType;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.StateDefinition;
+ 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 {
+
+@@ -41,164 +45,199 @@
+ @Deprecated
+ private final Block block;
+
+- public BlockItem(Block block, Item.Properties item_properties) {
+- super(item_properties);
++ public BlockItem(Block block, Item.Properties properties) {
++ super(properties);
+ this.block = block;
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- InteractionResult interactionresult = this.place(new BlockPlaceContext(useoncontext));
++ public InteractionResult useOn(UseOnContext context) {
++ InteractionResult enuminteractionresult = this.place(new BlockPlaceContext(context));
+
+- if (!interactionresult.consumesAction() && this.isEdible()) {
+- InteractionResult interactionresult1 = this.use(useoncontext.getLevel(), useoncontext.getPlayer(), useoncontext.getHand()).getResult();
++ if (!enuminteractionresult.consumesAction() && this.isEdible()) {
++ InteractionResult enuminteractionresult1 = this.use(context.getLevel(), context.getPlayer(), context.getHand()).getResult();
+
+- return interactionresult1 == InteractionResult.CONSUME ? InteractionResult.CONSUME_PARTIAL : interactionresult1;
++ return enuminteractionresult1 == InteractionResult.CONSUME ? InteractionResult.CONSUME_PARTIAL : enuminteractionresult1;
+ } else {
+- return interactionresult;
++ return enuminteractionresult;
+ }
+ }
+
+- public InteractionResult place(BlockPlaceContext blockplacecontext) {
+- if (!this.getBlock().isEnabled(blockplacecontext.getLevel().enabledFeatures())) {
++ public InteractionResult place(BlockPlaceContext context) {
++ if (!this.getBlock().isEnabled(context.getLevel().enabledFeatures())) {
+ return InteractionResult.FAIL;
+- } else if (!blockplacecontext.canPlace()) {
++ } else if (!context.canPlace()) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockPlaceContext blockplacecontext1 = this.updatePlacementContext(blockplacecontext);
++ BlockPlaceContext blockactioncontext1 = this.updatePlacementContext(context);
+
+- if (blockplacecontext1 == null) {
++ if (blockactioncontext1 == null) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockState blockstate = this.getPlacementState(blockplacecontext1);
++ 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 (blockstate == null) {
++ if (iblockdata == null) {
+ return InteractionResult.FAIL;
+- } else if (!this.placeBlock(blockplacecontext1, blockstate)) {
++ } else if (!this.placeBlock(blockactioncontext1, iblockdata)) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockPos blockpos = blockplacecontext1.getClickedPos();
+- Level level = blockplacecontext1.getLevel();
+- Player player = blockplacecontext1.getPlayer();
+- ItemStack itemstack = blockplacecontext1.getItemInHand();
+- BlockState blockstate1 = level.getBlockState(blockpos);
++ BlockPos blockposition = blockactioncontext1.getClickedPos();
++ Level world = blockactioncontext1.getLevel();
++ Player entityhuman = blockactioncontext1.getPlayer();
++ ItemStack itemstack = blockactioncontext1.getItemInHand();
++ IBlockData iblockdata1 = world.getBlockState(blockposition);
+
+- if (blockstate1.is(blockstate.getBlock())) {
+- blockstate1 = this.updateBlockStateFromTag(blockpos, level, itemstack, blockstate1);
+- this.updateCustomBlockEntityTag(blockpos, level, player, itemstack, blockstate1);
+- blockstate1.getBlock().setPlacedBy(level, blockpos, blockstate1, player, itemstack);
+- if (player instanceof ServerPlayer) {
+- CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) player, blockpos, itemstack);
++ 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 = blockstate1.getSoundType();
++ SoundType soundeffecttype = iblockdata1.getSoundType();
+
+- level.playSound(player, blockpos, this.getPlaceSound(blockstate1), SoundSource.BLOCKS, (soundtype.getVolume() + 1.0F) / 2.0F, soundtype.getPitch() * 0.8F);
+- level.gameEvent(GameEvent.BLOCK_PLACE, blockpos, GameEvent.Context.of(player, blockstate1));
+- if (player == null || !player.getAbilities().instabuild) {
++ // 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);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ }
+ }
+ }
+ }
+
+- protected SoundEvent getPlaceSound(BlockState blockstate) {
+- return blockstate.getSoundType().getPlaceSound();
++ protected SoundEvent getPlaceSound(IBlockData state) {
++ return state.getSoundType().getPlaceSound();
+ }
+
+ @Nullable
+- public BlockPlaceContext updatePlacementContext(BlockPlaceContext blockplacecontext) {
+- return blockplacecontext;
++ public BlockPlaceContext updatePlacementContext(BlockPlaceContext context) {
++ return context;
+ }
+
+- protected boolean updateCustomBlockEntityTag(BlockPos blockpos, Level level, @Nullable Player player, ItemStack itemstack, BlockState blockstate) {
+- return updateCustomBlockEntityTag(level, player, blockpos, itemstack);
++ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, IBlockData state) {
++ return updateCustomBlockEntityTag(level, player, pos, stack);
+ }
+
+ @Nullable
+- protected BlockState getPlacementState(BlockPlaceContext blockplacecontext) {
+- BlockState blockstate = this.getBlock().getStateForPlacement(blockplacecontext);
++ protected IBlockData getPlacementState(BlockPlaceContext context) {
++ IBlockData iblockdata = this.getBlock().getStateForPlacement(context);
+
+- return blockstate != null && this.canPlace(blockplacecontext, blockstate) ? blockstate : null;
++ return iblockdata != null && this.canPlace(context, iblockdata) ? iblockdata : null;
+ }
+
+- private BlockState updateBlockStateFromTag(BlockPos blockpos, Level level, ItemStack itemstack, BlockState blockstate) {
+- BlockState blockstate1 = blockstate;
+- CompoundTag compoundtag = itemstack.getTag();
++ private IBlockData updateBlockStateFromTag(BlockPos pos, Level level, ItemStack stack, IBlockData state) {
++ IBlockData iblockdata1 = state;
++ CompoundTag nbttagcompound = stack.getTag();
+
+- if (compoundtag != null) {
+- CompoundTag compoundtag1 = compoundtag.getCompound("BlockStateTag");
+- StateDefinition<Block, BlockState> statedefinition = blockstate.getBlock().getStateDefinition();
+- Iterator iterator = compoundtag1.getAllKeys().iterator();
++ if (nbttagcompound != null) {
++ CompoundTag nbttagcompound1 = nbttagcompound.getCompound("BlockStateTag");
++ // CraftBukkit start
++ iblockdata1 = getBlockState(iblockdata1, nbttagcompound1);
++ }
+
++ if (iblockdata1 != state) {
++ level.setBlock(pos, iblockdata1, 2);
++ }
++
++ return iblockdata1;
++ }
++
++ 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<?> property = statedefinition.getProperty(s);
++ Property<?> iblockstate = blockstatelist.getProperty(s);
+
+- if (property != null) {
+- String s1 = compoundtag1.get(s).getAsString();
++ if (iblockstate != null) {
++ String s1 = nbttagcompound1.get(s).getAsString();
+
+- blockstate1 = updateState(blockstate1, property, s1);
++ iblockdata1 = updateState(iblockdata1, iblockstate, s1);
+ }
+ }
+ }
+-
+- if (blockstate1 != blockstate) {
+- level.setBlock(blockpos, blockstate1, 2);
+- }
+-
+- return blockstate1;
++ return iblockdata1;
+ }
+
+- private static <T extends Comparable<T>> BlockState updateState(BlockState blockstate, Property<T> property, String s) {
+- return (BlockState) property.getValue(s).map((comparable) -> {
+- return (BlockState) blockstate.setValue(property, comparable);
+- }).orElse(blockstate);
++ private static <T extends Comparable<T>> IBlockData updateState(IBlockData state, Property<T> property, String valueIdentifier) {
++ return (IBlockData) property.getValue(valueIdentifier).map((comparable) -> {
++ return (IBlockData) state.setValue(property, comparable);
++ }).orElse(state);
+ }
+
+- protected boolean canPlace(BlockPlaceContext blockplacecontext, BlockState blockstate) {
+- Player player = blockplacecontext.getPlayer();
+- CollisionContext collisioncontext = player == null ? CollisionContext.empty() : CollisionContext.of(player);
++ 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;
+
+- return (!this.mustSurvive() || blockstate.canSurvive(blockplacecontext.getLevel(), blockplacecontext.getClickedPos())) && blockplacecontext.getLevel().isUnobstructed(blockstate, blockplacecontext.getClickedPos(), collisioncontext);
++ 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;
+ }
+
+- protected boolean placeBlock(BlockPlaceContext blockplacecontext, BlockState blockstate) {
+- return blockplacecontext.getLevel().setBlock(blockplacecontext.getClickedPos(), blockstate, 11);
++ protected boolean placeBlock(BlockPlaceContext context, IBlockData state) {
++ return context.getLevel().setBlock(context.getClickedPos(), state, 11);
+ }
+
+- public static boolean updateCustomBlockEntityTag(Level level, @Nullable Player player, BlockPos blockpos, ItemStack itemstack) {
++ public static boolean updateCustomBlockEntityTag(Level level, @Nullable Player player, BlockPos pos, ItemStack stack) {
+ MinecraftServer minecraftserver = level.getServer();
+
+ if (minecraftserver == null) {
+ return false;
+ } else {
+- CompoundTag compoundtag = getBlockEntityData(itemstack);
++ CompoundTag nbttagcompound = getBlockEntityData(stack);
+
+- if (compoundtag != null) {
+- BlockEntity blockentity = level.getBlockEntity(blockpos);
++ if (nbttagcompound != null) {
++ BlockEntity tileentity = level.getBlockEntity(pos);
+
+- if (blockentity != null) {
+- if (!level.isClientSide && blockentity.onlyOpCanSetNbt() && (player == null || !player.canUseGameMasterBlocks())) {
++ if (tileentity != null) {
++ if (!level.isClientSide && tileentity.onlyOpCanSetNbt() && (player == null || !player.canUseGameMasterBlocks())) {
+ return false;
+ }
+
+- CompoundTag compoundtag1 = blockentity.saveWithoutMetadata();
+- CompoundTag compoundtag2 = compoundtag1.copy();
++ CompoundTag nbttagcompound1 = tileentity.saveWithoutMetadata();
++ CompoundTag nbttagcompound2 = nbttagcompound1.copy();
+
+- compoundtag1.merge(compoundtag);
+- if (!compoundtag1.equals(compoundtag2)) {
+- blockentity.load(compoundtag1);
+- blockentity.setChanged();
++ nbttagcompound1.merge(nbttagcompound);
++ if (!nbttagcompound1.equals(nbttagcompound2)) {
++ tileentity.load(nbttagcompound1);
++ tileentity.setChanged();
+ return true;
+ }
+ }
+@@ -209,67 +248,62 @@
+ }
+
+ @Override
+- @Override
+ public String getDescriptionId() {
+ return this.getBlock().getDescriptionId();
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- super.appendHoverText(itemstack, level, list, tooltipflag);
+- this.getBlock().appendHoverText(itemstack, level, list, tooltipflag);
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
++ super.appendHoverText(stack, level, tooltip, flag);
++ this.getBlock().appendHoverText(stack, level, tooltip, flag);
+ }
+
+ public Block getBlock() {
+ return this.block;
+ }
+
+- public void registerBlocks(Map<Block, Item> map, Item item) {
+- map.put(this.getBlock(), item);
++ public void registerBlocks(Map<Block, Item> blockToItemMap, Item item) {
++ blockToItemMap.put(this.getBlock(), item);
+ }
+
+ @Override
+- @Override
+ public boolean canFitInsideContainerItems() {
+ return !(this.block instanceof ShulkerBoxBlock);
+ }
+
+ @Override
+- @Override
+- public void onDestroyed(ItemEntity itementity) {
++ public void onDestroyed(ItemEntity itemEntity) {
+ if (this.block instanceof ShulkerBoxBlock) {
+- ItemStack itemstack = itementity.getItem();
+- CompoundTag compoundtag = getBlockEntityData(itemstack);
++ ItemStack itemstack = itemEntity.getItem();
++ CompoundTag nbttagcompound = getBlockEntityData(itemstack);
+
+- if (compoundtag != null && compoundtag.contains("Items", 9)) {
+- ListTag listtag = compoundtag.getList("Items", 10);
+- Stream stream = listtag.stream();
++ if (nbttagcompound != null && nbttagcompound.contains("Items", 9)) {
++ ListTag nbttaglist = nbttagcompound.getList("Items", 10);
++ Stream<net.minecraft.nbt.Tag> stream = nbttaglist.stream(); // CraftBukkit - decompile error
+
+ Objects.requireNonNull(CompoundTag.class);
+- ItemUtils.onContainerDestroyed(itementity, stream.map(CompoundTag.class::cast).map(ItemStack::of));
++ ItemUtils.onContainerDestroyed(itemEntity, stream.map(CompoundTag.class::cast).map(ItemStack::of));
+ }
+ }
+
+ }
+
+ @Nullable
+- public static CompoundTag getBlockEntityData(ItemStack itemstack) {
+- return itemstack.getTagElement("BlockEntityTag");
++ public static CompoundTag getBlockEntityData(ItemStack stack) {
++ return stack.getTagElement("BlockEntityTag");
+ }
+
+- public static void setBlockEntityData(ItemStack itemstack, BlockEntityType<?> blockentitytype, CompoundTag compoundtag) {
+- if (compoundtag.isEmpty()) {
+- itemstack.removeTagKey("BlockEntityTag");
++ public static void setBlockEntityData(ItemStack stack, BlockEntityType<?> blockEntityType, CompoundTag blockEntityData) {
++ if (blockEntityData.isEmpty()) {
++ stack.removeTagKey("BlockEntityTag");
+ } else {
+- BlockEntity.addEntityType(compoundtag, blockentitytype);
+- itemstack.addTagElement("BlockEntityTag", compoundtag);
++ BlockEntity.addEntityType(blockEntityData, blockEntityType);
++ stack.addTagElement("BlockEntityTag", blockEntityData);
+ }
+
+ }
+
+ @Override
+- @Override
+ public FeatureFlagSet requiredFeatures() {
+ return this.getBlock().requiredFeatures();
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/BoatItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/BoatItem.java.patch
new file mode 100644
index 0000000000..e85cb14fde
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/BoatItem.java.patch
@@ -0,0 +1,118 @@
+--- a/net/minecraft/world/item/BoatItem.java
++++ b/net/minecraft/world/item/BoatItem.java
+@@ -5,7 +5,7 @@
+ import java.util.function.Predicate;
+ import net.minecraft.server.level.ServerLevel;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntitySelector;
+@@ -27,50 +27,64 @@
+ private final Boat.Type type;
+ private final boolean hasChest;
+
+- public BoatItem(boolean flag, Boat.Type boat_type, Item.Properties item_properties) {
+- super(item_properties);
+- this.hasChest = flag;
+- this.type = boat_type;
++ public BoatItem(boolean hasChest, Boat.Type type, Item.Properties properties) {
++ super(properties);
++ this.hasChest = hasChest;
++ this.type = type;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
+- BlockHitResult blockhitresult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++ BlockHitResult movingobjectpositionblock = getPlayerPOVHitResult(level, player, ClipContext.Fluid.ANY);
+
+- if (blockhitresult.getType() == HitResult.Type.MISS) {
++ if (movingobjectpositionblock.getType() == HitResult.EnumMovingObjectType.MISS) {
+ return InteractionResultHolder.pass(itemstack);
+ } else {
+- Vec3 vec3 = player.getViewVector(1.0F);
++ Vec3 vec3d = player.getViewVector(1.0F);
+ double d0 = 5.0D;
+- List<Entity> list = level.getEntities((Entity) player, player.getBoundingBox().expandTowards(vec3.scale(5.0D)).inflate(1.0D), BoatItem.ENTITY_PREDICATE);
++ List<Entity> list = level.getEntities((Entity) player, player.getBoundingBox().expandTowards(vec3d.scale(5.0D)).inflate(1.0D), BoatItem.ENTITY_PREDICATE);
+
+ if (!list.isEmpty()) {
+- Vec3 vec31 = player.getEyePosition();
++ Vec3 vec3d1 = player.getEyePosition();
+ Iterator iterator = list.iterator();
+
+ while (iterator.hasNext()) {
+ Entity entity = (Entity) iterator.next();
+- AABB aabb = entity.getBoundingBox().inflate((double) entity.getPickRadius());
++ AABB axisalignedbb = entity.getBoundingBox().inflate((double) entity.getPickRadius());
+
+- if (aabb.contains(vec31)) {
++ if (axisalignedbb.contains(vec3d1)) {
+ return InteractionResultHolder.pass(itemstack);
+ }
+ }
+ }
+
+- if (blockhitresult.getType() == HitResult.Type.BLOCK) {
+- Boat boat = this.getBoat(level, blockhitresult, itemstack, player);
++ 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());
+
+- boat.setVariant(this.type);
+- boat.setYRot(player.getYRot());
+- if (!level.noCollision(boat, boat.getBoundingBox())) {
++ 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((Entity) player, GameEvent.ENTITY_PLACE, blockhitresult.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) {
+ itemstack.shrink(1);
+ }
+@@ -85,14 +99,14 @@
+ }
+ }
+
+- private Boat getBoat(Level level, HitResult hitresult, ItemStack itemstack, Player player) {
+- Vec3 vec3 = hitresult.getLocation();
+- Object object = this.hasChest ? new ChestBoat(level, vec3.x, vec3.y, vec3.z) : new Boat(level, vec3.x, vec3.y, vec3.z);
++ private Boat getBoat(Level world, HitResult movingobjectposition, ItemStack itemstack, Player entityhuman) {
++ Vec3 vec3d = movingobjectposition.getLocation();
++ Boat object = this.hasChest ? new ChestBoat(world, vec3d.x, vec3d.y, vec3d.z) : new Boat(world, vec3d.x, vec3d.y, vec3d.z); // CraftBukkit - decompile error
+
+- if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) level;
++ if (world instanceof ServerLevel) {
++ ServerLevel worldserver = (ServerLevel) world;
+
+- EntityType.createDefaultStackConfig(serverlevel, itemstack, player).accept(object);
++ EntityType.createDefaultStackConfig(worldserver, itemstack, entityhuman).accept(object);
+ }
+
+ return (Boat) object;
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/BoneMealItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/BoneMealItem.java.patch
new file mode 100644
index 0000000000..850ee9f189
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/BoneMealItem.java.patch
@@ -0,0 +1,260 @@
+--- a/net/minecraft/world/item/BoneMealItem.java
++++ b/net/minecraft/world/item/BoneMealItem.java
+@@ -19,7 +19,7 @@
+ import net.minecraft.world.level.block.Block;
+ import net.minecraft.world.level.block.Blocks;
+ import net.minecraft.world.level.block.BonemealableBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+ public class BoneMealItem extends Item {
+@@ -28,55 +28,60 @@
+ public static final int GRASS_SPREAD_HEIGHT = 1;
+ public static final int GRASS_COUNT_MULTIPLIER = 3;
+
+- public BoneMealItem(Item.Properties item_properties) {
+- super(item_properties);
++ public BoneMealItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockPos blockpos1 = blockpos.relative(useoncontext.getClickedFace());
++ public InteractionResult useOn(UseOnContext context) {
++ // CraftBukkit start - extract bonemeal application logic to separate, static method
++ return applyBonemeal(context);
++ }
+
+- if (growCrop(useoncontext.getItemInHand(), level, blockpos)) {
+- if (!level.isClientSide) {
+- useoncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+- level.levelEvent(1505, blockpos, 0);
++ 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);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+- BlockState blockstate = level.getBlockState(blockpos);
+- boolean flag = blockstate.isFaceSturdy(level, blockpos, useoncontext.getClickedFace());
++ IBlockData iblockdata = world.getBlockState(blockposition);
++ boolean flag = iblockdata.isFaceSturdy(world, blockposition, itemactioncontext.getClickedFace());
+
+- if (flag && growWaterPlant(useoncontext.getItemInHand(), level, blockpos1, useoncontext.getClickedFace())) {
+- if (!level.isClientSide) {
+- useoncontext.getPlayer().gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+- level.levelEvent(1505, blockpos1, 0);
++ 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);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.PASS;
+ }
+ }
+ }
+
+- public static boolean growCrop(ItemStack itemstack, Level level, BlockPos blockpos) {
+- BlockState blockstate = level.getBlockState(blockpos);
+- Block block = blockstate.getBlock();
++ public static boolean growCrop(ItemStack stack, Level level, BlockPos pos) {
++ IBlockData iblockdata = level.getBlockState(pos);
++ Block block = iblockdata.getBlock();
+
+ if (block instanceof BonemealableBlock) {
+- BonemealableBlock bonemealableblock = (BonemealableBlock) block;
++ BonemealableBlock iblockfragileplantelement = (BonemealableBlock) block;
+
+- if (bonemealableblock.isValidBonemealTarget(level, blockpos, blockstate)) {
++ if (iblockfragileplantelement.isValidBonemealTarget(level, pos, iblockdata)) {
+ if (level instanceof ServerLevel) {
+- if (bonemealableblock.isBonemealSuccess(level, level.random, blockpos, blockstate)) {
+- bonemealableblock.performBonemeal((ServerLevel) level, level.random, blockpos, blockstate);
++ if (iblockfragileplantelement.isBonemealSuccess(level, level.random, pos, iblockdata)) {
++ iblockfragileplantelement.performBonemeal((ServerLevel) level, level.random, pos, iblockdata);
+ }
+
+- itemstack.shrink(1);
++ stack.shrink(1);
+ }
+
+ return true;
+@@ -86,8 +91,8 @@
+ return false;
+ }
+
+- public static boolean growWaterPlant(ItemStack itemstack, Level level, BlockPos blockpos, @Nullable Direction direction) {
+- if (level.getBlockState(blockpos).is(Blocks.WATER) && level.getFluidState(blockpos).getAmount() == 8) {
++ public static boolean growWaterPlant(ItemStack stack, Level level, BlockPos pos, @Nullable Direction clickedSide) {
++ if (level.getBlockState(pos).is(Blocks.WATER) && level.getFluidState(pos).getAmount() == 8) {
+ if (!(level instanceof ServerLevel)) {
+ return true;
+ } else {
+@@ -95,54 +100,54 @@
+ int i = 0;
+
+ while (i < 128) {
+- BlockPos blockpos1 = blockpos;
+- BlockState blockstate = Blocks.SEAGRASS.defaultBlockState();
++ BlockPos blockposition1 = pos;
++ IBlockData iblockdata = Blocks.SEAGRASS.defaultBlockState();
+ int j = 0;
+
+ while (true) {
+ if (j < i / 16) {
+- blockpos1 = blockpos1.offset(randomsource.nextInt(3) - 1, (randomsource.nextInt(3) - 1) * randomsource.nextInt(3) / 2, randomsource.nextInt(3) - 1);
+- if (!level.getBlockState(blockpos1).isCollisionShapeFullBlock(level, blockpos1)) {
++ blockposition1 = blockposition1.offset(randomsource.nextInt(3) - 1, (randomsource.nextInt(3) - 1) * randomsource.nextInt(3) / 2, randomsource.nextInt(3) - 1);
++ if (!level.getBlockState(blockposition1).isCollisionShapeFullBlock(level, blockposition1)) {
+ ++j;
+ continue;
+ }
+ } else {
+- Holder<Biome> holder = level.getBiome(blockpos1);
++ Holder<Biome> holder = level.getBiome(blockposition1);
+
+ if (holder.is(BiomeTags.PRODUCES_CORALS_FROM_BONEMEAL)) {
+- if (i == 0 && direction != null && direction.getAxis().isHorizontal()) {
+- blockstate = (BlockState) BuiltInRegistries.BLOCK.getTag(BlockTags.WALL_CORALS).flatMap((holderset_named) -> {
++ if (i == 0 && clickedSide != null && clickedSide.getAxis().isHorizontal()) {
++ iblockdata = (IBlockData) BuiltInRegistries.BLOCK.getTag(BlockTags.WALL_CORALS).flatMap((holderset_named) -> {
+ return holderset_named.getRandomElement(level.random);
+ }).map((holder1) -> {
+ return ((Block) holder1.value()).defaultBlockState();
+- }).orElse(blockstate);
+- if (blockstate.hasProperty(BaseCoralWallFanBlock.FACING)) {
+- blockstate = (BlockState) blockstate.setValue(BaseCoralWallFanBlock.FACING, direction);
++ }).orElse(iblockdata);
++ if (iblockdata.hasProperty(BaseCoralWallFanBlock.FACING)) {
++ iblockdata = (IBlockData) iblockdata.setValue(BaseCoralWallFanBlock.FACING, clickedSide);
+ }
+ } else if (randomsource.nextInt(4) == 0) {
+- blockstate = (BlockState) BuiltInRegistries.BLOCK.getTag(BlockTags.UNDERWATER_BONEMEALS).flatMap((holderset_named) -> {
++ iblockdata = (IBlockData) BuiltInRegistries.BLOCK.getTag(BlockTags.UNDERWATER_BONEMEALS).flatMap((holderset_named) -> {
+ return holderset_named.getRandomElement(level.random);
+ }).map((holder1) -> {
+ return ((Block) holder1.value()).defaultBlockState();
+- }).orElse(blockstate);
++ }).orElse(iblockdata);
+ }
+ }
+
+- if (blockstate.is(BlockTags.WALL_CORALS, (blockbehaviour_blockstatebase) -> {
+- return blockbehaviour_blockstatebase.hasProperty(BaseCoralWallFanBlock.FACING);
++ if (iblockdata.is(BlockTags.WALL_CORALS, (blockbase_blockdata) -> {
++ return blockbase_blockdata.hasProperty(BaseCoralWallFanBlock.FACING);
+ })) {
+- for (int k = 0; !blockstate.canSurvive(level, blockpos1) && k < 4; ++k) {
+- blockstate = (BlockState) blockstate.setValue(BaseCoralWallFanBlock.FACING, Direction.Plane.HORIZONTAL.getRandomDirection(randomsource));
++ for (int k = 0; !iblockdata.canSurvive(level, blockposition1) && k < 4; ++k) {
++ iblockdata = (IBlockData) iblockdata.setValue(BaseCoralWallFanBlock.FACING, Direction.Plane.HORIZONTAL.getRandomDirection(randomsource));
+ }
+ }
+
+- if (blockstate.canSurvive(level, blockpos1)) {
+- BlockState blockstate1 = level.getBlockState(blockpos1);
++ if (iblockdata.canSurvive(level, blockposition1)) {
++ IBlockData iblockdata1 = level.getBlockState(blockposition1);
+
+- if (blockstate1.is(Blocks.WATER) && level.getFluidState(blockpos1).getAmount() == 8) {
+- level.setBlock(blockpos1, blockstate, 3);
+- } else if (blockstate1.is(Blocks.SEAGRASS) && randomsource.nextInt(10) == 0) {
+- ((BonemealableBlock) Blocks.SEAGRASS).performBonemeal((ServerLevel) level, randomsource, blockpos1, blockstate1);
++ if (iblockdata1.is(Blocks.WATER) && level.getFluidState(blockposition1).getAmount() == 8) {
++ level.setBlock(blockposition1, iblockdata, 3);
++ } else if (iblockdata1.is(Blocks.SEAGRASS) && randomsource.nextInt(10) == 0) {
++ ((BonemealableBlock) Blocks.SEAGRASS).performBonemeal((ServerLevel) level, randomsource, blockposition1, iblockdata1);
+ }
+ }
+ }
+@@ -152,7 +157,7 @@
+ }
+ }
+
+- itemstack.shrink(1);
++ stack.shrink(1);
+ return true;
+ }
+ } else {
+@@ -160,44 +165,44 @@
+ }
+ }
+
+- public static void addGrowthParticles(LevelAccessor levelaccessor, BlockPos blockpos, int i) {
+- if (i == 0) {
+- i = 15;
++ public static void addGrowthParticles(LevelAccessor level, BlockPos pos, int data) {
++ if (data == 0) {
++ data = 15;
+ }
+
+- BlockState blockstate = levelaccessor.getBlockState(blockpos);
++ IBlockData iblockdata = level.getBlockState(pos);
+
+- if (!blockstate.isAir()) {
++ if (!iblockdata.isAir()) {
+ double d0 = 0.5D;
+ double d1;
+
+- if (blockstate.is(Blocks.WATER)) {
+- i *= 3;
++ if (iblockdata.is(Blocks.WATER)) {
++ data *= 3;
+ d1 = 1.0D;
+ d0 = 3.0D;
+- } else if (blockstate.isSolidRender(levelaccessor, blockpos)) {
+- blockpos = blockpos.above();
+- i *= 3;
++ } else if (iblockdata.isSolidRender(level, pos)) {
++ pos = pos.above();
++ data *= 3;
+ d0 = 3.0D;
+ d1 = 1.0D;
+ } else {
+- d1 = blockstate.getShape(levelaccessor, blockpos).max(Direction.Axis.Y);
++ d1 = iblockdata.getShape(level, pos).max(Direction.Axis.Y);
+ }
+
+- levelaccessor.addParticle(ParticleTypes.HAPPY_VILLAGER, (double) blockpos.getX() + 0.5D, (double) blockpos.getY() + 0.5D, (double) blockpos.getZ() + 0.5D, 0.0D, 0.0D, 0.0D);
+- RandomSource randomsource = levelaccessor.getRandom();
++ level.addParticle(ParticleTypes.HAPPY_VILLAGER, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 0.0D, 0.0D, 0.0D);
++ RandomSource randomsource = level.getRandom();
+
+- for (int j = 0; j < i; ++j) {
++ for (int j = 0; j < data; ++j) {
+ double d2 = randomsource.nextGaussian() * 0.02D;
+ double d3 = randomsource.nextGaussian() * 0.02D;
+ double d4 = randomsource.nextGaussian() * 0.02D;
+ double d5 = 0.5D - d0;
+- double d6 = (double) blockpos.getX() + d5 + randomsource.nextDouble() * d0 * 2.0D;
+- double d7 = (double) blockpos.getY() + randomsource.nextDouble() * d1;
+- double d8 = (double) blockpos.getZ() + d5 + randomsource.nextDouble() * d0 * 2.0D;
++ double d6 = (double) pos.getX() + d5 + randomsource.nextDouble() * d0 * 2.0D;
++ double d7 = (double) pos.getY() + randomsource.nextDouble() * d1;
++ double d8 = (double) pos.getZ() + d5 + randomsource.nextDouble() * d0 * 2.0D;
+
+- if (!levelaccessor.getBlockState(BlockPos.containing(d6, d7, d8).below()).isAir()) {
+- levelaccessor.addParticle(ParticleTypes.HAPPY_VILLAGER, d6, d7, d8, d2, d3, d4);
++ if (!level.getBlockState(BlockPos.containing(d6, d7, d8).below()).isAir()) {
++ level.addParticle(ParticleTypes.HAPPY_VILLAGER, d6, d7, d8, d2, d3, d4);
+ }
+ }
+
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/BowItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/BowItem.java.patch
new file mode 100644
index 0000000000..5b28a72dac
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/BowItem.java.patch
@@ -0,0 +1,190 @@
+--- a/net/minecraft/world/item/BowItem.java
++++ b/net/minecraft/world/item/BowItem.java
+@@ -4,7 +4,7 @@
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.LivingEntity;
+ import net.minecraft.world.entity.player.Player;
+@@ -13,85 +13,101 @@
+ import net.minecraft.world.item.enchantment.Enchantments;
+ import net.minecraft.world.level.Level;
+
+-public class BowItem extends ProjectileWeaponItem implements Vanishable {
++public class BowItem extends ProjectileWeaponItem implements ItemVanishable {
+
+ public static final int MAX_DRAW_DURATION = 20;
+ public static final int DEFAULT_RANGE = 15;
+
+- public BowItem(Item.Properties item_properties) {
+- super(item_properties);
++ public BowItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public void releaseUsing(ItemStack itemstack, Level level, LivingEntity livingentity, int i) {
+- if (livingentity instanceof Player) {
+- Player player = (Player) livingentity;
+- boolean flag = player.getAbilities().instabuild || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, itemstack) > 0;
+- ItemStack itemstack1 = player.getProjectile(itemstack);
++ public void releaseUsing(ItemStack stack, Level level, LivingEntity entityLiving, int timeLeft) {
++ if (entityLiving instanceof Player) {
++ Player entityhuman = (Player) entityLiving;
++ boolean flag = entityhuman.getAbilities().instabuild || EnchantmentHelper.getItemEnchantmentLevel(Enchantments.INFINITY_ARROWS, stack) > 0;
++ ItemStack itemstack1 = entityhuman.getProjectile(stack);
+
+ if (!itemstack1.isEmpty() || flag) {
+ if (itemstack1.isEmpty()) {
+ itemstack1 = new ItemStack(Items.ARROW);
+ }
+
+- int j = this.getUseDuration(itemstack) - i;
++ int j = this.getUseDuration(stack) - timeLeft;
+ float f = getPowerForTime(j);
+
+ if ((double) f >= 0.1D) {
+ boolean flag1 = flag && itemstack1.is(Items.ARROW);
+
+ if (!level.isClientSide) {
+- ArrowItem arrowitem = (ArrowItem) (itemstack1.getItem() instanceof ArrowItem ? itemstack1.getItem() : Items.ARROW);
+- AbstractArrow abstractarrow = arrowitem.createArrow(level, itemstack1, player);
++ ArrowItem itemarrow = (ArrowItem) (itemstack1.getItem() instanceof ArrowItem ? itemstack1.getItem() : Items.ARROW);
++ AbstractArrow entityarrow = itemarrow.createArrow(level, itemstack1, entityhuman);
+
+- abstractarrow.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, f * 3.0F, 1.0F);
++ entityarrow.shootFromRotation(entityhuman, entityhuman.getXRot(), entityhuman.getYRot(), 0.0F, f * 3.0F, 1.0F);
+ if (f == 1.0F) {
+- abstractarrow.setCritArrow(true);
++ entityarrow.setCritArrow(true);
+ }
+
+- int k = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.POWER_ARROWS, itemstack);
++ int k = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.POWER_ARROWS, stack);
+
+ if (k > 0) {
+- abstractarrow.setBaseDamage(abstractarrow.getBaseDamage() + (double) k * 0.5D + 0.5D);
++ entityarrow.setBaseDamage(entityarrow.getBaseDamage() + (double) k * 0.5D + 0.5D);
+ }
+
+- int l = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.PUNCH_ARROWS, itemstack);
++ int l = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.PUNCH_ARROWS, stack);
+
+ if (l > 0) {
+- abstractarrow.setKnockback(l);
++ entityarrow.setKnockback(l);
+ }
+
+- if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.FLAMING_ARROWS, itemstack) > 0) {
+- abstractarrow.setSecondsOnFire(100);
++ if (EnchantmentHelper.getItemEnchantmentLevel(Enchantments.FLAMING_ARROWS, stack) > 0) {
++ entityarrow.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
+
+- itemstack.hurtAndBreak(1, player, (player1) -> {
+- player1.broadcastBreakEvent(player.getUsedItemHand());
++ stack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(entityhuman.getUsedItemHand());
+ });
+- if (flag1 || player.getAbilities().instabuild && (itemstack1.is(Items.SPECTRAL_ARROW) || itemstack1.is(Items.TIPPED_ARROW))) {
+- abstractarrow.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
++ if (flag1 || entityhuman.getAbilities().instabuild && (itemstack1.is(Items.SPECTRAL_ARROW) || itemstack1.is(Items.TIPPED_ARROW))) {
++ entityarrow.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((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.ARROW_SHOOT, SoundSource.PLAYERS, 1.0F, 1.0F / (level.getRandom().nextFloat() * 0.4F + 1.2F) + f * 0.5F);
+- if (!flag1 && !player.getAbilities().instabuild) {
++ level.playSound((Player) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEvents.ARROW_SHOOT, SoundSource.PLAYERS, 1.0F, 1.0F / (level.getRandom().nextFloat() * 0.4F + 1.2F) + f * 0.5F);
++ if (!flag1 && !entityhuman.getAbilities().instabuild) {
+ itemstack1.shrink(1);
+ if (itemstack1.isEmpty()) {
+- player.getInventory().removeItem(itemstack1);
++ entityhuman.getInventory().removeItem(itemstack1);
+ }
+ }
+
+- player.awardStat(Stats.ITEM_USED.get(this));
++ entityhuman.awardStat(Stats.ITEM_USED.get(this));
+ }
+ }
+ }
+ }
+
+- public static float getPowerForTime(int i) {
+- float f = (float) i / 20.0F;
++ public static float getPowerForTime(int charge) {
++ float f = (float) charge / 20.0F;
+
+ f = (f * f + f * 2.0F) / 3.0F;
+ if (f > 1.0F) {
+@@ -102,39 +118,34 @@
+ }
+
+ @Override
+- @Override
+- public int getUseDuration(ItemStack itemstack) {
++ public int getUseDuration(ItemStack stack) {
+ return 72000;
+ }
+
+ @Override
+- @Override
+- public UseAnim getUseAnimation(ItemStack itemstack) {
+- return UseAnim.BOW;
++ public EnumAnimation getUseAnimation(ItemStack stack) {
++ return EnumAnimation.BOW;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+ boolean flag = !player.getProjectile(itemstack).isEmpty();
+
+ if (!player.getAbilities().instabuild && !flag) {
+ return InteractionResultHolder.fail(itemstack);
+ } else {
+- player.startUsingItem(interactionhand);
++ player.startUsingItem(hand);
+ return InteractionResultHolder.consume(itemstack);
+ }
+ }
+
+ @Override
+- @Override
+ public Predicate<ItemStack> getAllSupportedProjectiles() {
+ return BowItem.ARROW_ONLY;
+ }
+
+ @Override
+- @Override
+ public int getDefaultProjectileRange() {
+ return 15;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/BucketItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/BucketItem.java.patch
new file mode 100644
index 0000000000..59d28174e7
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/BucketItem.java.patch
@@ -0,0 +1,275 @@
+--- a/net/minecraft/world/item/BucketItem.java
++++ b/net/minecraft/world/item/BucketItem.java
+@@ -5,13 +5,15 @@
+ import net.minecraft.core.BlockPos;
+ import net.minecraft.core.Direction;
+ import net.minecraft.core.particles.ParticleTypes;
++import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
++import net.minecraft.server.level.ServerLevel;
+ import net.minecraft.server.level.ServerPlayer;
+ import net.minecraft.sounds.SoundEvent;
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+ import net.minecraft.tags.FluidTags;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.player.Player;
+@@ -21,56 +23,72 @@
+ import net.minecraft.world.level.block.Block;
+ import net.minecraft.world.level.block.BucketPickup;
+ import net.minecraft.world.level.block.LiquidBlockContainer;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.level.material.FlowingFluid;
+ import net.minecraft.world.level.material.Fluid;
+ 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;
++ public final Fluid content;
+
+- public BucketItem(Fluid fluid, Item.Properties item_properties) {
+- super(item_properties);
+- this.content = fluid;
++ public BucketItem(Fluid content, Item.Properties properties) {
++ super(properties);
++ this.content = content;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
+- BlockHitResult blockhitresult = getPlayerPOVHitResult(level, player, this.content == Fluids.EMPTY ? ClipContext.Fluid.SOURCE_ONLY : ClipContext.Fluid.NONE);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++ BlockHitResult movingobjectpositionblock = getPlayerPOVHitResult(level, player, this.content == Fluids.EMPTY ? ClipContext.Fluid.SOURCE_ONLY : ClipContext.Fluid.NONE);
+
+- if (blockhitresult.getType() == HitResult.Type.MISS) {
++ if (movingobjectpositionblock.getType() == HitResult.EnumMovingObjectType.MISS) {
+ return InteractionResultHolder.pass(itemstack);
+- } else if (blockhitresult.getType() != HitResult.Type.BLOCK) {
++ } else if (movingobjectpositionblock.getType() != HitResult.EnumMovingObjectType.BLOCK) {
+ return InteractionResultHolder.pass(itemstack);
+ } else {
+- BlockPos blockpos = blockhitresult.getBlockPos();
+- Direction direction = blockhitresult.getDirection();
+- BlockPos blockpos1 = blockpos.relative(direction);
++ BlockPos blockposition = movingobjectpositionblock.getBlockPos();
++ Direction enumdirection = movingobjectpositionblock.getDirection();
++ BlockPos blockposition1 = blockposition.relative(enumdirection);
+
+- if (level.mayInteract(player, blockpos) && player.mayUseItemAt(blockpos1, direction, itemstack)) {
+- BlockState blockstate;
++ if (level.mayInteract(player, blockposition) && player.mayUseItemAt(blockposition1, enumdirection, itemstack)) {
++ IBlockData iblockdata;
+
+ if (this.content == Fluids.EMPTY) {
+- blockstate = level.getBlockState(blockpos);
+- Block block = blockstate.getBlock();
++ iblockdata = level.getBlockState(blockposition);
++ Block block = iblockdata.getBlock();
+
+ if (block instanceof BucketPickup) {
+- BucketPickup bucketpickup = (BucketPickup) block;
+- ItemStack itemstack1 = bucketpickup.pickupBlock(player, level, blockpos, blockstate);
++ 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);
++
+ if (!itemstack1.isEmpty()) {
+ player.awardStat(Stats.ITEM_USED.get(this));
+- bucketpickup.getPickupSound().ifPresent((soundevent) -> {
+- player.playSound(soundevent, 1.0F, 1.0F);
++ ifluidsource.getPickupSound().ifPresent((soundeffect) -> {
++ player.playSound(soundeffect, 1.0F, 1.0F);
+ });
+- level.gameEvent((Entity) player, GameEvent.FLUID_PICKUP, blockpos);
+- ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, player, itemstack1);
++ level.gameEvent((Entity) player, GameEvent.FLUID_PICKUP, blockposition);
++ ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, player, CraftItemStack.asNMSCopy(event.getItemStack())); // CraftBukkit
+
+ if (!level.isClientSide) {
+ CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer) player, itemstack1);
+@@ -82,13 +100,13 @@
+
+ return InteractionResultHolder.fail(itemstack);
+ } else {
+- blockstate = level.getBlockState(blockpos);
+- BlockPos blockpos2 = blockstate.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? blockpos : blockpos1;
++ iblockdata = level.getBlockState(blockposition);
++ BlockPos blockposition2 = iblockdata.getBlock() instanceof LiquidBlockContainer && this.content == Fluids.WATER ? blockposition : blockposition1;
+
+- if (this.emptyContents(player, level, blockpos2, blockhitresult)) {
+- this.checkExtraContent(player, level, itemstack, blockpos2);
++ 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, blockpos2, itemstack);
++ CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) player, blockposition2, itemstack);
+ }
+
+ player.awardStat(Stats.ITEM_USED.get(this));
+@@ -103,40 +121,44 @@
+ }
+ }
+
+- public static ItemStack getEmptySuccessItem(ItemStack itemstack, Player player) {
+- return !player.getAbilities().instabuild ? new ItemStack(Items.BUCKET) : itemstack;
++ public static ItemStack getEmptySuccessItem(ItemStack bucketStack, Player player) {
++ return !player.getAbilities().instabuild ? new ItemStack(Items.BUCKET) : bucketStack;
+ }
+
+ @Override
+- @Override
+- public void checkExtraContent(@Nullable Player player, Level level, ItemStack itemstack, BlockPos blockpos) {}
++ public void checkExtraContent(@Nullable Player player, Level level, ItemStack containerStack, BlockPos pos) {}
+
+ @Override
+- @Override
+- public boolean emptyContents(@Nullable Player player, Level level, BlockPos blockpos, @Nullable BlockHitResult blockhitresult) {
+- Fluid fluid = this.content;
++ public boolean emptyContents(@Nullable Player player, Level level, BlockPos pos, @Nullable BlockHitResult result) {
++ // CraftBukkit start
++ return emptyContents(player, level, pos, result, null, null, null, EnumHand.MAIN_HAND);
++ }
+
+- if (!(fluid instanceof FlowingFluid)) {
++ 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 {
+- FlowingFluid flowingfluid;
+- BlockState blockstate;
++ FlowingFluid fluidtypeflowing;
++ IBlockData iblockdata;
+ Block block;
+ boolean flag;
+- LiquidBlockContainer liquidblockcontainer;
++ LiquidBlockContainer ifluidcontainer;
+ boolean flag1;
+ label70:
+ {
+- flowingfluid = (FlowingFluid) fluid;
+- blockstate = level.getBlockState(blockpos);
+- block = blockstate.getBlock();
+- flag = blockstate.canBeReplaced(this.content);
+- if (!blockstate.isAir() && !flag) {
++ fluidtypeflowing = (FlowingFluid) fluidtype;
++ iblockdata = world.getBlockState(blockposition);
++ block = iblockdata.getBlock();
++ flag = iblockdata.canBeReplaced(this.content);
++ if (!iblockdata.isAir() && !flag) {
+ label67:
+ {
+ if (block instanceof LiquidBlockContainer) {
+- liquidblockcontainer = (LiquidBlockContainer) block;
+- if (liquidblockcontainer.canPlaceLiquid(player, level, blockpos, blockstate, this.content)) {
++ ifluidcontainer = (LiquidBlockContainer) block;
++ if (ifluidcontainer.canPlaceLiquid(entityhuman, world, blockposition, iblockdata, this.content)) {
+ break label67;
+ }
+ }
+@@ -151,48 +173,58 @@
+
+ boolean flag2 = flag1;
+
++ // 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 blockhitresult != null && this.emptyContents(player, level, blockhitresult.getBlockPos().relative(blockhitresult.getDirection()), (BlockHitResult) null);
+- } else if (level.dimensionType().ultraWarm() && this.content.is(FluidTags.WATER)) {
+- int i = blockpos.getX();
+- int j = blockpos.getY();
+- int k = blockpos.getZ();
++ 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();
+
+- level.playSound(player, blockpos, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (level.random.nextFloat() - level.random.nextFloat()) * 0.8F);
++ world.playSound(entityhuman, blockposition, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (world.random.nextFloat() - world.random.nextFloat()) * 0.8F);
+
+ for (int l = 0; l < 8; ++l) {
+- level.addParticle(ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
++ world.addParticle(ParticleTypes.LARGE_SMOKE, (double) i + Math.random(), (double) j + Math.random(), (double) k + Math.random(), 0.0D, 0.0D, 0.0D);
+ }
+
+ return true;
+ } else {
+ if (block instanceof LiquidBlockContainer) {
+- liquidblockcontainer = (LiquidBlockContainer) block;
++ ifluidcontainer = (LiquidBlockContainer) block;
+ if (this.content == Fluids.WATER) {
+- liquidblockcontainer.placeLiquid(level, blockpos, blockstate, flowingfluid.getSource(false));
+- this.playEmptySound(player, level, blockpos);
++ ifluidcontainer.placeLiquid(world, blockposition, iblockdata, fluidtypeflowing.getSource(false));
++ this.playEmptySound(entityhuman, world, blockposition);
+ return true;
+ }
+ }
+
+- if (!level.isClientSide && flag && !blockstate.liquid()) {
+- level.destroyBlock(blockpos, true);
++ if (!world.isClientSide && flag && !iblockdata.liquid()) {
++ world.destroyBlock(blockposition, true);
+ }
+
+- if (!level.setBlock(blockpos, this.content.defaultFluidState().createLegacyBlock(), 11) && !blockstate.getFluidState().isSource()) {
++ if (!world.setBlock(blockposition, this.content.defaultFluidState().createLegacyBlock(), 11) && !iblockdata.getFluidState().isSource()) {
+ return false;
+ } else {
+- this.playEmptySound(player, level, blockpos);
++ this.playEmptySound(entityhuman, world, blockposition);
+ return true;
+ }
+ }
+ }
+ }
+
+- protected void playEmptySound(@Nullable Player player, LevelAccessor levelaccessor, BlockPos blockpos) {
+- SoundEvent soundevent = this.content.is(FluidTags.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA : SoundEvents.BUCKET_EMPTY;
++ protected void playEmptySound(@Nullable Player player, LevelAccessor level, BlockPos pos) {
++ SoundEvent soundeffect = this.content.is(FluidTags.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA : SoundEvents.BUCKET_EMPTY;
+
+- levelaccessor.playSound(player, blockpos, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F);
+- levelaccessor.gameEvent((Entity) player, GameEvent.FLUID_PLACE, blockpos);
++ level.playSound(player, pos, soundeffect, SoundSource.BLOCKS, 1.0F, 1.0F);
++ level.gameEvent((Entity) player, GameEvent.FLUID_PLACE, pos);
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/ChorusFruitItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/ChorusFruitItem.java.patch
new file mode 100644
index 0000000000..8a0e2affae
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/ChorusFruitItem.java.patch
@@ -0,0 +1,86 @@
+--- a/net/minecraft/world/item/ChorusFruitItem.java
++++ b/net/minecraft/world/item/ChorusFruitItem.java
+@@ -15,50 +15,58 @@
+
+ public class ChorusFruitItem extends Item {
+
+- public ChorusFruitItem(Item.Properties item_properties) {
+- super(item_properties);
++ public ChorusFruitItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public ItemStack finishUsingItem(ItemStack itemstack, Level level, LivingEntity livingentity) {
+- ItemStack itemstack1 = super.finishUsingItem(itemstack, level, livingentity);
++ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entityLiving) {
++ ItemStack itemstack1 = super.finishUsingItem(stack, level, entityLiving);
+
+ if (!level.isClientSide) {
+ for (int i = 0; i < 16; ++i) {
+- double d0 = livingentity.getX() + (livingentity.getRandom().nextDouble() - 0.5D) * 16.0D;
+- double d1 = Mth.clamp(livingentity.getY() + (double) (livingentity.getRandom().nextInt(16) - 8), (double) level.getMinBuildHeight(), (double) (level.getMinBuildHeight() + ((ServerLevel) level).getLogicalHeight() - 1));
+- double d2 = livingentity.getZ() + (livingentity.getRandom().nextDouble() - 0.5D) * 16.0D;
++ double d0 = entityLiving.getX() + (entityLiving.getRandom().nextDouble() - 0.5D) * 16.0D;
++ double d1 = Mth.clamp(entityLiving.getY() + (double) (entityLiving.getRandom().nextInt(16) - 8), (double) level.getMinBuildHeight(), (double) (level.getMinBuildHeight() + ((ServerLevel) level).getLogicalHeight() - 1));
++ double d2 = entityLiving.getZ() + (entityLiving.getRandom().nextDouble() - 0.5D) * 16.0D;
+
+- if (livingentity.isPassenger()) {
+- livingentity.stopRiding();
++ if (entityLiving.isPassenger()) {
++ entityLiving.stopRiding();
+ }
+
+- Vec3 vec3 = livingentity.position();
++ Vec3 vec3d = entityLiving.position();
+
+- if (livingentity.randomTeleport(d0, d1, d2, true)) {
+- level.gameEvent(GameEvent.TELEPORT, vec3, GameEvent.Context.of((Entity) livingentity));
+- SoundEvent soundevent;
+- SoundSource soundsource;
++ // 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 (livingentity instanceof Fox) {
+- soundevent = SoundEvents.FOX_TELEPORT;
+- soundsource = SoundSource.NEUTRAL;
++ 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) {
++ soundeffect = SoundEvents.FOX_TELEPORT;
++ soundcategory = SoundSource.NEUTRAL;
+ } else {
+- soundevent = SoundEvents.CHORUS_FRUIT_TELEPORT;
+- soundsource = SoundSource.PLAYERS;
++ soundeffect = SoundEvents.CHORUS_FRUIT_TELEPORT;
++ soundcategory = SoundSource.PLAYERS;
+ }
+
+- level.playSound((Player) null, livingentity.getX(), livingentity.getY(), livingentity.getZ(), soundevent, soundsource);
+- livingentity.resetFallDistance();
++ level.playSound((Player) null, entityLiving.getX(), entityLiving.getY(), entityLiving.getZ(), soundeffect, soundcategory);
++ entityLiving.resetFallDistance();
+ break;
+ }
+ }
+
+- if (livingentity instanceof Player) {
+- Player player = (Player) livingentity;
++ if (entityLiving instanceof Player) {
++ Player entityhuman = (Player) entityLiving;
+
+- player.getCooldowns().addCooldown(this, 20);
++ entityhuman.getCooldowns().addCooldown(this, 20);
+ }
+ }
+
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/CrossbowItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/CrossbowItem.java.patch
new file mode 100644
index 0000000000..28a9e4be50
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/CrossbowItem.java.patch
@@ -0,0 +1,538 @@
+--- a/net/minecraft/world/item/CrossbowItem.java
++++ b/net/minecraft/world/item/CrossbowItem.java
+@@ -16,7 +16,7 @@
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+ import net.minecraft.util.RandomSource;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.LivingEntity;
+@@ -32,7 +32,7 @@
+ import org.joml.Quaternionf;
+ import org.joml.Vector3f;
+
+-public class CrossbowItem extends ProjectileWeaponItem implements Vanishable {
++public class CrossbowItem extends ProjectileWeaponItem implements ItemVanishable {
+
+ private static final String TAG_CHARGED = "Charged";
+ private static final String TAG_CHARGED_PROJECTILES = "ChargedProjectiles";
+@@ -45,36 +45,33 @@
+ private static final float ARROW_POWER = 3.15F;
+ private static final float FIREWORK_POWER = 1.6F;
+
+- public CrossbowItem(Item.Properties item_properties) {
+- super(item_properties);
++ public CrossbowItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+ public Predicate<ItemStack> getSupportedHeldProjectiles() {
+ return CrossbowItem.ARROW_OR_FIREWORK;
+ }
+
+ @Override
+- @Override
+ public Predicate<ItemStack> getAllSupportedProjectiles() {
+ return CrossbowItem.ARROW_ONLY;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+ if (isCharged(itemstack)) {
+- performShooting(level, player, interactionhand, itemstack, getShootingPower(itemstack), 1.0F);
++ performShooting(level, player, hand, itemstack, getShootingPower(itemstack), 1.0F);
+ setCharged(itemstack, false);
+ return InteractionResultHolder.consume(itemstack);
+ } else if (!player.getProjectile(itemstack).isEmpty()) {
+ if (!isCharged(itemstack)) {
+ this.startSoundPlayed = false;
+ this.midLoadSoundPlayed = false;
+- player.startUsingItem(interactionhand);
++ player.startUsingItem(hand);
+ }
+
+ return InteractionResultHolder.consume(itemstack);
+@@ -83,30 +80,29 @@
+ }
+ }
+
+- private static float getShootingPower(ItemStack itemstack) {
+- return containsChargedProjectile(itemstack, Items.FIREWORK_ROCKET) ? 1.6F : 3.15F;
++ private static float getShootingPower(ItemStack crossbowStack) {
++ return containsChargedProjectile(crossbowStack, Items.FIREWORK_ROCKET) ? 1.6F : 3.15F;
+ }
+
+ @Override
+- @Override
+- public void releaseUsing(ItemStack itemstack, Level level, LivingEntity livingentity, int i) {
+- int j = this.getUseDuration(itemstack) - i;
+- float f = getPowerForTime(j, itemstack);
++ public void releaseUsing(ItemStack stack, Level level, LivingEntity entityLiving, int timeLeft) {
++ int j = this.getUseDuration(stack) - timeLeft;
++ float f = getPowerForTime(j, stack);
+
+- if (f >= 1.0F && !isCharged(itemstack) && tryLoadProjectiles(livingentity, itemstack)) {
+- setCharged(itemstack, true);
+- SoundSource soundsource = livingentity instanceof Player ? SoundSource.PLAYERS : SoundSource.HOSTILE;
++ if (f >= 1.0F && !isCharged(stack) && tryLoadProjectiles(entityLiving, stack)) {
++ setCharged(stack, true);
++ SoundSource soundcategory = entityLiving instanceof Player ? SoundSource.PLAYERS : SoundSource.HOSTILE;
+
+- level.playSound((Player) null, livingentity.getX(), livingentity.getY(), livingentity.getZ(), SoundEvents.CROSSBOW_LOADING_END, soundsource, 1.0F, 1.0F / (level.getRandom().nextFloat() * 0.5F + 1.0F) + 0.2F);
++ level.playSound((Player) null, entityLiving.getX(), entityLiving.getY(), entityLiving.getZ(), SoundEvents.CROSSBOW_LOADING_END, soundcategory, 1.0F, 1.0F / (level.getRandom().nextFloat() * 0.5F + 1.0F) + 0.2F);
+ }
+
+ }
+
+- private static boolean tryLoadProjectiles(LivingEntity livingentity, ItemStack itemstack) {
+- int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MULTISHOT, itemstack);
++ private static boolean tryLoadProjectiles(LivingEntity shooter, ItemStack crossbowStack) {
++ int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.MULTISHOT, crossbowStack);
+ int j = i == 0 ? 1 : 3;
+- boolean flag = livingentity instanceof Player && ((Player) livingentity).getAbilities().instabuild;
+- ItemStack itemstack1 = livingentity.getProjectile(itemstack);
++ boolean flag = shooter instanceof Player && ((Player) shooter).getAbilities().instabuild;
++ ItemStack itemstack1 = shooter.getProjectile(crossbowStack);
+ ItemStack itemstack2 = itemstack1.copy();
+
+ for (int k = 0; k < j; ++k) {
+@@ -119,7 +115,7 @@
+ itemstack2 = itemstack1.copy();
+ }
+
+- if (!loadProjectile(livingentity, itemstack, itemstack1, k > 0, flag)) {
++ if (!loadProjectile(shooter, crossbowStack, itemstack1, k > 0, flag)) {
+ return false;
+ }
+ }
+@@ -127,68 +123,68 @@
+ return true;
+ }
+
+- private static boolean loadProjectile(LivingEntity livingentity, ItemStack itemstack, ItemStack itemstack1, boolean flag, boolean flag1) {
+- if (itemstack1.isEmpty()) {
++ private static boolean loadProjectile(LivingEntity shooter, ItemStack crossbowStack, ItemStack ammoStack, boolean hasAmmo, boolean isCreative) {
++ if (ammoStack.isEmpty()) {
+ return false;
+ } else {
+- boolean flag2 = flag1 && itemstack1.getItem() instanceof ArrowItem;
++ boolean flag2 = isCreative && ammoStack.getItem() instanceof ArrowItem;
+ ItemStack itemstack2;
+
+- if (!flag2 && !flag1 && !flag) {
+- itemstack2 = itemstack1.split(1);
+- if (itemstack1.isEmpty() && livingentity instanceof Player) {
+- ((Player) livingentity).getInventory().removeItem(itemstack1);
++ if (!flag2 && !isCreative && !hasAmmo) {
++ itemstack2 = ammoStack.split(1);
++ if (ammoStack.isEmpty() && shooter instanceof Player) {
++ ((Player) shooter).getInventory().removeItem(ammoStack);
+ }
+ } else {
+- itemstack2 = itemstack1.copy();
++ itemstack2 = ammoStack.copy();
+ }
+
+- addChargedProjectile(itemstack, itemstack2);
++ addChargedProjectile(crossbowStack, itemstack2);
+ return true;
+ }
+ }
+
+- public static boolean isCharged(ItemStack itemstack) {
+- CompoundTag compoundtag = itemstack.getTag();
++ public static boolean isCharged(ItemStack crossbowStack) {
++ CompoundTag nbttagcompound = crossbowStack.getTag();
+
+- return compoundtag != null && compoundtag.getBoolean("Charged");
++ return nbttagcompound != null && nbttagcompound.getBoolean("Charged");
+ }
+
+- public static void setCharged(ItemStack itemstack, boolean flag) {
+- CompoundTag compoundtag = itemstack.getOrCreateTag();
++ public static void setCharged(ItemStack crossbowStack, boolean isCharged) {
++ CompoundTag nbttagcompound = crossbowStack.getOrCreateTag();
+
+- compoundtag.putBoolean("Charged", flag);
++ nbttagcompound.putBoolean("Charged", isCharged);
+ }
+
+- private static void addChargedProjectile(ItemStack itemstack, ItemStack itemstack1) {
+- CompoundTag compoundtag = itemstack.getOrCreateTag();
+- ListTag listtag;
++ private static void addChargedProjectile(ItemStack crossbowStack, ItemStack ammoStack) {
++ CompoundTag nbttagcompound = crossbowStack.getOrCreateTag();
++ ListTag nbttaglist;
+
+- if (compoundtag.contains("ChargedProjectiles", 9)) {
+- listtag = compoundtag.getList("ChargedProjectiles", 10);
++ if (nbttagcompound.contains("ChargedProjectiles", 9)) {
++ nbttaglist = nbttagcompound.getList("ChargedProjectiles", 10);
+ } else {
+- listtag = new ListTag();
++ nbttaglist = new ListTag();
+ }
+
+- CompoundTag compoundtag1 = new CompoundTag();
++ CompoundTag nbttagcompound1 = new CompoundTag();
+
+- itemstack1.save(compoundtag1);
+- listtag.add(compoundtag1);
+- compoundtag.put("ChargedProjectiles", listtag);
++ ammoStack.save(nbttagcompound1);
++ nbttaglist.add(nbttagcompound1);
++ nbttagcompound.put("ChargedProjectiles", nbttaglist);
+ }
+
+- private static List<ItemStack> getChargedProjectiles(ItemStack itemstack) {
++ private static List<ItemStack> getChargedProjectiles(ItemStack crossbowStack) {
+ List<ItemStack> list = Lists.newArrayList();
+- CompoundTag compoundtag = itemstack.getTag();
++ CompoundTag nbttagcompound = crossbowStack.getTag();
+
+- if (compoundtag != null && compoundtag.contains("ChargedProjectiles", 9)) {
+- ListTag listtag = compoundtag.getList("ChargedProjectiles", 10);
++ if (nbttagcompound != null && nbttagcompound.contains("ChargedProjectiles", 9)) {
++ ListTag nbttaglist = nbttagcompound.getList("ChargedProjectiles", 10);
+
+- if (listtag != null) {
+- for (int i = 0; i < listtag.size(); ++i) {
+- CompoundTag compoundtag1 = listtag.getCompound(i);
++ if (nbttaglist != null) {
++ for (int i = 0; i < nbttaglist.size(); ++i) {
++ CompoundTag nbttagcompound1 = nbttaglist.getCompound(i);
+
+- list.add(ItemStack.of(compoundtag1));
++ list.add(ItemStack.of(nbttagcompound1));
+ }
+ }
+ }
+@@ -196,134 +192,149 @@
+ return list;
+ }
+
+- private static void clearChargedProjectiles(ItemStack itemstack) {
+- CompoundTag compoundtag = itemstack.getTag();
++ private static void clearChargedProjectiles(ItemStack crossbowStack) {
++ CompoundTag nbttagcompound = crossbowStack.getTag();
+
+- if (compoundtag != null) {
+- ListTag listtag = compoundtag.getList("ChargedProjectiles", 9);
++ if (nbttagcompound != null) {
++ ListTag nbttaglist = nbttagcompound.getList("ChargedProjectiles", 9);
+
+- listtag.clear();
+- compoundtag.put("ChargedProjectiles", listtag);
++ nbttaglist.clear();
++ nbttagcompound.put("ChargedProjectiles", nbttaglist);
+ }
+
+ }
+
+- public static boolean containsChargedProjectile(ItemStack itemstack, Item item) {
+- return getChargedProjectiles(itemstack).stream().anyMatch((itemstack1) -> {
+- return itemstack1.is(item);
++ public static boolean containsChargedProjectile(ItemStack crossbowStack, Item ammoItem) {
++ return getChargedProjectiles(crossbowStack).stream().anyMatch((itemstack1) -> {
++ return itemstack1.is(ammoItem);
+ });
+ }
+
+- private static void shootProjectile(Level level, LivingEntity livingentity, InteractionHand interactionhand, ItemStack itemstack, ItemStack itemstack1, float f, boolean flag, float f1, float f2, float f3) {
++ private static void shootProjectile(Level level, LivingEntity shooter, EnumHand hand, ItemStack crossbowStack, ItemStack ammoStack, float soundPitch, boolean isCreativeMode, float velocity, float inaccuracy, float projectileAngle) {
+ if (!level.isClientSide) {
+- boolean flag1 = itemstack1.is(Items.FIREWORK_ROCKET);
++ boolean flag1 = ammoStack.is(Items.FIREWORK_ROCKET);
+ Object object;
+
+ if (flag1) {
+- object = new FireworkRocketEntity(level, itemstack1, livingentity, livingentity.getX(), livingentity.getEyeY() - 0.15000000596046448D, livingentity.getZ(), true);
++ object = new FireworkRocketEntity(level, ammoStack, shooter, shooter.getX(), shooter.getEyeY() - 0.15000000596046448D, shooter.getZ(), true);
+ } else {
+- object = getArrow(level, livingentity, itemstack, itemstack1);
+- if (flag || f3 != 0.0F) {
++ object = getArrow(level, shooter, crossbowStack, ammoStack);
++ if (isCreativeMode || projectileAngle != 0.0F) {
+ ((AbstractArrow) object).pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
+ }
+ }
+
+- if (livingentity instanceof CrossbowAttackMob) {
+- CrossbowAttackMob crossbowattackmob = (CrossbowAttackMob) livingentity;
++ if (shooter instanceof CrossbowAttackMob) {
++ CrossbowAttackMob icrossbow = (CrossbowAttackMob) shooter;
+
+- crossbowattackmob.shootCrossbowProjectile(crossbowattackmob.getTarget(), itemstack, (Projectile) object, f3);
++ icrossbow.shootCrossbowProjectile(icrossbow.getTarget(), crossbowStack, (Projectile) object, projectileAngle);
+ } else {
+- Vec3 vec3 = livingentity.getUpVector(1.0F);
+- Quaternionf quaternionf = (new Quaternionf()).setAngleAxis((double) (f3 * 0.017453292F), vec3.x, vec3.y, vec3.z);
+- Vec3 vec31 = livingentity.getViewVector(1.0F);
+- Vector3f vector3f = vec31.toVector3f().rotate(quaternionf);
++ Vec3 vec3d = shooter.getUpVector(1.0F);
++ Quaternionf quaternionf = (new Quaternionf()).setAngleAxis((double) (projectileAngle * 0.017453292F), vec3d.x, vec3d.y, vec3d.z);
++ Vec3 vec3d1 = shooter.getViewVector(1.0F);
++ Vector3f vector3f = vec3d1.toVector3f().rotate(quaternionf);
+
+- ((Projectile) object).shoot((double) vector3f.x(), (double) vector3f.y(), (double) vector3f.z(), f1, f2);
++ ((Projectile) object).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
+
+- itemstack.hurtAndBreak(flag1 ? 3 : 1, livingentity, (livingentity1) -> {
+- livingentity1.broadcastBreakEvent(interactionhand);
++ crossbowStack.hurtAndBreak(flag1 ? 3 : 1, shooter, (entityliving1) -> {
++ entityliving1.broadcastBreakEvent(hand);
+ });
+- level.addFreshEntity((Entity) object);
+- level.playSound((Player) null, livingentity.getX(), livingentity.getY(), livingentity.getZ(), SoundEvents.CROSSBOW_SHOOT, SoundSource.PLAYERS, 1.0F, f);
++ // 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);
+ }
+ }
+
+- private static AbstractArrow getArrow(Level level, LivingEntity livingentity, ItemStack itemstack, ItemStack itemstack1) {
+- ArrowItem arrowitem = (ArrowItem) (itemstack1.getItem() instanceof ArrowItem ? itemstack1.getItem() : Items.ARROW);
+- AbstractArrow abstractarrow = arrowitem.createArrow(level, itemstack1, livingentity);
++ private static AbstractArrow getArrow(Level level, LivingEntity livingEntity, ItemStack crossbowStack, ItemStack ammoStack) {
++ ArrowItem itemarrow = (ArrowItem) (ammoStack.getItem() instanceof ArrowItem ? ammoStack.getItem() : Items.ARROW);
++ AbstractArrow entityarrow = itemarrow.createArrow(level, ammoStack, livingEntity);
+
+- if (livingentity instanceof Player) {
+- abstractarrow.setCritArrow(true);
++ if (livingEntity instanceof Player) {
++ entityarrow.setCritArrow(true);
+ }
+
+- abstractarrow.setSoundEvent(SoundEvents.CROSSBOW_HIT);
+- abstractarrow.setShotFromCrossbow(true);
+- int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.PIERCING, itemstack);
++ entityarrow.setSoundEvent(SoundEvents.CROSSBOW_HIT);
++ entityarrow.setShotFromCrossbow(true);
++ int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.PIERCING, crossbowStack);
+
+ if (i > 0) {
+- abstractarrow.setPierceLevel((byte) i);
++ entityarrow.setPierceLevel((byte) i);
+ }
+
+- return abstractarrow;
++ return entityarrow;
+ }
+
+- public static void performShooting(Level level, LivingEntity livingentity, InteractionHand interactionhand, ItemStack itemstack, float f, float f1) {
+- List<ItemStack> list = getChargedProjectiles(itemstack);
+- float[] afloat = getShotPitches(livingentity.getRandom());
++ public static void performShooting(Level level, LivingEntity shooter, EnumHand usedHand, ItemStack crossbowStack, float velocity, float inaccuracy) {
++ List<ItemStack> list = getChargedProjectiles(crossbowStack);
++ float[] afloat = getShotPitches(shooter.getRandom());
+
+ for (int i = 0; i < list.size(); ++i) {
+ ItemStack itemstack1 = (ItemStack) list.get(i);
+- boolean flag = livingentity instanceof Player && ((Player) livingentity).getAbilities().instabuild;
++ boolean flag = shooter instanceof Player && ((Player) shooter).getAbilities().instabuild;
+
+ if (!itemstack1.isEmpty()) {
+ if (i == 0) {
+- shootProjectile(level, livingentity, interactionhand, itemstack, itemstack1, afloat[i], flag, f, f1, 0.0F);
++ shootProjectile(level, shooter, usedHand, crossbowStack, itemstack1, afloat[i], flag, velocity, inaccuracy, 0.0F);
+ } else if (i == 1) {
+- shootProjectile(level, livingentity, interactionhand, itemstack, itemstack1, afloat[i], flag, f, f1, -10.0F);
++ shootProjectile(level, shooter, usedHand, crossbowStack, itemstack1, afloat[i], flag, velocity, inaccuracy, -10.0F);
+ } else if (i == 2) {
+- shootProjectile(level, livingentity, interactionhand, itemstack, itemstack1, afloat[i], flag, f, f1, 10.0F);
++ shootProjectile(level, shooter, usedHand, crossbowStack, itemstack1, afloat[i], flag, velocity, inaccuracy, 10.0F);
+ }
+ }
+ }
+
+- onCrossbowShot(level, livingentity, itemstack);
++ onCrossbowShot(level, shooter, crossbowStack);
+ }
+
+- private static float[] getShotPitches(RandomSource randomsource) {
+- boolean flag = randomsource.nextBoolean();
++ private static float[] getShotPitches(RandomSource random) {
++ boolean flag = random.nextBoolean();
+
+- return new float[]{1.0F, getRandomShotPitch(flag, randomsource), getRandomShotPitch(!flag, randomsource)};
++ return new float[]{1.0F, getRandomShotPitch(flag, random), getRandomShotPitch(!flag, random)};
+ }
+
+- private static float getRandomShotPitch(boolean flag, RandomSource randomsource) {
+- float f = flag ? 0.63F : 0.43F;
++ private static float getRandomShotPitch(boolean isHighPitched, RandomSource random) {
++ float f = isHighPitched ? 0.63F : 0.43F;
+
+- return 1.0F / (randomsource.nextFloat() * 0.5F + 1.8F) + f;
++ return 1.0F / (random.nextFloat() * 0.5F + 1.8F) + f;
+ }
+
+- private static void onCrossbowShot(Level level, LivingEntity livingentity, ItemStack itemstack) {
+- if (livingentity instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) livingentity;
++ private static void onCrossbowShot(Level level, LivingEntity shooter, ItemStack crossbowStack) {
++ if (shooter instanceof ServerPlayer) {
++ ServerPlayer entityplayer = (ServerPlayer) shooter;
+
+ if (!level.isClientSide) {
+- CriteriaTriggers.SHOT_CROSSBOW.trigger(serverplayer, itemstack);
++ CriteriaTriggers.SHOT_CROSSBOW.trigger(entityplayer, crossbowStack);
+ }
+
+- serverplayer.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
++ entityplayer.awardStat(Stats.ITEM_USED.get(crossbowStack.getItem()));
+ }
+
+- clearChargedProjectiles(itemstack);
++ clearChargedProjectiles(crossbowStack);
+ }
+
+ @Override
+- @Override
+- public void onUseTick(Level level, LivingEntity livingentity, ItemStack itemstack, int i) {
++ public void onUseTick(Level level, LivingEntity livingEntity, ItemStack stack, int count) {
+ if (!level.isClientSide) {
+- int j = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, itemstack);
+- SoundEvent soundevent = this.getStartSound(j);
+- SoundEvent soundevent1 = j == 0 ? SoundEvents.CROSSBOW_LOADING_MIDDLE : null;
+- float f = (float) (itemstack.getUseDuration() - i) / (float) getChargeDuration(itemstack);
++ int j = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, stack);
++ SoundEvent soundeffect = this.getStartSound(j);
++ SoundEvent soundeffect1 = j == 0 ? SoundEvents.CROSSBOW_LOADING_MIDDLE : null;
++ float f = (float) (stack.getUseDuration() - count) / (float) getChargeDuration(stack);
+
+ if (f < 0.2F) {
+ this.startSoundPlayed = false;
+@@ -332,37 +343,35 @@
+
+ if (f >= 0.2F && !this.startSoundPlayed) {
+ this.startSoundPlayed = true;
+- level.playSound((Player) null, livingentity.getX(), livingentity.getY(), livingentity.getZ(), soundevent, SoundSource.PLAYERS, 0.5F, 1.0F);
++ level.playSound((Player) null, livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(), soundeffect, SoundSource.PLAYERS, 0.5F, 1.0F);
+ }
+
+- if (f >= 0.5F && soundevent1 != null && !this.midLoadSoundPlayed) {
++ if (f >= 0.5F && soundeffect1 != null && !this.midLoadSoundPlayed) {
+ this.midLoadSoundPlayed = true;
+- level.playSound((Player) null, livingentity.getX(), livingentity.getY(), livingentity.getZ(), soundevent1, SoundSource.PLAYERS, 0.5F, 1.0F);
++ level.playSound((Player) null, livingEntity.getX(), livingEntity.getY(), livingEntity.getZ(), soundeffect1, SoundSource.PLAYERS, 0.5F, 1.0F);
+ }
+ }
+
+ }
+
+ @Override
+- @Override
+- public int getUseDuration(ItemStack itemstack) {
+- return getChargeDuration(itemstack) + 3;
++ public int getUseDuration(ItemStack stack) {
++ return getChargeDuration(stack) + 3;
+ }
+
+- public static int getChargeDuration(ItemStack itemstack) {
+- int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, itemstack);
++ public static int getChargeDuration(ItemStack crossbowStack) {
++ int i = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.QUICK_CHARGE, crossbowStack);
+
+ return i == 0 ? 25 : 25 - 5 * i;
+ }
+
+ @Override
+- @Override
+- public UseAnim getUseAnimation(ItemStack itemstack) {
+- return UseAnim.CROSSBOW;
++ public EnumAnimation getUseAnimation(ItemStack stack) {
++ return EnumAnimation.CROSSBOW;
+ }
+
+- private SoundEvent getStartSound(int i) {
+- switch (i) {
++ private SoundEvent getStartSound(int enchantmentLevel) {
++ switch (enchantmentLevel) {
+ case 1:
+ return SoundEvents.CROSSBOW_QUICK_CHARGE_1;
+ case 2:
+@@ -374,8 +383,8 @@
+ }
+ }
+
+- private static float getPowerForTime(int i, ItemStack itemstack) {
+- float f = (float) i / (float) getChargeDuration(itemstack);
++ private static float getPowerForTime(int useTime, ItemStack crossbowStack) {
++ float f = (float) useTime / (float) getChargeDuration(crossbowStack);
+
+ if (f > 1.0F) {
+ f = 1.0F;
+@@ -385,24 +394,23 @@
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- List<ItemStack> list1 = getChargedProjectiles(itemstack);
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
++ List<ItemStack> list1 = getChargedProjectiles(stack);
+
+- if (isCharged(itemstack) && !list1.isEmpty()) {
++ if (isCharged(stack) && !list1.isEmpty()) {
+ ItemStack itemstack1 = (ItemStack) list1.get(0);
+
+- list.add(Component.translatable("item.minecraft.crossbow.projectile").append(CommonComponents.SPACE).append(itemstack1.getDisplayName()));
+- if (tooltipflag.isAdvanced() && itemstack1.is(Items.FIREWORK_ROCKET)) {
++ tooltip.add(Component.translatable("item.minecraft.crossbow.projectile").append(CommonComponents.SPACE).append(itemstack1.getDisplayName()));
++ if (flag.isAdvanced() && itemstack1.is(Items.FIREWORK_ROCKET)) {
+ List<Component> list2 = Lists.newArrayList();
+
+- Items.FIREWORK_ROCKET.appendHoverText(itemstack1, level, list2, tooltipflag);
++ Items.FIREWORK_ROCKET.appendHoverText(itemstack1, level, list2, flag);
+ if (!list2.isEmpty()) {
+ for (int i = 0; i < list2.size(); ++i) {
+ list2.set(i, Component.literal(" ").append((Component) list2.get(i)).withStyle(ChatFormatting.GRAY));
+ }
+
+- list.addAll(list2);
++ tooltip.addAll(list2);
+ }
+ }
+
+@@ -410,13 +418,11 @@
+ }
+
+ @Override
+- @Override
+- public boolean useOnRelease(ItemStack itemstack) {
+- return itemstack.is((Item) this);
++ public boolean useOnRelease(ItemStack stack) {
++ return stack.is((Item) this);
+ }
+
+ @Override
+- @Override
+ public int getDefaultProjectileRange() {
+ return 8;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/DebugStickItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/DebugStickItem.java.patch
new file mode 100644
index 0000000000..665bad6233
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/DebugStickItem.java.patch
@@ -0,0 +1,155 @@
+--- a/net/minecraft/world/item/DebugStickItem.java
++++ b/net/minecraft/world/item/DebugStickItem.java
+@@ -1,3 +1,4 @@
++// mc-dev import
+ package net.minecraft.world.item;
+
+ import java.util.Collection;
+@@ -8,88 +9,85 @@
+ import net.minecraft.nbt.CompoundTag;
+ import net.minecraft.network.chat.Component;
+ import net.minecraft.server.level.ServerPlayer;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.item.context.UseOnContext;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.LevelAccessor;
+ import net.minecraft.world.level.block.Block;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.StateDefinition;
+ import net.minecraft.world.level.block.state.properties.Property;
+
+ public class DebugStickItem extends Item {
+
+- public DebugStickItem(Item.Properties item_properties) {
+- super(item_properties);
++ public DebugStickItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public boolean isFoil(ItemStack itemstack) {
++ public boolean isFoil(ItemStack stack) {
+ return true;
+ }
+
+ @Override
+- @Override
+- public boolean canAttackBlock(BlockState blockstate, Level level, BlockPos blockpos, Player player) {
++ public boolean canAttackBlock(IBlockData state, Level level, BlockPos pos, Player player) {
+ if (!level.isClientSide) {
+- this.handleInteraction(player, blockstate, level, blockpos, false, player.getItemInHand(InteractionHand.MAIN_HAND));
++ this.handleInteraction(player, state, level, pos, false, player.getItemInHand(EnumHand.MAIN_HAND));
+ }
+
+ return false;
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Player player = useoncontext.getPlayer();
+- Level level = useoncontext.getLevel();
++ public InteractionResult useOn(UseOnContext context) {
++ Player entityhuman = context.getPlayer();
++ Level world = context.getLevel();
+
+- if (!level.isClientSide && player != null) {
+- BlockPos blockpos = useoncontext.getClickedPos();
++ if (!world.isClientSide && entityhuman != null) {
++ BlockPos blockposition = context.getClickedPos();
+
+- if (!this.handleInteraction(player, level.getBlockState(blockpos), level, blockpos, true, useoncontext.getItemInHand())) {
++ if (!this.handleInteraction(entityhuman, world.getBlockState(blockposition), world, blockposition, true, context.getItemInHand())) {
+ return InteractionResult.FAIL;
+ }
+ }
+
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ }
+
+- private boolean handleInteraction(Player player, BlockState blockstate, LevelAccessor levelaccessor, BlockPos blockpos, boolean flag, ItemStack itemstack) {
++ public boolean handleInteraction(Player player, IBlockData stateClicked, LevelAccessor accessor, BlockPos pos, boolean shouldCycleState, ItemStack debugStack) {
+ if (!player.canUseGameMasterBlocks()) {
+ return false;
+ } else {
+- Block block = blockstate.getBlock();
+- StateDefinition<Block, BlockState> statedefinition = block.getStateDefinition();
+- Collection<Property<?>> collection = statedefinition.getProperties();
++ Block block = stateClicked.getBlock();
++ StateDefinition<Block, IBlockData> blockstatelist = block.getStateDefinition();
++ Collection<Property<?>> collection = blockstatelist.getProperties();
+ String s = BuiltInRegistries.BLOCK.getKey(block).toString();
+
+ if (collection.isEmpty()) {
+ message(player, Component.translatable(this.getDescriptionId() + ".empty", s));
+ return false;
+ } else {
+- CompoundTag compoundtag = itemstack.getOrCreateTagElement("DebugProperty");
+- String s1 = compoundtag.getString(s);
+- Property<?> property = statedefinition.getProperty(s1);
++ CompoundTag nbttagcompound = debugStack.getOrCreateTagElement("DebugProperty");
++ String s1 = nbttagcompound.getString(s);
++ Property<?> iblockstate = blockstatelist.getProperty(s1);
+
+- if (flag) {
+- if (property == null) {
+- property = (Property) collection.iterator().next();
++ if (shouldCycleState) {
++ if (iblockstate == null) {
++ iblockstate = (Property) collection.iterator().next();
+ }
+
+- BlockState blockstate1 = cycleState(blockstate, property, player.isSecondaryUseActive());
++ IBlockData iblockdata1 = cycleState(stateClicked, iblockstate, player.isSecondaryUseActive());
+
+- levelaccessor.setBlock(blockpos, blockstate1, 18);
+- message(player, Component.translatable(this.getDescriptionId() + ".update", property.getName(), getNameHelper(blockstate1, property)));
++ accessor.setBlock(pos, iblockdata1, 18);
++ message(player, Component.translatable(this.getDescriptionId() + ".update", iblockstate.getName(), getNameHelper(iblockdata1, iblockstate)));
+ } else {
+- property = (Property) getRelative(collection, property, player.isSecondaryUseActive());
+- String s2 = property.getName();
++ iblockstate = (Property) getRelative(collection, iblockstate, player.isSecondaryUseActive());
++ String s2 = iblockstate.getName();
+
+- compoundtag.putString(s, s2);
+- message(player, Component.translatable(this.getDescriptionId() + ".select", s2, getNameHelper(blockstate, property)));
++ nbttagcompound.putString(s, s2);
++ message(player, Component.translatable(this.getDescriptionId() + ".select", s2, getNameHelper(stateClicked, iblockstate)));
+ }
+
+ return true;
+@@ -97,19 +95,19 @@
+ }
+ }
+
+- private static <T extends Comparable<T>> BlockState cycleState(BlockState blockstate, Property<T> property, boolean flag) {
+- return (BlockState) blockstate.setValue(property, (Comparable) getRelative(property.getPossibleValues(), blockstate.getValue(property), flag));
++ private static <T extends Comparable<T>> IBlockData cycleState(IBlockData state, Property<T> property, boolean backwards) {
++ return (IBlockData) state.setValue(property, getRelative(property.getPossibleValues(), state.getValue(property), backwards)); // CraftBukkit - decompile error
+ }
+
+- private static <T> T getRelative(Iterable<T> iterable, @Nullable T t0, boolean flag) {
+- return flag ? Util.findPreviousInIterable(iterable, t0) : Util.findNextInIterable(iterable, t0);
++ private static <T> T getRelative(Iterable<T> allowedValues, @Nullable T currentValue, boolean backwards) {
++ return backwards ? Util.findPreviousInIterable(allowedValues, currentValue) : Util.findNextInIterable(allowedValues, currentValue);
+ }
+
+- private static void message(Player player, Component component) {
+- ((ServerPlayer) player).sendSystemMessage(component, true);
++ private static void message(Player player, Component messageComponent) {
++ ((ServerPlayer) player).sendSystemMessage(messageComponent, true);
+ }
+
+- private static <T extends Comparable<T>> String getNameHelper(BlockState blockstate, Property<T> property) {
+- return property.getName(blockstate.getValue(property));
++ private static <T extends Comparable<T>> String getNameHelper(IBlockData state, Property<T> property) {
++ return property.getName(state.getValue(property));
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/DyeItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/DyeItem.java.patch
new file mode 100644
index 0000000000..ebdfdb2a0c
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/DyeItem.java.patch
@@ -0,0 +1,87 @@
+--- a/net/minecraft/world/item/DyeItem.java
++++ b/net/minecraft/world/item/DyeItem.java
+@@ -4,7 +4,7 @@
+ import java.util.Map;
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.LivingEntity;
+@@ -12,29 +12,39 @@
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.entity.SignBlockEntity;
++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);
+ private final DyeColor dyeColor;
+
+- public DyeItem(DyeColor dyecolor, Item.Properties item_properties) {
+- super(item_properties);
+- this.dyeColor = dyecolor;
+- DyeItem.ITEM_BY_COLOR.put(dyecolor, this);
++ public DyeItem(DyeColor dyeColor, Item.Properties properties) {
++ super(properties);
++ this.dyeColor = dyeColor;
++ DyeItem.ITEM_BY_COLOR.put(dyeColor, this);
+ }
+
+ @Override
+- @Override
+- public InteractionResult interactLivingEntity(ItemStack itemstack, Player player, LivingEntity livingentity, InteractionHand interactionhand) {
+- if (livingentity instanceof Sheep) {
+- Sheep sheep = (Sheep) livingentity;
++ public InteractionResult interactLivingEntity(ItemStack stack, Player player, LivingEntity target, EnumHand hand) {
++ if (target instanceof Sheep) {
++ Sheep entitysheep = (Sheep) target;
+
+- if (sheep.isAlive() && !sheep.isSheared() && sheep.getColor() != this.dyeColor) {
+- sheep.level().playSound(player, (Entity) sheep, SoundEvents.DYE_USE, SoundSource.PLAYERS, 1.0F, 1.0F);
++ 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) {
+- sheep.setColor(this.dyeColor);
+- itemstack.shrink(1);
++ // 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);
+@@ -48,17 +58,16 @@
+ return this.dyeColor;
+ }
+
+- public static DyeItem byColor(DyeColor dyecolor) {
+- return (DyeItem) DyeItem.ITEM_BY_COLOR.get(dyecolor);
++ public static DyeItem byColor(DyeColor color) {
++ return (DyeItem) DyeItem.ITEM_BY_COLOR.get(color);
+ }
+
+ @Override
+- @Override
+- public boolean tryApplyToSign(Level level, SignBlockEntity signblockentity, boolean flag, Player player) {
+- if (signblockentity.updateText((signtext) -> {
++ public boolean tryApplyToSign(Level level, SignBlockEntity sign, boolean isFront, Player player) {
++ if (sign.updateText((signtext) -> {
+ return signtext.setColor(this.getDyeColor());
+- }, flag)) {
+- level.playSound((Player) null, signblockentity.getBlockPos(), SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F);
++ }, isFront)) {
++ level.playSound((Player) null, sign.getBlockPos(), SoundEvents.DYE_USE, SoundSource.BLOCKS, 1.0F, 1.0F);
+ return true;
+ } else {
+ return false;
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/EggItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/EggItem.java.patch
new file mode 100644
index 0000000000..6678bf5c4e
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/EggItem.java.patch
@@ -0,0 +1,52 @@
+--- a/net/minecraft/world/item/EggItem.java
++++ b/net/minecraft/world/item/EggItem.java
+@@ -3,7 +3,7 @@
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.ThrownEgg;
+@@ -11,23 +11,30 @@
+
+ public class EggItem extends Item {
+
+- public EggItem(Item.Properties item_properties) {
+- super(item_properties);
++ public EggItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+- level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
++ // 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 entityegg = new ThrownEgg(level, player);
+
+- thrownegg.setItem(itemstack);
+- thrownegg.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
+- level.addFreshEntity(thrownegg);
++ 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
+ }
++ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.EGG_THROW, SoundSource.PLAYERS, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
+
+ player.awardStat(Stats.ITEM_USED.get(this));
+ if (!player.getAbilities().instabuild) {
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/EndCrystalItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/EndCrystalItem.java.patch
new file mode 100644
index 0000000000..3253e9f5c4
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/EndCrystalItem.java.patch
@@ -0,0 +1,96 @@
+--- a/net/minecraft/world/item/EndCrystalItem.java
++++ b/net/minecraft/world/item/EndCrystalItem.java
+@@ -9,63 +9,66 @@
+ import net.minecraft.world.item.context.UseOnContext;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.Blocks;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.dimension.end.EndDragonFight;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.AABB;
+
+ public class EndCrystalItem extends Item {
+
+- public EndCrystalItem(Item.Properties item_properties) {
+- super(item_properties);
++ public EndCrystalItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (!blockstate.is(Blocks.OBSIDIAN) && !blockstate.is(Blocks.BEDROCK)) {
++ if (!iblockdata.is(Blocks.OBSIDIAN) && !iblockdata.is(Blocks.BEDROCK)) {
+ return InteractionResult.FAIL;
+ } else {
+- BlockPos blockpos1 = blockpos.above();
++ BlockPos blockposition1 = blockposition.above();
+
+- if (!level.isEmptyBlock(blockpos1)) {
++ if (!world.isEmptyBlock(blockposition1)) {
+ return InteractionResult.FAIL;
+ } else {
+- double d0 = (double) blockpos1.getX();
+- double d1 = (double) blockpos1.getY();
+- double d2 = (double) blockpos1.getZ();
+- List<Entity> list = level.getEntities((Entity) null, new AABB(d0, d1, d2, d0 + 1.0D, d1 + 2.0D, d2 + 1.0D));
++ double d0 = (double) blockposition1.getX();
++ double d1 = (double) blockposition1.getY();
++ double d2 = (double) blockposition1.getZ();
++ List<Entity> list = world.getEntities((Entity) null, new AABB(d0, d1, d2, d0 + 1.0D, d1 + 2.0D, d2 + 1.0D));
+
+ if (!list.isEmpty()) {
+ return InteractionResult.FAIL;
+ } else {
+- if (level instanceof ServerLevel) {
+- EndCrystal endcrystal = new EndCrystal(level, d0 + 0.5D, d1, d2 + 0.5D);
++ if (world instanceof ServerLevel) {
++ EndCrystal entityendercrystal = new EndCrystal(world, d0 + 0.5D, d1, d2 + 0.5D);
+
+- endcrystal.setShowBottom(false);
+- level.addFreshEntity(endcrystal);
+- level.gameEvent((Entity) useoncontext.getPlayer(), GameEvent.ENTITY_PLACE, blockpos1);
+- EndDragonFight enddragonfight = ((ServerLevel) level).getDragonFight();
++ 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 (enddragonfight != null) {
+- enddragonfight.tryRespawn();
++ if (enderdragonbattle != null) {
++ enderdragonbattle.tryRespawn();
+ }
+ }
+
+- useoncontext.getItemInHand().shrink(1);
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ context.getItemInHand().shrink(1);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ }
+ }
+ }
+ }
+
+ @Override
+- @Override
+- public boolean isFoil(ItemStack itemstack) {
++ public boolean isFoil(ItemStack stack) {
+ return true;
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderEyeItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderEyeItem.java.patch
new file mode 100644
index 0000000000..43ff750020
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderEyeItem.java.patch
@@ -0,0 +1,136 @@
+--- a/net/minecraft/world/item/EnderEyeItem.java
++++ b/net/minecraft/world/item/EnderEyeItem.java
+@@ -8,7 +8,7 @@
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+ import net.minecraft.tags.StructureTags;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
+@@ -20,7 +20,7 @@
+ import net.minecraft.world.level.block.Block;
+ import net.minecraft.world.level.block.Blocks;
+ import net.minecraft.world.level.block.EndPortalFrameBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.pattern.BlockPattern;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.BlockHitResult;
+@@ -28,40 +28,39 @@
+
+ public class EnderEyeItem extends Item {
+
+- public EnderEyeItem(Item.Properties item_properties) {
+- super(item_properties);
++ public EnderEyeItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (blockstate.is(Blocks.END_PORTAL_FRAME) && !(Boolean) blockstate.getValue(EndPortalFrameBlock.HAS_EYE)) {
+- if (level.isClientSide) {
++ if (iblockdata.is(Blocks.END_PORTAL_FRAME) && !(Boolean) iblockdata.getValue(EndPortalFrameBlock.HAS_EYE)) {
++ if (world.isClientSide) {
+ return InteractionResult.SUCCESS;
+ } else {
+- BlockState blockstate1 = (BlockState) blockstate.setValue(EndPortalFrameBlock.HAS_EYE, true);
++ IBlockData iblockdata1 = (IBlockData) iblockdata.setValue(EndPortalFrameBlock.HAS_EYE, true);
+
+- Block.pushEntitiesUp(blockstate, blockstate1, level, blockpos);
+- level.setBlock(blockpos, blockstate1, 2);
+- level.updateNeighbourForOutputSignal(blockpos, Blocks.END_PORTAL_FRAME);
+- useoncontext.getItemInHand().shrink(1);
+- level.levelEvent(1503, blockpos, 0);
+- BlockPattern.BlockPatternMatch blockpattern_blockpatternmatch = EndPortalFrameBlock.getOrCreatePortalShape().find(level, blockpos);
++ Block.pushEntitiesUp(iblockdata, iblockdata1, world, blockposition);
++ world.setBlock(blockposition, iblockdata1, 2);
++ world.updateNeighbourForOutputSignal(blockposition, Blocks.END_PORTAL_FRAME);
++ context.getItemInHand().shrink(1);
++ world.levelEvent(1503, blockposition, 0);
++ BlockPattern.BlockPatternMatch shapedetector_shapedetectorcollection = EndPortalFrameBlock.getOrCreatePortalShape().find(world, blockposition);
+
+- if (blockpattern_blockpatternmatch != null) {
+- BlockPos blockpos1 = blockpattern_blockpatternmatch.getFrontTopLeft().offset(-3, 0, -3);
++ if (shapedetector_shapedetectorcollection != null) {
++ BlockPos blockposition1 = shapedetector_shapedetectorcollection.getFrontTopLeft().offset(-3, 0, -3);
+
+ for (int i = 0; i < 3; ++i) {
+ for (int j = 0; j < 3; ++j) {
+- level.setBlock(blockpos1.offset(i, 0, j), Blocks.END_PORTAL.defaultBlockState(), 2);
++ world.setBlock(blockposition1.offset(i, 0, j), Blocks.END_PORTAL.defaultBlockState(), 2);
+ }
+ }
+
+- level.globalLevelEvent(1038, blockpos1.offset(1, 0, 1), 0);
++ world.globalLevelEvent(1038, blockposition1.offset(1, 0, 1), 0);
+ }
+
+ return InteractionResult.CONSUME;
+@@ -72,28 +71,31 @@
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
+- BlockHitResult blockhitresult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.NONE);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++ BlockHitResult movingobjectpositionblock = getPlayerPOVHitResult(level, player, ClipContext.Fluid.NONE);
+
+- if (blockhitresult.getType() == HitResult.Type.BLOCK && level.getBlockState(blockhitresult.getBlockPos()).is(Blocks.END_PORTAL_FRAME)) {
++ if (movingobjectpositionblock.getType() == HitResult.EnumMovingObjectType.BLOCK && level.getBlockState(movingobjectpositionblock.getBlockPos()).is(Blocks.END_PORTAL_FRAME)) {
+ return InteractionResultHolder.pass(itemstack);
+ } else {
+- player.startUsingItem(interactionhand);
++ player.startUsingItem(hand);
+ if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) level;
+- BlockPos blockpos = serverlevel.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, player.blockPosition(), 100, false);
++ ServerLevel worldserver = (ServerLevel) level;
++ BlockPos blockposition = worldserver.findNearestMapStructure(StructureTags.EYE_OF_ENDER_LOCATED, player.blockPosition(), 100, false);
+
+- if (blockpos != null) {
+- EyeOfEnder eyeofender = new EyeOfEnder(level, player.getX(), player.getY(0.5D), player.getZ());
++ if (blockposition != null) {
++ EyeOfEnder entityendersignal = new EyeOfEnder(level, player.getX(), player.getY(0.5D), player.getZ());
+
+- eyeofender.setItem(itemstack);
+- eyeofender.signalTo(blockpos);
+- level.gameEvent(GameEvent.PROJECTILE_SHOOT, eyeofender.position(), GameEvent.Context.of((Entity) player));
+- level.addFreshEntity(eyeofender);
++ 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);
++ CriteriaTriggers.USED_ENDER_EYE.trigger((ServerPlayer) player, blockposition);
+ }
+
+ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.ENDER_EYE_LAUNCH, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
+@@ -103,7 +105,7 @@
+ }
+
+ player.awardStat(Stats.ITEM_USED.get(this));
+- player.swing(interactionhand, true);
++ player.swing(hand, true);
+ return InteractionResultHolder.success(itemstack);
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderpearlItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderpearlItem.java.patch
new file mode 100644
index 0000000000..2a4701dc4e
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/EnderpearlItem.java.patch
@@ -0,0 +1,55 @@
+--- a/net/minecraft/world/item/EnderpearlItem.java
++++ b/net/minecraft/world/item/EnderpearlItem.java
+@@ -3,7 +3,7 @@
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.ThrownEnderpearl;
+@@ -11,25 +11,32 @@
+
+ public class EnderpearlItem extends Item {
+
+- public EnderpearlItem(Item.Properties item_properties) {
+- super(item_properties);
++ public EnderpearlItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+- 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 start - change order
+ if (!level.isClientSide) {
+- ThrownEnderpearl thrownenderpearl = new ThrownEnderpearl(level, player);
++ ThrownEnderpearl entityenderpearl = new ThrownEnderpearl(level, player);
+
+- thrownenderpearl.setItem(itemstack);
+- thrownenderpearl.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
+- level.addFreshEntity(thrownenderpearl);
++ entityenderpearl.setItem(itemstack);
++ entityenderpearl.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
++ if (!level.addFreshEntity(entityenderpearl)) {
++ if (player instanceof net.minecraft.server.level.ServerPlayer) {
++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().updateInventory();
++ }
++ return InteractionResultHolder.fail(itemstack);
++ }
+ }
+
++ 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) {
+ itemstack.shrink(1);
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/FireChargeItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/FireChargeItem.java.patch
new file mode 100644
index 0000000000..fffc0310e0
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/FireChargeItem.java.patch
@@ -0,0 +1,89 @@
+--- a/net/minecraft/world/item/FireChargeItem.java
++++ b/net/minecraft/world/item/FireChargeItem.java
+@@ -13,50 +13,65 @@
+ import net.minecraft.world.level.block.CampfireBlock;
+ import net.minecraft.world.level.block.CandleBlock;
+ import net.minecraft.world.level.block.CandleCakeBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.properties.BlockStateProperties;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+ public class FireChargeItem extends Item {
+
+- public FireChargeItem(Item.Properties item_properties) {
+- super(item_properties);
++ public FireChargeItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+ boolean flag = false;
+
+- if (!CampfireBlock.canLight(blockstate) && !CandleBlock.canLight(blockstate) && !CandleCakeBlock.canLight(blockstate)) {
+- blockpos = blockpos.relative(useoncontext.getClickedFace());
+- if (BaseFireBlock.canBePlacedAt(level, blockpos, useoncontext.getHorizontalDirection())) {
+- this.playSound(level, blockpos);
+- level.setBlockAndUpdate(blockpos, BaseFireBlock.getState(level, blockpos));
+- level.gameEvent((Entity) useoncontext.getPlayer(), GameEvent.BLOCK_PLACE, blockpos);
++ 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, blockpos);
+- level.setBlockAndUpdate(blockpos, (BlockState) blockstate.setValue(BlockStateProperties.LIT, true));
+- level.gameEvent((Entity) useoncontext.getPlayer(), GameEvent.BLOCK_CHANGE, blockpos);
++ // 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;
+ }
+
+ if (flag) {
+- useoncontext.getItemInHand().shrink(1);
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ context.getItemInHand().shrink(1);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.FAIL;
+ }
+ }
+
+- private void playSound(Level level, BlockPos blockpos) {
++ private void playSound(Level level, BlockPos pos) {
+ RandomSource randomsource = level.getRandom();
+
+- level.playSound((Player) null, blockpos, SoundEvents.FIRECHARGE_USE, SoundSource.BLOCKS, 1.0F, (randomsource.nextFloat() - randomsource.nextFloat()) * 0.2F + 1.0F);
++ level.playSound((Player) null, pos, SoundEvents.FIRECHARGE_USE, SoundSource.BLOCKS, 1.0F, (randomsource.nextFloat() - randomsource.nextFloat()) * 0.2F + 1.0F);
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/FishingRodItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/FishingRodItem.java.patch
new file mode 100644
index 0000000000..f8e99a2b8f
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/FishingRodItem.java.patch
@@ -0,0 +1,80 @@
+--- a/net/minecraft/world/item/FishingRodItem.java
++++ b/net/minecraft/world/item/FishingRodItem.java
+@@ -3,7 +3,7 @@
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.FishingHook;
+@@ -11,35 +11,50 @@
+ 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 FishingRodItem(Item.Properties item_properties) {
+- super(item_properties);
++public class FishingRodItem extends Item implements ItemVanishable {
++
++ public FishingRodItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+ int i;
+
+ if (player.fishing != null) {
+ if (!level.isClientSide) {
+ i = player.fishing.retrieve(itemstack);
+- itemstack.hurtAndBreak(i, player, (player1) -> {
+- player1.broadcastBreakEvent(interactionhand);
++ itemstack.hurtAndBreak(i, player, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(hand);
+ });
+ }
+
+ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.FISHING_BOBBER_RETRIEVE, SoundSource.NEUTRAL, 1.0F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
+ player.gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+ } else {
+- 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));
++ // world.playSound((EntityHuman) null, entityhuman.getX(), entityhuman.getY(), entityhuman.getZ(), SoundEffects.FISHING_BOBBER_THROW, SoundCategory.NEUTRAL, 0.5F, 0.4F / (world.getRandom().nextFloat() * 0.4F + 0.8F));
+ if (!level.isClientSide) {
+ i = EnchantmentHelper.getFishingSpeedBonus(itemstack);
+ int j = EnchantmentHelper.getFishingLuckBonus(itemstack);
+
+- level.addFreshEntity(new FishingHook(player, level, j, i));
++ // 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));
+@@ -50,7 +65,6 @@
+ }
+
+ @Override
+- @Override
+ public int getEnchantmentValue() {
+ return 1;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/FlintAndSteelItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/FlintAndSteelItem.java.patch
new file mode 100644
index 0000000000..9cc0efceef
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/FlintAndSteelItem.java.patch
@@ -0,0 +1,104 @@
+--- a/net/minecraft/world/item/FlintAndSteelItem.java
++++ b/net/minecraft/world/item/FlintAndSteelItem.java
+@@ -14,57 +14,72 @@
+ import net.minecraft.world.level.block.CampfireBlock;
+ import net.minecraft.world.level.block.CandleBlock;
+ import net.minecraft.world.level.block.CandleCakeBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.block.state.properties.BlockStateProperties;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+ public class FlintAndSteelItem extends Item {
+
+- public FlintAndSteelItem(Item.Properties item_properties) {
+- super(item_properties);
++ public FlintAndSteelItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Player player = useoncontext.getPlayer();
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Player entityhuman = context.getPlayer();
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (!CampfireBlock.canLight(blockstate) && !CandleBlock.canLight(blockstate) && !CandleCakeBlock.canLight(blockstate)) {
+- BlockPos blockpos1 = blockpos.relative(useoncontext.getClickedFace());
++ if (!CampfireBlock.canLight(iblockdata) && !CandleBlock.canLight(iblockdata) && !CandleCakeBlock.canLight(iblockdata)) {
++ BlockPos blockposition1 = blockposition.relative(context.getClickedFace());
+
+- if (BaseFireBlock.canBePlacedAt(level, blockpos1, useoncontext.getHorizontalDirection())) {
+- level.playSound(player, blockpos1, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F);
+- BlockState blockstate1 = BaseFireBlock.getState(level, blockpos1);
++ 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);
+
+- level.setBlock(blockpos1, blockstate1, 11);
+- level.gameEvent((Entity) player, GameEvent.BLOCK_PLACE, blockpos);
+- ItemStack itemstack = useoncontext.getItemInHand();
++ world.setBlock(blockposition1, iblockdata1, 11);
++ world.gameEvent((Entity) entityhuman, GameEvent.BLOCK_PLACE, blockposition);
++ ItemStack itemstack = context.getItemInHand();
+
+- if (player instanceof ServerPlayer) {
+- CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) player, blockpos1, itemstack);
+- itemstack.hurtAndBreak(1, player, (player1) -> {
+- player1.broadcastBreakEvent(useoncontext.getHand());
++ if (entityhuman instanceof ServerPlayer) {
++ CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer) entityhuman, blockposition1, itemstack);
++ itemstack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(context.getHand());
+ });
+ }
+
+- return InteractionResult.sidedSuccess(level.isClientSide());
++ return InteractionResult.sidedSuccess(world.isClientSide());
+ } else {
+ return InteractionResult.FAIL;
+ }
+ } else {
+- level.playSound(player, blockpos, SoundEvents.FLINTANDSTEEL_USE, SoundSource.BLOCKS, 1.0F, level.getRandom().nextFloat() * 0.4F + 0.8F);
+- level.setBlock(blockpos, (BlockState) blockstate.setValue(BlockStateProperties.LIT, true), 11);
+- level.gameEvent((Entity) player, GameEvent.BLOCK_CHANGE, blockpos);
+- if (player != null) {
+- useoncontext.getItemInHand().hurtAndBreak(1, player, (player1) -> {
+- player1.broadcastBreakEvent(useoncontext.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());
++ return InteractionResult.sidedSuccess(world.isClientSide());
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/HangingEntityItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/HangingEntityItem.java.patch
new file mode 100644
index 0000000000..a0a0dfeb0b
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/HangingEntityItem.java.patch
@@ -0,0 +1,157 @@
+--- a/net/minecraft/world/item/HangingEntityItem.java
++++ b/net/minecraft/world/item/HangingEntityItem.java
+@@ -17,38 +17,41 @@
+ import net.minecraft.world.entity.decoration.ItemFrame;
+ import net.minecraft.world.entity.decoration.Painting;
+ import net.minecraft.world.entity.decoration.PaintingVariant;
+-import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.item.context.UseOnContext;
+ 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;
+
+- public HangingEntityItem(EntityType<? extends HangingEntity> entitytype, Item.Properties item_properties) {
+- super(item_properties);
+- this.type = entitytype;
++ public HangingEntityItem(EntityType<? extends HangingEntity> type, Item.Properties properties) {
++ super(properties);
++ this.type = type;
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- BlockPos blockpos = useoncontext.getClickedPos();
+- Direction direction = useoncontext.getClickedFace();
+- BlockPos blockpos1 = blockpos.relative(direction);
+- Player player = useoncontext.getPlayer();
+- ItemStack itemstack = useoncontext.getItemInHand();
++ public InteractionResult useOn(UseOnContext context) {
++ BlockPos blockposition = context.getClickedPos();
++ Direction enumdirection = context.getClickedFace();
++ BlockPos blockposition1 = blockposition.relative(enumdirection);
++ net.minecraft.world.entity.player.Player entityhuman = context.getPlayer();
++ ItemStack itemstack = context.getItemInHand();
+
+- if (player != null && !this.mayPlace(player, direction, itemstack, blockpos1)) {
++ if (entityhuman != null && !this.mayPlace(entityhuman, enumdirection, itemstack, blockposition1)) {
+ return InteractionResult.FAIL;
+ } else {
+- Level level = useoncontext.getLevel();
++ Level world = context.getLevel();
+ Object object;
+
+ if (this.type == EntityType.PAINTING) {
+- Optional<Painting> optional = Painting.create(level, blockpos1, direction);
++ Optional<Painting> optional = Painting.create(world, blockposition1, enumdirection);
+
+ if (optional.isEmpty()) {
+ return InteractionResult.CONSUME;
+@@ -56,61 +59,73 @@
+
+ object = (HangingEntity) optional.get();
+ } else if (this.type == EntityType.ITEM_FRAME) {
+- object = new ItemFrame(level, blockpos1, direction);
++ object = new ItemFrame(world, blockposition1, enumdirection);
+ } else {
+ if (this.type != EntityType.GLOW_ITEM_FRAME) {
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ }
+
+- object = new GlowItemFrame(level, blockpos1, direction);
++ object = new GlowItemFrame(world, blockposition1, enumdirection);
+ }
+
+- CompoundTag compoundtag = itemstack.getTag();
++ CompoundTag nbttagcompound = itemstack.getTag();
+
+- if (compoundtag != null) {
+- EntityType.updateCustomEntityTag(level, player, (Entity) object, compoundtag);
++ if (nbttagcompound != null) {
++ EntityType.updateCustomEntityTag(world, entityhuman, (Entity) object, nbttagcompound);
+ }
+
+ if (((HangingEntity) object).survives()) {
+- if (!level.isClientSide) {
++ 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();
+- level.gameEvent((Entity) player, GameEvent.ENTITY_PLACE, ((HangingEntity) object).position());
+- level.addFreshEntity((Entity) object);
++ world.gameEvent((Entity) entityhuman, GameEvent.ENTITY_PLACE, ((HangingEntity) object).position());
++ world.addFreshEntity((Entity) object);
+ }
+
+ itemstack.shrink(1);
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.CONSUME;
+ }
+ }
+ }
+
+- protected boolean mayPlace(Player player, Direction direction, ItemStack itemstack, BlockPos blockpos) {
+- return !direction.getAxis().isVertical() && player.mayUseItemAt(blockpos, direction, itemstack);
++ protected boolean mayPlace(net.minecraft.world.entity.player.Player player, Direction direction, ItemStack hangingEntityStack, BlockPos pos) {
++ return !direction.getAxis().isVertical() && player.mayUseItemAt(pos, direction, hangingEntityStack);
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- super.appendHoverText(itemstack, level, list, tooltipflag);
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltipComponents, TooltipFlag isAdvanced) {
++ super.appendHoverText(stack, level, tooltipComponents, isAdvanced);
+ if (this.type == EntityType.PAINTING) {
+- CompoundTag compoundtag = itemstack.getTag();
++ CompoundTag nbttagcompound = stack.getTag();
+
+- if (compoundtag != null && compoundtag.contains("EntityTag", 10)) {
+- CompoundTag compoundtag1 = compoundtag.getCompound("EntityTag");
++ if (nbttagcompound != null && nbttagcompound.contains("EntityTag", 10)) {
++ CompoundTag nbttagcompound1 = nbttagcompound.getCompound("EntityTag");
+
+- Painting.loadVariant(compoundtag1).ifPresentOrElse((holder) -> {
++ Painting.loadVariant(nbttagcompound1).ifPresentOrElse((holder) -> {
+ holder.unwrapKey().ifPresent((resourcekey) -> {
+- list.add(Component.translatable(resourcekey.location().toLanguageKey("painting", "title")).withStyle(ChatFormatting.YELLOW));
+- list.add(Component.translatable(resourcekey.location().toLanguageKey("painting", "author")).withStyle(ChatFormatting.GRAY));
++ tooltipComponents.add(Component.translatable(resourcekey.location().toLanguageKey("painting", "title")).withStyle(ChatFormatting.YELLOW));
++ tooltipComponents.add(Component.translatable(resourcekey.location().toLanguageKey("painting", "author")).withStyle(ChatFormatting.GRAY));
+ });
+- list.add(Component.translatable("painting.dimensions", Mth.positiveCeilDiv(((PaintingVariant) holder.value()).getWidth(), 16), Mth.positiveCeilDiv(((PaintingVariant) holder.value()).getHeight(), 16)));
++ tooltipComponents.add(Component.translatable("painting.dimensions", Mth.positiveCeilDiv(((PaintingVariant) holder.value()).getWidth(), 16), Mth.positiveCeilDiv(((PaintingVariant) holder.value()).getHeight(), 16)));
+ }, () -> {
+- list.add(HangingEntityItem.TOOLTIP_RANDOM_VARIANT);
++ tooltipComponents.add(HangingEntityItem.TOOLTIP_RANDOM_VARIANT);
+ });
+- } else if (tooltipflag.isCreative()) {
+- list.add(HangingEntityItem.TOOLTIP_RANDOM_VARIANT);
++ } else if (isAdvanced.isCreative()) {
++ tooltipComponents.add(HangingEntityItem.TOOLTIP_RANDOM_VARIANT);
+ }
+ }
+
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/ItemStack.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/ItemStack.java.patch
new file mode 100644
index 0000000000..d4e2ce6fd3
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/ItemStack.java.patch
@@ -0,0 +1,1314 @@
+--- a/net/minecraft/world/item/ItemStack.java
++++ b/net/minecraft/world/item/ItemStack.java
+@@ -28,6 +28,7 @@
+ import net.minecraft.advancements.CriteriaTriggers;
+ import net.minecraft.commands.arguments.blocks.BlockStateParser;
+ import net.minecraft.core.BlockPos;
++import net.minecraft.core.Direction;
+ import net.minecraft.core.Holder;
+ import net.minecraft.core.HolderSet;
+ import net.minecraft.core.Registry;
+@@ -35,6 +36,7 @@
+ import net.minecraft.core.registries.Registries;
+ import net.minecraft.nbt.CompoundTag;
+ import net.minecraft.nbt.ListTag;
++import net.minecraft.nbt.NbtOps;
+ import net.minecraft.nbt.Tag;
+ import net.minecraft.nbt.TagParser;
+ import net.minecraft.network.chat.CommonComponents;
+@@ -43,27 +45,24 @@
+ import net.minecraft.network.chat.HoverEvent;
+ import net.minecraft.network.chat.MutableComponent;
+ import net.minecraft.network.chat.Style;
++import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket;
+ import net.minecraft.resources.ResourceLocation;
+-import net.minecraft.server.level.ServerPlayer;
+-import net.minecraft.sounds.SoundEvent;
+-import net.minecraft.stats.Stats;
+ import net.minecraft.tags.TagKey;
+ import net.minecraft.util.ExtraCodecs;
+ import net.minecraft.util.RandomSource;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
++import net.minecraft.world.entity.EnumMonsterType;
+ import net.minecraft.world.entity.EquipmentSlot;
+ import net.minecraft.world.entity.LivingEntity;
+-import net.minecraft.world.entity.MobType;
+ import net.minecraft.world.entity.SlotAccess;
+ import net.minecraft.world.entity.ai.attributes.Attribute;
+ import net.minecraft.world.entity.ai.attributes.AttributeModifier;
+ import net.minecraft.world.entity.ai.attributes.Attributes;
+ import net.minecraft.world.entity.decoration.ItemFrame;
+ import net.minecraft.world.entity.item.ItemEntity;
+-import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.flag.FeatureFlagSet;
+ import net.minecraft.world.inventory.ClickAction;
+ import net.minecraft.world.inventory.Slot;
+@@ -74,13 +73,50 @@
+ import net.minecraft.world.item.enchantment.Enchantment;
+ import net.minecraft.world.item.enchantment.EnchantmentHelper;
+ import net.minecraft.world.item.enchantment.Enchantments;
+-import net.minecraft.world.level.ItemLike;
++import net.minecraft.world.level.IMaterial;
+ import net.minecraft.world.level.Level;
++import net.minecraft.world.level.block.BaseEntityBlock;
++import net.minecraft.world.level.block.BedBlock;
+ import net.minecraft.world.level.block.Block;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ 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) -> {
+@@ -131,7 +167,7 @@
+ /** @deprecated */
+ @Deprecated
+ @Nullable
+- private final Item item;
++ private Item item;
+ @Nullable
+ private CompoundTag tag;
+ @Nullable
+@@ -145,26 +181,26 @@
+ return this.getItem().getTooltipImage(this);
+ }
+
+- public ItemStack(ItemLike itemlike) {
+- this(itemlike, 1);
++ public ItemStack(IMaterial item) {
++ this(item, 1);
+ }
+
+- public ItemStack(Holder<Item> holder) {
+- this((ItemLike) holder.value(), 1);
++ public ItemStack(Holder<Item> tag) {
++ this((IMaterial) tag.value(), 1);
+ }
+
+- public ItemStack(Holder<Item> holder, int i, Optional<CompoundTag> optional) {
+- this(holder, i);
++ public ItemStack(Holder<Item> item, int count, Optional<CompoundTag> optional) {
++ this(item, count);
+ optional.ifPresent(this::setTag);
+ }
+
+- public ItemStack(Holder<Item> holder, int i) {
+- this((ItemLike) holder.value(), i);
++ public ItemStack(Holder<Item> item, int count) {
++ this((IMaterial) item.value(), count);
+ }
+
+- public ItemStack(ItemLike itemlike, int i) {
+- this.item = itemlike.asItem();
+- this.count = i;
++ public ItemStack(IMaterial item, int count) {
++ this.item = item.asItem();
++ this.count = count;
+ if (this.item.canBeDepleted()) {
+ this.setDamageValue(this.getDamageValue());
+ }
+@@ -175,11 +211,22 @@
+ this.item = null;
+ }
+
+- private ItemStack(CompoundTag compoundtag) {
+- this.item = (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);
+ }
+
+@@ -189,11 +236,16 @@
+
+ }
+
+- public static ItemStack of(CompoundTag compoundtag) {
++ private ItemStack(CompoundTag compoundTag) {
++ this.load(compoundTag);
++ // CraftBukkit end
++ }
++
++ public static ItemStack of(CompoundTag compoundTag) {
+ try {
+- return new ItemStack(compoundtag);
++ return new ItemStack(compoundTag);
+ } catch (RuntimeException runtimeexception) {
+- ItemStack.LOGGER.debug("Tried to load invalid item: {}", compoundtag, runtimeexception);
++ ItemStack.LOGGER.debug("Tried to load invalid item: {}", compoundTag, runtimeexception);
+ return ItemStack.EMPTY;
+ }
+ }
+@@ -202,12 +254,12 @@
+ return this == ItemStack.EMPTY || this.item == Items.AIR || this.count <= 0;
+ }
+
+- public boolean isItemEnabled(FeatureFlagSet featureflagset) {
+- return this.isEmpty() || this.getItem().isEnabled(featureflagset);
++ public boolean isItemEnabled(FeatureFlagSet enabledFlags) {
++ return this.isEmpty() || this.getItem().isEnabled(enabledFlags);
+ }
+
+- public ItemStack split(int i) {
+- int j = Math.min(i, this.getCount());
++ public ItemStack split(int amount) {
++ int j = Math.min(amount, this.getCount());
+ ItemStack itemstack = this.copyWithCount(j);
+
+ this.shrink(j);
+@@ -233,20 +285,20 @@
+ return this.getItem().builtInRegistryHolder();
+ }
+
+- public boolean is(TagKey<Item> tagkey) {
+- return this.getItem().builtInRegistryHolder().is(tagkey);
++ public boolean is(TagKey<Item> tag) {
++ return this.getItem().builtInRegistryHolder().is(tag);
+ }
+
+ public boolean is(Item item) {
+ return this.getItem() == item;
+ }
+
+- public boolean is(Predicate<Holder<Item>> predicate) {
+- return predicate.test(this.getItem().builtInRegistryHolder());
++ public boolean is(Predicate<Holder<Item>> item) {
++ return item.test(this.getItem().builtInRegistryHolder());
+ }
+
+- public boolean is(Holder<Item> holder) {
+- return this.getItem().builtInRegistryHolder() == holder;
++ public boolean is(Holder<Item> item) {
++ return this.getItem().builtInRegistryHolder() == item;
+ }
+
+ public boolean is(HolderSet<Item> holderset) {
+@@ -257,47 +309,226 @@
+ return this.getItem().builtInRegistryHolder().tags();
+ }
+
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Player player = useoncontext.getPlayer();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockInWorld blockinworld = new BlockInWorld(useoncontext.getLevel(), blockpos, false);
++ public InteractionResult useOn(UseOnContext context) {
++ net.minecraft.world.entity.player.Player entityhuman = context.getPlayer();
++ BlockPos blockposition = context.getClickedPos();
++ BlockInWorld shapedetectorblock = new BlockInWorld(context.getLevel(), blockposition, false);
+
+- if (player != null && !player.getAbilities().mayBuild && !this.hasAdventureModePlaceTagForBlock(useoncontext.getLevel().registryAccess().registryOrThrow(Registries.BLOCK), blockinworld)) {
++ if (entityhuman != null && !entityhuman.getAbilities().mayBuild && !this.hasAdventureModePlaceTagForBlock(context.getLevel().registryAccess().registryOrThrow(Registries.BLOCK), shapedetectorblock)) {
+ return InteractionResult.PASS;
+ } else {
+ Item item = this.getItem();
+- InteractionResult interactionresult = item.useOn(useoncontext);
++ // CraftBukkit start - handle all block place event logic here
++ CompoundTag oldData = this.getTagClone();
++ int oldCount = this.getCount();
++ ServerLevel world = (ServerLevel) context.getLevel();
+
+- if (player != null && interactionresult.shouldAwardStats()) {
+- player.awardStat(Stats.ITEM_USED.get(item));
++ if (!(item instanceof BucketItem || item instanceof SolidBucketItem)) { // if not bucket
++ world.captureBlockStates = true;
++ // special case bonemeal
++ if (item == Items.BONE_MEAL) {
++ world.captureTreeGeneration = true;
++ }
+ }
++ InteractionResult enuminteractionresult;
++ try {
++ enuminteractionresult = item.useOn(context);
++ } finally {
++ world.captureBlockStates = false;
++ }
++ CompoundTag newData = this.getTagClone();
++ int newCount = this.getCount();
++ this.setCount(oldCount);
++ this.setTagClone(oldData);
++ if (enuminteractionresult.consumesAction() && world.captureTreeGeneration && world.capturedBlockStates.size() > 0) {
++ world.captureTreeGeneration = false;
++ Location location = CraftLocation.toBukkit(blockposition, world.getWorld());
++ TreeType treeType = SaplingBlock.treeType;
++ SaplingBlock.treeType = null;
++ List<CraftBlockState> blocks = new java.util.ArrayList<>(world.capturedBlockStates.values());
++ world.capturedBlockStates.clear();
++ StructureGrowEvent structureEvent = null;
++ if (treeType != null) {
++ boolean isBonemeal = getItem() == Items.BONE_MEAL;
++ structureEvent = new StructureGrowEvent(location, treeType, isBonemeal, (Player) entityhuman.getBukkitEntity(), (List< BlockState>) (List<? extends BlockState>) blocks);
++ org.bukkit.Bukkit.getPluginManager().callEvent(structureEvent);
++ }
+
+- 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;
+ }
+ }
+
+- public float getDestroySpeed(BlockState blockstate) {
+- return this.getItem().getDestroySpeed(this, blockstate);
++ public float getDestroySpeed(IBlockData state) {
++ return this.getItem().getDestroySpeed(this, state);
+ }
+
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- return this.getItem().use(level, player, interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, net.minecraft.world.entity.player.Player player, EnumHand usedHand) {
++ return this.getItem().use(level, player, usedHand);
+ }
+
+- public ItemStack finishUsingItem(Level level, LivingEntity livingentity) {
+- return this.getItem().finishUsingItem(this, level, livingentity);
++ public ItemStack finishUsingItem(Level level, LivingEntity livingEntity) {
++ return this.getItem().finishUsingItem(this, level, livingEntity);
+ }
+
+- public CompoundTag save(CompoundTag compoundtag) {
+- ResourceLocation resourcelocation = BuiltInRegistries.ITEM.getKey(this.getItem());
++ public CompoundTag save(CompoundTag compoundTag) {
++ ResourceLocation minecraftkey = BuiltInRegistries.ITEM.getKey(this.getItem());
+
+- compoundtag.putString("id", resourcelocation == null ? "minecraft:air" : resourcelocation.toString());
+- compoundtag.putByte("Count", (byte) this.count);
++ compoundTag.putString("id", minecraftkey == null ? "minecraft:air" : minecraftkey.toString());
++ compoundTag.putByte("Count", (byte) this.count);
+ if (this.tag != null) {
+- compoundtag.put("tag", this.tag.copy());
++ compoundTag.put("tag", this.tag.copy());
+ }
+
+- return compoundtag;
++ return compoundTag;
+ }
+
+ public int getMaxStackSize() {
+@@ -310,9 +541,9 @@
+
+ public boolean isDamageableItem() {
+ if (!this.isEmpty() && this.getItem().getMaxDamage() > 0) {
+- CompoundTag compoundtag = this.getTag();
++ CompoundTag nbttagcompound = this.getTag();
+
+- return compoundtag == null || !compoundtag.getBoolean("Unbreakable");
++ return nbttagcompound == null || !nbttagcompound.getBoolean("Unbreakable");
+ } else {
+ return false;
+ }
+@@ -326,56 +557,76 @@
+ return this.tag == null ? 0 : this.tag.getInt("Damage");
+ }
+
+- public void setDamageValue(int i) {
+- this.getOrCreateTag().putInt("Damage", Math.max(0, i));
++ public void setDamageValue(int damage) {
++ this.getOrCreateTag().putInt("Damage", Math.max(0, damage));
+ }
+
+ public int getMaxDamage() {
+ return this.getItem().getMaxDamage();
+ }
+
+- public boolean hurt(int i, RandomSource randomsource, @Nullable ServerPlayer serverplayer) {
++ public boolean hurt(int amount, RandomSource random, @Nullable ServerPlayer user) {
+ if (!this.isDamageableItem()) {
+ return false;
+ } else {
+ int j;
+
+- if (i > 0) {
++ if (amount > 0) {
+ j = EnchantmentHelper.getItemEnchantmentLevel(Enchantments.UNBREAKING, this);
+ int k = 0;
+
+- for (int l = 0; j > 0 && l < i; ++l) {
+- if (DigDurabilityEnchantment.shouldIgnoreDurabilityDrop(this, j, randomsource)) {
++ for (int l = 0; j > 0 && l < amount; ++l) {
++ if (DigDurabilityEnchantment.shouldIgnoreDurabilityDrop(this, j, random)) {
+ ++k;
+ }
+ }
+
+- i -= k;
+- if (i <= 0) {
++ 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;
+ }
+ }
+
+- if (serverplayer != null && i != 0) {
+- CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(serverplayer, this, this.getDamageValue() + i);
++ if (user != null && amount != 0) {
++ CriteriaTriggers.ITEM_DURABILITY_CHANGED.trigger(user, this, this.getDamageValue() + amount);
+ }
+
+- j = this.getDamageValue() + i;
++ j = this.getDamageValue() + amount;
+ this.setDamageValue(j);
+ return j >= this.getMaxDamage();
+ }
+ }
+
+- public <T extends LivingEntity> void hurtAndBreak(int i, T t0, Consumer<T> consumer) {
+- if (!t0.level().isClientSide && (!(t0 instanceof Player) || !((Player) t0).getAbilities().instabuild)) {
++ public <T extends LivingEntity> void hurtAndBreak(int amount, T entity, Consumer<T> onBroken) {
++ if (!entity.level().isClientSide && (!(entity instanceof net.minecraft.world.entity.player.Player) || !((net.minecraft.world.entity.player.Player) entity).getAbilities().instabuild)) {
+ if (this.isDamageableItem()) {
+- if (this.hurt(i, t0.getRandom(), t0 instanceof ServerPlayer ? (ServerPlayer) t0 : null)) {
+- consumer.accept(t0);
++ 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 (t0 instanceof Player) {
+- ((Player) t0).awardStat(Stats.ITEM_BROKEN.get(item));
++ if (entity instanceof net.minecraft.world.entity.player.Player) {
++ ((net.minecraft.world.entity.player.Player) entity).awardStat(Stats.ITEM_BROKEN.get(item));
+ }
+
+ this.setDamageValue(0);
+@@ -397,38 +648,38 @@
+ return this.getItem().getBarColor(this);
+ }
+
+- public boolean overrideStackedOnOther(Slot slot, ClickAction clickaction, Player player) {
+- return this.getItem().overrideStackedOnOther(this, slot, clickaction, player);
++ public boolean overrideStackedOnOther(Slot slot, ClickAction action, net.minecraft.world.entity.player.Player player) {
++ return this.getItem().overrideStackedOnOther(this, slot, action, player);
+ }
+
+- public boolean overrideOtherStackedOnMe(ItemStack itemstack, Slot slot, ClickAction clickaction, Player player, SlotAccess slotaccess) {
+- return this.getItem().overrideOtherStackedOnMe(this, itemstack, slot, clickaction, player, slotaccess);
++ public boolean overrideOtherStackedOnMe(ItemStack stack, Slot slot, ClickAction action, net.minecraft.world.entity.player.Player player, SlotAccess access) {
++ return this.getItem().overrideOtherStackedOnMe(this, stack, slot, action, player, access);
+ }
+
+- public void hurtEnemy(LivingEntity livingentity, Player player) {
++ public void hurtEnemy(LivingEntity entity, net.minecraft.world.entity.player.Player player) {
+ Item item = this.getItem();
+
+- if (item.hurtEnemy(this, livingentity, player)) {
++ if (item.hurtEnemy(this, entity, player)) {
+ player.awardStat(Stats.ITEM_USED.get(item));
+ }
+
+ }
+
+- public void mineBlock(Level level, BlockState blockstate, BlockPos blockpos, Player player) {
++ public void mineBlock(Level level, IBlockData state, BlockPos pos, net.minecraft.world.entity.player.Player player) {
+ Item item = this.getItem();
+
+- if (item.mineBlock(this, level, blockstate, blockpos, player)) {
++ if (item.mineBlock(this, level, state, pos, player)) {
+ player.awardStat(Stats.ITEM_USED.get(item));
+ }
+
+ }
+
+- public boolean isCorrectToolForDrops(BlockState blockstate) {
+- return this.getItem().isCorrectToolForDrops(blockstate);
++ public boolean isCorrectToolForDrops(IBlockData state) {
++ return this.getItem().isCorrectToolForDrops(state);
+ }
+
+- public InteractionResult interactLivingEntity(Player player, LivingEntity livingentity, InteractionHand interactionhand) {
+- return this.getItem().interactLivingEntity(this, player, livingentity, interactionhand);
++ public InteractionResult interactLivingEntity(net.minecraft.world.entity.player.Player player, LivingEntity entity, EnumHand usedHand) {
++ return this.getItem().interactLivingEntity(this, player, entity, usedHand);
+ }
+
+ public ItemStack copy() {
+@@ -446,70 +697,69 @@
+ }
+ }
+
+- public ItemStack copyWithCount(int i) {
++ public ItemStack copyWithCount(int count) {
+ if (this.isEmpty()) {
+ return ItemStack.EMPTY;
+ } else {
+ ItemStack itemstack = this.copy();
+
+- itemstack.setCount(i);
++ itemstack.setCount(count);
+ return itemstack;
+ }
+ }
+
+- public static boolean matches(ItemStack itemstack, ItemStack itemstack1) {
+- return itemstack == itemstack1 ? true : (itemstack.getCount() != itemstack1.getCount() ? false : isSameItemSameTags(itemstack, itemstack1));
++ public static boolean matches(ItemStack stack, ItemStack other) {
++ return stack == other ? true : (stack.getCount() != other.getCount() ? false : isSameItemSameTags(stack, other));
+ }
+
+- public static boolean isSameItem(ItemStack itemstack, ItemStack itemstack1) {
+- return itemstack.is(itemstack1.getItem());
++ public static boolean isSameItem(ItemStack stack, ItemStack other) {
++ return stack.is(other.getItem());
+ }
+
+- public static boolean isSameItemSameTags(ItemStack itemstack, ItemStack itemstack1) {
+- return !itemstack.is(itemstack1.getItem()) ? false : (itemstack.isEmpty() && itemstack1.isEmpty() ? true : Objects.equals(itemstack.tag, itemstack1.tag));
++ public static boolean isSameItemSameTags(ItemStack stack, ItemStack other) {
++ return !stack.is(other.getItem()) ? false : (stack.isEmpty() && other.isEmpty() ? true : Objects.equals(stack.tag, other.tag));
+ }
+
+ public String getDescriptionId() {
+ return this.getItem().getDescriptionId(this);
+ }
+
+- @Override
+ public String toString() {
+ int i = this.getCount();
+
+ return i + " " + this.getItem();
+ }
+
+- public void inventoryTick(Level level, Entity entity, int i, boolean flag) {
++ public void inventoryTick(Level level, Entity entity, int inventorySlot, boolean isCurrentItem) {
+ if (this.popTime > 0) {
+ --this.popTime;
+ }
+
+ if (this.getItem() != null) {
+- this.getItem().inventoryTick(this, level, entity, i, flag);
++ this.getItem().inventoryTick(this, level, entity, inventorySlot, isCurrentItem);
+ }
+
+ }
+
+- public void onCraftedBy(Level level, Player player, int i) {
+- player.awardStat(Stats.ITEM_CRAFTED.get(this.getItem()), i);
++ public void onCraftedBy(Level level, net.minecraft.world.entity.player.Player player, int amount) {
++ player.awardStat(Stats.ITEM_CRAFTED.get(this.getItem()), amount);
+ this.getItem().onCraftedBy(this, level, player);
+ }
+
+- public void onCraftedBySystem(Level level) {
+- this.getItem().onCraftedPostProcess(this, level);
++ public void onCraftedBySystem(Level world) {
++ this.getItem().onCraftedPostProcess(this, world);
+ }
+
+ public int getUseDuration() {
+ return this.getItem().getUseDuration(this);
+ }
+
+- public UseAnim getUseAnimation() {
++ public EnumAnimation getUseAnimation() {
+ return this.getItem().getUseAnimation(this);
+ }
+
+- public void releaseUsing(Level level, LivingEntity livingentity, int i) {
+- this.getItem().releaseUsing(this, level, livingentity, i);
++ public void releaseUsing(Level level, LivingEntity livingEntity, int timeLeft) {
++ this.getItem().releaseUsing(this, level, livingEntity, timeLeft);
+ }
+
+ public boolean useOnRelease() {
+@@ -525,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());
+@@ -533,25 +794,25 @@
+ return this.tag;
+ }
+
+- public CompoundTag getOrCreateTagElement(String s) {
+- if (this.tag != null && this.tag.contains(s, 10)) {
+- return this.tag.getCompound(s);
++ public CompoundTag getOrCreateTagElement(String key) {
++ if (this.tag != null && this.tag.contains(key, 10)) {
++ return this.tag.getCompound(key);
+ } else {
+- CompoundTag compoundtag = new CompoundTag();
++ CompoundTag nbttagcompound = new CompoundTag();
+
+- this.addTagElement(s, compoundtag);
+- return compoundtag;
++ this.addTagElement(key, nbttagcompound);
++ return nbttagcompound;
+ }
+ }
+
+ @Nullable
+- public CompoundTag getTagElement(String s) {
+- return this.tag != null && this.tag.contains(s, 10) ? this.tag.getCompound(s) : null;
++ public CompoundTag getTagElement(String key) {
++ return this.tag != null && this.tag.contains(key, 10) ? this.tag.getCompound(key) : null;
+ }
+
+- public void removeTagKey(String s) {
+- if (this.tag != null && this.tag.contains(s)) {
+- this.tag.remove(s);
++ public void removeTagKey(String key) {
++ if (this.tag != null && this.tag.contains(key)) {
++ this.tag.remove(key);
+ if (this.tag.isEmpty()) {
+ this.tag = null;
+ }
+@@ -563,56 +824,56 @@
+ return this.tag != null ? this.tag.getList("Enchantments", 10) : new ListTag();
+ }
+
+- public void setTag(@Nullable CompoundTag compoundtag) {
+- this.tag = compoundtag;
++ public void setTag(@Nullable CompoundTag compoundTag) {
++ this.tag = compoundTag;
+ if (this.getItem().canBeDepleted()) {
+ this.setDamageValue(this.getDamageValue());
+ }
+
+- if (compoundtag != null) {
+- this.getItem().verifyTagAfterLoad(compoundtag);
++ if (compoundTag != null) {
++ this.getItem().verifyTagAfterLoad(compoundTag);
+ }
+
+ }
+
+ public Component getHoverName() {
+- CompoundTag compoundtag = this.getTagElement("display");
++ CompoundTag nbttagcompound = this.getTagElement("display");
+
+- if (compoundtag != null && compoundtag.contains("Name", 8)) {
++ if (nbttagcompound != null && nbttagcompound.contains("Name", 8)) {
+ try {
+- MutableComponent mutablecomponent = Component.Serializer.fromJson(compoundtag.getString("Name"));
++ MutableComponent ichatmutablecomponent = Component.Serializer.fromJson(nbttagcompound.getString("Name"));
+
+- if (mutablecomponent != null) {
+- return mutablecomponent;
++ if (ichatmutablecomponent != null) {
++ return ichatmutablecomponent;
+ }
+
+- compoundtag.remove("Name");
++ nbttagcompound.remove("Name");
+ } catch (Exception exception) {
+- compoundtag.remove("Name");
++ nbttagcompound.remove("Name");
+ }
+ }
+
+ return this.getItem().getName(this);
+ }
+
+- public ItemStack setHoverName(@Nullable Component component) {
+- CompoundTag compoundtag = this.getOrCreateTagElement("display");
++ public ItemStack setHoverName(@Nullable Component nameComponent) {
++ CompoundTag nbttagcompound = this.getOrCreateTagElement("display");
+
+- if (component != null) {
+- compoundtag.putString("Name", Component.Serializer.toJson(component));
++ if (nameComponent != null) {
++ nbttagcompound.putString("Name", Component.Serializer.toJson(nameComponent));
+ } else {
+- compoundtag.remove("Name");
++ nbttagcompound.remove("Name");
+ }
+
+ return this;
+ }
+
+ public void resetHoverName() {
+- CompoundTag compoundtag = this.getTagElement("display");
++ CompoundTag nbttagcompound = this.getTagElement("display");
+
+- if (compoundtag != null) {
+- compoundtag.remove("Name");
+- if (compoundtag.isEmpty()) {
++ if (nbttagcompound != null) {
++ nbttagcompound.remove("Name");
++ if (nbttagcompound.isEmpty()) {
+ this.removeTagKey("display");
+ }
+ }
+@@ -624,21 +885,21 @@
+ }
+
+ public boolean hasCustomHoverName() {
+- CompoundTag compoundtag = this.getTagElement("display");
++ CompoundTag nbttagcompound = this.getTagElement("display");
+
+- return compoundtag != null && compoundtag.contains("Name", 8);
++ return nbttagcompound != null && nbttagcompound.contains("Name", 8);
+ }
+
+- public List<Component> getTooltipLines(@Nullable Player player, TooltipFlag tooltipflag) {
++ public List<Component> getTooltipLines(@Nullable net.minecraft.world.entity.player.Player player, TooltipFlag isAdvanced) {
+ List<Component> list = Lists.newArrayList();
+- MutableComponent mutablecomponent = Component.empty().append(this.getHoverName()).withStyle(this.getRarity().color);
++ MutableComponent ichatmutablecomponent = Component.empty().append(this.getHoverName()).withStyle(this.getRarity().color);
+
+ if (this.hasCustomHoverName()) {
+- mutablecomponent.withStyle(ChatFormatting.ITALIC);
++ ichatmutablecomponent.withStyle(ChatFormatting.ITALIC);
+ }
+
+- list.add(mutablecomponent);
+- if (!tooltipflag.isAdvanced() && !this.hasCustomHoverName() && this.is(Items.FILLED_MAP)) {
++ list.add(ichatmutablecomponent);
++ if (!isAdvanced.isAdvanced() && !this.hasCustomHoverName() && this.is(Items.FILLED_MAP)) {
+ Integer integer = MapItem.getMapId(this);
+
+ if (integer != null) {
+@@ -648,46 +909,46 @@
+
+ int i = this.getHideFlags();
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.ADDITIONAL)) {
+- this.getItem().appendHoverText(this, player == null ? null : player.level(), list, tooltipflag);
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.ADDITIONAL)) {
++ this.getItem().appendHoverText(this, player == null ? null : player.level(), list, isAdvanced);
+ }
+
+ int j;
+
+ if (this.hasTag()) {
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.UPGRADES) && player != null) {
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.UPGRADES) && player != null) {
+ ArmorTrim.appendUpgradeHoverText(this, player.level().registryAccess(), list);
+ }
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.ENCHANTMENTS)) {
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.ENCHANTMENTS)) {
+ appendEnchantmentNames(list, this.getEnchantmentTags());
+ }
+
+ if (this.tag.contains("display", 10)) {
+- CompoundTag compoundtag = this.tag.getCompound("display");
++ CompoundTag nbttagcompound = this.tag.getCompound("display");
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.DYE) && compoundtag.contains("color", 99)) {
+- if (tooltipflag.isAdvanced()) {
+- list.add(Component.translatable("item.color", String.format(Locale.ROOT, "#%06X", compoundtag.getInt("color"))).withStyle(ChatFormatting.GRAY));
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.DYE) && nbttagcompound.contains("color", 99)) {
++ if (isAdvanced.isAdvanced()) {
++ list.add(Component.translatable("item.color", String.format(Locale.ROOT, "#%06X", nbttagcompound.getInt("color"))).withStyle(ChatFormatting.GRAY));
+ } else {
+ list.add(Component.translatable("item.dyed").withStyle(ChatFormatting.GRAY, ChatFormatting.ITALIC));
+ }
+ }
+
+- if (compoundtag.getTagType("Lore") == 9) {
+- ListTag listtag = compoundtag.getList("Lore", 8);
++ if (nbttagcompound.getTagType("Lore") == 9) {
++ ListTag nbttaglist = nbttagcompound.getList("Lore", 8);
+
+- for (j = 0; j < listtag.size(); ++j) {
+- String s = listtag.getString(j);
++ for (j = 0; j < nbttaglist.size(); ++j) {
++ String s = nbttaglist.getString(j);
+
+ try {
+- MutableComponent mutablecomponent1 = Component.Serializer.fromJson(s);
++ MutableComponent ichatmutablecomponent1 = Component.Serializer.fromJson(s);
+
+- if (mutablecomponent1 != null) {
+- list.add(ComponentUtils.mergeStyles(mutablecomponent1, ItemStack.LORE_STYLE));
++ if (ichatmutablecomponent1 != null) {
++ list.add(ComponentUtils.mergeStyles(ichatmutablecomponent1, ItemStack.LORE_STYLE));
+ }
+ } catch (Exception exception) {
+- compoundtag.remove("Lore");
++ nbttagcompound.remove("Lore");
+ }
+ }
+ }
+@@ -696,18 +957,18 @@
+
+ int k;
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.MODIFIERS)) {
+- EquipmentSlot[] aequipmentslot = EquipmentSlot.values();
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.MODIFIERS)) {
++ EquipmentSlot[] aenumitemslot = EquipmentSlot.values();
+
+- k = aequipmentslot.length;
++ k = aenumitemslot.length;
+
+ for (j = 0; j < k; ++j) {
+- EquipmentSlot equipmentslot = aequipmentslot[j];
+- Multimap<Attribute, AttributeModifier> multimap = this.getAttributeModifiers(equipmentslot);
++ EquipmentSlot enumitemslot = aenumitemslot[j];
++ Multimap<Attribute, AttributeModifier> multimap = this.getAttributeModifiers(enumitemslot);
+
+ if (!multimap.isEmpty()) {
+ list.add(CommonComponents.EMPTY);
+- list.add(Component.translatable("item.modifiers." + equipmentslot.getName()).withStyle(ChatFormatting.GRAY));
++ list.add(Component.translatable("item.modifiers." + enumitemslot.getName()).withStyle(ChatFormatting.GRAY));
+ Iterator iterator = multimap.entries().iterator();
+
+ while (iterator.hasNext()) {
+@@ -719,7 +980,7 @@
+ if (player != null) {
+ if (attributemodifier.getId() == Item.BASE_ATTACK_DAMAGE_UUID) {
+ d0 += player.getAttributeBaseValue(Attributes.ATTACK_DAMAGE);
+- d0 += (double) EnchantmentHelper.getDamageBonus(this, MobType.UNDEFINED);
++ d0 += (double) EnchantmentHelper.getDamageBonus(this, EnumMonsterType.UNDEFINED);
+ flag = true;
+ } else if (attributemodifier.getId() == Item.BASE_ATTACK_SPEED_UUID) {
+ d0 += player.getAttributeBaseValue(Attributes.ATTACK_SPEED);
+@@ -753,38 +1014,38 @@
+ }
+
+ if (this.hasTag()) {
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.UNBREAKABLE) && this.tag.getBoolean("Unbreakable")) {
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.UNBREAKABLE) && this.tag.getBoolean("Unbreakable")) {
+ list.add(Component.translatable("item.unbreakable").withStyle(ChatFormatting.BLUE));
+ }
+
+- ListTag listtag1;
++ ListTag nbttaglist1;
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.CAN_DESTROY) && this.tag.contains("CanDestroy", 9)) {
+- listtag1 = this.tag.getList("CanDestroy", 8);
+- if (!listtag1.isEmpty()) {
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.CAN_DESTROY) && this.tag.contains("CanDestroy", 9)) {
++ nbttaglist1 = this.tag.getList("CanDestroy", 8);
++ if (!nbttaglist1.isEmpty()) {
+ list.add(CommonComponents.EMPTY);
+ list.add(Component.translatable("item.canBreak").withStyle(ChatFormatting.GRAY));
+
+- for (k = 0; k < listtag1.size(); ++k) {
+- list.addAll(expandBlockState(listtag1.getString(k)));
++ for (k = 0; k < nbttaglist1.size(); ++k) {
++ list.addAll(expandBlockState(nbttaglist1.getString(k)));
+ }
+ }
+ }
+
+- if (shouldShowInTooltip(i, ItemStack.TooltipPart.CAN_PLACE) && this.tag.contains("CanPlaceOn", 9)) {
+- listtag1 = this.tag.getList("CanPlaceOn", 8);
+- if (!listtag1.isEmpty()) {
++ if (shouldShowInTooltip(i, ItemStack.HideFlags.CAN_PLACE) && this.tag.contains("CanPlaceOn", 9)) {
++ nbttaglist1 = this.tag.getList("CanPlaceOn", 8);
++ if (!nbttaglist1.isEmpty()) {
+ list.add(CommonComponents.EMPTY);
+ list.add(Component.translatable("item.canPlace").withStyle(ChatFormatting.GRAY));
+
+- for (k = 0; k < listtag1.size(); ++k) {
+- list.addAll(expandBlockState(listtag1.getString(k)));
++ for (k = 0; k < nbttaglist1.size(); ++k) {
++ list.addAll(expandBlockState(nbttaglist1.getString(k)));
+ }
+ }
+ }
+ }
+
+- if (tooltipflag.isAdvanced()) {
++ if (isAdvanced.isAdvanced()) {
+ if (this.isDamaged()) {
+ list.add(Component.translatable("item.durability", this.getMaxDamage() - this.getDamageValue(), this.getMaxDamage()));
+ }
+@@ -802,37 +1063,37 @@
+ return list;
+ }
+
+- private static boolean shouldShowInTooltip(int i, ItemStack.TooltipPart itemstack_tooltippart) {
+- return (i & itemstack_tooltippart.getMask()) == 0;
++ private static boolean shouldShowInTooltip(int hideFlags, ItemStack.HideFlags part) {
++ return (hideFlags & part.getMask()) == 0;
+ }
+
+ private int getHideFlags() {
+ return this.hasTag() && this.tag.contains("HideFlags", 99) ? this.tag.getInt("HideFlags") : 0;
+ }
+
+- public void hideTooltipPart(ItemStack.TooltipPart itemstack_tooltippart) {
+- CompoundTag compoundtag = this.getOrCreateTag();
++ public void hideTooltipPart(ItemStack.HideFlags part) {
++ CompoundTag nbttagcompound = this.getOrCreateTag();
+
+- compoundtag.putInt("HideFlags", compoundtag.getInt("HideFlags") | itemstack_tooltippart.getMask());
++ nbttagcompound.putInt("HideFlags", nbttagcompound.getInt("HideFlags") | part.getMask());
+ }
+
+- public static void appendEnchantmentNames(List<Component> list, ListTag listtag) {
+- for (int i = 0; i < listtag.size(); ++i) {
+- CompoundTag compoundtag = listtag.getCompound(i);
++ public static void appendEnchantmentNames(List<Component> tooltipComponents, ListTag storedEnchantments) {
++ for (int i = 0; i < storedEnchantments.size(); ++i) {
++ CompoundTag nbttagcompound = storedEnchantments.getCompound(i);
+
+- BuiltInRegistries.ENCHANTMENT.getOptional(EnchantmentHelper.getEnchantmentId(compoundtag)).ifPresent((enchantment) -> {
+- list.add(enchantment.getFullname(EnchantmentHelper.getEnchantmentLevel(compoundtag)));
++ BuiltInRegistries.ENCHANTMENT.getOptional(EnchantmentHelper.getEnchantmentId(nbttagcompound)).ifPresent((enchantment) -> {
++ tooltipComponents.add(enchantment.getFullname(EnchantmentHelper.getEnchantmentLevel(nbttagcompound)));
+ });
+ }
+
+ }
+
+- private static Collection<Component> expandBlockState(String s) {
++ private static Collection<Component> expandBlockState(String stateString) {
+ try {
+- return (Collection) BlockStateParser.parseForTesting(BuiltInRegistries.BLOCK.asLookup(), s, true).map((blockstateparser_blockresult) -> {
+- return Lists.newArrayList(new Component[]{blockstateparser_blockresult.blockState().getBlock().getName().withStyle(ChatFormatting.DARK_GRAY)});
+- }, (blockstateparser_tagresult) -> {
+- return (List) blockstateparser_tagresult.tag().stream().map((holder) -> {
++ return (Collection) BlockStateParser.parseForTesting(BuiltInRegistries.BLOCK.asLookup(), stateString, true).map((argumentblock_a) -> {
++ return Lists.newArrayList(new Component[]{argumentblock_a.blockState().getBlock().getName().withStyle(ChatFormatting.DARK_GRAY)});
++ }, (argumentblock_b) -> {
++ return (List) argumentblock_b.tag().stream().map((holder) -> {
+ return ((Block) holder.value()).getName().withStyle(ChatFormatting.DARK_GRAY);
+ }).collect(Collectors.toList());
+ });
+@@ -853,23 +1114,23 @@
+ return !this.getItem().isEnchantable(this) ? false : !this.isEnchanted();
+ }
+
+- public void enchant(Enchantment enchantment, int i) {
++ public void enchant(Enchantment enchantment, int level) {
+ this.getOrCreateTag();
+ if (!this.tag.contains("Enchantments", 9)) {
+ this.tag.put("Enchantments", new ListTag());
+ }
+
+- ListTag listtag = this.tag.getList("Enchantments", 10);
++ ListTag nbttaglist = this.tag.getList("Enchantments", 10);
+
+- listtag.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) i));
++ nbttaglist.add(EnchantmentHelper.storeEnchantment(EnchantmentHelper.getEnchantmentId(enchantment), (byte) level));
+ }
+
+ public boolean isEnchanted() {
+ return this.tag != null && this.tag.contains("Enchantments", 9) ? !this.tag.getList("Enchantments", 10).isEmpty() : false;
+ }
+
+- public void addTagElement(String s, Tag tag) {
+- this.getOrCreateTag().put(s, tag);
++ public void addTagElement(String key, Tag tag) {
++ this.getOrCreateTag().put(key, tag);
+ }
+
+ public boolean isFramed() {
+@@ -894,30 +1155,30 @@
+ return this.hasTag() && this.tag.contains("RepairCost", 3) ? this.tag.getInt("RepairCost") : 0;
+ }
+
+- public void setRepairCost(int i) {
+- if (i > 0) {
+- this.getOrCreateTag().putInt("RepairCost", i);
++ public void setRepairCost(int cost) {
++ if (cost > 0) {
++ this.getOrCreateTag().putInt("RepairCost", cost);
+ } else {
+ this.removeTagKey("RepairCost");
+ }
+
+ }
+
+- public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlot equipmentslot) {
++ public Multimap<Attribute, AttributeModifier> getAttributeModifiers(EquipmentSlot slot) {
+ Object object;
+
+ if (this.hasTag() && this.tag.contains("AttributeModifiers", 9)) {
+ object = HashMultimap.create();
+- ListTag listtag = this.tag.getList("AttributeModifiers", 10);
++ ListTag nbttaglist = this.tag.getList("AttributeModifiers", 10);
+
+- for (int i = 0; i < listtag.size(); ++i) {
+- CompoundTag compoundtag = listtag.getCompound(i);
++ for (int i = 0; i < nbttaglist.size(); ++i) {
++ CompoundTag nbttagcompound = nbttaglist.getCompound(i);
+
+- if (!compoundtag.contains("Slot", 8) || compoundtag.getString("Slot").equals(equipmentslot.getName())) {
+- Optional<Attribute> optional = BuiltInRegistries.ATTRIBUTE.getOptional(ResourceLocation.tryParse(compoundtag.getString("AttributeName")));
++ if (!nbttagcompound.contains("Slot", 8) || nbttagcompound.getString("Slot").equals(slot.getName())) {
++ Optional<Attribute> optional = BuiltInRegistries.ATTRIBUTE.getOptional(ResourceLocation.tryParse(nbttagcompound.getString("AttributeName")));
+
+ if (!optional.isEmpty()) {
+- AttributeModifier attributemodifier = AttributeModifier.load(compoundtag);
++ AttributeModifier attributemodifier = AttributeModifier.load(nbttagcompound);
+
+ if (attributemodifier != null && attributemodifier.getId().getLeastSignificantBits() != 0L && attributemodifier.getId().getMostSignificantBits() != 0L) {
+ ((Multimap) object).put((Attribute) optional.get(), attributemodifier);
+@@ -926,93 +1187,100 @@
+ }
+ }
+ } else {
+- object = this.getItem().getDefaultAttributeModifiers(equipmentslot);
++ object = this.getItem().getDefaultAttributeModifiers(slot);
+ }
+
+ return (Multimap) object;
+ }
+
+- public void addAttributeModifier(Attribute attribute, AttributeModifier attributemodifier, @Nullable EquipmentSlot equipmentslot) {
++ public void addAttributeModifier(Attribute attribute, AttributeModifier modifier, @Nullable EquipmentSlot slot) {
+ this.getOrCreateTag();
+ if (!this.tag.contains("AttributeModifiers", 9)) {
+ this.tag.put("AttributeModifiers", new ListTag());
+ }
+
+- ListTag listtag = this.tag.getList("AttributeModifiers", 10);
+- CompoundTag compoundtag = attributemodifier.save();
++ ListTag nbttaglist = this.tag.getList("AttributeModifiers", 10);
++ CompoundTag nbttagcompound = modifier.save();
+
+- compoundtag.putString("AttributeName", BuiltInRegistries.ATTRIBUTE.getKey(attribute).toString());
+- if (equipmentslot != null) {
+- compoundtag.putString("Slot", equipmentslot.getName());
++ nbttagcompound.putString("AttributeName", BuiltInRegistries.ATTRIBUTE.getKey(attribute).toString());
++ if (slot != null) {
++ nbttagcompound.putString("Slot", slot.getName());
+ }
+
+- listtag.add(compoundtag);
++ nbttaglist.add(nbttagcompound);
+ }
+
++ // CraftBukkit start
++ @Deprecated
++ public void setItem(Item item) {
++ this.item = item;
++ }
++ // CraftBukkit end
++
+ public Component getDisplayName() {
+- MutableComponent mutablecomponent = Component.empty().append(this.getHoverName());
++ MutableComponent ichatmutablecomponent = Component.empty().append(this.getHoverName());
+
+ if (this.hasCustomHoverName()) {
+- mutablecomponent.withStyle(ChatFormatting.ITALIC);
++ ichatmutablecomponent.withStyle(ChatFormatting.ITALIC);
+ }
+
+- MutableComponent mutablecomponent1 = ComponentUtils.wrapInSquareBrackets(mutablecomponent);
++ MutableComponent ichatmutablecomponent1 = ComponentUtils.wrapInSquareBrackets(ichatmutablecomponent);
+
+ if (!this.isEmpty()) {
+- mutablecomponent1.withStyle(this.getRarity().color).withStyle((style) -> {
+- return style.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(this)));
++ ichatmutablecomponent1.withStyle(this.getRarity().color).withStyle((chatmodifier) -> {
++ return chatmodifier.withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, new HoverEvent.ItemStackInfo(this)));
+ });
+ }
+
+- return mutablecomponent1;
++ return ichatmutablecomponent1;
+ }
+
+- public boolean hasAdventureModePlaceTagForBlock(Registry<Block> registry, BlockInWorld blockinworld) {
++ public boolean hasAdventureModePlaceTagForBlock(Registry<Block> blockRegistry, BlockInWorld block) {
+ if (this.adventurePlaceCheck == null) {
+ this.adventurePlaceCheck = new AdventureModeCheck("CanPlaceOn");
+ }
+
+- return this.adventurePlaceCheck.test(this, registry, blockinworld);
++ return this.adventurePlaceCheck.test(this, blockRegistry, block);
+ }
+
+- public boolean hasAdventureModeBreakTagForBlock(Registry<Block> registry, BlockInWorld blockinworld) {
++ public boolean hasAdventureModeBreakTagForBlock(Registry<Block> blockRegistry, BlockInWorld block) {
+ if (this.adventureBreakCheck == null) {
+ this.adventureBreakCheck = new AdventureModeCheck("CanDestroy");
+ }
+
+- return this.adventureBreakCheck.test(this, registry, blockinworld);
++ return this.adventureBreakCheck.test(this, blockRegistry, block);
+ }
+
+ public int getPopTime() {
+ return this.popTime;
+ }
+
+- public void setPopTime(int i) {
+- this.popTime = i;
++ public void setPopTime(int popTime) {
++ this.popTime = popTime;
+ }
+
+ public int getCount() {
+ return this.isEmpty() ? 0 : this.count;
+ }
+
+- public void setCount(int i) {
+- this.count = i;
++ public void setCount(int count) {
++ this.count = count;
+ }
+
+- public void grow(int i) {
+- this.setCount(this.getCount() + i);
++ public void grow(int increment) {
++ this.setCount(this.getCount() + increment);
+ }
+
+- public void shrink(int i) {
+- this.grow(-i);
++ public void shrink(int decrement) {
++ this.grow(-decrement);
+ }
+
+- public void onUseTick(Level level, LivingEntity livingentity, int i) {
+- this.getItem().onUseTick(level, livingentity, this, i);
++ public void onUseTick(Level level, LivingEntity livingEntity, int count) {
++ this.getItem().onUseTick(level, livingEntity, this, count);
+ }
+
+- public void onDestroyed(ItemEntity itementity) {
+- this.getItem().onDestroyed(itementity);
++ public void onDestroyed(ItemEntity itemEntity) {
++ this.getItem().onDestroyed(itemEntity);
+ }
+
+ public boolean isEdible() {
+@@ -1027,13 +1295,13 @@
+ return this.getItem().getEatingSound();
+ }
+
+- public static enum TooltipPart {
++ public static enum HideFlags {
+
+ ENCHANTMENTS, MODIFIERS, UNBREAKABLE, CAN_DESTROY, CAN_PLACE, ADDITIONAL, DYE, UPGRADES;
+
+ private final int mask = 1 << this.ordinal();
+
+- private TooltipPart() {}
++ private HideFlags() {}
+
+ public int getMask() {
+ return this.mask;
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/LeadItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/LeadItem.java.patch
new file mode 100644
index 0000000000..3e499c1786
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/LeadItem.java.patch
@@ -0,0 +1,119 @@
+--- a/net/minecraft/world/item/LeadItem.java
++++ b/net/minecraft/world/item/LeadItem.java
+@@ -11,64 +11,90 @@
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.item.context.UseOnContext;
+ import net.minecraft.world.level.Level;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ 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 item_properties) {
+- super(item_properties);
++ public LeadItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (blockstate.is(BlockTags.FENCES)) {
+- Player player = useoncontext.getPlayer();
++ if (iblockdata.is(BlockTags.FENCES)) {
++ Player entityhuman = context.getPlayer();
+
+- if (!level.isClientSide && player != null) {
+- bindPlayerMobs(player, level, blockpos);
++ if (!world.isClientSide && entityhuman != null) {
++ bindPlayerMobs(entityhuman, world, blockposition, context.getHand()); // CraftBukkit - Pass hand
+ }
+
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.PASS;
+ }
+ }
+
+- public static InteractionResult bindPlayerMobs(Player player, Level level, BlockPos blockpos) {
+- 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 d0 = 7.0D;
+- int i = blockpos.getX();
+- int j = blockpos.getY();
+- int k = blockpos.getZ();
+- List<Mob> list = level.getEntitiesOfClass(Mob.class, new AABB((double) i - 7.0D, (double) j - 7.0D, (double) k - 7.0D, (double) i + 7.0D, (double) j + 7.0D, (double) k + 7.0D));
++ int i = blockposition.getX();
++ int j = blockposition.getY();
++ int k = blockposition.getZ();
++ List<Mob> list = world.getEntitiesOfClass(Mob.class, new AABB((double) i - 7.0D, (double) j - 7.0D, (double) k - 7.0D, (double) i + 7.0D, (double) j + 7.0D, (double) k + 7.0D));
+ Iterator iterator = list.iterator();
+
+ while (iterator.hasNext()) {
+- Mob mob = (Mob) iterator.next();
++ Mob entityinsentient = (Mob) iterator.next();
+
+- if (mob.getLeashHolder() == player) {
+- if (leashfenceknotentity == null) {
+- leashfenceknotentity = LeashFenceKnotEntity.getOrCreateKnot(level, blockpos);
+- leashfenceknotentity.playPlacementSound();
++ 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;
+ }
+ }
+
+ if (flag) {
+- level.gameEvent(GameEvent.BLOCK_ATTACH, blockpos, GameEvent.Context.of((Entity) player));
++ world.gameEvent(GameEvent.BLOCK_ATTACH, blockposition, GameEvent.Context.of((Entity) entityhuman));
+ }
+
+ 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-spigotflower/net/minecraft/world/item/MapItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/MapItem.java.patch
new file mode 100644
index 0000000000..393489499f
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/MapItem.java.patch
@@ -0,0 +1,548 @@
+--- a/net/minecraft/world/item/MapItem.java
++++ b/net/minecraft/world/item/MapItem.java
+@@ -26,7 +26,7 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.biome.Biome;
+ import net.minecraft.world.level.block.Blocks;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.chunk.LevelChunk;
+ import net.minecraft.world.level.levelgen.Heightmap;
+ import net.minecraft.world.level.material.FluidState;
+@@ -42,80 +42,80 @@
+ public static final String MAP_SCALE_TAG = "map_scale_direction";
+ public static final String MAP_LOCK_TAG = "map_to_lock";
+
+- public MapItem(Item.Properties item_properties) {
+- super(item_properties);
++ public MapItem(Item.Properties properties) {
++ super(properties);
+ }
+
+- public static ItemStack create(Level level, int i, int j, byte b0, boolean flag, boolean flag1) {
++ public static ItemStack create(Level level, int levelX, int levelZ, byte scale, boolean trackingPosition, boolean unlimitedTracking) {
+ ItemStack itemstack = new ItemStack(Items.FILLED_MAP);
+
+- createAndStoreSavedData(itemstack, level, i, j, b0, flag, flag1, level.dimension());
++ createAndStoreSavedData(itemstack, level, levelX, levelZ, scale, trackingPosition, unlimitedTracking, level.dimension());
+ return itemstack;
+ }
+
+ @Nullable
+- public static MapItemSavedData getSavedData(@Nullable Integer integer, Level level) {
+- return integer == null ? null : level.getMapData(makeKey(integer));
++ public static MapItemSavedData getSavedData(@Nullable Integer mapId, Level level) {
++ return mapId == null ? null : level.getMapData(makeKey(mapId));
+ }
+
+ @Nullable
+- public static MapItemSavedData getSavedData(ItemStack itemstack, Level level) {
+- Integer integer = getMapId(itemstack);
++ public static MapItemSavedData getSavedData(ItemStack stack, Level level) {
++ Integer integer = getMapId(stack);
+
+ return getSavedData(integer, level);
+ }
+
+ @Nullable
+- public static Integer getMapId(ItemStack itemstack) {
+- CompoundTag compoundtag = itemstack.getTag();
++ public static Integer getMapId(ItemStack stack) {
++ CompoundTag nbttagcompound = stack.getTag();
+
+- return compoundtag != null && compoundtag.contains("map", 99) ? compoundtag.getInt("map") : null;
++ return nbttagcompound != null && nbttagcompound.contains("map", 99) ? nbttagcompound.getInt("map") : -1; // CraftBukkit - make new maps for no tag
+ }
+
+- private static int createNewSavedData(Level level, int i, int j, int k, boolean flag, boolean flag1, ResourceKey<Level> resourcekey) {
+- MapItemSavedData mapitemsaveddata = MapItemSavedData.createFresh((double) i, (double) j, (byte) k, flag, flag1, resourcekey);
++ public static int createNewSavedData(Level level, int x, int z, int scale, boolean trackingPosition, boolean unlimitedTracking, ResourceKey<Level> dimension) {
++ MapItemSavedData worldmap = MapItemSavedData.createFresh((double) x, (double) z, (byte) scale, trackingPosition, unlimitedTracking, dimension);
+ int l = level.getFreeMapId();
+
+- level.setMapData(makeKey(l), mapitemsaveddata);
++ level.setMapData(makeKey(l), worldmap);
+ return l;
+ }
+
+- private static void storeMapData(ItemStack itemstack, int i) {
+- itemstack.getOrCreateTag().putInt("map", i);
++ private static void storeMapData(ItemStack stack, int mapId) {
++ stack.getOrCreateTag().putInt("map", mapId);
+ }
+
+- private static void createAndStoreSavedData(ItemStack itemstack, Level level, int i, int j, int k, boolean flag, boolean flag1, ResourceKey<Level> resourcekey) {
+- int l = createNewSavedData(level, i, j, k, flag, flag1, resourcekey);
++ private static void createAndStoreSavedData(ItemStack stack, Level level, int x, int z, int scale, boolean trackingPosition, boolean unlimitedTracking, ResourceKey<Level> dimension) {
++ int l = createNewSavedData(level, x, z, scale, trackingPosition, unlimitedTracking, dimension);
+
+- storeMapData(itemstack, l);
++ storeMapData(stack, l);
+ }
+
+- public static String makeKey(int i) {
+- return "map_" + i;
++ public static String makeKey(int mapId) {
++ return "map_" + mapId;
+ }
+
+- public void update(Level level, Entity entity, MapItemSavedData mapitemsaveddata) {
+- if (level.dimension() == mapitemsaveddata.dimension && entity instanceof Player) {
+- int i = 1 << mapitemsaveddata.scale;
+- int j = mapitemsaveddata.centerX;
+- int k = mapitemsaveddata.centerZ;
+- int l = Mth.floor(entity.getX() - (double) j) / i + 64;
+- int i1 = Mth.floor(entity.getZ() - (double) k) / i + 64;
++ public void update(Level level, Entity viewer, MapItemSavedData data) {
++ if (level.dimension() == data.dimension && viewer instanceof Player) {
++ int i = 1 << data.scale;
++ int j = data.centerX;
++ int k = data.centerZ;
++ int l = Mth.floor(viewer.getX() - (double) j) / i + 64;
++ int i1 = Mth.floor(viewer.getZ() - (double) k) / i + 64;
+ int j1 = 128 / i;
+
+ if (level.dimensionType().hasCeiling()) {
+ j1 /= 2;
+ }
+
+- MapItemSavedData.HoldingPlayer mapitemsaveddata_holdingplayer = mapitemsaveddata.getHoldingPlayer((Player) entity);
++ MapItemSavedData.HoldingPlayer worldmap_worldmaphumantracker = data.getHoldingPlayer((Player) viewer);
+
+- ++mapitemsaveddata_holdingplayer.step;
+- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos();
+- BlockPos.MutableBlockPos blockpos_mutableblockpos1 = new BlockPos.MutableBlockPos();
++ ++worldmap_worldmaphumantracker.step;
++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
++ BlockPos.MutableBlockPos blockposition_mutableblockposition1 = new BlockPos.MutableBlockPos();
+ boolean flag = false;
+
+ for (int k1 = l - j1 + 1; k1 < l + j1; ++k1) {
+- if ((k1 & 15) == (mapitemsaveddata_holdingplayer.step & 15) || flag) {
++ if ((k1 & 15) == (worldmap_worldmaphumantracker.step & 15) || flag) {
+ flag = false;
+ double d0 = 0.0D;
+
+@@ -126,9 +126,9 @@
+ int j2 = (j / i + k1 - 64) * i;
+ int k2 = (k / i + l1 - 64) * i;
+ Multiset<MapColor> multiset = LinkedHashMultiset.create();
+- LevelChunk levelchunk = level.getChunk(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2));
++ LevelChunk chunk = level.getChunk(SectionPos.blockToSectionCoord(j2), SectionPos.blockToSectionCoord(k2));
+
+- if (!levelchunk.isEmpty()) {
++ if (!chunk.isEmpty()) {
+ int l2 = 0;
+ double d1 = 0.0D;
+ int i3;
+@@ -146,71 +146,71 @@
+ } else {
+ for (i3 = 0; i3 < i; ++i3) {
+ for (int j3 = 0; j3 < i; ++j3) {
+- blockpos_mutableblockpos.set(j2 + i3, 0, k2 + j3);
+- int k3 = levelchunk.getHeight(Heightmap.Types.WORLD_SURFACE, blockpos_mutableblockpos.getX(), blockpos_mutableblockpos.getZ()) + 1;
+- BlockState blockstate;
++ blockposition_mutableblockposition.set(j2 + i3, 0, k2 + j3);
++ int k3 = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, blockposition_mutableblockposition.getX(), blockposition_mutableblockposition.getZ()) + 1;
++ IBlockData iblockdata;
+
+ if (k3 > level.getMinBuildHeight() + 1) {
+ do {
+ --k3;
+- blockpos_mutableblockpos.setY(k3);
+- blockstate = levelchunk.getBlockState(blockpos_mutableblockpos);
+- } while (blockstate.getMapColor(level, blockpos_mutableblockpos) == MapColor.NONE && k3 > level.getMinBuildHeight());
++ blockposition_mutableblockposition.setY(k3);
++ iblockdata = chunk.getBlockState(blockposition_mutableblockposition);
++ } while (iblockdata.getMapColor(level, blockposition_mutableblockposition) == MapColor.NONE && k3 > level.getMinBuildHeight());
+
+- if (k3 > level.getMinBuildHeight() && !blockstate.getFluidState().isEmpty()) {
++ if (k3 > level.getMinBuildHeight() && !iblockdata.getFluidState().isEmpty()) {
+ int l3 = k3 - 1;
+
+- blockpos_mutableblockpos1.set(blockpos_mutableblockpos);
++ blockposition_mutableblockposition1.set(blockposition_mutableblockposition);
+
+- BlockState blockstate1;
++ IBlockData iblockdata1;
+
+ do {
+- blockpos_mutableblockpos1.setY(l3--);
+- blockstate1 = levelchunk.getBlockState(blockpos_mutableblockpos1);
++ blockposition_mutableblockposition1.setY(l3--);
++ iblockdata1 = chunk.getBlockState(blockposition_mutableblockposition1);
+ ++l2;
+- } while (l3 > level.getMinBuildHeight() && !blockstate1.getFluidState().isEmpty());
++ } while (l3 > level.getMinBuildHeight() && !iblockdata1.getFluidState().isEmpty());
+
+- blockstate = this.getCorrectStateForFluidBlock(level, blockstate, blockpos_mutableblockpos);
++ iblockdata = this.getCorrectStateForFluidBlock(level, iblockdata, blockposition_mutableblockposition);
+ }
+ } else {
+- blockstate = Blocks.BEDROCK.defaultBlockState();
++ iblockdata = Blocks.BEDROCK.defaultBlockState();
+ }
+
+- mapitemsaveddata.checkBanners(level, blockpos_mutableblockpos.getX(), blockpos_mutableblockpos.getZ());
++ data.checkBanners(level, blockposition_mutableblockposition.getX(), blockposition_mutableblockposition.getZ());
+ d1 += (double) k3 / (double) (i * i);
+- multiset.add(blockstate.getMapColor(level, blockpos_mutableblockpos));
++ multiset.add(iblockdata.getMapColor(level, blockposition_mutableblockposition));
+ }
+ }
+ }
+
+ l2 /= i * i;
+- MapColor mapcolor = (MapColor) Iterables.getFirst(Multisets.copyHighestCountFirst(multiset), MapColor.NONE);
++ MapColor materialmapcolor = (MapColor) Iterables.getFirst(Multisets.copyHighestCountFirst(multiset), MapColor.NONE);
+ double d2;
+- MapColor.Brightness mapcolor_brightness;
++ MapColor.Brightness materialmapcolor_a;
+
+- if (mapcolor == MapColor.WATER) {
++ if (materialmapcolor == MapColor.WATER) {
+ d2 = (double) l2 * 0.1D + (double) (k1 + l1 & 1) * 0.2D;
+ if (d2 < 0.5D) {
+- mapcolor_brightness = MapColor.Brightness.HIGH;
++ materialmapcolor_a = MapColor.Brightness.HIGH;
+ } else if (d2 > 0.9D) {
+- mapcolor_brightness = MapColor.Brightness.LOW;
++ materialmapcolor_a = MapColor.Brightness.LOW;
+ } else {
+- mapcolor_brightness = MapColor.Brightness.NORMAL;
++ materialmapcolor_a = MapColor.Brightness.NORMAL;
+ }
+ } else {
+ d2 = (d1 - d0) * 4.0D / (double) (i + 4) + ((double) (k1 + l1 & 1) - 0.5D) * 0.4D;
+ if (d2 > 0.6D) {
+- mapcolor_brightness = MapColor.Brightness.HIGH;
++ materialmapcolor_a = MapColor.Brightness.HIGH;
+ } else if (d2 < -0.6D) {
+- mapcolor_brightness = MapColor.Brightness.LOW;
++ materialmapcolor_a = MapColor.Brightness.LOW;
+ } else {
+- mapcolor_brightness = MapColor.Brightness.NORMAL;
++ materialmapcolor_a = MapColor.Brightness.NORMAL;
+ }
+ }
+
+ d0 = d1;
+ if (l1 >= 0 && i2 < j1 * j1 && (!flag1 || (k1 + l1 & 1) != 0)) {
+- flag |= mapitemsaveddata.updateColor(k1, l1, mapcolor.getPackedId(mapcolor_brightness));
++ flag |= data.updateColor(k1, l1, materialmapcolor.getPackedId(materialmapcolor_a));
+ }
+ }
+ }
+@@ -221,35 +221,35 @@
+ }
+ }
+
+- private BlockState getCorrectStateForFluidBlock(Level level, BlockState blockstate, BlockPos blockpos) {
+- FluidState fluidstate = blockstate.getFluidState();
++ private IBlockData getCorrectStateForFluidBlock(Level level, IBlockData state, BlockPos pos) {
++ FluidState fluid = state.getFluidState();
+
+- return !fluidstate.isEmpty() && !blockstate.isFaceSturdy(level, blockpos, Direction.UP) ? fluidstate.createLegacyBlock() : blockstate;
++ return !fluid.isEmpty() && !state.isFaceSturdy(level, pos, Direction.UP) ? fluid.createLegacyBlock() : state;
+ }
+
+- private static boolean isBiomeWatery(boolean[] aboolean, int i, int j) {
+- return aboolean[j * 128 + i];
++ private static boolean isBiomeWatery(boolean[] wateryMap, int xSample, int zSample) {
++ return wateryMap[zSample * 128 + xSample];
+ }
+
+- public static void renderBiomePreviewMap(ServerLevel serverlevel, ItemStack itemstack) {
+- MapItemSavedData mapitemsaveddata = getSavedData(itemstack, serverlevel);
++ public static void renderBiomePreviewMap(ServerLevel serverLevel, ItemStack stack) {
++ MapItemSavedData worldmap = getSavedData(stack, serverLevel);
+
+- if (mapitemsaveddata != null) {
+- if (serverlevel.dimension() == mapitemsaveddata.dimension) {
+- int i = 1 << mapitemsaveddata.scale;
+- int j = mapitemsaveddata.centerX;
+- int k = mapitemsaveddata.centerZ;
++ if (worldmap != null) {
++ if (serverLevel.dimension() == worldmap.dimension) {
++ int i = 1 << worldmap.scale;
++ int j = worldmap.centerX;
++ int k = worldmap.centerZ;
+ boolean[] aboolean = new boolean[16384];
+ int l = j / i - 64;
+ int i1 = k / i - 64;
+- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos();
++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+
+ int j1;
+ int k1;
+
+ for (j1 = 0; j1 < 128; ++j1) {
+ for (k1 = 0; k1 < 128; ++k1) {
+- Holder<Biome> holder = serverlevel.getBiome(blockpos_mutableblockpos.set((l + k1) * i, 0, (i1 + j1) * i));
++ Holder<Biome> holder = serverLevel.getBiome(blockposition_mutableblockposition.set((l + k1) * i, 0, (i1 + j1) * i));
+
+ aboolean[j1 * 128 + k1] = holder.is(BiomeTags.WATER_ON_MAP_OUTLINES);
+ }
+@@ -267,44 +267,44 @@
+ }
+ }
+
+- MapColor.Brightness mapcolor_brightness = MapColor.Brightness.LOWEST;
+- MapColor mapcolor = MapColor.NONE;
++ MapColor.Brightness materialmapcolor_a = MapColor.Brightness.LOWEST;
++ MapColor materialmapcolor = MapColor.NONE;
+
+ if (isBiomeWatery(aboolean, j1, k1)) {
+- mapcolor = MapColor.COLOR_ORANGE;
++ materialmapcolor = MapColor.COLOR_ORANGE;
+ if (l1 > 7 && k1 % 2 == 0) {
+ switch ((j1 + (int) (Mth.sin((float) k1 + 0.0F) * 7.0F)) / 8 % 5) {
+ case 0:
+ case 4:
+- mapcolor_brightness = MapColor.Brightness.LOW;
++ materialmapcolor_a = MapColor.Brightness.LOW;
+ break;
+ case 1:
+ case 3:
+- mapcolor_brightness = MapColor.Brightness.NORMAL;
++ materialmapcolor_a = MapColor.Brightness.NORMAL;
+ break;
+ case 2:
+- mapcolor_brightness = MapColor.Brightness.HIGH;
++ materialmapcolor_a = MapColor.Brightness.HIGH;
+ }
+ } else if (l1 > 7) {
+- mapcolor = MapColor.NONE;
++ materialmapcolor = MapColor.NONE;
+ } else if (l1 > 5) {
+- mapcolor_brightness = MapColor.Brightness.NORMAL;
++ materialmapcolor_a = MapColor.Brightness.NORMAL;
+ } else if (l1 > 3) {
+- mapcolor_brightness = MapColor.Brightness.LOW;
++ materialmapcolor_a = MapColor.Brightness.LOW;
+ } else if (l1 > 1) {
+- mapcolor_brightness = MapColor.Brightness.LOW;
++ materialmapcolor_a = MapColor.Brightness.LOW;
+ }
+ } else if (l1 > 0) {
+- mapcolor = MapColor.COLOR_BROWN;
++ materialmapcolor = MapColor.COLOR_BROWN;
+ if (l1 > 3) {
+- mapcolor_brightness = MapColor.Brightness.NORMAL;
++ materialmapcolor_a = MapColor.Brightness.NORMAL;
+ } else {
+- mapcolor_brightness = MapColor.Brightness.LOWEST;
++ materialmapcolor_a = MapColor.Brightness.LOWEST;
+ }
+ }
+
+- if (mapcolor != MapColor.NONE) {
+- mapitemsaveddata.setColor(j1, k1, mapcolor.getPackedId(mapcolor_brightness));
++ if (materialmapcolor != MapColor.NONE) {
++ worldmap.setColor(j1, k1, materialmapcolor.getPackedId(materialmapcolor_a));
+ }
+ }
+ }
+@@ -314,20 +314,19 @@
+ }
+
+ @Override
+- @Override
+- public void inventoryTick(ItemStack itemstack, Level level, Entity entity, int i, boolean flag) {
++ public void inventoryTick(ItemStack stack, Level level, Entity entity, int itemSlot, boolean isSelected) {
+ if (!level.isClientSide) {
+- MapItemSavedData mapitemsaveddata = getSavedData(itemstack, level);
++ MapItemSavedData worldmap = getSavedData(stack, level);
+
+- if (mapitemsaveddata != null) {
++ if (worldmap != null) {
+ if (entity instanceof Player) {
+- Player player = (Player) entity;
++ Player entityhuman = (Player) entity;
+
+- mapitemsaveddata.tickCarriedBy(player, itemstack);
++ worldmap.tickCarriedBy(entityhuman, stack);
+ }
+
+- if (!mapitemsaveddata.locked && (flag || entity instanceof Player && ((Player) entity).getOffhandItem() == itemstack)) {
+- this.update(level, entity, mapitemsaveddata);
++ if (!worldmap.locked && (isSelected || entity instanceof Player && ((Player) entity).getOffhandItem() == stack)) {
++ this.update(level, entity, worldmap);
+ }
+
+ }
+@@ -336,88 +335,85 @@
+
+ @Nullable
+ @Override
+- @Override
+- public Packet<?> getUpdatePacket(ItemStack itemstack, Level level, Player player) {
+- Integer integer = getMapId(itemstack);
+- MapItemSavedData mapitemsaveddata = getSavedData(integer, level);
++ public Packet<?> getUpdatePacket(ItemStack stack, Level level, Player player) {
++ Integer integer = getMapId(stack);
++ MapItemSavedData worldmap = getSavedData(integer, level);
+
+- return mapitemsaveddata != null ? mapitemsaveddata.getUpdatePacket(integer, player) : null;
++ return worldmap != null ? worldmap.getUpdatePacket(integer, player) : null;
+ }
+
+ @Override
+- @Override
+- public void onCraftedPostProcess(ItemStack itemstack, Level level) {
+- CompoundTag compoundtag = itemstack.getTag();
++ public void onCraftedPostProcess(ItemStack itemstack, Level world) {
++ CompoundTag nbttagcompound = itemstack.getTag();
+
+- if (compoundtag != null && compoundtag.contains("map_scale_direction", 99)) {
+- scaleMap(itemstack, level, compoundtag.getInt("map_scale_direction"));
+- compoundtag.remove("map_scale_direction");
+- } else if (compoundtag != null && compoundtag.contains("map_to_lock", 1) && compoundtag.getBoolean("map_to_lock")) {
+- lockMap(level, itemstack);
+- compoundtag.remove("map_to_lock");
++ if (nbttagcompound != null && nbttagcompound.contains("map_scale_direction", 99)) {
++ scaleMap(itemstack, world, nbttagcompound.getInt("map_scale_direction"));
++ nbttagcompound.remove("map_scale_direction");
++ } else if (nbttagcompound != null && nbttagcompound.contains("map_to_lock", 1) && nbttagcompound.getBoolean("map_to_lock")) {
++ lockMap(world, itemstack);
++ nbttagcompound.remove("map_to_lock");
+ }
+
+ }
+
+- private static void scaleMap(ItemStack itemstack, Level level, int i) {
+- MapItemSavedData mapitemsaveddata = getSavedData(itemstack, level);
++ private static void scaleMap(ItemStack stack, Level level, int scale) {
++ MapItemSavedData worldmap = getSavedData(stack, level);
+
+- if (mapitemsaveddata != null) {
++ if (worldmap != null) {
+ int j = level.getFreeMapId();
+
+- level.setMapData(makeKey(j), mapitemsaveddata.scaled(i));
+- storeMapData(itemstack, j);
++ level.setMapData(makeKey(j), worldmap.scaled(scale));
++ storeMapData(stack, j);
+ }
+
+ }
+
+- public static void lockMap(Level level, ItemStack itemstack) {
+- MapItemSavedData mapitemsaveddata = getSavedData(itemstack, level);
++ public static void lockMap(Level level, ItemStack stack) {
++ MapItemSavedData worldmap = getSavedData(stack, level);
+
+- if (mapitemsaveddata != null) {
++ if (worldmap != null) {
+ int i = level.getFreeMapId();
+ String s = makeKey(i);
+- MapItemSavedData mapitemsaveddata1 = mapitemsaveddata.locked();
++ MapItemSavedData worldmap1 = worldmap.locked();
+
+- level.setMapData(s, mapitemsaveddata1);
+- storeMapData(itemstack, i);
++ level.setMapData(s, worldmap1);
++ storeMapData(stack, i);
+ }
+
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- Integer integer = getMapId(itemstack);
+- MapItemSavedData mapitemsaveddata = level == null ? null : getSavedData(integer, level);
+- CompoundTag compoundtag = itemstack.getTag();
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
++ Integer integer = getMapId(stack);
++ MapItemSavedData worldmap = level == null ? null : getSavedData(integer, level);
++ CompoundTag nbttagcompound = stack.getTag();
+ boolean flag;
+ byte b0;
+
+- if (compoundtag != null) {
+- flag = compoundtag.getBoolean("map_to_lock");
+- b0 = compoundtag.getByte("map_scale_direction");
++ if (nbttagcompound != null) {
++ flag = nbttagcompound.getBoolean("map_to_lock");
++ b0 = nbttagcompound.getByte("map_scale_direction");
+ } else {
+ flag = false;
+ b0 = 0;
+ }
+
+- if (mapitemsaveddata != null && (mapitemsaveddata.locked || flag)) {
+- list.add(Component.translatable("filled_map.locked", integer).withStyle(ChatFormatting.GRAY));
++ if (worldmap != null && (worldmap.locked || flag)) {
++ tooltip.add(Component.translatable("filled_map.locked", integer).withStyle(ChatFormatting.GRAY));
+ }
+
+- if (tooltipflag.isAdvanced()) {
+- if (mapitemsaveddata != null) {
++ if (flag.isAdvanced()) {
++ if (worldmap != null) {
+ if (!flag && b0 == 0) {
+- list.add(getTooltipForId(integer));
++ tooltip.add(getTooltipForId(integer));
+ }
+
+- int i = Math.min(mapitemsaveddata.scale + b0, 4);
++ int i = Math.min(worldmap.scale + b0, 4);
+
+- list.add(Component.translatable("filled_map.scale", 1 << i).withStyle(ChatFormatting.GRAY));
+- list.add(Component.translatable("filled_map.level", i, 4).withStyle(ChatFormatting.GRAY));
++ tooltip.add(Component.translatable("filled_map.scale", 1 << i).withStyle(ChatFormatting.GRAY));
++ tooltip.add(Component.translatable("filled_map.level", i, 4).withStyle(ChatFormatting.GRAY));
+ } else {
+- list.add(Component.translatable("filled_map.unknown").withStyle(ChatFormatting.GRAY));
++ tooltip.add(Component.translatable("filled_map.unknown").withStyle(ChatFormatting.GRAY));
+ }
+ }
+
+@@ -431,11 +427,11 @@
+ return getTooltipForId(getMapId(itemstack));
+ }
+
+- public static int getColor(ItemStack itemstack) {
+- CompoundTag compoundtag = itemstack.getTagElement("display");
++ public static int getColor(ItemStack stack) {
++ CompoundTag nbttagcompound = stack.getTagElement("display");
+
+- if (compoundtag != null && compoundtag.contains("MapColor", 99)) {
+- int i = compoundtag.getInt("MapColor");
++ if (nbttagcompound != null && nbttagcompound.contains("MapColor", 99)) {
++ int i = nbttagcompound.getInt("MapColor");
+
+ return -16777216 | i & 16777215;
+ } else {
+@@ -444,22 +440,21 @@
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- BlockState blockstate = useoncontext.getLevel().getBlockState(useoncontext.getClickedPos());
++ public InteractionResult useOn(UseOnContext context) {
++ IBlockData iblockdata = context.getLevel().getBlockState(context.getClickedPos());
+
+- if (blockstate.is(BlockTags.BANNERS)) {
+- if (!useoncontext.getLevel().isClientSide) {
+- MapItemSavedData mapitemsaveddata = getSavedData(useoncontext.getItemInHand(), useoncontext.getLevel());
++ if (iblockdata.is(BlockTags.BANNERS)) {
++ if (!context.getLevel().isClientSide) {
++ MapItemSavedData worldmap = getSavedData(context.getItemInHand(), context.getLevel());
+
+- if (mapitemsaveddata != null && !mapitemsaveddata.toggleBanner(useoncontext.getLevel(), useoncontext.getClickedPos())) {
++ if (worldmap != null && !worldmap.toggleBanner(context.getLevel(), context.getClickedPos())) {
+ return InteractionResult.FAIL;
+ }
+ }
+
+- return InteractionResult.sidedSuccess(useoncontext.getLevel().isClientSide);
++ return InteractionResult.sidedSuccess(context.getLevel().isClientSide);
+ } else {
+- return super.useOn(useoncontext);
++ return super.useOn(context);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/MilkBucketItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/MilkBucketItem.java.patch
new file mode 100644
index 0000000000..f8e7e4b1eb
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/MilkBucketItem.java.patch
@@ -0,0 +1,74 @@
+--- a/net/minecraft/world/item/MilkBucketItem.java
++++ b/net/minecraft/world/item/MilkBucketItem.java
+@@ -3,7 +3,7 @@
+ import net.minecraft.advancements.CriteriaTriggers;
+ import net.minecraft.server.level.ServerPlayer;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.LivingEntity;
+ import net.minecraft.world.entity.player.Player;
+@@ -13,46 +13,42 @@
+
+ private static final int DRINK_DURATION = 32;
+
+- public MilkBucketItem(Item.Properties item_properties) {
+- super(item_properties);
++ public MilkBucketItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public ItemStack finishUsingItem(ItemStack itemstack, Level level, LivingEntity livingentity) {
+- if (livingentity instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) livingentity;
++ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entityLiving) {
++ if (entityLiving instanceof ServerPlayer) {
++ ServerPlayer entityplayer = (ServerPlayer) entityLiving;
+
+- CriteriaTriggers.CONSUME_ITEM.trigger(serverplayer, itemstack);
+- serverplayer.awardStat(Stats.ITEM_USED.get(this));
++ CriteriaTriggers.CONSUME_ITEM.trigger(entityplayer, stack);
++ entityplayer.awardStat(Stats.ITEM_USED.get(this));
+ }
+
+- if (livingentity instanceof Player && !((Player) livingentity).getAbilities().instabuild) {
+- itemstack.shrink(1);
++ if (entityLiving instanceof Player && !((Player) entityLiving).getAbilities().instabuild) {
++ stack.shrink(1);
+ }
+
+ if (!level.isClientSide) {
+- livingentity.removeAllEffects();
++ entityLiving.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.MILK); // CraftBukkit
+ }
+
+- return itemstack.isEmpty() ? new ItemStack(Items.BUCKET) : itemstack;
++ return stack.isEmpty() ? new ItemStack(Items.BUCKET) : stack;
+ }
+
+ @Override
+- @Override
+- public int getUseDuration(ItemStack itemstack) {
++ public int getUseDuration(ItemStack stack) {
+ return 32;
+ }
+
+ @Override
+- @Override
+- public UseAnim getUseAnimation(ItemStack itemstack) {
+- return UseAnim.DRINK;
++ public EnumAnimation getUseAnimation(ItemStack stack) {
++ return EnumAnimation.DRINK;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- return ItemUtils.startUsingInstantly(level, player, interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ return ItemUtils.startUsingInstantly(level, player, hand);
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/MinecartItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/MinecartItem.java.patch
new file mode 100644
index 0000000000..506e4c1f8e
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/MinecartItem.java.patch
@@ -0,0 +1,195 @@
+--- a/net/minecraft/world/item/MinecartItem.java
++++ b/net/minecraft/world/item/MinecartItem.java
+@@ -2,9 +2,9 @@
+
+ import net.minecraft.core.BlockPos;
+ import net.minecraft.core.Direction;
+-import net.minecraft.core.dispenser.BlockSource;
+ import net.minecraft.core.dispenser.DefaultDispenseItemBehavior;
+ import net.minecraft.core.dispenser.DispenseItemBehavior;
++import net.minecraft.core.dispenser.SourceBlock;
+ import net.minecraft.server.level.ServerLevel;
+ import net.minecraft.tags.BlockTags;
+ import net.minecraft.world.InteractionResult;
+@@ -14,10 +14,15 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.BaseRailBlock;
+ import net.minecraft.world.level.block.DispenserBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ 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 {
+
+@@ -25,90 +30,121 @@
+ private final DefaultDispenseItemBehavior defaultDispenseItemBehavior = new DefaultDispenseItemBehavior();
+
+ @Override
+- @Override
+- public ItemStack execute(BlockSource blocksource, ItemStack itemstack) {
+- Direction direction = (Direction) blocksource.state().getValue(DispenserBlock.FACING);
+- ServerLevel serverlevel = blocksource.level();
+- Vec3 vec3 = blocksource.center();
+- double d0 = vec3.x() + (double) direction.getStepX() * 1.125D;
+- double d1 = Math.floor(vec3.y()) + (double) direction.getStepY();
+- double d2 = vec3.z() + (double) direction.getStepZ() * 1.125D;
+- BlockPos blockpos = blocksource.pos().relative(direction);
+- BlockState blockstate = serverlevel.getBlockState(blockpos);
+- RailShape railshape = blockstate.getBlock() instanceof BaseRailBlock ? (RailShape) blockstate.getValue(((BaseRailBlock) blockstate.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
++ public ItemStack execute(SourceBlock sourceblock, ItemStack itemstack) {
++ Direction enumdirection = (Direction) sourceblock.state().getValue(DispenserBlock.FACING);
++ ServerLevel worldserver = sourceblock.level();
++ Vec3 vec3d = sourceblock.center();
++ double d0 = vec3d.x() + (double) enumdirection.getStepX() * 1.125D;
++ double d1 = Math.floor(vec3d.y()) + (double) enumdirection.getStepY();
++ double d2 = vec3d.z() + (double) enumdirection.getStepZ() * 1.125D;
++ BlockPos blockposition = sourceblock.pos().relative(enumdirection);
++ IBlockData iblockdata = worldserver.getBlockState(blockposition);
++ RailShape blockpropertytrackposition = iblockdata.getBlock() instanceof BaseRailBlock ? (RailShape) iblockdata.getValue(((BaseRailBlock) iblockdata.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
+ double d3;
+
+- if (blockstate.is(BlockTags.RAILS)) {
+- if (railshape.isAscending()) {
++ if (iblockdata.is(BlockTags.RAILS)) {
++ if (blockpropertytrackposition.isAscending()) {
+ d3 = 0.6D;
+ } else {
+ d3 = 0.1D;
+ }
+ } else {
+- if (!blockstate.isAir() || !serverlevel.getBlockState(blockpos.below()).is(BlockTags.RAILS)) {
+- return this.defaultDispenseItemBehavior.dispense(blocksource, itemstack);
++ if (!iblockdata.isAir() || !worldserver.getBlockState(blockposition.below()).is(BlockTags.RAILS)) {
++ return this.defaultDispenseItemBehavior.dispense(sourceblock, itemstack);
+ }
+
+- BlockState blockstate1 = serverlevel.getBlockState(blockpos.below());
+- RailShape railshape1 = blockstate1.getBlock() instanceof BaseRailBlock ? (RailShape) blockstate1.getValue(((BaseRailBlock) blockstate1.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
++ IBlockData iblockdata1 = worldserver.getBlockState(blockposition.below());
++ RailShape blockpropertytrackposition1 = iblockdata1.getBlock() instanceof BaseRailBlock ? (RailShape) iblockdata1.getValue(((BaseRailBlock) iblockdata1.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
+
+- if (direction != Direction.DOWN && railshape1.isAscending()) {
++ if (enumdirection != Direction.DOWN && blockpropertytrackposition1.isAscending()) {
+ d3 = -0.4D;
+ } else {
+ d3 = -0.9D;
+ }
+ }
+
+- AbstractMinecart abstractminecart = AbstractMinecart.createMinecart(serverlevel, d0, d1 + d3, d2, ((MinecartItem) itemstack.getItem()).type, itemstack, (Player) null);
++ // 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);
+
+- serverlevel.addFreshEntity(abstractminecart);
+- itemstack.shrink(1);
++ 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
+- @Override
+- protected void playSound(BlockSource blocksource) {
+- blocksource.level().levelEvent(1000, blocksource.pos(), 0);
++ protected void playSound(SourceBlock sourceblock) {
++ sourceblock.level().levelEvent(1000, sourceblock.pos(), 0);
+ }
+ };
+- final AbstractMinecart.Type type;
++ final AbstractMinecart.EnumMinecartType type;
+
+- public MinecartItem(AbstractMinecart.Type abstractminecart_type, Item.Properties item_properties) {
+- super(item_properties);
+- this.type = abstractminecart_type;
++ public MinecartItem(AbstractMinecart.EnumMinecartType type, Item.Properties properties) {
++ super(properties);
++ this.type = type;
+ DispenserBlock.registerBehavior(this, MinecartItem.DISPENSE_ITEM_BEHAVIOR);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (!blockstate.is(BlockTags.RAILS)) {
++ if (!iblockdata.is(BlockTags.RAILS)) {
+ return InteractionResult.FAIL;
+ } else {
+- ItemStack itemstack = useoncontext.getItemInHand();
++ ItemStack itemstack = context.getItemInHand();
+
+- if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) level;
+- RailShape railshape = blockstate.getBlock() instanceof BaseRailBlock ? (RailShape) blockstate.getValue(((BaseRailBlock) blockstate.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
++ if (world instanceof ServerLevel) {
++ ServerLevel worldserver = (ServerLevel) world;
++ RailShape blockpropertytrackposition = iblockdata.getBlock() instanceof BaseRailBlock ? (RailShape) iblockdata.getValue(((BaseRailBlock) iblockdata.getBlock()).getShapeProperty()) : RailShape.NORTH_SOUTH;
+ double d0 = 0.0D;
+
+- if (railshape.isAscending()) {
++ if (blockpropertytrackposition.isAscending()) {
+ d0 = 0.5D;
+ }
+
+- AbstractMinecart abstractminecart = AbstractMinecart.createMinecart(serverlevel, (double) blockpos.getX() + 0.5D, (double) blockpos.getY() + 0.0625D + d0, (double) blockpos.getZ() + 0.5D, this.type, itemstack, useoncontext.getPlayer());
++ 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());
+
+- serverlevel.addFreshEntity(abstractminecart);
+- serverlevel.gameEvent(GameEvent.ENTITY_PLACE, blockpos, GameEvent.Context.of(useoncontext.getPlayer(), serverlevel.getBlockState(blockpos.below())));
++ // 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())));
+ }
+
+ itemstack.shrink(1);
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/PotionItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/PotionItem.java.patch
new file mode 100644
index 0000000000..cdf203b6ae
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/PotionItem.java.patch
@@ -0,0 +1,185 @@
+--- a/net/minecraft/world/item/PotionItem.java
++++ b/net/minecraft/world/item/PotionItem.java
+@@ -14,7 +14,7 @@
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+ import net.minecraft.tags.BlockTags;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.effect.MobEffectInstance;
+@@ -26,125 +26,117 @@
+ import net.minecraft.world.item.context.UseOnContext;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.Blocks;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+ public class PotionItem extends Item {
+
+ private static final int DRINK_DURATION = 32;
+
+- public PotionItem(Item.Properties item_properties) {
+- super(item_properties);
++ public PotionItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+ public ItemStack getDefaultInstance() {
+ return PotionUtils.setPotion(super.getDefaultInstance(), Potions.WATER);
+ }
+
+ @Override
+- @Override
+- public ItemStack finishUsingItem(ItemStack itemstack, Level level, LivingEntity livingentity) {
+- Player player = livingentity instanceof Player ? (Player) livingentity : null;
++ public ItemStack finishUsingItem(ItemStack stack, Level level, LivingEntity entityLiving) {
++ Player entityhuman = entityLiving instanceof Player ? (Player) entityLiving : null;
+
+- if (player instanceof ServerPlayer) {
+- CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer) player, itemstack);
++ if (entityhuman instanceof ServerPlayer) {
++ CriteriaTriggers.CONSUME_ITEM.trigger((ServerPlayer) entityhuman, stack);
+ }
+
+ if (!level.isClientSide) {
+- List<MobEffectInstance> list = PotionUtils.getMobEffects(itemstack);
++ List<MobEffectInstance> list = PotionUtils.getMobEffects(stack);
+ Iterator iterator = list.iterator();
+
+ while (iterator.hasNext()) {
+- MobEffectInstance mobeffectinstance = (MobEffectInstance) iterator.next();
++ MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
+
+- if (mobeffectinstance.getEffect().isInstantenous()) {
+- mobeffectinstance.getEffect().applyInstantenousEffect(player, player, livingentity, mobeffectinstance.getAmplifier(), 1.0D);
++ if (mobeffect.getEffect().isInstantenous()) {
++ mobeffect.getEffect().applyInstantenousEffect(entityhuman, entityhuman, entityLiving, mobeffect.getAmplifier(), 1.0D);
+ } else {
+- livingentity.addEffect(new MobEffectInstance(mobeffectinstance));
++ entityLiving.addEffect(new MobEffectInstance(mobeffect), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.POTION_DRINK); // CraftBukkit
+ }
+ }
+ }
+
+- if (player != null) {
+- player.awardStat(Stats.ITEM_USED.get(this));
+- if (!player.getAbilities().instabuild) {
+- itemstack.shrink(1);
++ if (entityhuman != null) {
++ entityhuman.awardStat(Stats.ITEM_USED.get(this));
++ if (!entityhuman.getAbilities().instabuild) {
++ stack.shrink(1);
+ }
+ }
+
+- if (player == null || !player.getAbilities().instabuild) {
+- if (itemstack.isEmpty()) {
++ if (entityhuman == null || !entityhuman.getAbilities().instabuild) {
++ if (stack.isEmpty()) {
+ return new ItemStack(Items.GLASS_BOTTLE);
+ }
+
+- if (player != null) {
+- player.getInventory().add(new ItemStack(Items.GLASS_BOTTLE));
++ if (entityhuman != null) {
++ entityhuman.getInventory().add(new ItemStack(Items.GLASS_BOTTLE));
+ }
+ }
+
+- livingentity.gameEvent(GameEvent.DRINK);
+- return itemstack;
++ entityLiving.gameEvent(GameEvent.DRINK);
++ return stack;
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- Player player = useoncontext.getPlayer();
+- ItemStack itemstack = useoncontext.getItemInHand();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ Player entityhuman = context.getPlayer();
++ ItemStack itemstack = context.getItemInHand();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (useoncontext.getClickedFace() != Direction.DOWN && blockstate.is(BlockTags.CONVERTABLE_TO_MUD) && PotionUtils.getPotion(itemstack) == Potions.WATER) {
+- level.playSound((Player) null, blockpos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F);
+- player.setItemInHand(useoncontext.getHand(), ItemUtils.createFilledResult(itemstack, player, new ItemStack(Items.GLASS_BOTTLE)));
+- player.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
+- if (!level.isClientSide) {
+- ServerLevel serverlevel = (ServerLevel) level;
++ if (context.getClickedFace() != Direction.DOWN && iblockdata.is(BlockTags.CONVERTABLE_TO_MUD) && PotionUtils.getPotion(itemstack) == Potions.WATER) {
++ world.playSound((Player) null, blockposition, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1.0F, 1.0F);
++ entityhuman.setItemInHand(context.getHand(), ItemUtils.createFilledResult(itemstack, entityhuman, new ItemStack(Items.GLASS_BOTTLE)));
++ entityhuman.awardStat(Stats.ITEM_USED.get(itemstack.getItem()));
++ if (!world.isClientSide) {
++ ServerLevel worldserver = (ServerLevel) world;
+
+ for (int i = 0; i < 5; ++i) {
+- serverlevel.sendParticles(ParticleTypes.SPLASH, (double) blockpos.getX() + level.random.nextDouble(), (double) (blockpos.getY() + 1), (double) blockpos.getZ() + level.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D);
++ worldserver.sendParticles(ParticleTypes.SPLASH, (double) blockposition.getX() + world.random.nextDouble(), (double) (blockposition.getY() + 1), (double) blockposition.getZ() + world.random.nextDouble(), 1, 0.0D, 0.0D, 0.0D, 1.0D);
+ }
+ }
+
+- level.playSound((Player) null, blockpos, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
+- level.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockpos);
+- level.setBlockAndUpdate(blockpos, Blocks.MUD.defaultBlockState());
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ world.playSound((Player) null, blockposition, SoundEvents.BOTTLE_EMPTY, SoundSource.BLOCKS, 1.0F, 1.0F);
++ world.gameEvent((Entity) null, GameEvent.FLUID_PLACE, blockposition);
++ world.setBlockAndUpdate(blockposition, Blocks.MUD.defaultBlockState());
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.PASS;
+ }
+ }
+
+ @Override
+- @Override
+- public int getUseDuration(ItemStack itemstack) {
++ public int getUseDuration(ItemStack stack) {
+ return 32;
+ }
+
+ @Override
+- @Override
+- public UseAnim getUseAnimation(ItemStack itemstack) {
+- return UseAnim.DRINK;
++ public EnumAnimation getUseAnimation(ItemStack stack) {
++ return EnumAnimation.DRINK;
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- return ItemUtils.startUsingInstantly(level, player, interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ return ItemUtils.startUsingInstantly(level, player, hand);
+ }
+
+ @Override
+- @Override
+- public String getDescriptionId(ItemStack itemstack) {
+- return PotionUtils.getPotion(itemstack).getName(this.getDescriptionId() + ".effect.");
++ public String getDescriptionId(ItemStack stack) {
++ return PotionUtils.getPotion(stack).getName(this.getDescriptionId() + ".effect.");
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- PotionUtils.addPotionTooltip(itemstack, list, 1.0F, level == null ? 20.0F : level.tickRateManager().tickrate());
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
++ PotionUtils.addPotionTooltip(stack, tooltip, 1.0F, level == null ? 20.0F : level.tickRateManager().tickrate());
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/RecordItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/RecordItem.java.patch
new file mode 100644
index 0000000000..fde55760c4
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/RecordItem.java.patch
@@ -0,0 +1,99 @@
+--- a/net/minecraft/world/item/RecordItem.java
++++ b/net/minecraft/world/item/RecordItem.java
+@@ -18,7 +18,7 @@
+ import net.minecraft.world.level.block.JukeboxBlock;
+ import net.minecraft.world.level.block.entity.BlockEntity;
+ import net.minecraft.world.level.block.entity.JukeboxBlockEntity;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.gameevent.GameEvent;
+
+ public class RecordItem extends Item {
+@@ -28,42 +28,42 @@
+ private final SoundEvent sound;
+ private final int lengthInTicks;
+
+- protected RecordItem(int i, SoundEvent soundevent, Item.Properties item_properties, int j) {
+- super(item_properties);
+- this.analogOutput = i;
+- this.sound = soundevent;
+- this.lengthInTicks = j * 20;
++ protected RecordItem(int analogOutput, SoundEvent sound, Item.Properties properties, int lengthInSeconds) {
++ super(properties);
++ this.analogOutput = analogOutput;
++ this.sound = sound;
++ this.lengthInTicks = lengthInSeconds * 20;
+ RecordItem.BY_NAME.put(this.sound, this);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- BlockState blockstate = level.getBlockState(blockpos);
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ IBlockData iblockdata = world.getBlockState(blockposition);
+
+- if (blockstate.is(Blocks.JUKEBOX) && !(Boolean) blockstate.getValue(JukeboxBlock.HAS_RECORD)) {
+- ItemStack itemstack = useoncontext.getItemInHand();
++ if (iblockdata.is(Blocks.JUKEBOX) && !(Boolean) iblockdata.getValue(JukeboxBlock.HAS_RECORD)) {
++ ItemStack itemstack = context.getItemInHand();
+
+- if (!level.isClientSide) {
+- Player player = useoncontext.getPlayer();
+- BlockEntity blockentity = level.getBlockEntity(blockpos);
++ if (!world.isClientSide) {
++ if (true) return InteractionResult.SUCCESS; // CraftBukkit - handled in ItemStack
++ Player entityhuman = context.getPlayer();
++ BlockEntity tileentity = world.getBlockEntity(blockposition);
+
+- if (blockentity instanceof JukeboxBlockEntity) {
+- JukeboxBlockEntity jukeboxblockentity = (JukeboxBlockEntity) blockentity;
++ if (tileentity instanceof JukeboxBlockEntity) {
++ JukeboxBlockEntity tileentityjukebox = (JukeboxBlockEntity) tileentity;
+
+- jukeboxblockentity.setTheItem(itemstack.copy());
+- level.gameEvent(GameEvent.BLOCK_CHANGE, blockpos, GameEvent.Context.of(player, blockstate));
++ tileentityjukebox.setTheItem(itemstack.copy());
++ world.gameEvent(GameEvent.BLOCK_CHANGE, blockposition, GameEvent.Context.of(entityhuman, iblockdata));
+ }
+
+ itemstack.shrink(1);
+- if (player != null) {
+- player.awardStat(Stats.PLAY_RECORD);
++ if (entityhuman != null) {
++ entityhuman.awardStat(Stats.PLAY_RECORD);
+ }
+ }
+
+- return InteractionResult.sidedSuccess(level.isClientSide);
++ return InteractionResult.sidedSuccess(world.isClientSide);
+ } else {
+ return InteractionResult.PASS;
+ }
+@@ -74,9 +74,8 @@
+ }
+
+ @Override
+- @Override
+- public void appendHoverText(ItemStack itemstack, @Nullable Level level, List<Component> list, TooltipFlag tooltipflag) {
+- list.add(this.getDisplayName().withStyle(ChatFormatting.GRAY));
++ public void appendHoverText(ItemStack stack, @Nullable Level level, List<Component> tooltip, TooltipFlag flag) {
++ tooltip.add(this.getDisplayName().withStyle(ChatFormatting.GRAY));
+ }
+
+ public MutableComponent getDisplayName() {
+@@ -84,8 +83,8 @@
+ }
+
+ @Nullable
+- public static RecordItem getBySound(SoundEvent soundevent) {
+- return (RecordItem) RecordItem.BY_NAME.get(soundevent);
++ public static RecordItem getBySound(SoundEvent sound) {
++ return (RecordItem) RecordItem.BY_NAME.get(sound);
+ }
+
+ public SoundEvent getSound() {
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/SignItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/SignItem.java.patch
new file mode 100644
index 0000000000..a7b04b1904
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/SignItem.java.patch
@@ -0,0 +1,55 @@
+--- a/net/minecraft/world/item/SignItem.java
++++ b/net/minecraft/world/item/SignItem.java
+@@ -9,34 +9,38 @@
+ import net.minecraft.world.level.block.SignBlock;
+ import net.minecraft.world.level.block.entity.BlockEntity;
+ import net.minecraft.world.level.block.entity.SignBlockEntity;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+
+ public class SignItem extends StandingAndWallBlockItem {
+
+- public SignItem(Item.Properties item_properties, Block block, Block block1) {
+- super(block, block1, item_properties, Direction.DOWN);
++ public static BlockPos openSign; // CraftBukkit
++
++ public SignItem(Item.Properties properties, Block standingBlock, Block wallBlock) {
++ super(standingBlock, wallBlock, properties, Direction.DOWN);
+ }
+
+- public SignItem(Item.Properties item_properties, Block block, Block block1, Direction direction) {
+- super(block, block1, item_properties, direction);
++ public SignItem(Item.Properties properties, Block standingBlock, Block wallBlock, Direction attachmentDirection) {
++ super(standingBlock, wallBlock, properties, attachmentDirection);
+ }
+
+ @Override
+- @Override
+- protected boolean updateCustomBlockEntityTag(BlockPos blockpos, Level level, @Nullable Player player, ItemStack itemstack, BlockState blockstate) {
+- boolean flag = super.updateCustomBlockEntityTag(blockpos, level, player, itemstack, blockstate);
++ protected boolean updateCustomBlockEntityTag(BlockPos pos, Level level, @Nullable Player player, ItemStack stack, IBlockData state) {
++ boolean flag = super.updateCustomBlockEntityTag(pos, level, player, stack, state);
+
+ if (!level.isClientSide && !flag && player != null) {
+- BlockEntity blockentity = level.getBlockEntity(blockpos);
++ BlockEntity tileentity = level.getBlockEntity(pos);
+
+- if (blockentity instanceof SignBlockEntity) {
+- SignBlockEntity signblockentity = (SignBlockEntity) blockentity;
+- Block block = level.getBlockState(blockpos).getBlock();
++ if (tileentity instanceof SignBlockEntity) {
++ SignBlockEntity tileentitysign = (SignBlockEntity) tileentity;
++ Block block = level.getBlockState(pos).getBlock();
+
+ if (block instanceof SignBlock) {
+- SignBlock signblock = (SignBlock) block;
++ SignBlock blocksign = (SignBlock) block;
+
+- signblock.openTextEdit(player, signblockentity, true);
++ // CraftBukkit start - SPIGOT-4678
++ // blocksign.openTextEdit(entityhuman, tileentitysign, true);
++ SignItem.openSign = pos;
++ // CraftBukkit end
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/SnowballItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/SnowballItem.java.patch
new file mode 100644
index 0000000000..07f92d46c9
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/SnowballItem.java.patch
@@ -0,0 +1,63 @@
+--- a/net/minecraft/world/item/SnowballItem.java
++++ b/net/minecraft/world/item/SnowballItem.java
+@@ -3,7 +3,7 @@
+ import net.minecraft.sounds.SoundEvents;
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.Snowball;
+@@ -11,28 +11,40 @@
+
+ public class SnowballItem extends Item {
+
+- public SnowballItem(Item.Properties item_properties) {
+- super(item_properties);
++ public SnowballItem(Item.Properties properties) {
++ super(properties);
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+- level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
++ // 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 entitysnowball = new Snowball(level, player);
+
+- snowball.setItem(itemstack);
+- snowball.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
+- level.addFreshEntity(snowball);
++ entitysnowball.setItem(itemstack);
++ entitysnowball.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 1.5F, 1.0F);
++ if (level.addFreshEntity(entitysnowball)) {
++ if (!player.getAbilities().instabuild) {
++ itemstack.shrink(1);
++ }
++
++ level.playSound((Player) null, player.getX(), player.getY(), player.getZ(), SoundEvents.SNOWBALL_THROW, SoundSource.NEUTRAL, 0.5F, 0.4F / (level.getRandom().nextFloat() * 0.4F + 0.8F));
++ } else if (player instanceof net.minecraft.server.level.ServerPlayer) {
++ ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity().updateInventory();
++ }
+ }
++ // CraftBukkit end
+
+ player.awardStat(Stats.ITEM_USED.get(this));
+- if (!player.getAbilities().instabuild) {
++ // CraftBukkit start - moved up
++ /*
++ if (!entityhuman.getAbilities().instabuild) {
+ itemstack.shrink(1);
+ }
++ */
+
+ return InteractionResultHolder.sidedSuccess(itemstack, level.isClientSide());
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/SpawnEggItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/SpawnEggItem.java.patch
new file mode 100644
index 0000000000..839b0598c2
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/SpawnEggItem.java.patch
@@ -0,0 +1,232 @@
+--- a/net/minecraft/world/item/SpawnEggItem.java
++++ b/net/minecraft/world/item/SpawnEggItem.java
+@@ -11,14 +11,14 @@
+ import net.minecraft.nbt.CompoundTag;
+ import net.minecraft.server.level.ServerLevel;
+ import net.minecraft.stats.Stats;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResult;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.AgeableMob;
+ import net.minecraft.world.entity.Entity;
+ import net.minecraft.world.entity.EntityType;
++import net.minecraft.world.entity.EnumMobSpawn;
+ import net.minecraft.world.entity.Mob;
+-import net.minecraft.world.entity.MobSpawnType;
+ import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.flag.FeatureFlagSet;
+ import net.minecraft.world.item.context.UseOnContext;
+@@ -27,7 +27,7 @@
+ import net.minecraft.world.level.Spawner;
+ import net.minecraft.world.level.block.LiquidBlock;
+ import net.minecraft.world.level.block.entity.BlockEntity;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.phys.BlockHitResult;
+ import net.minecraft.world.phys.HitResult;
+@@ -40,51 +40,50 @@
+ private final int highlightColor;
+ private final EntityType<?> defaultType;
+
+- public SpawnEggItem(EntityType<? extends Mob> entitytype, int i, int j, Item.Properties item_properties) {
+- super(item_properties);
+- this.defaultType = entitytype;
+- this.backgroundColor = i;
+- this.highlightColor = j;
+- SpawnEggItem.BY_ID.put(entitytype, this);
++ public SpawnEggItem(EntityType<? extends Mob> defaultType, int backgroundColor, int highlightColor, Item.Properties properties) {
++ super(properties);
++ this.defaultType = defaultType;
++ this.backgroundColor = backgroundColor;
++ this.highlightColor = highlightColor;
++ SpawnEggItem.BY_ID.put(defaultType, this);
+ }
+
+ @Override
+- @Override
+- public InteractionResult useOn(UseOnContext useoncontext) {
+- Level level = useoncontext.getLevel();
++ public InteractionResult useOn(UseOnContext context) {
++ Level world = context.getLevel();
+
+- if (!(level instanceof ServerLevel)) {
++ if (!(world instanceof ServerLevel)) {
+ return InteractionResult.SUCCESS;
+ } else {
+- ItemStack itemstack = useoncontext.getItemInHand();
+- BlockPos blockpos = useoncontext.getClickedPos();
+- Direction direction = useoncontext.getClickedFace();
+- BlockState blockstate = level.getBlockState(blockpos);
+- BlockEntity blockentity = level.getBlockEntity(blockpos);
+- EntityType entitytype;
++ ItemStack itemstack = context.getItemInHand();
++ BlockPos blockposition = context.getClickedPos();
++ Direction enumdirection = context.getClickedFace();
++ IBlockData iblockdata = world.getBlockState(blockposition);
++ BlockEntity tileentity = world.getBlockEntity(blockposition);
++ EntityType entitytypes;
+
+- if (blockentity instanceof Spawner) {
+- Spawner spawner = (Spawner) blockentity;
++ if (tileentity instanceof Spawner) {
++ Spawner spawner = (Spawner) tileentity;
+
+- entitytype = this.getType(itemstack.getTag());
+- spawner.setEntityId(entitytype, level.getRandom());
+- level.sendBlockUpdated(blockpos, blockstate, blockstate, 3);
+- level.gameEvent((Entity) useoncontext.getPlayer(), GameEvent.BLOCK_CHANGE, blockpos);
++ entitytypes = this.getType(itemstack.getTag());
++ spawner.setEntityId(entitytypes, world.getRandom());
++ world.sendBlockUpdated(blockposition, iblockdata, iblockdata, 3);
++ world.gameEvent((Entity) context.getPlayer(), GameEvent.BLOCK_CHANGE, blockposition);
+ itemstack.shrink(1);
+ return InteractionResult.CONSUME;
+ } else {
+- BlockPos blockpos1;
++ BlockPos blockposition1;
+
+- if (blockstate.getCollisionShape(level, blockpos).isEmpty()) {
+- blockpos1 = blockpos;
++ if (iblockdata.getCollisionShape(world, blockposition).isEmpty()) {
++ blockposition1 = blockposition;
+ } else {
+- blockpos1 = blockpos.relative(direction);
++ blockposition1 = blockposition.relative(enumdirection);
+ }
+
+- entitytype = this.getType(itemstack.getTag());
+- if (entitytype.spawn((ServerLevel) level, itemstack, useoncontext.getPlayer(), blockpos1, MobSpawnType.SPAWN_EGG, true, !Objects.equals(blockpos, blockpos1) && direction == Direction.UP) != null) {
++ entitytypes = this.getType(itemstack.getTag());
++ if (entitytypes.spawn((ServerLevel) world, itemstack, context.getPlayer(), blockposition1, EnumMobSpawn.SPAWN_EGG, true, !Objects.equals(blockposition, blockposition1) && enumdirection == Direction.UP) != null) {
+ itemstack.shrink(1);
+- level.gameEvent((Entity) useoncontext.getPlayer(), GameEvent.ENTITY_PLACE, blockpos);
++ world.gameEvent((Entity) context.getPlayer(), GameEvent.ENTITY_PLACE, blockposition);
+ }
+
+ return InteractionResult.CONSUME;
+@@ -93,23 +92,22 @@
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
+- BlockHitResult blockhitresult = getPlayerPOVHitResult(level, player, ClipContext.Fluid.SOURCE_ONLY);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
++ BlockHitResult movingobjectpositionblock = getPlayerPOVHitResult(level, player, ClipContext.Fluid.SOURCE_ONLY);
+
+- if (blockhitresult.getType() != HitResult.Type.BLOCK) {
++ if (movingobjectpositionblock.getType() != HitResult.EnumMovingObjectType.BLOCK) {
+ return InteractionResultHolder.pass(itemstack);
+ } else if (!(level instanceof ServerLevel)) {
+ return InteractionResultHolder.success(itemstack);
+ } else {
+- BlockPos blockpos = blockhitresult.getBlockPos();
++ BlockPos blockposition = movingobjectpositionblock.getBlockPos();
+
+- if (!(level.getBlockState(blockpos).getBlock() instanceof LiquidBlock)) {
++ if (!(level.getBlockState(blockposition).getBlock() instanceof LiquidBlock)) {
+ return InteractionResultHolder.pass(itemstack);
+- } else if (level.mayInteract(player, blockpos) && player.mayUseItemAt(blockpos, blockhitresult.getDirection(), itemstack)) {
+- EntityType<?> entitytype = this.getType(itemstack.getTag());
+- Entity entity = entitytype.spawn((ServerLevel) level, itemstack, player, blockpos, MobSpawnType.SPAWN_EGG, false, false);
++ } else if (level.mayInteract(player, blockposition) && player.mayUseItemAt(blockposition, movingobjectpositionblock.getDirection(), itemstack)) {
++ EntityType<?> entitytypes = this.getType(itemstack.getTag());
++ Entity entity = entitytypes.spawn((ServerLevel) level, itemstack, player, blockposition, EnumMobSpawn.SPAWN_EGG, false, false);
+
+ if (entity == null) {
+ return InteractionResultHolder.pass(itemstack);
+@@ -128,29 +126,29 @@
+ }
+ }
+
+- public boolean spawnsEntity(@Nullable CompoundTag compoundtag, EntityType<?> entitytype) {
+- return Objects.equals(this.getType(compoundtag), entitytype);
++ public boolean spawnsEntity(@Nullable CompoundTag nbt, EntityType<?> type) {
++ return Objects.equals(this.getType(nbt), type);
+ }
+
+- public int getColor(int i) {
+- return i == 0 ? this.backgroundColor : this.highlightColor;
++ public int getColor(int tintIndex) {
++ return tintIndex == 0 ? this.backgroundColor : this.highlightColor;
+ }
+
+ @Nullable
+- public static SpawnEggItem byId(@Nullable EntityType<?> entitytype) {
+- return (SpawnEggItem) SpawnEggItem.BY_ID.get(entitytype);
++ public static SpawnEggItem byId(@Nullable EntityType<?> type) {
++ return (SpawnEggItem) SpawnEggItem.BY_ID.get(type);
+ }
+
+ public static Iterable<SpawnEggItem> eggs() {
+ return Iterables.unmodifiableIterable(SpawnEggItem.BY_ID.values());
+ }
+
+- public EntityType<?> getType(@Nullable CompoundTag compoundtag) {
+- if (compoundtag != null && compoundtag.contains("EntityTag", 10)) {
+- CompoundTag compoundtag1 = compoundtag.getCompound("EntityTag");
++ public EntityType<?> getType(@Nullable CompoundTag nbt) {
++ if (nbt != null && nbt.contains("EntityTag", 10)) {
++ CompoundTag nbttagcompound1 = nbt.getCompound("EntityTag");
+
+- if (compoundtag1.contains("id", 8)) {
+- return (EntityType) EntityType.byString(compoundtag1.getString("id")).orElse(this.defaultType);
++ if (nbttagcompound1.contains("id", 8)) {
++ return (EntityType) EntityType.byString(nbttagcompound1.getString("id")).orElse(this.defaultType);
+ }
+ }
+
+@@ -158,21 +156,20 @@
+ }
+
+ @Override
+- @Override
+ public FeatureFlagSet requiredFeatures() {
+ return this.defaultType.requiredFeatures();
+ }
+
+- public Optional<Mob> spawnOffspringFromSpawnEgg(Player player, Mob mob, EntityType<? extends Mob> entitytype, ServerLevel serverlevel, Vec3 vec3, ItemStack itemstack) {
+- if (!this.spawnsEntity(itemstack.getTag(), entitytype)) {
++ public Optional<Mob> spawnOffspringFromSpawnEgg(Player player, Mob mob, EntityType<? extends Mob> entityType, ServerLevel serverLevel, Vec3 pos, ItemStack stack) {
++ if (!this.spawnsEntity(stack.getTag(), entityType)) {
+ return Optional.empty();
+ } else {
+ Object object;
+
+ if (mob instanceof AgeableMob) {
+- object = ((AgeableMob) mob).getBreedOffspring(serverlevel, (AgeableMob) mob);
++ object = ((AgeableMob) mob).getBreedOffspring(serverLevel, (AgeableMob) mob);
+ } else {
+- object = (Mob) entitytype.create(serverlevel);
++ object = (Mob) entityType.create(serverLevel);
+ }
+
+ if (object == null) {
+@@ -182,17 +179,17 @@
+ if (!((Mob) object).isBaby()) {
+ return Optional.empty();
+ } else {
+- ((Mob) object).moveTo(vec3.x(), vec3.y(), vec3.z(), 0.0F, 0.0F);
+- serverlevel.addFreshEntityWithPassengers((Entity) object);
+- if (itemstack.hasCustomHoverName()) {
+- ((Mob) object).setCustomName(itemstack.getHoverName());
++ ((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()) {
++ ((Mob) object).setCustomName(stack.getHoverName());
+ }
+
+ if (!player.getAbilities().instabuild) {
+- itemstack.shrink(1);
++ stack.shrink(1);
+ }
+
+- return Optional.of(object);
++ return Optional.of((Mob) object); // CraftBukkit - decompile error
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/StandingAndWallBlockItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/StandingAndWallBlockItem.java.patch
new file mode 100644
index 0000000000..e6f2b4e97c
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/StandingAndWallBlockItem.java.patch
@@ -0,0 +1,103 @@
+--- a/net/minecraft/world/item/StandingAndWallBlockItem.java
++++ b/net/minecraft/world/item/StandingAndWallBlockItem.java
+@@ -4,59 +4,74 @@
+ import javax.annotation.Nullable;
+ import net.minecraft.core.BlockPos;
+ import net.minecraft.core.Direction;
++import net.minecraft.server.level.ServerPlayer;
+ import net.minecraft.world.item.context.BlockPlaceContext;
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.LevelReader;
+ import net.minecraft.world.level.block.Block;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ 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;
++ public final Block wallBlock;
+ private final Direction attachmentDirection;
+
+- public StandingAndWallBlockItem(Block block, Block block1, Item.Properties item_properties, Direction direction) {
+- super(block, item_properties);
+- this.wallBlock = block1;
+- this.attachmentDirection = direction;
++ public StandingAndWallBlockItem(Block block, Block wallBlock, Item.Properties properties, Direction attachmentDirection) {
++ super(block, properties);
++ this.wallBlock = wallBlock;
++ this.attachmentDirection = attachmentDirection;
+ }
+
+- protected boolean canPlace(LevelReader levelreader, BlockState blockstate, BlockPos blockpos) {
+- return blockstate.canSurvive(levelreader, blockpos);
++ protected boolean canPlace(LevelReader level, IBlockData state, BlockPos pos) {
++ return state.canSurvive(level, pos);
+ }
+
+ @Nullable
+ @Override
+- @Override
+- protected BlockState getPlacementState(BlockPlaceContext blockplacecontext) {
+- BlockState blockstate = this.wallBlock.getStateForPlacement(blockplacecontext);
+- BlockState blockstate1 = null;
+- Level level = blockplacecontext.getLevel();
+- BlockPos blockpos = blockplacecontext.getClickedPos();
+- Direction[] adirection = blockplacecontext.getNearestLookingDirections();
+- int i = adirection.length;
++ protected IBlockData getPlacementState(BlockPlaceContext context) {
++ IBlockData iblockdata = this.wallBlock.getStateForPlacement(context);
++ IBlockData iblockdata1 = null;
++ Level world = context.getLevel();
++ BlockPos blockposition = context.getClickedPos();
++ Direction[] aenumdirection = context.getNearestLookingDirections();
++ int i = aenumdirection.length;
+
+ for (int j = 0; j < i; ++j) {
+- Direction direction = adirection[j];
++ Direction enumdirection = aenumdirection[j];
+
+- if (direction != this.attachmentDirection.getOpposite()) {
+- BlockState blockstate2 = direction == this.attachmentDirection ? this.getBlock().getStateForPlacement(blockplacecontext) : blockstate;
++ if (enumdirection != this.attachmentDirection.getOpposite()) {
++ IBlockData iblockdata2 = enumdirection == this.attachmentDirection ? this.getBlock().getStateForPlacement(context) : iblockdata;
+
+- if (blockstate2 != null && this.canPlace(level, blockstate2, blockpos)) {
+- blockstate1 = blockstate2;
++ if (iblockdata2 != null && this.canPlace(world, iblockdata2, blockposition)) {
++ iblockdata1 = iblockdata2;
+ break;
+ }
+ }
+ }
+
+- return blockstate1 != null && level.isUnobstructed(blockstate1, blockpos, CollisionContext.empty()) ? blockstate1 : 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
+- @Override
+- public void registerBlocks(Map<Block, Item> map, Item item) {
+- super.registerBlocks(map, item);
+- map.put(this.wallBlock, item);
++ public void registerBlocks(Map<Block, Item> blockToItemMap, Item item) {
++ super.registerBlocks(blockToItemMap, item);
++ blockToItemMap.put(this.wallBlock, item);
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/TridentItem.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/TridentItem.java.patch
new file mode 100644
index 0000000000..65ea0af315
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/TridentItem.java.patch
@@ -0,0 +1,245 @@
+--- a/net/minecraft/world/item/TridentItem.java
++++ b/net/minecraft/world/item/TridentItem.java
+@@ -9,12 +9,12 @@
+ import net.minecraft.sounds.SoundSource;
+ import net.minecraft.stats.Stats;
+ import net.minecraft.util.Mth;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.InteractionResultHolder;
+ import net.minecraft.world.entity.Entity;
++import net.minecraft.world.entity.EnumMoveType;
+ import net.minecraft.world.entity.EquipmentSlot;
+ import net.minecraft.world.entity.LivingEntity;
+-import net.minecraft.world.entity.MoverType;
+ import net.minecraft.world.entity.ai.attributes.Attribute;
+ import net.minecraft.world.entity.ai.attributes.AttributeModifier;
+ import net.minecraft.world.entity.ai.attributes.Attributes;
+@@ -23,18 +23,18 @@
+ import net.minecraft.world.entity.projectile.ThrownTrident;
+ import net.minecraft.world.item.enchantment.EnchantmentHelper;
+ import net.minecraft.world.level.Level;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.phys.Vec3;
+
+-public class TridentItem extends Item implements Vanishable {
++public class TridentItem extends Item implements ItemVanishable {
+
+ public static final int THROW_THRESHOLD_TIME = 10;
+ public static final float BASE_DAMAGE = 8.0F;
+ public static final float SHOOT_POWER = 2.5F;
+ private final Multimap<Attribute, AttributeModifier> defaultModifiers;
+
+- public TridentItem(Item.Properties item_properties) {
+- super(item_properties);
++ public TridentItem(Item.Properties properties) {
++ super(properties);
+ Builder<Attribute, AttributeModifier> builder = ImmutableMultimap.builder();
+
+ builder.put(Attributes.ATTACK_DAMAGE, new AttributeModifier(TridentItem.BASE_ATTACK_DAMAGE_UUID, "Tool modifier", 8.0D, AttributeModifier.Operation.ADDITION));
+@@ -43,58 +43,80 @@
+ }
+
+ @Override
+- @Override
+- public boolean canAttackBlock(BlockState blockstate, Level level, BlockPos blockpos, Player player) {
++ public boolean canAttackBlock(IBlockData state, Level level, BlockPos pos, Player player) {
+ return !player.isCreative();
+ }
+
+ @Override
+- @Override
+- public UseAnim getUseAnimation(ItemStack itemstack) {
+- return UseAnim.SPEAR;
++ public EnumAnimation getUseAnimation(ItemStack stack) {
++ return EnumAnimation.SPEAR;
+ }
+
+ @Override
+- @Override
+- public int getUseDuration(ItemStack itemstack) {
++ public int getUseDuration(ItemStack stack) {
+ return 72000;
+ }
+
+ @Override
+- @Override
+- public void releaseUsing(ItemStack itemstack, Level level, LivingEntity livingentity, int i) {
+- if (livingentity instanceof Player) {
+- Player player = (Player) livingentity;
+- int j = this.getUseDuration(itemstack) - i;
++ public void releaseUsing(ItemStack stack, Level level, LivingEntity entityLiving, int timeLeft) {
++ if (entityLiving instanceof Player) {
++ Player entityhuman = (Player) entityLiving;
++ int j = this.getUseDuration(stack) - timeLeft;
+
+ if (j >= 10) {
+- int k = EnchantmentHelper.getRiptide(itemstack);
++ int k = EnchantmentHelper.getRiptide(stack);
+
+- if (k <= 0 || player.isInWaterOrRain()) {
++ if (k <= 0 || entityhuman.isInWaterOrRain()) {
+ if (!level.isClientSide) {
+- itemstack.hurtAndBreak(1, player, (player1) -> {
+- player1.broadcastBreakEvent(livingentity.getUsedItemHand());
++ // CraftBukkit - moved down
++ /*
++ itemstack.hurtAndBreak(1, entityhuman, (entityhuman1) -> {
++ entityhuman1.broadcastBreakEvent(entityliving.getUsedItemHand());
+ });
++ */
+ if (k == 0) {
+- ThrownTrident throwntrident = new ThrownTrident(level, player, itemstack);
++ ThrownTrident entitythrowntrident = new ThrownTrident(level, entityhuman, stack);
+
+- throwntrident.shootFromRotation(player, player.getXRot(), player.getYRot(), 0.0F, 2.5F + (float) k * 0.5F, 1.0F);
+- if (player.getAbilities().instabuild) {
+- throwntrident.pickup = AbstractArrow.Pickup.CREATIVE_ONLY;
++ 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((Player) null, (Entity) throwntrident, SoundEvents.TRIDENT_THROW, SoundSource.PLAYERS, 1.0F, 1.0F);
+- if (!player.getAbilities().instabuild) {
+- player.getInventory().removeItem(itemstack);
++ // 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));
++ entityhuman.awardStat(Stats.ITEM_USED.get(this));
+ if (k > 0) {
+- float f = player.getYRot();
+- float f1 = player.getXRot();
++ // 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);
+@@ -104,25 +126,25 @@
+ f2 *= f6 / f5;
+ f3 *= f6 / f5;
+ f4 *= f6 / f5;
+- player.push((double) f2, (double) f3, (double) f4);
+- player.startAutoSpinAttack(20);
+- if (player.onGround()) {
++ entityhuman.push((double) f2, (double) f3, (double) f4);
++ entityhuman.startAutoSpinAttack(20);
++ if (entityhuman.onGround()) {
+ float f7 = 1.1999999F;
+
+- player.move(MoverType.SELF, new Vec3(0.0D, 1.1999999284744263D, 0.0D));
++ entityhuman.move(EnumMoveType.SELF, new Vec3(0.0D, 1.1999999284744263D, 0.0D));
+ }
+
+- SoundEvent soundevent;
++ SoundEvent soundeffect;
+
+ if (k >= 3) {
+- soundevent = SoundEvents.TRIDENT_RIPTIDE_3;
++ soundeffect = SoundEvents.TRIDENT_RIPTIDE_3;
+ } else if (k == 2) {
+- soundevent = SoundEvents.TRIDENT_RIPTIDE_2;
++ soundeffect = SoundEvents.TRIDENT_RIPTIDE_2;
+ } else {
+- soundevent = SoundEvents.TRIDENT_RIPTIDE_1;
++ soundeffect = SoundEvents.TRIDENT_RIPTIDE_1;
+ }
+
+- level.playSound((Player) null, (Entity) player, soundevent, SoundSource.PLAYERS, 1.0F, 1.0F);
++ level.playSound((Player) null, (Entity) entityhuman, soundeffect, SoundSource.PLAYERS, 1.0F, 1.0F);
+ }
+
+ }
+@@ -131,35 +153,32 @@
+ }
+
+ @Override
+- @Override
+- public InteractionResultHolder<ItemStack> use(Level level, Player player, InteractionHand interactionhand) {
+- ItemStack itemstack = player.getItemInHand(interactionhand);
++ public InteractionResultHolder<ItemStack> use(Level level, Player player, EnumHand hand) {
++ ItemStack itemstack = player.getItemInHand(hand);
+
+ if (itemstack.getDamageValue() >= itemstack.getMaxDamage() - 1) {
+ return InteractionResultHolder.fail(itemstack);
+ } else if (EnchantmentHelper.getRiptide(itemstack) > 0 && !player.isInWaterOrRain()) {
+ return InteractionResultHolder.fail(itemstack);
+ } else {
+- player.startUsingItem(interactionhand);
++ player.startUsingItem(hand);
+ return InteractionResultHolder.consume(itemstack);
+ }
+ }
+
+ @Override
+- @Override
+- public boolean hurtEnemy(ItemStack itemstack, LivingEntity livingentity, LivingEntity livingentity1) {
+- itemstack.hurtAndBreak(1, livingentity1, (livingentity2) -> {
+- livingentity2.broadcastBreakEvent(EquipmentSlot.MAINHAND);
++ public boolean hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) {
++ stack.hurtAndBreak(1, attacker, (entityliving2) -> {
++ entityliving2.broadcastBreakEvent(EquipmentSlot.MAINHAND);
+ });
+ return true;
+ }
+
+ @Override
+- @Override
+- public boolean mineBlock(ItemStack itemstack, Level level, BlockState blockstate, BlockPos blockpos, LivingEntity livingentity) {
+- if ((double) blockstate.getDestroySpeed(level, blockpos) != 0.0D) {
+- itemstack.hurtAndBreak(2, livingentity, (livingentity1) -> {
+- livingentity1.broadcastBreakEvent(EquipmentSlot.MAINHAND);
++ public boolean mineBlock(ItemStack stack, Level level, IBlockData state, BlockPos pos, LivingEntity entityLiving) {
++ if ((double) state.getDestroySpeed(level, pos) != 0.0D) {
++ stack.hurtAndBreak(2, entityLiving, (entityliving1) -> {
++ entityliving1.broadcastBreakEvent(EquipmentSlot.MAINHAND);
+ });
+ }
+
+@@ -167,13 +186,11 @@
+ }
+
+ @Override
+- @Override
+- public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot equipmentslot) {
+- return equipmentslot == EquipmentSlot.MAINHAND ? this.defaultModifiers : super.getDefaultAttributeModifiers(equipmentslot);
++ public Multimap<Attribute, AttributeModifier> getDefaultAttributeModifiers(EquipmentSlot equipmentSlot) {
++ return equipmentSlot == EquipmentSlot.MAINHAND ? this.defaultModifiers : super.getDefaultAttributeModifiers(equipmentSlot);
+ }
+
+ @Override
+- @Override
+ public int getEnchantmentValue() {
+ return 1;
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
new file mode 100644
index 0000000000..e459ae58c7
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/BlastingRecipe.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/crafting/BlastingRecipe.java
++++ b/net/minecraft/world/item/crafting/BlastingRecipe.java
+@@ -3,21 +3,40 @@
+ 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 s, CookingBookCategory cookingbookcategory, Ingredient ingredient, ItemStack itemstack, float f, int i) {
+- super(RecipeType.BLASTING, s, cookingbookcategory, ingredient, itemstack, f, i);
++ public BlastingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.BLASTING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+- @Override
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.BLAST_FURNACE);
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
new file mode 100644
index 0000000000..281bcf37fa
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CampfireCookingRecipe.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
++++ b/net/minecraft/world/item/crafting/CampfireCookingRecipe.java
+@@ -3,21 +3,40 @@
+ 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 s, CookingBookCategory cookingbookcategory, Ingredient ingredient, ItemStack itemstack, float f, int i) {
+- super(RecipeType.CAMPFIRE_COOKING, s, cookingbookcategory, ingredient, itemstack, f, i);
++ public CampfireCookingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.CAMPFIRE_COOKING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+- @Override
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.CAMPFIRE);
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch
new file mode 100644
index 0000000000..6edc4b87a8
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/CustomRecipe.java.patch
@@ -0,0 +1,46 @@
+--- a/net/minecraft/world/item/crafting/CustomRecipe.java
++++ b/net/minecraft/world/item/crafting/CustomRecipe.java
+@@ -3,8 +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) {
+@@ -12,20 +17,24 @@
+ }
+
+ @Override
+- @Override
+ public boolean isSpecial() {
+ return true;
+ }
+
+ @Override
+- @Override
+- public ItemStack getResultItem(RegistryAccess registryaccess) {
++ public ItemStack getResultItem(RegistryAccess registryAccess) {
+ return ItemStack.EMPTY;
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/crafting/Ingredient.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Ingredient.java.patch
new file mode 100644
index 0000000000..56822af3df
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Ingredient.java.patch
@@ -0,0 +1,278 @@
+--- a/net/minecraft/world/item/crafting/Ingredient.java
++++ b/net/minecraft/world/item/crafting/Ingredient.java
+@@ -25,33 +25,34 @@
+ import net.minecraft.world.entity.player.StackedContents;
+ import net.minecraft.world.item.Item;
+ import net.minecraft.world.item.ItemStack;
+-import net.minecraft.world.level.ItemLike;
++import net.minecraft.world.level.IMaterial;
+
+ public final class Ingredient implements Predicate<ItemStack> {
+
+ public static final Ingredient EMPTY = new Ingredient(Stream.empty());
+- private final Ingredient.Value[] values;
++ private final Ingredient.Provider[] values;
+ @Nullable
+- private ItemStack[] itemStacks;
++ public 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);
+
+- private Ingredient(Stream<? extends Ingredient.Value> stream) {
+- this.values = (Ingredient.Value[]) stream.toArray((i) -> {
+- return new Ingredient.Value[i];
++ public Ingredient(Stream<? extends Ingredient.Provider> values) {
++ this.values = (Ingredient.Provider[]) values.toArray((i) -> {
++ return new Ingredient.Provider[i];
+ });
+ }
+
+- private Ingredient(Ingredient.Value[] aingredient_value) {
+- this.values = aingredient_value;
++ private Ingredient(Ingredient.Provider[] arecipeitemstack_provider) {
++ this.values = arecipeitemstack_provider;
+ }
+
+ public ItemStack[] getItems() {
+ if (this.itemStacks == null) {
+- this.itemStacks = (ItemStack[]) Arrays.stream(this.values).flatMap((ingredient_value) -> {
+- return ingredient_value.getItems().stream();
++ this.itemStacks = (ItemStack[]) Arrays.stream(this.values).flatMap((recipeitemstack_provider) -> {
++ return recipeitemstack_provider.getItems().stream();
+ }).distinct().toArray((i) -> {
+ return new ItemStack[i];
+ });
+@@ -60,12 +61,11 @@
+ return this.itemStacks;
+ }
+
+- @Override
+- public boolean test(@Nullable ItemStack itemstack) {
+- if (itemstack == null) {
++ public boolean test(@Nullable ItemStack stack) {
++ if (stack == null) {
+ return false;
+ } else if (this.isEmpty()) {
+- return itemstack.isEmpty();
++ return stack.isEmpty();
+ } else {
+ ItemStack[] aitemstack = this.getItems();
+ int i = aitemstack.length;
+@@ -73,7 +73,16 @@
+ for (int j = 0; j < i; ++j) {
+ ItemStack itemstack1 = aitemstack[j];
+
+- if (itemstack1.is(itemstack.getItem())) {
++ // 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;
+ }
+ }
+@@ -102,92 +111,91 @@
+ return this.stackingIds;
+ }
+
+- public void toNetwork(FriendlyByteBuf friendlybytebuf) {
+- friendlybytebuf.writeCollection(Arrays.asList(this.getItems()), FriendlyByteBuf::writeItem);
++ public void toNetwork(FriendlyByteBuf buffer) {
++ buffer.writeCollection(Arrays.asList(this.getItems()), FriendlyByteBuf::writeItem);
+ }
+
+ public boolean isEmpty() {
+ return this.values.length == 0;
+ }
+
+- @Override
+ public boolean equals(Object object) {
+ if (object instanceof Ingredient) {
+- Ingredient ingredient = (Ingredient) object;
++ Ingredient recipeitemstack = (Ingredient) object;
+
+- return Arrays.equals(this.values, ingredient.values);
++ return Arrays.equals(this.values, recipeitemstack.values);
+ } else {
+ return false;
+ }
+ }
+
+- private static Ingredient fromValues(Stream<? extends Ingredient.Value> stream) {
+- Ingredient ingredient = new Ingredient(stream);
++ private static Ingredient fromValues(Stream<? extends Ingredient.Provider> stream) {
++ Ingredient recipeitemstack = new Ingredient(stream);
+
+- return ingredient.isEmpty() ? Ingredient.EMPTY : ingredient;
++ return recipeitemstack.isEmpty() ? Ingredient.EMPTY : recipeitemstack;
+ }
+
+ public static Ingredient of() {
+ return Ingredient.EMPTY;
+ }
+
+- public static Ingredient of(ItemLike... aitemlike) {
+- return of(Arrays.stream(aitemlike).map(ItemStack::new));
++ public static Ingredient of(IMaterial... items) {
++ return of(Arrays.stream(items).map(ItemStack::new));
+ }
+
+- public static Ingredient of(ItemStack... aitemstack) {
+- return of(Arrays.stream(aitemstack));
++ public static Ingredient of(ItemStack... stacks) {
++ return of(Arrays.stream(stacks));
+ }
+
+- public static Ingredient of(Stream<ItemStack> stream) {
+- return fromValues(stream.filter((itemstack) -> {
++ public static Ingredient of(Stream<ItemStack> stacks) {
++ return fromValues(stacks.filter((itemstack) -> {
+ return !itemstack.isEmpty();
+ }).map(Ingredient.ItemValue::new));
+ }
+
+- public static Ingredient of(TagKey<Item> tagkey) {
+- return fromValues(Stream.of(new Ingredient.TagValue(tagkey)));
++ public static Ingredient of(TagKey<Item> tag) {
++ return fromValues(Stream.of(new Ingredient.TagValue(tag)));
+ }
+
+- public static Ingredient fromNetwork(FriendlyByteBuf friendlybytebuf) {
+- return fromValues(friendlybytebuf.readList(FriendlyByteBuf::readItem).stream().map(Ingredient.ItemValue::new));
++ public static Ingredient fromNetwork(FriendlyByteBuf buffer) {
++ return fromValues(buffer.readList(FriendlyByteBuf::readItem).stream().map(Ingredient.ItemValue::new));
+ }
+
+ private static Codec<Ingredient> codec(boolean flag) {
+- Codec<Ingredient.Value[]> codec = Codec.list(Ingredient.Value.CODEC).comapFlatMap((list) -> {
++ Codec<Ingredient.Provider[]> codec = Codec.list(Ingredient.Provider.CODEC).comapFlatMap((list) -> {
+ return !flag && list.size() < 1 ? DataResult.error(() -> {
+ return "Item array cannot be empty, at least one item must be defined";
+- }) : DataResult.success((Ingredient.Value[]) list.toArray(new Ingredient.Value[0]));
++ }) : DataResult.success((Ingredient.Provider[]) list.toArray(new Ingredient.Provider[0]));
+ }, List::of);
+
+- return ExtraCodecs.either(codec, Ingredient.Value.CODEC).flatComapMap((either) -> {
+- return (Ingredient) either.map(Ingredient::new, (ingredient_value) -> {
+- return new Ingredient(new Ingredient.Value[]{ingredient_value});
++ return ExtraCodecs.either(codec, Ingredient.Provider.CODEC).flatComapMap((either) -> {
++ return (Ingredient) either.map(Ingredient::new, (recipeitemstack_provider) -> {
++ return new Ingredient(new Ingredient.Provider[]{recipeitemstack_provider});
+ });
+- }, (ingredient) -> {
+- return ingredient.values.length == 1 ? DataResult.success(Either.right(ingredient.values[0])) : (ingredient.values.length == 0 && !flag ? DataResult.error(() -> {
++ }, (recipeitemstack) -> {
++ return recipeitemstack.values.length == 1 ? DataResult.success(Either.right(recipeitemstack.values[0])) : (recipeitemstack.values.length == 0 && !flag ? DataResult.error(() -> {
+ return "Item array cannot be empty, at least one item must be defined";
+- }) : DataResult.success(Either.left(ingredient.values)));
++ }) : DataResult.success(Either.left(recipeitemstack.values)));
+ });
+ }
+
+- private interface Value {
++ public interface Provider {
+
+- Codec<Ingredient.Value> CODEC = ExtraCodecs.xor(Ingredient.ItemValue.CODEC, Ingredient.TagValue.CODEC).xmap((either) -> {
+- return (Ingredient.Value) either.map((ingredient_itemvalue) -> {
+- return ingredient_itemvalue;
+- }, (ingredient_tagvalue) -> {
+- return ingredient_tagvalue;
++ Codec<Ingredient.Provider> CODEC = ExtraCodecs.xor(Ingredient.ItemValue.CODEC, Ingredient.TagValue.CODEC).xmap((either) -> {
++ return (Ingredient.Provider) either.map((recipeitemstack_stackprovider) -> {
++ return recipeitemstack_stackprovider;
++ }, (recipeitemstack_b) -> {
++ return recipeitemstack_b;
+ });
+- }, (ingredient_value) -> {
+- if (ingredient_value instanceof Ingredient.TagValue) {
+- Ingredient.TagValue ingredient_tagvalue = (Ingredient.TagValue) ingredient_value;
++ }, (recipeitemstack_provider) -> {
++ if (recipeitemstack_provider instanceof Ingredient.TagValue) {
++ Ingredient.TagValue recipeitemstack_b = (Ingredient.TagValue) recipeitemstack_provider;
+
+- return Either.right(ingredient_tagvalue);
+- } else if (ingredient_value instanceof Ingredient.ItemValue) {
+- Ingredient.ItemValue ingredient_itemvalue = (Ingredient.ItemValue) ingredient_value;
++ return Either.right(recipeitemstack_b);
++ } else if (recipeitemstack_provider instanceof Ingredient.ItemValue) {
++ Ingredient.ItemValue recipeitemstack_stackprovider = (Ingredient.ItemValue) recipeitemstack_provider;
+
+- return Either.left(ingredient_itemvalue);
++ return Either.left(recipeitemstack_stackprovider);
+ } else {
+ throw new UnsupportedOperationException("This is neither an item value nor a tag value.");
+ }
+@@ -196,27 +204,25 @@
+ Collection<ItemStack> getItems();
+ }
+
+- private static record TagValue(TagKey<Item> tag) implements Ingredient.Value {
++ private static record TagValue(TagKey<Item> tag) implements Ingredient.Provider {
+
+ static final Codec<Ingredient.TagValue> CODEC = RecordCodecBuilder.create((instance) -> {
+- return instance.group(TagKey.codec(Registries.ITEM).fieldOf("tag").forGetter((ingredient_tagvalue) -> {
+- return ingredient_tagvalue.tag;
++ return instance.group(TagKey.codec(Registries.ITEM).fieldOf("tag").forGetter((recipeitemstack_b) -> {
++ return recipeitemstack_b.tag;
+ })).apply(instance, Ingredient.TagValue::new);
+ });
+
+- @Override
+ public boolean equals(Object object) {
+ if (object instanceof Ingredient.TagValue) {
+- Ingredient.TagValue ingredient_tagvalue = (Ingredient.TagValue) object;
++ Ingredient.TagValue recipeitemstack_b = (Ingredient.TagValue) object;
+
+- return ingredient_tagvalue.tag.location().equals(this.tag.location());
++ return recipeitemstack_b.tag.location().equals(this.tag.location());
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+- @Override
+ public Collection<ItemStack> getItems() {
+ List<ItemStack> list = Lists.newArrayList();
+ Iterator iterator = BuiltInRegistries.ITEM.getTagOrEmpty(this.tag).iterator();
+@@ -231,27 +237,25 @@
+ }
+ }
+
+- private static record ItemValue(ItemStack item) implements Ingredient.Value {
++ public static record ItemValue(ItemStack item) implements Ingredient.Provider {
+
+ static final Codec<Ingredient.ItemValue> CODEC = RecordCodecBuilder.create((instance) -> {
+- return instance.group(ItemStack.SINGLE_ITEM_CODEC.fieldOf("item").forGetter((ingredient_itemvalue) -> {
+- return ingredient_itemvalue.item;
++ return instance.group(ItemStack.SINGLE_ITEM_CODEC.fieldOf("item").forGetter((recipeitemstack_stackprovider) -> {
++ return recipeitemstack_stackprovider.item;
+ })).apply(instance, Ingredient.ItemValue::new);
+ });
+
+- @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof Ingredient.ItemValue)) {
+ return false;
+ } else {
+- Ingredient.ItemValue ingredient_itemvalue = (Ingredient.ItemValue) object;
++ Ingredient.ItemValue recipeitemstack_stackprovider = (Ingredient.ItemValue) object;
+
+- return ingredient_itemvalue.item.getItem().equals(this.item.getItem()) && ingredient_itemvalue.item.getCount() == this.item.getCount();
++ return recipeitemstack_stackprovider.item.getItem().equals(this.item.getItem()) && recipeitemstack_stackprovider.item.getCount() == this.item.getCount();
+ }
+ }
+
+ @Override
+- @Override
+ public Collection<ItemStack> getItems() {
+ return Collections.singleton(this.item);
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Recipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Recipe.java.patch
new file mode 100644
index 0000000000..a1bd9ee38e
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/Recipe.java.patch
@@ -0,0 +1,30 @@
+--- a/net/minecraft/world/item/crafting/Recipe.java
++++ b/net/minecraft/world/item/crafting/Recipe.java
+@@ -22,11 +22,11 @@
+
+ ItemStack getResultItem(RegistryAccess registryAccess);
+
+- default NonNullList<ItemStack> getRemainingItems(C c0) {
+- NonNullList<ItemStack> nonnulllist = NonNullList.withSize(c0.getContainerSize(), ItemStack.EMPTY);
++ default NonNullList<ItemStack> getRemainingItems(C container) {
++ NonNullList<ItemStack> nonnulllist = NonNullList.withSize(container.getContainerSize(), ItemStack.EMPTY);
+
+ for (int i = 0; i < nonnulllist.size(); ++i) {
+- Item item = c0.getItem(i).getItem();
++ Item item = container.getItem(i).getItem();
+
+ if (item.hasCraftingRemainingItem()) {
+ nonnulllist.set(i, new ItemStack(item.getCraftingRemainingItem()));
+@@ -63,8 +63,10 @@
+ default boolean isIncomplete() {
+ NonNullList<Ingredient> nonnulllist = this.getIngredients();
+
+- return nonnulllist.isEmpty() || nonnulllist.stream().anyMatch((ingredient) -> {
+- return ingredient.getItems().length == 0;
++ return nonnulllist.isEmpty() || nonnulllist.stream().anyMatch((recipeitemstack) -> {
++ return recipeitemstack.getItems().length == 0;
+ });
+ }
++
++ org.bukkit.inventory.Recipe toBukkitRecipe(org.bukkit.NamespacedKey id); // CraftBukkit
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch
new file mode 100644
index 0000000000..16a1050265
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeHolder.java.patch
@@ -0,0 +1,35 @@
+--- a/net/minecraft/world/item/crafting/RecipeHolder.java
++++ b/net/minecraft/world/item/crafting/RecipeHolder.java
+@@ -1,10 +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) {
++public record RecipeHolder<T extends net.minecraft.world.item.crafting.Recipe<?>>(ResourceLocation id, T value) {
+
+- @Override
++ public final Recipe toBukkitRecipe() {
++ return this.value.toBukkitRecipe(CraftNamespacedKey.fromMinecraft(this.id));
++ }
++ // CraftBukkit end
++
+ public boolean equals(Object object) {
+ if (this == object) {
+ return true;
+@@ -25,12 +32,10 @@
+ }
+ }
+
+- @Override
+ public int hashCode() {
+ return this.id.hashCode();
+ }
+
+- @Override
+ public String toString() {
+ return this.id.toString();
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeManager.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeManager.java.patch
new file mode 100644
index 0000000000..ae8c6942ab
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/RecipeManager.java.patch
@@ -0,0 +1,274 @@
+--- a/net/minecraft/world/item/crafting/RecipeManager.java
++++ b/net/minecraft/world/item/crafting/RecipeManager.java
+@@ -24,21 +24,26 @@
+ 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;
+ import net.minecraft.util.GsonHelper;
+ import net.minecraft.util.profiling.ProfilerFiller;
+-import net.minecraft.world.Container;
+-import net.minecraft.world.item.ItemStack;
+-import net.minecraft.world.level.Level;
+-import org.slf4j.Logger;
+
+ 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;
+
+@@ -46,98 +51,121 @@
+ super(RecipeManager.GSON, "recipes");
+ }
+
+- @Override
+- protected void apply(Map<ResourceLocation, JsonElement> map, ResourceManager resourcemanager, ProfilerFiller profilerfiller) {
++ protected void apply(Map<ResourceLocation, JsonElement> object, ResourceManager resourceManager, ProfilerFiller profiler) {
+ this.hasErrors = false;
+- Map<RecipeType<?>, Builder<ResourceLocation, RecipeHolder<?>>> map1 = 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();
+- Iterator iterator = map.entrySet().iterator();
++ Iterator iterator = object.entrySet().iterator();
+
+ while (iterator.hasNext()) {
+ Entry<ResourceLocation, JsonElement> entry = (Entry) iterator.next();
+- ResourceLocation resourcelocation = (ResourceLocation) entry.getKey();
++ ResourceLocation minecraftkey = (ResourceLocation) entry.getKey();
+
+ try {
+- RecipeHolder<?> recipeholder = fromJson(resourcelocation, GsonHelper.convertToJsonObject((JsonElement) entry.getValue(), "top element"));
++ RecipeHolder<?> recipeholder = fromJson(minecraftkey, GsonHelper.convertToJsonObject((JsonElement) entry.getValue(), "top element"));
+
+- ((Builder) map1.computeIfAbsent(recipeholder.value().getType(), (recipetype) -> {
+- return ImmutableMap.builder();
+- })).put(resourcelocation, recipeholder);
+- builder.put(resourcelocation, recipeholder);
++ // 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 {}", resourcelocation, jsonparseexception);
++ RecipeManager.LOGGER.error("Parsing error loading recipe {}", minecraftkey, jsonparseexception);
+ }
+ }
+
+ this.recipes = (Map) map1.entrySet().stream().collect(ImmutableMap.toImmutableMap(Entry::getKey, (entry1) -> {
+- return ((Builder) entry1.getValue()).build();
++ return (entry1.getValue()); // CraftBukkit
+ }));
+- this.byName = builder.build();
++ 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 c0, Level level) {
+- return this.byType(recipetype).values().stream().filter((recipeholder) -> {
+- return recipeholder.value().matches(c0, level);
++ public <C extends Container, T extends Recipe<C>> Optional<RecipeHolder<T>> getRecipeFor(RecipeType<T> recipeType, C inventory, Level level) {
++ // 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(RecipeType<T> recipetype, C c0, Level level, @Nullable ResourceLocation resourcelocation) {
+- Map<ResourceLocation, RecipeHolder<T>> map = this.byType(recipetype);
++ public <C extends Container, T extends Recipe<C>> Optional<Pair<ResourceLocation, RecipeHolder<T>>> getRecipeFor(RecipeType<T> recipeType, C inventory, Level level, @Nullable ResourceLocation lastRecipe) {
++ Map<ResourceLocation, RecipeHolder<T>> map = this.byType(recipeType);
+
+- if (resourcelocation != null) {
+- RecipeHolder<T> recipeholder = (RecipeHolder) map.get(resourcelocation);
++ if (lastRecipe != null) {
++ RecipeHolder<T> recipeholder = (RecipeHolder) map.get(lastRecipe);
+
+- if (recipeholder != null && recipeholder.value().matches(c0, level)) {
+- return Optional.of(Pair.of(resourcelocation, recipeholder));
++ if (recipeholder != null && recipeholder.value().matches(inventory, level)) {
++ return Optional.of(Pair.of(lastRecipe, recipeholder));
+ }
+ }
+
+ return map.entrySet().stream().filter((entry) -> {
+- return ((RecipeHolder) entry.getValue()).value().matches(c0, level);
++ return ((RecipeHolder) entry.getValue()).value().matches(inventory, level);
+ }).findFirst().map((entry) -> {
+ return Pair.of((ResourceLocation) entry.getKey(), (RecipeHolder) entry.getValue());
+ });
+ }
+
+- public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getAllRecipesFor(RecipeType<T> recipetype) {
+- return List.copyOf(this.byType(recipetype).values());
++ public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getAllRecipesFor(RecipeType<T> recipeType) {
++ return List.copyOf(this.byType(recipeType).values());
+ }
+
+- public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getRecipesFor(RecipeType<T> recipetype, C c0, Level level) {
+- return (List) this.byType(recipetype).values().stream().filter((recipeholder) -> {
+- return recipeholder.value().matches(c0, level);
++ public <C extends Container, T extends Recipe<C>> List<RecipeHolder<T>> getRecipesFor(RecipeType<T> recipeType, C inventory, Level level) {
++ return (List) this.byType(recipeType).values().stream().filter((recipeholder) -> {
++ return recipeholder.value().matches(inventory, level);
+ }).sorted(Comparator.comparing((recipeholder) -> {
+ return recipeholder.value().getResultItem(level.registryAccess()).getDescriptionId();
+ })).collect(Collectors.toList());
+ }
+
+- private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, RecipeHolder<T>> byType(RecipeType<T> recipetype) {
+- return (Map) this.recipes.getOrDefault(recipetype, Collections.emptyMap());
++ private <C extends Container, T extends Recipe<C>> Map<ResourceLocation, RecipeHolder<T>> byType(RecipeType<T> recipeType) {
++ return (Map) this.recipes.getOrDefault(recipeType, new Object2ObjectLinkedOpenHashMap<>()); // CraftBukkit
+ }
+
+- public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> recipetype, C c0, Level level) {
+- Optional<RecipeHolder<T>> optional = this.getRecipeFor(recipetype, c0, level);
++ public <C extends Container, T extends Recipe<C>> NonNullList<ItemStack> getRemainingItemsFor(RecipeType<T> recipeType, C inventory, Level level) {
++ Optional<RecipeHolder<T>> optional = this.getRecipeFor(recipeType, inventory, level);
+
+ if (optional.isPresent()) {
+- return ((RecipeHolder) optional.get()).value().getRemainingItems(c0);
++ return ((RecipeHolder) optional.get()).value().getRemainingItems(inventory);
+ } else {
+- NonNullList<ItemStack> nonnulllist = NonNullList.withSize(c0.getContainerSize(), ItemStack.EMPTY);
++ NonNullList<ItemStack> nonnulllist = NonNullList.withSize(inventory.getContainerSize(), ItemStack.EMPTY);
+
+ for (int i = 0; i < nonnulllist.size(); ++i) {
+- nonnulllist.set(i, c0.getItem(i));
++ nonnulllist.set(i, inventory.getItem(i));
+ }
+
+ return nonnulllist;
+ }
+ }
+
+- public Optional<RecipeHolder<?>> byKey(ResourceLocation resourcelocation) {
+- return Optional.ofNullable((RecipeHolder) this.byName.get(resourcelocation));
++ public Optional<RecipeHolder<?>> byKey(ResourceLocation recipeId) {
++ return Optional.ofNullable((RecipeHolder) this.byName.get(recipeId));
+ }
+
+ public Collection<RecipeHolder<?>> getRecipes() {
+@@ -152,43 +180,62 @@
+ });
+ }
+
+- protected static RecipeHolder<?> fromJson(ResourceLocation resourcelocation, JsonObject jsonobject) {
+- Recipe<?> recipe = (Recipe) Util.getOrThrow(Recipe.CODEC.parse(JsonOps.INSTANCE, jsonobject), JsonParseException::new);
++ protected static RecipeHolder<?> fromJson(ResourceLocation minecraftkey, JsonObject jsonobject) {
++ Recipe<?> irecipe = (Recipe) Util.getOrThrow(Recipe.CODEC.parse(JsonOps.INSTANCE, jsonobject), JsonParseException::new);
+
+- return new RecipeHolder<>(resourcelocation, recipe);
++ return new RecipeHolder<>(minecraftkey, irecipe);
+ }
+
+- public void replaceRecipes(Iterable<RecipeHolder<?>> iterable) {
++ 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();
+
+- iterable.forEach((recipeholder) -> {
+- Map<ResourceLocation, RecipeHolder<?>> map1 = (Map) map.computeIfAbsent(recipeholder.value().getType(), (recipetype) -> {
+- return Maps.newHashMap();
++ recipes.forEach((recipeholder) -> {
++ Map<ResourceLocation, RecipeHolder<?>> map1 = (Map) map.computeIfAbsent(recipeholder.value().getType(), (recipes) -> {
++ return new Object2ObjectLinkedOpenHashMap<>(); // CraftBukkit
+ });
+- ResourceLocation resourcelocation = recipeholder.id();
+- RecipeHolder<?> recipeholder1 = (RecipeHolder) map1.put(resourcelocation, recipeholder);
++ ResourceLocation minecraftkey = recipeholder.id();
++ RecipeHolder<?> recipeholder1 = (RecipeHolder) map1.put(minecraftkey, recipeholder);
+
+- builder.put(resourcelocation, recipeholder);
++ builder.put(minecraftkey, recipeholder);
+ if (recipeholder1 != null) {
+- throw new IllegalStateException("Duplicate recipe ignored with ID " + resourcelocation);
++ 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
+ }
+
+- public static <C extends Container, T extends Recipe<C>> RecipeManager.CachedCheck<C, T> createCheck(final RecipeType<T> recipetype) {
++ // 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
+ private ResourceLocation lastRecipe;
+
+ @Override
+- @Override
+- public Optional<RecipeHolder<T>> getRecipeFor(C c0, Level level) {
+- RecipeManager recipemanager = level.getRecipeManager();
+- Optional<Pair<ResourceLocation, RecipeHolder<T>>> optional = recipemanager.getRecipeFor(recipetype, c0, level, this.lastRecipe);
++ public Optional<RecipeHolder<T>> getRecipeFor(C container, Level level) {
++ RecipeManager craftingmanager = level.getRecipeManager();
++ Optional<Pair<ResourceLocation, RecipeHolder<T>>> optional = craftingmanager.getRecipeFor(recipeType, container, level, this.lastRecipe);
+
+ if (optional.isPresent()) {
+ Pair<ResourceLocation, RecipeHolder<T>> pair = (Pair) optional.get();
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
new file mode 100644
index 0000000000..28bf8b2493
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapedRecipe.java.patch
@@ -0,0 +1,235 @@
+--- a/net/minecraft/world/item/crafting/ShapedRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapedRecipe.java
+@@ -6,11 +6,18 @@
+ import net.minecraft.core.RegistryAccess;
+ import net.minecraft.network.FriendlyByteBuf;
+ import net.minecraft.util.ExtraCodecs;
+-import net.minecraft.world.inventory.CraftingContainer;
++import net.minecraft.world.inventory.InventoryCrafting;
+ 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 {
++public class ShapedRecipe implements RecipeCrafting {
+
+ final ShapedRecipePattern pattern;
+ final ItemStack result;
+@@ -30,56 +37,109 @@
+ this(s, 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;
+ }
+
+ @Override
+- @Override
+ public String getGroup() {
+ return this.group;
+ }
+
+ @Override
+- @Override
+ public CraftingBookCategory category() {
+ return this.category;
+ }
+
+ @Override
+- @Override
+- public ItemStack getResultItem(RegistryAccess registryaccess) {
++ public ItemStack getResultItem(RegistryAccess registryAccess) {
+ return this.result;
+ }
+
+ @Override
+- @Override
+ public NonNullList<Ingredient> getIngredients() {
+ return this.pattern.ingredients();
+ }
+
+ @Override
+- @Override
+ public boolean showNotification() {
+ return this.showNotification;
+ }
+
+ @Override
+- @Override
+- public boolean canCraftInDimensions(int i, int j) {
+- return i >= this.pattern.width() && j >= this.pattern.height();
++ public boolean canCraftInDimensions(int width, int height) {
++ return width >= this.pattern.width() && height >= this.pattern.height();
+ }
+
+- @Override
+- public boolean matches(CraftingContainer craftingcontainer, Level level) {
+- return this.pattern.matches(craftingcontainer);
++ public boolean matches(InventoryCrafting inv, Level level) {
++ return this.pattern.matches(inv);
+ }
+
+- @Override
+- public ItemStack assemble(CraftingContainer craftingcontainer, RegistryAccess registryaccess) {
+- return this.getResultItem(registryaccess).copy();
++ public ItemStack assemble(InventoryCrafting container, RegistryAccess registryAccess) {
++ return this.getResultItem(registryAccess).copy();
+ }
+
+ public int getWidth() {
+@@ -91,60 +151,56 @@
+ }
+
+ @Override
+- @Override
+ public boolean isIncomplete() {
+ NonNullList<Ingredient> nonnulllist = this.getIngredients();
+
+- return nonnulllist.isEmpty() || nonnulllist.stream().filter((ingredient) -> {
+- return !ingredient.isEmpty();
+- }).anyMatch((ingredient) -> {
+- return ingredient.getItems().length == 0;
++ return nonnulllist.isEmpty() || nonnulllist.stream().filter((recipeitemstack) -> {
++ return !recipeitemstack.isEmpty();
++ }).anyMatch((recipeitemstack) -> {
++ return recipeitemstack.getItems().length == 0;
+ });
+ }
+
+ public static class Serializer implements RecipeSerializer<ShapedRecipe> {
+
+ public static final Codec<ShapedRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
+- return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapedrecipe) -> {
+- return shapedrecipe.group;
+- }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapedrecipe) -> {
+- return shapedrecipe.category;
+- }), ShapedRecipePattern.MAP_CODEC.forGetter((shapedrecipe) -> {
+- return shapedrecipe.pattern;
+- }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapedrecipe) -> {
+- return shapedrecipe.result;
+- }), ExtraCodecs.strictOptionalField(Codec.BOOL, "show_notification", true).forGetter((shapedrecipe) -> {
+- return shapedrecipe.showNotification;
++ return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapedrecipes) -> {
++ return shapedrecipes.group;
++ }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapedrecipes) -> {
++ return shapedrecipes.category;
++ }), ShapedRecipePattern.MAP_CODEC.forGetter((shapedrecipes) -> {
++ return shapedrecipes.pattern;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapedrecipes) -> {
++ return shapedrecipes.result;
++ }), ExtraCodecs.strictOptionalField(Codec.BOOL, "show_notification", true).forGetter((shapedrecipes) -> {
++ return shapedrecipes.showNotification;
+ })).apply(instance, ShapedRecipe::new);
+ });
+
+ public Serializer() {}
+
+ @Override
+- @Override
+ public Codec<ShapedRecipe> codec() {
+ return ShapedRecipe.Serializer.CODEC;
+ }
+
+ @Override
+- @Override
+- public ShapedRecipe fromNetwork(FriendlyByteBuf friendlybytebuf) {
+- String s = friendlybytebuf.readUtf();
+- CraftingBookCategory craftingbookcategory = (CraftingBookCategory) friendlybytebuf.readEnum(CraftingBookCategory.class);
+- ShapedRecipePattern shapedrecipepattern = ShapedRecipePattern.fromNetwork(friendlybytebuf);
+- ItemStack itemstack = friendlybytebuf.readItem();
+- boolean flag = friendlybytebuf.readBoolean();
++ public ShapedRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ String s = packetdataserializer.readUtf();
++ CraftingBookCategory craftingbookcategory = (CraftingBookCategory) packetdataserializer.readEnum(CraftingBookCategory.class);
++ ShapedRecipePattern shapedrecipepattern = ShapedRecipePattern.fromNetwork(packetdataserializer);
++ ItemStack itemstack = packetdataserializer.readItem();
++ boolean flag = packetdataserializer.readBoolean();
+
+ return new ShapedRecipe(s, craftingbookcategory, shapedrecipepattern, itemstack, flag);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf friendlybytebuf, ShapedRecipe shapedrecipe) {
+- friendlybytebuf.writeUtf(shapedrecipe.group);
+- friendlybytebuf.writeEnum(shapedrecipe.category);
+- shapedrecipe.pattern.toNetwork(friendlybytebuf);
+- friendlybytebuf.writeItem(shapedrecipe.result);
+- friendlybytebuf.writeBoolean(shapedrecipe.showNotification);
++ public void toNetwork(FriendlyByteBuf buffer, ShapedRecipe recipe) {
++ buffer.writeUtf(recipe.group);
++ buffer.writeEnum(recipe.category);
++ recipe.pattern.toNetwork(buffer);
++ buffer.writeItem(recipe.result);
++ buffer.writeBoolean(recipe.showNotification);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
new file mode 100644
index 0000000000..c3b7af75af
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/ShapelessRecipe.java.patch
@@ -0,0 +1,204 @@
+--- a/net/minecraft/world/item/crafting/ShapelessRecipe.java
++++ b/net/minecraft/world/item/crafting/ShapelessRecipe.java
+@@ -10,11 +10,17 @@
+ import net.minecraft.network.FriendlyByteBuf;
+ import net.minecraft.util.ExtraCodecs;
+ import net.minecraft.world.entity.player.StackedContents;
+-import net.minecraft.world.inventory.CraftingContainer;
++import net.minecraft.world.inventory.InventoryCrafting;
+ 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 {
++public class ShapelessRecipe implements RecipeCrafting {
+
+ final String group;
+ final CraftingBookCategory category;
+@@ -28,129 +34,134 @@
+ this.ingredients = nonnulllist;
+ }
+
++ // 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;
+ }
+
+ @Override
+- @Override
+ public String getGroup() {
+ return this.group;
+ }
+
+ @Override
+- @Override
+ public CraftingBookCategory category() {
+ return this.category;
+ }
+
+ @Override
+- @Override
+- public ItemStack getResultItem(RegistryAccess registryaccess) {
++ public ItemStack getResultItem(RegistryAccess registryAccess) {
+ return this.result;
+ }
+
+ @Override
+- @Override
+ public NonNullList<Ingredient> getIngredients() {
+ return this.ingredients;
+ }
+
+- @Override
+- public boolean matches(CraftingContainer craftingcontainer, Level level) {
+- StackedContents stackedcontents = new StackedContents();
++ public boolean matches(InventoryCrafting inv, Level level) {
++ StackedContents autorecipestackmanager = new StackedContents();
+ int i = 0;
+
+- for (int j = 0; j < craftingcontainer.getContainerSize(); ++j) {
+- ItemStack itemstack = craftingcontainer.getItem(j);
++ for (int j = 0; j < inv.getContainerSize(); ++j) {
++ ItemStack itemstack = inv.getItem(j);
+
+ if (!itemstack.isEmpty()) {
+ ++i;
+- stackedcontents.accountStack(itemstack, 1);
++ autorecipestackmanager.accountStack(itemstack, 1);
+ }
+ }
+
+- return i == this.ingredients.size() && stackedcontents.canCraft(this, (IntList) null);
++ return i == this.ingredients.size() && autorecipestackmanager.canCraft(this, (IntList) null);
+ }
+
+- @Override
+- public ItemStack assemble(CraftingContainer craftingcontainer, RegistryAccess registryaccess) {
++ public ItemStack assemble(InventoryCrafting container, RegistryAccess registryAccess) {
+ return this.result.copy();
+ }
+
+ @Override
+- @Override
+- public boolean canCraftInDimensions(int i, int j) {
+- return i * j >= this.ingredients.size();
++ public boolean canCraftInDimensions(int width, int height) {
++ return width * height >= this.ingredients.size();
+ }
+
+ public static class Serializer implements RecipeSerializer<ShapelessRecipe> {
+
+ private static final Codec<ShapelessRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
+- return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapelessrecipe) -> {
+- return shapelessrecipe.group;
+- }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapelessrecipe) -> {
+- return shapelessrecipe.category;
+- }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapelessrecipe) -> {
+- return shapelessrecipe.result;
++ return instance.group(ExtraCodecs.strictOptionalField(Codec.STRING, "group", "").forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.group;
++ }), CraftingBookCategory.CODEC.fieldOf("category").orElse(CraftingBookCategory.MISC).forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.category;
++ }), ItemStack.ITEM_WITH_COUNT_CODEC.fieldOf("result").forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.result;
+ }), Ingredient.CODEC_NONEMPTY.listOf().fieldOf("ingredients").flatXmap((list) -> {
+- Ingredient[] aingredient = (Ingredient[]) list.stream().filter((ingredient) -> {
+- return !ingredient.isEmpty();
++ Ingredient[] arecipeitemstack = (Ingredient[]) list.stream().filter((recipeitemstack) -> {
++ return !recipeitemstack.isEmpty();
+ }).toArray((i) -> {
+ return new Ingredient[i];
+ });
+
+- return aingredient.length == 0 ? DataResult.error(() -> {
++ return arecipeitemstack.length == 0 ? DataResult.error(() -> {
+ return "No ingredients for shapeless recipe";
+- }) : (aingredient.length > 9 ? DataResult.error(() -> {
++ }) : (arecipeitemstack.length > 9 ? DataResult.error(() -> {
+ return "Too many ingredients for shapeless recipe";
+- }) : DataResult.success(NonNullList.of(Ingredient.EMPTY, aingredient)));
+- }, DataResult::success).forGetter((shapelessrecipe) -> {
+- return shapelessrecipe.ingredients;
++ }) : DataResult.success(NonNullList.of(Ingredient.EMPTY, arecipeitemstack)));
++ }, DataResult::success).forGetter((shapelessrecipes) -> {
++ return shapelessrecipes.ingredients;
+ })).apply(instance, ShapelessRecipe::new);
+ });
+
+ public Serializer() {}
+
+ @Override
+- @Override
+ public Codec<ShapelessRecipe> codec() {
+ return ShapelessRecipe.Serializer.CODEC;
+ }
+
+ @Override
+- @Override
+- public ShapelessRecipe fromNetwork(FriendlyByteBuf friendlybytebuf) {
+- String s = friendlybytebuf.readUtf();
+- CraftingBookCategory craftingbookcategory = (CraftingBookCategory) friendlybytebuf.readEnum(CraftingBookCategory.class);
+- int i = friendlybytebuf.readVarInt();
++ public ShapelessRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ String s = packetdataserializer.readUtf();
++ CraftingBookCategory craftingbookcategory = (CraftingBookCategory) packetdataserializer.readEnum(CraftingBookCategory.class);
++ int i = packetdataserializer.readVarInt();
+ NonNullList<Ingredient> nonnulllist = NonNullList.withSize(i, Ingredient.EMPTY);
+
+ for (int j = 0; j < nonnulllist.size(); ++j) {
+- nonnulllist.set(j, Ingredient.fromNetwork(friendlybytebuf));
++ nonnulllist.set(j, Ingredient.fromNetwork(packetdataserializer));
+ }
+
+- ItemStack itemstack = friendlybytebuf.readItem();
++ ItemStack itemstack = packetdataserializer.readItem();
+
+ return new ShapelessRecipe(s, craftingbookcategory, itemstack, nonnulllist);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf friendlybytebuf, ShapelessRecipe shapelessrecipe) {
+- friendlybytebuf.writeUtf(shapelessrecipe.group);
+- friendlybytebuf.writeEnum(shapelessrecipe.category);
+- friendlybytebuf.writeVarInt(shapelessrecipe.ingredients.size());
+- Iterator iterator = shapelessrecipe.ingredients.iterator();
++ public void toNetwork(FriendlyByteBuf buffer, ShapelessRecipe recipe) {
++ buffer.writeUtf(recipe.group);
++ buffer.writeEnum(recipe.category);
++ buffer.writeVarInt(recipe.ingredients.size());
++ Iterator iterator = recipe.ingredients.iterator();
+
+ while (iterator.hasNext()) {
+- Ingredient ingredient = (Ingredient) iterator.next();
++ Ingredient recipeitemstack = (Ingredient) iterator.next();
+
+- ingredient.toNetwork(friendlybytebuf);
++ recipeitemstack.toNetwork(buffer);
+ }
+
+- friendlybytebuf.writeItem(shapelessrecipe.result);
++ buffer.writeItem(recipe.result);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
new file mode 100644
index 0000000000..6869ddcb4f
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmeltingRecipe.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/crafting/SmeltingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmeltingRecipe.java
+@@ -3,21 +3,40 @@
+ 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 s, CookingBookCategory cookingbookcategory, Ingredient ingredient, ItemStack itemstack, float f, int i) {
+- super(RecipeType.SMELTING, s, cookingbookcategory, ingredient, itemstack, f, i);
++ public SmeltingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.SMELTING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+- @Override
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.FURNACE);
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
new file mode 100644
index 0000000000..d4f0b6a3ff
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTransformRecipe.java.patch
@@ -0,0 +1,159 @@
+--- a/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTransformRecipe.java
+@@ -9,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 {
+
+@@ -17,70 +24,73 @@
+ final Ingredient addition;
+ final ItemStack result;
+
+- public SmithingTransformRecipe(Ingredient ingredient, Ingredient ingredient1, Ingredient ingredient2, ItemStack itemstack) {
+- this.template = ingredient;
+- this.base = ingredient1;
+- this.addition = ingredient2;
++ public SmithingTransformRecipe(Ingredient recipeitemstack, Ingredient recipeitemstack1, Ingredient recipeitemstack2, ItemStack itemstack) {
++ this.template = recipeitemstack;
++ this.base = recipeitemstack1;
++ this.addition = recipeitemstack2;
+ this.result = itemstack;
+ }
+
+ @Override
+- @Override
+ public boolean matches(Container container, Level level) {
+ return this.template.test(container.getItem(0)) && this.base.test(container.getItem(1)) && this.addition.test(container.getItem(2));
+ }
+
+ @Override
+- @Override
+- public ItemStack assemble(Container container, RegistryAccess registryaccess) {
++ public ItemStack assemble(Container container, RegistryAccess registryAccess) {
+ ItemStack itemstack = this.result.copy();
+- CompoundTag compoundtag = container.getItem(1).getTag();
++ CompoundTag nbttagcompound = container.getItem(1).getTag();
+
+- if (compoundtag != null) {
+- itemstack.setTag(compoundtag.copy());
++ if (nbttagcompound != null) {
++ itemstack.setTag(nbttagcompound.copy());
+ }
+
+ return itemstack;
+ }
+
+ @Override
+- @Override
+- public ItemStack getResultItem(RegistryAccess registryaccess) {
++ public ItemStack getResultItem(RegistryAccess registryAccess) {
+ return this.result;
+ }
+
+ @Override
+- @Override
+- public boolean isTemplateIngredient(ItemStack itemstack) {
+- return this.template.test(itemstack);
++ public boolean isTemplateIngredient(ItemStack stack) {
++ return this.template.test(stack);
+ }
+
+ @Override
+- @Override
+- public boolean isBaseIngredient(ItemStack itemstack) {
+- return this.base.test(itemstack);
++ public boolean isBaseIngredient(ItemStack stack) {
++ return this.base.test(stack);
+ }
+
+ @Override
+- @Override
+- public boolean isAdditionIngredient(ItemStack itemstack) {
+- return this.addition.test(itemstack);
++ public boolean isAdditionIngredient(ItemStack stack) {
++ return this.addition.test(stack);
+ }
+
+ @Override
+- @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMITHING_TRANSFORM;
+ }
+
+ @Override
+- @Override
+ public boolean isIncomplete() {
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTransformRecipe> {
++ // 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;
+@@ -93,31 +103,28 @@
+ })).apply(instance, SmithingTransformRecipe::new);
+ });
+
+- public Serializer() {}
++ public a() {}
+
+ @Override
+- @Override
+ public Codec<SmithingTransformRecipe> codec() {
+- return SmithingTransformRecipe.Serializer.CODEC;
++ return SmithingTransformRecipe.a.CODEC;
+ }
+
+ @Override
+- @Override
+- public SmithingTransformRecipe fromNetwork(FriendlyByteBuf friendlybytebuf) {
+- Ingredient ingredient = Ingredient.fromNetwork(friendlybytebuf);
+- Ingredient ingredient1 = Ingredient.fromNetwork(friendlybytebuf);
+- Ingredient ingredient2 = Ingredient.fromNetwork(friendlybytebuf);
+- ItemStack itemstack = friendlybytebuf.readItem();
++ public SmithingTransformRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ Ingredient recipeitemstack = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack1 = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack2 = Ingredient.fromNetwork(packetdataserializer);
++ ItemStack itemstack = packetdataserializer.readItem();
+
+- return new SmithingTransformRecipe(ingredient, ingredient1, ingredient2, itemstack);
++ return new SmithingTransformRecipe(recipeitemstack, recipeitemstack1, recipeitemstack2, itemstack);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf friendlybytebuf, SmithingTransformRecipe smithingtransformrecipe) {
+- smithingtransformrecipe.template.toNetwork(friendlybytebuf);
+- smithingtransformrecipe.base.toNetwork(friendlybytebuf);
+- smithingtransformrecipe.addition.toNetwork(friendlybytebuf);
+- friendlybytebuf.writeItem(smithingtransformrecipe.result);
++ public void toNetwork(FriendlyByteBuf packetdataserializer, SmithingTransformRecipe smithingtransformrecipe) {
++ smithingtransformrecipe.template.toNetwork(packetdataserializer);
++ smithingtransformrecipe.base.toNetwork(packetdataserializer);
++ smithingtransformrecipe.addition.toNetwork(packetdataserializer);
++ packetdataserializer.writeItem(smithingtransformrecipe.result);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
new file mode 100644
index 0000000000..8e6da53406
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmithingTrimRecipe.java.patch
@@ -0,0 +1,178 @@
+--- a/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
++++ b/net/minecraft/world/item/crafting/SmithingTrimRecipe.java
+@@ -17,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 {
+
+@@ -24,29 +30,27 @@
+ final Ingredient base;
+ final Ingredient addition;
+
+- public SmithingTrimRecipe(Ingredient ingredient, Ingredient ingredient1, Ingredient ingredient2) {
+- this.template = ingredient;
+- this.base = ingredient1;
+- this.addition = ingredient2;
++ public SmithingTrimRecipe(Ingredient recipeitemstack, Ingredient recipeitemstack1, Ingredient recipeitemstack2) {
++ this.template = recipeitemstack;
++ this.base = recipeitemstack1;
++ this.addition = recipeitemstack2;
+ }
+
+ @Override
+- @Override
+ public boolean matches(Container container, Level level) {
+ return this.template.test(container.getItem(0)) && this.base.test(container.getItem(1)) && this.addition.test(container.getItem(2));
+ }
+
+ @Override
+- @Override
+- public ItemStack assemble(Container container, RegistryAccess registryaccess) {
++ public ItemStack assemble(Container container, RegistryAccess registryAccess) {
+ ItemStack itemstack = container.getItem(1);
+
+ if (this.base.test(itemstack)) {
+- Optional<Holder.Reference<TrimMaterial>> optional = TrimMaterials.getFromIngredient(registryaccess, container.getItem(2));
+- Optional<Holder.Reference<TrimPattern>> optional1 = TrimPatterns.getFromTemplate(registryaccess, container.getItem(0));
++ Optional<Holder.Reference<TrimMaterial>> optional = TrimMaterials.getFromIngredient(registryAccess, container.getItem(2));
++ Optional<Holder.Reference<TrimPattern>> optional1 = TrimPatterns.getFromTemplate(registryAccess, container.getItem(0));
+
+ if (optional.isPresent() && optional1.isPresent()) {
+- Optional<ArmorTrim> optional2 = ArmorTrim.getTrim(registryaccess, itemstack, false);
++ Optional<ArmorTrim> optional2 = ArmorTrim.getTrim(registryAccess, itemstack, false);
+
+ if (optional2.isPresent() && ((ArmorTrim) optional2.get()).hasPatternAndMaterial((Holder) optional1.get(), (Holder) optional.get())) {
+ return ItemStack.EMPTY;
+@@ -57,7 +61,7 @@
+ itemstack1.setCount(1);
+ ArmorTrim armortrim = new ArmorTrim((Holder) optional.get(), (Holder) optional1.get());
+
+- if (ArmorTrim.setTrim(registryaccess, itemstack1, armortrim)) {
++ if (ArmorTrim.setTrim(registryAccess, itemstack1, armortrim)) {
+ return itemstack1;
+ }
+ }
+@@ -67,18 +71,17 @@
+ }
+
+ @Override
+- @Override
+- public ItemStack getResultItem(RegistryAccess registryaccess) {
++ public ItemStack getResultItem(RegistryAccess registryAccess) {
+ ItemStack itemstack = new ItemStack(Items.IRON_CHESTPLATE);
+- Optional<Holder.Reference<TrimPattern>> optional = registryaccess.registryOrThrow(Registries.TRIM_PATTERN).holders().findFirst();
++ Optional<Holder.Reference<TrimPattern>> optional = registryAccess.registryOrThrow(Registries.TRIM_PATTERN).holders().findFirst();
+
+ if (optional.isPresent()) {
+- Optional<Holder.Reference<TrimMaterial>> optional1 = registryaccess.registryOrThrow(Registries.TRIM_MATERIAL).getHolder(TrimMaterials.REDSTONE);
++ Optional<Holder.Reference<TrimMaterial>> optional1 = registryAccess.registryOrThrow(Registries.TRIM_MATERIAL).getHolder(TrimMaterials.REDSTONE);
+
+ if (optional1.isPresent()) {
+ ArmorTrim armortrim = new ArmorTrim((Holder) optional1.get(), (Holder) optional.get());
+
+- ArmorTrim.setTrim(registryaccess, itemstack, armortrim);
++ ArmorTrim.setTrim(registryAccess, itemstack, armortrim);
+ }
+ }
+
+@@ -86,37 +89,39 @@
+ }
+
+ @Override
+- @Override
+- public boolean isTemplateIngredient(ItemStack itemstack) {
+- return this.template.test(itemstack);
++ public boolean isTemplateIngredient(ItemStack stack) {
++ return this.template.test(stack);
+ }
+
+ @Override
+- @Override
+- public boolean isBaseIngredient(ItemStack itemstack) {
+- return this.base.test(itemstack);
++ public boolean isBaseIngredient(ItemStack stack) {
++ return this.base.test(stack);
+ }
+
+ @Override
+- @Override
+- public boolean isAdditionIngredient(ItemStack itemstack) {
+- return this.addition.test(itemstack);
++ public boolean isAdditionIngredient(ItemStack stack) {
++ return this.addition.test(stack);
+ }
+
+ @Override
+- @Override
+ public RecipeSerializer<?> getSerializer() {
+ return RecipeSerializer.SMITHING_TRIM;
+ }
+
+ @Override
+- @Override
+ public boolean isIncomplete() {
+ return Stream.of(this.template, this.base, this.addition).anyMatch(Ingredient::isEmpty);
+ }
+
+- public static class Serializer implements RecipeSerializer<SmithingTrimRecipe> {
++ // 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
+
++ public static class a implements RecipeSerializer<SmithingTrimRecipe> {
++
+ private static final Codec<SmithingTrimRecipe> CODEC = RecordCodecBuilder.create((instance) -> {
+ return instance.group(Ingredient.CODEC.fieldOf("template").forGetter((smithingtrimrecipe) -> {
+ return smithingtrimrecipe.template;
+@@ -127,29 +132,26 @@
+ })).apply(instance, SmithingTrimRecipe::new);
+ });
+
+- public Serializer() {}
++ public a() {}
+
+ @Override
+- @Override
+ public Codec<SmithingTrimRecipe> codec() {
+- return SmithingTrimRecipe.Serializer.CODEC;
++ return SmithingTrimRecipe.a.CODEC;
+ }
+
+ @Override
+- @Override
+- public SmithingTrimRecipe fromNetwork(FriendlyByteBuf friendlybytebuf) {
+- Ingredient ingredient = Ingredient.fromNetwork(friendlybytebuf);
+- Ingredient ingredient1 = Ingredient.fromNetwork(friendlybytebuf);
+- Ingredient ingredient2 = Ingredient.fromNetwork(friendlybytebuf);
++ public SmithingTrimRecipe fromNetwork(FriendlyByteBuf packetdataserializer) {
++ Ingredient recipeitemstack = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack1 = Ingredient.fromNetwork(packetdataserializer);
++ Ingredient recipeitemstack2 = Ingredient.fromNetwork(packetdataserializer);
+
+- return new SmithingTrimRecipe(ingredient, ingredient1, ingredient2);
++ return new SmithingTrimRecipe(recipeitemstack, recipeitemstack1, recipeitemstack2);
+ }
+
+- @Override
+- public void toNetwork(FriendlyByteBuf friendlybytebuf, SmithingTrimRecipe smithingtrimrecipe) {
+- smithingtrimrecipe.template.toNetwork(friendlybytebuf);
+- smithingtrimrecipe.base.toNetwork(friendlybytebuf);
+- smithingtrimrecipe.addition.toNetwork(friendlybytebuf);
++ public void toNetwork(FriendlyByteBuf packetdataserializer, SmithingTrimRecipe smithingtrimrecipe) {
++ smithingtrimrecipe.template.toNetwork(packetdataserializer);
++ smithingtrimrecipe.base.toNetwork(packetdataserializer);
++ smithingtrimrecipe.addition.toNetwork(packetdataserializer);
+ }
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
new file mode 100644
index 0000000000..d5799e7952
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/SmokingRecipe.java.patch
@@ -0,0 +1,47 @@
+--- a/net/minecraft/world/item/crafting/SmokingRecipe.java
++++ b/net/minecraft/world/item/crafting/SmokingRecipe.java
+@@ -3,21 +3,40 @@
+ 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 s, CookingBookCategory cookingbookcategory, Ingredient ingredient, ItemStack itemstack, float f, int i) {
+- super(RecipeType.SMOKING, s, cookingbookcategory, ingredient, itemstack, f, i);
++ public SmokingRecipe(String s, CookingBookCategory cookingbookcategory, Ingredient recipeitemstack, ItemStack itemstack, float f, int i) {
++ super(RecipeType.SMOKING, s, cookingbookcategory, recipeitemstack, itemstack, f, i);
+ }
+
+ @Override
+- @Override
+ public ItemStack getToastSymbol() {
+ return new ItemStack(Blocks.SMOKER);
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
new file mode 100644
index 0000000000..0b933cd748
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/crafting/StonecutterRecipe.java.patch
@@ -0,0 +1,48 @@
+--- a/net/minecraft/world/item/crafting/StonecutterRecipe.java
++++ b/net/minecraft/world/item/crafting/StonecutterRecipe.java
+@@ -5,21 +5,39 @@
+ 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 s, Ingredient ingredient, ItemStack itemstack) {
+- super(RecipeType.STONECUTTING, RecipeSerializer.STONECUTTER, s, ingredient, itemstack);
++ public StonecutterRecipe(String s, Ingredient recipeitemstack, ItemStack itemstack) {
++ super(RecipeType.STONECUTTING, RecipeSerializer.STONECUTTER, s, recipeitemstack, itemstack);
+ }
+
+ @Override
+- @Override
+- public boolean matches(Container container, Level level) {
+- return this.ingredient.test(container.getItem(0));
++ public boolean matches(Container inv, Level level) {
++ return this.ingredient.test(inv.getItem(0));
+ }
+
+ @Override
+- @Override
+ 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-spigotflower/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch
new file mode 100644
index 0000000000..1a94a27b76
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/DamageEnchantment.java.patch
@@ -0,0 +1,90 @@
+--- a/net/minecraft/world/item/enchantment/DamageEnchantment.java
++++ b/net/minecraft/world/item/enchantment/DamageEnchantment.java
+@@ -3,9 +3,9 @@
+ import net.minecraft.world.effect.MobEffectInstance;
+ import net.minecraft.world.effect.MobEffects;
+ import net.minecraft.world.entity.Entity;
++import net.minecraft.world.entity.EnumMonsterType;
+ import net.minecraft.world.entity.EquipmentSlot;
+ import net.minecraft.world.entity.LivingEntity;
+-import net.minecraft.world.entity.MobType;
+ import net.minecraft.world.item.AxeItem;
+ import net.minecraft.world.item.ItemStack;
+
+@@ -20,57 +20,50 @@
+ private static final int[] LEVEL_COST_SPAN = new int[]{20, 20, 20};
+ public final int type;
+
+- public DamageEnchantment(Enchantment.Rarity enchantment_rarity, int i, EquipmentSlot... aequipmentslot) {
+- super(enchantment_rarity, EnchantmentCategory.WEAPON, aequipmentslot);
+- this.type = i;
++ public DamageEnchantment(Enchantment.Rarity rarity, int type, EquipmentSlot... applicableSlots) {
++ super(rarity, EnchantmentCategory.WEAPON, applicableSlots);
++ this.type = type;
+ }
+
+ @Override
+- @Override
+- public int getMinCost(int i) {
+- return DamageEnchantment.MIN_COST[this.type] + (i - 1) * DamageEnchantment.LEVEL_COST[this.type];
++ public int getMinCost(int enchantmentLevel) {
++ return DamageEnchantment.MIN_COST[this.type] + (enchantmentLevel - 1) * DamageEnchantment.LEVEL_COST[this.type];
+ }
+
+ @Override
+- @Override
+- public int getMaxCost(int i) {
+- return this.getMinCost(i) + DamageEnchantment.LEVEL_COST_SPAN[this.type];
++ public int getMaxCost(int enchantmentLevel) {
++ return this.getMinCost(enchantmentLevel) + DamageEnchantment.LEVEL_COST_SPAN[this.type];
+ }
+
+ @Override
+- @Override
+ public int getMaxLevel() {
+ return 5;
+ }
+
+ @Override
+- @Override
+- public float getDamageBonus(int i, MobType mobtype) {
+- return this.type == 0 ? 1.0F + (float) Math.max(0, i - 1) * 0.5F : (this.type == 1 && mobtype == MobType.UNDEAD ? (float) i * 2.5F : (this.type == 2 && mobtype == MobType.ARTHROPOD ? (float) i * 2.5F : 0.0F));
++ public float getDamageBonus(int level, EnumMonsterType creatureType) {
++ return this.type == 0 ? 1.0F + (float) Math.max(0, level - 1) * 0.5F : (this.type == 1 && creatureType == EnumMonsterType.UNDEAD ? (float) level * 2.5F : (this.type == 2 && creatureType == EnumMonsterType.ARTHROPOD ? (float) level * 2.5F : 0.0F));
+ }
+
+ @Override
+- @Override
+- public boolean checkCompatibility(Enchantment enchantment) {
+- return !(enchantment instanceof DamageEnchantment);
++ public boolean checkCompatibility(Enchantment ench) {
++ return !(ench instanceof DamageEnchantment);
+ }
+
+ @Override
+- @Override
+- public boolean canEnchant(ItemStack itemstack) {
+- return itemstack.getItem() instanceof AxeItem ? true : super.canEnchant(itemstack);
++ public boolean canEnchant(ItemStack stack) {
++ return stack.getItem() instanceof AxeItem ? true : super.canEnchant(stack);
+ }
+
+ @Override
+- @Override
+- public void doPostAttack(LivingEntity livingentity, Entity entity, int i) {
+- if (entity instanceof LivingEntity) {
+- LivingEntity livingentity1 = (LivingEntity) entity;
++ public void doPostAttack(LivingEntity user, Entity target, int level) {
++ if (target instanceof LivingEntity) {
++ LivingEntity entityliving1 = (LivingEntity) target;
+
+- if (this.type == 2 && i > 0 && livingentity1.getMobType() == MobType.ARTHROPOD) {
+- int j = 20 + livingentity.getRandom().nextInt(10 * i);
++ if (this.type == 2 && level > 0 && entityliving1.getMobType() == EnumMonsterType.ARTHROPOD) {
++ int j = 20 + user.getRandom().nextInt(10 * level);
+
+- livingentity1.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, j, 3));
++ entityliving1.addEffect(new MobEffectInstance(MobEffects.MOVEMENT_SLOWDOWN, j, 3), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit
+ }
+ }
+
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch
new file mode 100644
index 0000000000..d6b70c75f8
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java.patch
@@ -0,0 +1,98 @@
+--- a/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java
++++ b/net/minecraft/world/item/enchantment/FrostWalkerEnchantment.java
+@@ -8,59 +8,58 @@
+ import net.minecraft.world.level.Level;
+ import net.minecraft.world.level.block.Blocks;
+ import net.minecraft.world.level.block.FrostedIceBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.phys.shapes.CollisionContext;
+
+ public class FrostWalkerEnchantment extends Enchantment {
+
+- public FrostWalkerEnchantment(Enchantment.Rarity enchantment_rarity, EquipmentSlot... aequipmentslot) {
+- super(enchantment_rarity, EnchantmentCategory.ARMOR_FEET, aequipmentslot);
++ public FrostWalkerEnchantment(Enchantment.Rarity rarity, EquipmentSlot... applicableSlots) {
++ super(rarity, EnchantmentCategory.ARMOR_FEET, applicableSlots);
+ }
+
+ @Override
+- @Override
+- public int getMinCost(int i) {
+- return i * 10;
++ public int getMinCost(int enchantmentLevel) {
++ return enchantmentLevel * 10;
+ }
+
+ @Override
+- @Override
+- public int getMaxCost(int i) {
+- return this.getMinCost(i) + 15;
++ public int getMaxCost(int enchantmentLevel) {
++ return this.getMinCost(enchantmentLevel) + 15;
+ }
+
+ @Override
+- @Override
+ public boolean isTreasureOnly() {
+ return true;
+ }
+
+ @Override
+- @Override
+ public int getMaxLevel() {
+ return 2;
+ }
+
+- public static void onEntityMoved(LivingEntity livingentity, Level level, BlockPos blockpos, int i) {
+- if (livingentity.onGround()) {
+- BlockState blockstate = Blocks.FROSTED_ICE.defaultBlockState();
+- int j = Math.min(16, 2 + i);
+- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos();
+- Iterator iterator = BlockPos.betweenClosed(blockpos.offset(-j, -1, -j), blockpos.offset(j, -1, j)).iterator();
++ public static void onEntityMoved(LivingEntity living, Level level, BlockPos pos, int levelConflicting) {
++ if (living.onGround()) {
++ IBlockData iblockdata = Blocks.FROSTED_ICE.defaultBlockState();
++ int j = Math.min(16, 2 + levelConflicting);
++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
++ Iterator iterator = BlockPos.betweenClosed(pos.offset(-j, -1, -j), pos.offset(j, -1, j)).iterator();
+
+ while (iterator.hasNext()) {
+- BlockPos blockpos1 = (BlockPos) iterator.next();
++ BlockPos blockposition1 = (BlockPos) iterator.next();
+
+- if (blockpos1.closerToCenterThan(livingentity.position(), (double) j)) {
+- blockpos_mutableblockpos.set(blockpos1.getX(), blockpos1.getY() + 1, blockpos1.getZ());
+- BlockState blockstate1 = level.getBlockState(blockpos_mutableblockpos);
++ if (blockposition1.closerToCenterThan(living.position(), (double) j)) {
++ blockposition_mutableblockposition.set(blockposition1.getX(), blockposition1.getY() + 1, blockposition1.getZ());
++ IBlockData iblockdata1 = level.getBlockState(blockposition_mutableblockposition);
+
+- if (blockstate1.isAir()) {
+- BlockState blockstate2 = level.getBlockState(blockpos1);
++ if (iblockdata1.isAir()) {
++ IBlockData iblockdata2 = level.getBlockState(blockposition1);
+
+- if (blockstate2 == FrostedIceBlock.meltsInto() && blockstate.canSurvive(level, blockpos1) && level.isUnobstructed(blockstate, blockpos1, CollisionContext.empty())) {
+- level.setBlockAndUpdate(blockpos1, blockstate);
+- level.scheduleTick(blockpos1, Blocks.FROSTED_ICE, Mth.nextInt(livingentity.getRandom(), 60, 120));
++ 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
+ }
+ }
+ }
+@@ -70,8 +69,7 @@
+ }
+
+ @Override
+- @Override
+- public boolean checkCompatibility(Enchantment enchantment) {
+- return super.checkCompatibility(enchantment) && enchantment != Enchantments.DEPTH_STRIDER;
++ public boolean checkCompatibility(Enchantment ench) {
++ return super.checkCompatibility(ench) && ench != Enchantments.DEPTH_STRIDER;
+ }
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/Merchant.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/Merchant.java.patch
new file mode 100644
index 0000000000..e01c6979e5
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/Merchant.java.patch
@@ -0,0 +1,32 @@
+--- a/net/minecraft/world/item/trading/Merchant.java
++++ b/net/minecraft/world/item/trading/Merchant.java
+@@ -36,20 +36,22 @@
+ return false;
+ }
+
+- default void openTradingScreen(Player player, Component component, int i) {
+- OptionalInt optionalint = player.openMenu(new SimpleMenuProvider((j, inventory, player1) -> {
+- return new MerchantMenu(j, inventory, this);
+- }, component));
++ default void openTradingScreen(Player player, Component displayName, int level) {
++ OptionalInt optionalint = player.openMenu(new SimpleMenuProvider((j, playerinventory, entityhuman1) -> {
++ return new MerchantMenu(j, playerinventory, this);
++ }, displayName));
+
+ if (optionalint.isPresent()) {
+- MerchantOffers merchantoffers = this.getOffers();
++ MerchantOffers merchantrecipelist = this.getOffers();
+
+- if (!merchantoffers.isEmpty()) {
+- player.sendMerchantOffers(optionalint.getAsInt(), merchantoffers, i, this.getVillagerXp(), this.showProgressBar(), this.canRestock());
++ if (!merchantrecipelist.isEmpty()) {
++ player.sendMerchantOffers(optionalint.getAsInt(), merchantrecipelist, level, this.getVillagerXp(), this.showProgressBar(), this.canRestock());
+ }
+ }
+
+ }
+
+ boolean isClientSide();
++
++ org.bukkit.craftbukkit.inventory.CraftMerchant getCraftMerchant(); // CraftBukkit
+ }
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/MerchantOffer.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/MerchantOffer.java.patch
new file mode 100644
index 0000000000..83b82b1693
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/item/trading/MerchantOffer.java.patch
@@ -0,0 +1,261 @@
+--- a/net/minecraft/world/item/trading/MerchantOffer.java
++++ b/net/minecraft/world/item/trading/MerchantOffer.java
+@@ -5,86 +5,104 @@
+ 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;
+- private final ItemStack result;
+- private int uses;
+- private final int maxUses;
+- private boolean rewardExp;
+- private int specialPriceDiff;
+- private int demand;
+- private float priceMultiplier;
+- private int xp;
++ 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 MerchantOffer(CompoundTag compoundtag) {
++ 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.rewardExp = true;
+ this.xp = 1;
+- this.baseCostA = ItemStack.of(compoundtag.getCompound("buy"));
+- this.costB = ItemStack.of(compoundtag.getCompound("buyB"));
+- this.result = ItemStack.of(compoundtag.getCompound("sell"));
+- this.uses = compoundtag.getInt("uses");
+- if (compoundtag.contains("maxUses", 99)) {
+- this.maxUses = compoundtag.getInt("maxUses");
++ this.baseCostA = ItemStack.of(compoundTag.getCompound("buy"));
++ this.costB = ItemStack.of(compoundTag.getCompound("buyB"));
++ this.result = ItemStack.of(compoundTag.getCompound("sell"));
++ this.uses = compoundTag.getInt("uses");
++ if (compoundTag.contains("maxUses", 99)) {
++ this.maxUses = compoundTag.getInt("maxUses");
+ } else {
+ this.maxUses = 4;
+ }
+
+- if (compoundtag.contains("rewardExp", 1)) {
+- this.rewardExp = compoundtag.getBoolean("rewardExp");
++ if (compoundTag.contains("rewardExp", 1)) {
++ this.rewardExp = compoundTag.getBoolean("rewardExp");
+ }
+
+- if (compoundtag.contains("xp", 3)) {
+- this.xp = compoundtag.getInt("xp");
++ if (compoundTag.contains("xp", 3)) {
++ this.xp = compoundTag.getInt("xp");
+ }
+
+- if (compoundtag.contains("priceMultiplier", 5)) {
+- this.priceMultiplier = compoundtag.getFloat("priceMultiplier");
++ if (compoundTag.contains("priceMultiplier", 5)) {
++ this.priceMultiplier = compoundTag.getFloat("priceMultiplier");
+ }
+
+- this.specialPriceDiff = compoundtag.getInt("specialPrice");
+- this.demand = compoundtag.getInt("demand");
++ this.specialPriceDiff = compoundTag.getInt("specialPrice");
++ this.demand = compoundTag.getInt("demand");
+ }
+
+- public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, int i, int j, float f) {
+- this(itemstack, ItemStack.EMPTY, itemstack1, i, j, f);
++ public MerchantOffer(ItemStack baseCostA, ItemStack result, int maxUses, int xp, float priceMultiplier) {
++ this(baseCostA, ItemStack.EMPTY, result, maxUses, xp, priceMultiplier);
+ }
+
+- public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, ItemStack itemstack2, int i, int j, float f) {
+- this(itemstack, itemstack1, itemstack2, 0, i, j, f);
++ public MerchantOffer(ItemStack baseCostA, ItemStack costB, ItemStack result, int maxUses, int xp, float priceMultiplier) {
++ this(baseCostA, costB, result, 0, maxUses, xp, priceMultiplier);
+ }
+
+- public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, ItemStack itemstack2, int i, int j, int k, float f) {
+- this(itemstack, itemstack1, itemstack2, i, j, k, f, 0);
++ public MerchantOffer(ItemStack baseCostA, ItemStack costB, ItemStack result, int uses, int maxUses, int xp, float priceMultiplier) {
++ this(baseCostA, costB, result, uses, maxUses, xp, priceMultiplier, 0);
+ }
+
+- public MerchantOffer(ItemStack itemstack, ItemStack itemstack1, ItemStack itemstack2, int i, int j, int k, float f, int l) {
++ public MerchantOffer(ItemStack baseCostA, ItemStack costB, ItemStack result, int uses, int maxUses, int xp, float priceMultiplier, int demand) {
+ this.rewardExp = true;
+ this.xp = 1;
+- this.baseCostA = itemstack;
+- this.costB = itemstack1;
+- this.result = itemstack2;
+- this.uses = i;
+- this.maxUses = j;
+- this.xp = k;
+- this.priceMultiplier = f;
+- this.demand = l;
++ this.baseCostA = baseCostA;
++ this.costB = costB;
++ this.result = result;
++ this.uses = uses;
++ this.maxUses = maxUses;
++ this.xp = xp;
++ this.priceMultiplier = priceMultiplier;
++ this.demand = demand;
+ }
+
+- private MerchantOffer(MerchantOffer merchantoffer) {
++ private MerchantOffer(MerchantOffer merchantrecipe) {
+ this.rewardExp = true;
+ this.xp = 1;
+- this.baseCostA = merchantoffer.baseCostA.copy();
+- this.costB = merchantoffer.costB.copy();
+- this.result = merchantoffer.result.copy();
+- this.uses = merchantoffer.uses;
+- this.maxUses = merchantoffer.maxUses;
+- this.rewardExp = merchantoffer.rewardExp;
+- this.specialPriceDiff = merchantoffer.specialPriceDiff;
+- this.demand = merchantoffer.demand;
+- this.priceMultiplier = merchantoffer.priceMultiplier;
+- this.xp = merchantoffer.xp;
++ this.baseCostA = merchantrecipe.baseCostA.copy();
++ this.costB = merchantrecipe.costB.copy();
++ this.result = merchantrecipe.result.copy();
++ this.uses = merchantrecipe.uses;
++ this.maxUses = merchantrecipe.maxUses;
++ this.rewardExp = merchantrecipe.rewardExp;
++ this.specialPriceDiff = merchantrecipe.specialPriceDiff;
++ this.demand = merchantrecipe.demand;
++ this.priceMultiplier = merchantrecipe.priceMultiplier;
++ this.xp = merchantrecipe.xp;
+ }
+
+ public ItemStack getBaseCostA() {
+@@ -96,6 +114,7 @@
+ return ItemStack.EMPTY;
+ } else {
+ 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()));
+@@ -138,8 +157,8 @@
+ return this.demand;
+ }
+
+- public void addToSpecialPriceDiff(int i) {
+- this.specialPriceDiff += i;
++ public void addToSpecialPriceDiff(int add) {
++ this.specialPriceDiff += add;
+ }
+
+ public void resetSpecialPriceDiff() {
+@@ -150,8 +169,8 @@
+ return this.specialPriceDiff;
+ }
+
+- public void setSpecialPriceDiff(int i) {
+- this.specialPriceDiff = i;
++ public void setSpecialPriceDiff(int price) {
++ this.specialPriceDiff = price;
+ }
+
+ public float getPriceMultiplier() {
+@@ -179,46 +198,50 @@
+ }
+
+ public CompoundTag createTag() {
+- CompoundTag compoundtag = new CompoundTag();
++ CompoundTag nbttagcompound = new CompoundTag();
+
+- compoundtag.put("buy", this.baseCostA.save(new CompoundTag()));
+- compoundtag.put("sell", this.result.save(new CompoundTag()));
+- compoundtag.put("buyB", this.costB.save(new CompoundTag()));
+- compoundtag.putInt("uses", this.uses);
+- compoundtag.putInt("maxUses", this.maxUses);
+- compoundtag.putBoolean("rewardExp", this.rewardExp);
+- compoundtag.putInt("xp", this.xp);
+- compoundtag.putFloat("priceMultiplier", this.priceMultiplier);
+- compoundtag.putInt("specialPrice", this.specialPriceDiff);
+- compoundtag.putInt("demand", this.demand);
+- return compoundtag;
++ nbttagcompound.put("buy", this.baseCostA.save(new CompoundTag()));
++ nbttagcompound.put("sell", this.result.save(new CompoundTag()));
++ nbttagcompound.put("buyB", this.costB.save(new CompoundTag()));
++ nbttagcompound.putInt("uses", this.uses);
++ nbttagcompound.putInt("maxUses", this.maxUses);
++ nbttagcompound.putBoolean("rewardExp", this.rewardExp);
++ nbttagcompound.putInt("xp", this.xp);
++ nbttagcompound.putFloat("priceMultiplier", this.priceMultiplier);
++ nbttagcompound.putInt("specialPrice", this.specialPriceDiff);
++ nbttagcompound.putInt("demand", this.demand);
++ return nbttagcompound;
+ }
+
+- public boolean satisfiedBy(ItemStack itemstack, ItemStack itemstack1) {
+- return this.isRequiredItem(itemstack, this.getCostA()) && itemstack.getCount() >= this.getCostA().getCount() && this.isRequiredItem(itemstack1, this.costB) && itemstack1.getCount() >= this.costB.getCount();
++ public boolean satisfiedBy(ItemStack playerOfferA, ItemStack playerOfferB) {
++ return this.isRequiredItem(playerOfferA, this.getCostA()) && playerOfferA.getCount() >= this.getCostA().getCount() && this.isRequiredItem(playerOfferB, this.costB) && playerOfferB.getCount() >= this.costB.getCount();
+ }
+
+- private boolean isRequiredItem(ItemStack itemstack, ItemStack itemstack1) {
+- if (itemstack1.isEmpty() && itemstack.isEmpty()) {
++ private boolean isRequiredItem(ItemStack offer, ItemStack cost) {
++ if (cost.isEmpty() && offer.isEmpty()) {
+ return true;
+ } else {
+- ItemStack itemstack2 = itemstack.copy();
++ ItemStack itemstack2 = offer.copy();
+
+ if (itemstack2.getItem().canBeDepleted()) {
+ itemstack2.setDamageValue(itemstack2.getDamageValue());
+ }
+
+- return ItemStack.isSameItem(itemstack2, itemstack1) && (!itemstack1.hasTag() || itemstack2.hasTag() && NbtUtils.compareNbt(itemstack1.getTag(), itemstack2.getTag(), false));
++ return ItemStack.isSameItem(itemstack2, cost) && (!cost.hasTag() || itemstack2.hasTag() && NbtUtils.compareNbt(cost.getTag(), itemstack2.getTag(), false));
+ }
+ }
+
+- public boolean take(ItemStack itemstack, ItemStack itemstack1) {
+- if (!this.satisfiedBy(itemstack, itemstack1)) {
++ public boolean take(ItemStack playerOfferA, ItemStack playerOfferB) {
++ if (!this.satisfiedBy(playerOfferA, playerOfferB)) {
+ return false;
+ } else {
+- itemstack.shrink(this.getCostA().getCount());
++ // CraftBukkit start
++ if (!this.getCostA().isEmpty()) {
++ playerOfferA.shrink(this.getCostA().getCount());
++ }
++ // CraftBukkit end
+ if (!this.getCostB().isEmpty()) {
+- itemstack1.shrink(this.getCostB().getCount());
++ playerOfferB.shrink(this.getCostB().getCount());
+ }
+
+ return true;