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

@@ -0,0 +1,155 @@
--- a/net/minecraft/world/inventory/AnvilMenu.java
+++ b/net/minecraft/world/inventory/AnvilMenu.java
@@ -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 org.bukkit.craftbukkit.inventory.view.CraftAnvilView bukkitEntity;
+ // CraftBukkit end
+ public boolean bypassEnchantmentLevelRestriction = false; // Paper - bypass anvil level restrictions
public AnvilMenu(int containerId, Inventory playerInventory) {
this(containerId, playerInventory, ContainerLevelAccess.NULL);
@@ -68,7 +_,7 @@
@Override
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 && hasStack; // CraftBukkit - allow cost 0 like a free item
}
@Override
@@ -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((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(), 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) {
+ blockState1 = null;
+ } else {
+ blockState1 = ((org.bukkit.craftbukkit.block.data.CraftBlockData) event.getDamageState().getMaterial().createBlockData()).getState().setValue(AnvilBlock.FACING, blockState.getValue(AnvilBlock.FACING));
+ }
+ // Paper end - AnvilDamageEvent
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
+ this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
return;
}
@@ -144,8 +_,8 @@
this.repairItemCountCost = i2;
} else {
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
+ this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
return;
}
@@ -191,7 +_,7 @@
flag1 = true;
} else {
flag = true;
- if (intValue > enchantment.getMaxLevel()) {
+ if (intValue > enchantment.getMaxLevel() && !this.bypassEnchantmentLevelRestriction) { // Paper - bypass anvil level restrictions
intValue = enchantment.getMaxLevel();
}
@@ -209,8 +_,8 @@
}
if (flag1 && !flag) {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
- this.cost.set(0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+ this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
return;
}
}
@@ -235,14 +_,16 @@
}
if (i1 == i && i1 > 0) {
- if (this.cost.get() >= 40) {
- this.cost.set(39);
+ // CraftBukkit start
+ if (this.cost.get() >= this.maximumRepairCost) {
+ this.cost.set(this.maximumRepairCost - 1);
+ // CraftBukkit end
}
this.onlyRenaming = true;
}
- if (this.cost.get() >= 40 && !this.player.getAbilities().instabuild) {
+ if (this.cost.get() >= this.maximumRepairCost && !this.player.getAbilities().instabuild) { // CraftBukkit
itemStack = ItemStack.EMPTY;
}
@@ -260,12 +_,13 @@
EnchantmentHelper.setEnchantments(itemStack, mutable.toImmutable());
}
- this.resultSlots.setItem(0, itemStack);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), itemStack); // CraftBukkit
this.broadcastChanges();
} else {
- this.resultSlots.setItem(0, ItemStack.EMPTY);
- this.cost.set(0);
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareAnvilEvent(this.getBukkitView(), ItemStack.EMPTY); // CraftBukkit
+ this.cost.set(AnvilMenu.DEFAULT_DENIED_COST); // CraftBukkit - use a variable for set a cost for denied item
}
+ this.sendAllDataToRemote(); // CraftBukkit - SPIGOT-6686, SPIGOT-7931: Always send completed inventory to stay in sync with client
}
public static int calculateIncreasedRepairCost(int oldRepairCost) {
@@ -286,6 +_,7 @@
}
this.createResult();
+ org.bukkit.craftbukkit.event.CraftEventFactory.callPrepareResultEvent(this, RESULT_SLOT); // Paper - Add PrepareResultEvent
return true;
} else {
return false;
@@ -301,4 +_,19 @@
public int getCost() {
return this.cost.get();
}
+
+ // CraftBukkit start
+ @Override
+ 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 org.bukkit.craftbukkit.inventory.view.CraftAnvilView(this.player.getBukkitEntity(), inventory, this);
+ this.bukkitEntity.updateFromLegacy(inventory);
+ return this.bukkitEntity;
+ }
+ // CraftBukkit end
}

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

@@ -0,0 +1,69 @@
--- a/net/minecraft/world/inventory/ContainerLevelAccess.java
+++ b/net/minecraft/world/inventory/ContainerLevelAccess.java
@@ -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
};
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.");
+ }
+
+ default BlockPos getPosition() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ default org.bukkit.Location getLocation() {
+ return new org.bukkit.Location(this.getWorld().getWorld(), this.getPosition().getX(), this.getPosition().getY(), this.getPosition().getZ());
+ }
+ // CraftBukkit end
+ // Paper start - Add missing InventoryHolders
+ default boolean isBlock() {
+ return false;
+ }
+
+ default org.bukkit.inventory.@org.jetbrains.annotations.Nullable BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) {
+ if (!this.isBlock()) {
+ return null;
+ }
+ return new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(this, menu.getBukkitView().getTopInventory());
+ }
+ // Paper end - Add missing InventoryHolders
}

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

@@ -0,0 +1,56 @@
--- a/net/minecraft/world/inventory/ItemCombinerMenu.java
+++ b/net/minecraft/world/inventory/ItemCombinerMenu.java
@@ -15,12 +_,7 @@
protected final ContainerLevelAccess access;
protected final Player player;
protected final Container inputSlots;
- protected final ResultContainer resultSlots = new ResultContainer() {
- @Override
- public void setChanged() {
- ItemCombinerMenu.this.slotsChanged(this);
- }
- };
+ protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init
private final int resultSlotIndex;
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
+ public void setChanged() {
+ ItemCombinerMenu.this.slotsChanged(this);
+ }
+ };
+ // Paper end - Add missing InventoryHolders; delay field init
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) {
- return new SimpleContainer(size) {
+ return new SimpleContainer(this.createBlockHolder(this.access), size) {
@Override
public void setChanged() {
super.setChanged();
@@ -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
}
}
@@ -104,6 +_,7 @@
@Override
public boolean stillValid(Player player) {
+ if (!this.checkReachable) return true; // CraftBukkit
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

@@ -0,0 +1,37 @@
--- a/net/minecraft/world/inventory/MerchantResultSlot.java
+++ b/net/minecraft/world/inventory/MerchantResultSlot.java
@@ -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 activeOffer = this.slots.getActiveOffer();
+ // Paper start - Add PlayerTradeEvent and PlayerPurchaseEvent
+ io.papermc.paper.event.player.PlayerPurchaseEvent event = null;
+ 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(), 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(), activeOffer.asBukkit(), false, true);
+ }
+ if (event != null) {
+ if (!event.callEvent()) {
+ stack.setCount(0);
+ event.getPlayer().updateInventory();
+ return;
+ }
+ activeOffer = org.bukkit.craftbukkit.inventory.CraftMerchantRecipe.fromBukkit(event.getTrade()).toMinecraft();
+ }
+ }
+ this.checkTakeAchievements(stack);
+ // Paper end - 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, 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

@@ -0,0 +1,56 @@
--- a/net/minecraft/world/inventory/ResultContainer.java
+++ b/net/minecraft/world/inventory/ResultContainer.java
@@ -12,6 +_,53 @@
private final NonNullList<ItemStack> itemStacks = NonNullList.withSize(1, ItemStack.EMPTY);
@Nullable
private RecipeHolder<?> recipeUsed;
+ // CraftBukkit start
+ private int maxStack = MAX_STACK;
+
+ public java.util.List<ItemStack> getContents() {
+ return this.itemStacks;
+ }
+
+ public org.bukkit.inventory.InventoryHolder getOwner() {
+ // Paper start - Add missing InventoryHolders
+ if (this.holder == null && this.holderCreator != null) {
+ this.holder = this.holderCreator.get();
+ }
+ return this.holder; // Result slots don't get an owner
+ // Paper end - Add missing InventoryHolders
+ }
+
+ // Don't need a transaction; the InventoryCrafting keeps track of it for us
+ 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
+ public int getMaxStackSize() {
+ return this.maxStack;
+ }
+
+ public void setMaxStackSize(int size) {
+ this.maxStack = size;
+ }
+
+ @Override
+ public org.bukkit.Location getLocation() {
+ return null;
+ }
+ // CraftBukkit end
+ // Paper start - Add missing InventoryHolders
+ 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.holderCreator = holderCreator;
+ }
+
+ 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));
}