mirror of
https://github.com/PaperMC/Paper.git
synced 2024-12-30 16:19:03 +01:00
3d9d0a7227
- 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
381 lines
No EOL
17 KiB
Diff
381 lines
No EOL
17 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: Techcable <Techcable@outlook.com>
|
|
Date: Sat, 18 Jun 2016 01:01:37 -0500
|
|
Subject: [PATCH] Make entities look for hoppers
|
|
|
|
Every tick hoppers try and find an block-inventory to extract from.
|
|
If no tile entity is above the hopper (which there often isn't) it will do a bounding box search for minecart chests and minecart hoppers.
|
|
If it can't find an inventory, it will then look for a dropped item, which is another bounding box search.
|
|
This patch eliminates that expensive check by having dropped items and minecart hoppers/chests look for hoppers instead.
|
|
Hoppers are tile entities meaning you can do a simple tile entity lookup to find the nearest hopper in range.
|
|
Pushing out of hoppers causes a bouding box lookup, which this patch replaces with a tile entity lookup.
|
|
|
|
This patch may causes a decrease in the performance of dropped items, which is why it can be disabled in the configuration.
|
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/HopperPusher.java b/src/main/java/com/destroystokyo/paper/HopperPusher.java
|
|
new file mode 100644
|
|
index 000000000..52457e3d8
|
|
--- /dev/null
|
|
+++ b/src/main/java/com/destroystokyo/paper/HopperPusher.java
|
|
@@ -0,0 +0,0 @@
|
|
+package com.destroystokyo.paper;
|
|
+
|
|
+import net.minecraft.server.AxisAlignedBB;
|
|
+import net.minecraft.server.BlockPosition;
|
|
+import net.minecraft.server.MCUtil;
|
|
+import net.minecraft.server.TileEntityHopper;
|
|
+import net.minecraft.server.World;
|
|
+
|
|
+public interface HopperPusher {
|
|
+
|
|
+ default TileEntityHopper findHopper() {
|
|
+ BlockPosition pos = new BlockPosition(getX(), getY(), getZ());
|
|
+ int startX = pos.getX() - 1;
|
|
+ int endX = pos.getX() + 1;
|
|
+ int startY = Math.max(0, pos.getY() - 1);
|
|
+ int endY = Math.min(255, pos.getY() + 1);
|
|
+ int startZ = pos.getZ() - 1;
|
|
+ int endZ = pos.getZ() + 1;
|
|
+ BlockPosition.PooledBlockPosition adjacentPos = BlockPosition.PooledBlockPosition.aquire();
|
|
+ for (int x = startX; x <= endX; x++) {
|
|
+ for (int y = startY; y <= endY; y++) {
|
|
+ for (int z = startZ; z <= endZ; z++) {
|
|
+ adjacentPos.setValues(x, y, z);
|
|
+ TileEntityHopper hopper = MCUtil.getHopper(getWorld(), adjacentPos);
|
|
+ if (hopper == null) continue; // Avoid playing with the bounding boxes, if at all possible
|
|
+ AxisAlignedBB hopperBoundingBox = hopper.getHopperLookupBoundingBox();
|
|
+ /*
|
|
+ * Check if the entity's bounding box intersects with the hopper's lookup box.
|
|
+ * This operation doesn't work both ways!
|
|
+ * Make sure you check if the entity's box intersects the hopper's box, not vice versa!
|
|
+ */
|
|
+ AxisAlignedBB boundingBox = this.getBoundingBox().shrink(0.1); // Imitate vanilla behavior
|
|
+ if (boundingBox.intersects(hopperBoundingBox)) {
|
|
+ return hopper;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ adjacentPos.free();
|
|
+ return null;
|
|
+ }
|
|
+
|
|
+ boolean acceptItem(TileEntityHopper hopper);
|
|
+
|
|
+ default boolean tryPutInHopper() {
|
|
+ if (!getWorld().paperConfig.isHopperPushBased) return false;
|
|
+ TileEntityHopper hopper = findHopper();
|
|
+ return hopper != null && hopper.canAcceptItems() && acceptItem(hopper);
|
|
+ }
|
|
+
|
|
+ AxisAlignedBB getBoundingBox();
|
|
+
|
|
+ World getWorld();
|
|
+
|
|
+ double getX();
|
|
+
|
|
+ double getY();
|
|
+
|
|
+ double getZ();
|
|
+}
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
index 600e603bd..ce43e7bb7 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -0,0 +0,0 @@ public class PaperWorldConfig {
|
|
private void altFallingBlockOnGround() {
|
|
altFallingBlockOnGround = getBoolean("use-alternate-fallingblock-onGround-detection", false);
|
|
}
|
|
+
|
|
+ public boolean isHopperPushBased;
|
|
+ private void isHopperPushBased() {
|
|
+ isHopperPushBased = getBoolean("hopper.push-based", false);
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/AxisAlignedBB.java b/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
|
index 1eb9c2da8..c88b76a79 100644
|
|
--- a/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
|
+++ b/src/main/java/net/minecraft/server/AxisAlignedBB.java
|
|
@@ -0,0 +0,0 @@ public class AxisAlignedBB {
|
|
}
|
|
}
|
|
|
|
+ public final boolean intersects(AxisAlignedBB intersecting) { return this.c(intersecting); } // Paper - OBFHELPER
|
|
public boolean c(AxisAlignedBB axisalignedbb) {
|
|
return this.a(axisalignedbb.a, axisalignedbb.b, axisalignedbb.c, axisalignedbb.d, axisalignedbb.e, axisalignedbb.f);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
|
|
index 008ed206d..b3c1f550c 100644
|
|
--- a/src/main/java/net/minecraft/server/BlockPosition.java
|
|
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
|
|
@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition {
|
|
super(i, j, k);
|
|
}
|
|
|
|
+ public static BlockPosition.PooledBlockPosition aquire() { return s(); } // Paper - OBFHELPER
|
|
public static BlockPosition.PooledBlockPosition s() {
|
|
return e(0, 0, 0);
|
|
}
|
|
@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition {
|
|
return new BlockPosition.PooledBlockPosition(i, j, k);
|
|
}
|
|
|
|
+ public void free() { t(); } // Paper - OBFHELPER
|
|
public void t() {
|
|
List list = BlockPosition.PooledBlockPosition.g;
|
|
|
|
@@ -0,0 +0,0 @@ public class BlockPosition extends BaseBlockPosition {
|
|
return this.d;
|
|
}
|
|
|
|
+ public void setValues(int x, int y, int z) { c(x, y, z); } // Paper - OBFHELPER
|
|
public BlockPosition.MutableBlockPosition c(int i, int j, int k) {
|
|
this.b = i;
|
|
this.c = j;
|
|
diff --git a/src/main/java/net/minecraft/server/Entity.java b/src/main/java/net/minecraft/server/Entity.java
|
|
index d46fb1d76..9ab892876 100644
|
|
--- a/src/main/java/net/minecraft/server/Entity.java
|
|
+++ b/src/main/java/net/minecraft/server/Entity.java
|
|
@@ -0,0 +0,0 @@ public abstract class Entity implements ICommandListener {
|
|
public double locX;
|
|
public double locY;
|
|
public double locZ;
|
|
+ // Paper start - getters to implement HopperPusher
|
|
+ public double getX() {
|
|
+ return locX;
|
|
+ }
|
|
+
|
|
+ public double getY() {
|
|
+ return locY;
|
|
+ }
|
|
+
|
|
+ public double getZ() {
|
|
+ return locZ;
|
|
+ }
|
|
+ // Paper end
|
|
public double motX;
|
|
public double motY;
|
|
public double motZ;
|
|
diff --git a/src/main/java/net/minecraft/server/EntityItem.java b/src/main/java/net/minecraft/server/EntityItem.java
|
|
index 4d3aef96b..6593fc633 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityItem.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityItem.java
|
|
@@ -0,0 +0,0 @@ import org.apache.logging.log4j.Logger;
|
|
import org.bukkit.event.entity.EntityPickupItemEvent;
|
|
import org.bukkit.event.player.PlayerPickupItemEvent;
|
|
// CraftBukkit end
|
|
+import com.destroystokyo.paper.HopperPusher; // Paper
|
|
|
|
-public class EntityItem extends Entity {
|
|
+// Paper start - implement HopperPusher
|
|
+public class EntityItem extends Entity implements HopperPusher {
|
|
+ @Override
|
|
+ public boolean acceptItem(TileEntityHopper hopper) {
|
|
+ return TileEntityHopper.putDropInInventory(null, hopper, this);
|
|
+ }
|
|
+// Paper end
|
|
|
|
private static final Logger b = LogManager.getLogger();
|
|
private static final DataWatcherObject<ItemStack> c = DataWatcher.a(EntityItem.class, DataWatcherRegistry.f);
|
|
@@ -0,0 +0,0 @@ public class EntityItem extends Entity {
|
|
this.die();
|
|
} else {
|
|
super.B_();
|
|
+ if (tryPutInHopper()) return; // Paper
|
|
// CraftBukkit start - Use wall time for pickup and despawn timers
|
|
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
|
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
|
@@ -0,0 +0,0 @@ public class EntityItem extends Entity {
|
|
// Spigot start - copied from above
|
|
@Override
|
|
public void inactiveTick() {
|
|
+ if (tryPutInHopper()) return; // Paper
|
|
// CraftBukkit start - Use wall time for pickup and despawn timers
|
|
int elapsedTicks = MinecraftServer.currentTick - this.lastTick;
|
|
if (this.pickupDelay != 32767) this.pickupDelay -= elapsedTicks;
|
|
diff --git a/src/main/java/net/minecraft/server/EntityMinecartContainer.java b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
index 50d7d34b8..15f392d23 100644
|
|
--- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
+++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
|
|
@@ -0,0 +0,0 @@ import javax.annotation.Nullable;
|
|
import java.util.List;
|
|
import org.bukkit.Location;
|
|
|
|
+import com.destroystokyo.paper.HopperPusher; // Paper
|
|
import com.destroystokyo.paper.loottable.CraftLootableInventoryData; // Paper
|
|
import com.destroystokyo.paper.loottable.CraftLootableInventory; // Paper
|
|
import com.destroystokyo.paper.loottable.LootableInventory; // Paper
|
|
@@ -0,0 +0,0 @@ import org.bukkit.entity.HumanEntity;
|
|
import org.bukkit.inventory.InventoryHolder;
|
|
// CraftBukkit end
|
|
|
|
-public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable, CraftLootableInventory { // Paper
|
|
+// Paper start - push into hoppers
|
|
+public abstract class EntityMinecartContainer extends EntityMinecartAbstract implements ITileInventory, ILootable, CraftLootableInventory, HopperPusher { // Paper - CraftLootableInventory
|
|
+ @Override
|
|
+ public boolean acceptItem(TileEntityHopper hopper) {
|
|
+ return TileEntityHopper.acceptItem(hopper, this);
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void B_() {
|
|
+ super.B_();
|
|
+ tryPutInHopper();
|
|
+ }
|
|
+
|
|
+ @Override
|
|
+ public void inactiveTick() {
|
|
+ super.inactiveTick();
|
|
+ tryPutInHopper();
|
|
+ }
|
|
+ // Paper end
|
|
|
|
private NonNullList<ItemStack> items;
|
|
private boolean b;
|
|
diff --git a/src/main/java/net/minecraft/server/IHopper.java b/src/main/java/net/minecraft/server/IHopper.java
|
|
index 804215a1c..e830d8390 100644
|
|
--- a/src/main/java/net/minecraft/server/IHopper.java
|
|
+++ b/src/main/java/net/minecraft/server/IHopper.java
|
|
@@ -0,0 +0,0 @@ public interface IHopper extends IInventory {
|
|
|
|
World getWorld();
|
|
|
|
- double E();
|
|
+ double E(); default double getX() { return E(); } // Paper - OBFHELPER
|
|
|
|
- double F();
|
|
+ double F(); default double getY() { return F(); } // Paper - OBFHELPER
|
|
|
|
- double G();
|
|
+ double G(); default double getZ() { return G(); } // Paper - OBFHELPER
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/TileEntityHopper.java b/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
index 985513511..e9315f2d5 100644
|
|
--- a/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
|
|
private boolean o() {
|
|
+ mayAcceptItems = false; // Paper - at the beginning of a tick, assume we can't accept items
|
|
if (this.world != null && !this.world.isClientSide) {
|
|
if (!this.J() && BlockHopper.f(this.v())) {
|
|
boolean flag = false;
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
|
|
if (!this.r()) {
|
|
+ mayAcceptItems = true; // Paper - flag this hopper to be able to accept items
|
|
flag = a((IHopper) this) || flag;
|
|
}
|
|
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
|
|
+ // Paper start
|
|
+ private boolean mayAcceptItems = false;
|
|
+
|
|
+ public boolean canAcceptItems() {
|
|
+ return mayAcceptItems;
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
private boolean p() {
|
|
Iterator iterator = this.items.iterator();
|
|
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
return true;
|
|
}
|
|
|
|
+ // Paper start - split methods, and only do entity lookup if in pull mode
|
|
public static boolean a(IHopper ihopper) {
|
|
- IInventory iinventory = b(ihopper);
|
|
+ IInventory iinventory = getInventory(ihopper, !(ihopper instanceof TileEntityHopper) || !ihopper.getWorld().paperConfig.isHopperPushBased);
|
|
+
|
|
+ return acceptItem(ihopper, iinventory);
|
|
+ }
|
|
+
|
|
+ public static boolean acceptItem(IHopper ihopper, IInventory iinventory) {
|
|
+ // Paper end
|
|
|
|
if (iinventory != null) {
|
|
EnumDirection enumdirection = EnumDirection.DOWN;
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
}
|
|
- } else {
|
|
- Iterator iterator = a(ihopper.getWorld(), ihopper.E(), ihopper.F(), ihopper.G()).iterator();
|
|
+ } else if (!ihopper.getWorld().paperConfig.isHopperPushBased || !(ihopper instanceof TileEntityHopper)) { // Paper - only search for entities in 'pull mode'
|
|
+ Iterator iterator = a(ihopper.getWorld(), ihopper.E(), ihopper.F(), ihopper.G()).iterator(); // Change getHopperLookupBoundingBox() if this ever changes
|
|
|
|
while (iterator.hasNext()) {
|
|
EntityItem entityitem = (EntityItem) iterator.next();
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
return false;
|
|
}
|
|
|
|
+ public static boolean putDropInInventory(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) { return a(iinventory, iinventory1, entityitem); } // Paper - OBFHELPER
|
|
public static boolean a(IInventory iinventory, IInventory iinventory1, EntityItem entityitem) {
|
|
boolean flag = false;
|
|
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
private IInventory I() {
|
|
EnumDirection enumdirection = BlockHopper.b(this.v());
|
|
|
|
- return b(this.getWorld(), this.E() + (double) enumdirection.getAdjacentX(), this.F() + (double) enumdirection.getAdjacentY(), this.G() + (double) enumdirection.getAdjacentZ());
|
|
+ // Paper start - don't search for entities in push mode
|
|
+ World world = getWorld();
|
|
+ return getInventory(world, this.E() + (double) enumdirection.getAdjacentX(), this.F() + (double) enumdirection.getAdjacentY(), this.G() + (double) enumdirection.getAdjacentZ(), !world.paperConfig.isHopperPushBased);
|
|
+ // Paper end
|
|
}
|
|
|
|
- public static IInventory b(IHopper ihopper) {
|
|
- return b(ihopper.getWorld(), ihopper.E(), ihopper.F() + 1.0D, ihopper.G());
|
|
+ // Paper start - add option to search for entities
|
|
+ public static IInventory b(IHopper hopper) {
|
|
+ return getInventory(hopper, true);
|
|
+ }
|
|
+
|
|
+ public static IInventory getInventory(IHopper ihopper, boolean searchForEntities) {
|
|
+ return getInventory(ihopper.getWorld(), ihopper.E(), ihopper.F() + 1.0D, ihopper.G(), searchForEntities);
|
|
+ // Paper end
|
|
}
|
|
|
|
public static List<EntityItem> a(World world, double d0, double d1, double d2) {
|
|
- return world.a(EntityItem.class, new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D), IEntitySelector.a);
|
|
+ return world.a(EntityItem.class, new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D), IEntitySelector.a); // Change getHopperLookupBoundingBox(double, double, double) if the bounding box calculation is ever changed
|
|
+ }
|
|
+
|
|
+ // Paper start
|
|
+ public AxisAlignedBB getHopperLookupBoundingBox() {
|
|
+ return getHopperLookupBoundingBox(this.getX(), this.getY(), this.getZ());
|
|
}
|
|
|
|
+ private static AxisAlignedBB getHopperLookupBoundingBox(double d0, double d1, double d2) {
|
|
+ // Change this if a(World, double, double, double) above ever changes
|
|
+ return new AxisAlignedBB(d0 - 0.5D, d1, d2 - 0.5D, d0 + 0.5D, d1 + 1.5D, d2 + 0.5D);
|
|
+ }
|
|
+ // Paper end
|
|
+
|
|
+ // Paper start - add option to searchForEntities
|
|
public static IInventory b(World world, double d0, double d1, double d2) {
|
|
+ return getInventory(world, d0, d1, d2, true);
|
|
+ }
|
|
+
|
|
+ public static IInventory getInventory(World world, double d0, double d1, double d2, boolean searchForEntities) {
|
|
+ // Paper end
|
|
Object object = null;
|
|
int i = MathHelper.floor(d0);
|
|
int j = MathHelper.floor(d1);
|
|
@@ -0,0 +0,0 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
|
|
}
|
|
}
|
|
|
|
- if (object == null) {
|
|
+ if (object == null && searchForEntities) { // Paper - only if searchForEntities
|
|
List 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.c);
|
|
|
|
if (!list.isEmpty()) {
|
|
--
|