--- a/net/minecraft/world/inventory/AnvilMenu.java
+++ b/net/minecraft/world/inventory/AnvilMenu.java
@@ -1,6 +1,7 @@
 package net.minecraft.world.inventory;
 
 import com.mojang.logging.LogUtils;
+import java.util.Iterator;
 import java.util.Map;
 import javax.annotation.Nullable;
 import net.minecraft.SharedConstants;
@@ -18,7 +19,12 @@
 import net.minecraft.world.level.block.state.BlockState;
 import org.slf4j.Logger;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventoryView;
+// CraftBukkit end
+
 public class AnvilMenu extends ItemCombinerMenu {
+
     public static final int INPUT_SLOT = 0;
     public static final int ADDITIONAL_SLOT = 1;
     public static final int RESULT_SLOT = 2;
@@ -28,7 +34,7 @@
     public int repairItemCountCost;
     @Nullable
     public String itemName;
-    public final DataSlot cost = DataSlot.standalone();
+    public final DataSlot cost;
     private static final int COST_FAIL = 0;
     private static final int COST_BASE = 1;
     private static final int COST_ADDED_BASE = 1;
@@ -40,6 +46,11 @@
     private static final int ADDITIONAL_SLOT_X_PLACEMENT = 76;
     private static final int RESULT_SLOT_X_PLACEMENT = 134;
     private static final int SLOT_Y_PLACEMENT = 47;
+    // CraftBukkit start
+    public static final int DEFAULT_DENIED_COST = -1;
+    public int maximumRepairCost = 40;
+    private CraftInventoryView bukkitEntity;
+    // CraftBukkit end
 
     public AnvilMenu(int syncId, Inventory inventory) {
         this(syncId, inventory, ContainerLevelAccess.NULL);
@@ -47,14 +58,15 @@
 
     public AnvilMenu(int syncId, Inventory inventory, ContainerLevelAccess context) {
         super(MenuType.ANVIL, syncId, inventory, context);
+        this.cost = DataSlot.standalone();
         this.addDataSlot(this.cost);
     }
 
     @Override
     protected ItemCombinerMenuSlotDefinition createInputSlotDefinitions() {
-        return ItemCombinerMenuSlotDefinition.create().withSlot(0, 27, 47, (stack) -> {
+        return ItemCombinerMenuSlotDefinition.create().withSlot(0, 27, 47, (itemstack) -> {
             return true;
-        }).withSlot(1, 76, 47, (stack) -> {
+        }).withSlot(1, 76, 47, (itemstack) -> {
             return true;
         }).withResultSlot(2, 134, 47).build();
     }
@@ -66,7 +78,7 @@
 
     @Override
     protected boolean mayPickup(Player player, boolean present) {
-        return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() > 0;
+        return (player.getAbilities().instabuild || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item
     }
 
     @Override
@@ -77,10 +89,11 @@
 
         this.inputSlots.setItem(0, ItemStack.EMPTY);
         if (this.repairItemCountCost > 0) {
-            ItemStack itemStack = this.inputSlots.getItem(1);
-            if (!itemStack.isEmpty() && itemStack.getCount() > this.repairItemCountCost) {
-                itemStack.shrink(this.repairItemCountCost);
-                this.inputSlots.setItem(1, itemStack);
+            ItemStack itemstack1 = this.inputSlots.getItem(1);
+
+            if (!itemstack1.isEmpty() && itemstack1.getCount() > this.repairItemCountCost) {
+                itemstack1.shrink(this.repairItemCountCost);
+                this.inputSlots.setItem(1, itemstack1);
             } else {
                 this.inputSlots.setItem(1, ItemStack.EMPTY);
             }
@@ -88,20 +101,32 @@
             this.inputSlots.setItem(1, ItemStack.EMPTY);
         }
 
-        this.cost.set(0);
-        this.access.execute((world, pos) -> {
-            BlockState blockState = world.getBlockState(pos);
-            if (!player.getAbilities().instabuild && blockState.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
-                BlockState blockState2 = AnvilBlock.damage(blockState);
-                if (blockState2 == null) {
-                    world.removeBlock(pos, false);
-                    world.levelEvent(1029, pos, 0);
+        this.cost.set(DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
+        this.access.execute((world, blockposition) -> {
+            BlockState iblockdata = world.getBlockState(blockposition);
+
+            if (!player.getAbilities().instabuild && iblockdata.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
+                BlockState iblockdata1 = AnvilBlock.damage(iblockdata);
+
+                // Paper start
+                com.destroystokyo.paper.event.block.AnvilDamagedEvent event = new com.destroystokyo.paper.event.block.AnvilDamagedEvent(getBukkitView(), iblockdata1 != null ? org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData.fromData(iblockdata1) : null);
+                if (!event.callEvent()) {
+                    return;
+                } else if (event.getDamageState() == com.destroystokyo.paper.event.block.AnvilDamagedEvent.DamageState.BROKEN) {
+                    iblockdata1 = null;
                 } else {
-                    world.setBlock(pos, blockState2, 2);
-                    world.levelEvent(1030, pos, 0);
+                    iblockdata1 = ((org.bukkit.craftbukkit.v1_20_R2.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, iblockdata.getValue(AnvilBlock.FACING));
+                }
+                // Paper end
+                if (iblockdata1 == null) {
+                    world.removeBlock(blockposition, false);
+                    world.levelEvent(1029, blockposition, 0);
+                } else {
+                    world.setBlock(blockposition, iblockdata1, 2);
+                    world.levelEvent(1030, blockposition, 0);
                 }
             } else {
-                world.levelEvent(1030, pos, 0);
+                world.levelEvent(1030, blockposition, 0);
             }
 
         });
@@ -109,167 +134,186 @@
 
     @Override
     public void createResult() {
-        ItemStack itemStack = this.inputSlots.getItem(0);
+        ItemStack itemstack = this.inputSlots.getItem(0);
+
         this.cost.set(1);
         int i = 0;
-        int j = 0;
-        int k = 0;
-        if (itemStack.isEmpty()) {
-            this.resultSlots.setItem(0, ItemStack.EMPTY);
-            this.cost.set(0);
+        byte b0 = 0;
+        byte b1 = 0;
+
+        if (itemstack.isEmpty()) {
+            org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+            this.cost.set(DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
         } else {
-            ItemStack itemStack2 = itemStack.copy();
-            ItemStack itemStack3 = this.inputSlots.getItem(1);
-            Map<Enchantment, Integer> map = EnchantmentHelper.getEnchantments(itemStack2);
-            j += itemStack.getBaseRepairCost() + (itemStack3.isEmpty() ? 0 : itemStack3.getBaseRepairCost());
+            ItemStack itemstack1 = itemstack.copy();
+            ItemStack itemstack2 = this.inputSlots.getItem(1);
+            Map<Enchantment, Integer> map = EnchantmentHelper.getEnchantments(itemstack1);
+            int j = b0 + itemstack.getBaseRepairCost() + (itemstack2.isEmpty() ? 0 : itemstack2.getBaseRepairCost());
+
             this.repairItemCountCost = 0;
-            if (!itemStack3.isEmpty()) {
-                boolean bl = itemStack3.is(Items.ENCHANTED_BOOK) && !EnchantedBookItem.getEnchantments(itemStack3).isEmpty();
-                if (itemStack2.isDamageableItem() && itemStack2.getItem().isValidRepairItem(itemStack, itemStack3)) {
-                    int l = Math.min(itemStack2.getDamageValue(), itemStack2.getMaxDamage() / 4);
-                    if (l <= 0) {
-                        this.resultSlots.setItem(0, ItemStack.EMPTY);
-                        this.cost.set(0);
+            if (!itemstack2.isEmpty()) {
+                boolean flag = itemstack2.is(Items.ENCHANTED_BOOK) && !EnchantedBookItem.getEnchantments(itemstack2).isEmpty();
+                int k;
+                int l;
+                int i1;
+
+                if (itemstack1.isDamageableItem() && itemstack1.getItem().isValidRepairItem(itemstack, itemstack2)) {
+                    k = Math.min(itemstack1.getDamageValue(), itemstack1.getMaxDamage() / 4);
+                    if (k <= 0) {
+                        org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+                        this.cost.set(DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
                         return;
                     }
 
-                    int m;
-                    for(m = 0; l > 0 && m < itemStack3.getCount(); ++m) {
-                        int n = itemStack2.getDamageValue() - l;
-                        itemStack2.setDamageValue(n);
+                    for (i1 = 0; k > 0 && i1 < itemstack2.getCount(); ++i1) {
+                        l = itemstack1.getDamageValue() - k;
+                        itemstack1.setDamageValue(l);
                         ++i;
-                        l = Math.min(itemStack2.getDamageValue(), itemStack2.getMaxDamage() / 4);
+                        k = Math.min(itemstack1.getDamageValue(), itemstack1.getMaxDamage() / 4);
                     }
 
-                    this.repairItemCountCost = m;
+                    this.repairItemCountCost = i1;
                 } else {
-                    if (!bl && (!itemStack2.is(itemStack3.getItem()) || !itemStack2.isDamageableItem())) {
-                        this.resultSlots.setItem(0, ItemStack.EMPTY);
-                        this.cost.set(0);
+                    if (!flag && (!itemstack1.is(itemstack2.getItem()) || !itemstack1.isDamageableItem())) {
+                        org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+                        this.cost.set(DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
                         return;
                     }
 
-                    if (itemStack2.isDamageableItem() && !bl) {
-                        int o = itemStack.getMaxDamage() - itemStack.getDamageValue();
-                        int p = itemStack3.getMaxDamage() - itemStack3.getDamageValue();
-                        int q = p + itemStack2.getMaxDamage() * 12 / 100;
-                        int r = o + q;
-                        int s = itemStack2.getMaxDamage() - r;
-                        if (s < 0) {
-                            s = 0;
+                    if (itemstack1.isDamageableItem() && !flag) {
+                        k = itemstack.getMaxDamage() - itemstack.getDamageValue();
+                        i1 = itemstack2.getMaxDamage() - itemstack2.getDamageValue();
+                        l = i1 + itemstack1.getMaxDamage() * 12 / 100;
+                        int j1 = k + l;
+                        int k1 = itemstack1.getMaxDamage() - j1;
+
+                        if (k1 < 0) {
+                            k1 = 0;
                         }
 
-                        if (s < itemStack2.getDamageValue()) {
-                            itemStack2.setDamageValue(s);
+                        if (k1 < itemstack1.getDamageValue()) {
+                            itemstack1.setDamageValue(k1);
                             i += 2;
                         }
                     }
 
-                    Map<Enchantment, Integer> map2 = EnchantmentHelper.getEnchantments(itemStack3);
-                    boolean bl2 = false;
-                    boolean bl3 = false;
+                    Map<Enchantment, Integer> map1 = EnchantmentHelper.getEnchantments(itemstack2);
+                    boolean flag1 = false;
+                    boolean flag2 = false;
+                    Iterator iterator = map1.keySet().iterator();
+
+                    while (iterator.hasNext()) {
+                        Enchantment enchantment = (Enchantment) iterator.next();
 
-                    for(Enchantment enchantment : map2.keySet()) {
                         if (enchantment != null) {
-                            int t = map.getOrDefault(enchantment, 0);
-                            int u = map2.get(enchantment);
-                            u = t == u ? u + 1 : Math.max(u, t);
-                            boolean bl4 = enchantment.canEnchant(itemStack);
-                            if (this.player.getAbilities().instabuild || itemStack.is(Items.ENCHANTED_BOOK)) {
-                                bl4 = true;
+                            int l1 = (Integer) map.getOrDefault(enchantment, 0);
+                            int i2 = (Integer) map1.get(enchantment);
+
+                            i2 = l1 == i2 ? i2 + 1 : Math.max(i2, l1);
+                            boolean flag3 = enchantment.canEnchant(itemstack);
+
+                            if (this.player.getAbilities().instabuild || itemstack.is(Items.ENCHANTED_BOOK)) {
+                                flag3 = true;
                             }
 
-                            for(Enchantment enchantment2 : map.keySet()) {
-                                if (enchantment2 != enchantment && !enchantment.isCompatibleWith(enchantment2)) {
-                                    bl4 = false;
+                            Iterator iterator1 = map.keySet().iterator();
+
+                            while (iterator1.hasNext()) {
+                                Enchantment enchantment1 = (Enchantment) iterator1.next();
+
+                                if (enchantment1 != enchantment && !enchantment.isCompatibleWith(enchantment1)) {
+                                    flag3 = false;
                                     ++i;
                                 }
                             }
 
-                            if (!bl4) {
-                                bl3 = true;
+                            if (!flag3) {
+                                flag2 = true;
                             } else {
-                                bl2 = true;
-                                if (u > enchantment.getMaxLevel()) {
-                                    u = enchantment.getMaxLevel();
+                                flag1 = true;
+                                if (i2 > enchantment.getMaxLevel()) {
+                                    i2 = enchantment.getMaxLevel();
                                 }
 
-                                map.put(enchantment, u);
-                                int v = 0;
+                                map.put(enchantment, i2);
+                                int j2 = 0;
+
                                 switch (enchantment.getRarity()) {
                                     case COMMON:
-                                        v = 1;
+                                        j2 = 1;
                                         break;
                                     case UNCOMMON:
-                                        v = 2;
+                                        j2 = 2;
                                         break;
                                     case RARE:
-                                        v = 4;
+                                        j2 = 4;
                                         break;
                                     case VERY_RARE:
-                                        v = 8;
+                                        j2 = 8;
                                 }
 
-                                if (bl) {
-                                    v = Math.max(1, v / 2);
+                                if (flag) {
+                                    j2 = Math.max(1, j2 / 2);
                                 }
 
-                                i += v * u;
-                                if (itemStack.getCount() > 1) {
+                                i += j2 * i2;
+                                if (itemstack.getCount() > 1) {
                                     i = 40;
                                 }
                             }
                         }
                     }
 
-                    if (bl3 && !bl2) {
-                        this.resultSlots.setItem(0, ItemStack.EMPTY);
-                        this.cost.set(0);
+                    if (flag2 && !flag1) {
+                        org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+                        this.cost.set(DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
                         return;
                     }
                 }
             }
 
             if (this.itemName != null && !Util.isBlank(this.itemName)) {
-                if (!this.itemName.equals(itemStack.getHoverName().getString())) {
-                    k = 1;
-                    i += k;
-                    itemStack2.setHoverName(Component.literal(this.itemName));
+                if (!this.itemName.equals(itemstack.getHoverName().getString())) {
+                    b1 = 1;
+                    i += b1;
+                    itemstack1.setHoverName(Component.literal(this.itemName));
                 }
-            } else if (itemStack.hasCustomHoverName()) {
-                k = 1;
-                i += k;
-                itemStack2.resetHoverName();
+            } else if (itemstack.hasCustomHoverName()) {
+                b1 = 1;
+                i += b1;
+                itemstack1.resetHoverName();
             }
 
             this.cost.set(j + i);
             if (i <= 0) {
-                itemStack2 = ItemStack.EMPTY;
+                itemstack1 = ItemStack.EMPTY;
             }
 
-            if (k == i && k > 0 && this.cost.get() >= 40) {
-                this.cost.set(39);
+            if (b1 == i && b1 > 0 && this.cost.get() >= this.maximumRepairCost) { // CraftBukkit
+                this.cost.set(this.maximumRepairCost - 1); // CraftBukkit
             }
 
-            if (this.cost.get() >= 40 && !this.player.getAbilities().instabuild) {
-                itemStack2 = ItemStack.EMPTY;
+            if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit
+                itemstack1 = ItemStack.EMPTY;
             }
 
-            if (!itemStack2.isEmpty()) {
-                int w = itemStack2.getBaseRepairCost();
-                if (!itemStack3.isEmpty() && w < itemStack3.getBaseRepairCost()) {
-                    w = itemStack3.getBaseRepairCost();
+            if (!itemstack1.isEmpty()) {
+                int k2 = itemstack1.getBaseRepairCost();
+
+                if (!itemstack2.isEmpty() && k2 < itemstack2.getBaseRepairCost()) {
+                    k2 = itemstack2.getBaseRepairCost();
                 }
 
-                if (k != i || k == 0) {
-                    w = calculateIncreasedRepairCost(w);
+                if (b1 != i || b1 == 0) {
+                    k2 = AnvilMenu.calculateIncreasedRepairCost(k2);
                 }
 
-                itemStack2.setRepairCost(w);
-                EnchantmentHelper.setEnchantments(map, itemStack2);
+                itemstack1.setRepairCost(k2);
+                EnchantmentHelper.setEnchantments(map, itemstack1);
             }
 
-            this.resultSlots.setItem(0, itemStack2);
+            org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit
+            sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client
             this.broadcastChanges();
         }
     }
@@ -279,19 +323,22 @@
     }
 
     public boolean setItemName(String newItemName) {
-        String string = validateName(newItemName);
-        if (string != null && !string.equals(this.itemName)) {
-            this.itemName = string;
+        String s1 = AnvilMenu.validateName(newItemName);
+
+        if (s1 != null && !s1.equals(this.itemName)) {
+            this.itemName = s1;
             if (this.getSlot(2).hasItem()) {
-                ItemStack itemStack = this.getSlot(2).getItem();
-                if (Util.isBlank(string)) {
-                    itemStack.resetHoverName();
+                ItemStack itemstack = this.getSlot(2).getItem();
+
+                if (Util.isBlank(s1)) {
+                    itemstack.resetHoverName();
                 } else {
-                    itemStack.setHoverName(Component.literal(string));
+                    itemstack.setHoverName(Component.literal(s1));
                 }
             }
 
             this.createResult();
+            org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper
             return true;
         } else {
             return false;
@@ -300,11 +347,26 @@
 
     @Nullable
     private static String validateName(String name) {
-        String string = SharedConstants.filterText(name);
-        return string.length() <= 50 ? string : null;
+        String s1 = SharedConstants.filterText(name);
+
+        return s1.length() <= 50 ? s1 : null;
     }
 
     public int getCost() {
         return this.cost.get();
     }
+
+    // CraftBukkit start
+    @Override
+    public CraftInventoryView getBukkitView() {
+        if (this.bukkitEntity != null) {
+            return this.bukkitEntity;
+        }
+
+        org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.v1_20_R2.inventory.CraftInventoryAnvil(
+                access.getLocation(), this.inputSlots, this.resultSlots, this);
+        this.bukkitEntity = new CraftInventoryView(this.player.getBukkitEntity(), inventory, this);
+        return this.bukkitEntity;
+    }
+    // CraftBukkit end
 }
