mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-12 21:54:06 +01:00
c97ce029e9
PaperMC believes that 1.16.2 is now ready for general release as we fixed the main issue plagueing the 1.16.x release, the MapLike data conversion issues. Until now, it was not safe for a server to convert a world to 1.16.2 without data conversion issues around villages and potentially other things. If you did, those MapLike errors meant something went wrong. This is now resolved. Big thanks to all those that helped, notably @BillyGalbreath and @Proximyst who did large parts of the update process with me. Please as always, backup your worlds and test before updating to 1.16.2! If you update to 1.16.2, there is no going back to an older build than this. --------------------------------- Co-authored-by: William Blake Galbreath <Blake.Galbreath@GMail.com> Co-authored-by: Mariell Hoversholm <proximyst@proximyst.com> Co-authored-by: krolik-exe <69214078+krolik-exe@users.noreply.github.com> Co-authored-by: BillyGalbreath <BillyGalbreath@users.noreply.github.com> Co-authored-by: stonar96 <minecraft.stonar96@gmail.com> Co-authored-by: Shane Freeder <theboyetronic@gmail.com> Co-authored-by: Jason <jasonpenilla2@me.com> Co-authored-by: kashike <kashike@vq.lc> Co-authored-by: Aurora <21148213+aurorasmiles@users.noreply.github.com> Co-authored-by: KennyTV <kennytv@t-online.de> Co-authored-by: commandblockguy <commandblockguy1@gmail.com> Co-authored-by: DigitalRegent <misterwener@gmail.com> Co-authored-by: ishland <ishlandmc@yeah.net>
502 lines
26 KiB
Diff
502 lines
26 KiB
Diff
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/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index b94c8e33780e10e458951384ffc49bd7fb015a6b..d846c55de176879e94f6c0e5bf8f58910657fc75 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -571,4 +571,13 @@ public class PaperWorldConfig {
|
|
private void entitiesTargetWithFollowRange() {
|
|
entitiesTargetWithFollowRange = getBoolean("entities-target-with-follow-range", entitiesTargetWithFollowRange);
|
|
}
|
|
+
|
|
+ public boolean cooldownHopperWhenFull = true;
|
|
+ public boolean disableHopperMoveEvents = false;
|
|
+ private void hopperOptimizations() {
|
|
+ cooldownHopperWhenFull = getBoolean("hopper.cooldown-when-full", cooldownHopperWhenFull);
|
|
+ log("Cooldown Hoppers when Full: " + (cooldownHopperWhenFull ? "enabled" : "disabled"));
|
|
+ disableHopperMoveEvents = getBoolean("hopper.disable-move-event", disableHopperMoveEvents);
|
|
+ log("Hopper Move Item Events: " + (disableHopperMoveEvents ? "disabled" : "enabled"));
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/IHopper.java b/src/main/java/net/minecraft/server/IHopper.java
|
|
index b548ab8b7eb7e3c8a455f4653c30ea1610f268e8..187000f1e49f6609267b00f69fe2d266ea6b9255 100644
|
|
--- a/src/main/java/net/minecraft/server/IHopper.java
|
|
+++ b/src/main/java/net/minecraft/server/IHopper.java
|
|
@@ -12,12 +12,13 @@ public interface IHopper extends IInventory {
|
|
return IHopper.c;
|
|
}
|
|
|
|
- @Nullable
|
|
+ //@Nullable // Paper - it's annoying
|
|
World getWorld();
|
|
+ default BlockPosition getBlockPosition() { return new BlockPosition(getX(), getY(), getZ()); } // Paper
|
|
|
|
- double x();
|
|
+ double x(); default double getX() { return this.x(); } // Paper - OBFHELPER
|
|
|
|
- double z();
|
|
+ double z(); default double getY() { return this.z(); } // Paper - OBFHELPER
|
|
|
|
- double A();
|
|
+ double A(); default double getZ() { return this.A(); } // Paper - OBFHELPER
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/ItemStack.java b/src/main/java/net/minecraft/server/ItemStack.java
|
|
index 63aa474c73f506737cb5de31977bffcd17d4dc11..b6703378e21a6cd7e140fd35756a20d47f49ed31 100644
|
|
--- a/src/main/java/net/minecraft/server/ItemStack.java
|
|
+++ b/src/main/java/net/minecraft/server/ItemStack.java
|
|
@@ -486,11 +486,12 @@ public final class ItemStack {
|
|
return this.getItem().a(this, entityhuman, entityliving, enumhand);
|
|
}
|
|
|
|
- public ItemStack cloneItemStack() {
|
|
- if (this.isEmpty()) {
|
|
+ public ItemStack cloneItemStack() { return cloneItemStack(false); } // Paper
|
|
+ public ItemStack cloneItemStack(boolean origItem) { // Paper
|
|
+ if (!origItem && this.isEmpty()) { // Paper
|
|
return ItemStack.b;
|
|
} else {
|
|
- ItemStack itemstack = new ItemStack(this.getItem(), this.count);
|
|
+ ItemStack itemstack = new ItemStack(origItem ? this.item : this.getItem(), this.count); // Paper
|
|
|
|
itemstack.d(this.D());
|
|
if (this.tag != null) {
|
|
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
index bdcbc2a05714c37fc034ddbfd0166efbeff1c4ac..9290d6c84e764bf691d9222723d73209a3d9ae2e 100644
|
|
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
|
|
@@ -1245,6 +1245,7 @@ public abstract class MinecraftServer extends IAsyncTaskHandlerReentrant<TickTas
|
|
while (iterator.hasNext()) {
|
|
WorldServer worldserver = (WorldServer) iterator.next();
|
|
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper
|
|
+ TileEntityHopper.skipHopperEvents = worldserver.paperConfig.disableHopperMoveEvents || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper
|
|
|
|
this.methodProfiler.a(() -> {
|
|
return worldserver + " " + worldserver.getDimensionKey().a();
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntity.java b/src/main/java/net/minecraft/server/TileEntity.java
|
|
index 6ccca984daa803ddf446a8f69aca0d86ee27fabc..e48fbf6280e107ab3a288f9099373df0fd6fccbd 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntity.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntity.java
|
|
@@ -62,6 +62,7 @@ public abstract class TileEntity implements KeyedObject { // Paper
|
|
public void setCurrentChunk(Chunk chunk) {
|
|
this.currentChunk = chunk != null ? new java.lang.ref.WeakReference<>(chunk) : null;
|
|
}
|
|
+ static boolean IGNORE_TILE_UPDATES = false;
|
|
// Paper end
|
|
|
|
@Nullable
|
|
@@ -140,6 +141,7 @@ public abstract class TileEntity implements KeyedObject { // Paper
|
|
|
|
public void update() {
|
|
if (this.world != null) {
|
|
+ if (IGNORE_TILE_UPDATES) return; // Paper
|
|
this.c = this.world.getType(this.position);
|
|
this.world.b(this.position, this);
|
|
if (!this.c.isAir()) {
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
index 4398f452c52182694c5e2c0945fe70ca32cb0dfd..d432de40eba2767f4ced4d9c642c9d2033acd0ea 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
@@ -168,6 +168,160 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
return false;
|
|
}
|
|
|
|
+ // Paper start - Optimize Hoppers
|
|
+ private static boolean skipPullModeEventFire = false;
|
|
+ private static boolean skipPushModeEventFire = false;
|
|
+ static boolean skipHopperEvents = false;
|
|
+
|
|
+ private boolean hopperPush(IInventory iinventory, EnumDirection enumdirection) {
|
|
+ skipPushModeEventFire = skipHopperEvents;
|
|
+ boolean foundItem = false;
|
|
+ for (int i = 0; i < this.getSize(); ++i) {
|
|
+ ItemStack item = this.getItem(i);
|
|
+ if (!item.isEmpty()) {
|
|
+ foundItem = true;
|
|
+ ItemStack origItemStack = item;
|
|
+ ItemStack itemstack = origItemStack;
|
|
+
|
|
+ final int origCount = origItemStack.getCount();
|
|
+ final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
|
|
+ origItemStack.setCount(moved);
|
|
+
|
|
+ // 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) {
|
|
+ itemstack = callPushMoveEvent(iinventory, itemstack);
|
|
+ if (itemstack == null) { // cancelled
|
|
+ origItemStack.setCount(origCount);
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ final ItemStack itemstack2 = addItem(this, iinventory, itemstack, enumdirection);
|
|
+ final int remaining = itemstack2.getCount();
|
|
+ if (remaining != moved) {
|
|
+ origItemStack = origItemStack.cloneItemStack(true);
|
|
+ origItemStack.setCount(origCount);
|
|
+ if (!origItemStack.isEmpty()) {
|
|
+ origItemStack.setCount(origCount - moved + remaining);
|
|
+ }
|
|
+ this.setItem(i, origItemStack);
|
|
+ iinventory.update();
|
|
+ return true;
|
|
+ }
|
|
+ origItemStack.setCount(origCount);
|
|
+ }
|
|
+ }
|
|
+ if (foundItem && world.paperConfig.cooldownHopperWhenFull) { // Inventory was full - cooldown
|
|
+ this.setCooldown(world.spigotConfig.hopperTransfer);
|
|
+ }
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ private static boolean hopperPull(IHopper ihopper, IInventory iinventory, ItemStack origItemStack, int i) {
|
|
+ ItemStack itemstack = origItemStack;
|
|
+ final int origCount = origItemStack.getCount();
|
|
+ final World world = ihopper.getWorld();
|
|
+ final int moved = Math.min(world.spigotConfig.hopperAmount, origCount);
|
|
+ itemstack.setCount(moved);
|
|
+
|
|
+ if (!skipPullModeEventFire) {
|
|
+ itemstack = callPullMoveEvent(ihopper, iinventory, itemstack);
|
|
+ if (itemstack == null) { // cancelled
|
|
+ origItemStack.setCount(origCount);
|
|
+ // 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;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ final ItemStack itemstack2 = addItem(iinventory, ihopper, itemstack, null);
|
|
+ final int remaining = itemstack2.getCount();
|
|
+ if (remaining != moved) {
|
|
+ origItemStack = origItemStack.cloneItemStack(true);
|
|
+ origItemStack.setCount(origCount);
|
|
+ if (!origItemStack.isEmpty()) {
|
|
+ origItemStack.setCount(origCount - moved + remaining);
|
|
+ }
|
|
+ IGNORE_TILE_UPDATES = true;
|
|
+ iinventory.setItem(i, origItemStack);
|
|
+ IGNORE_TILE_UPDATES = false;
|
|
+ iinventory.update();
|
|
+ return true;
|
|
+ }
|
|
+ origItemStack.setCount(origCount);
|
|
+
|
|
+ if (world.paperConfig.cooldownHopperWhenFull) {
|
|
+ cooldownHopper(ihopper);
|
|
+ }
|
|
+
|
|
+ return false;
|
|
+ }
|
|
+
|
|
+ private ItemStack callPushMoveEvent(IInventory iinventory, ItemStack itemstack) {
|
|
+ Inventory destinationInventory = getInventory(iinventory);
|
|
+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(this.getOwner(false).getInventory(),
|
|
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true);
|
|
+ boolean result = event.callEvent();
|
|
+ if (!event.calledGetItem && !event.calledSetItem) {
|
|
+ skipPushModeEventFire = true;
|
|
+ }
|
|
+ if (!result) {
|
|
+ cooldownHopper(this);
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (event.calledSetItem) {
|
|
+ return CraftItemStack.asNMSCopy(event.getItem());
|
|
+ } else {
|
|
+ return itemstack;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static ItemStack callPullMoveEvent(IHopper hopper, IInventory iinventory, ItemStack itemstack) {
|
|
+ Inventory sourceInventory = getInventory(iinventory);
|
|
+ Inventory destination = getInventory(hopper);
|
|
+
|
|
+ InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory,
|
|
+ // Mirror is safe as we no plugins ever use this item
|
|
+ CraftItemStack.asCraftMirror(itemstack), destination, false);
|
|
+ boolean result = event.callEvent();
|
|
+ if (!event.calledGetItem && !event.calledSetItem) {
|
|
+ skipPullModeEventFire = true;
|
|
+ }
|
|
+ if (!result) {
|
|
+ cooldownHopper(hopper);
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ if (event.calledSetItem) {
|
|
+ return CraftItemStack.asNMSCopy(event.getItem());
|
|
+ } else {
|
|
+ return itemstack;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private static Inventory getInventory(IInventory iinventory) {
|
|
+ Inventory sourceInventory;// Have to special case large chests as they work oddly
|
|
+ if (iinventory instanceof InventoryLargeChest) {
|
|
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((InventoryLargeChest) iinventory);
|
|
+ } else if (iinventory instanceof TileEntity) {
|
|
+ sourceInventory = ((TileEntity) iinventory).getOwner(false).getInventory();
|
|
+ } else {
|
|
+ sourceInventory = iinventory.getOwner().getInventory();
|
|
+ }
|
|
+ return sourceInventory;
|
|
+ }
|
|
+
|
|
+ private static void cooldownHopper(IHopper hopper) {
|
|
+ if (hopper instanceof TileEntityHopper) {
|
|
+ ((TileEntityHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer);
|
|
+ } else if (hopper instanceof EntityMinecartHopper) {
|
|
+ ((EntityMinecartHopper) hopper).setCooldown(hopper.getWorld().spigotConfig.hopperTransfer / 2);
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
private boolean k() {
|
|
IInventory iinventory = this.l();
|
|
|
|
@@ -179,6 +333,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
if (this.b(iinventory, enumdirection)) {
|
|
return false;
|
|
} else {
|
|
+ return hopperPush(iinventory, enumdirection); /* // Paper - disable rest
|
|
for (int i = 0; i < this.getSize(); ++i) {
|
|
if (!this.getItem(i).isEmpty()) {
|
|
ItemStack itemstack = this.getItem(i).cloneItemStack();
|
|
@@ -216,7 +371,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
|
|
- return false;
|
|
+ return false;*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
|
}
|
|
}
|
|
}
|
|
@@ -225,18 +380,54 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
return iinventory instanceof IWorldInventory ? IntStream.of(((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) : IntStream.range(0, iinventory.getSize());
|
|
}
|
|
|
|
- private boolean b(IInventory iinventory, EnumDirection enumdirection) {
|
|
- return a(iinventory, enumdirection).allMatch((i) -> {
|
|
- ItemStack itemstack = iinventory.getItem(i);
|
|
+ private static boolean allMatch(IInventory iinventory, EnumDirection enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
|
+ if (iinventory instanceof IWorldInventory) {
|
|
+ for (int i : ((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) {
|
|
+ if (!test.test(iinventory.getItem(i), i)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ int size = iinventory.getSize();
|
|
+ for (int i = 0; i < size; i++) {
|
|
+ if (!test.test(iinventory.getItem(i), i)) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ return true;
|
|
+ }
|
|
|
|
- return itemstack.getCount() >= itemstack.getMaxStackSize();
|
|
- });
|
|
+ private static boolean anyMatch(IInventory iinventory, EnumDirection enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) {
|
|
+ if (iinventory instanceof IWorldInventory) {
|
|
+ for (int i : ((IWorldInventory) iinventory).getSlotsForFace(enumdirection)) {
|
|
+ if (test.test(iinventory.getItem(i), i)) {
|
|
+ return true;
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ int size = iinventory.getSize();
|
|
+ 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();
|
|
+
|
|
+ // Paper end
|
|
+
|
|
+ private boolean b(IInventory iinventory, EnumDirection enumdirection) {
|
|
+ // Paper start - no streams
|
|
+ return allMatch(iinventory, enumdirection, STACK_SIZE_TEST);
|
|
+ // Paper end
|
|
}
|
|
|
|
private static boolean c(IInventory iinventory, EnumDirection enumdirection) {
|
|
- return a(iinventory, enumdirection).allMatch((i) -> {
|
|
- return iinventory.getItem(i).isEmpty();
|
|
- });
|
|
+ return allMatch(iinventory, enumdirection, IS_EMPTY_TEST);
|
|
}
|
|
|
|
public static boolean a(IHopper ihopper) {
|
|
@@ -245,9 +436,17 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
if (iinventory != null) {
|
|
EnumDirection enumdirection = EnumDirection.DOWN;
|
|
|
|
- return c(iinventory, enumdirection) ? false : a(iinventory, enumdirection).anyMatch((i) -> {
|
|
- return a(ihopper, iinventory, i, enumdirection);
|
|
+ // Paper start - optimize hoppers and remove streams
|
|
+ skipPullModeEventFire = skipHopperEvents;
|
|
+ return !c(iinventory, enumdirection) && anyMatch(iinventory, enumdirection, (item, i) -> {
|
|
+ // Logic copied from below to avoid extra getItem calls
|
|
+ if (!item.isEmpty() && canTakeItem(iinventory, item, i, enumdirection)) {
|
|
+ return hopperPull(ihopper, iinventory, item, i);
|
|
+ } else {
|
|
+ return false;
|
|
+ }
|
|
});
|
|
+ // Paper end
|
|
} else {
|
|
Iterator iterator = c(ihopper).iterator();
|
|
|
|
@@ -265,10 +464,11 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
|
|
- private static boolean a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection) {
|
|
+ private static boolean a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection) {// Paper - method unused as logic is inlined above
|
|
ItemStack itemstack = iinventory.getItem(i);
|
|
|
|
- if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) {
|
|
+ if (!itemstack.isEmpty() && b(iinventory, itemstack, i, enumdirection)) { // If this logic changes, update above. this is left inused incase reflective plugins
|
|
+ return hopperPull(ihopper, iinventory, itemstack, i); /* // Paper - disable rest
|
|
ItemStack itemstack1 = itemstack.cloneItemStack();
|
|
// ItemStack itemstack2 = addItem(iinventory, ihopper, iinventory.splitStack(i, 1), (EnumDirection) null);
|
|
// CraftBukkit start - Call event on collection of items from inventories into the hopper
|
|
@@ -305,7 +505,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
|
|
itemstack1.subtract(origCount - itemstack2.getCount()); // Spigot
|
|
- iinventory.setItem(i, itemstack1);
|
|
+ iinventory.setItem(i, itemstack1);*/ // Paper - end commenting out replaced block for Hopper Optimizations
|
|
}
|
|
|
|
return false;
|
|
@@ -314,7 +514,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
public static boolean a(IInventory iinventory, EntityItem entityitem) {
|
|
boolean flag = false;
|
|
// CraftBukkit start
|
|
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(iinventory.getOwner().getInventory(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
|
|
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(iinventory), (org.bukkit.entity.Item) entityitem.getBukkitEntity()); // Paper - use getInventory() to avoid snapshot creation
|
|
entityitem.world.getServer().getPluginManager().callEvent(event);
|
|
if (event.isCancelled()) {
|
|
return false;
|
|
@@ -356,6 +556,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
return !iinventory.b(i, itemstack) ? false : !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canPlaceItemThroughFace(i, itemstack, enumdirection);
|
|
}
|
|
|
|
+ private static boolean canTakeItem(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) { return b(iinventory, itemstack, i, enumdirection); } // Paper - OBFHELPER
|
|
private static boolean b(IInventory iinventory, ItemStack itemstack, int i, EnumDirection enumdirection) {
|
|
return !(iinventory instanceof IWorldInventory) || ((IWorldInventory) iinventory).canTakeItemThroughFace(i, itemstack, enumdirection);
|
|
}
|
|
@@ -368,7 +569,9 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
boolean flag1 = iinventory1.isEmpty();
|
|
|
|
if (itemstack1.isEmpty()) {
|
|
+ IGNORE_TILE_UPDATES = true; // Paper
|
|
iinventory1.setItem(i, itemstack);
|
|
+ IGNORE_TILE_UPDATES = false; // Paper
|
|
itemstack = ItemStack.b;
|
|
flag = true;
|
|
} else if (a(itemstack1, itemstack)) {
|
|
@@ -419,18 +622,24 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
|
|
public static List<EntityItem> c(IHopper ihopper) {
|
|
- return (List) ihopper.aa_().d().stream().flatMap((axisalignedbb) -> {
|
|
- return ihopper.getWorld().a(EntityItem.class, axisalignedbb.d(ihopper.x() - 0.5D, ihopper.z() - 0.5D, ihopper.A() - 0.5D), IEntitySelector.a).stream();
|
|
- }).collect(Collectors.toList());
|
|
+ // Paper start - Optimize item suck in. remove streams, restore 1.12 checks. Seriously checking the bowl?!
|
|
+ World world = ihopper.getWorld();
|
|
+ double d0 = ihopper.getX();
|
|
+ double d1 = ihopper.getY();
|
|
+ double d2 = ihopper.getZ();
|
|
+ AxisAlignedBB bb = new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D);
|
|
+ return world.getEntities(EntityItem.class, bb, Entity::isAlive);
|
|
+ // Paper end
|
|
}
|
|
|
|
@Nullable
|
|
public static IInventory b(World world, BlockPosition blockposition) {
|
|
- return a(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D);
|
|
+ return a(world, (double) blockposition.getX() + 0.5D, (double) blockposition.getY() + 0.5D, (double) blockposition.getZ() + 0.5D, true); // Paper
|
|
}
|
|
|
|
@Nullable
|
|
- public static IInventory a(World world, double d0, double d1, double d2) {
|
|
+ public static IInventory a(World world, double d0, double d1, double d2) { return a(world, d0, d1, d2, false); } // Paper - overload to default false
|
|
+ public static IInventory a(World world, double d0, double d1, double d2, boolean optimizeEntities) { // Paper
|
|
Object object = null;
|
|
BlockPosition blockposition = new BlockPosition(d0, d1, d2);
|
|
if ( !world.isLoaded( blockposition ) ) return null; // Spigot
|
|
@@ -450,7 +659,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
|
|
- if (object == null) {
|
|
+ if (object == null && (!optimizeEntities || !org.bukkit.craftbukkit.util.CraftMagicNumbers.getMaterial(block).isOccluding())) { // Paper
|
|
List<Entity> list = world.getEntities((Entity) null, new AxisAlignedBB(d0 - 0.5D, d1 - 0.5D, d2 - 0.5D, d0 + 0.5D, d1 + 0.5D, d2 + 0.5D), IEntitySelector.d);
|
|
|
|
if (!list.isEmpty()) {
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntityLootable.java b/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
index c6e6c54a3eb5d725b71f2ec2bb27dd8e2aceabde..c79ebe2343cc14f113c0cc6496c20e7d7bf6fd32 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntityLootable.java
|
|
@@ -77,12 +77,19 @@ public abstract class TileEntityLootable extends TileEntityContainer {
|
|
@Override
|
|
public boolean isEmpty() {
|
|
this.d((EntityHuman) null);
|
|
- return this.f().stream().allMatch(ItemStack::isEmpty);
|
|
+ // Paper start
|
|
+ for (ItemStack itemStack : this.f()) {
|
|
+ if (!itemStack.isEmpty()) {
|
|
+ return false;
|
|
+ }
|
|
+ }
|
|
+ // Paper end
|
|
+ return true;
|
|
}
|
|
|
|
@Override
|
|
public ItemStack getItem(int i) {
|
|
- this.d((EntityHuman) null);
|
|
+ if (i == 0) this.d((EntityHuman) null); // Paper
|
|
return (ItemStack) this.f().get(i);
|
|
}
|
|
|
|
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
|
index ab5bf1ea0413cd947204794017b02a52cb601507..3db488d602dde2ba5dcd324ad38b19edd24e9285 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -1099,8 +1099,8 @@ public abstract class World implements GeneratorAccess, AutoCloseable {
|
|
return list;
|
|
}
|
|
|
|
- @Override
|
|
- public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super T> predicate) {
|
|
+ public <T extends Entity> List<T> getEntities(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super T> predicate) { return a(oclass, axisalignedbb, predicate); } // Paper - OBFHELPER
|
|
+ @Override public <T extends Entity> List<T> a(Class<? extends T> oclass, AxisAlignedBB axisalignedbb, @Nullable Predicate<? super T> predicate) {
|
|
this.getMethodProfiler().c("getEntities");
|
|
int i = MathHelper.floor((axisalignedbb.minX - 2.0D) / 16.0D);
|
|
int j = MathHelper.f((axisalignedbb.maxX + 2.0D) / 16.0D);
|