From 30672ed8f72fa215d0d92eccaaa8b0269305e892 Mon Sep 17 00:00:00 2001 From: William Blake Galbreath Date: Sun, 5 Jan 2025 11:51:38 -0800 Subject: [PATCH] Anvil API --- patches/api/0014-Anvil-API.patch | 189 --------------- patches/server/0016-Anvil-API.patch | 225 ------------------ .../inventory/AnvilInventory.java.patch | 45 ++++ .../inventory/view/AnvilView.java.patch | 37 +++ .../event/inventory/AnvilTakeResultEvent.java | 50 ++++ .../inventory/AnvilUpdateResultEvent.java | 35 +++ .../AbstractContainerMenu.java.patch | 10 + .../world/inventory/AnvilMenu.java.patch | 102 ++++++++ .../inventory/ItemCombinerMenu.java.patch | 12 + .../inventory/CraftInventoryAnvil.java.patch | 55 +++++ .../inventory/view/CraftAnvilView.java.patch | 29 +++ 11 files changed, 375 insertions(+), 414 deletions(-) delete mode 100644 patches/api/0014-Anvil-API.patch delete mode 100644 patches/server/0016-Anvil-API.patch create mode 100644 purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/AnvilInventory.java.patch create mode 100644 purpur-api/paper-patches/files/src/main/java/org/bukkit/inventory/view/AnvilView.java.patch create mode 100644 purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java create mode 100644 purpur-api/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java create mode 100644 purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AbstractContainerMenu.java.patch create mode 100644 purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/AnvilMenu.java.patch create mode 100644 purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch create mode 100644 purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch create mode 100644 purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch diff --git a/patches/api/0014-Anvil-API.patch b/patches/api/0014-Anvil-API.patch deleted file mode 100644 index 3601d5000..000000000 --- a/patches/api/0014-Anvil-API.patch +++ /dev/null @@ -1,189 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 19 Apr 2020 00:25:09 -0500 -Subject: [PATCH] Anvil API - - -diff --git a/src/main/java/org/bukkit/inventory/AnvilInventory.java b/src/main/java/org/bukkit/inventory/AnvilInventory.java -index f1f97a85ec713c05c882d7588f4a3e4a017f4795..813f6cd253322538bdf96eb323dd23a7809a1c1e 100644 ---- a/src/main/java/org/bukkit/inventory/AnvilInventory.java -+++ b/src/main/java/org/bukkit/inventory/AnvilInventory.java -@@ -138,4 +138,42 @@ public interface AnvilInventory extends Inventory { - setItem(2, result); - } - // Paper end -+ -+ // Purpur start -+ /** -+ * Gets if the player viewing the anvil inventory can bypass experience cost -+ * -+ * @return whether the player viewing the anvil inventory can bypass the experience cost -+ * @deprecated use {@link AnvilView#canBypassCost()}. -+ */ -+ @Deprecated(forRemoval = true, since = "1.21") -+ boolean canBypassCost(); -+ -+ /** -+ * Set if the player viewing the anvil inventory can bypass the experience cost -+ * -+ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost -+ * @deprecated use {@link AnvilView#setBypassCost(boolean)}. -+ */ -+ @Deprecated(forRemoval = true, since = "1.21") -+ void setBypassCost(boolean bypassCost); -+ -+ /** -+ * Gets if the player viewing the anvil inventory can do unsafe enchants -+ * -+ * @return whether the player viewing the anvil inventory can do unsafe enchants -+ * @deprecated use {@link AnvilView#canDoUnsafeEnchants()}. -+ */ -+ @Deprecated(forRemoval = true, since = "1.21") -+ boolean canDoUnsafeEnchants(); -+ -+ /** -+ * Set if the player viewing the anvil inventory can do unsafe enchants -+ * -+ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants -+ * @deprecated use {@link AnvilView#setDoUnsafeEnchants(boolean)}. -+ */ -+ @Deprecated(forRemoval = true, since = "1.21") -+ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); -+ // Purpur end - } -diff --git a/src/main/java/org/bukkit/inventory/view/AnvilView.java b/src/main/java/org/bukkit/inventory/view/AnvilView.java -index 3c1aa1e036bee08304c1cdca59f6a5bc0ba306c0..709fb2d1c7e3253034a651a9f68c003601b598a4 100644 ---- a/src/main/java/org/bukkit/inventory/view/AnvilView.java -+++ b/src/main/java/org/bukkit/inventory/view/AnvilView.java -@@ -89,4 +89,34 @@ public interface AnvilView extends InventoryView { - */ - void bypassEnchantmentLevelRestriction(boolean bypassEnchantmentLevelRestriction); - // Paper end - bypass anvil level restrictions -+ -+ // Purpur start -+ /** -+ * Gets if the player viewing the anvil inventory can bypass experience cost -+ * -+ * @return whether the player viewing the anvil inventory can bypass the experience cost -+ */ -+ boolean canBypassCost(); -+ -+ /** -+ * Set if the player viewing the anvil inventory can bypass the experience cost -+ * -+ * @param bypassCost whether the player viewing the anvil inventory can bypass the experience cost -+ */ -+ void setBypassCost(boolean bypassCost); -+ -+ /** -+ * Gets if the player viewing the anvil inventory can do unsafe enchants -+ * -+ * @return whether the player viewing the anvil inventory can do unsafe enchants -+ */ -+ boolean canDoUnsafeEnchants(); -+ -+ /** -+ * Set if the player viewing the anvil inventory can do unsafe enchants -+ * -+ * @param canDoUnsafeEnchants whether the player viewing the anvil inventory can do unsafe enchants -+ */ -+ void setDoUnsafeEnchants(boolean canDoUnsafeEnchants); -+ // Purpur end - } -diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..b2199854b5c7e74a673cbadbe584e5aaebbe3883 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilTakeResultEvent.java -@@ -0,0 +1,50 @@ -+package org.purpurmc.purpur.event.inventory; -+ -+import org.bukkit.entity.HumanEntity; -+import org.bukkit.entity.Player; -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.AnvilInventory; -+import org.bukkit.inventory.InventoryView; -+import org.bukkit.inventory.ItemStack; -+import org.jetbrains.annotations.ApiStatus; -+import org.jspecify.annotations.NullMarked; -+ -+/** -+ * Called when a player takes the result item out of an anvil -+ */ -+@NullMarked -+public class AnvilTakeResultEvent extends InventoryEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ private final Player player; -+ private final ItemStack result; -+ -+ @ApiStatus.Internal -+ public AnvilTakeResultEvent(HumanEntity player, InventoryView view, ItemStack result) { -+ super(view); -+ this.player = (Player) player; -+ this.result = result; -+ } -+ -+ public Player getPlayer() { -+ return player; -+ } -+ -+ public ItemStack getResult() { -+ return result; -+ } -+ -+ @Override -+ public AnvilInventory getInventory() { -+ return (AnvilInventory) super.getInventory(); -+ } -+ -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} -diff --git a/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java -new file mode 100644 -index 0000000000000000000000000000000000000000..4293c4a57c1c054e8248b7712e8664bd4cb1a972 ---- /dev/null -+++ b/src/main/java/org/purpurmc/purpur/event/inventory/AnvilUpdateResultEvent.java -@@ -0,0 +1,35 @@ -+package org.purpurmc.purpur.event.inventory; -+ -+import org.bukkit.event.HandlerList; -+import org.bukkit.event.inventory.InventoryEvent; -+import org.bukkit.inventory.AnvilInventory; -+import org.bukkit.inventory.InventoryView; -+import org.jetbrains.annotations.ApiStatus; -+import org.jspecify.annotations.NullMarked; -+ -+/** -+ * Called when anvil slots change, triggering the result slot to be updated -+ */ -+@NullMarked -+public class AnvilUpdateResultEvent extends InventoryEvent { -+ private static final HandlerList handlers = new HandlerList(); -+ -+ @ApiStatus.Internal -+ public AnvilUpdateResultEvent(InventoryView view) { -+ super(view); -+ } -+ -+ @Override -+ public AnvilInventory getInventory() { -+ return (AnvilInventory) super.getInventory(); -+ } -+ -+ @Override -+ public HandlerList getHandlers() { -+ return handlers; -+ } -+ -+ public static HandlerList getHandlerList() { -+ return handlers; -+ } -+} diff --git a/patches/server/0016-Anvil-API.patch b/patches/server/0016-Anvil-API.patch deleted file mode 100644 index 114f1f954..000000000 --- a/patches/server/0016-Anvil-API.patch +++ /dev/null @@ -1,225 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: William Blake Galbreath -Date: Sun, 19 Apr 2020 00:17:56 -0500 -Subject: [PATCH] Anvil API - - -diff --git a/net/minecraft/world/inventory/AbstractContainerMenu.java b/net/minecraft/world/inventory/AbstractContainerMenu.java -index 4680f77a275d8d2b226018db89a571ac25998dd8..bfc90524bd739ed1d91fe9912e38093b3c28928f 100644 ---- a/net/minecraft/world/inventory/AbstractContainerMenu.java -+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java -@@ -80,6 +80,7 @@ public abstract class AbstractContainerMenu { - @Nullable - private ContainerSynchronizer synchronizer; - private boolean suppressRemoteUpdates; -+ @Nullable protected ItemStack activeQuickItem = null; // Purpur - Anvil API - - // CraftBukkit start - public boolean checkReachable = true; -diff --git a/net/minecraft/world/inventory/AnvilMenu.java b/net/minecraft/world/inventory/AnvilMenu.java -index 286ae002e1711ad9e800b7f2091988d66cd572a7..f8c0a4fd95f341cbf8f6a06dfae408d505b0f018 100644 ---- a/net/minecraft/world/inventory/AnvilMenu.java -+++ b/net/minecraft/world/inventory/AnvilMenu.java -@@ -25,6 +25,12 @@ import org.slf4j.Logger; - import org.bukkit.craftbukkit.inventory.view.CraftAnvilView; - // CraftBukkit end - -+// Purpur start - Anvil API -+import net.minecraft.network.protocol.game.ClientboundContainerSetDataPacket; -+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; -+import net.minecraft.server.level.ServerPlayer; -+// Purpur end - Anvil API -+ - public class AnvilMenu extends ItemCombinerMenu { - - public static final int INPUT_SLOT = 0; -@@ -55,6 +61,10 @@ public class AnvilMenu extends ItemCombinerMenu { - private CraftAnvilView bukkitEntity; - // CraftBukkit end - public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions -+ // Purpur start - Anvil API -+ public boolean bypassCost = false; -+ public boolean canDoUnsafeEnchants = false; -+ // Purpur end - Anvil API - - public AnvilMenu(int syncId, Inventory inventory) { - this(syncId, inventory, ContainerLevelAccess.NULL); -@@ -82,12 +92,17 @@ public class AnvilMenu extends ItemCombinerMenu { - - @Override - protected boolean mayPickup(Player player, boolean present) { -- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && present; // CraftBukkit - allow cost 0 like a free item -+ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (this.bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && present; // CraftBukkit - allow cost 0 like a free item // Purpur - Anvil API - } - - @Override - protected void onTake(Player player, ItemStack stack) { -+ // Purpur start - Anvil API -+ ItemStack itemstack = this.activeQuickItem != null ? this.activeQuickItem : stack; -+ if (org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent(); -+ // Purpur end - Anvil API - if (!player.getAbilities().instabuild) { -+ if (this.bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur - Anvil API - player.giveExperienceLevels(-this.cost.get()); - } - -@@ -138,6 +153,12 @@ public class AnvilMenu extends ItemCombinerMenu { - - @Override - public void createResult() { -+ // Purpur start - Anvil API -+ this.bypassCost = false; -+ this.canDoUnsafeEnchants = false; -+ if (org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent(); -+ // Purpur end - Anvil API -+ - ItemStack itemstack = this.inputSlots.getItem(0); - - this.onlyRenaming = false; -@@ -146,7 +167,7 @@ public class AnvilMenu extends ItemCombinerMenu { - long j = 0L; - byte b0 = 0; - -- if (!itemstack.isEmpty() && EnchantmentHelper.canStoreEnchantments(itemstack)) { -+ if (!itemstack.isEmpty() && this.canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(itemstack)) { // Purpur - Anvil API - ItemStack itemstack1 = itemstack.copy(); - ItemStack itemstack2 = this.inputSlots.getItem(1); - ItemEnchantments.Mutable itemenchantments_a = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemstack1)); -@@ -225,7 +246,7 @@ public class AnvilMenu extends ItemCombinerMenu { - Holder holder1 = (Holder) iterator1.next(); - - if (!holder1.equals(holder) && !Enchantment.areCompatible(holder, holder1)) { -- flag3 = false; -+ flag3 = this.canDoUnsafeEnchants; // Purpur - Anvil API - ++i; - } - } -@@ -287,6 +308,12 @@ public class AnvilMenu extends ItemCombinerMenu { - this.onlyRenaming = true; - } - -+ // Purpur start - Anvil API -+ if (this.bypassCost && this.cost.get() >= this.maximumRepairCost) { -+ this.cost.set(this.maximumRepairCost - 1); -+ } -+ // Purpur end - Anvil API -+ - if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit - itemstack1 = ItemStack.EMPTY; - } -@@ -307,6 +334,13 @@ public class AnvilMenu extends ItemCombinerMenu { - - org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit - this.broadcastChanges(); -+ -+ // Purpur start - Anvil API -+ if (this.canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { -+ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 2, itemstack1)); -+ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetDataPacket(this.containerId, 0, this.cost.get())); -+ } -+ // Purpur end - Anvil API - } else { - org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit - this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item -diff --git a/net/minecraft/world/inventory/ItemCombinerMenu.java b/net/minecraft/world/inventory/ItemCombinerMenu.java -index a5d53a656513ae81cc3f9fc506caf6adaba62a8e..ac9df238ef0f3d009f25976b95e0b750e963e952 100644 ---- a/net/minecraft/world/inventory/ItemCombinerMenu.java -+++ b/net/minecraft/world/inventory/ItemCombinerMenu.java -@@ -164,7 +164,9 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu { - return ItemStack.EMPTY; - } - -+ this.activeQuickItem = itemstack; // Purpur - Anvil API - slot1.onTake(player, itemstack1); -+ this.activeQuickItem = null; // Purpur - Anvil API - } - - return itemstack; -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -index 792cb6adf0c7a6335cc5985fce8bed2e0f1149af..5734c5caffda79383ae30df20c3defb51b87f39e 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java -@@ -19,6 +19,10 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn - private int repairCost; - private int repairCostAmount; - private int maximumRepairCost; -+ // Purpur start - Anvil API -+ private boolean bypassCost; -+ private boolean canDoUnsafeEnchants; -+ // Purpur end - Anvil API - - public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory) { - super(inventory, resultInventory); -@@ -27,6 +31,10 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn - this.repairCost = CraftInventoryAnvil.DEFAULT_REPAIR_COST; - this.repairCostAmount = CraftInventoryAnvil.DEFAULT_REPAIR_COST_AMOUNT; - this.maximumRepairCost = CraftInventoryAnvil.DEFAULT_MAXIMUM_REPAIR_COST; -+ // Purpur start - Anvil API -+ this.bypassCost = false; -+ this.canDoUnsafeEnchants = false; -+ // Purpur end - Anvil API - } - - @Override -@@ -113,4 +121,30 @@ public class CraftInventoryAnvil extends CraftResultInventory implements AnvilIn - consumer.accept(cav); - } - } -+ -+ // Purpur start - Anvil API -+ @Override -+ public boolean canBypassCost() { -+ this.syncWithArbitraryViewValue((cav) -> this.bypassCost = cav.canBypassCost()); -+ return this.bypassCost; -+ } -+ -+ @Override -+ public void setBypassCost(boolean bypassCost) { -+ this.bypassCost = bypassCost; -+ this.syncViews((cav) -> cav.setBypassCost(bypassCost)); -+ } -+ -+ @Override -+ public boolean canDoUnsafeEnchants() { -+ this.syncWithArbitraryViewValue((cav) -> this.canDoUnsafeEnchants = cav.canDoUnsafeEnchants()); -+ return this.canDoUnsafeEnchants; -+ } -+ -+ @Override -+ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { -+ this.canDoUnsafeEnchants = canDoUnsafeEnchants; -+ this.syncViews((cav) -> cav.setDoUnsafeEnchants(canDoUnsafeEnchants)); -+ } -+ // Purpur end - Anvil API - } -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java -index f86c95a13dff012de5db3e41ac261e9e8d44d9f3..1db0b790d824e419bb5fb6ab1f3003e120f9763b 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java -@@ -75,4 +75,26 @@ public class CraftAnvilView extends CraftInventoryView= this.cost.get()) && this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && hasStack; // CraftBukkit - allow cost 0 like a free item ++ return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && (this.bypassCost || this.cost.get() > AnvilMenu.DEFAULT_DENIED_COST) && hasStack; // CraftBukkit - allow cost 0 like a free item // Purpur - Anvil API + } + + @Override + protected void onTake(Player player, ItemStack stack) { ++ // Purpur start - Anvil API ++ ItemStack itemstack = this.activeQuickItem != null ? this.activeQuickItem : stack; ++ if (org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilTakeResultEvent(player.getBukkitEntity(), getBukkitView(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)).callEvent(); ++ // Purpur end - Anvil API + if (!player.getAbilities().instabuild) { ++ if (this.bypassCost) ((ServerPlayer) player).lastSentExp = -1; else // Purpur - Anvil API + player.giveExperienceLevels(-this.cost.get()); + } + +@@ -126,13 +_,19 @@ + + @Override + public void createResult() { ++ // Purpur start - Anvil API ++ this.bypassCost = false; ++ this.canDoUnsafeEnchants = false; ++ if (org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent.getHandlerList().getRegisteredListeners().length > 0) new org.purpurmc.purpur.event.inventory.AnvilUpdateResultEvent(getBukkitView()).callEvent(); ++ // Purpur end - Anvil API ++ + ItemStack item = this.inputSlots.getItem(0); + this.onlyRenaming = false; + this.cost.set(1); + int i = 0; + long l = 0L; + int i1 = 0; +- if (!item.isEmpty() && EnchantmentHelper.canStoreEnchantments(item)) { ++ if (!item.isEmpty() && this.canDoUnsafeEnchants || EnchantmentHelper.canStoreEnchantments(item)) { // Purpur - Anvil API + ItemStack itemStack = item.copy(); + ItemStack item1 = this.inputSlots.getItem(1); + ItemEnchantments.Mutable mutable = new ItemEnchantments.Mutable(EnchantmentHelper.getEnchantmentsForCrafting(itemStack)); +@@ -198,7 +_,7 @@ + + for (Holder holder1 : mutable.keySet()) { + if (!holder1.equals(holder) && !Enchantment.areCompatible(holder, holder1)) { +- canEnchant = false; ++ canEnchant = this.canDoUnsafeEnchants; // Purpur - Anvil API + i++; + } + } +@@ -260,6 +_,12 @@ + this.onlyRenaming = true; + } + ++ // Purpur start - Anvil API ++ if (this.bypassCost && this.cost.get() >= this.maximumRepairCost) { ++ this.cost.set(this.maximumRepairCost - 1); ++ } ++ // Purpur end - Anvil API ++ + if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit + itemStack = ItemStack.EMPTY; + } +@@ -280,6 +_,13 @@ + + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemStack); // CraftBukkit + this.broadcastChanges(); ++ ++ // Purpur start - Anvil API ++ if (this.canDoUnsafeEnchants && itemstack1 != ItemStack.EMPTY) { ++ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 2, itemstack1)); ++ ((ServerPlayer) this.player).connection.send(new ClientboundContainerSetDataPacket(this.containerId, 0, this.cost.get())); ++ } ++ // Purpur end - Anvil API + } else { + org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit + this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item diff --git a/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch new file mode 100644 index 000000000..9899e30a5 --- /dev/null +++ b/purpur-server/minecraft-patches/sources/net/minecraft/world/inventory/ItemCombinerMenu.java.patch @@ -0,0 +1,12 @@ +--- a/net/minecraft/world/inventory/ItemCombinerMenu.java ++++ b/net/minecraft/world/inventory/ItemCombinerMenu.java +@@ -156,7 +_,9 @@ + return ItemStack.EMPTY; + } + ++ this.activeQuickItem = itemStack; // Purpur - Anvil API + slot.onTake(player, item); ++ this.activeQuickItem = null; // Purpur - Anvil API + } + + return itemStack; diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch new file mode 100644 index 000000000..58b895e59 --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java.patch @@ -0,0 +1,55 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryAnvil.java +@@ -19,6 +_,10 @@ + private int repairCost; + private int repairCostAmount; + private int maximumRepairCost; ++ // Purpur start - Anvil API ++ private boolean bypassCost; ++ private boolean canDoUnsafeEnchants; ++ // Purpur end - Anvil API + + public CraftInventoryAnvil(Location location, Container inventory, Container resultInventory) { + super(inventory, resultInventory); +@@ -27,6 +_,10 @@ + this.repairCost = CraftInventoryAnvil.DEFAULT_REPAIR_COST; + this.repairCostAmount = CraftInventoryAnvil.DEFAULT_REPAIR_COST_AMOUNT; + this.maximumRepairCost = CraftInventoryAnvil.DEFAULT_MAXIMUM_REPAIR_COST; ++ // Purpur start - Anvil API ++ this.bypassCost = false; ++ this.canDoUnsafeEnchants = false; ++ // Purpur end - Anvil API + } + + @Override +@@ -113,4 +_,30 @@ + consumer.accept(cav); + } + } ++ ++ // Purpur start - Anvil API ++ @Override ++ public boolean canBypassCost() { ++ this.syncWithArbitraryViewValue((cav) -> this.bypassCost = cav.canBypassCost()); ++ return this.bypassCost; ++ } ++ ++ @Override ++ public void setBypassCost(boolean bypassCost) { ++ this.bypassCost = bypassCost; ++ this.syncViews((cav) -> cav.setBypassCost(bypassCost)); ++ } ++ ++ @Override ++ public boolean canDoUnsafeEnchants() { ++ this.syncWithArbitraryViewValue((cav) -> this.canDoUnsafeEnchants = cav.canDoUnsafeEnchants()); ++ return this.canDoUnsafeEnchants; ++ } ++ ++ @Override ++ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { ++ this.canDoUnsafeEnchants = canDoUnsafeEnchants; ++ this.syncViews((cav) -> cav.setDoUnsafeEnchants(canDoUnsafeEnchants)); ++ } ++ // Purpur end - Anvil API + } diff --git a/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch new file mode 100644 index 000000000..f2659f49e --- /dev/null +++ b/purpur-server/paper-patches/files/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java.patch @@ -0,0 +1,29 @@ +--- a/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/view/CraftAnvilView.java +@@ -75,4 +_,26 @@ + this.setMaximumRepairCost(legacy.getMaximumRepairCost()); + } + } ++ ++ // Purpur start - Anvil API ++ @Override ++ public boolean canBypassCost() { ++ return this.container.bypassCost; ++ } ++ ++ @Override ++ public void setBypassCost(boolean bypassCost) { ++ this.container.bypassCost = bypassCost; ++ } ++ ++ @Override ++ public boolean canDoUnsafeEnchants() { ++ return this.container.canDoUnsafeEnchants; ++ } ++ ++ @Override ++ public void setDoUnsafeEnchants(boolean canDoUnsafeEnchants) { ++ this.container.canDoUnsafeEnchants = canDoUnsafeEnchants; ++ } ++ // Purpur end - Anvil API + }