aboutsummaryrefslogtreecommitdiffhomepage
path: root/Spigot-Server-Patches/0143-Make-entities-look-for-hoppers.patch
blob: 125875ed302a36d012089eec115a96b6d09a16f8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
From 5e24b91319bb930c470e28e5751d7f9b758fe063 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..aef7c2be9
--- /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().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 7bd745a27..894d40662 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -340,4 +340,9 @@ 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
@@ -235,6 +235,7 @@ 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
@@ -250,6 +250,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);
         }
@@ -276,6 +277,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;
 
@@ -393,6 +395,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 0d1fdd3ee..0479b7551 100644
--- a/src/main/java/net/minecraft/server/Entity.java
+++ b/src/main/java/net/minecraft/server/Entity.java
@@ -80,6 +80,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 9742afc65..95ca1b8e4 100644
--- a/src/main/java/net/minecraft/server/EntityItem.java
+++ b/src/main/java/net/minecraft/server/EntityItem.java
@@ -5,8 +5,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.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);
@@ -56,6 +63,7 @@ public class EntityItem extends Entity {
             this.die();
         } else {
             super.A_();
+            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;
@@ -143,6 +151,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 965aa5c23..04256898b 100644
--- a/src/main/java/net/minecraft/server/EntityMinecartContainer.java
+++ b/src/main/java/net/minecraft/server/EntityMinecartContainer.java
@@ -7,6 +7,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
@@ -15,7 +16,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 A_() {
+        super.A_();
+        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
@@ -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 44b6ecc5d..022e64520 100644
--- a/src/main/java/net/minecraft/server/TileEntityHopper.java
+++ b/src/main/java/net/minecraft/server/TileEntityHopper.java
@@ -126,6 +126,7 @@ 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;
@@ -135,6 +136,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;
                 }
 
@@ -150,6 +152,14 @@ 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();
 
@@ -302,8 +312,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;
@@ -334,8 +351,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();
@@ -401,6 +418,7 @@ 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;
 
@@ -506,18 +524,44 @@ public class TileEntityHopper extends TileEntityLootable implements IHopper, ITi
     private IInventory I() {
         EnumDirection enumdirection = BlockHopper.e(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);
@@ -537,7 +581,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.12.2.windows.2