Update hopper optimization patch

This commit is contained in:
Nassim Jahnke 2024-12-17 11:00:56 +01:00
parent e7995023f1
commit 6f26d53582
No known key found for this signature in database
GPG key ID: EF6771C01F6EF02F
2 changed files with 388 additions and 360 deletions

View file

@ -12,28 +12,27 @@ Subject: [PATCH] Optimize Hoppers
* Don't check for Entities with Inventories if the block above us is also occluding (not just Inventoried) * 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) * 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/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java b/src/main/java/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
diff --git a/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java b/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
new file mode 100644 new file mode 100644
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 index 0000000000000000000000000000000000000000..24a2090e068ad3c0d08705050944abdfe19136a2
--- /dev/null --- /dev/null
+++ b/src/main/java/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java +++ b/io/papermc/paper/event/inventory/PaperInventoryMoveItemEvent.java
@@ -0,0 +0,0 @@ @@ -0,0 +1,29 @@
+package io.papermc.paper.event.inventory; +package io.papermc.paper.event.inventory;
+ +
+import org.bukkit.event.inventory.InventoryMoveItemEvent; +import org.bukkit.event.inventory.InventoryMoveItemEvent;
+import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ItemStack;
+import org.checkerframework.checker.nullness.qual.NonNull; +import org.jspecify.annotations.NullMarked;
+import org.checkerframework.framework.qual.DefaultQualifier;
+import org.jetbrains.annotations.NotNull;
+ +
+@DefaultQualifier(NonNull.class) +@NullMarked
+public class PaperInventoryMoveItemEvent extends InventoryMoveItemEvent { +public class PaperInventoryMoveItemEvent extends InventoryMoveItemEvent {
+ +
+ public boolean calledSetItem; + public boolean calledSetItem;
+ public boolean calledGetItem; + public boolean calledGetItem;
+ +
+ public PaperInventoryMoveItemEvent(final @NotNull Inventory sourceInventory, final @NotNull ItemStack itemStack, final @NotNull Inventory destinationInventory, final boolean didSourceInitiate) { + public PaperInventoryMoveItemEvent(final Inventory sourceInventory, final ItemStack itemStack, final Inventory destinationInventory, final boolean didSourceInitiate) {
+ super(sourceInventory, itemStack, destinationInventory, didSourceInitiate); + super(sourceInventory, itemStack, destinationInventory, didSourceInitiate);
+ } + }
+ +
@ -49,23 +48,23 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ this.calledSetItem = true; + this.calledSetItem = true;
+ } + }
+} +}
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 646c2f2b617ed706021c83c9fc4492860dfdd4e9..415ab7faf371507e278d0da5bf0ffa9972585876 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java --- a/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java
@@ -0,0 +0,0 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa @@ -1564,6 +1564,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
ServerLevel worldserver = (ServerLevel) iterator.next(); for (ServerLevel serverLevel : this.getAllLevels()) {
worldserver.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
worldserver.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
+ net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = worldserver.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers + net.minecraft.world.level.block.entity.HopperBlockEntity.skipHopperEvents = serverLevel.paperConfig().hopper.disableMoveEvent || org.bukkit.event.inventory.InventoryMoveItemEvent.getHandlerList().getRegisteredListeners().length == 0; // Paper - Perf: Optimize Hoppers
profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
gameprofilerfiller.push(() -> { /* Drop global time updates
String s = String.valueOf(worldserver); if (this.tickCount % 20 == 0) {
diff --git a/src/main/java/net/minecraft/world/item/ItemStack.java b/src/main/java/net/minecraft/world/item/ItemStack.java diff --git a/net/minecraft/world/item/ItemStack.java b/net/minecraft/world/item/ItemStack.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 50cd12def88c9449cad8875c553f5ed9ef1cd791..3d93bb1aac5ad4830fc1dceddb6bebacee28f72a 100644
--- a/src/main/java/net/minecraft/world/item/ItemStack.java --- a/net/minecraft/world/item/ItemStack.java
+++ b/src/main/java/net/minecraft/world/item/ItemStack.java +++ b/net/minecraft/world/item/ItemStack.java
@@ -0,0 +0,0 @@ public final class ItemStack implements DataComponentHolder { @@ -815,10 +815,16 @@ public final class ItemStack implements DataComponentHolder {
} }
public ItemStack copy() { public ItemStack copy() {
@ -74,42 +73,42 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return this.copy(false); + return this.copy(false);
+ } + }
+ +
+ public ItemStack copy(boolean originalItem) { + public ItemStack copy(final boolean originalItem) {
+ if (!originalItem && this.isEmpty()) { + if (!originalItem && this.isEmpty()) {
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
return ItemStack.EMPTY; return EMPTY;
} else { } else {
- ItemStack itemstack = new ItemStack(this.getItem(), this.count, this.components.copy()); - ItemStack itemStack = new ItemStack(this.getItem(), this.count, this.components.copy());
+ ItemStack itemstack = new ItemStack(originalItem ? this.item : this.getItem(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers + ItemStack itemStack = new ItemStack(originalItem ? this.item : this.getItem(), this.count, this.components.copy()); // Paper - Perf: Optimize Hoppers
itemStack.setPopTime(this.getPopTime());
itemstack.setPopTime(this.getPopTime()); return itemStack;
return itemstack; }
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 diff --git a/net/minecraft/world/level/block/entity/BlockEntity.java b/net/minecraft/world/level/block/entity/BlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 2ebdf1ad323bb53dfe9eed319e25856b35a1443c..77618757c0e678532dbab814aceed83f7f1cd892 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java --- a/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java +++ b/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -0,0 +0,0 @@ import org.bukkit.inventory.InventoryHolder; @@ -26,6 +26,7 @@ import net.minecraft.world.level.block.state.BlockState;
// CraftBukkit end import org.slf4j.Logger;
public abstract class BlockEntity { public abstract class BlockEntity {
+ static boolean ignoreTileUpdates; // Paper - Perf: Optimize Hoppers + static boolean ignoreBlockEntityUpdates; // Paper - Perf: Optimize Hoppers
// CraftBukkit start - data containers // CraftBukkit start - data containers
private static final CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new CraftPersistentDataTypeRegistry(); private static final org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry DATA_TYPE_REGISTRY = new org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry();
@@ -0,0 +0,0 @@ public abstract class BlockEntity { public org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer persistentDataContainer;
@@ -196,6 +197,7 @@ public abstract class BlockEntity {
public void setChanged() { public void setChanged() {
if (this.level != null) { if (this.level != null) {
+ if (ignoreTileUpdates) return; // Paper - Perf: Optimize Hoppers + if (ignoreBlockEntityUpdates) return; // Paper - Perf: Optimize Hoppers
BlockEntity.setChanged(this.level, this.worldPosition, this.blockState); setChanged(this.level, this.worldPosition, this.blockState);
}
}
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 60e1e44f328e66d52ebf08476b533fef83bc5eba..8139868201c2eaca29588b840a2bd85778f1b3d5 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -139,18 +139,56 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
} }
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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
} }
+ // Paper start - Perf: Optimize Hoppers + // Paper start - Perf: Optimize Hoppers
@ -117,10 +116,10 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ private static final int HOPPER_HAS_ITEMS = 1; + private static final int HOPPER_HAS_ITEMS = 1;
+ private static final int HOPPER_IS_FULL = 2; + private static final int HOPPER_IS_FULL = 2;
+ +
+ private static int getFullState(final HopperBlockEntity tileEntity) { + private static int getFullState(final HopperBlockEntity hoper) {
+ tileEntity.unpackLootTable(null); + hoper.unpackLootTable(null);
+ +
+ final List<ItemStack> hopperItems = tileEntity.getItems(); + final List<ItemStack> hopperItems = hoper.items;
+ +
+ boolean empty = true; + boolean empty = true;
+ boolean full = true; + boolean full = true;
@ -149,32 +148,33 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
+ +
private static boolean tryMoveItems(Level world, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier booleansupplier) { private static boolean tryMoveItems(Level level, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier validator) {
if (world.isClientSide) { if (level.isClientSide) {
return false; return false;
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen } else {
if (!blockEntity.isOnCooldown() && (Boolean) state.getValue(HopperBlock.ENABLED)) { if (!blockEntity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
boolean flag = false; boolean flag = false;
- if (!blockEntity.isEmpty()) { - if (!blockEntity.isEmpty()) {
+ final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers + final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
+ if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers + if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
flag = HopperBlockEntity.ejectItems(world, pos, blockEntity); flag = ejectItems(level, pos, blockEntity);
} }
- if (!blockEntity.inventoryFull()) { - if (!blockEntity.inventoryFull()) {
- flag |= validator.getAsBoolean();
+ if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers + if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers
flag |= booleansupplier.getAsBoolean(); + flag |= validator.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
} }
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen if (flag) {
return false; @@ -174,6 +212,206 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return true;
} }
+ // Paper start - Perf: Optimize Hoppers + // Paper start - Perf: Optimize Hoppers
+ public static boolean skipHopperEvents;
+ private static boolean skipPullModeEventFire; + private static boolean skipPullModeEventFire;
+ private static boolean skipPushModeEventFire; + private static boolean skipPushModeEventFire;
+ public static boolean skipHopperEvents;
+ +
+ private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) { + private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
+ skipPushModeEventFire = skipHopperEvents; + skipPushModeEventFire = skipHopperEvents;
@ -233,7 +233,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ if (movedItem == null) { // cancelled + if (movedItem == null) { // cancelled
+ origItemStack.setCount(originalItemCount); + origItemStack.setCount(originalItemCount);
+ // Drastically improve performance by returning true. + // Drastically improve performance by returning true.
+ // No plugin could of relied on the behavior of false as the other call + // No plugin could have relied on the behavior of false as the other call
+ // site for IMIE did not exhibit the same behavior + // site for IMIE did not exhibit the same behavior
+ return true; + return true;
+ } + }
@ -248,68 +248,72 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount); + origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ } + }
+ +
+ ignoreTileUpdates = true; + ignoreBlockEntityUpdates = true;
+ container.setItem(i, origItemStack); + container.setItem(i, origItemStack);
+ ignoreTileUpdates = false; + ignoreBlockEntityUpdates = false;
+ container.setChanged(); + container.setChanged();
+ return true; + return true;
+ } + }
+ origItemStack.setCount(originalItemCount); + origItemStack.setCount(originalItemCount);
+ +
+ if (level.paperConfig().hopper.cooldownWhenFull) { + if (level.paperConfig().hopper.cooldownWhenFull) {
+ cooldownHopper(hopper); + applyCooldown(hopper);
+ } + }
+ +
+ return false; + return false;
+ } + }
+ +
+ @Nullable + @Nullable
+ private static ItemStack callPushMoveEvent(Container iinventory, ItemStack itemstack, HopperBlockEntity hopper) { + private static ItemStack callPushMoveEvent(Container destination, ItemStack itemStack, HopperBlockEntity hopper) {
+ final Inventory destinationInventory = getInventory(iinventory); + final org.bukkit.inventory.Inventory destinationInventory = getInventory(destination);
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(hopper.getOwner(false).getInventory(), + final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(
+ CraftItemStack.asCraftMirror(itemstack), destinationInventory, true); + hopper.getOwner(false).getInventory(),
+ org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack),
+ destinationInventory,
+ true
+ );
+ final boolean result = event.callEvent(); + final boolean result = event.callEvent();
+ if (!event.calledGetItem && !event.calledSetItem) { + if (!event.calledGetItem && !event.calledSetItem) {
+ skipPushModeEventFire = true; + skipPushModeEventFire = true;
+ } + }
+ if (!result) { + if (!result) {
+ cooldownHopper(hopper); + applyCooldown(hopper);
+ return null; + return null;
+ } + }
+ +
+ if (event.calledSetItem) { + if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem()); + return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ } else { + } else {
+ return itemstack; + return itemStack;
+ } + }
+ } + }
+ +
+ @Nullable + @Nullable
+ private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) { + private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
+ final Inventory sourceInventory = getInventory(container); + final org.bukkit.inventory.Inventory sourceInventory = getInventory(container);
+ final Inventory destination = getInventory(hopper); + final org.bukkit.inventory.Inventory destination = getInventory(hopper);
+ +
+ // Mirror is safe as no plugins ever use this item + // Mirror is safe as no plugins ever use this item
+ final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, CraftItemStack.asCraftMirror(itemstack), destination, false); + final io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent event = new io.papermc.paper.event.inventory.PaperInventoryMoveItemEvent(sourceInventory, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), destination, false);
+ final boolean result = event.callEvent(); + final boolean result = event.callEvent();
+ if (!event.calledGetItem && !event.calledSetItem) { + if (!event.calledGetItem && !event.calledSetItem) {
+ skipPullModeEventFire = true; + skipPullModeEventFire = true;
+ } + }
+ if (!result) { + if (!result) {
+ cooldownHopper(hopper); + applyCooldown(hopper);
+ return null; + return null;
+ } + }
+ +
+ if (event.calledSetItem) { + if (event.calledSetItem) {
+ return CraftItemStack.asNMSCopy(event.getItem()); + return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
+ } else { + } else {
+ return itemstack; + return itemstack;
+ } + }
+ } + }
+ +
+ private static Inventory getInventory(final Container container) { + private static org.bukkit.inventory.Inventory getInventory(final Container container) {
+ final Inventory sourceInventory; + final org.bukkit.inventory.Inventory sourceInventory;
+ if (container instanceof CompoundContainer compoundContainer) { + if (container instanceof net.minecraft.world.CompoundContainer compoundContainer) {
+ // Have to special-case large chests as they work oddly + // Have to special-case large chests as they work oddly
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer); + sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (container instanceof BlockEntity blockEntity) { + } else if (container instanceof BlockEntity blockEntity) {
@ -317,28 +321,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } else if (container.getOwner() != null) { + } else if (container.getOwner() != null) {
+ sourceInventory = container.getOwner().getInventory(); + sourceInventory = container.getOwner().getInventory();
+ } else { + } else {
+ sourceInventory = new CraftInventory(container); + sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
+ } + }
+ return sourceInventory; + return sourceInventory;
+ } + }
+ +
+ private static void cooldownHopper(final Hopper hopper) { + private static void applyCooldown(final Hopper hopper) {
+ if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) { + if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
+ blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer); + blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
+ } + }
+ } + }
+ +
+ private static boolean allMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) { + private static boolean allMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) { + if (container instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) { + for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
+ if (!test.test(iinventory.getItem(i), i)) { + if (!test.test(container.getItem(slot), slot)) {
+ return false; + return false;
+ } + }
+ } + }
+ } else { + } else {
+ int size = iinventory.getContainerSize(); + int size = container.getContainerSize();
+ for (int i = 0; i < size; i++) { + for (int slot = 0; slot < size; slot++) {
+ if (!test.test(iinventory.getItem(i), i)) { + if (!test.test(container.getItem(slot), slot)) {
+ return false; + return false;
+ } + }
+ } + }
@ -346,319 +350,335 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ return true; + return true;
+ } + }
+ +
+ private static boolean anyMatch(Container iinventory, Direction enumdirection, java.util.function.BiPredicate<ItemStack, Integer> test) { + private static boolean anyMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
+ if (iinventory instanceof WorldlyContainer) { + if (container instanceof WorldlyContainer) {
+ for (int i : ((WorldlyContainer) iinventory).getSlotsForFace(enumdirection)) { + for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
+ if (test.test(iinventory.getItem(i), i)) { + if (test.test(container.getItem(slot), slot)) {
+ return true; + return true;
+ } + }
+ } + }
+ } else { + } else {
+ int size = iinventory.getContainerSize(); + int size = container.getContainerSize();
+ for (int i = 0; i < size; i++) { + for (int slot = 0; slot < size; slot++) {
+ if (test.test(iinventory.getItem(i), i)) { + if (test.test(container.getItem(slot), slot)) {
+ return true; + return true;
+ } + }
+ } + }
+ } + }
+ 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> 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(); + private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty();
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
+ +
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) { private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) {
Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity); Container attachedContainer = getAttachedContainer(level, pos, blockEntity);
if (attachedContainer == null) {
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -183,57 +421,60 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (HopperBlockEntity.isFullContainer(iinventory, enumdirection)) { if (isFullContainer(attachedContainer, opposite)) {
return false; return false;
} else { } else {
- for (int i = 0; i < blockEntity.getContainerSize(); ++i) { - for (int i = 0; i < blockEntity.getContainerSize(); i++) {
- ItemStack itemstack = blockEntity.getItem(i); - ItemStack item = blockEntity.getItem(i);
- - if (!item.isEmpty()) {
- if (!itemstack.isEmpty()) { - int count = item.getCount();
- int j = itemstack.getCount();
- // CraftBukkit start - Call event when pushing items into other inventories - // CraftBukkit start - Call event when pushing items into other inventories
- ItemStack original = itemstack.copy(); - ItemStack original = item.copy();
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
- ); // Spigot
- -
- Inventory destinationInventory; - org.bukkit.inventory.Inventory destinationInventory;
- // Have to special case large chests as they work oddly - // Have to special case large chests as they work oddly
- if (iinventory instanceof CompoundContainer) { - if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); - destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- } else if (iinventory.getOwner() != null) { - } else if (attachedContainer.getOwner() != null) {
- destinationInventory = iinventory.getOwner().getInventory(); - destinationInventory = attachedContainer.getOwner().getInventory();
- } else { - } else {
- destinationInventory = new CraftInventory(iinventory); - destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
- } - }
- -
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(blockEntity.getOwner().getInventory(), oitemstack, destinationInventory, true); - org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- world.getCraftServer().getPluginManager().callEvent(event); - blockEntity.getOwner().getInventory(),
- if (event.isCancelled()) { - oitemstack,
- destinationInventory,
- true
- );
- if (!event.callEvent()) {
- blockEntity.setItem(i, original); - blockEntity.setItem(i, original);
- blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot - blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
- return false; - return false;
- } - }
- int origCount = event.getItem().getAmount(); // Spigot - int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); - ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
- // CraftBukkit end - // CraftBukkit end
- -
- if (itemstack1.isEmpty()) { - if (itemStack.isEmpty()) {
- iinventory.setChanged(); - attachedContainer.setChanged();
- return true; - return true;
- } - }
- -
- itemstack.setCount(j); - item.setCount(count);
- // Spigot start - // Spigot start
- itemstack.shrink(origCount - itemstack1.getCount()); - item.shrink(origCount - itemStack.getCount());
- if (j <= world.spigotConfig.hopperAmount) { - if (count <= level.spigotConfig.hopperAmount) {
- // Spigot end - // Spigot end
- blockEntity.setItem(i, itemstack); - blockEntity.setItem(i, item);
- } - }
- } - }
- } - }
- -
- return false; - return false;
+ // Paper start - Perf: Optimize Hoppers + // Paper start - Perf: Optimize Hoppers
+ return hopperPush(world, iinventory, enumdirection, blockEntity); + return hopperPush(level, attachedContainer, opposite, blockEntity);
+ //for (int i = 0; i < blockEntity.getContainerSize(); ++i) { + //for (int i = 0; i < blockEntity.getContainerSize(); i++) {
+ // ItemStack itemstack = blockEntity.getItem(i); + // ItemStack item = blockEntity.getItem(i);
+ + // if (!item.isEmpty()) {
+ // if (!itemstack.isEmpty()) { + // int count = item.getCount();
+ // int j = itemstack.getCount();
+ // // CraftBukkit start - Call event when pushing items into other inventories + // // CraftBukkit start - Call event when pushing items into other inventories
+ // ItemStack original = itemstack.copy(); + // ItemStack original = item.copy();
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(blockEntity.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot + // org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ // blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
+ // ); // Spigot
+ +
+ // Inventory destinationInventory; + // org.bukkit.inventory.Inventory destinationInventory;
+ // // Have to special case large chests as they work oddly + // // Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) { + // if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); + // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ // } else if (iinventory.getOwner() != null) { + // } else if (attachedContainer.getOwner() != null) {
+ // destinationInventory = iinventory.getOwner().getInventory(); + // destinationInventory = attachedContainer.getOwner().getInventory();
+ // } else { + // } else {
+ // destinationInventory = new CraftInventory(iinventory); + // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
+ // } + // }
+ +
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(tileentityhopper.getOwner().getInventory(), oitemstack, destinationInventory, true); + // org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ // world.getCraftServer().getPluginManager().callEvent(event); + // blockEntity.getOwner().getInventory(),
+ // if (event.isCancelled()) { + // oitemstack,
+ // destinationInventory,
+ // true
+ // );
+ // if (!event.callEvent()) {
+ // blockEntity.setItem(i, original); + // blockEntity.setItem(i, original);
+ // blockEntity.setCooldown(world.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot + // blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
+ // return false; + // return false;
+ // } + // }
+ // int origCount = event.getItem().getAmount(); // Spigot + // int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(blockEntity, iinventory, CraftItemStack.asNMSCopy(event.getItem()), enumdirection); + // ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
+ // // CraftBukkit end + // // CraftBukkit end
+ +
+ // if (itemstack1.isEmpty()) { + // if (itemStack.isEmpty()) {
+ // iinventory.setChanged(); + // attachedContainer.setChanged();
+ // return true; + // return true;
+ // } + // }
+ +
+ // itemstack.setCount(j); + // item.setCount(count);
+ // // Spigot start + // // Spigot start
+ // itemstack.shrink(origCount - itemstack1.getCount()); + // item.shrink(origCount - itemStack.getCount());
+ // if (j <= world.spigotConfig.hopperAmount) { + // if (count <= level.spigotConfig.hopperAmount) {
+ // // Spigot end + // // Spigot end
+ // blockEntity.setItem(i, itemstack); + // blockEntity.setItem(i, item);
+ // } + // }
+ // } + // }
+ //} + //}
+ +
+ // return false; + //return false;
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
} }
} }
} }
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -288,6 +529,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return false; Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState);
} if (sourceContainer != null) {
} Direction direction = Direction.DOWN;
-
return true;
}
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (iinventory != null) {
Direction enumdirection = Direction.DOWN;
+ skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers + skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers
int[] aint = HopperBlockEntity.getSlots(iinventory, enumdirection);
int i = aint.length;
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen for (int i : getSlots(sourceContainer, direction)) {
ItemStack itemstack = iinventory.getItem(i); if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot
@@ -313,55 +555,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (!itemstack.isEmpty() && HopperBlockEntity.canTakeItemFromContainer(ihopper, iinventory, itemstack, i, enumdirection)) { private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot
- int j = itemstack.getCount(); ItemStack item = container.getItem(slot);
if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) {
- int count = item.getCount();
- // CraftBukkit start - Call event on collection of items from inventories into the hopper - // CraftBukkit start - Call event on collection of items from inventories into the hopper
- ItemStack original = itemstack.copy(); - ItemStack original = item.copy();
- CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot - org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
- );
- -
- Inventory sourceInventory; - org.bukkit.inventory.Inventory sourceInventory;
- // Have to special case large chests as they work oddly - // Have to special case large chests as they work oddly
- if (iinventory instanceof CompoundContainer) { - if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); - sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- } else if (iinventory.getOwner() != null) { - } else if (container.getOwner() != null) {
- sourceInventory = iinventory.getOwner().getInventory(); - sourceInventory = container.getOwner().getInventory();
- } else { - } else {
- sourceInventory = new CraftInventory(iinventory); - sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
- } - }
- -
- InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false); - org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- sourceInventory,
- oitemstack,
- hopper.getOwner().getInventory(),
- false
- );
- -
- Bukkit.getServer().getPluginManager().callEvent(event); - if (!event.callEvent()) {
- if (event.isCancelled()) { - container.setItem(slot, original);
- iinventory.setItem(i, original);
- -
- if (ihopper instanceof HopperBlockEntity) { - if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
- ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot - hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
- } - }
- -
- return false; - return false;
- } - }
- int origCount = event.getItem().getAmount(); // Spigot - int origCount = event.getItem().getAmount(); // Spigot
- ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); - ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
- // CraftBukkit end - // CraftBukkit end
- -
- if (itemstack1.isEmpty()) { - if (itemStack.isEmpty()) {
- iinventory.setChanged(); - container.setChanged();
- return true; - return true;
- } - }
- -
- itemstack.setCount(j); - item.setCount(count);
- // Spigot start - // Spigot start
- itemstack.shrink(origCount - itemstack1.getCount()); - item.shrink(origCount - itemStack.getCount());
- if (j <= world.spigotConfig.hopperAmount) { - if (count <= level.spigotConfig.hopperAmount) {
- // Spigot end - // Spigot end
- iinventory.setItem(i, itemstack); - container.setItem(slot, item);
- } - }
+ // Paper start - Perf: Optimize Hoppers + // Paper start - Perf: Optimize Hoppers
+ return hopperPull(world, ihopper, iinventory, itemstack, i); + return hopperPull(level, hopper, container, item, slot);
+ // int j = itemstack.getCount(); + //int count = item.getCount();
+ // // CraftBukkit start - Call event on collection of items from inventories into the hopper + //// CraftBukkit start - Call event on collection of items from inventories into the hopper
+ // ItemStack original = itemstack.copy(); + //ItemStack original = item.copy();
+ // CraftItemStack oitemstack = CraftItemStack.asCraftMirror(iinventory.removeItem(i, world.spigotConfig.hopperAmount)); // Spigot + //org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ // container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
+ //);
+ +
+ // Inventory sourceInventory; + //org.bukkit.inventory.Inventory sourceInventory;
+ // // Have to special case large chests as they work oddly + //// Have to special case large chests as they work oddly
+ // if (iinventory instanceof CompoundContainer) { + //if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest((CompoundContainer) iinventory); + // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ // } else if (iinventory.getOwner() != null) { + //} else if (container.getOwner() != null) {
+ // sourceInventory = iinventory.getOwner().getInventory(); + // sourceInventory = container.getOwner().getInventory();
+ // } else { + //} else {
+ // sourceInventory = new CraftInventory(iinventory); + // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
+ // } + //}
+ +
+ // InventoryMoveItemEvent event = new InventoryMoveItemEvent(sourceInventory, oitemstack, ihopper.getOwner().getInventory(), false); + //org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ // sourceInventory,
+ // oitemstack,
+ // hopper.getOwner().getInventory(),
+ // false
+ //);
+ +
+ // Bukkit.getServer().getPluginManager().callEvent(event); + //if (!event.callEvent()) {
+ // if (event.isCancelled()) { + // container.setItem(slot, original);
+ // iinventory.setItem(i, original);
+ +
+ // if (ihopper instanceof HopperBlockEntity) { + // if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
+ // ((HopperBlockEntity) ihopper).setCooldown(world.spigotConfig.hopperTransfer); // Spigot + // hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
+ // } + // }
+ +
+ // return false; + // return false;
+ // } + //}
+ // int origCount = event.getItem().getAmount(); // Spigot + //int origCount = event.getItem().getAmount(); // Spigot
+ // ItemStack itemstack1 = HopperBlockEntity.addItem(iinventory, ihopper, CraftItemStack.asNMSCopy(event.getItem()), null); + //ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
+ // // CraftBukkit end + //// CraftBukkit end
+ +
+ // if (itemstack1.isEmpty()) { + //if (itemStack.isEmpty()) {
+ // iinventory.setChanged(); + // container.setChanged();
+ // return true; + // return true;
+ // } + //}
+ +
+ // itemstack.setCount(j); + //item.setCount(count);
+ // // Spigot start + //// Spigot start
+ // itemstack.shrink(origCount - itemstack1.getCount()); + //item.shrink(origCount - itemStack.getCount());
+ // if (j <= world.spigotConfig.hopperAmount) { + //if (count <= level.spigotConfig.hopperAmount) {
+ // // Spigot end + // // Spigot end
+ // iinventory.setItem(i, itemstack); + // container.setItem(slot, item);
+ // } + //}
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
} }
return false; return false;
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -370,13 +615,15 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean addItem(Container inventory, ItemEntity itemEntity) { public static boolean addItem(Container container, ItemEntity item) {
boolean flag = false; boolean flag = false;
// CraftBukkit start // CraftBukkit start
- InventoryPickupItemEvent event = new InventoryPickupItemEvent(inventory.getOwner().getInventory(), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); + if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
+ if (InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent(
+ InventoryPickupItemEvent event = new InventoryPickupItemEvent(getInventory(inventory), (org.bukkit.entity.Item) itemEntity.getBukkitEntity()); // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation - container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity()
itemEntity.level().getCraftServer().getPluginManager().callEvent(event); + getInventory(container), (org.bukkit.entity.Item) item.getBukkitEntity() // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation
if (event.isCancelled()) { );
if (!event.callEvent()) {
return false; return false;
} }
// CraftBukkit end // CraftBukkit end
+ } // Paper - Perf: Optimize Hoppers + } // Paper - Perf: Optimize Hoppers
ItemStack itemstack = itemEntity.getItem().copy(); ItemStack itemStack = item.getItem().copy();
ItemStack itemstack1 = HopperBlockEntity.addItem((Container) null, inventory, itemstack, (Direction) null); ItemStack itemStack1 = addItem(null, container, itemStack, null);
if (itemStack1.isEmpty()) {
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -431,7 +678,9 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(to.getMaxStackSize()); stack = stack.split(destination.getMaxStackSize());
} }
// Spigot end // Spigot end
+ ignoreTileUpdates = true; // Paper - Perf: Optimize Hoppers + ignoreBlockEntityUpdates = true; // Paper - Perf: Optimize Hoppers
to.setItem(slot, stack); destination.setItem(slot, stack);
+ ignoreTileUpdates = false; // Paper - Perf: Optimize Hoppers + ignoreBlockEntityUpdates = false; // Paper - Perf: Optimize Hoppers
stack = leftover; // Paper - Make hoppers respect inventory max stack size stack = leftover; // Paper - Make hoppers respect inventory max stack size
flag = true; flag = true;
} else if (HopperBlockEntity.canMergeItems(itemstack1, stack)) { } else if (canMergeItems(item, stack)) {
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -519,13 +768,19 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable @Nullable
public static Container getContainerAt(Level world, BlockPos pos) { public static Container getContainerAt(Level level, BlockPos pos) {
- return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D); - return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
+ return HopperBlockEntity.getContainerAt(world, pos, world.getBlockState(pos), (double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, true); + return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, true); // Paper - Optimize hoppers
} }
@Nullable @Nullable
private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z) { private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z) {
+ // Paper start - Perf: Optimize Hoppers + // Paper start - Perf: Optimize Hoppers
+ return HopperBlockEntity.getContainerAt(world, pos, state, x, y, z, false); + return HopperBlockEntity.getContainerAt(level, pos, state, x, y, z, false);
+ } + }
+ @Nullable + @Nullable
+ private static Container getContainerAt(Level world, BlockPos pos, BlockState state, double x, double y, double z, boolean optimizeEntities) { + private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z, final boolean optimizeEntities) {
+ // Paper end - Perf: Optimize Hoppers + // Paper end - Perf: Optimize Hoppers
Container iinventory = HopperBlockEntity.getBlockContainer(world, pos, state); Container blockContainer = getBlockContainer(level, pos, state);
- if (blockContainer == null) {
- if (iinventory == null) { + if (blockContainer == null && (!optimizeEntities || !level.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
+ if (iinventory == null && (!optimizeEntities || !world.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers blockContainer = getEntityContainer(level, x, y, z);
iinventory = HopperBlockEntity.getEntityContainer(world, x, y, z);
} }
@@ -0,0 +0,0 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -551,14 +806,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable @Nullable
private static Container getEntityContainer(Level world, double x, double y, double z) { private static Container getEntityContainer(Level level, double x, double y, double z) {
- 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); - List<Entity> entities = level.getEntities(
+ List<Entity> list = world.getEntitiesOfClass((Class) Container.class, new AABB(x - 0.5D, y - 0.5D, z - 0.5D, x + 0.5D, y + 0.5D, z + 0.5D), EntitySelector.CONTAINER_ENTITY_SELECTOR); // Paper - Perf: Optimize hoppers - (Entity)null, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR
+ List<Entity> entities = level.getEntitiesOfClass(
return !list.isEmpty() ? (Container) list.get(world.random.nextInt(list.size())) : null; + (Class) Container.class, new AABB(x - 0.5, y - 0.5, z - 0.5, x + 0.5, y + 0.5, z + 0.5), EntitySelector.CONTAINER_ENTITY_SELECTOR // Paper - Perf: Optimize hoppers
);
return !entities.isEmpty() ? (Container)entities.get(level.random.nextInt(entities.size())) : null;
} }
private static boolean canMergeItems(ItemStack first, ItemStack second) { private static boolean canMergeItems(ItemStack stack1, ItemStack stack2) {
- return first.getCount() <= first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second); - return stack1.getCount() <= stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2);
+ return first.getCount() < first.getMaxStackSize() && ItemStack.isSameItemSameComponents(first, second); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?! + return stack1.getCount() < stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
} }
@Override @Override
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 diff --git a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 73b3ddb120d6b6f89e478960e78bed415baea205..f9c31da81d84033abfc1179fc643bceffe35da17 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java --- a/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java +++ b/net/minecraft/world/level/block/entity/RandomizableContainerBlockEntity.java
@@ -0,0 +0,0 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc @@ -53,7 +53,7 @@ public abstract class RandomizableContainerBlockEntity extends BaseContainerBloc
@Override @Override
public ItemStack getItem(int slot) { public ItemStack getItem(int index) {
- this.unpackLootTable(null); - this.unpackLootTable(null);
+ if (slot == 0) this.unpackLootTable(null); // Paper - Perf: Optimize Hoppers + if (index == 0) this.unpackLootTable(null); // Paper - Perf: Optimize Hoppers
return super.getItem(slot); return super.getItem(index);
} }

View file

@ -6,44 +6,50 @@ Subject: [PATCH] Remove streams from hot code
Co-authored-by: Bjarne Koll <git@lynxplay.dev> Co-authored-by: Bjarne Koll <git@lynxplay.dev>
Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com> Co-authored-by: Spottedleaf <Spottedleaf@users.noreply.github.com>
diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java diff --git a/net/minecraft/world/entity/ai/behavior/GateBehavior.java b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index c215d97c24e6501e1a48a76fc08bf48ff4dfe462..bd31d1cac0d022a72bd536c41d1ef811886e7068 100644
--- a/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java --- a/net/minecraft/world/entity/ai/behavior/GateBehavior.java
+++ b/src/main/java/net/minecraft/world/entity/ai/behavior/GateBehavior.java +++ b/net/minecraft/world/entity/ai/behavior/GateBehavior.java
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E> @@ -57,7 +57,7 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
if (this.hasRequiredMemories(entity)) { if (this.hasRequiredMemories(entity)) {
this.status = Behavior.Status.RUNNING; this.status = Behavior.Status.RUNNING;
this.orderPolicy.apply(this.behaviors); this.orderPolicy.apply(this.behaviors);
- this.runningPolicy.apply(this.behaviors.stream(), world, entity, time); - this.runningPolicy.apply(this.behaviors.stream(), level, entity, gameTime);
+ this.runningPolicy.apply(this.behaviors, world, entity, time); // Paper - Perf: Remove streams from hot code + this.runningPolicy.apply(this.behaviors, level, entity, gameTime); // Paper - Perf: Remove streams from hot code
return true; return true;
} else { } else {
return false; return false;
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E> @@ -66,10 +66,13 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
@Override @Override
public final void tickOrStop(ServerLevel world, E entity, long time) { public final void tickOrStop(ServerLevel level, E entity, long gameTime) {
- this.behaviors.stream().filter(task -> task.getStatus() == Behavior.Status.RUNNING).forEach(task -> task.tickOrStop(world, entity, time)); - this.behaviors
- .stream()
- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
- .forEach(behavior -> behavior.tickOrStop(level, entity, gameTime));
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
+ for (final BehaviorControl<? super E> task : this.behaviors) { + for (final BehaviorControl<? super E> behavior : this.behaviors) {
+ if (task.getStatus() == Behavior.Status.RUNNING) { + if (behavior.getStatus() == Behavior.Status.RUNNING) {
+ task.tickOrStop(world, entity, time); + behavior.tickOrStop(level, entity, gameTime);
+ } + }
+ } + }
+ // Paper end - Perf: Remove streams from hot code + // Paper end - Perf: Remove streams from hot code
if (this.behaviors.stream().noneMatch(task -> task.getStatus() == Behavior.Status.RUNNING)) { if (this.behaviors.stream().noneMatch(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)) {
this.doStop(world, entity, time); this.doStop(level, entity, gameTime);
} }
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E> @@ -78,11 +81,16 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
@Override @Override
public final void doStop(ServerLevel world, E entity, long time) { public final void doStop(ServerLevel level, E entity, long gameTime) {
this.status = Behavior.Status.STOPPED; this.status = Behavior.Status.STOPPED;
- this.behaviors.stream().filter(task -> task.getStatus() == Behavior.Status.RUNNING).forEach(task -> task.doStop(world, entity, time)); - this.behaviors
- .stream()
- .filter(behavior -> behavior.getStatus() == Behavior.Status.RUNNING)
- .forEach(behavior -> behavior.doStop(level, entity, gameTime));
- this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory); - this.exitErasedMemories.forEach(entity.getBrain()::eraseMemory);
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
+ for (final BehaviorControl<? super E> task : this.behaviors) { + for (final BehaviorControl<? super E> behavior : this.behaviors) {
+ if (task.getStatus() == Behavior.Status.RUNNING) { + if (behavior.getStatus() == Behavior.Status.RUNNING) {
+ task.doStop(world, entity, time); + behavior.doStop(level, entity, gameTime);
+ } + }
+ } + }
+ for (final MemoryModuleType<?> exitErasedMemory : this.exitErasedMemories) { + for (final MemoryModuleType<?> exitErasedMemory : this.exitErasedMemories) {
@ -53,17 +59,19 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
} }
@Override @Override
@@ -0,0 +0,0 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E> @@ -116,20 +124,30 @@ public class GateBehavior<E extends LivingEntity> implements BehaviorControl<E>
public static enum RunningPolicy { public static enum RunningPolicy {
RUN_ONE { RUN_ONE {
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
@Override @Override
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) { - public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
- tasks.filter(task -> task.getStatus() == Behavior.Status.STOPPED).filter(task -> task.tryStart(world, entity, time)).findFirst(); - behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED)
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) { - .filter(behavior -> behavior.tryStart(level, owner, gameTime))
+ for (final BehaviorControl<? super E> task : tasks) { - .findFirst();
+ if (task.getStatus() == Behavior.Status.STOPPED && task.tryStart(world, entity, time)) { + public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
+ for (final BehaviorControl<? super E> behavior : behaviors) {
+ if (behavior.getStatus() == Behavior.Status.STOPPED && behavior.tryStart(level, owner, gameTime)) {
+ break; + break;
+ } + }
+ } + }
@ -73,28 +81,28 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
TRY_ALL { TRY_ALL {
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
@Override @Override
- public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) { - public <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
- tasks.filter(task -> task.getStatus() == Behavior.Status.STOPPED).forEach(task -> task.tryStart(world, entity, time)); - behaviors.filter(behavior -> behavior.getStatus() == Behavior.Status.STOPPED).forEach(behavior -> behavior.tryStart(level, owner, gameTime));
+ public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time) { + public <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime) {
+ for (final BehaviorControl<? super E> task : tasks) { + for (final BehaviorControl<? super E> behavior : behaviors) {
+ if (task.getStatus() == Behavior.Status.STOPPED) { + if (behavior.getStatus() == Behavior.Status.STOPPED) {
+ task.tryStart(world, entity, time); + behavior.tryStart(level, owner, gameTime);
+ } + }
+ } + }
+ // Paper end - Perf: Remove streams from hot code + // Paper end - Perf: Remove streams from hot code
} }
}; };
- public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time); - public abstract <E extends LivingEntity> void apply(Stream<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime);
+ public abstract <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> tasks, ServerLevel world, E entity, long time); // Paper - Perf: Remove streams from hot code + public abstract <E extends LivingEntity> void apply(ShufflingList<BehaviorControl<? super E>> behaviors, ServerLevel level, E owner, long gameTime); // Paper - Perf: Remove streams from hot code
} }
} }
diff --git a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java diff --git a/net/minecraft/world/entity/ai/gossip/GossipContainer.java b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 2c839dc80f451c83135828a97aced1a531004bab..b74a4ce1b629d440681a1f5c026997ccaf1d0373 100644
--- a/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java --- a/net/minecraft/world/entity/ai/gossip/GossipContainer.java
+++ b/src/main/java/net/minecraft/world/entity/ai/gossip/GossipContainer.java +++ b/net/minecraft/world/entity/ai/gossip/GossipContainer.java
@@ -0,0 +0,0 @@ public class GossipContainer { @@ -59,8 +59,22 @@ public class GossipContainer {
return this.gossips.entrySet().stream().flatMap(entry -> entry.getValue().unpack(entry.getKey())); return this.gossips.entrySet().stream().flatMap(gossip -> gossip.getValue().unpack(gossip.getKey()));
} }
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
@ -111,35 +119,35 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ } + }
+ // Paper end - Perf: Remove streams from hot code + // Paper end - Perf: Remove streams from hot code
+ +
private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int count) { private Collection<GossipContainer.GossipEntry> selectGossipsForTransfer(RandomSource random, int amount) {
- List<GossipContainer.GossipEntry> list = this.unpack().toList(); - List<GossipContainer.GossipEntry> list = this.unpack().toList();
+ List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Perf: Remove streams from hot code + List<GossipContainer.GossipEntry> list = this.decompress(); // Paper - Perf: Remove streams from hot code
if (list.isEmpty()) { if (list.isEmpty()) {
return Collections.emptyList(); return Collections.emptyList();
} else { } else {
@@ -0,0 +0,0 @@ public class GossipContainer { @@ -145,7 +159,7 @@ public class GossipContainer {
public <T> T store(DynamicOps<T> ops) { public <T> T store(DynamicOps<T> ops) {
return GossipContainer.GossipEntry.LIST_CODEC return GossipContainer.GossipEntry.LIST_CODEC
- .encodeStart(ops, this.unpack().toList()) - .encodeStart(ops, this.unpack().toList())
+ .encodeStart(ops, this.decompress()) // Paper - Perf: Remove streams from hot code + .encodeStart(ops, this.decompress()) // Paper - Perf: Remove streams from hot code
.resultOrPartial(error -> LOGGER.warn("Failed to serialize gossips: {}", error)) .resultOrPartial(errorMessage -> LOGGER.warn("Failed to serialize gossips: {}", errorMessage))
.orElseGet(ops::emptyList); .orElseGet(ops::emptyList);
} }
@@ -0,0 +0,0 @@ public class GossipContainer { @@ -172,12 +186,23 @@ public class GossipContainer {
final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>(); final Object2IntMap<GossipType> entries = new Object2IntOpenHashMap<>();
public int weightedValue(Predicate<GossipType> gossipTypeFilter) { public int weightedValue(Predicate<GossipType> gossipType) {
- return this.entries - return this.entries
- .object2IntEntrySet() - .object2IntEntrySet()
- .stream() - .stream()
- .filter(entry -> gossipTypeFilter.test(entry.getKey())) - .filter(gossip -> gossipType.test(gossip.getKey()))
- .mapToInt(entry -> entry.getIntValue() * entry.getKey().weight) - .mapToInt(gossip -> gossip.getIntValue() * gossip.getKey().weight)
- .sum(); - .sum();
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
+ int weight = 0; + int weight = 0;
+ for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) { + for (Object2IntMap.Entry<GossipType> entry : entries.object2IntEntrySet()) {
+ if (gossipTypeFilter.test(entry.getKey())) { + if (gossipType.test(entry.getKey())) {
+ weight += entry.getIntValue() * entry.getKey().weight; + weight += entry.getIntValue() * entry.getKey().weight;
+ } + }
+ } + }
@ -155,29 +163,29 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - Perf: Remove streams from hot code + // Paper end - Perf: Remove streams from hot code
} }
public Stream<GossipContainer.GossipEntry> unpack(UUID target) { public Stream<GossipContainer.GossipEntry> unpack(UUID identifier) {
diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java diff --git a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 38873e56e95dc772b184e4271f7af1fb411ac9f8..09fd13e2d958da8326276c4dadf25bf488aff5ac 100644
--- a/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java --- a/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
+++ b/src/main/java/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java +++ b/net/minecraft/world/entity/ai/sensing/NearestItemSensor.java
@@ -0,0 +0,0 @@ public class NearestItemSensor extends Sensor<Mob> { @@ -24,13 +24,17 @@ public class NearestItemSensor extends Sensor<Mob> {
@Override @Override
protected void doTick(ServerLevel world, Mob entity) { protected void doTick(ServerLevel level, Mob entity) {
Brain<?> brain = entity.getBrain(); Brain<?> brain = entity.getBrain();
- List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true); - List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> true);
+ List<ItemEntity> list = world.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(world, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities + List<ItemEntity> entitiesOfClass = level.getEntitiesOfClass(ItemEntity.class, entity.getBoundingBox().inflate(32.0, 16.0, 32.0), itemEntity -> itemEntity.closerThan(entity, MAX_DISTANCE_TO_WANTED_ITEM) && entity.wantsToPickUp(level, itemEntity.getItem())); // Paper - Perf: Move predicate into getEntities
list.sort(Comparator.comparingDouble(entity::distanceToSqr)); entitiesOfClass.sort(Comparator.comparingDouble(entity::distanceToSqr));
- Optional<ItemEntity> optional = list.stream() - Optional<ItemEntity> optional = entitiesOfClass.stream()
- .filter(itemEntity -> entity.wantsToPickUp(world, itemEntity.getItem())) - .filter(itemEntity -> entity.wantsToPickUp(level, itemEntity.getItem()))
- .filter(itemEntityx -> itemEntityx.closerThan(entity, 32.0)) - .filter(itemEntity -> itemEntity.closerThan(entity, 32.0))
- .filter(entity::hasLineOfSight) - .filter(entity::hasLineOfSight)
- .findFirst(); - .findFirst();
- brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional); - brain.setMemory(MemoryModuleType.NEAREST_VISIBLE_WANTED_ITEM, optional);
+ // Paper start - Perf: remove streams from hot code + // Paper start - Perf: remove streams from hot code
+ ItemEntity nearest = null; + ItemEntity nearest = null;
+ for (ItemEntity entityItem : list) { + for (final ItemEntity itemEntity : entitiesOfClass) {
+ if (entity.hasLineOfSight(entityItem)) { // Paper - Perf: Move predicate into getEntities + if (entity.hasLineOfSight(itemEntity)) { // Paper - Perf: Move predicate into getEntities
+ nearest = entityItem; + nearest = itemEntity;
+ break; + break;
+ } + }
+ } + }
@ -185,31 +193,31 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000
+ // Paper end - Perf: remove streams from hot code + // Paper end - Perf: remove streams from hot code
} }
} }
diff --git a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java diff --git a/net/minecraft/world/level/levelgen/Beardifier.java b/net/minecraft/world/level/levelgen/Beardifier.java
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 index 1a09da5aa1ae047a002d6779326c2a29e47d32b5..131923282c9ecbcb1d7f45a826da907c02bd2716 100644
--- a/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java --- a/net/minecraft/world/level/levelgen/Beardifier.java
+++ b/src/main/java/net/minecraft/world/level/levelgen/Beardifier.java +++ b/net/minecraft/world/level/levelgen/Beardifier.java
@@ -0,0 +0,0 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { @@ -35,9 +35,10 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
int j = pos.getMinBlockZ(); int minBlockZ = chunkPos.getMinBlockZ();
ObjectList<Beardifier.Rigid> objectList = new ObjectArrayList<>(10); ObjectList<Beardifier.Rigid> list = new ObjectArrayList<>(10);
ObjectList<JigsawJunction> objectList2 = new ObjectArrayList<>(32); ObjectList<JigsawJunction> list1 = new ObjectArrayList<>(32);
- world.startsForStructure(pos, structure -> structure.terrainAdaptation() != TerrainAdjustment.NONE) - structureManager.startsForStructure(chunkPos, structure -> structure.terrainAdaptation() != TerrainAdjustment.NONE)
- .forEach( - .forEach(
- start -> { - structureStart -> {
+ // Paper start - Perf: Remove streams from hot code + // Paper start - Perf: Remove streams from hot code
+ for (net.minecraft.world.level.levelgen.structure.StructureStart start : world.startsForStructure(pos, (structure) -> { + for (net.minecraft.world.level.levelgen.structure.StructureStart structureStart : structureManager.startsForStructure(chunkPos, structure -> {
+ return structure.terrainAdaptation() != TerrainAdjustment.NONE; + return structure.terrainAdaptation() != TerrainAdjustment.NONE;
+ })) { // Paper end - Perf: Remove streams from hot code + })) { // Paper end - Perf: Remove streams from hot code
TerrainAdjustment terrainAdjustment = start.getStructure().terrainAdaptation(); TerrainAdjustment terrainAdjustment = structureStart.getStructure().terrainAdaptation();
for (StructurePiece structurePiece : start.getPieces()) { for (StructurePiece structurePiece : structureStart.getPieces()) {
@@ -0,0 +0,0 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker { @@ -65,8 +66,7 @@ public class Beardifier implements DensityFunctions.BeardifierOrMarker {
} }
} }
} }
- } - }
- ); - );
+ } // Paper - Perf: Remove streams from hot code + } // Paper - Perf: Remove streams from hot code
return new Beardifier(objectList.iterator(), objectList2.iterator()); return new Beardifier(list.iterator(), list1.iterator());
} }