PaperMC/patches/server/0942-Optimize-Hoppers.patch

608 lines
32 KiB
Diff
Raw Normal View History

2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Wed, 27 Apr 2016 22:09:52 -0400
Subject: [PATCH] Optimize Hoppers
* Removes unnecessary extra calls to .update() that are very expensive
* Lots of itemstack cloning removed. Only clone if the item is actually moved
* Return true when a plugin cancels inventory move item event instead of false, as false causes pulls to cycle through all items.
However, pushes do not exhibit the same behavior, so this is not something plugins could of been relying on.
* Add option (Default on) to cooldown hoppers when they fail to move an item due to full inventory
* Skip subsequent InventoryMoveItemEvents if a plugin does not use the item after first event fire for an iteration
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried)
* Remove Streams from Item Suck In and restore restore 1.12 AABB checks which is simpler and no voxel allocations (was doing TWO Item Suck ins)
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index c5f3dc74888919e82e2ffbb8d648b7640aa6b690..80cf4852e4010eeeadaf920ab927a40df0179b40 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1522,6 +1522,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
2021-06-11 14:02:28 +02:00
while (iterator.hasNext()) {
ServerLevel worldserver = (ServerLevel) iterator.next();
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
2023-03-18 20:03:42 +01:00
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
2021-06-11 14:02:28 +02:00
this.profiler.push(() -> {
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#9440) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 01aa02eb PR-858: Add LivingEntity#playHurtAnimation() 9421320f PR-884: Refinements to new ban API for improved compatibility and correctness 37a60b45 SPIGOT-6455, SPIGOT-7030, PR-750: Improve ban API 4eeb174b All smithing inventories are now the new smithing inventory f2bb168e PR-880: Add methods to get/set FallingBlock CancelDrop e7a807fa PR-879: Add Player#sendHealthUpdate() 692b8e96 SPIGOT-7370: Remove float value conversion in plugin.yml 2d033390 SPIGOT-7403: Add direct API for waxed signs 16a08373 PR-876: Add missing Raider API and 'no action ticks' CraftBukkit Changes: b60a95c8c PR-1189: Add LivingEntity#playHurtAnimation() 95c335c63 PR-1226: Fix VehicleEnterEvent not being called for certain entities 0a0fc3bee PR-1227: Refinements to new ban API for improved compatibility and correctness 0d0b1e5dc Revert bad change to PathfinderGoalSit causing all cats to sit 648196070 SPIGOT-6455, SPIGOT-7030, PR-1054: Improve ban API 31fe848d6 All smithing inventories are now the new smithing inventory 9a919a143 SPIGOT-7416: SmithItemEvent not firing in Smithing Table 9f64f0d22 PR-1221: Add methods to get/set FallingBlock CancelDrop 3be9ac171 PR-1220: Add Player#sendHealthUpdate() c1279f775 PR-1209: Clean up various patches c432e4397 Fix Raider#setCelebrating() implementation 504d96665 SPIGOT-7403: Add direct API for waxed signs c68c1f1b3 PR-1216: Add missing Raider API and 'no action ticks' 85b89c3dd Increase outdated build delay Spigot Changes: 9ebce8af Rebuild patches 64b565e6 Rebuild patches
2023-07-04 10:22:56 +02:00
index 90e4f8d21822cb0dc8bda586803f8c086f0fbeee..22e148867a2832035546148fc5aa27b9d4de3c64 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java
Updated Upstream (Bukkit/CraftBukkit/Spigot) (#9440) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 01aa02eb PR-858: Add LivingEntity#playHurtAnimation() 9421320f PR-884: Refinements to new ban API for improved compatibility and correctness 37a60b45 SPIGOT-6455, SPIGOT-7030, PR-750: Improve ban API 4eeb174b All smithing inventories are now the new smithing inventory f2bb168e PR-880: Add methods to get/set FallingBlock CancelDrop e7a807fa PR-879: Add Player#sendHealthUpdate() 692b8e96 SPIGOT-7370: Remove float value conversion in plugin.yml 2d033390 SPIGOT-7403: Add direct API for waxed signs 16a08373 PR-876: Add missing Raider API and 'no action ticks' CraftBukkit Changes: b60a95c8c PR-1189: Add LivingEntity#playHurtAnimation() 95c335c63 PR-1226: Fix VehicleEnterEvent not being called for certain entities 0a0fc3bee PR-1227: Refinements to new ban API for improved compatibility and correctness 0d0b1e5dc Revert bad change to PathfinderGoalSit causing all cats to sit 648196070 SPIGOT-6455, SPIGOT-7030, PR-1054: Improve ban API 31fe848d6 All smithing inventories are now the new smithing inventory 9a919a143 SPIGOT-7416: SmithItemEvent not firing in Smithing Table 9f64f0d22 PR-1221: Add methods to get/set FallingBlock CancelDrop 3be9ac171 PR-1220: Add Player#sendHealthUpdate() c1279f775 PR-1209: Clean up various patches c432e4397 Fix Raider#setCelebrating() implementation 504d96665 SPIGOT-7403: Add direct API for waxed signs c68c1f1b3 PR-1216: Add missing Raider API and 'no action ticks' 85b89c3dd Increase outdated build delay Spigot Changes: 9ebce8af Rebuild patches 64b565e6 Rebuild patches
2023-07-04 10:22:56 +02:00
@@ -719,10 +719,16 @@ public final class ItemStack {
2021-06-11 14:02:28 +02:00
}
2023-03-18 20:03:42 +01:00
public ItemStack copy() {
2021-06-11 14:02:28 +02:00
- if (this.isEmpty()) {
2023-03-18 20:03:42 +01:00
+ // Paper start
+ return this.copy(false);
+ }
+
+ public ItemStack copy(boolean originalItem) {
+ if (!originalItem && this.isEmpty()) {
+ // Paper end
2021-06-11 14:02:28 +02:00
return ItemStack.EMPTY;
} else {
- ItemStack itemstack = new ItemStack(this.getItem(), this.count);
2023-03-18 20:03:42 +01:00
+ ItemStack itemstack = new ItemStack(originalItem ? this.item : this.getItem(), this.count); // Paper
2021-06-11 14:02:28 +02:00
itemstack.setPopTime(this.getPopTime());
if (this.tag != null) {
diff --git a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
2023-06-08 10:47:19 +02:00
index 5bdad1866386908b9fef74d15862eb107fabe68f..370a25d2deb54f10a35ee24d9e7e92fbfde60edf 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
2022-03-30 22:28:38 +02:00
@@ -26,6 +26,7 @@ import co.aikar.timings.MinecraftTimings; // Paper
import co.aikar.timings.Timing; // Paper
public abstract class BlockEntity {
2023-02-23 17:37:56 +01:00
+ static boolean ignoreTileUpdates; // Paper
2021-06-11 14:02:28 +02:00
2022-03-30 22:28:38 +02:00
public Timing tickTimer = MinecraftTimings.getTileEntityTimings(this); // Paper
// CraftBukkit start - data containers
2023-06-08 10:47:19 +02:00
@@ -161,6 +162,7 @@ public abstract class BlockEntity {
2021-06-11 14:02:28 +02:00
public void setChanged() {
if (this.level != null) {
2023-02-23 17:37:56 +01:00
+ if (ignoreTileUpdates) return; // Paper
2021-06-13 21:29:58 +02:00
BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 6907e647ef4d3f5c9c46edb4cf0905844dd1cea9..a8a26a0a37a08b6bbeb5a1fde417d6f448d3c79f 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
2023-03-18 20:03:42 +01:00
@@ -193,6 +193,201 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
return false;
}
2023-03-18 20:03:42 +01:00
2021-06-11 14:02:28 +02:00
+ // Paper start - Optimize Hoppers
2023-02-23 17:37:56 +01:00
+ private static boolean skipPullModeEventFire;
+ private static boolean skipPushModeEventFire;
+ public static boolean skipHopperEvents;
2021-06-11 14:02:28 +02:00
+
2023-02-23 17:37:56 +01:00
+ private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
2021-06-11 14:02:28 +02:00
+ skipPushModeEventFire = skipHopperEvents;
+ boolean foundItem = false;
2021-06-14 12:18:42 +02:00
+ for (int i = 0; i < hopper.getContainerSize(); ++i) {
2023-02-23 17:37:56 +01:00
+ final ItemStack item = hopper.getItem(i);
2021-06-11 14:02:28 +02:00
+ if (!item.isEmpty()) {
+ foundItem = true;
+ ItemStack origItemStack = item;
2023-02-23 17:37:56 +01:00
+ ItemStack movedItem = origItemStack;
2021-06-11 14:02:28 +02:00
+
2023-02-23 17:37:56 +01:00
+ final int originalItemCount = origItemStack.getCount();
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
+ origItemStack.setCount(movedItemCount);
2021-06-11 14:02:28 +02:00
+
+ // We only need to fire the event once to give protection plugins a chance to cancel this event
+ // Because nothing uses getItem, every event call should end up the same result.
+ if (!skipPushModeEventFire) {
2023-02-23 17:37:56 +01:00
+ movedItem = callPushMoveEvent(destination, movedItem, hopper);
+ if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+ return false;
+ }
+ }
2023-02-23 17:37:56 +01:00
+
+ final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) {
2023-03-18 20:03:42 +01:00
+ origItemStack = origItemStack.copy(true);
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+ if (!origItemStack.isEmpty()) {
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
2021-06-11 14:02:28 +02:00
+ }
2021-06-13 21:29:58 +02:00
+ hopper.setItem(i, origItemStack);
2021-06-14 12:18:42 +02:00
+ destination.setChanged();
2021-06-11 14:02:28 +02:00
+ return true;
+ }
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+ }
+ }
+ if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
2021-06-13 21:29:58 +02:00
+ hopper.setCooldown(level.spigotConfig.hopperTransfer);
2021-06-11 14:02:28 +02:00
+ }
+ return false;
+ }
+
2023-02-23 17:37:56 +01:00
+ private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
+ ItemStack movedItem = origItemStack;
+ final int originalItemCount = origItemStack.getCount();
+ final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
+ movedItem.setCount(movedItemCount);
2021-06-11 14:02:28 +02:00
+
+ if (!skipPullModeEventFire) {
2023-02-23 17:37:56 +01:00
+ movedItem = callPullMoveEvent(hopper, container, movedItem);
+ if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+ // Drastically improve performance by returning true.
+ // No plugin could of relied on the behavior of false as the other call
+ // site for IMIE did not exhibit the same behavior
+ return true;
+ }
+ }
+
2023-02-23 17:37:56 +01:00
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) {
2023-03-18 20:03:42 +01:00
+ origItemStack = origItemStack.copy(true);
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+ if (!origItemStack.isEmpty()) {
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
2021-06-11 14:02:28 +02:00
+ }
2023-02-23 17:37:56 +01:00
+
+ ignoreTileUpdates = true;
+ container.setItem(i, origItemStack);
+ ignoreTileUpdates = false;
+ container.setChanged();
2021-06-11 14:02:28 +02:00
+ return true;
+ }
2023-02-23 17:37:56 +01:00
+ origItemStack.setCount(originalItemCount);
2021-06-11 14:02:28 +02:00
+
+ if (level.paperConfig().hopper.cooldownWhenFull) {
2023-02-23 17:37:56 +01:00
+ cooldownHopper(hopper);
2021-06-11 14:02:28 +02:00
+ }
+
+ return false;
+ }
+
2023-02-23 17:37:56 +01:00
+ @Nullable
2021-06-13 21:29:58 +02:00
+ private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) {
2023-02-23 17:37:56 +01:00
+ final Inventory destinationInventory = getInventory(iinventory);
+ final InventoryMoveItemEvent event = new InventoryMoveItemEvent(hopper.getOwner(false).getInventory(),
2021-06-11 14:02:28 +02:00
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
2023-02-23 17:37:56 +01:00
+ final boolean result = event.callEvent();
2021-06-11 14:02:28 +02:00
+ if (!event.calledGetItem && !event.calledSetItem) {
+ skipPushModeEventFire = true;
+ }
+ if (!result) {
2021-06-13 21:29:58 +02:00
+ cooldownHopper(hopper);
2021-06-11 14:02:28 +02:00
+ return null;
+ }
+
+ if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem());
+ } else {
+ return itemstack;
+ }
+ }
+
2023-02-23 17:37:56 +01:00
+ @Nullable
+ private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
+ final Inventory sourceInventory = getInventory(container);
+ final Inventory destination = getInventory(hopper);
2021-06-11 14:02:28 +02:00
+
2023-02-23 17:37:56 +01:00
+ // Mirror is safe as no plugins ever use this item
+ final InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false);
+ final boolean result = event.callEvent();
2021-06-11 14:02:28 +02:00
+ if (!event.calledGetItem && !event.calledSetItem) {
+ skipPullModeEventFire = true;
+ }
+ if (!result) {
+ cooldownHopper(hopper);
+ return null;
+ }
+
+ if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem());
+ } else {
+ return itemstack;
+ }
+ }
+
2023-02-23 17:37:56 +01:00
+ private static Inventory getInventory(final Container container) {
+ final Inventory sourceInventory;
+ if (container instanceof CompoundContainer compoundContainer) {
+ // Have to special-case large chests as they work oddly
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (container instanceof BlockEntity blockEntity) {
+ sourceInventory = blockEntity.getOwner(false).getInventory();
2023-03-18 20:03:42 +01:00
+ } else if (container.getOwner() != null) {
2023-02-23 17:37:56 +01:00
+ sourceInventory = container.getOwner().getInventory();
2023-03-18 20:03:42 +01:00
+ } else {
+ sourceInventory = new CraftInventory(container);
2021-06-11 14:02:28 +02:00
+ }
+ return sourceInventory;
+ }
+
2023-02-23 17:37:56 +01:00
+ private static void cooldownHopper(final Hopper hopper) {
2023-03-18 20:03:42 +01:00
+ if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
2021-06-11 14:02:28 +02:00
+ }
+ }
2023-03-18 20:03:42 +01:00
+
+ private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
+ if (!test.test(iinventory.getItem(i), i)) {
+ return false;
+ }
+ }
+ } else {
+ int size = iinventory.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (!test.test(iinventory.getItem(i), i)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private static boolean anyMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) {
+ if (test.test(iinventory.getItem(i), i)) {
+ return true;
+ }
+ }
+ } else {
+ int size = iinventory.getContainerSize();
+ for (int i = 0; i < size; i++) {
+ if (test.test(iinventory.getItem(i), i)) {
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+ private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemstack, i) -> itemstack.getCount() >= itemstack.getMaxStackSize();
+ private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemstack, i) -> itemstack.isEmpty();
2021-06-11 14:02:28 +02:00
+ // Paper end
2023-03-18 20:03:42 +01:00
+
2021-11-24 06:44:21 +01:00
private static boolean ejectItems(Level world, BlockPos blockposition, BlockState iblockdata, Container iinventory, HopperBlockEntity hopper) { // CraftBukkit
2021-06-13 21:29:58 +02:00
Container iinventory1 = HopperBlockEntity.getAttachedContainer(world, blockposition, iblockdata);
2023-03-18 20:03:42 +01:00
@@ -204,46 +399,49 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-13 21:29:58 +02:00
if (HopperBlockEntity.isFullContainer(iinventory1, enumdirection)) {
2021-06-11 14:02:28 +02:00
return false;
} else {
2023-02-23 17:37:56 +01:00
- for (int i = 0; i < iinventory.getContainerSize(); ++i) {
- if (!iinventory.getItem(i).isEmpty()) {
- ItemStack itemstack = iinventory.getItem(i).copy();
- // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
2023-03-23 22:57:03 +01:00
-
2023-02-23 17:37:56 +01:00
- // CraftBukkit start - Call event when pushing items into other inventories
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
2023-03-23 22:57:03 +01:00
-
2023-02-23 17:37:56 +01:00
- Inventory destinationInventory;
- // Have to special case large chests as they work oddly
- if (iinventory1 instanceof CompoundContainer) {
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
2023-03-18 20:03:42 +01:00
- } else if (iinventory1.getOwner() != null) {
2023-02-23 17:37:56 +01:00
- destinationInventory = iinventory1.getOwner().getInventory();
2023-03-18 20:03:42 +01:00
- } else {
- destinationInventory = new CraftInventory(iinventory);
2023-02-23 17:37:56 +01:00
- }
2023-03-23 22:57:03 +01:00
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
- world.getCraftServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- hopper.setItem(i, itemstack);
- hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
2023-03-23 22:57:03 +01:00
+ // Paper start - replace logic; MAKE SURE TO CHECK FOR DIFFS ON UPDATES
+ return hopperPush(world, iinventory1, enumdirection, hopper);
+ // for (int i = 0; i < iinventory.getContainerSize(); ++i) {
+ // if (!iinventory.getItem(i).isEmpty()) {
+ // ItemStack itemstack = iinventory.getItem(i).copy();
+ // // ItemStack itemstack1 = addItem(iinventory, iinventory1, iinventory.removeItem(i, 1), enumdirection);
+
+ // // CraftBukkit start - Call event when pushing items into other inventories
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
+ // Inventory destinationInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory1 instanceof CompoundContainer) {
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory1);
+ // } else if (iinventory1.getOwner() != null) {
+ // destinationInventory = iinventory1.getOwner().getInventory();
+ // } else {
+ // destinationInventory = new CraftInventory(iinventory);
+ // }
+
2023-03-18 20:03:42 +01:00
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(iinventory.getOwner().getInventory(), oitemstack.clone(), destinationInventory, true);
+ // world.getCraftServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // hopper.setItem(i, itemstack);
+ // hopper.setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, iinventory1, CraftItemStack.asNMSCopy(event.getItem()), enumdirection);
2023-02-23 17:37:56 +01:00
// CraftBukkit end
- if (itemstack1.isEmpty()) {
- iinventory1.setChanged();
- return true;
- }
2023-03-18 20:03:42 +01:00
+ // if (itemstack1.isEmpty()) {
+ // iinventory1.setChanged();
+ // return true;
+ // }
2023-02-23 17:37:56 +01:00
- itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
- iinventory.setItem(i, itemstack);
- }
- }
2023-03-18 20:03:42 +01:00
+ // itemstack.shrink(origCount - itemstack1.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack);
+ // }
+ // }
2021-06-11 14:02:28 +02:00
- return false;
2023-03-18 20:03:42 +01:00
+ // return false;
2023-02-23 17:37:56 +01:00
+ // Paper end
2021-06-11 14:02:28 +02:00
}
}
}
2023-03-18 20:03:42 +01:00
@@ -253,17 +451,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
}
2021-06-13 21:29:58 +02:00
private static boolean isFullContainer(Container inventory, Direction direction) {
- return HopperBlockEntity.getSlots(inventory, direction).allMatch((i) -> {
- ItemStack itemstack = inventory.getItem(i);
-
- return itemstack.getCount() >= itemstack.getMaxStackSize();
- });
+ return allMatch(inventory, direction, STACK_SIZE_TEST); // Paper - no streams
}
private static boolean isEmptyContainer(Container inv, Direction facing) {
- return HopperBlockEntity.getSlots(inv, facing).allMatch((i) -> {
- return inv.getItem(i).isEmpty();
- });
+ return allMatch(inv, facing, IS_EMPTY_TEST);
2023-02-23 17:37:56 +01:00
}
2021-06-13 21:29:58 +02:00
public static boolean suckInItems(Level world, Hopper hopper) {
2023-03-18 20:03:42 +01:00
@@ -272,8 +464,16 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
if (iinventory != null) {
Direction enumdirection = Direction.DOWN;
2021-06-13 21:29:58 +02:00
- return HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) ? false : HopperBlockEntity.getSlots(iinventory, enumdirection).anyMatch((i) -> {
- return HopperBlockEntity.a(hopper, iinventory, i, enumdirection, world); // Spigot
2021-06-11 14:02:28 +02:00
+ // Paper start - optimize hoppers and remove streams
+ skipPullModeEventFire = skipHopperEvents;
2021-06-13 21:29:58 +02:00
+ return !HopperBlockEntity.isEmptyContainer(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> {
2021-06-11 14:02:28 +02:00
+ // Logic copied from below to avoid extra getItem calls
2023-03-18 20:03:42 +01:00
+ if (!item.isEmpty() && canTakeItemFromContainer(hopper, iinventory, item, i, enumdirection)) {
+ return hopperPull(world, hopper, iinventory, item, i);
2021-06-11 14:02:28 +02:00
+ } else {
+ return false;
+ }
2021-06-13 21:29:58 +02:00
+ // Paper end
2021-06-11 14:02:28 +02:00
});
} else {
2021-06-13 21:29:58 +02:00
Iterator iterator = HopperBlockEntity.getItemsAtAndAbove(world, hopper).iterator();
2023-03-18 20:03:42 +01:00
@@ -292,48 +492,52 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
}
}
2023-03-18 20:03:42 +01:00
+ @io.papermc.paper.annotation.DoNotUse // Paper - method unused as logic is inlined above
2021-06-13 21:29:58 +02:00
private static boolean a(Hopper ihopper, Container iinventory, int i, Direction enumdirection, Level world) { // Spigot
ItemStack itemstack = iinventory.getItem(i);
2021-06-11 14:02:28 +02:00
2023-03-18 20:03:42 +01:00
- if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) {
2023-02-23 17:37:56 +01:00
- ItemStack itemstack1 = itemstack.copy();
- // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
- // CraftBukkit start - Call event on collection of items from inventories into the hopper
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
2023-03-23 22:57:03 +01:00
-
2023-02-23 17:37:56 +01:00
- Inventory sourceInventory;
- // Have to special case large chests as they work oddly
- if (iinventory instanceof CompoundContainer) {
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
2023-03-18 20:03:42 +01:00
- } else if (iinventory.getOwner() != null) {
2023-02-23 17:37:56 +01:00
- sourceInventory = iinventory.getOwner().getInventory();
2023-03-18 20:03:42 +01:00
- } else {
- sourceInventory = new CraftInventory(iinventory);
2023-02-23 17:37:56 +01:00
- }
2023-03-23 22:57:03 +01:00
-
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
-
- Bukkit.getServer().getPluginManager().callEvent(event);
- if (event.isCancelled()) {
- iinventory.setItem(i, itemstack1);
-
- if (ihopper instanceof HopperBlockEntity) {
- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
- }
-
- return false;
- }
- int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
- // CraftBukkit end
-
- if (itemstack2.isEmpty()) {
- iinventory.setChanged();
- return true;
- }
-
- itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
- iinventory.setItem(i, itemstack1);
+ // Paper start - replace pull logic; MAKE SURE TO CHECK FOR DIFFS WHEN UPDATING
+ if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left unused incase reflective plugins
+ return hopperPull(world, ihopper, iinventory, itemstack, i);
+ // ItemStack itemstack1 = itemstack.copy();
+ // // ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.removeItem(i, 1), (EnumDirection) null);
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot
+
2023-03-18 20:03:42 +01:00
+ // Inventory sourceInventory;
+ // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) {
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory);
+ // } else if (iinventory.getOwner() != null) {
+ // sourceInventory = iinventory.getOwner().getInventory();
+ // } else {
+ // sourceInventory = new CraftInventory(iinventory);
+ // }
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack.clone(), ihopper.getOwner().getInventory(), false);
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // Bukkit.getServer().getPluginManager().callEvent(event);
+ // if (event.isCancelled()) {
+ // iinventory.setItem(i, itemstack1);
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // if (ihopper instanceof HopperBlockEntity) {
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot
+ // }
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // return false;
+ // }
+ // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack2 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null);
+ // // CraftBukkit end
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // if (itemstack2.isEmpty()) {
+ // iinventory.setChanged();
+ // return true;
+ // }
2023-03-23 22:57:03 +01:00
+
2023-03-18 20:03:42 +01:00
+ // itemstack1.shrink(origCount - itemstack2.getCount()); // Spigot
+ // iinventory.setItem(i, itemstack1);
2023-02-23 17:37:56 +01:00
+ // Paper end
2021-06-11 14:02:28 +02:00
}
return false;
2023-03-18 20:03:42 +01:00
@@ -342,7 +546,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
public static boolean addItem(Container inventory, ItemEntity itemEntity) {
boolean flag = false;
// CraftBukkit start
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity());
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - use getInventory() to avoid snapshot creation
2023-06-08 10:47:19 +02:00
itemEntity.level().getCraftServer().getPluginManager().callEvent(event);
2021-06-11 14:02:28 +02:00
if (event.isCancelled()) {
return false;
2023-03-18 20:03:42 +01:00
@@ -442,7 +646,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(to.getMaxStackSize());
}
// Spigot end
2023-02-23 17:37:56 +01:00
+ ignoreTileUpdates = true; // Paper
2021-06-11 14:02:28 +02:00
to.setItem(slot, stack);
2023-02-23 17:37:56 +01:00
+ ignoreTileUpdates = false; // Paper
2023-03-18 20:03:42 +01:00
stack = leftover; // Paper
2021-06-11 14:02:28 +02:00
flag = true;
2021-06-13 21:29:58 +02:00
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) {
@@ -516,19 +722,47 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
// CraftBukkit end
2021-06-11 14:02:28 +02:00
}
+ // Paper start - optimize hopper item suck in
+ static final AABB HOPPER_ITEM_SUCK_OVERALL = Hopper.SUCK.bounds();
+ static final AABB[] HOPPER_ITEM_SUCK_INDIVIDUAL = Hopper.SUCK.toAabbs().toArray(new AABB[0]);
+ // Paper end - optimize hopper item suck in
+
2021-06-13 21:29:58 +02:00
public static List<ItemEntity> getItemsAtAndAbove(Level world, Hopper hopper) {
- return (List) hopper.getSuckShape().toAabbs().stream().flatMap((axisalignedbb) -> {
- return world.getEntitiesOfClass(ItemEntity.class, axisalignedbb.move(hopper.getLevelX() - 0.5D, hopper.getLevelY() - 0.5D, hopper.getLevelZ() - 0.5D), EntitySelector.ENTITY_STILL_ALIVE).stream();
2021-06-11 14:02:28 +02:00
- }).collect(Collectors.toList());
+ // Paper start - optimize hopper item suck in
+ // eliminate multiple getEntitiesOfClass() but maintain the voxelshape collision by moving
+ // the individual AABB checks into the predicate
+ final double shiftX = hopper.getLevelX() - 0.5D;
+ final double shiftY = hopper.getLevelY() - 0.5D;
+ final double shiftZ = hopper.getLevelZ() - 0.5D;
+ return world.getEntitiesOfClass(ItemEntity.class, HOPPER_ITEM_SUCK_OVERALL.move(shiftX, shiftY, shiftZ), (final Entity entity) -> {
+ if (!entity.isAlive()) { // EntitySelector.ENTITY_STILL_ALIVE
+ return false;
+ }
+
+ for (final AABB aabb : HOPPER_ITEM_SUCK_INDIVIDUAL) {
+ if (aabb.move(shiftX, shiftY, shiftZ).intersects(entity.getBoundingBox())) {
+ return true;
+ }
+ }
+
+ return false;
+ });
+ // Paper end - optimize hopper item suck in
2021-06-11 14:02:28 +02:00
}
@Nullable
2021-06-13 21:29:58 +02:00
public static Container getContainerAt(Level world, BlockPos pos) {
- return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D);
+ return HopperBlockEntity.getContainerAt(world, (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true); // Paper
2021-06-11 14:02:28 +02:00
}
@Nullable
2023-03-18 20:03:42 +01:00
private static Container getContainerAt(Level world, double x, double y, double z) {
2023-02-23 17:37:56 +01:00
+ // Paper start - add optimizeEntities parameter
2023-03-18 20:03:42 +01:00
+ return HopperBlockEntity.getContainerAt(world, x, y, z, false);
2023-02-23 17:37:56 +01:00
+ }
+ @Nullable
+ private static Container getContainerAt(Level world, double x, double y, double z, final boolean optimizeEntities) {
+ // Paper end - add optimizeEntities parameter
2021-06-11 14:02:28 +02:00
Object object = null;
2023-03-18 20:03:42 +01:00
BlockPos blockposition = BlockPos.containing(x, y, z);
if ( !world.spigotConfig.hopperCanLoadChunks && !world.hasChunkAt( blockposition ) ) return null; // Spigot
@@ -548,7 +782,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
2021-06-11 14:02:28 +02:00
}
}
- if (object == null) {
+ if (object == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper
2021-06-13 21:29:58 +02:00
List<Entity> list = world.getEntities((Entity) null, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR);
2021-06-11 14:02:28 +02:00
if (!list.isEmpty()) {
@@ -560,7 +794,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
private static boolean canMergeItems(ItemStack first, ItemStack second) {
2023-06-08 10:47:19 +02:00
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameTags(first, second);
+ return first.getCount() < first.getMaxStackSize() && first.is(second.getItem()) && first.getDamageValue() == second.getDamageValue() && ((first.isEmpty() && second.isEmpty()) || java.util.Objects.equals(first.getTag(), second.getTag())); // Paper - used to return true for full itemstacks?!
}
@Override
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
2023-06-08 10:47:19 +02:00
index e11618247ad889fa8fadbb2c7addd0de94caf249..081691f9710ff1115e4308f79ed49fbc38941193 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
2023-06-08 10:47:19 +02:00
@@ -95,12 +95,19 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
2021-06-11 14:02:28 +02:00
@Override
public boolean isEmpty() {
2021-06-13 21:29:58 +02:00
this.unpackLootTable((Player)null);
2021-06-11 14:02:28 +02:00
- return this.getItems().stream().allMatch(ItemStack::isEmpty);
+ // Paper start
2023-03-18 20:03:42 +01:00
+ for (final ItemStack itemStack : this.getItems()) {
2021-06-11 14:02:28 +02:00
+ if (!itemStack.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
2023-03-18 20:03:42 +01:00
+ // Paper end
2021-06-11 14:02:28 +02:00
}
@Override
public ItemStack getItem(int slot) {
2021-06-13 21:29:58 +02:00
- this.unpackLootTable((Player)null);
2023-03-18 20:03:42 +01:00
+ if (slot == 0) this.unpackLootTable((Player)null); // Paper
2021-06-13 21:29:58 +02:00
return this.getItems().get(slot);
2021-06-11 14:02:28 +02:00
}