Paper/Spigot-Server-Patches/0161-Make-entities-look-for-hoppers.patch
Aikar 3faaaab75d Optimize isInvalidYLocation, getType and getBlockData
Some pretty micro optimizations, but this is the hottest method in the server....

This will drastically reduce number of operations to perform getType

the 2 previous patches was squashed into 1
2016-06-22 22:43:02 -04:00

363 lines
16 KiB
Diff

From 002cc7e522a849abd35c3f69170c669965d89125 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 0000000..5ff43e2
--- /dev/null
+++ b/src/main/java/com/destroystokyo/paper/HopperPusher.java
@@ -0,0 +1,59 @@
+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!
+ */
+ if (this.getBoundingBox().b(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 40ede20..0d2af96 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -363,4 +363,9 @@ public class PaperWorldConfig {
log("Old Cannon Behaviors: This feature may not be working entirely properly at the moment");
}
}
+
+ public boolean isHopperPushBased;
+ private void isHopperPushBased() {
+ isHopperPushBased = getBoolean("hopper.push-based", true);
+ }
}
diff --git a/src/main/java/net/minecraft/server/BlockPosition.java b/src/main/java/net/minecraft/server/BlockPosition.java
index d6cc51b..5bbaa87 100644
--- a/src/main/java/net/minecraft/server/BlockPosition.java
+++ b/src/main/java/net/minecraft/server/BlockPosition.java
@@ -265,6 +265,7 @@ 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);
}
@@ -291,6 +292,7 @@ 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;
@@ -392,6 +394,7 @@ 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 e21769f..93f9eab 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -77,6 +77,19 @@ 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 691a78b..6f474b4 100644
--- a/src/main/java/net/minecraft/server/EntityItem.java
+++ b/src/main/java/net/minecraft/server/EntityItem.java
@@ -6,8 +6,15 @@ import javax.annotation.Nullable;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.bukkit.event.player.PlayerPickupItemEvent; // CraftBukkit
+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.a(hopper, this);
+ }
+// Paper end
private static final Logger b = LogManager.getLogger();
private static final DataWatcherObject<Optional<ItemStack>> c = DataWatcher.a(EntityItem.class, DataWatcherRegistry.f);
@@ -63,6 +70,7 @@ public class EntityItem extends Entity {
this.die();
} else {
super.m();
+ 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;
@@ -130,6 +138,7 @@ 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 b808716..035db5e 100644
--- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java
+++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
@@ -6,6 +6,7 @@ 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
@@ -14,7 +15,25 @@ 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 m() {
+ super.m();
+ tryPutInHopper();
+ }
+
+ @Override
+ public void inactiveTick() {
+ super.inactiveTick();
+ tryPutInHopper();
+ }
+ // Paper end
private ItemStack[] items = new ItemStack[27]; // CraftBukkit - 36 -> 27
private boolean b = true;
diff --git a/src/main/java/net/minecraft/server/IHopper.java b/src/main/java/net/minecraft/server/IHopper.java
index 804215a..e830d83 100644
--- a/src/main/java/net/minecraft/server/IHopper.java
+++ b/src/main/java/net/minecraft/server/IHopper.java
@@ -4,9 +4,9 @@ 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 8717ae1..cefd659 100644
--- a/src/main/java/net/minecraft/server/TileEntityHopper.java
+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java
@@ -170,6 +170,7 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
}
public boolean m() {
+ mayAcceptItems = false; // Paper - at the beginning of a tick, assume we can't accept items
if (this.world != null && !this.world.isClientSide) {
if (!this.o() && BlockHopper.f(this.u())) {
boolean flag = false;
@@ -179,6 +180,7 @@ 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;
}
@@ -201,6 +203,14 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
}
}
+ // Paper start
+ private boolean mayAcceptItems = true;
+
+ public boolean canAcceptItems() {
+ return mayAcceptItems;
+ }
+ // Paper end
+
private boolean q() {
ItemStack[] aitemstack = this.items;
int i = aitemstack.length;
@@ -344,8 +354,15 @@ 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;
@@ -376,8 +393,8 @@ 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();
@@ -541,18 +558,44 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
private IInventory I() {
EnumDirection enumdirection = BlockHopper.e(this.u());
- 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 endtcon
}
- 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);
@@ -572,7 +615,7 @@ 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()) {
--
2.9.0