net/minecraft/world/inventory

This commit is contained in:
Owen1212055 2024-12-14 11:56:00 -05:00
parent 3672a7d70f
commit 64e61681f4
63 changed files with 2256 additions and 2791 deletions

View file

@ -0,0 +1,281 @@
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -19,6 +_,8 @@
import net.minecraft.ReportedException;
import net.minecraft.core.NonNullList;
import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
@@ -63,6 +_,31 @@
@Nullable
private ContainerSynchronizer synchronizer;
private boolean suppressRemoteUpdates;
+ // CraftBukkit start
+ public boolean checkReachable = true;
+ public abstract org.bukkit.inventory.InventoryView getBukkitView();
+ public void transferTo(AbstractContainerMenu other, org.bukkit.craftbukkit.entity.CraftHumanEntity player) {
+ org.bukkit.inventory.InventoryView source = this.getBukkitView(), destination = other.getBukkitView();
+ ((org.bukkit.craftbukkit.inventory.CraftInventory) source.getTopInventory()).getInventory().onClose(player);
+ ((org.bukkit.craftbukkit.inventory.CraftInventory) source.getBottomInventory()).getInventory().onClose(player);
+ ((org.bukkit.craftbukkit.inventory.CraftInventory) destination.getTopInventory()).getInventory().onOpen(player);
+ ((org.bukkit.craftbukkit.inventory.CraftInventory) destination.getBottomInventory()).getInventory().onOpen(player);
+ }
+ private Component title;
+ public final Component getTitle() {
+ // Paper start - return chat component with empty text instead of throwing error
+ // Preconditions.checkState(this.title != null, "Title not set");
+ if (this.title == null){
+ return Component.literal("");
+ }
+ // Paper end - return chat component with empty text instead of throwing error
+ return this.title;
+ }
+ public final void setTitle(Component title) {
+ com.google.common.base.Preconditions.checkState(this.title == null, "Title already set");
+ this.title = title;
+ }
+ // CraftBukkit end
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
this.menuType = menuType;
@@ -168,8 +_,18 @@
if (this.synchronizer != null) {
this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
- }
- }
+ this.synchronizer.sendOffHandSlotChange(); // Paper - Sync offhand slot in menus; update player's offhand since the offhand slot is not added to the slots for menus but can be changed by swapping from a menu slot
+ }
+ }
+
+ // CraftBukkit start
+ public void broadcastCarriedItem() {
+ this.remoteCarried = this.getCarried().copy();
+ if (this.synchronizer != null) {
+ this.synchronizer.sendCarriedChange(this, this.remoteCarried);
+ }
+ }
+ // CraftBukkit end
public void removeSlotListener(ContainerListener listener) {
this.containerListeners.remove(listener);
@@ -235,7 +_,7 @@
this.lastSlots.set(slotIndex, itemStack1);
for (ContainerListener containerListener : this.containerListeners) {
- containerListener.slotChanged(this, slotIndex, itemStack1);
+ containerListener.slotChanged(this, slotIndex, itemStack, itemStack1); // Paper - Add PlayerInventorySlotChangeEvent
}
}
}
@@ -343,6 +_,7 @@
this.resetQuickCraft();
}
} else if (this.quickcraftStatus == 1) {
+ if (slotId < 0) return; // Paper - Add slot sanity checks to container clicks
Slot slot = this.slots.get(slotId);
ItemStack carried = this.getCarried();
if (canItemQuickReplace(slot, carried, true)
@@ -367,6 +_,7 @@
}
int count = this.getCarried().getCount();
+ java.util.Map<Integer, ItemStack> draggedSlots = new java.util.HashMap<>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack)
for (Slot slot1 : this.quickcraftSlots) {
ItemStack carried1 = this.getCarried();
@@ -379,12 +_,48 @@
int min = Math.min(itemStack.getMaxStackSize(), slot1.getMaxStackSize(itemStack));
int min1 = Math.min(getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemStack) + i2, min);
count -= min1 - i2;
- slot1.setByPlayer(itemStack.copyWithCount(min1));
- }
- }
-
- itemStack.setCount(count);
- this.setCarried(itemStack);
+ // slot1.setByPlayer(itemStack.copyWithCount(min1));
+ draggedSlots.put(slot1.index, itemStack.copyWithCount(min1)); // CraftBukkit - Put in map instead of setting
+ }
+ }
+
+ // CraftBukkit start - InventoryDragEvent
+ org.bukkit.inventory.InventoryView view = this.getBukkitView();
+ org.bukkit.inventory.ItemStack newcursor = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+ newcursor.setAmount(count);
+ java.util.Map<Integer, org.bukkit.inventory.ItemStack> eventmap = new java.util.HashMap<Integer, org.bukkit.inventory.ItemStack>();
+ for (java.util.Map.Entry<Integer, ItemStack> ditem : draggedSlots.entrySet()) {
+ eventmap.put(ditem.getKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(ditem.getValue()));
+ }
+
+ // It's essential that we set the cursor to the new value here to prevent item duplication if a plugin closes the inventory.
+ ItemStack oldCursor = this.getCarried();
+ this.setCarried(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(newcursor));
+
+ org.bukkit.event.inventory.InventoryDragEvent event = new org.bukkit.event.inventory.InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(oldCursor), this.quickcraftType == 1, eventmap);
+ player.level().getCraftServer().getPluginManager().callEvent(event);
+
+ // Whether or not a change was made to the inventory that requires an update.
+ boolean needsUpdate = event.getResult() != org.bukkit.event.Event.Result.DEFAULT;
+
+ if (event.getResult() != org.bukkit.event.Event.Result.DENY) {
+ for (java.util.Map.Entry<Integer, ItemStack> dslot : draggedSlots.entrySet()) {
+ view.setItem(dslot.getKey(), org.bukkit.craftbukkit.inventory.CraftItemStack.asBukkitCopy(dslot.getValue()));
+ }
+ // The only time the carried item will be set to null is if the inventory is closed by the server.
+ // If the inventory is closed by the server, then the cursor items are dropped. This is why we change the cursor early.
+ if (this.getCarried() != null) {
+ this.setCarried(org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getCursor()));
+ needsUpdate = true;
+ }
+ } else {
+ this.setCarried(oldCursor);
+ }
+
+ if (needsUpdate && player instanceof ServerPlayer) {
+ this.sendAllDataToRemote();
+ }
+ // CraftBukkit end
}
this.resetQuickCraft();
@@ -398,8 +_,11 @@
if (slotId == -999) {
if (!this.getCarried().isEmpty()) {
if (clickAction == ClickAction.PRIMARY) {
- player.drop(this.getCarried(), true);
- this.setCarried(ItemStack.EMPTY);
+ // CraftBukkit start
+ ItemStack carried = this.getCarried();
+ this.setCarried(ItemStack.EMPTY);
+ player.drop(carried, true);
+ // CraftBukkit start
} else {
player.drop(this.getCarried().split(1), true);
}
@@ -461,8 +_,18 @@
}
slot.setChanged();
+ // CraftBukkit start - Make sure the client has the right slot contents
+ if (player instanceof ServerPlayer && slot.getMaxStackSize() != 64) {
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem()));
+ // Updating a crafting inventory makes the client reset the result slot, have to send it again
+ if (this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.WORKBENCH || this.getBukkitView().getType() == org.bukkit.event.inventory.InventoryType.CRAFTING) {
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 0, this.getSlot(0).getItem()));
+ }
+ }
+ // CraftBukkit end
}
} else if (clickType == ClickType.SWAP && (button >= 0 && button < 9 || button == 40)) {
+ if (slotId < 0) return; // Paper - Add slot sanity checks to container clicks
ItemStack item = inventory.getItem(button);
Slot slot = this.slots.get(slotId);
ItemStack carried = slot.getItem();
@@ -582,8 +_,9 @@
if (player instanceof ServerPlayer) {
ItemStack carried = this.getCarried();
if (!carried.isEmpty()) {
+ this.setCarried(ItemStack.EMPTY); // CraftBukkit - SPIGOT-4556 - from below
dropOrPlaceInInventory(player, carried);
- this.setCarried(ItemStack.EMPTY);
+ // this.setCarried(ItemStack.EMPTY); // CraftBukkit - moved up
}
}
}
@@ -629,6 +_,14 @@
public abstract boolean stillValid(Player player);
protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection) {
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ return this.moveItemStackTo(stack, startIndex, endIndex, reverseDirection, false);
+ }
+ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean reverseDirection, boolean isCheck) {
+ if (isCheck) {
+ stack = stack.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
boolean flag = false;
int i = startIndex;
if (reverseDirection) {
@@ -639,18 +_,27 @@
while (!stack.isEmpty() && (reverseDirection ? i >= startIndex : i < endIndex)) {
Slot slot = this.slots.get(i);
ItemStack item = slot.getItem();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check
+ if (isCheck) {
+ item = item.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
if (!item.isEmpty() && ItemStack.isSameItemSameComponents(stack, item)) {
int i1 = item.getCount() + stack.getCount();
int maxStackSize = slot.getMaxStackSize(item);
if (i1 <= maxStackSize) {
stack.setCount(0);
item.setCount(i1);
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag = true;
} else if (item.getCount() < maxStackSize) {
stack.shrink(maxStackSize - item.getCount());
item.setCount(maxStackSize);
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag = true;
}
}
@@ -673,10 +_,21 @@
while (reverseDirection ? i >= startIndex : i < endIndex) {
Slot slotx = this.slots.get(i);
ItemStack itemx = slotx.getItem();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (isCheck) {
+ itemx = itemx.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
if (itemx.isEmpty() && slotx.mayPlace(stack)) {
int i1 = slotx.getMaxStackSize(stack);
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (isCheck) {
+ stack.shrink(Math.min(stack.getCount(), i1));
+ } else {
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
slotx.setByPlayer(stack.split(Math.min(stack.getCount(), i1)));
slotx.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag = true;
break;
}
@@ -760,6 +_,11 @@
}
public ItemStack getCarried() {
+ // CraftBukkit start
+ if (this.carried.isEmpty()) {
+ this.setCarried(ItemStack.EMPTY);
+ }
+ // CraftBukkit end
return this.carried;
}
@@ -808,4 +_,15 @@
this.stateId = this.stateId + 1 & 32767;
return this.stateId;
}
+
+ // Paper start - Add missing InventoryHolders
+ // The reason this is a supplier, is that the createHolder method uses the bukkit InventoryView#getTopInventory to get the inventory in question
+ // and that can't be obtained safely until the AbstractContainerMenu has been fully constructed. Using a supplier lazily
+ // initializes the InventoryHolder safely.
+ protected final Supplier<org.bukkit.inventory.BlockInventoryHolder> createBlockHolder(final ContainerLevelAccess context) {
+ //noinspection ConstantValue
+ com.google.common.base.Preconditions.checkArgument(context != null, "context was null");
+ return () -> context.createBlockHolder(this);
+ }
+ // Paper end - Add missing InventoryHolders
}

View file

@ -0,0 +1,39 @@
--- a/net/minecraft/world/inventory/AbstractCraftingMenu.java
+++ b/net/minecraft/world/inventory/AbstractCraftingMenu.java
@@ -12,14 +_,17 @@
public abstract class AbstractCraftingMenu extends RecipeBookMenu {
private final int width;
private final int height;
- public final CraftingContainer craftSlots;
+ public final TransientCraftingContainer craftSlots; // CraftBukkit
public final ResultContainer resultSlots = new ResultContainer();
- public AbstractCraftingMenu(MenuType<?> menuType, int containerId, int width, int height) {
+ public AbstractCraftingMenu(MenuType<?> menuType, int containerId, int width, int height, Inventory playerInventory) { // CraftBukkit
super(menuType, containerId);
this.width = width;
this.height = height;
- this.craftSlots = new TransientCraftingContainer(this, width, height);
+ // CraftBukkit start
+ this.craftSlots = new TransientCraftingContainer(this, width, height, playerInventory.player); // CraftBukkit - pass player
+ this.craftSlots.resultInventory = this.resultSlots; // CraftBukkit - let InventoryCrafting know about its result slot
+ // CraftBukkit end
}
protected Slot addResultSlot(Player player, int x, int y) {
@@ -35,13 +_,13 @@
}
@Override
- public RecipeBookMenu.PostPlaceAction handlePlacement(
+ public PostPlaceAction handlePlacement(
boolean useMaxItems, boolean isCreative, RecipeHolder<?> recipe, ServerLevel level, Inventory playerInventory
) {
RecipeHolder<CraftingRecipe> recipeHolder = (RecipeHolder<CraftingRecipe>)recipe;
this.beginPlacingRecipe();
- RecipeBookMenu.PostPlaceAction var8;
+ PostPlaceAction var8;
try {
List<Slot> inputGridSlots = this.getInputGridSlots();
var8 = ServerPlaceRecipe.placeRecipe(new ServerPlaceRecipe.CraftingMenuAccess<CraftingRecipe>() {

View file

@ -0,0 +1,49 @@
--- a/net/minecraft/world/inventory/AbstractFurnaceMenu.java
+++ b/net/minecraft/world/inventory/AbstractFurnaceMenu.java
@@ -34,6 +_,21 @@
private final RecipeType<? extends AbstractCookingRecipe> recipeType;
private final RecipePropertySet acceptedInputs;
private final RecipeBookType recipeBookType;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftFurnaceView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftFurnaceView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryFurnace inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryFurnace((net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity) this.container);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftFurnaceView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
protected AbstractFurnaceMenu(
MenuType<?> menuType,
@@ -68,6 +_,7 @@
this.addSlot(new Slot(container, 0, 56, 17));
this.addSlot(new FurnaceFuelSlot(this, container, 1, 56, 53));
this.addSlot(new FurnaceResultSlot(inventory.player, container, 2, 116, 35));
+ this.player = inventory; // CraftBukkit - save player
this.addStandardInventorySlots(inventory, 8, 84);
this.addDataSlots(data);
}
@@ -85,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}
@@ -170,7 +_,7 @@
}
@Override
- public RecipeBookMenu.PostPlaceAction handlePlacement(
+ public PostPlaceAction handlePlacement(
boolean useMaxItems, boolean isCreative, RecipeHolder<?> recipe, final ServerLevel level, Inventory playerInventory
) {
final List<Slot> list = List.of(this.getSlot(0), this.getSlot(2));

View file

@ -1,68 +1,55 @@
--- a/net/minecraft/world/inventory/AnvilMenu.java
+++ b/net/minecraft/world/inventory/AnvilMenu.java
@@ -21,6 +21,10 @@
import net.minecraft.world.level.block.state.BlockState;
import org.slf4j.Logger;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.view.CraftAnvilView;
+// CraftBukkit end
+
public class AnvilMenu extends ItemCombinerMenu {
public static final int INPUT_SLOT = 0;
@@ -45,6 +49,12 @@
@@ -43,6 +_,12 @@
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 CraftAnvilView bukkitEntity;
+ private org.bukkit.craftbukkit.inventory.view.CraftAnvilView bukkitEntity;
+ // CraftBukkit end
+ public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions
public AnvilMenu(int syncId, Inventory inventory) {
this(syncId, inventory, ContainerLevelAccess.NULL);
@@ -72,7 +82,7 @@
public AnvilMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -68,7 +_,7 @@
@Override
protected boolean mayPickup(Player player, boolean present) {
protected boolean mayPickup(Player player, boolean hasStack) {
- return (player.hasInfiniteMaterials() || player.experienceLevel >= this.cost.get()) && this.cost.get() > 0;
+ 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.cost.get() > AnvilMenu.DEFAULT_DENIED_COST && hasStack; // CraftBukkit - allow cost 0 like a free item
}
@Override
@@ -94,7 +104,7 @@
@@ -89,12 +_,22 @@
this.inputSlots.setItem(1, ItemStack.EMPTY);
}
- this.cost.set(0);
+ this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
this.inputSlots.setItem(0, ItemStack.EMPTY);
this.access.execute((world, blockposition) -> {
BlockState iblockdata = world.getBlockState(blockposition);
@@ -102,6 +112,16 @@
if (!player.hasInfiniteMaterials() && iblockdata.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
BlockState iblockdata1 = AnvilBlock.damage(iblockdata);
this.access.execute((level, blockPos) -> {
BlockState blockState = level.getBlockState(blockPos);
if (!player.hasInfiniteMaterials() && blockState.is(BlockTags.ANVIL) && player.getRandom().nextFloat() < 0.12F) {
BlockState blockState1 = AnvilBlock.damage(blockState);
+ // Paper start - AnvilDamageEvent
+ com.destroystokyo.paper.event.block.AnvilDamagedEvent event = new com.destroystokyo.paper.event.block.AnvilDamagedEvent(getBukkitView(), iblockdata1 != null ? org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(iblockdata1) : null);
+ com.destroystokyo.paper.event.block.AnvilDamagedEvent event = new com.destroystokyo.paper.event.block.AnvilDamagedEvent(getBukkitView(), blockState1 != null ? org.bukkit.craftbukkit.block.data.CraftBlockData.fromData(blockState1) : null);
+ if (!event.callEvent()) {
+ return;
+ } else if (event.getDamageState() == com.destroystokyo.paper.event.block.AnvilDamagedEvent.DamageState.BROKEN) {
+ iblockdata1 = null;
+ blockState1 = null;
+ } else {
+ iblockdata1 = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, iblockdata.getValue(AnvilBlock.FACING));
+ blockState1 = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, blockState.getValue(AnvilBlock.FACING));
+ }
+ // Paper end - AnvilDamageEvent
if (iblockdata1 == null) {
world.removeBlock(blockposition, false);
world.levelEvent(1029, blockposition, 0);
@@ -143,8 +163,8 @@
if (itemstack1.isDamageableItem() && itemstack.isValidRepairItem(itemstack2)) {
k = Math.min(itemstack1.getDamageValue(), itemstack1.getMaxDamage() / 4);
if (k <= 0) {
if (blockState1 == null) {
level.removeBlock(blockPos, false);
level.levelEvent(1029, blockPos, 0);
@@ -128,8 +_,8 @@
if (itemStack.isDamageableItem() && item.isValidRepairItem(item1)) {
int min = Math.min(itemStack.getDamageValue(), itemStack.getMaxDamage() / 4);
if (min <= 0) {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
- this.cost.set(0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
@ -70,10 +57,10 @@
return;
}
@@ -158,8 +178,8 @@
this.repairItemCountCost = i1;
@@ -144,8 +_,8 @@
this.repairItemCountCost = i2;
} else {
if (!flag && (!itemstack1.is(itemstack2.getItem()) || !itemstack1.isDamageableItem())) {
if (!hasStoredEnchantments && (!itemStack.is(item1.getItem()) || !itemStack.isDamageableItem())) {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
- this.cost.set(0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
@ -81,19 +68,19 @@
return;
}
@@ -214,7 +234,7 @@
flag2 = true;
} else {
@@ -191,7 +_,7 @@
flag1 = true;
- if (i2 > enchantment.getMaxLevel()) {
+ if (i2 > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions
i2 = enchantment.getMaxLevel();
} else {
flag = true;
- if (intValue > enchantment.getMaxLevel()) {
+ if (intValue > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions
intValue = enchantment.getMaxLevel();
}
@@ -233,8 +253,8 @@
@@ -209,8 +_,8 @@
}
if (flag2 && !flag1) {
if (flag1 && !flag) {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
- this.cost.set(0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
@ -101,14 +88,16 @@
return;
}
}
@@ -260,14 +280,14 @@
@@ -235,14 +_,16 @@
}
if (b0 == i && b0 > 0) {
if (i1 == i && i1 > 0) {
- if (this.cost.get() >= 40) {
- this.cost.set(39);
+ if (this.cost.get() >= this.maximumRepairCost) { // CraftBukkit
+ this.cost.set(this.maximumRepairCost - 1); // CraftBukkit
+ // CraftBukkit start
+ if (this.cost.get() >= this.maximumRepairCost) {
+ this.cost.set(this.maximumRepairCost - 1);
+ // CraftBukkit end
}
this.onlyRenaming = true;
@ -116,15 +105,15 @@
- if (this.cost.get() >= 40 && !this.player.getAbilities().instabuild) {
+ if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit
itemstack1 = ItemStack.EMPTY;
itemStack = ItemStack.EMPTY;
}
@@ -285,12 +305,13 @@
EnchantmentHelper.setEnchantments(itemstack1, itemenchantments_a.toImmutable());
@@ -260,12 +_,13 @@
EnchantmentHelper.setEnchantments(itemStack, mutable.toImmutable());
}
- this.resultSlots.setItem(0, itemstack1);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemstack1); // CraftBukkit
- this.resultSlots.setItem(0, itemStack);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemStack); // CraftBukkit
this.broadcastChanges();
} else {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
@ -135,8 +124,8 @@
+ this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686, SPIGOT-7931: Always send completed inventory to stay in sync with client
}
public static int calculateIncreasedRepairCost(int cost) {
@@ -313,6 +334,7 @@
public static int calculateIncreasedRepairCost(int oldRepairCost) {
@@ -286,6 +_,7 @@
}
this.createResult();
@ -144,21 +133,21 @@
return true;
} else {
return false;
@@ -329,4 +351,19 @@
@@ -301,4 +_,19 @@
public int getCost() {
return this.cost.get();
}
+
+ // CraftBukkit start
+ @Override
+ public CraftAnvilView getBukkitView() {
+ public org.bukkit.craftbukkit.inventory.view.CraftAnvilView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryAnvil inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryAnvil(
+ this.access.getLocation(), this.inputSlots, this.resultSlots);
+ this.bukkitEntity = new CraftAnvilView(this.player.getBukkitEntity(), inventory, this);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftAnvilView(this.player.getBukkitEntity(), inventory, this);
+ this.bukkitEntity.updateFromLegacy(inventory);
+ return this.bukkitEntity;
+ }

View file

@ -0,0 +1,121 @@
--- a/net/minecraft/world/inventory/BeaconMenu.java
+++ b/net/minecraft/world/inventory/BeaconMenu.java
@@ -22,20 +_,14 @@
private static final int USE_ROW_SLOT_START = 28;
private static final int USE_ROW_SLOT_END = 37;
private static final int NO_EFFECT = 0;
- private final Container beacon = new SimpleContainer(1) {
- @Override
- public boolean canPlaceItem(int slot, ItemStack stack) {
- return stack.is(ItemTags.BEACON_PAYMENT_ITEMS);
- }
-
- @Override
- public int getMaxStackSize() {
- return 1;
- }
- };
- private final BeaconMenu.PaymentSlot paymentSlot;
+ private final Container beacon; // Paper - Add missing InventoryHolders Move down
+ private final PaymentSlot paymentSlot;
private final ContainerLevelAccess access;
private final ContainerData beaconData;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftBeaconView bukkitEntity = null;
+ private net.minecraft.world.entity.player.Inventory player;
+ // CraftBukkit end
public BeaconMenu(int containerId, Container container) {
this(containerId, container, new SimpleContainerData(3), ContainerLevelAccess.NULL);
@@ -43,10 +_,31 @@
public BeaconMenu(int containerId, Container container, ContainerData beaconData, ContainerLevelAccess access) {
super(MenuType.BEACON, containerId);
+ this.player = (net.minecraft.world.entity.player.Inventory) container; // CraftBukkit - TODO: check this
+ // Paper - Add missing InventoryHolders
+ this.beacon = new SimpleContainer(this.createBlockHolder(access), 1) {
+ @Override
+ public boolean canPlaceItem(int slot, ItemStack stack) {
+ return stack.is(ItemTags.BEACON_PAYMENT_ITEMS);
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return 1;
+ }
+
+ // Paper start - Fix inventories returning null Locations
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // Paper end - Fix inventories returning null Locations
+ };
+ // Paper end
checkContainerDataCount(beaconData, 3);
this.beaconData = beaconData;
this.access = access;
- this.paymentSlot = new BeaconMenu.PaymentSlot(this.beacon, 0, 136, 110);
+ this.paymentSlot = new PaymentSlot(this.beacon, 0, 136, 110);
this.addSlot(this.paymentSlot);
this.addDataSlots(beaconData);
this.addStandardInventorySlots(container, 36, 137);
@@ -65,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.BEACON);
}
@@ -141,13 +_,30 @@
public Holder<MobEffect> getSecondaryEffect() {
return decodeEffect(this.beaconData.get(2));
}
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ private static @Nullable org.bukkit.potion.PotionEffectType convert(Optional<Holder<MobEffect>> optionalEffect) {
+ return optionalEffect.map(org.bukkit.craftbukkit.potion.CraftPotionEffectType::minecraftHolderToBukkit).orElse(null);
+ }
+ // Paper end - Add PlayerChangeBeaconEffectEvent
public void updateEffects(Optional<Holder<MobEffect>> primaryEffect, Optional<Holder<MobEffect>> secondaryEffect) {
+ // Paper start - fix MC-174630 - validate secondary power
+ if (secondaryEffect.isPresent() && secondaryEffect.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primaryEffect.isPresent() && secondaryEffect.get() != primaryEffect.get())) {
+ secondaryEffect = Optional.empty();
+ }
+ // Paper end
if (this.paymentSlot.hasItem()) {
- this.beaconData.set(1, encodeEffect(primaryEffect.orElse(null)));
- this.beaconData.set(2, encodeEffect(secondaryEffect.orElse(null)));
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.player.player.getBukkitEntity(), convert(primaryEffect), convert(secondaryEffect), this.access.getLocation().getBlock());
+ if (event.callEvent()) {
+ // Paper end - Add PlayerChangeBeaconEffectEvent
+ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error
+ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error
+ if (event.willConsumeItem()) { // Paper
this.paymentSlot.remove(1);
+ } // Paper
this.access.execute(Level::blockEntityChanged);
+ } // Paper end - Add PlayerChangeBeaconEffectEvent
}
}
@@ -170,4 +_,17 @@
return 1;
}
}
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftBeaconView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryBeacon inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryBeacon(this.beacon);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftBeaconView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,139 @@
--- a/net/minecraft/world/inventory/BrewingStandMenu.java
+++ b/net/minecraft/world/inventory/BrewingStandMenu.java
@@ -1,6 +_,5 @@
package net.minecraft.world.inventory;
-import java.util.Optional;
import net.minecraft.advancements.CriteriaTriggers;
import net.minecraft.core.Holder;
import net.minecraft.core.component.DataComponents;
@@ -16,6 +_,7 @@
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.alchemy.PotionContents;
+import java.util.Optional;
public class BrewingStandMenu extends AbstractContainerMenu {
static final ResourceLocation EMPTY_SLOT_FUEL = ResourceLocation.withDefaultNamespace("container/slot/brewing_fuel");
@@ -33,29 +_,50 @@
private final Container brewingStand;
public final ContainerData brewingStandData;
private final Slot ingredientSlot;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftBrewingStandView bukkitEntity = null;
+ private Inventory player;
+ // CraftBukkit end
public BrewingStandMenu(int containerId, Inventory playerInventory) {
- this(containerId, playerInventory, new SimpleContainer(5), new SimpleContainerData(2));
+ this(containerId, playerInventory, new SimpleContainer(5), new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add totalBrewTime
}
public BrewingStandMenu(int containerId, Inventory playerInventory, Container brewingStandContainer, ContainerData brewingStandData) {
super(MenuType.BREWING_STAND, containerId);
+ this.player = playerInventory; // CraftBukkit
checkContainerSize(brewingStandContainer, 5);
checkContainerDataCount(brewingStandData, 2);
this.brewingStand = brewingStandContainer;
this.brewingStandData = brewingStandData;
PotionBrewing potionBrewing = playerInventory.player.level().potionBrewing();
- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 0, 56, 51));
- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 1, 79, 58));
- this.addSlot(new BrewingStandMenu.PotionSlot(brewingStandContainer, 2, 102, 51));
- this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionBrewing, brewingStandContainer, 3, 79, 17));
- this.addSlot(new BrewingStandMenu.FuelSlot(brewingStandContainer, 4, 17, 17));
- this.addDataSlots(brewingStandData);
+ // Paper start - custom potion mixes
+ this.addSlot(new PotionSlot(brewingStandContainer, 0, 56, 51, potionBrewing));
+ this.addSlot(new PotionSlot(brewingStandContainer, 1, 79, 58, potionBrewing));
+ this.addSlot(new PotionSlot(brewingStandContainer, 2, 102, 51, potionBrewing));
+ // Paper end - custom potion mixes
+ this.ingredientSlot = this.addSlot(new IngredientsSlot(potionBrewing, brewingStandContainer, 3, 79, 17));
+ this.addSlot(new FuelSlot(brewingStandContainer, 4, 17, 17));
+ // Paper start - Add recipeBrewTime
+ this.addDataSlots(new SimpleContainerData(2) {
+ @Override
+ public int get(final int index) {
+ if (index == 0) return 400 * brewingStandData.get(index) / brewingStandData.get(2);
+ return brewingStandData.get(index);
+ }
+
+ @Override
+ public void set(final int index, final int value) {
+ brewingStandData.set(index, value);
+ }
+ });
+ // Paper end - Add recipeBrewTime
this.addStandardInventorySlots(playerInventory, 8, 84);
}
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.brewingStand.stillValid(player);
}
@@ -67,7 +_,7 @@
ItemStack item = slot.getItem();
itemStack = item.copy();
if ((index < 0 || index > 2) && index != 3 && index != 4) {
- if (BrewingStandMenu.FuelSlot.mayPlaceItem(itemStack)) {
+ if (FuelSlot.mayPlaceItem(itemStack)) {
if (this.moveItemStackTo(item, 4, 5, false) || this.ingredientSlot.mayPlace(item) && !this.moveItemStackTo(item, 3, 4, false)) {
return ItemStack.EMPTY;
}
@@ -75,7 +_,7 @@
if (!this.moveItemStackTo(item, 3, 4, false)) {
return ItemStack.EMPTY;
}
- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemStack)) {
+ } else if (PotionSlot.mayPlaceItem(itemStack, this.player.player.level().potionBrewing())) { // Paper - custom potion mixes
if (!this.moveItemStackTo(item, 0, 3, false)) {
return ItemStack.EMPTY;
}
@@ -157,13 +_,15 @@
}
static class PotionSlot extends Slot {
- public PotionSlot(Container container, int slot, int x, int y) {
+ private final PotionBrewing potionBrewing; // Paper - custom potion mixes
+ public PotionSlot(Container container, int slot, int x, int y, PotionBrewing potionBrewing) { // Paper - custom potion mixes
super(container, slot, x, y);
+ this.potionBrewing = potionBrewing; // Paper - custom potion mixes
}
@Override
public boolean mayPlace(ItemStack stack) {
- return mayPlaceItem(stack);
+ return mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes
}
@Override
@@ -181,8 +_,8 @@
super.onTake(player, stack);
}
- public static boolean mayPlaceItem(ItemStack stack) {
- return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE);
+ public static boolean mayPlaceItem(ItemStack stack, PotionBrewing potionBrewing) { // Paper - custom potion mixes
+ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack); // Paper - Custom Potion Mixes
}
@Override
@@ -190,4 +_,16 @@
return BrewingStandMenu.EMPTY_SLOT_POTION;
}
}
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftBrewingStandView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryBrewer inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryBrewer(this.brewingStand);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftBrewingStandView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,103 @@
--- a/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -15,6 +_,21 @@
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
public class CartographyTableMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryCartography inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryCartography(this.container, this.resultContainer);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public static final int MAP_SLOT = 0;
public static final int ADDITIONAL_SLOT = 1;
public static final int RESULT_SLOT = 2;
@@ -24,20 +_,8 @@
private static final int USE_ROW_SLOT_END = 39;
private final ContainerLevelAccess access;
long lastSoundTime;
- public final Container container = new SimpleContainer(2) {
- @Override
- public void setChanged() {
- CartographyTableMenu.this.slotsChanged(this);
- super.setChanged();
- }
- };
- private final ResultContainer resultContainer = new ResultContainer() {
- @Override
- public void setChanged() {
- CartographyTableMenu.this.slotsChanged(this);
- super.setChanged();
- }
- };
+ public final Container container; // Paper - Add missing InventoryHolders - move down
+ private final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down
public CartographyTableMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -45,6 +_,34 @@
public CartographyTableMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) {
super(MenuType.CARTOGRAPHY_TABLE, containerId);
+ // Paper Start - Add missing InventoryHolders - move down
+ this.container = new SimpleContainer(this.createBlockHolder(access), 2) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ CartographyTableMenu.this.slotsChanged(this);
+ super.setChanged();
+ }
+ // CraftBukkit start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // CraftBukkit end
+ };
+ this.resultContainer = new ResultContainer(this.createBlockHolder(access)) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ CartographyTableMenu.this.slotsChanged(this);
+ super.setChanged();
+ }
+ // CraftBukkit start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // CraftBukkit end
+ };
+ // Paper Start - Add missing InventoryHolders - move down
this.access = access;
this.addSlot(new Slot(this.container, 0, 15, 15) {
@Override
@@ -80,10 +_,12 @@
}
});
this.addStandardInventorySlots(playerInventory, 8, 84);
+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.CARTOGRAPHY_TABLE);
}
@@ -99,6 +_,7 @@
} else {
this.resultContainer.removeItemNoUpdate(2);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
private void setupResultSlot(ItemStack map, ItemStack firstSlotStack, ItemStack resultOutput) {

View file

@ -0,0 +1,50 @@
--- a/net/minecraft/world/inventory/ChestMenu.java
+++ b/net/minecraft/world/inventory/ChestMenu.java
@@ -9,6 +_,29 @@
public class ChestMenu extends AbstractContainerMenu {
private final Container container;
private final int containerRows;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventory inventory;
+ if (this.container instanceof Inventory) {
+ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryPlayer((Inventory) this.container);
+ } else if (this.container instanceof net.minecraft.world.CompoundContainer) {
+ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((net.minecraft.world.CompoundContainer) this.container);
+ } else {
+ inventory = new org.bukkit.craftbukkit.inventory.CraftInventory(this.container);
+ }
+
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
private ChestMenu(MenuType<?> type, int containerId, Inventory playerInventory, int rows) {
this(type, containerId, playerInventory, new SimpleContainer(9 * rows), rows);
@@ -52,6 +_,9 @@
this.container = container;
this.containerRows = rows;
container.startOpen(playerInventory.player);
+ // CraftBukkit start - Save player
+ this.player = playerInventory;
+ // CraftBukkit end
int i = 18;
this.addChestGrid(container, 8, 18);
int i1 = 18 + this.containerRows * 18 + 13;
@@ -68,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -1,9 +1,46 @@
--- a/net/minecraft/world/inventory/ContainerLevelAccess.java
+++ b/net/minecraft/world/inventory/ContainerLevelAccess.java
@@ -8,16 +8,66 @@
@@ -12,6 +_,12 @@
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> levelPosConsumer) {
return Optional.empty();
}
+ // Paper start - fix menus with empty level accesses
+ @Override
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // Paper end - fix menus with empty level accesses
};
public interface ContainerLevelAccess {
static ContainerLevelAccess create(final Level level, final BlockPos pos) {
@@ -20,6 +_,23 @@
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> levelPosConsumer) {
return Optional.of(levelPosConsumer.apply(level, pos));
}
+ // CraftBukkit start
+ @Override
+ public Level getWorld() {
+ return level;
+ }
+
+ @Override
+ public BlockPos getPosition() {
+ return pos;
+ }
+ // CraftBukkit end
+ // Paper start - Add missing InventoryHolders
+ @Override
+ public boolean isBlock() {
+ return true;
+ }
+ // Paper end - Add missing InventoryHolders
};
}
@@ -35,4 +_,29 @@
return Optional.empty();
});
}
+ // CraftBukkit start
+ default Level getWorld() {
+ throw new UnsupportedOperationException("Not supported yet.");
@ -29,41 +66,4 @@
+ return new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(this, menu.getBukkitView().getTopInventory());
+ }
+ // Paper end - Add missing InventoryHolders
+
ContainerLevelAccess NULL = new ContainerLevelAccess() {
@Override
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> getter) {
return Optional.empty();
}
+ // Paper start - fix menus with empty level accesses
+ @Override
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // Paper end - fix menus with empty level accesses
};
static ContainerLevelAccess create(final Level world, final BlockPos pos) {
return new ContainerLevelAccess() {
+ // CraftBukkit start
@Override
+ public Level getWorld() {
+ return world;
+ }
+
+ @Override
+ public BlockPos getPosition() {
+ return pos;
+ }
+ // CraftBukkit end
+ // Paper start - Add missing InventoryHolders
+ @Override
+ public boolean isBlock() {
+ return true;
+ }
+ // Paper end - Add missing InventoryHolders
+
+ @Override
public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> getter) {
return Optional.of(getter.apply(world, pos));
}
}

View file

@ -0,0 +1,13 @@
--- a/net/minecraft/world/inventory/ContainerListener.java
+++ b/net/minecraft/world/inventory/ContainerListener.java
@@ -6,4 +_,10 @@
void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack stack);
void dataChanged(AbstractContainerMenu containerMenu, int dataSlotIndex, int value);
+
+ // Paper start - Add PlayerInventorySlotChangeEvent
+ default void slotChanged(AbstractContainerMenu containerToSend, int dataSlotIndex, ItemStack oldStack, ItemStack stack) {
+ slotChanged(containerToSend, dataSlotIndex, stack);
+ }
+ // Paper end - Add PlayerInventorySlotChangeEvent
}

View file

@ -0,0 +1,9 @@
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
@@ -11,4 +_,6 @@
void sendCarriedChange(AbstractContainerMenu containerMenu, ItemStack stack);
void sendDataChange(AbstractContainerMenu container, int id, int value);
+
+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus
}

View file

@ -0,0 +1,31 @@
--- a/net/minecraft/world/inventory/CrafterMenu.java
+++ b/net/minecraft/world/inventory/CrafterMenu.java
@@ -19,6 +_,20 @@
private final ContainerData containerData;
private final Player player;
private final CraftingContainer container;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftCrafterView bukkitEntity = null;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftCrafterView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryCrafter inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryCrafter(this.container, this.resultContainer);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftCrafterView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public CrafterMenu(int containerId, Inventory playerInventory) {
super(MenuType.CRAFTER_3x3, containerId);
@@ -100,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -0,0 +1,18 @@
--- a/net/minecraft/world/inventory/CraftingContainer.java
+++ b/net/minecraft/world/inventory/CraftingContainer.java
@@ -12,6 +_,15 @@
List<ItemStack> getItems();
+ // CraftBukkit start
+ default net.minecraft.world.item.crafting.RecipeHolder<?> getCurrentRecipe() {
+ return null;
+ }
+
+ default void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<?> recipe) {
+ }
+ // CraftBukkit end
+
default CraftingInput asCraftInput() {
return this.asPositionedCraftInput().input();
}

View file

@ -0,0 +1,62 @@
--- a/net/minecraft/world/inventory/CraftingMenu.java
+++ b/net/minecraft/world/inventory/CraftingMenu.java
@@ -30,13 +_,16 @@
public final ContainerLevelAccess access;
private final Player player;
private boolean placingRecipe;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ // CraftBukkit end
public CraftingMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
}
public CraftingMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) {
- super(MenuType.CRAFTING, containerId, 3, 3);
+ super(MenuType.CRAFTING, containerId, 3, 3, playerInventory); // CraftBukkit - pass player
this.access = access;
this.player = playerInventory.player;
this.addResultSlot(this.player, 124, 35);
@@ -56,6 +_,7 @@
ServerPlayer serverPlayer = (ServerPlayer)player;
ItemStack itemStack = ItemStack.EMPTY;
Optional<RecipeHolder<CraftingRecipe>> recipeFor = level.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftInput, level, recipe);
+ craftSlots.setCurrentRecipe(recipeFor.orElse(null)); // CraftBukkit
if (recipeFor.isPresent()) {
RecipeHolder<CraftingRecipe> recipeHolder = recipeFor.get();
CraftingRecipe craftingRecipe = recipeHolder.value();
@@ -66,6 +_,7 @@
}
}
}
+ itemStack = org.bukkit.craftbukkit.event.CraftEventFactory.callPreCraftEvent(craftSlots, resultSlots, itemStack, menu.getBukkitView(), recipeFor.map(RecipeHolder::value).orElse(null) instanceof net.minecraft.world.item.crafting.RepairItemRecipe); // CraftBukkit
resultSlots.setItem(0, itemStack);
menu.setRemoteSlot(0, itemStack);
@@ -102,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.CRAFTING_TABLE);
}
@@ -176,4 +_,17 @@
protected Player owner() {
return this.player;
}
+
+ // CraftBukkit start
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftSlots, this.resultSlots);
+ this.bukkitEntity = new CraftInventoryView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,49 @@
--- a/net/minecraft/world/inventory/DispenserMenu.java
+++ b/net/minecraft/world/inventory/DispenserMenu.java
@@ -13,6 +_,10 @@
private static final int USE_ROW_SLOT_START = 36;
private static final int USE_ROW_SLOT_END = 45;
public final Container dispenser;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+ // CraftBukkit end
public DispenserMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new SimpleContainer(9));
@@ -20,6 +_,9 @@
public DispenserMenu(int containerId, Inventory playerInventory, Container container) {
super(MenuType.GENERIC_3x3, containerId);
+ // CraftBukkit start - Save player
+ this.player = playerInventory;
+ // CraftBukkit end
checkContainerSize(container, 9);
this.dispenser = container;
container.startOpen(playerInventory.player);
@@ -38,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.dispenser.stillValid(player);
}
@@ -77,4 +_,17 @@
super.removed(player);
this.dispenser.stopOpen(player);
}
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventory(this.dispenser);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,205 @@
--- a/net/minecraft/world/inventory/EnchantmentMenu.java
+++ b/net/minecraft/world/inventory/EnchantmentMenu.java
@@ -31,19 +_,17 @@
public class EnchantmentMenu extends AbstractContainerMenu {
static final ResourceLocation EMPTY_SLOT_LAPIS_LAZULI = ResourceLocation.withDefaultNamespace("container/slot/lapis_lazuli");
- private final Container enchantSlots = new SimpleContainer(2) {
- @Override
- public void setChanged() {
- super.setChanged();
- EnchantmentMenu.this.slotsChanged(this);
- }
- };
+ private final Container enchantSlots; // Paper - Add missing InventoryHolders - move down
private final ContainerLevelAccess access;
private final RandomSource random = RandomSource.create();
private final DataSlot enchantmentSeed = DataSlot.standalone();
public final int[] costs = new int[3];
public final int[] enchantClue = new int[]{-1, -1, -1};
public final int[] levelClue = new int[]{-1, -1, -1};
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftEnchantmentView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+ // CraftBukkit end
public EnchantmentMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -51,6 +_,22 @@
public EnchantmentMenu(int containerId, Inventory playerInventory, ContainerLevelAccess access) {
super(MenuType.ENCHANTMENT, containerId);
+ // Paper start - Add missing InventoryHolders
+ this.enchantSlots = new SimpleContainer(this.createBlockHolder(access), 2) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ EnchantmentMenu.this.slotsChanged(this);
+ }
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // CraftBukkit end
+ };
+ // Paper end - Add missing InventoryHolders
this.access = access;
this.addSlot(new Slot(this.enchantSlots, 0, 15, 47) {
@Override
@@ -80,13 +_,16 @@
this.addDataSlot(DataSlot.shared(this.levelClue, 0));
this.addDataSlot(DataSlot.shared(this.levelClue, 1));
this.addDataSlot(DataSlot.shared(this.levelClue, 2));
+ // CraftBukkit start
+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity();
+ // CraftBukkit end
}
@Override
public void slotsChanged(Container inventory) {
if (inventory == this.enchantSlots) {
ItemStack item = inventory.getItem(0);
- if (!item.isEmpty() && item.isEnchantable()) {
+ if (!item.isEmpty()) { // CraftBukkit - relax condition
this.access.execute((level, blockPos) -> {
IdMap<Holder<Enchantment>> holderIdMap = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
int i1 = 0;
@@ -119,6 +_,42 @@
}
}
+ // CraftBukkit start
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(item);
+ org.bukkit.enchantments.EnchantmentOffer[] offers = new org.bukkit.enchantments.EnchantmentOffer[3];
+ for (int j = 0; j < 3; ++j) {
+ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[j] >= 0) ? org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(holderIdMap.byId(this.enchantClue[j])) : null;
+ offers[j] = (enchantment != null) ? new org.bukkit.enchantments.EnchantmentOffer(enchantment, this.levelClue[j], this.costs[j]) : null;
+ }
+
+ org.bukkit.event.enchantment.PrepareItemEnchantEvent event = new org.bukkit.event.enchantment.PrepareItemEnchantEvent(this.player, this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, offers, i1);
+ event.setCancelled(!item.isEnchantable());
+ level.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ for (int j = 0; j < 3; ++j) {
+ this.costs[j] = 0;
+ this.enchantClue[j] = -1;
+ this.levelClue[j] = -1;
+ }
+ return;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ org.bukkit.enchantments.EnchantmentOffer offer = event.getOffers()[j];
+ if (offer != null) {
+ this.costs[j] = offer.getCost();
+ this.enchantClue[j] = holderIdMap.getId(org.bukkit.craftbukkit.enchantments.CraftEnchantment
+ .bukkitToMinecraftHolder(offer.getEnchantment()));
+ this.levelClue[j] = offer.getEnchantmentLevel();
+ } else {
+ this.costs[j] = 0;
+ this.enchantClue[j] = -1;
+ this.levelClue[j] = -1;
+ }
+ }
+ // CraftBukkit end
+
this.broadcastChanges();
});
} else {
@@ -145,19 +_,51 @@
return false;
} else {
this.access.execute((level, blockPos) -> {
- ItemStack itemStack = item;
+ ItemStack itemStack = item; // Paper - diff on change
List<EnchantmentInstance> enchantmentList = this.getEnchantmentList(level.registryAccess(), item, id, this.costs[id]);
- if (!enchantmentList.isEmpty()) {
+ // CraftBukkit start
+ IdMap<Holder<Enchantment>> registry = level.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
+ if (true || !enchantmentList.isEmpty()) {
+ // player.onEnchantmentPerformed(item, i); // Moved down
+ java.util.Map<org.bukkit.enchantments.Enchantment, Integer> enchants = new java.util.HashMap<>();
+ for (EnchantmentInstance instance : enchantmentList) {
+ enchants.put(org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(instance.enchantment), instance.level);
+ }
+ org.bukkit.craftbukkit.inventory.CraftItemStack craftItemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack);
+ org.bukkit.enchantments.Enchantment hintedEnchantment = org.bukkit.craftbukkit.enchantments.CraftEnchantment.minecraftHolderToBukkit(registry.byId(this.enchantClue[id]));
+ int hintedEnchantmentLevel = this.levelClue[id];
+ org.bukkit.event.enchantment.EnchantItemEvent event = new org.bukkit.event.enchantment.EnchantItemEvent((org.bukkit.entity.Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), craftItemStack, this.costs[id], enchants, hintedEnchantment, hintedEnchantmentLevel, id);
+ level.getCraftServer().getPluginManager().callEvent(event);
+ int itemLevel = event.getExpLevelCost();
+ if (event.isCancelled() || (itemLevel > player.experienceLevel && !player.getAbilities().instabuild) || event.getEnchantsToAdd().isEmpty()) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper start
+ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(craftItemStack, event.getItem());
+ if (itemStack != item) {
+ this.enchantSlots.setItem(0, itemStack);
+ }
+ if (itemStack.is(Items.BOOK)) {
+ itemStack = itemStack.transmuteCopy(Items.ENCHANTED_BOOK);
+ this.enchantSlots.setItem(0, itemStack);
+ }
+ // Paper end
+
+ // CraftBukkit start
+ for (java.util.Map.Entry<org.bukkit.enchantments.Enchantment, Integer> entry : event.getEnchantsToAdd().entrySet()) {
+ Holder<Enchantment> nms = org.bukkit.craftbukkit.enchantments.CraftEnchantment.bukkitToMinecraftHolder(entry.getKey());
+ if (nms == null) {
+ continue;
+ }
+
+ EnchantmentInstance weightedrandomenchant = new EnchantmentInstance(nms, entry.getValue());
+ itemStack.enchant(weightedrandomenchant.enchantment, weightedrandomenchant.level);
+ }
player.onEnchantmentPerformed(item, i);
- if (item.is(Items.BOOK)) {
- itemStack = item.transmuteCopy(Items.ENCHANTED_BOOK);
- this.enchantSlots.setItem(0, itemStack);
- }
-
- for (EnchantmentInstance enchantmentInstance : enchantmentList) {
- itemStack.enchant(enchantmentInstance.enchantment, enchantmentInstance.level);
- }
-
+ // CraftBukkit end
+
+ // CraftBukkit - TODO: let plugins change this
item1.consume(i, player);
if (item1.isEmpty()) {
this.enchantSlots.setItem(1, ItemStack.EMPTY);
@@ -214,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.ENCHANTING_TABLE);
}
@@ -261,4 +_,22 @@
return itemStack;
}
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftEnchantmentView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryEnchanting inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryEnchanting(this.enchantSlots);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftEnchantmentView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
+ // Paper start - add enchantment seed update API
+ public void setEnchantmentSeed(int seed) {
+ this.enchantmentSeed.set(seed);
+ }
+ // Paper end - add enchantment seed update API
}

View file

@ -0,0 +1,11 @@
--- a/net/minecraft/world/inventory/FurnaceResultSlot.java
+++ b/net/minecraft/world/inventory/FurnaceResultSlot.java
@@ -45,7 +_,7 @@
protected void checkTakeAchievements(ItemStack stack) {
stack.onCraftedBy(this.player.level(), this.player, this.removeCount);
if (this.player instanceof ServerPlayer serverPlayer && this.container instanceof AbstractFurnaceBlockEntity abstractFurnaceBlockEntity) {
- abstractFurnaceBlockEntity.awardUsedRecipesAndPopExperience(serverPlayer);
+ abstractFurnaceBlockEntity.awardUsedRecipesAndPopExperience(serverPlayer, stack, this.removeCount); // CraftBukkit
}
this.removeCount = 0;

View file

@ -0,0 +1,108 @@
--- a/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -20,6 +_,21 @@
import net.minecraft.world.phys.Vec3;
public class GrindstoneMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryGrindstone inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryGrindstone(this.repairSlots, this.resultSlots);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public static final int MAX_NAME_LENGTH = 35;
public static final int INPUT_SLOT = 0;
public static final int ADDITIONAL_SLOT = 1;
@@ -28,14 +_,8 @@
private static final int INV_SLOT_END = 30;
private static final int USE_ROW_SLOT_START = 30;
private static final int USE_ROW_SLOT_END = 39;
- private final Container resultSlots = new ResultContainer();
- final Container repairSlots = new SimpleContainer(2) {
- @Override
- public void setChanged() {
- super.setChanged();
- GrindstoneMenu.this.slotsChanged(this);
- }
- };
+ private final Container resultSlots; // Paper - Add missing InventoryHolders - move down
+ final Container repairSlots; // Paper - Add missing InventoryHolders - move down
private final ContainerLevelAccess access;
public GrindstoneMenu(int containerId, Inventory playerInventory) {
@@ -44,6 +_,22 @@
public GrindstoneMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) {
super(MenuType.GRINDSTONE, containerId);
+ // Paper start - Add missing InventoryHolders
+ this.resultSlots = new ResultContainer(this.createBlockHolder(access)); // Paper - Add missing InventoryHolders
+ this.repairSlots = new SimpleContainer(this.createBlockHolder(access), 2) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ GrindstoneMenu.this.slotsChanged(this);
+ }
+ // CraftBukkit start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // CraftBukkit end
+ };
+ // Paper end - Add missing InventoryHolders
this.access = access;
this.addSlot(new Slot(this.repairSlots, 0, 49, 19) {
@Override
@@ -67,7 +_,11 @@
public void onTake(Player player, ItemStack stack) {
access.execute((level, blockPos) -> {
if (level instanceof ServerLevel) {
- ExperienceOrb.award((ServerLevel)level, Vec3.atCenterOf(blockPos), this.getExperienceAmount(level));
+ // Paper start - Fire BlockExpEvent on grindstone use
+ org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(level, blockPos), this.getExperienceAmount(level));
+ event.callEvent();
+ ExperienceOrb.award((ServerLevel) level, Vec3.atCenterOf(blockPos), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player);
+ // Paper end - Fire BlockExpEvent on grindstone use
}
level.levelEvent(1042, blockPos, 0);
@@ -104,6 +_,7 @@
}
});
this.addStandardInventorySlots(playerInventory, 8, 84);
+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
@@ -111,11 +_,13 @@
super.slotsChanged(inventory);
if (inventory == this.repairSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
}
private void createResult() {
- this.resultSlots.setItem(0, this.computeResult(this.repairSlots.getItem(0), this.repairSlots.getItem(1)));
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareGrindstoneEvent(this.getBukkitView(), this.computeResult(this.repairSlots.getItem(0), this.repairSlots.getItem(1))); // CraftBukkit
+ this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client
this.broadcastChanges();
}
@@ -201,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.GRINDSTONE);
}

View file

@ -0,0 +1,40 @@
--- a/net/minecraft/world/inventory/HopperMenu.java
+++ b/net/minecraft/world/inventory/HopperMenu.java
@@ -9,6 +_,21 @@
public class HopperMenu extends AbstractContainerMenu {
public static final int CONTAINER_SIZE = 5;
private final Container hopper;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventory(this.hopper);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public HopperMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new SimpleContainer(5));
@@ -17,6 +_,7 @@
public HopperMenu(int containerId, Inventory playerInventory, Container container) {
super(MenuType.HOPPER, containerId);
this.hopper = container;
+ this.player = playerInventory; // CraftBukkit - save player
checkContainerSize(container, 5);
container.startOpen(playerInventory.player);
@@ -29,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.hopper.stillValid(player);
}

View file

@ -0,0 +1,26 @@
--- a/net/minecraft/world/inventory/HorseInventoryMenu.java
+++ b/net/minecraft/world/inventory/HorseInventoryMenu.java
@@ -19,9 +_,23 @@
private final AbstractHorse horse;
public static final int SLOT_BODY_ARMOR = 1;
private static final int SLOT_HORSE_INVENTORY_START = 2;
+ // CraftBukkit start
+ org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
+ Inventory player;
+
+ @Override
+ public org.bukkit.inventory.InventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ return this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), this.horseContainer.getOwner().getInventory(), this);
+ }
+ // CraftBukkit end
public HorseInventoryMenu(int containerId, Inventory inventory, Container horseContainer, final AbstractHorse horse, int columns) {
super(null, containerId);
+ this.player = inventory; // CraftBukkit - save player
this.horseContainer = horseContainer;
this.armorContainer = horse.getBodyArmorAccess();
this.horse = horse;

View file

@ -0,0 +1,45 @@
--- a/net/minecraft/world/inventory/InventoryMenu.java
+++ b/net/minecraft/world/inventory/InventoryMenu.java
@@ -2,6 +_,7 @@
import java.util.List;
import java.util.Map;
+import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
@@ -44,9 +_,15 @@
private static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
public final boolean active;
private final Player owner;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity = null;
+ // CraftBukkit end
public InventoryMenu(Inventory playerInventory, boolean active, final Player owner) {
- super(null, 0, 2, 2);
+ // CraftBukkit start
+ super((MenuType) null, 0, 2, 2, playerInventory); // CraftBukkit - save player
+ this.setTitle(Component.translatable("container.crafting")); // SPIGOT-4722: Allocate title for player inventory
+ // CraftBukkit end
this.active = active;
this.owner = owner;
this.addResultSlot(owner, 154, 28);
@@ -188,4 +_,17 @@
protected Player owner() {
return this.owner;
}
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryCrafting inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryCrafting(this.craftSlots, this.resultSlots);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.owner.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,6 +1,6 @@
--- a/net/minecraft/world/inventory/ItemCombinerMenu.java
+++ b/net/minecraft/world/inventory/ItemCombinerMenu.java
@@ -17,12 +17,7 @@
@@ -15,12 +_,7 @@
protected final ContainerLevelAccess access;
protected final Player player;
protected final Container inputSlots;
@ -13,11 +13,11 @@
+ protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init
private final int resultSlotIndex;
protected boolean mayPickup(Player player, boolean present) {
@@ -36,6 +31,14 @@
public ItemCombinerMenu(@Nullable MenuType<?> type, int syncId, Inventory playerInventory, ContainerLevelAccess context, ItemCombinerMenuSlotDefinition forgingSlotsManager) {
super(type, syncId);
this.access = context;
protected boolean mayPickup(Player player, boolean hasStack) {
@@ -36,6 +_,14 @@
) {
super(menuType, containerId);
this.access = access;
+ // Paper start - Add missing InventoryHolders; delay field init
+ this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) {
+ @Override
@ -26,19 +26,10 @@
+ }
+ };
+ // Paper end - Add missing InventoryHolders; delay field init
this.player = playerInventory.player;
this.inputSlots = this.createContainer(forgingSlotsManager.getNumOfInputSlots());
this.resultSlotIndex = forgingSlotsManager.getResultSlotIndex();
@@ -50,7 +53,7 @@
while (iterator.hasNext()) {
final ItemCombinerMenuSlotDefinition.SlotDefinition itemcombinermenuslotdefinition_b = (ItemCombinerMenuSlotDefinition.SlotDefinition) iterator.next();
- this.addSlot(new Slot(this, this.inputSlots, itemcombinermenuslotdefinition_b.slotIndex(), itemcombinermenuslotdefinition_b.x(), itemcombinermenuslotdefinition_b.y()) {
+ this.addSlot(new Slot(this.inputSlots, itemcombinermenuslotdefinition_b.slotIndex(), itemcombinermenuslotdefinition_b.x(), itemcombinermenuslotdefinition_b.y()) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return itemcombinermenuslotdefinition_b.mayPlace().test(stack);
@@ -82,7 +85,7 @@
this.player = inventory.player;
this.inputSlots = this.createContainer(slotDefinition.getNumOfInputSlots());
this.resultSlotIndex = slotDefinition.getResultSlotIndex();
@@ -79,7 +_,7 @@
public abstract void createResult();
private SimpleContainer createContainer(int size) {
@ -47,19 +38,19 @@
@Override
public void setChanged() {
super.setChanged();
@@ -96,6 +99,7 @@
@@ -93,6 +_,7 @@
super.slotsChanged(inventory);
if (inventory == this.inputSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, this instanceof SmithingMenu ? 3 : 2); // Paper - Add PrepareResultEvent
}
}
@@ -110,6 +114,7 @@
@@ -104,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return (Boolean) this.access.evaluate((world, blockposition) -> {
return !this.isValidBlock(world.getBlockState(blockposition)) ? false : player.canInteractWithBlock(blockposition, 4.0D);
}, true);
return this.access
.evaluate((level, blockPos) -> !this.isValidBlock(level.getBlockState(blockPos)) ? false : player.canInteractWithBlock(blockPos, 4.0), true);
}

View file

@ -0,0 +1,103 @@
--- a/net/minecraft/world/inventory/LecternMenu.java
+++ b/net/minecraft/world/inventory/LecternMenu.java
@@ -14,12 +_,29 @@
public static final int BUTTON_PAGE_JUMP_RANGE_START = 100;
private final Container lectern;
private final ContainerData lecternData;
-
- public LecternMenu(int containerId) {
- this(containerId, new SimpleContainer(1), new SimpleContainerData(1));
- }
-
- public LecternMenu(int containerId, Container lectern, ContainerData lecternData) {
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftLecternView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftLecternView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryLectern inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryLectern(this.lectern);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftLecternView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
+ // CraftBukkit start - add player
+ public LecternMenu(int containerId, net.minecraft.world.entity.player.Inventory playerinventory) {
+ this(containerId, new SimpleContainer(1), new SimpleContainerData(1), playerinventory);
+ // CraftBukkit end - add player
+ }
+
+ public LecternMenu(int containerId, Container lectern, ContainerData lecternData, net.minecraft.world.entity.player.Inventory playerinventory) {
super(MenuType.LECTERN, containerId);
checkContainerSize(lectern, 1);
checkContainerDataCount(lecternData, 1);
@@ -33,10 +_,12 @@
}
});
this.addDataSlots(lecternData);
+ this.player = (org.bukkit.entity.Player) playerinventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
public boolean clickMenuButton(Player player, int id) {
+ io.papermc.paper.event.player.PlayerLecternPageChangeEvent playerLecternPageChangeEvent; org.bukkit.craftbukkit.inventory.CraftInventoryLectern bukkitView; // Paper - Add PlayerLecternPageChangeEvent
if (id >= 100) {
int i = id - 100;
this.setData(0, i);
@@ -45,12 +_,26 @@
switch (id) {
case 1: {
int i = this.lecternData.get(0);
- this.setData(0, i - 1);
+ // Paper start - Add PlayerLecternPageChangeEvent
+ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory();
+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, i, i - 1);
+ if (!playerLecternPageChangeEvent.callEvent()) {
+ return false;
+ }
+ this.setData(0, playerLecternPageChangeEvent.getNewPage());
+ // Paper end - Add PlayerLecternPageChangeEvent
return true;
}
case 2: {
int i = this.lecternData.get(0);
- this.setData(0, i + 1);
+ // Paper start - Add PlayerLecternPageChangeEvent
+ bukkitView = (org.bukkit.craftbukkit.inventory.CraftInventoryLectern) getBukkitView().getTopInventory();
+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, i, i + 1);
+ if (!playerLecternPageChangeEvent.callEvent()) {
+ return false;
+ }
+ this.setData(0, playerLecternPageChangeEvent.getNewPage());
+ // Paper end - Add PlayerLecternPageChangeEvent
return true;
}
case 3:
@@ -58,6 +_,13 @@
return false;
}
+ // CraftBukkit start - Event for taking the book
+ org.bukkit.event.player.PlayerTakeLecternBookEvent event = new org.bukkit.event.player.PlayerTakeLecternBookEvent(this.player, ((org.bukkit.craftbukkit.inventory.CraftInventoryLectern) this.getBukkitView().getTopInventory()).getHolder());
+ org.bukkit.Bukkit.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
ItemStack itemStack = this.lectern.removeItemNoUpdate(0);
this.lectern.setChanged();
if (!player.getInventory().add(itemStack)) {
@@ -84,6 +_,8 @@
@Override
public boolean stillValid(Player player) {
+ if (this.lectern instanceof net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory && !((net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory) this.lectern).getLectern().hasBook()) return false; // CraftBukkit
+ if (!this.checkReachable) return true; // CraftBukkit
return this.lectern.stillValid(player);
}

View file

@ -0,0 +1,143 @@
--- a/net/minecraft/world/inventory/LoomMenu.java
+++ b/net/minecraft/world/inventory/LoomMenu.java
@@ -38,21 +_,23 @@
private final Slot patternSlot;
private final Slot resultSlot;
long lastSoundTime;
- private final Container inputContainer = new SimpleContainer(3) {
- @Override
- public void setChanged() {
- super.setChanged();
- LoomMenu.this.slotsChanged(this);
- LoomMenu.this.slotUpdateListener.run();
- }
- };
- private final Container outputContainer = new SimpleContainer(1) {
- @Override
- public void setChanged() {
- super.setChanged();
- LoomMenu.this.slotUpdateListener.run();
- }
- };
+ private final Container inputContainer; // Paper - Add missing InventoryHolders - move down
+ private final Container outputContainer; // Paper - Add missing InventoryHolders - move down
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftLoomView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftLoomView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryLoom inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryLoom(this.inputContainer, this.outputContainer);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftLoomView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public LoomMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -61,6 +_,28 @@
public LoomMenu(int containerId, Inventory playerInventory, final ContainerLevelAccess access) {
super(MenuType.LOOM, containerId);
this.access = access;
+ // CraftBukkit start
+ this.inputContainer = new SimpleContainer(this.createBlockHolder(access), 3) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ LoomMenu.this.slotsChanged(this);
+ LoomMenu.this.slotUpdateListener.run();
+ }
+ };
+ this.outputContainer = new SimpleContainer(this.createBlockHolder(access), 1) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ LoomMenu.this.slotUpdateListener.run();
+ }
+
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ };
+ // CraftBukkit end
this.bannerSlot = this.addSlot(new Slot(this.inputContainer, 0, 13, 26) {
@Override
public boolean mayPlace(ItemStack stack) {
@@ -106,18 +_,44 @@
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(this.selectedBannerPatternIndex);
this.patternGetter = playerInventory.player.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN);
+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.LOOM);
}
@Override
public boolean clickMenuButton(Player player, int id) {
if (id >= 0 && id < this.selectablePatterns.size()) {
- this.selectedBannerPatternIndex.set(id);
- this.setupResultSlot(this.selectablePatterns.get(id));
+ // Paper start - Add PlayerLoomPatternSelectEvent
+ int selectablePatternIndex = id;
+ io.papermc.paper.event.player.PlayerLoomPatternSelectEvent event = new io.papermc.paper.event.player.PlayerLoomPatternSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), ((org.bukkit.craftbukkit.inventory.CraftInventoryLoom) getBukkitView().getTopInventory()), org.bukkit.craftbukkit.block.banner.CraftPatternType.minecraftHolderToBukkit(this.selectablePatterns.get(selectablePatternIndex)));
+ if (!event.callEvent()) {
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+ final Holder<BannerPattern> eventPattern = org.bukkit.craftbukkit.block.banner.CraftPatternType.bukkitToMinecraftHolder(event.getPatternType());
+ Holder<BannerPattern> selectedPattern = null;
+ for (int i = 0; i < this.selectablePatterns.size(); i++) {
+ final Holder<BannerPattern> holder = this.selectablePatterns.get(i);
+ if (eventPattern.equals(holder)) {
+ selectablePatternIndex = i;
+ selectedPattern = holder;
+ break;
+ }
+ }
+ if (selectedPattern == null) {
+ selectedPattern = eventPattern;
+ selectablePatternIndex = -1;
+ }
+
+ player.containerMenu.sendAllDataToRemote();
+ this.selectedBannerPatternIndex.set(selectablePatternIndex);
+ this.setupResultSlot(java.util.Objects.requireNonNull(selectedPattern, "selectedPattern was null, this is unexpected"));
+ // Paper end - Add PlayerLoomPatternSelectEvent
return true;
} else {
return false;
@@ -180,7 +_,8 @@
this.resultSlot.set(ItemStack.EMPTY);
}
- this.broadcastChanges();
+ // this.broadcastChanges(); // Paper - Add PrepareResultEvent; done below
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper - Add PrepareResultEvent
} else {
this.resultSlot.set(ItemStack.EMPTY);
this.selectablePatterns = List.of();
@@ -269,7 +_,14 @@
itemStack.update(
DataComponents.BANNER_PATTERNS,
BannerPatternLayers.EMPTY,
- bannerPatternLayers -> new BannerPatternLayers.Builder().addAll(bannerPatternLayers).add(pattern, dyeColor).build()
+ // CraftBukkit start
+ bannerPatternLayers -> {
+ if (bannerPatternLayers.layers().size() > 20) {
+ bannerPatternLayers = new BannerPatternLayers(List.copyOf(bannerPatternLayers.layers().subList(0, 20)));
+ }
+ return new BannerPatternLayers.Builder().addAll(bannerPatternLayers).add(pattern, dyeColor).build();
+ }
+ // CraftBukkit end
);
}

View file

@ -0,0 +1,33 @@
--- a/net/minecraft/world/inventory/MenuType.java
+++ b/net/minecraft/world/inventory/MenuType.java
@@ -26,7 +_,7 @@
public static final MenuType<FurnaceMenu> FURNACE = register("furnace", FurnaceMenu::new);
public static final MenuType<GrindstoneMenu> GRINDSTONE = register("grindstone", GrindstoneMenu::new);
public static final MenuType<HopperMenu> HOPPER = register("hopper", HopperMenu::new);
- public static final MenuType<LecternMenu> LECTERN = register("lectern", (containerId, playerInventory) -> new LecternMenu(containerId));
+ public static final MenuType<LecternMenu> LECTERN = register("lectern", LecternMenu::new); // CraftBukkit
public static final MenuType<LoomMenu> LOOM = register("loom", LoomMenu::new);
public static final MenuType<MerchantMenu> MERCHANT = register("merchant", MerchantMenu::new);
public static final MenuType<ShulkerBoxMenu> SHULKER_BOX = register("shulker_box", ShulkerBoxMenu::new);
@@ -35,17 +_,17 @@
public static final MenuType<CartographyTableMenu> CARTOGRAPHY_TABLE = register("cartography_table", CartographyTableMenu::new);
public static final MenuType<StonecutterMenu> STONECUTTER = register("stonecutter", StonecutterMenu::new);
private final FeatureFlagSet requiredFeatures;
- private final MenuType.MenuSupplier<T> constructor;
+ private final MenuSupplier<T> constructor;
- private static <T extends AbstractContainerMenu> MenuType<T> register(String key, MenuType.MenuSupplier<T> factory) {
+ private static <T extends AbstractContainerMenu> MenuType<T> register(String key, MenuSupplier<T> factory) {
return Registry.register(BuiltInRegistries.MENU, key, new MenuType<>(factory, FeatureFlags.VANILLA_SET));
}
- private static <T extends AbstractContainerMenu> MenuType<T> register(String key, MenuType.MenuSupplier<T> factory, FeatureFlag... requiredFeatures) {
+ private static <T extends AbstractContainerMenu> MenuType<T> register(String key, MenuSupplier<T> factory, FeatureFlag... requiredFeatures) {
return Registry.register(BuiltInRegistries.MENU, key, new MenuType<>(factory, FeatureFlags.REGISTRY.subset(requiredFeatures)));
}
- private MenuType(MenuType.MenuSupplier<T> constructor, FeatureFlagSet requiredFeatures) {
+ private MenuType(MenuSupplier<T> constructor, FeatureFlagSet requiredFeatures) {
this.constructor = constructor;
this.requiredFeatures = requiredFeatures;
}

View file

@ -0,0 +1,48 @@
--- a/net/minecraft/world/inventory/MerchantContainer.java
+++ b/net/minecraft/world/inventory/MerchantContainer.java
@@ -17,6 +_,45 @@
private MerchantOffer activeOffer;
public int selectionHint;
private int futureXp;
+ // CraftBukkit start - add fields and methods
+ public java.util.List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<org.bukkit.entity.HumanEntity>();
+ private int maxStack = MAX_STACK;
+
+ public java.util.List<ItemStack> getContents() {
+ return this.itemStacks;
+ }
+
+ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {
+ this.transaction.add(who);
+ }
+
+ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {
+ this.transaction.remove(who);
+ this.merchant.setTradingPlayer((Player) null); // SPIGOT-4860
+ }
+
+ public java.util.List<org.bukkit.entity.HumanEntity> getViewers() {
+ return this.transaction;
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return this.maxStack;
+ }
+
+ public void setMaxStackSize(int i) {
+ this.maxStack = i;
+ }
+
+ public org.bukkit.inventory.InventoryHolder getOwner() {
+ return (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager abstractVillager) ? (org.bukkit.craftbukkit.entity.CraftAbstractVillager) ((net.minecraft.world.entity.npc.AbstractVillager) this.merchant).getBukkitEntity() : null;
+ }
+
+ @Override
+ public org.bukkit.Location getLocation() {
+ return (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager) ? ((net.minecraft.world.entity.npc.AbstractVillager) this.merchant).getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations
+ }
+ // CraftBukkit end
public MerchantContainer(Merchant merchant) {
this.merchant = merchant;

View file

@ -0,0 +1,83 @@
--- a/net/minecraft/world/inventory/MerchantMenu.java
+++ b/net/minecraft/world/inventory/MerchantMenu.java
@@ -30,6 +_,18 @@
private int merchantLevel;
private boolean showProgressBar;
private boolean canRestock;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftMerchantView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftMerchantView getBukkitView() {
+ if (this.bukkitEntity == null) {
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftMerchantView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventoryMerchant(this.trader, this.tradeContainer), this, this.trader);
+ }
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public MerchantMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new ClientSideMerchant(playerInventory.player));
@@ -42,6 +_,7 @@
this.addSlot(new Slot(this.tradeContainer, 0, 136, 37));
this.addSlot(new Slot(this.tradeContainer, 1, 162, 37));
this.addSlot(new MerchantResultSlot(playerInventory.player, trader, this.tradeContainer, 2, 220, 37));
+ this.player = playerInventory; // CraftBukkit - save player
this.addStandardInventorySlots(playerInventory, 108, 84);
}
@@ -105,12 +_,12 @@
ItemStack item = slot.getItem();
itemStack = item.copy();
if (index == 2) {
- if (!this.moveItemStackTo(item, 3, 39, true)) {
+ if (!this.moveItemStackTo(item, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
return ItemStack.EMPTY;
}
- slot.onQuickCraft(item, itemStack);
- this.playTradeSound();
+ // slot.onQuickCraft(item, itemStack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call
+ // this.playTradeSound();
} else if (index != 0 && index != 1) {
if (index >= 3 && index < 30) {
if (!this.moveItemStackTo(item, 30, 39, false)) {
@@ -123,6 +_,7 @@
return ItemStack.EMPTY;
}
+ if (index != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2
if (item.isEmpty()) {
slot.setByPlayer(ItemStack.EMPTY);
} else {
@@ -134,13 +_,28 @@
}
slot.onTake(player, item);
+ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2
+ if (index == 2) { // is merchant result slot
+ slot.onTake(player, item);
+ if (item.isEmpty()) {
+ slot.set(ItemStack.EMPTY);
+ return ItemStack.EMPTY;
+ }
+
+ this.moveItemStackTo(item, 3, 39, true, false); // This should always succeed because it's checked above
+
+ slot.onQuickCraft(item, itemStack);
+ this.playTradeSound();
+ slot.set(ItemStack.EMPTY); // item should ALWAYS be empty
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
}
return itemStack;
}
private void playTradeSound() {
- if (!this.trader.isClientSide()) {
+ if (!this.trader.isClientSide() && this.trader instanceof Entity) { // CraftBukkit - SPIGOT-5035
Entity entity = (Entity)this.trader;
entity.level()
.playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.trader.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false);

View file

@ -1,19 +1,19 @@
--- a/net/minecraft/world/inventory/MerchantResultSlot.java
+++ b/net/minecraft/world/inventory/MerchantResultSlot.java
@@ -47,13 +47,32 @@
@@ -47,13 +_,32 @@
@Override
public void onTake(Player player, ItemStack stack) {
- this.checkTakeAchievements(stack);
+ // this.checkTakeAchievements(stack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; move to after event is called and not cancelled
MerchantOffer merchantOffer = this.slots.getActiveOffer();
MerchantOffer activeOffer = this.slots.getActiveOffer();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ io.papermc.paper.event.player.PlayerPurchaseEvent event = null;
+ if (merchantOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
+ if (activeOffer != null && player instanceof net.minecraft.server.level.ServerPlayer serverPlayer) {
+ if (this.merchant instanceof net.minecraft.world.entity.npc.AbstractVillager abstractVillager) {
+ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), merchantOffer.asBukkit(), true, true);
+ event = new io.papermc.paper.event.player.PlayerTradeEvent(serverPlayer.getBukkitEntity(), (org.bukkit.entity.AbstractVillager) abstractVillager.getBukkitEntity(), activeOffer.asBukkit(), true, true);
+ } else if (this.merchant instanceof org.bukkit.craftbukkit.inventory.CraftMerchantCustom.MinecraftMerchant) {
+ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), merchantOffer.asBukkit(), false, true);
+ event = new io.papermc.paper.event.player.PlayerPurchaseEvent(serverPlayer.getBukkitEntity(), activeOffer.asBukkit(), false, true);
+ }
+ if (event != null) {
+ if (!event.callEvent()) {
@ -21,17 +21,17 @@
+ event.getPlayer().updateInventory();
+ return;
+ }
+ merchantOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft();
+ activeOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft();
+ }
+ }
+ this.checkTakeAchievements(stack);
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
if (merchantOffer != null) {
ItemStack itemStack = this.slots.getItem(0);
ItemStack itemStack2 = this.slots.getItem(1);
if (merchantOffer.take(itemStack, itemStack2) || merchantOffer.take(itemStack2, itemStack)) {
- this.merchant.notifyTrade(merchantOffer);
+ this.merchant.processTrade(merchantOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
if (activeOffer != null) {
ItemStack item = this.slots.getItem(0);
ItemStack item1 = this.slots.getItem(1);
if (activeOffer.take(item, item1) || activeOffer.take(item1, item)) {
- this.merchant.notifyTrade(activeOffer);
+ this.merchant.processTrade(activeOffer, event); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
player.awardStat(Stats.TRADED_WITH_VILLAGER);
this.slots.setItem(0, itemStack);
this.slots.setItem(1, itemStack2);
this.slots.setItem(0, item);
this.slots.setItem(1, item1);

View file

@ -0,0 +1,27 @@
--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
@@ -12,9 +_,22 @@
public class PlayerEnderChestContainer extends SimpleContainer {
@Nullable
private EnderChestBlockEntity activeChest;
-
- public PlayerEnderChestContainer() {
+ // CraftBukkit start
+ private final Player owner;
+
+ public org.bukkit.inventory.InventoryHolder getBukkitOwner() {
+ return this.owner.getBukkitEntity();
+ }
+
+ @Override
+ public org.bukkit.Location getLocation() {
+ return this.activeChest != null ? org.bukkit.craftbukkit.util.CraftLocation.toBukkit(this.activeChest.getBlockPos(), this.activeChest.getLevel().getWorld()) : null;
+ }
+
+ public PlayerEnderChestContainer(Player owner) {
super(27);
+ this.owner = owner;
+ // CraftBukkit end
}
public void setActiveChest(EnderChestBlockEntity enderChestBlockEntity) {

View file

@ -1,21 +1,9 @@
--- a/net/minecraft/world/inventory/ResultContainer.java
+++ b/net/minecraft/world/inventory/ResultContainer.java
@@ -9,12 +9,64 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeHolder;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.entity.HumanEntity;
+// CraftBukkit end
+
public class ResultContainer implements Container, RecipeCraftingHolder {
private final NonNullList<ItemStack> itemStacks;
@@ -12,6 +_,53 @@
private final NonNullList<ItemStack> itemStacks = NonNullList.withSize(1, ItemStack.EMPTY);
@Nullable
private RecipeHolder<?> recipeUsed;
+ // CraftBukkit start
+ private int maxStack = MAX_STACK;
+
@ -33,10 +21,10 @@
+ }
+
+ // Don't need a transaction; the InventoryCrafting keeps track of it for us
+ public void onOpen(CraftHumanEntity who) {}
+ public void onClose(CraftHumanEntity who) {}
+ public java.util.List<HumanEntity> getViewers() {
+ return new java.util.ArrayList<HumanEntity>();
+ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {}
+ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {}
+ public java.util.List<org.bukkit.entity.HumanEntity> getViewers() {
+ return new java.util.ArrayList<>();
+ }
+
+ @Override
@ -49,7 +37,7 @@
+ }
+
+ @Override
+ public Location getLocation() {
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // CraftBukkit end
@ -57,11 +45,12 @@
+ private @Nullable java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> holderCreator;
+ private @Nullable org.bukkit.inventory.InventoryHolder holder;
+ public ResultContainer(java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> holderCreator) {
+ this();
+ this.holderCreator = holderCreator;
+ }
+ // Paper end - Add missing InventoryHolders
+
public ResultContainer() {
this.itemStacks = NonNullList.withSize(1, ItemStack.EMPTY);
}
+ public ResultContainer() {
+ }
+ // Paper end - Add missing InventoryHolders
@Override
public int getContainerSize() {

View file

@ -0,0 +1,39 @@
--- a/net/minecraft/world/inventory/ShulkerBoxMenu.java
+++ b/net/minecraft/world/inventory/ShulkerBoxMenu.java
@@ -9,6 +_,20 @@
public class ShulkerBoxMenu extends AbstractContainerMenu {
private static final int CONTAINER_SIZE = 27;
private final Container container;
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
+ private Inventory player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventory(this.container), this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public ShulkerBoxMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, new SimpleContainer(27));
@@ -18,6 +_,7 @@
super(MenuType.SHULKER_BOX, containerId);
checkContainerSize(container, 27);
this.container = container;
+ this.player = playerInventory; // CraftBukkit - save player
container.startOpen(playerInventory.player);
int i = 3;
int i1 = 9;
@@ -33,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -0,0 +1,50 @@
--- a/net/minecraft/world/inventory/SmithingMenu.java
+++ b/net/minecraft/world/inventory/SmithingMenu.java
@@ -32,6 +_,9 @@
private final RecipePropertySet templateItemTest;
private final RecipePropertySet additionItemTest;
private final DataSlot hasRecipeError = DataSlot.standalone();
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
+ // CraftBukkit end
public SmithingMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -99,6 +_,7 @@
if (this.level instanceof ServerLevel) {
boolean flag = this.getSlot(0).hasItem() && this.getSlot(1).hasItem() && this.getSlot(2).hasItem() && !this.getSlot(this.getResultSlot()).hasItem();
this.hasRecipeError.set(flag ? 1 : 0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
}
@@ -115,7 +_,9 @@
recipeFor.ifPresentOrElse(recipe -> {
ItemStack itemStack = recipe.value().assemble(smithingRecipeInput, this.level.registryAccess());
this.resultSlots.setRecipeUsed((RecipeHolder<?>)recipe);
- this.resultSlots.setItem(0, itemStack);
+ // CraftBukkit start
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareSmithingEvent(this.getBukkitView(), itemStack);
+ // CraftBukkit end
}, () -> {
this.resultSlots.setRecipeUsed(null);
this.resultSlots.setItem(0, ItemStack.EMPTY);
@@ -137,4 +_,18 @@
public boolean hasRecipeError() {
return this.hasRecipeError.get() > 0;
}
+
+ // CraftBukkit start
+ @Override
+ public org.bukkit.craftbukkit.inventory.CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventorySmithing(
+ this.access.getLocation(), this.inputSlots, this.resultSlots);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -0,0 +1,128 @@
--- a/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/net/minecraft/world/inventory/StonecutterMenu.java
@@ -25,7 +_,7 @@
private static final int USE_ROW_SLOT_START = 29;
private static final int USE_ROW_SLOT_END = 38;
private final ContainerLevelAccess access;
- final DataSlot selectedRecipeIndex = DataSlot.standalone();
+ final DataSlot selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent
private final Level level;
private SelectableRecipe.SingleInputSet<StonecutterRecipe> recipesForInput = SelectableRecipe.SingleInputSet.empty();
private ItemStack input = ItemStack.EMPTY;
@@ -33,15 +_,23 @@
final Slot inputSlot;
final Slot resultSlot;
Runnable slotUpdateListener = () -> {};
- public final Container container = new SimpleContainer(1) {
- @Override
- public void setChanged() {
- super.setChanged();
- StonecutterMenu.this.slotsChanged(this);
- StonecutterMenu.this.slotUpdateListener.run();
+ public final Container container; // Paper - Add missing InventoryHolders - move down
+ final ResultContainer resultContainer; // Paper - Add missing InventoryHolders - move down
+ // CraftBukkit start
+ private org.bukkit.craftbukkit.inventory.view.CraftStonecutterView bukkitEntity = null;
+ private org.bukkit.entity.Player player;
+
+ @Override
+ public org.bukkit.craftbukkit.inventory.view.CraftStonecutterView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
}
- };
- final ResultContainer resultContainer = new ResultContainer();
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter(this.container, this.resultContainer);
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.view.CraftStonecutterView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public StonecutterMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -51,6 +_,23 @@
super(MenuType.STONECUTTER, containerId);
this.access = access;
this.level = playerInventory.player.level();
+ // Paper start
+ this.container = new SimpleContainer(this.createBlockHolder(access), 1) { // Paper - Add missing InventoryHolders
+ @Override
+ public void setChanged() {
+ super.setChanged();
+ StonecutterMenu.this.slotsChanged(this);
+ StonecutterMenu.this.slotUpdateListener.run();
+ }
+ // CraftBukkit start
+ @Override
+ public org.bukkit.Location getLocation() {
+ return access.getLocation();
+ }
+ // CraftBukkit end
+ };
+ this.resultContainer = new ResultContainer(this.createBlockHolder(access)); // Paper - Add missing InventoryHolders
+ // Paper end
this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33));
this.resultSlot = this.addSlot(new Slot(this.resultContainer, 1, 143, 33) {
@Override
@@ -83,6 +_,7 @@
});
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(this.selectedRecipeIndex);
+ this.player = (org.bukkit.entity.Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
public int getSelectedRecipeIndex() {
@@ -103,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.STONECUTTER);
}
@@ -112,8 +_,34 @@
return false;
} else {
if (this.isValidRecipeIndex(id)) {
- this.selectedRecipeIndex.set(id);
- this.setupResultSlot(id);
+ // Paper start - Add PlayerStonecutterRecipeSelectEvent
+ int recipeIndex = id;
+ this.selectedRecipeIndex.set(recipeIndex);
+ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed
+ paperEventBlock: if (this.isValidRecipeIndex(id)) {
+ final Optional<RecipeHolder<StonecutterRecipe>> recipe = this.recipesForInput.entries().get(id).recipe().recipe();
+ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break.
+
+ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((org.bukkit.entity.Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe());
+ if (!event.callEvent()) {
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+
+ net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey());
+ if (!recipe.get().id().location().equals(key)) { // If the recipe did NOT stay the same
+ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) {
+ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().location().equals(key)).isPresent()) {
+ recipeIndex = newRecipeIndex;
+ break;
+ }
+ }
+ }
+ }
+ player.containerMenu.sendAllDataToRemote();
+ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it
+ this.setupResultSlot(recipeIndex);
+ // Paper end - Add PlayerStonecutterRecipeSelectEvent
}
return true;
@@ -131,6 +_,7 @@
this.input = item.copy();
this.setupRecipeList(item);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
private void setupRecipeList(ItemStack stack) {

View file

@ -0,0 +1,71 @@
--- a/net/minecraft/world/inventory/TransientCraftingContainer.java
+++ b/net/minecraft/world/inventory/TransientCraftingContainer.java
@@ -13,6 +_,68 @@
private final int height;
private final AbstractContainerMenu menu;
+ // CraftBukkit start - add fields
+ public List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>();
+ private net.minecraft.world.item.crafting.RecipeHolder<?> currentRecipe;
+ public net.minecraft.world.Container resultInventory;
+ private Player owner;
+ private int maxStack = MAX_STACK;
+
+ public List<ItemStack> getContents() {
+ return this.items;
+ }
+
+ public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {
+ this.transaction.add(who);
+ }
+
+ public org.bukkit.event.inventory.InventoryType getInvType() {
+ return this.items.size() == 4 ? org.bukkit.event.inventory.InventoryType.CRAFTING : org.bukkit.event.inventory.InventoryType.WORKBENCH;
+ }
+
+ public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity who) {
+ this.transaction.remove(who);
+ }
+
+ public List<org.bukkit.entity.HumanEntity> getViewers() {
+ return this.transaction;
+ }
+
+ public org.bukkit.inventory.InventoryHolder getOwner() {
+ return (this.owner == null) ? null : this.owner.getBukkitEntity();
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return this.maxStack;
+ }
+
+ public void setMaxStackSize(int size) {
+ this.maxStack = size;
+ this.resultInventory.setMaxStackSize(size);
+ }
+
+ @Override
+ public org.bukkit.Location getLocation() {
+ return this.menu instanceof CraftingMenu ? ((CraftingMenu) this.menu).access.getLocation() : this.owner.getBukkitEntity().getLocation();
+ }
+
+ @Override
+ public net.minecraft.world.item.crafting.RecipeHolder<?> getCurrentRecipe() {
+ return this.currentRecipe;
+ }
+
+ @Override
+ public void setCurrentRecipe(net.minecraft.world.item.crafting.RecipeHolder<?> currentRecipe) {
+ this.currentRecipe = currentRecipe;
+ }
+
+ public TransientCraftingContainer(AbstractContainerMenu menu, int width, int height, Player player) {
+ this(menu, width, height);
+ this.owner = player;
+ }
+ // CraftBukkit end
+
public TransientCraftingContainer(AbstractContainerMenu menu, int width, int height) {
this(menu, width, height, NonNullList.withSize(width * height, ItemStack.EMPTY));
}

View file

@ -1,310 +0,0 @@
--- a/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -21,6 +21,8 @@
import net.minecraft.ReportedException;
import net.minecraft.core.NonNullList;
import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.Mth;
import net.minecraft.world.Container;
@@ -35,6 +37,18 @@
import net.minecraft.world.level.block.entity.BlockEntity;
import org.slf4j.Logger;
+// CraftBukkit start
+import com.google.common.base.Preconditions;
+import java.util.HashMap;
+import java.util.Map;
+import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.event.Event.Result;
+import org.bukkit.event.inventory.InventoryDragEvent;
+import org.bukkit.event.inventory.InventoryType;
+import org.bukkit.inventory.InventoryView;
+// CraftBukkit end
+
public abstract class AbstractContainerMenu {
private static final Logger LOGGER = LogUtils.getLogger();
@@ -67,6 +81,32 @@
private ContainerSynchronizer synchronizer;
private boolean suppressRemoteUpdates;
+ // CraftBukkit start
+ public boolean checkReachable = true;
+ public abstract InventoryView getBukkitView();
+ public void transferTo(AbstractContainerMenu other, org.bukkit.craftbukkit.entity.CraftHumanEntity player) {
+ InventoryView source = this.getBukkitView(), destination = other.getBukkitView();
+ ((CraftInventory) source.getTopInventory()).getInventory().onClose(player);
+ ((CraftInventory) source.getBottomInventory()).getInventory().onClose(player);
+ ((CraftInventory) destination.getTopInventory()).getInventory().onOpen(player);
+ ((CraftInventory) destination.getBottomInventory()).getInventory().onOpen(player);
+ }
+ private Component title;
+ public final Component getTitle() {
+ // Paper start - return chat component with empty text instead of throwing error
+ // Preconditions.checkState(this.title != null, "Title not set");
+ if (this.title == null){
+ return Component.literal("");
+ }
+ // Paper end - return chat component with empty text instead of throwing error
+ return this.title;
+ }
+ public final void setTitle(Component title) {
+ Preconditions.checkState(this.title == null, "Title already set");
+ this.title = title;
+ }
+ // CraftBukkit end
+
protected AbstractContainerMenu(@Nullable MenuType<?> type, int syncId) {
this.carried = ItemStack.EMPTY;
this.remoteSlots = NonNullList.create();
@@ -188,10 +228,20 @@
if (this.synchronizer != null) {
this.synchronizer.sendInitialData(this, this.remoteSlots, this.remoteCarried, this.remoteDataSlots.toIntArray());
+ this.synchronizer.sendOffHandSlotChange(); // Paper - Sync offhand slot in menus; update player's offhand since the offhand slot is not added to the slots for menus but can be changed by swapping from a menu slot
}
}
+ // CraftBukkit start
+ public void broadcastCarriedItem() {
+ this.remoteCarried = this.getCarried().copy();
+ if (this.synchronizer != null) {
+ this.synchronizer.sendCarriedChange(this, this.remoteCarried);
+ }
+ }
+ // CraftBukkit end
+
public void removeSlotListener(ContainerListener listener) {
this.containerListeners.remove(listener);
}
@@ -281,7 +331,7 @@
while (iterator.hasNext()) {
ContainerListener icrafting = (ContainerListener) iterator.next();
- icrafting.slotChanged(this, slot, itemstack2);
+ icrafting.slotChanged(this, slot, itemstack1, itemstack2); // Paper - Add PlayerInventorySlotChangeEvent
}
}
@@ -410,6 +460,7 @@
this.resetQuickCraft();
}
} else if (this.quickcraftStatus == 1) {
+ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks
slot = (Slot) this.slots.get(slotIndex);
itemstack = this.getCarried();
if (AbstractContainerMenu.canItemQuickReplace(slot, itemstack, true) && slot.mayPlace(itemstack) && (this.quickcraftType == 2 || itemstack.getCount() > this.quickcraftSlots.size()) && this.canDragTo(slot)) {
@@ -417,7 +468,7 @@
}
} else if (this.quickcraftStatus == 2) {
if (!this.quickcraftSlots.isEmpty()) {
- if (this.quickcraftSlots.size() == 1) {
+ if (this.quickcraftSlots.size() == 1) { // Paper - Fix CraftBukkit drag system
k = ((Slot) this.quickcraftSlots.iterator().next()).index;
this.resetQuickCraft();
this.doClick(k, this.quickcraftType, ClickType.PICKUP, player);
@@ -433,6 +484,7 @@
l = this.getCarried().getCount();
Iterator iterator = this.quickcraftSlots.iterator();
+ Map<Integer, ItemStack> draggedSlots = new HashMap<Integer, ItemStack>(); // CraftBukkit - Store slots from drag in map (raw slot id -> new stack)
while (iterator.hasNext()) {
Slot slot1 = (Slot) iterator.next();
ItemStack itemstack2 = this.getCarried();
@@ -443,12 +495,48 @@
int l1 = Math.min(AbstractContainerMenu.getQuickCraftPlaceCount(this.quickcraftSlots, this.quickcraftType, itemstack1) + j1, k1);
l -= l1 - j1;
- slot1.setByPlayer(itemstack1.copyWithCount(l1));
+ // slot1.setByPlayer(itemstack1.copyWithCount(l1));
+ draggedSlots.put(slot1.index, itemstack1.copyWithCount(l1)); // CraftBukkit - Put in map instead of setting
}
}
- itemstack1.setCount(l);
- this.setCarried(itemstack1);
+ // CraftBukkit start - InventoryDragEvent
+ InventoryView view = this.getBukkitView();
+ org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack1);
+ newcursor.setAmount(l);
+ Map<Integer, org.bukkit.inventory.ItemStack> eventmap = new HashMap<Integer, org.bukkit.inventory.ItemStack>();
+ for (Map.Entry<Integer, ItemStack> ditem : draggedSlots.entrySet()) {
+ eventmap.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue()));
+ }
+
+ // It's essential that we set the cursor to the new value here to prevent item duplication if a plugin closes the inventory.
+ ItemStack oldCursor = this.getCarried();
+ this.setCarried(CraftItemStack.asNMSCopy(newcursor));
+
+ InventoryDragEvent event = new InventoryDragEvent(view, (newcursor.getType() != org.bukkit.Material.AIR ? newcursor : null), CraftItemStack.asBukkitCopy(oldCursor), this.quickcraftType == 1, eventmap);
+ player.level().getCraftServer().getPluginManager().callEvent(event);
+
+ // Whether or not a change was made to the inventory that requires an update.
+ boolean needsUpdate = event.getResult() != Result.DEFAULT;
+
+ if (event.getResult() != Result.DENY) {
+ for (Map.Entry<Integer, ItemStack> dslot : draggedSlots.entrySet()) {
+ view.setItem(dslot.getKey(), CraftItemStack.asBukkitCopy(dslot.getValue()));
+ }
+ // The only time the carried item will be set to null is if the inventory is closed by the server.
+ // If the inventory is closed by the server, then the cursor items are dropped. This is why we change the cursor early.
+ if (this.getCarried() != null) {
+ this.setCarried(CraftItemStack.asNMSCopy(event.getCursor()));
+ needsUpdate = true;
+ }
+ } else {
+ this.setCarried(oldCursor);
+ }
+
+ if (needsUpdate && player instanceof ServerPlayer) {
+ this.sendAllDataToRemote();
+ }
+ // CraftBukkit end
}
this.resetQuickCraft();
@@ -466,8 +554,11 @@
if (slotIndex == -999) {
if (!this.getCarried().isEmpty()) {
if (clickaction == ClickAction.PRIMARY) {
- player.drop(this.getCarried(), true);
+ // CraftBukkit start
+ ItemStack carried = this.getCarried();
this.setCarried(ItemStack.EMPTY);
+ player.drop(carried, true);
+ // CraftBukkit start
} else {
player.drop(this.getCarried().split(1), true);
}
@@ -530,11 +621,21 @@
}
slot.setChanged();
+ // CraftBukkit start - Make sure the client has the right slot contents
+ if (player instanceof ServerPlayer && slot.getMaxStackSize() != 64) {
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), slot.index, slot.getItem()));
+ // Updating a crafting inventory makes the client reset the result slot, have to send it again
+ if (this.getBukkitView().getType() == InventoryType.WORKBENCH || this.getBukkitView().getType() == InventoryType.CRAFTING) {
+ ((ServerPlayer) player).connection.send(new ClientboundContainerSetSlotPacket(this.containerId, this.incrementStateId(), 0, this.getSlot(0).getItem()));
+ }
+ }
+ // CraftBukkit end
}
} else {
int j2;
if (actionType == ClickType.SWAP && (button >= 0 && button < 9 || button == 40)) {
+ if (slotIndex < 0) return; // Paper - Add slot sanity checks to container clicks
ItemStack itemstack4 = playerinventory.getItem(button);
slot = (Slot) this.slots.get(slotIndex);
@@ -662,8 +763,9 @@
ItemStack itemstack = this.getCarried();
if (!itemstack.isEmpty()) {
+ this.setCarried(ItemStack.EMPTY); // CraftBukkit - SPIGOT-4556 - from below
AbstractContainerMenu.dropOrPlaceInInventory(player, itemstack);
- this.setCarried(ItemStack.EMPTY);
+ // this.setCarried(ItemStack.EMPTY); // CraftBukkit - moved up
}
}
@@ -729,6 +831,14 @@
public abstract boolean stillValid(Player player);
protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast) {
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ return this.moveItemStackTo(stack, startIndex, endIndex, fromLast, false);
+ }
+ protected boolean moveItemStackTo(ItemStack stack, int startIndex, int endIndex, boolean fromLast, boolean isCheck) {
+ if (isCheck) {
+ stack = stack.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
boolean flag1 = false;
int k = startIndex;
@@ -752,6 +862,11 @@
slot = (Slot) this.slots.get(k);
itemstack1 = slot.getItem();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; clone if only a check
+ if (isCheck) {
+ itemstack1 = itemstack1.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
if (!itemstack1.isEmpty() && ItemStack.isSameItemSameComponents(stack, itemstack1)) {
l = itemstack1.getCount() + stack.getCount();
int i1 = slot.getMaxStackSize(itemstack1);
@@ -759,12 +874,16 @@
if (l <= i1) {
stack.setCount(0);
itemstack1.setCount(l);
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag1 = true;
} else if (itemstack1.getCount() < i1) {
stack.shrink(i1 - itemstack1.getCount());
itemstack1.setCount(i1);
+ if (!isCheck) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag1 = true;
}
}
@@ -795,10 +914,21 @@
slot = (Slot) this.slots.get(k);
itemstack1 = slot.getItem();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (isCheck) {
+ itemstack1 = itemstack1.copy();
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
if (itemstack1.isEmpty() && slot.mayPlace(stack)) {
l = slot.getMaxStackSize(stack);
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ if (isCheck) {
+ stack.shrink(Math.min(stack.getCount(), l));
+ } else {
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
slot.setByPlayer(stack.split(Math.min(stack.getCount(), l)));
slot.setChanged();
+ } // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
flag1 = true;
break;
}
@@ -893,6 +1023,11 @@
}
public ItemStack getCarried() {
+ // CraftBukkit start
+ if (this.carried.isEmpty()) {
+ this.setCarried(ItemStack.EMPTY);
+ }
+ // CraftBukkit end
return this.carried;
}
@@ -947,4 +1082,15 @@
this.stateId = this.stateId + 1 & 32767;
return this.stateId;
}
+
+ // Paper start - Add missing InventoryHolders
+ // The reason this is a supplier, is that the createHolder method uses the bukkit InventoryView#getTopInventory to get the inventory in question
+ // and that can't be obtained safely until the AbstractContainerMenu has been fully constructed. Using a supplier lazily
+ // initializes the InventoryHolder safely.
+ protected final Supplier<org.bukkit.inventory.BlockInventoryHolder> createBlockHolder(final ContainerLevelAccess context) {
+ //noinspection ConstantValue
+ Preconditions.checkArgument(context != null, "context was null");
+ return () -> context.createBlockHolder(this);
+ }
+ // Paper end - Add missing InventoryHolders
}

View file

@ -1,44 +0,0 @@
--- a/net/minecraft/world/inventory/AbstractCraftingMenu.java
+++ b/net/minecraft/world/inventory/AbstractCraftingMenu.java
@@ -13,14 +13,17 @@
private final int width;
private final int height;
- public final CraftingContainer craftSlots;
+ public final TransientCraftingContainer craftSlots; // CraftBukkit
public final ResultContainer resultSlots = new ResultContainer();
- public AbstractCraftingMenu(MenuType<?> type, int syncId, int width, int height) {
- super(type, syncId);
- this.width = width;
- this.height = height;
- this.craftSlots = new TransientCraftingContainer(this, width, height);
+ public AbstractCraftingMenu(MenuType<?> containers, int i, int j, int k, Inventory playerInventory) { // CraftBukkit
+ super(containers, i);
+ this.width = j;
+ this.height = k;
+ // CraftBukkit start
+ this.craftSlots = new TransientCraftingContainer(this, j, k, playerInventory.player); // CraftBukkit - pass player
+ this.craftSlots.resultInventory = this.resultSlots; // CraftBukkit - let InventoryCrafting know about its result slot
+ // CraftBukkit end
}
protected Slot addResultSlot(Player player, int x, int y) {
@@ -38,7 +41,7 @@
@Override
public RecipeBookMenu.PostPlaceAction handlePlacement(boolean craftAll, boolean creative, RecipeHolder<?> recipe, ServerLevel world, Inventory inventory) {
- RecipeHolder<CraftingRecipe> recipeholder1 = recipe;
+ RecipeHolder<CraftingRecipe> recipeholder1 = (RecipeHolder<CraftingRecipe>) recipe; // CraftBukkit - decompile error
this.beginPlacingRecipe();
@@ -65,7 +68,7 @@
}
}, this.width, this.height, list, list, inventory, recipeholder1, craftAll, creative);
} finally {
- this.finishPlacingRecipe(world, recipe);
+ this.finishPlacingRecipe(world, recipeholder1); // CraftBukkit - decompile error
}
return containerrecipebook_a;

View file

@ -1,60 +0,0 @@
--- a/net/minecraft/world/inventory/AbstractFurnaceMenu.java
+++ b/net/minecraft/world/inventory/AbstractFurnaceMenu.java
@@ -17,6 +17,10 @@
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.SingleRecipeInput;
import net.minecraft.world.level.Level;
+import net.minecraft.world.level.block.entity.AbstractFurnaceBlockEntity;
+import org.bukkit.craftbukkit.inventory.CraftInventoryFurnace;
+import org.bukkit.craftbukkit.inventory.view.CraftFurnaceView;
+// CraftBukkit end
public abstract class AbstractFurnaceMenu extends RecipeBookMenu {
@@ -36,6 +40,22 @@
private final RecipePropertySet acceptedInputs;
private final RecipeBookType recipeBookType;
+ // CraftBukkit start
+ private CraftFurnaceView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public CraftFurnaceView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryFurnace inventory = new CraftInventoryFurnace((AbstractFurnaceBlockEntity) this.container);
+ this.bukkitEntity = new CraftFurnaceView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
protected AbstractFurnaceMenu(MenuType<?> type, RecipeType<? extends AbstractCookingRecipe> recipeType, ResourceKey<RecipePropertySet> recipePropertySetKey, RecipeBookType category, int syncId, Inventory platerInventory) {
this(type, recipeType, recipePropertySetKey, category, syncId, platerInventory, new SimpleContainer(3), new SimpleContainerData(4));
}
@@ -53,6 +73,7 @@
this.addSlot(new Slot(inventory, 0, 56, 17));
this.addSlot(new FurnaceFuelSlot(this, inventory, 1, 56, 53));
this.addSlot(new FurnaceResultSlot(platerInventory.player, inventory, 2, 116, 35));
+ this.player = platerInventory; // CraftBukkit - save player
this.addStandardInventorySlots(platerInventory, 8, 84);
this.addDataSlots(propertyDelegate);
}
@@ -71,6 +92,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}
@@ -180,6 +202,6 @@
public boolean recipeMatches(RecipeHolder<AbstractCookingRecipe> entry) {
return ((AbstractCookingRecipe) entry.value()).matches(new SingleRecipeInput(AbstractFurnaceMenu.this.container.getItem(0)), world);
}
- }, 1, 1, List.of(this.getSlot(0)), list, inventory, recipe, craftAll, creative);
+ }, 1, 1, List.of(this.getSlot(0)), list, inventory, (RecipeHolder<AbstractCookingRecipe>) recipe, craftAll, creative); // CraftBukkit - decompile error
}
}

View file

@ -1,109 +0,0 @@
--- a/net/minecraft/world/inventory/BeaconMenu.java
+++ b/net/minecraft/world/inventory/BeaconMenu.java
@@ -8,10 +8,13 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.effect.MobEffect;
+import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
+import org.bukkit.craftbukkit.inventory.view.CraftBeaconView;
+// CraftBukkit end
public class BeaconMenu extends AbstractContainerMenu {
@@ -27,6 +30,10 @@
private final BeaconMenu.PaymentSlot paymentSlot;
private final ContainerLevelAccess access;
private final ContainerData beaconData;
+ // CraftBukkit start
+ private CraftBeaconView bukkitEntity = null;
+ private Inventory player;
+ // CraftBukkit end
public BeaconMenu(int syncId, Container inventory) {
this(syncId, inventory, new SimpleContainerData(3), ContainerLevelAccess.NULL);
@@ -34,7 +41,8 @@
public BeaconMenu(int syncId, Container inventory, ContainerData propertyDelegate, ContainerLevelAccess context) {
super(MenuType.BEACON, syncId);
- this.beacon = new SimpleContainer(this, 1) {
+ this.player = (Inventory) inventory; // CraftBukkit - TODO: check this
+ this.beacon = new SimpleContainer(this.createBlockHolder(context), 1) { // CraftBukkit - decompile error // Paper - Add missing InventoryHolders
@Override
public boolean canPlaceItem(int slot, ItemStack stack) {
return stack.is(ItemTags.BEACON_PAYMENT_ITEMS);
@@ -44,6 +52,12 @@
public int getMaxStackSize() {
return 1;
}
+ // Paper start - Fix inventories returning null Locations
+ @Override
+ public org.bukkit.Location getLocation() {
+ return context.getLocation();
+ }
+ // Paper end - Fix inventories returning null Locations
};
checkContainerDataCount(propertyDelegate, 3);
this.beaconData = propertyDelegate;
@@ -69,6 +83,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.BEACON);
}
@@ -148,12 +163,30 @@
return BeaconMenu.decodeEffect(this.beaconData.get(2));
}
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ private static @Nullable org.bukkit.potion.PotionEffectType convert(Optional<Holder<MobEffect>> optionalEffect) {
+ return optionalEffect.map(org.bukkit.craftbukkit.potion.CraftPotionEffectType::minecraftHolderToBukkit).orElse(null);
+ }
+ // Paper end - Add PlayerChangeBeaconEffectEvent
+
public void updateEffects(Optional<Holder<MobEffect>> primary, Optional<Holder<MobEffect>> secondary) {
+ // Paper start - fix MC-174630 - validate secondary power
+ if (secondary.isPresent() && secondary.get() != net.minecraft.world.effect.MobEffects.REGENERATION && (primary.isPresent() && secondary.get() != primary.get())) {
+ secondary = Optional.empty();
+ }
+ // Paper end
if (this.paymentSlot.hasItem()) {
- this.beaconData.set(1, BeaconMenu.encodeEffect((Holder) primary.orElse((Object) null)));
- this.beaconData.set(2, BeaconMenu.encodeEffect((Holder) secondary.orElse((Object) null)));
+ // Paper start - Add PlayerChangeBeaconEffectEvent
+ io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent event = new io.papermc.paper.event.player.PlayerChangeBeaconEffectEvent((org.bukkit.entity.Player) this.player.player.getBukkitEntity(), convert(primary), convert(secondary), this.access.getLocation().getBlock());
+ if (event.callEvent()) {
+ // Paper end - Add PlayerChangeBeaconEffectEvent
+ this.beaconData.set(1, BeaconMenu.encodeEffect(event.getPrimary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getPrimary())));// CraftBukkit - decompile error
+ this.beaconData.set(2, BeaconMenu.encodeEffect(event.getSecondary() == null ? null : org.bukkit.craftbukkit.potion.CraftPotionEffectType.bukkitToMinecraftHolder(event.getSecondary())));// CraftBukkit - decompile error
+ if (event.willConsumeItem()) { // Paper
this.paymentSlot.remove(1);
+ } // Paper
this.access.execute(Level::blockEntityChanged);
+ } // Paper end - Add PlayerChangeBeaconEffectEvent
}
}
@@ -178,4 +211,17 @@
return 1;
}
}
+
+ // CraftBukkit start
+ @Override
+ public CraftBeaconView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventoryBeacon inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryBeacon(this.beacon);
+ this.bukkitEntity = new CraftBeaconView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,127 +0,0 @@
--- a/net/minecraft/world/inventory/BrewingStandMenu.java
+++ b/net/minecraft/world/inventory/BrewingStandMenu.java
@@ -16,6 +16,10 @@
import net.minecraft.world.item.alchemy.Potion;
import net.minecraft.world.item.alchemy.PotionBrewing;
import net.minecraft.world.item.alchemy.PotionContents;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventoryBrewer;
+import org.bukkit.craftbukkit.inventory.view.CraftBrewingStandView;
+// CraftBukkit end
public class BrewingStandMenu extends AbstractContainerMenu {
@@ -35,29 +39,51 @@
public final ContainerData brewingStandData;
private final Slot ingredientSlot;
+ // CraftBukkit start
+ private CraftBrewingStandView bukkitEntity = null;
+ private Inventory player;
+ // CraftBukkit end
+
public BrewingStandMenu(int syncId, Inventory playerInventory) {
- this(syncId, playerInventory, new SimpleContainer(5), new SimpleContainerData(2));
+ this(syncId, playerInventory, new SimpleContainer(5), new io.papermc.paper.inventory.BrewingSimpleContainerData()); // Paper - Add totalBrewTime
}
public BrewingStandMenu(int syncId, Inventory playerInventory, Container inventory, ContainerData propertyDelegate) {
super(MenuType.BREWING_STAND, syncId);
+ this.player = playerInventory; // CraftBukkit
checkContainerSize(inventory, 5);
- checkContainerDataCount(propertyDelegate, 2);
+ checkContainerDataCount(propertyDelegate, 3); // Paper - Add recipeBrewTime
this.brewingStand = inventory;
this.brewingStandData = propertyDelegate;
PotionBrewing potionbrewer = playerInventory.player.level().potionBrewing();
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51));
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58));
- this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51));
+ // Paper start - custom potion mixes
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 0, 56, 51, potionbrewer));
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 1, 79, 58, potionbrewer));
+ this.addSlot(new BrewingStandMenu.PotionSlot(inventory, 2, 102, 51, potionbrewer));
+ // Paper end - custom potion mixes
this.ingredientSlot = this.addSlot(new BrewingStandMenu.IngredientsSlot(potionbrewer, inventory, 3, 79, 17));
this.addSlot(new BrewingStandMenu.FuelSlot(inventory, 4, 17, 17));
- this.addDataSlots(propertyDelegate);
+ // Paper start - Add recipeBrewTime
+ this.addDataSlots(new SimpleContainerData(2) {
+ @Override
+ public int get(final int index) {
+ if (index == 0) return 400 * propertyDelegate.get(index) / propertyDelegate.get(2);
+ return propertyDelegate.get(index);
+ }
+
+ @Override
+ public void set(final int index, final int value) {
+ propertyDelegate.set(index, value);
+ }
+ });
+ // Paper end - Add recipeBrewTime
this.addStandardInventorySlots(playerInventory, 8, 84);
}
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.brewingStand.stillValid(player);
}
@@ -79,7 +105,7 @@
if (!this.moveItemStackTo(itemstack1, 3, 4, false)) {
return ItemStack.EMPTY;
}
- } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack)) {
+ } else if (BrewingStandMenu.PotionSlot.mayPlaceItem(itemstack, this.player.player.level().potionBrewing())) { // Paper - custom potion mixes
if (!this.moveItemStackTo(itemstack1, 0, 3, false)) {
return ItemStack.EMPTY;
}
@@ -128,13 +154,15 @@
private static class PotionSlot extends Slot {
- public PotionSlot(Container inventory, int index, int x, int y) {
+ private final PotionBrewing potionBrewing; // Paper - custom potion mixes
+ public PotionSlot(Container inventory, int index, int x, int y, PotionBrewing potionBrewing) { // Paper - custom potion mixes
super(inventory, index, x, y);
+ this.potionBrewing = potionBrewing; // Paper - custom potion mixes
}
@Override
public boolean mayPlace(ItemStack stack) {
- return PotionSlot.mayPlaceItem(stack);
+ return PotionSlot.mayPlaceItem(stack, this.potionBrewing); // Paper - custom potion mixes
}
@Override
@@ -153,8 +181,8 @@
super.onTake(player, stack);
}
- public static boolean mayPlaceItem(ItemStack stack) {
- return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE);
+ public static boolean mayPlaceItem(ItemStack stack, PotionBrewing potionBrewing) { // Paper - custom potion mixes
+ return stack.is(Items.POTION) || stack.is(Items.SPLASH_POTION) || stack.is(Items.LINGERING_POTION) || stack.is(Items.GLASS_BOTTLE) || potionBrewing.isCustomInput(stack); // Paper - Custom Potion Mixes
}
@Override
@@ -198,4 +226,17 @@
return BrewingStandMenu.EMPTY_SLOT_FUEL;
}
}
+
+ // CraftBukkit start
+ @Override
+ public CraftBrewingStandView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryBrewer inventory = new CraftInventoryBrewer(this.brewingStand);
+ this.bukkitEntity = new CraftBrewingStandView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,146 +0,0 @@
--- a/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -6,16 +6,36 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.MapItem;
import net.minecraft.world.item.component.MapPostProcessing;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.saveddata.maps.MapItemSavedData;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryCartography;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class CartographyTableMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ private Player player;
+
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryCartography inventory = new CraftInventoryCartography(this.container, this.resultContainer);
+ this.bukkitEntity = new CraftInventoryView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public static final int MAP_SLOT = 0;
public static final int ADDITIONAL_SLOT = 1;
public static final int RESULT_SLOT = 2;
@@ -34,28 +54,42 @@
public CartographyTableMenu(int syncId, Inventory inventory, final ContainerLevelAccess context) {
super(MenuType.CARTOGRAPHY_TABLE, syncId);
- this.container = new SimpleContainer(2) {
+ this.container = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
CartographyTableMenu.this.slotsChanged(this);
super.setChanged();
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
- this.resultContainer = new ResultContainer() {
+ this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
- CartographyTableMenu.this.slotsChanged(this);
+ // CartographyTableMenu.this.slotsChanged(this); // Paper - Add CatographyItemEvent - do not recompute results if the result slot changes - allows to set the result slot via api
super.setChanged();
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
this.access = context;
- this.addSlot(new Slot(this, this.container, 0, 15, 15) {
+ this.addSlot(new Slot(this.container, 0, 15, 15) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.has(DataComponents.MAP_ID);
}
});
- this.addSlot(new Slot(this, this.container, 1, 15, 52) {
+ this.addSlot(new Slot(this.container, 1, 15, 52) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.is(Items.PAPER) || stack.is(Items.MAP) || stack.is(Items.GLASS_PANE);
@@ -68,7 +102,7 @@
}
@Override
- public void onTake(Player player, ItemStack stack) {
+ public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
((Slot) CartographyTableMenu.this.slots.get(0)).remove(1);
((Slot) CartographyTableMenu.this.slots.get(1)).remove(1);
stack.getItem().onCraftedBy(stack, player.level(), player);
@@ -76,7 +110,7 @@
long j = world.getGameTime();
if (CartographyTableMenu.this.lastSoundTime != j) {
- world.playSound((Player) null, blockposition, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.UI_CARTOGRAPHY_TABLE_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
CartographyTableMenu.this.lastSoundTime = j;
}
@@ -85,10 +119,12 @@
}
});
this.addStandardInventorySlots(inventory, 8, 84);
+ this.player = (Player) inventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.CARTOGRAPHY_TABLE);
}
@@ -104,6 +140,7 @@
this.setupResultSlot(itemstack, itemstack1, itemstack2);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
private void setupResultSlot(ItemStack map, ItemStack item, ItemStack oldResult) {
@@ -147,7 +184,7 @@
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot1 = (Slot) this.slots.get(slot);
@@ -199,7 +236,7 @@
}
@Override
- public void removed(Player player) {
+ public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.resultContainer.removeItemNoUpdate(2);
this.access.execute((world, blockposition) -> {

View file

@ -1,64 +0,0 @@
--- a/net/minecraft/world/inventory/ChestMenu.java
+++ b/net/minecraft/world/inventory/ChestMenu.java
@@ -1,16 +1,43 @@
package net.minecraft.world.inventory;
+import net.minecraft.world.CompoundContainer;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
public class ChestMenu extends AbstractContainerMenu {
private final Container container;
private final int containerRows;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventory inventory;
+ if (this.container instanceof Inventory) {
+ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryPlayer((Inventory) this.container);
+ } else if (this.container instanceof CompoundContainer) {
+ inventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) this.container);
+ } else {
+ inventory = new CraftInventory(this.container);
+ }
+
+ this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
private ChestMenu(MenuType<?> type, int syncId, Inventory playerInventory, int rows) {
this(type, syncId, playerInventory, new SimpleContainer(9 * rows), rows);
}
@@ -53,6 +80,9 @@
this.container = inventory;
this.containerRows = rows;
inventory.startOpen(playerInventory.player);
+ // CraftBukkit start - Save player
+ this.player = playerInventory;
+ // CraftBukkit end
boolean flag = true;
this.addChestGrid(inventory, 8, 18);
@@ -72,6 +102,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -1,14 +0,0 @@
--- a/net/minecraft/world/inventory/ContainerListener.java
+++ b/net/minecraft/world/inventory/ContainerListener.java
@@ -5,5 +5,11 @@
public interface ContainerListener {
void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack stack);
+ // Paper start - Add PlayerInventorySlotChangeEvent
+ default void slotChanged(AbstractContainerMenu handler, int slotId, ItemStack oldStack, ItemStack stack) {
+ slotChanged(handler, slotId, stack);
+ }
+ // Paper end - Add PlayerInventorySlotChangeEvent
+
void dataChanged(AbstractContainerMenu handler, int property, int value);
}

View file

@ -1,10 +0,0 @@
--- a/net/minecraft/world/inventory/ContainerSynchronizer.java
+++ b/net/minecraft/world/inventory/ContainerSynchronizer.java
@@ -6,6 +6,7 @@
public interface ContainerSynchronizer {
void sendInitialData(AbstractContainerMenu handler, NonNullList<ItemStack> stacks, ItemStack cursorStack, int[] properties);
+ default void sendOffHandSlotChange() {} // Paper - Sync offhand slot in menus
void sendSlotChange(AbstractContainerMenu handler, int slot, ItemStack stack);
void sendCarriedChange(AbstractContainerMenu handler, ItemStack stack);

View file

@ -1,38 +0,0 @@
--- a/net/minecraft/world/inventory/CrafterMenu.java
+++ b/net/minecraft/world/inventory/CrafterMenu.java
@@ -10,8 +10,27 @@
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.level.block.CrafterBlock;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventoryCrafter;
+import org.bukkit.craftbukkit.inventory.view.CraftCrafterView;
+// CraftBukkit end
+
public class CrafterMenu extends AbstractContainerMenu implements ContainerListener {
+ // CraftBukkit start
+ private CraftCrafterView bukkitEntity = null;
+
+ @Override
+ public CraftCrafterView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryCrafter inventory = new CraftInventoryCrafter(this.container, this.resultContainer);
+ this.bukkitEntity = new CraftCrafterView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
protected static final int SLOT_COUNT = 9;
private static final int INV_SLOT_START = 9;
private static final int INV_SLOT_END = 36;
@@ -106,6 +125,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -1,29 +0,0 @@
--- a/net/minecraft/world/inventory/CraftingContainer.java
+++ b/net/minecraft/world/inventory/CraftingContainer.java
@@ -5,6 +5,10 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.CraftingInput;
+// CraftBukkit start
+import net.minecraft.world.item.crafting.RecipeHolder;
+// CraftBukkit end
+
public interface CraftingContainer extends Container, StackedContentsCompatible {
int getWidth();
@@ -13,6 +17,15 @@
List<ItemStack> getItems();
+ // CraftBukkit start
+ default RecipeHolder<?> getCurrentRecipe() {
+ return null;
+ }
+
+ default void setCurrentRecipe(RecipeHolder<?> recipe) {
+ }
+ // CraftBukkit end
+
default CraftingInput asCraftInput() {
return this.asPositionedCraftInput().input();
}

View file

@ -1,74 +0,0 @@
--- a/net/minecraft/world/inventory/CraftingMenu.java
+++ b/net/minecraft/world/inventory/CraftingMenu.java
@@ -14,7 +14,11 @@
import net.minecraft.world.item.crafting.CraftingRecipe;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.item.crafting.RecipeType;
+import net.minecraft.world.item.crafting.RepairItemRecipe;
import net.minecraft.world.level.block.Blocks;
+import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
public class CraftingMenu extends AbstractCraftingMenu {
@@ -31,13 +35,16 @@
public final ContainerLevelAccess access;
private final Player player;
private boolean placingRecipe;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ // CraftBukkit end
public CraftingMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, ContainerLevelAccess.NULL);
}
public CraftingMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) {
- super(MenuType.CRAFTING, syncId, 3, 3);
+ super(MenuType.CRAFTING, syncId, 3, 3, playerInventory); // CraftBukkit - pass player
this.access = context;
this.player = playerInventory.player;
this.addResultSlot(this.player, 124, 35);
@@ -50,6 +57,7 @@
ServerPlayer entityplayer = (ServerPlayer) player;
ItemStack itemstack = ItemStack.EMPTY;
Optional<RecipeHolder<CraftingRecipe>> optional = world.getServer().getRecipeManager().getRecipeFor(RecipeType.CRAFTING, craftinginput, world, recipe);
+ craftingInventory.setCurrentRecipe(optional.orElse(null)); // CraftBukkit
if (optional.isPresent()) {
RecipeHolder<CraftingRecipe> recipeholder1 = (RecipeHolder) optional.get();
@@ -63,6 +71,7 @@
}
}
}
+ itemstack = org.bukkit.craftbukkit.event.CraftEventFactory.callPreCraftEvent(craftingInventory, resultInventory, itemstack, handler.getBukkitView(), optional.map(RecipeHolder::value).orElse(null) instanceof RepairItemRecipe); // CraftBukkit
resultInventory.setItem(0, itemstack);
handler.setRemoteSlot(0, itemstack);
@@ -103,6 +112,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.CRAFTING_TABLE);
}
@@ -181,4 +191,17 @@
protected Player owner() {
return this.player;
}
+
+ // CraftBukkit start
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftSlots, this.resultSlots);
+ this.bukkitEntity = new CraftInventoryView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,62 +0,0 @@
--- a/net/minecraft/world/inventory/DispenserMenu.java
+++ b/net/minecraft/world/inventory/DispenserMenu.java
@@ -6,6 +6,11 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
+
public class DispenserMenu extends AbstractContainerMenu {
private static final int SLOT_COUNT = 9;
@@ -14,6 +19,10 @@
private static final int USE_ROW_SLOT_START = 36;
private static final int USE_ROW_SLOT_END = 45;
public final Container dispenser;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+ // CraftBukkit end
public DispenserMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, new SimpleContainer(9));
@@ -21,6 +30,10 @@
public DispenserMenu(int syncId, Inventory playerInventory, Container inventory) {
super(MenuType.GENERIC_3x3, syncId);
+ // CraftBukkit start - Save player
+ this.player = playerInventory;
+ // CraftBukkit end
+
checkContainerSize(inventory, 9);
this.dispenser = inventory;
inventory.startOpen(playerInventory.player);
@@ -41,6 +54,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.dispenser.stillValid(player);
}
@@ -82,4 +96,17 @@
super.removed(player);
this.dispenser.stopOpen(player);
}
+
+ // CraftBukkit start
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventory inventory = new CraftInventory(this.dispenser);
+ this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,270 +0,0 @@
--- a/net/minecraft/world/inventory/EnchantmentMenu.java
+++ b/net/minecraft/world/inventory/EnchantmentMenu.java
@@ -21,7 +21,6 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.Enchantment;
@@ -29,6 +28,18 @@
import net.minecraft.world.item.enchantment.EnchantmentInstance;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.EnchantingTableBlock;
+// CraftBukkit start
+import java.util.Map;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.enchantments.CraftEnchantment;
+import org.bukkit.craftbukkit.inventory.CraftInventoryEnchanting;
+import org.bukkit.craftbukkit.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.inventory.view.CraftEnchantmentView;
+import org.bukkit.enchantments.EnchantmentOffer;
+import org.bukkit.event.enchantment.EnchantItemEvent;
+import org.bukkit.event.enchantment.PrepareItemEnchantEvent;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class EnchantmentMenu extends AbstractContainerMenu {
@@ -40,6 +51,10 @@
public final int[] costs;
public final int[] enchantClue;
public final int[] levelClue;
+ // CraftBukkit start
+ private CraftEnchantmentView bukkitEntity = null;
+ private Player player;
+ // CraftBukkit end
public EnchantmentMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, ContainerLevelAccess.NULL);
@@ -47,12 +62,19 @@
public EnchantmentMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) {
super(MenuType.ENCHANTMENT, syncId);
- this.enchantSlots = new SimpleContainer(2) {
+ this.enchantSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
super.setChanged();
EnchantmentMenu.this.slotsChanged(this);
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
this.random = RandomSource.create();
this.enchantmentSeed = DataSlot.standalone();
@@ -60,13 +82,13 @@
this.enchantClue = new int[]{-1, -1, -1};
this.levelClue = new int[]{-1, -1, -1};
this.access = context;
- this.addSlot(new Slot(this, this.enchantSlots, 0, 15, 47) {
+ this.addSlot(new Slot(this.enchantSlots, 0, 15, 47) { // CraftBukkit - decompile error
@Override
public int getMaxStackSize() {
return 1;
}
});
- this.addSlot(new Slot(this, this.enchantSlots, 1, 35, 47) {
+ this.addSlot(new Slot(this.enchantSlots, 1, 35, 47) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.is(Items.LAPIS_LAZULI);
@@ -88,6 +110,9 @@
this.addDataSlot(DataSlot.shared(this.levelClue, 0));
this.addDataSlot(DataSlot.shared(this.levelClue, 1));
this.addDataSlot(DataSlot.shared(this.levelClue, 2));
+ // CraftBukkit start
+ this.player = (Player) playerInventory.player.getBukkitEntity();
+ // CraftBukkit end
}
@Override
@@ -95,7 +120,7 @@
if (inventory == this.enchantSlots) {
ItemStack itemstack = inventory.getItem(0);
- if (!itemstack.isEmpty() && itemstack.isEnchantable()) {
+ if (!itemstack.isEmpty()) { // CraftBukkit - relax condition
this.access.execute((world, blockposition) -> {
IdMap<Holder<Enchantment>> registry = world.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
int i = 0;
@@ -135,6 +160,41 @@
}
}
+ // CraftBukkit start
+ CraftItemStack item = CraftItemStack.asCraftMirror(itemstack);
+ org.bukkit.enchantments.EnchantmentOffer[] offers = new EnchantmentOffer[3];
+ for (j = 0; j < 3; ++j) {
+ org.bukkit.enchantments.Enchantment enchantment = (this.enchantClue[j] >= 0) ? CraftEnchantment.minecraftHolderToBukkit(registry.byId(this.enchantClue[j])) : null;
+ offers[j] = (enchantment != null) ? new EnchantmentOffer(enchantment, this.levelClue[j], this.costs[j]) : null;
+ }
+
+ PrepareItemEnchantEvent event = new PrepareItemEnchantEvent(this.player, this.getBukkitView(), this.access.getLocation().getBlock(), item, offers, i);
+ event.setCancelled(!itemstack.isEnchantable());
+ world.getCraftServer().getPluginManager().callEvent(event);
+
+ if (event.isCancelled()) {
+ for (j = 0; j < 3; ++j) {
+ this.costs[j] = 0;
+ this.enchantClue[j] = -1;
+ this.levelClue[j] = -1;
+ }
+ return;
+ }
+
+ for (j = 0; j < 3; j++) {
+ EnchantmentOffer offer = event.getOffers()[j];
+ if (offer != null) {
+ this.costs[j] = offer.getCost();
+ this.enchantClue[j] = registry.getId(CraftEnchantment.bukkitToMinecraftHolder(offer.getEnchantment()));
+ this.levelClue[j] = offer.getEnchantmentLevel();
+ } else {
+ this.costs[j] = 0;
+ this.enchantClue[j] = -1;
+ this.levelClue[j] = -1;
+ }
+ }
+ // CraftBukkit end
+
this.broadcastChanges();
});
} else {
@@ -149,7 +209,7 @@
}
@Override
- public boolean clickMenuButton(Player player, int id) {
+ public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
if (id >= 0 && id < this.costs.length) {
ItemStack itemstack = this.enchantSlots.getItem(0);
ItemStack itemstack1 = this.enchantSlots.getItem(1);
@@ -159,24 +219,55 @@
return false;
} else if (this.costs[id] > 0 && !itemstack.isEmpty() && (player.experienceLevel >= j && player.experienceLevel >= this.costs[id] || player.getAbilities().instabuild)) {
this.access.execute((world, blockposition) -> {
- ItemStack itemstack2 = itemstack;
+ ItemStack itemstack2 = itemstack; // Paper - diff on change
List<EnchantmentInstance> list = this.getEnchantmentList(world.registryAccess(), itemstack, id, this.costs[id]);
- if (!list.isEmpty()) {
- player.onEnchantmentPerformed(itemstack, j);
- if (itemstack.is(Items.BOOK)) {
- itemstack2 = itemstack.transmuteCopy(Items.ENCHANTED_BOOK);
- this.enchantSlots.setItem(0, itemstack2);
+ // CraftBukkit start
+ IdMap<Holder<Enchantment>> registry = world.registryAccess().lookupOrThrow(Registries.ENCHANTMENT).asHolderIdMap();
+ if (true || !list.isEmpty()) {
+ // entityhuman.onEnchantmentPerformed(itemstack, j); // Moved down
+ Map<org.bukkit.enchantments.Enchantment, Integer> enchants = new java.util.HashMap<org.bukkit.enchantments.Enchantment, Integer>();
+ for (EnchantmentInstance instance : list) {
+ enchants.put(CraftEnchantment.minecraftHolderToBukkit(instance.enchantment), instance.level);
}
+ CraftItemStack item = CraftItemStack.asCraftMirror(itemstack2);
- Iterator iterator = list.iterator();
+ org.bukkit.enchantments.Enchantment hintedEnchantment = CraftEnchantment.minecraftHolderToBukkit(registry.byId(this.enchantClue[id]));
+ int hintedEnchantmentLevel = this.levelClue[id];
+ EnchantItemEvent event = new EnchantItemEvent((Player) player.getBukkitEntity(), this.getBukkitView(), this.access.getLocation().getBlock(), item, this.costs[id], enchants, hintedEnchantment, hintedEnchantmentLevel, id);
+ world.getCraftServer().getPluginManager().callEvent(event);
- while (iterator.hasNext()) {
- EnchantmentInstance weightedrandomenchant = (EnchantmentInstance) iterator.next();
+ int level = event.getExpLevelCost();
+ if (event.isCancelled() || (level > player.experienceLevel && !player.getAbilities().instabuild) || event.getEnchantsToAdd().isEmpty()) {
+ return;
+ }
+ // CraftBukkit end
+ // Paper start
+ itemstack2 = org.bukkit.craftbukkit.inventory.CraftItemStack.getOrCloneOnMutation(item, event.getItem());
+ if (itemstack2 != itemstack) {
+ this.enchantSlots.setItem(0, itemstack2);
+ }
+ if (itemstack2.is(Items.BOOK)) {
+ itemstack2 = itemstack2.transmuteCopy(Items.ENCHANTED_BOOK);
+ this.enchantSlots.setItem(0, itemstack2);
+ }
+ // Paper end
+ // CraftBukkit start
+ for (Map.Entry<org.bukkit.enchantments.Enchantment, Integer> entry : event.getEnchantsToAdd().entrySet()) {
+ Holder<Enchantment> nms = CraftEnchantment.bukkitToMinecraftHolder(entry.getKey());
+ if (nms == null) {
+ continue;
+ }
+
+ EnchantmentInstance weightedrandomenchant = new EnchantmentInstance(nms, entry.getValue());
itemstack2.enchant(weightedrandomenchant.enchantment, weightedrandomenchant.level);
}
+ player.onEnchantmentPerformed(itemstack, j);
+ // CraftBukkit end
+
+ // CraftBukkit - TODO: let plugins change this
itemstack1.consume(j, player);
if (itemstack1.isEmpty()) {
this.enchantSlots.setItem(1, ItemStack.EMPTY);
@@ -190,7 +281,7 @@
this.enchantSlots.setChanged();
this.enchantmentSeed.set(player.getEnchantmentSeed());
this.slotsChanged(this.enchantSlots);
- world.playSound((Player) null, blockposition, SoundEvents.ENCHANTMENT_TABLE_USE, SoundSource.BLOCKS, 1.0F, world.random.nextFloat() * 0.1F + 0.9F);
+ world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.ENCHANTMENT_TABLE_USE, SoundSource.BLOCKS, 1.0F, world.random.nextFloat() * 0.1F + 0.9F);
}
});
@@ -234,7 +325,7 @@
}
@Override
- public void removed(Player player) {
+ public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.access.execute((world, blockposition) -> {
this.clearContainer(player, this.enchantSlots);
@@ -242,12 +333,13 @@
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.ENCHANTING_TABLE);
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot1 = (Slot) this.slots.get(slot);
@@ -293,4 +385,23 @@
return itemstack;
}
+
+ // CraftBukkit start
+ @Override
+ public CraftEnchantmentView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryEnchanting inventory = new CraftInventoryEnchanting(this.enchantSlots);
+ this.bukkitEntity = new CraftEnchantmentView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
+ // Paper start - add enchantment seed update API
+ public void setEnchantmentSeed(int seed) {
+ this.enchantmentSeed.set(seed);
+ }
+ // Paper end - add enchantment seed update API
}

View file

@ -1,11 +0,0 @@
--- a/net/minecraft/world/inventory/FurnaceResultSlot.java
+++ b/net/minecraft/world/inventory/FurnaceResultSlot.java
@@ -51,7 +51,7 @@
Container iinventory = this.container;
if (iinventory instanceof AbstractFurnaceBlockEntity tileentityfurnace) {
- tileentityfurnace.awardUsedRecipesAndPopExperience(entityplayer);
+ tileentityfurnace.awardUsedRecipesAndPopExperience(entityplayer, stack, this.removeCount); // CraftBukkit
}
}

View file

@ -1,141 +0,0 @@
--- a/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -10,7 +10,6 @@
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.ExperienceOrb;
import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.item.enchantment.Enchantment;
@@ -19,9 +18,30 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryGrindstone;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class GrindstoneMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ private Player player;
+
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryGrindstone inventory = new CraftInventoryGrindstone(this.repairSlots, this.resultSlots);
+ this.bukkitEntity = new CraftInventoryView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
public static final int MAX_NAME_LENGTH = 35;
public static final int INPUT_SLOT = 0;
public static final int ADDITIONAL_SLOT = 1;
@@ -40,22 +60,29 @@
public GrindstoneMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) {
super(MenuType.GRINDSTONE, syncId);
- this.resultSlots = new ResultContainer();
- this.repairSlots = new SimpleContainer(2) {
+ this.resultSlots = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders
+ this.repairSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
super.setChanged();
GrindstoneMenu.this.slotsChanged(this);
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
this.access = context;
- this.addSlot(new Slot(this, this.repairSlots, 0, 49, 19) {
+ this.addSlot(new Slot(this.repairSlots, 0, 49, 19) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.isDamageableItem() || EnchantmentHelper.hasAnyEnchantments(stack);
}
});
- this.addSlot(new Slot(this, this.repairSlots, 1, 49, 40) {
+ this.addSlot(new Slot(this.repairSlots, 1, 49, 40) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.isDamageableItem() || EnchantmentHelper.hasAnyEnchantments(stack);
@@ -68,10 +95,14 @@
}
@Override
- public void onTake(Player player, ItemStack stack) {
+ public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
context.execute((world, blockposition) -> {
if (world instanceof ServerLevel) {
- ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), this.getExperienceAmount(world));
+ // Paper start - Fire BlockExpEvent on grindstone use
+ org.bukkit.event.block.BlockExpEvent event = new org.bukkit.event.block.BlockExpEvent(org.bukkit.craftbukkit.block.CraftBlock.at(world, blockposition), this.getExperienceAmount(world));
+ event.callEvent();
+ ExperienceOrb.award((ServerLevel) world, Vec3.atCenterOf(blockposition), event.getExpToDrop(), org.bukkit.entity.ExperienceOrb.SpawnReason.GRINDSTONE, player);
+ // Paper end - Fire BlockExpEvent on grindstone use
}
world.levelEvent(1042, blockposition, 0);
@@ -113,6 +144,7 @@
}
});
this.addStandardInventorySlots(playerInventory, 8, 84);
+ this.player = (Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
@@ -120,12 +152,14 @@
super.slotsChanged(inventory);
if (inventory == this.repairSlots) {
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
}
private void createResult() {
- this.resultSlots.setItem(0, this.computeResult(this.repairSlots.getItem(0), this.repairSlots.getItem(1)));
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareGrindstoneEvent(this.getBukkitView(), this.computeResult(this.repairSlots.getItem(0), this.repairSlots.getItem(1))); // CraftBukkit
+ this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686: Always send completed inventory to stay in sync with client
this.broadcastChanges();
}
@@ -218,7 +252,7 @@
}
@Override
- public void removed(Player player) {
+ public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.access.execute((world, blockposition) -> {
this.clearContainer(player, this.repairSlots);
@@ -226,12 +260,13 @@
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.GRINDSTONE);
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot1 = (Slot) this.slots.get(slot);

View file

@ -1,51 +0,0 @@
--- a/net/minecraft/world/inventory/HopperMenu.java
+++ b/net/minecraft/world/inventory/HopperMenu.java
@@ -6,11 +6,32 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
+
public class HopperMenu extends AbstractContainerMenu {
public static final int CONTAINER_SIZE = 5;
private final Container hopper;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventory inventory = new CraftInventory(this.hopper);
+ this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
public HopperMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, new SimpleContainer(5));
}
@@ -18,6 +39,7 @@
public HopperMenu(int syncId, Inventory playerInventory, Container inventory) {
super(MenuType.HOPPER, syncId);
this.hopper = inventory;
+ this.player = playerInventory; // CraftBukkit - save player
checkContainerSize(inventory, 5);
inventory.startOpen(playerInventory.player);
@@ -30,6 +52,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.hopper.stillValid(player);
}

View file

@ -1,53 +0,0 @@
--- a/net/minecraft/world/inventory/HorseInventoryMenu.java
+++ b/net/minecraft/world/inventory/HorseInventoryMenu.java
@@ -11,6 +11,11 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+import org.bukkit.inventory.InventoryView;
+// CraftBukkit end
+
public class HorseInventoryMenu extends AbstractContainerMenu {
static final ResourceLocation SADDLE_SLOT_SPRITE = ResourceLocation.withDefaultNamespace("container/slot/saddle");
@@ -22,13 +27,28 @@
public static final int SLOT_BODY_ARMOR = 1;
private static final int SLOT_HORSE_INVENTORY_START = 2;
+ // CraftBukkit start
+ org.bukkit.craftbukkit.inventory.CraftInventoryView bukkitEntity;
+ Inventory player;
+
+ @Override
+ public InventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ return this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), this.horseContainer.getOwner().getInventory(), this);
+ }
+
public HorseInventoryMenu(int syncId, Inventory playerInventory, Container inventory, final AbstractHorse entity, int slotColumnCount) {
super((MenuType) null, syncId);
+ this.player = playerInventory;
+ // CraftBukkit end
this.horseContainer = inventory;
this.armorContainer = entity.getBodyArmorAccess();
this.horse = entity;
inventory.startOpen(playerInventory.player);
- this.addSlot(new Slot(this, inventory, 0, 8, 18) {
+ this.addSlot(new Slot(inventory, 0, 8, 18) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.is(Items.SADDLE) && !this.hasItem() && entity.isSaddleable();
@@ -46,7 +66,7 @@
});
ResourceLocation minecraftkey = entity instanceof Llama ? HorseInventoryMenu.LLAMA_ARMOR_SLOT_SPRITE : HorseInventoryMenu.ARMOR_SLOT_SPRITE;
- this.addSlot(new ArmorSlot(this, this.armorContainer, entity, EquipmentSlot.BODY, 0, 8, 36, minecraftkey) {
+ this.addSlot(new ArmorSlot(this.armorContainer, entity, EquipmentSlot.BODY, 0, 8, 36, minecraftkey) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return entity.isEquippableInSlot(stack, EquipmentSlot.BODY);

View file

@ -1,64 +0,0 @@
--- a/net/minecraft/world/inventory/InventoryMenu.java
+++ b/net/minecraft/world/inventory/InventoryMenu.java
@@ -2,6 +2,7 @@
import java.util.List;
import java.util.Map;
+import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.Container;
@@ -11,6 +12,9 @@
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeHolder;
import net.minecraft.world.level.Level;
+import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
public class InventoryMenu extends AbstractCraftingMenu {
@@ -38,9 +42,15 @@
private static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
public final boolean active;
private final Player owner;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity = null;
+ // CraftBukkit end
public InventoryMenu(Inventory inventory, boolean onServer, final Player owner) {
- super((MenuType) null, 0, 2, 2);
+ // CraftBukkit start
+ super((MenuType) null, 0, 2, 2, inventory); // CraftBukkit - save player
+ this.setTitle(Component.translatable("container.crafting")); // SPIGOT-4722: Allocate title for player inventory
+ // CraftBukkit end
this.active = onServer;
this.owner = owner;
this.addResultSlot(owner, 154, 28);
@@ -54,7 +64,7 @@
}
this.addStandardInventorySlots(inventory, 8, 84);
- this.addSlot(new Slot(this, inventory, 40, 77, 62) {
+ this.addSlot(new Slot(inventory, 40, 77, 62) { // CraftBukkit - decompile error
@Override
public void setByPlayer(ItemStack stack, ItemStack previousStack) {
owner.onEquipItem(EquipmentSlot.OFFHAND, previousStack, stack);
@@ -190,4 +200,17 @@
protected Player owner() {
return this.owner;
}
+
+ // CraftBukkit start
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftSlots, this.resultSlots);
+ this.bukkitEntity = new CraftInventoryView(this.owner.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,143 +0,0 @@
--- a/net/minecraft/world/inventory/LecternMenu.java
+++ b/net/minecraft/world/inventory/LecternMenu.java
@@ -2,11 +2,33 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
-import net.minecraft.world.entity.player.Player;
+import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.item.ItemStack;
+import net.minecraft.world.level.block.entity.LecternBlockEntity.LecternInventory;
+import org.bukkit.Bukkit;
+import org.bukkit.craftbukkit.inventory.CraftInventoryLectern;
+import org.bukkit.craftbukkit.inventory.view.CraftLecternView;
+import org.bukkit.entity.Player;
+import org.bukkit.event.player.PlayerTakeLecternBookEvent;
+// CraftBukkit end
public class LecternMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private CraftLecternView bukkitEntity = null;
+ private Player player;
+
+ @Override
+ public CraftLecternView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryLectern inventory = new CraftInventoryLectern(this.lectern);
+ this.bukkitEntity = new CraftLecternView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
private static final int DATA_COUNT = 1;
private static final int SLOT_COUNT = 1;
public static final int BUTTON_PREV_PAGE = 1;
@@ -16,29 +38,33 @@
private final Container lectern;
private final ContainerData lecternData;
- public LecternMenu(int syncId) {
- this(syncId, new SimpleContainer(1), new SimpleContainerData(1));
+ // CraftBukkit start - add player
+ public LecternMenu(int i, Inventory playerinventory) {
+ this(i, new SimpleContainer(1), new SimpleContainerData(1), playerinventory);
}
- public LecternMenu(int syncId, Container inventory, ContainerData propertyDelegate) {
- super(MenuType.LECTERN, syncId);
- checkContainerSize(inventory, 1);
- checkContainerDataCount(propertyDelegate, 1);
- this.lectern = inventory;
- this.lecternData = propertyDelegate;
- this.addSlot(new Slot(inventory, 0, 0, 0) {
+ public LecternMenu(int i, Container iinventory, ContainerData icontainerproperties, Inventory playerinventory) {
+ // CraftBukkit end
+ super(MenuType.LECTERN, i);
+ checkContainerSize(iinventory, 1);
+ checkContainerDataCount(icontainerproperties, 1);
+ this.lectern = iinventory;
+ this.lecternData = icontainerproperties;
+ this.addSlot(new Slot(iinventory, 0, 0, 0) {
@Override
public void setChanged() {
super.setChanged();
LecternMenu.this.slotsChanged(this.container);
}
});
- this.addDataSlots(propertyDelegate);
+ this.addDataSlots(icontainerproperties);
+ this.player = (Player) playerinventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
- public boolean clickMenuButton(Player player, int id) {
+ public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
int j;
+ io.papermc.paper.event.player.PlayerLecternPageChangeEvent playerLecternPageChangeEvent; CraftInventoryLectern bukkitView; // Paper - Add PlayerLecternPageChangeEvent
if (id >= 100) {
j = id - 100;
@@ -48,17 +74,38 @@
switch (id) {
case 1:
j = this.lecternData.get(0);
- this.setData(0, j - 1);
+ // Paper start - Add PlayerLecternPageChangeEvent
+ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory();
+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.LEFT, j, j - 1);
+ if (!playerLecternPageChangeEvent.callEvent()) {
+ return false;
+ }
+ this.setData(0, playerLecternPageChangeEvent.getNewPage());
+ // Paper end - Add PlayerLecternPageChangeEvent
return true;
case 2:
j = this.lecternData.get(0);
- this.setData(0, j + 1);
+ // Paper start - Add PlayerLecternPageChangeEvent
+ bukkitView = (CraftInventoryLectern) getBukkitView().getTopInventory();
+ playerLecternPageChangeEvent = new io.papermc.paper.event.player.PlayerLecternPageChangeEvent((org.bukkit.entity.Player) player.getBukkitEntity(), bukkitView.getHolder(), bukkitView.getBook(), io.papermc.paper.event.player.PlayerLecternPageChangeEvent.PageChangeDirection.RIGHT, j, j + 1);
+ if (!playerLecternPageChangeEvent.callEvent()) {
+ return false;
+ }
+ this.setData(0, playerLecternPageChangeEvent.getNewPage());
+ // Paper end - Add PlayerLecternPageChangeEvent
return true;
case 3:
if (!player.mayBuild()) {
return false;
}
+ // CraftBukkit start - Event for taking the book
+ PlayerTakeLecternBookEvent event = new PlayerTakeLecternBookEvent(this.player, ((CraftInventoryLectern) this.getBukkitView().getTopInventory()).getHolder());
+ Bukkit.getServer().getPluginManager().callEvent(event);
+ if (event.isCancelled()) {
+ return false;
+ }
+ // CraftBukkit end
ItemStack itemstack = this.lectern.removeItemNoUpdate(0);
this.lectern.setChanged();
@@ -74,7 +121,7 @@
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
return ItemStack.EMPTY;
}
@@ -85,7 +132,9 @@
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (this.lectern instanceof LecternInventory && !((LecternInventory) this.lectern).getLectern().hasBook()) return false; // CraftBukkit
+ if (!this.checkReachable) return true; // CraftBukkit
return this.lectern.stillValid(player);
}

View file

@ -1,203 +0,0 @@
--- a/net/minecraft/world/inventory/LoomMenu.java
+++ b/net/minecraft/world/inventory/LoomMenu.java
@@ -12,7 +12,6 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.BannerItem;
import net.minecraft.world.item.BannerPatternItem;
import net.minecraft.world.item.DyeColor;
@@ -22,9 +21,30 @@
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.entity.BannerPattern;
import net.minecraft.world.level.block.entity.BannerPatternLayers;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryLoom;
+import org.bukkit.craftbukkit.inventory.view.CraftLoomView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
public class LoomMenu extends AbstractContainerMenu {
+ // CraftBukkit start
+ private CraftLoomView bukkitEntity = null;
+ private Player player;
+
+ @Override
+ public CraftLoomView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryLoom inventory = new CraftInventoryLoom(this.inputContainer, this.outputContainer);
+ this.bukkitEntity = new CraftLoomView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
private static final int PATTERN_NOT_SET = -1;
private static final int INV_SLOT_START = 4;
private static final int INV_SLOT_END = 31;
@@ -53,35 +73,49 @@
this.selectablePatterns = List.of();
this.slotUpdateListener = () -> {
};
- this.inputContainer = new SimpleContainer(3) {
+ this.inputContainer = new SimpleContainer(this.createBlockHolder(context), 3) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
super.setChanged();
LoomMenu.this.slotsChanged(this);
LoomMenu.this.slotUpdateListener.run();
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
- this.outputContainer = new SimpleContainer(1) {
+ this.outputContainer = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
super.setChanged();
LoomMenu.this.slotUpdateListener.run();
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
this.access = context;
- this.bannerSlot = this.addSlot(new Slot(this, this.inputContainer, 0, 13, 26) {
+ this.bannerSlot = this.addSlot(new Slot(this.inputContainer, 0, 13, 26) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.getItem() instanceof BannerItem;
}
});
- this.dyeSlot = this.addSlot(new Slot(this, this.inputContainer, 1, 33, 26) {
+ this.dyeSlot = this.addSlot(new Slot(this.inputContainer, 1, 33, 26) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.getItem() instanceof DyeItem;
}
});
- this.patternSlot = this.addSlot(new Slot(this, this.inputContainer, 2, 23, 45) {
+ this.patternSlot = this.addSlot(new Slot(this.inputContainer, 2, 23, 45) { // CraftBukkit - decompile error
@Override
public boolean mayPlace(ItemStack stack) {
return stack.getItem() instanceof BannerPatternItem;
@@ -94,7 +128,7 @@
}
@Override
- public void onTake(Player player, ItemStack stack) {
+ public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
LoomMenu.this.bannerSlot.remove(1);
LoomMenu.this.dyeSlot.remove(1);
if (!LoomMenu.this.bannerSlot.hasItem() || !LoomMenu.this.dyeSlot.hasItem()) {
@@ -105,7 +139,7 @@
long j = world.getGameTime();
if (LoomMenu.this.lastSoundTime != j) {
- world.playSound((Player) null, blockposition, SoundEvents.UI_LOOM_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.UI_LOOM_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
LoomMenu.this.lastSoundTime = j;
}
@@ -116,18 +150,44 @@
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(this.selectedBannerPatternIndex);
this.patternGetter = playerInventory.player.registryAccess().lookupOrThrow(Registries.BANNER_PATTERN);
+ this.player = (Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.LOOM);
}
@Override
- public boolean clickMenuButton(Player player, int id) {
+ public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
if (id >= 0 && id < this.selectablePatterns.size()) {
- this.selectedBannerPatternIndex.set(id);
- this.setupResultSlot((Holder) this.selectablePatterns.get(id));
+ // Paper start - Add PlayerLoomPatternSelectEvent
+ int selectablePatternIndex = id;
+ io.papermc.paper.event.player.PlayerLoomPatternSelectEvent event = new io.papermc.paper.event.player.PlayerLoomPatternSelectEvent((Player) player.getBukkitEntity(), ((CraftInventoryLoom) getBukkitView().getTopInventory()), org.bukkit.craftbukkit.block.banner.CraftPatternType.minecraftHolderToBukkit(this.selectablePatterns.get(selectablePatternIndex)));
+ if (!event.callEvent()) {
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+ final Holder<BannerPattern> eventPattern = org.bukkit.craftbukkit.block.banner.CraftPatternType.bukkitToMinecraftHolder(event.getPatternType());
+ Holder<BannerPattern> selectedPattern = null;
+ for (int i = 0; i < this.selectablePatterns.size(); i++) {
+ final Holder<BannerPattern> holder = this.selectablePatterns.get(i);
+ if (eventPattern.equals(holder)) {
+ selectablePatternIndex = i;
+ selectedPattern = holder;
+ break;
+ }
+ }
+ if (selectedPattern == null) {
+ selectedPattern = eventPattern;
+ selectablePatternIndex = -1;
+ }
+
+ player.containerMenu.sendAllDataToRemote();
+ this.selectedBannerPatternIndex.set(selectablePatternIndex);
+ this.setupResultSlot(java.util.Objects.requireNonNull(selectedPattern, "selectedPattern was null, this is unexpected"));
+ // Paper end - Add PlayerLoomPatternSelectEvent
return true;
} else {
return false;
@@ -201,7 +261,8 @@
this.resultSlot.set(ItemStack.EMPTY);
}
- this.broadcastChanges();
+ // this.broadcastChanges(); // Paper - Add PrepareResultEvent; done below
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, 3); // Paper - Add PrepareResultEvent
} else {
this.resultSlot.set(ItemStack.EMPTY);
this.selectablePatterns = List.of();
@@ -222,7 +283,7 @@
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot1 = (Slot) this.slots.get(slot);
@@ -277,7 +338,7 @@
}
@Override
- public void removed(Player player) {
+ public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.access.execute((world, blockposition) -> {
this.clearContainer(player, this.inputContainer);
@@ -294,6 +355,11 @@
DyeColor enumcolor = ((DyeItem) itemstack1.getItem()).getDyeColor();
itemstack2.update(DataComponents.BANNER_PATTERNS, BannerPatternLayers.EMPTY, (bannerpatternlayers) -> {
+ // CraftBukkit start
+ if (bannerpatternlayers.layers().size() > 20) {
+ bannerpatternlayers = new BannerPatternLayers(List.copyOf(bannerpatternlayers.layers().subList(0, 20)));
+ }
+ // CraftBukkit end
return (new BannerPatternLayers.Builder()).addAll(bannerpatternlayers).add(pattern, enumcolor).build();
});
}

View file

@ -1,11 +0,0 @@
--- a/net/minecraft/world/inventory/MenuType.java
+++ b/net/minecraft/world/inventory/MenuType.java
@@ -28,7 +28,7 @@
public static final MenuType<GrindstoneMenu> GRINDSTONE = MenuType.register("grindstone", GrindstoneMenu::new);
public static final MenuType<HopperMenu> HOPPER = MenuType.register("hopper", HopperMenu::new);
public static final MenuType<LecternMenu> LECTERN = MenuType.register("lectern", (i, playerinventory) -> {
- return new LecternMenu(i);
+ return new LecternMenu(i, playerinventory); // CraftBukkit
});
public static final MenuType<LoomMenu> LOOM = MenuType.register("loom", LoomMenu::new);
public static final MenuType<MerchantMenu> MERCHANT = MenuType.register("merchant", MerchantMenu::new);

View file

@ -1,70 +0,0 @@
--- a/net/minecraft/world/inventory/MerchantContainer.java
+++ b/net/minecraft/world/inventory/MerchantContainer.java
@@ -5,11 +5,20 @@
import net.minecraft.core.NonNullList;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
+import net.minecraft.world.entity.npc.AbstractVillager;
+import net.minecraft.world.entity.npc.Villager;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.trading.Merchant;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.item.trading.MerchantOffers;
+// CraftBukkit start
+import java.util.List;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.entity.CraftAbstractVillager;
+import org.bukkit.entity.HumanEntity;
+// CraftBukkit end
public class MerchantContainer implements Container {
@@ -20,6 +29,46 @@
public int selectionHint;
private int futureXp;
+ // CraftBukkit start - add fields and methods
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+ private int maxStack = MAX_STACK;
+
+ public List<ItemStack> getContents() {
+ return this.itemStacks;
+ }
+
+ public void onOpen(CraftHumanEntity who) {
+ this.transaction.add(who);
+ }
+
+ public void onClose(CraftHumanEntity who) {
+ this.transaction.remove(who);
+ this.merchant.setTradingPlayer((Player) null); // SPIGOT-4860
+ }
+
+ public List<HumanEntity> getViewers() {
+ return this.transaction;
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return this.maxStack;
+ }
+
+ public void setMaxStackSize(int i) {
+ this.maxStack = i;
+ }
+
+ public org.bukkit.inventory.InventoryHolder getOwner() {
+ return (this.merchant instanceof AbstractVillager) ? (CraftAbstractVillager) ((AbstractVillager) this.merchant).getBukkitEntity() : null;
+ }
+
+ @Override
+ public Location getLocation() {
+ return (this.merchant instanceof AbstractVillager) ? ((AbstractVillager) this.merchant).getBukkitEntity().getLocation() : null; // Paper - Fix inventories returning null Locations
+ }
+ // CraftBukkit end
+
public MerchantContainer(Merchant merchant) {
this.itemStacks = NonNullList.withSize(3, ItemStack.EMPTY);
this.merchant = merchant;

View file

@ -1,92 +0,0 @@
--- a/net/minecraft/world/inventory/MerchantMenu.java
+++ b/net/minecraft/world/inventory/MerchantMenu.java
@@ -12,6 +12,7 @@
import net.minecraft.world.item.trading.Merchant;
import net.minecraft.world.item.trading.MerchantOffer;
import net.minecraft.world.item.trading.MerchantOffers;
+import org.bukkit.craftbukkit.inventory.view.CraftMerchantView; // CraftBukkit
public class MerchantMenu extends AbstractContainerMenu {
@@ -32,6 +33,19 @@
private boolean showProgressBar;
private boolean canRestock;
+ // CraftBukkit start
+ private CraftMerchantView bukkitEntity = null;
+ private Inventory player;
+
+ @Override
+ public CraftMerchantView getBukkitView() {
+ if (this.bukkitEntity == null) {
+ this.bukkitEntity = new CraftMerchantView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventoryMerchant(this.trader, this.tradeContainer), this, this.trader);
+ }
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
public MerchantMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, new ClientSideMerchant(playerInventory.player));
}
@@ -43,6 +57,7 @@
this.addSlot(new Slot(this.tradeContainer, 0, 136, 37));
this.addSlot(new Slot(this.tradeContainer, 1, 162, 37));
this.addSlot(new MerchantResultSlot(playerInventory.player, merchant, this.tradeContainer, 2, 220, 37));
+ this.player = playerInventory; // CraftBukkit - save player
this.addStandardInventorySlots(playerInventory, 108, 84);
}
@@ -108,12 +123,12 @@
itemstack = itemstack1.copy();
if (slot == 2) {
- if (!this.moveItemStackTo(itemstack1, 3, 39, true)) {
+ if (!this.moveItemStackTo(itemstack1, 3, 39, true, true)) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent
return ItemStack.EMPTY;
}
- slot1.onQuickCraft(itemstack1, itemstack);
- this.playTradeSound();
+ // slot1.onQuickCraft(itemstack1, itemstack); // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved to after the non-check moveItemStackTo call
+ // this.playTradeSound();
} else if (slot != 0 && slot != 1) {
if (slot >= 3 && slot < 30) {
if (!this.moveItemStackTo(itemstack1, 30, 39, false)) {
@@ -126,6 +141,7 @@
return ItemStack.EMPTY;
}
+ if (slot != 2) { // Paper - Add PlayerTradeEvent and PlayerPurchaseEvent; moved down for slot 2
if (itemstack1.isEmpty()) {
slot1.setByPlayer(ItemStack.EMPTY);
} else {
@@ -137,13 +153,28 @@
}
slot1.onTake(player, itemstack1);
+ } // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent; handle slot 2
+ if (slot == 2) { // is merchant result slot
+ slot1.onTake(player, itemstack1);
+ if (itemstack1.isEmpty()) {
+ slot1.set(ItemStack.EMPTY);
+ return ItemStack.EMPTY;
+ }
+
+ this.moveItemStackTo(itemstack1, 3, 39, true, false); // This should always succeed because it's checked above
+
+ slot1.onQuickCraft(itemstack1, itemstack);
+ this.playTradeSound();
+ slot1.set(ItemStack.EMPTY); // itemstack1 should ALWAYS be empty
+ }
+ // Paper end - Add PlayerTradeEvent and PlayerPurchaseEvent
}
return itemstack;
}
private void playTradeSound() {
- if (!this.trader.isClientSide()) {
+ if (!this.trader.isClientSide() && this.trader instanceof Entity) { // CraftBukkit - SPIGOT-5035
Entity entity = (Entity) this.trader;
entity.level().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.trader.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false);

View file

@ -1,36 +0,0 @@
--- a/net/minecraft/world/inventory/PlayerEnderChestContainer.java
+++ b/net/minecraft/world/inventory/PlayerEnderChestContainer.java
@@ -8,14 +8,32 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.entity.EnderChestBlockEntity;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.util.CraftLocation;
+import org.bukkit.inventory.InventoryHolder;
+// CraftBukkit end
public class PlayerEnderChestContainer extends SimpleContainer {
@Nullable
private EnderChestBlockEntity activeChest;
+ // CraftBukkit start
+ private final Player owner;
- public PlayerEnderChestContainer() {
+ public InventoryHolder getBukkitOwner() {
+ return this.owner.getBukkitEntity();
+ }
+
+ @Override
+ public Location getLocation() {
+ return this.activeChest != null ? CraftLocation.toBukkit(this.activeChest.getBlockPos(), this.activeChest.getLevel().getWorld()) : null;
+ }
+
+ public PlayerEnderChestContainer(Player owner) {
super(27);
+ this.owner = owner;
+ // CraftBukkit end
}
public void setActiveChest(EnderChestBlockEntity blockEntity) {

View file

@ -1,49 +0,0 @@
--- a/net/minecraft/world/inventory/ShulkerBoxMenu.java
+++ b/net/minecraft/world/inventory/ShulkerBoxMenu.java
@@ -6,11 +6,30 @@
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import org.bukkit.craftbukkit.inventory.CraftInventory;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
+
public class ShulkerBoxMenu extends AbstractContainerMenu {
private static final int CONTAINER_SIZE = 27;
private final Container container;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity;
+ private Inventory player;
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), new CraftInventory(this.container), this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
public ShulkerBoxMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, new SimpleContainer(27));
}
@@ -19,6 +38,7 @@
super(MenuType.SHULKER_BOX, syncId);
checkContainerSize(inventory, 27);
this.container = inventory;
+ this.player = playerInventory; // CraftBukkit - save player
inventory.startOpen(playerInventory.player);
boolean flag = true;
boolean flag1 = true;
@@ -34,6 +54,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return this.container.stillValid(player);
}

View file

@ -1,66 +0,0 @@
--- a/net/minecraft/world/inventory/SmithingMenu.java
+++ b/net/minecraft/world/inventory/SmithingMenu.java
@@ -17,6 +17,7 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView; // CraftBukkit
public class SmithingMenu extends ItemCombinerMenu {
@@ -34,6 +35,9 @@
private final RecipePropertySet templateItemTest;
private final RecipePropertySet additionItemTest;
private final DataSlot hasRecipeError;
+ // CraftBukkit start
+ private CraftInventoryView bukkitEntity;
+ // CraftBukkit end
public SmithingMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, ContainerLevelAccess.NULL);
@@ -111,13 +115,14 @@
this.hasRecipeError.set(flag ? 1 : 0);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
@Override
public void createResult() {
SmithingRecipeInput smithingrecipeinput = this.createRecipeInput();
Level world = this.level;
- Optional optional;
+ Optional<RecipeHolder<SmithingRecipe>> optional; // CraftBukkit - decompile error
if (world instanceof ServerLevel worldserver) {
optional = worldserver.recipeAccess().getRecipeFor(RecipeType.SMITHING, smithingrecipeinput, worldserver);
@@ -129,7 +134,9 @@
ItemStack itemstack = ((SmithingRecipe) recipeholder.value()).assemble(smithingrecipeinput, this.level.registryAccess());
this.resultSlots.setRecipeUsed(recipeholder);
- this.resultSlots.setItem(0, itemstack);
+ // CraftBukkit start
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareSmithingEvent(this.getBukkitView(), itemstack);
+ // CraftBukkit end
}, () -> {
this.resultSlots.setRecipeUsed((RecipeHolder) null);
this.resultSlots.setItem(0, ItemStack.EMPTY);
@@ -149,4 +156,18 @@
public boolean hasRecipeError() {
return this.hasRecipeError.get() > 0;
}
+
+ // CraftBukkit start
+ @Override
+ public CraftInventoryView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ org.bukkit.craftbukkit.inventory.CraftInventory inventory = new org.bukkit.craftbukkit.inventory.CraftInventorySmithing(
+ this.access.getLocation(), this.inputSlots, this.resultSlots);
+ this.bukkitEntity = new CraftInventoryView(this.player.getBukkitEntity(), inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

View file

@ -1,188 +0,0 @@
--- a/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/net/minecraft/world/inventory/StonecutterMenu.java
@@ -7,7 +7,6 @@
import net.minecraft.world.Container;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.player.Inventory;
-import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeHolder;
@@ -17,6 +16,13 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.inventory.CraftInventoryStonecutter;
+import org.bukkit.craftbukkit.inventory.view.CraftStonecutterView;
+import org.bukkit.entity.Player;
+// CraftBukkit end
+
public class StonecutterMenu extends AbstractContainerMenu {
public static final int INPUT_SLOT = 0;
@@ -36,27 +42,49 @@
Runnable slotUpdateListener;
public final Container container;
final ResultContainer resultContainer;
+ // CraftBukkit start
+ private CraftStonecutterView bukkitEntity = null;
+ private Player player;
+ @Override
+ public CraftStonecutterView getBukkitView() {
+ if (this.bukkitEntity != null) {
+ return this.bukkitEntity;
+ }
+
+ CraftInventoryStonecutter inventory = new CraftInventoryStonecutter(this.container, this.resultContainer);
+ this.bukkitEntity = new CraftStonecutterView(this.player, inventory, this);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
+
public StonecutterMenu(int syncId, Inventory playerInventory) {
this(syncId, playerInventory, ContainerLevelAccess.NULL);
}
public StonecutterMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) {
super(MenuType.STONECUTTER, syncId);
- this.selectedRecipeIndex = DataSlot.standalone();
+ this.selectedRecipeIndex = DataSlot.shared(new int[1], 0); // Paper - Add PlayerStonecutterRecipeSelectEvent
this.recipesForInput = SelectableRecipe.SingleInputSet.empty();
this.input = ItemStack.EMPTY;
this.slotUpdateListener = () -> {
};
- this.container = new SimpleContainer(1) {
+ this.container = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders
@Override
public void setChanged() {
super.setChanged();
StonecutterMenu.this.slotsChanged(this);
StonecutterMenu.this.slotUpdateListener.run();
}
+
+ // CraftBukkit start
+ @Override
+ public Location getLocation() {
+ return context.getLocation();
+ }
+ // CraftBukkit end
};
- this.resultContainer = new ResultContainer();
+ this.resultContainer = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders
this.access = context;
this.level = playerInventory.player.level();
this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33));
@@ -67,7 +95,7 @@
}
@Override
- public void onTake(Player player, ItemStack stack) {
+ public void onTake(net.minecraft.world.entity.player.Player player, ItemStack stack) {
stack.onCraftedBy(player.level(), player, stack.getCount());
StonecutterMenu.this.resultContainer.awardUsedRecipes(player, this.getRelevantItems());
ItemStack itemstack1 = StonecutterMenu.this.inputSlot.remove(1);
@@ -80,7 +108,7 @@
long j = world.getGameTime();
if (StonecutterMenu.this.lastSoundTime != j) {
- world.playSound((Player) null, blockposition, SoundEvents.UI_STONECUTTER_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
+ world.playSound((net.minecraft.world.entity.player.Player) null, blockposition, SoundEvents.UI_STONECUTTER_TAKE_RESULT, SoundSource.BLOCKS, 1.0F, 1.0F);
StonecutterMenu.this.lastSoundTime = j;
}
@@ -94,6 +122,7 @@
});
this.addStandardInventorySlots(playerInventory, 8, 84);
this.addDataSlot(this.selectedRecipeIndex);
+ this.player = (Player) playerInventory.player.getBukkitEntity(); // CraftBukkit
}
public int getSelectedRecipeIndex() {
@@ -113,18 +142,45 @@
}
@Override
- public boolean stillValid(Player player) {
+ public boolean stillValid(net.minecraft.world.entity.player.Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
return stillValid(this.access, player, Blocks.STONECUTTER);
}
@Override
- public boolean clickMenuButton(Player player, int id) {
+ public boolean clickMenuButton(net.minecraft.world.entity.player.Player player, int id) {
if (this.selectedRecipeIndex.get() == id) {
return false;
} else {
if (this.isValidRecipeIndex(id)) {
- this.selectedRecipeIndex.set(id);
- this.setupResultSlot(id);
+ // Paper start - Add PlayerStonecutterRecipeSelectEvent
+ int recipeIndex = id;
+ this.selectedRecipeIndex.set(recipeIndex);
+ this.selectedRecipeIndex.checkAndClearUpdateFlag(); // mark as changed
+ paperEventBlock: if (this.isValidRecipeIndex(id)) {
+ final Optional<RecipeHolder<StonecutterRecipe>> recipe = this.recipesForInput.entries().get(id).recipe().recipe();
+ if (recipe.isEmpty()) break paperEventBlock; // The recipe selected does not have an actual server recipe (presumably its the empty one). Cannot call the event, just break.
+
+ io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent event = new io.papermc.paper.event.player.PlayerStonecutterRecipeSelectEvent((Player) player.getBukkitEntity(), getBukkitView().getTopInventory(), (org.bukkit.inventory.StonecuttingRecipe) recipe.get().toBukkitRecipe());
+ if (!event.callEvent()) {
+ player.containerMenu.sendAllDataToRemote();
+ return false;
+ }
+
+ net.minecraft.resources.ResourceLocation key = org.bukkit.craftbukkit.util.CraftNamespacedKey.toMinecraft(event.getStonecuttingRecipe().getKey());
+ if (!recipe.get().id().location().equals(key)) { // If the recipe did NOT stay the same
+ for (int newRecipeIndex = 0; newRecipeIndex < this.recipesForInput.entries().size(); newRecipeIndex++) {
+ if (this.recipesForInput.entries().get(newRecipeIndex).recipe().recipe().filter(r -> r.id().location().equals(key)).isPresent()) {
+ recipeIndex = newRecipeIndex;
+ break;
+ }
+ }
+ }
+ }
+ player.containerMenu.sendAllDataToRemote();
+ this.selectedRecipeIndex.set(recipeIndex); // set new index, so that listeners can read it
+ this.setupResultSlot(recipeIndex);
+ // Paper end - Add PlayerStonecutterRecipeSelectEvent
}
return true;
@@ -144,6 +200,7 @@
this.setupRecipeList(itemstack);
}
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
}
private void setupRecipeList(ItemStack stack) {
@@ -158,7 +215,7 @@
}
void setupResultSlot(int selectedId) {
- Optional optional;
+ Optional<RecipeHolder<StonecutterRecipe>> optional; // CraftBukkit - decompile error
if (!this.recipesForInput.isEmpty() && this.isValidRecipeIndex(selectedId)) {
SelectableRecipe.SingleInputEntry<StonecutterRecipe> selectablerecipe_a = (SelectableRecipe.SingleInputEntry) this.recipesForInput.entries().get(selectedId);
@@ -193,7 +250,7 @@
}
@Override
- public ItemStack quickMoveStack(Player player, int slot) {
+ public ItemStack quickMoveStack(net.minecraft.world.entity.player.Player player, int slot) {
ItemStack itemstack = ItemStack.EMPTY;
Slot slot1 = (Slot) this.slots.get(slot);
@@ -246,7 +303,7 @@
}
@Override
- public void removed(Player player) {
+ public void removed(net.minecraft.world.entity.player.Player player) {
super.removed(player);
this.resultContainer.removeItemNoUpdate(1);
this.access.execute((world, blockposition) -> {

View file

@ -1,93 +0,0 @@
--- a/net/minecraft/world/inventory/TransientCraftingContainer.java
+++ b/net/minecraft/world/inventory/TransientCraftingContainer.java
@@ -3,11 +3,21 @@
import java.util.Iterator;
import java.util.List;
import net.minecraft.core.NonNullList;
+import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.player.StackedItemContents;
import net.minecraft.world.item.ItemStack;
+// CraftBukkit start
+import java.util.List;
+import net.minecraft.world.item.crafting.RecipeHolder;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.inventory.InventoryType;
+// CraftBukkit end
+
public class TransientCraftingContainer implements CraftingContainer {
private final NonNullList<ItemStack> items;
@@ -15,6 +25,68 @@
private final int height;
private final AbstractContainerMenu menu;
+ // CraftBukkit start - add fields
+ public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+ private RecipeHolder<?> currentRecipe;
+ public Container resultInventory;
+ private Player owner;
+ private int maxStack = MAX_STACK;
+
+ public List<ItemStack> getContents() {
+ return this.items;
+ }
+
+ public void onOpen(CraftHumanEntity who) {
+ this.transaction.add(who);
+ }
+
+ public InventoryType getInvType() {
+ return this.items.size() == 4 ? InventoryType.CRAFTING : InventoryType.WORKBENCH;
+ }
+
+ public void onClose(CraftHumanEntity who) {
+ this.transaction.remove(who);
+ }
+
+ public List<HumanEntity> getViewers() {
+ return this.transaction;
+ }
+
+ public org.bukkit.inventory.InventoryHolder getOwner() {
+ return (this.owner == null) ? null : this.owner.getBukkitEntity();
+ }
+
+ @Override
+ public int getMaxStackSize() {
+ return this.maxStack;
+ }
+
+ public void setMaxStackSize(int size) {
+ this.maxStack = size;
+ this.resultInventory.setMaxStackSize(size);
+ }
+
+ @Override
+ public Location getLocation() {
+ return this.menu instanceof CraftingMenu ? ((CraftingMenu) this.menu).access.getLocation() : this.owner.getBukkitEntity().getLocation();
+ }
+
+ @Override
+ public RecipeHolder<?> getCurrentRecipe() {
+ return this.currentRecipe;
+ }
+
+ @Override
+ public void setCurrentRecipe(RecipeHolder<?> currentRecipe) {
+ this.currentRecipe = currentRecipe;
+ }
+
+ public TransientCraftingContainer(AbstractContainerMenu container, int i, int j, Player player) {
+ this(container, i, j);
+ this.owner = player;
+ }
+ // CraftBukkit end
+
public TransientCraftingContainer(AbstractContainerMenu handler, int width, int height) {
this(handler, width, height, NonNullList.withSize(width * height, ItemStack.EMPTY));
}