9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-21 15:59:23 +00:00
Files
DivineMC/divinemc-server/minecraft-patches/features/0013-Optimize-hoppers.patch
NONPLAYT 8de5311cab Updated Upstream (Purpur)
Upstream has released updates that appear to apply and compile correctly

Purpur Changes:
PurpurMC/Purpur@4a3b139f Updated Upstream (Paper)
2025-03-09 16:07:14 +03:00

683 lines
37 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 1 Feb 2025 00:55:34 +0300
Subject: [PATCH] Optimize hoppers
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 3002ed51a579e81c3266da79a5dd38bac0b4a39c..9fdd4bbbe0e4c75880e9f24741fea7c60c57d09a 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1789,7 +1789,6 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
serverLevel.hasPhysicsEvent = org.bukkit.event.block.BlockPhysicsEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - BlockPhysicsEvent
serverLevel.hasEntityMoveEvent = io.papermc.paper.event.entity.EntityMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Paper - Add EntityMoveEvent
serverLevel.updateLagCompensationTick(); // Paper - lag compensation
- 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
serverLevel.hasRidableMoveEvent = org.purpurmc.purpur.event.entity.RidableMoveEvent.getHandlerList().getRegisteredListeners().length > 0; // Purpur - Ridables
profilerFiller.push(() -> serverLevel + " " + serverLevel.dimension().location());
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a3f363d0c86142e03edc7fc6e2ff6ed81de8ed65..0de0570397a6c6de43b1143b0d722af7a6093c8e 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -195,7 +195,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
private final LevelTicks<Fluid> fluidTicks = new LevelTicks<>(this::isPositionTickingWithEntitiesLoaded);
private final PathTypeCache pathTypesByPosCache = new PathTypeCache();
final Set<Mob> navigatingMobs = new ObjectOpenHashSet<>();
- volatile boolean isUpdatingNavigations;
+ final java.util.concurrent.atomic.AtomicBoolean isUpdatingNavigations = new java.util.concurrent.atomic.AtomicBoolean(false); // DivineMC - Optimize Hoppers
protected final Raids raids;
private final ObjectLinkedOpenHashSet<BlockEventData> blockEvents = new ObjectLinkedOpenHashSet<>();
private final List<BlockEventData> blockEventsToReschedule = new ArrayList<>(64);
@@ -1770,7 +1770,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
@Override
public void sendBlockUpdated(BlockPos pos, BlockState oldState, BlockState newState, int flags) {
- if (this.isUpdatingNavigations) {
+ if (this.isUpdatingNavigations.get() && false) { // DivineMC
String string = "recursive call to sendBlockUpdated";
Util.logAndPauseIfInIde("recursive call to sendBlockUpdated", new IllegalStateException("recursive call to sendBlockUpdated"));
}
@@ -1801,13 +1801,13 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
// Paper end - catch CME see below why
try {
- this.isUpdatingNavigations = true;
+ this.isUpdatingNavigations.set(true); // DivineMC
for (PathNavigation pathNavigation : list) {
pathNavigation.recomputePath();
}
} finally {
- this.isUpdatingNavigations = false;
+ this.isUpdatingNavigations.set(false); // DivineMC
}
}
} // Paper - option to disable pathfinding updates
@@ -2699,7 +2699,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
if (entity instanceof Mob mob) {
- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning
+ if (false && ServerLevel.this.isUpdatingNavigations.get()) { // Paper - Remove unnecessary onTrackingStart during navigation warning // DivineMC
String string = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
@@ -2769,7 +2769,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe
}
if (entity instanceof Mob mob) {
- if (false && ServerLevel.this.isUpdatingNavigations) { // Paper - Remove unnecessary onTrackingStart during navigation warning
+ if (false && ServerLevel.this.isUpdatingNavigations.get()) { // Paper - Remove unnecessary onTrackingStart during navigation warning // DivineMC
String string = "onTrackingStart called during navigation iteration";
Util.logAndPauseIfInIde(
"onTrackingStart called during navigation iteration", new IllegalStateException("onTrackingStart called during navigation iteration")
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..a0ee6ad6e7a6791605191d20d742e16cc9857a60 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -139,56 +139,18 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
}
}
- // Paper start - Perf: Optimize Hoppers
- private static final int HOPPER_EMPTY = 0;
- private static final int HOPPER_HAS_ITEMS = 1;
- private static final int HOPPER_IS_FULL = 2;
-
- private static int getFullState(final HopperBlockEntity hopper) {
- hopper.unpackLootTable(null);
-
- final List<ItemStack> hopperItems = hopper.items;
-
- boolean empty = true;
- boolean full = true;
-
- for (int i = 0, len = hopperItems.size(); i < len; ++i) {
- final ItemStack stack = hopperItems.get(i);
- if (stack.isEmpty()) {
- full = false;
- continue;
- }
-
- if (!full) {
- // can't be full
- return HOPPER_HAS_ITEMS;
- }
-
- empty = false;
-
- if (stack.getCount() != stack.getMaxStackSize()) {
- // can't be full or empty
- return HOPPER_HAS_ITEMS;
- }
- }
-
- return empty ? HOPPER_EMPTY : (full ? HOPPER_IS_FULL : HOPPER_HAS_ITEMS);
- }
- // Paper end - Perf: Optimize Hoppers
-
private static boolean tryMoveItems(Level level, BlockPos pos, BlockState state, HopperBlockEntity blockEntity, BooleanSupplier validator) {
if (level.isClientSide) {
return false;
} else {
if (!blockEntity.isOnCooldown() && state.getValue(HopperBlock.ENABLED)) {
boolean flag = false;
- final int fullState = getFullState(blockEntity); // Paper - Perf: Optimize Hoppers
- if (fullState != HOPPER_EMPTY) { // Paper - Perf: Optimize Hoppers
+ if (!blockEntity.isEmpty()) { // DivineMC - Optimize hoppers
flag = ejectItems(level, pos, blockEntity);
}
- if (fullState != HOPPER_IS_FULL || flag) { // Paper - Perf: Optimize Hoppers
- flag |= validator.getAsBoolean(); // Paper - note: this is not a validator, it's what adds/sucks in items
+ if (!blockEntity.inventoryFull()) { // DivineMC - Optimize hoppers
+ flag |= validator.getAsBoolean(); // DivineMC - Optimize hoppers
}
if (flag) {
@@ -212,206 +174,6 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
return true;
}
- // Paper start - Perf: Optimize Hoppers
- public static boolean skipHopperEvents;
- private static boolean skipPullModeEventFire;
- private static boolean skipPushModeEventFire;
-
- private static boolean hopperPush(final Level level, final Container destination, final Direction direction, final HopperBlockEntity hopper) {
- skipPushModeEventFire = skipHopperEvents;
- boolean foundItem = false;
- for (int i = 0; i < hopper.getContainerSize(); ++i) {
- final ItemStack item = hopper.getItem(i);
- if (!item.isEmpty()) {
- foundItem = true;
- ItemStack origItemStack = item;
- ItemStack movedItem = origItemStack;
-
- final int originalItemCount = origItemStack.getCount();
- final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- origItemStack.setCount(movedItemCount);
-
- // We only need to fire the event once to give protection plugins a chance to cancel this event
- // Because nothing uses getItem, every event call should end up the same result.
- if (!skipPushModeEventFire) {
- movedItem = callPushMoveEvent(destination, movedItem, hopper);
- if (movedItem == null) { // cancelled
- origItemStack.setCount(originalItemCount);
- return false;
- }
- }
-
- final ItemStack remainingItem = addItem(hopper, destination, movedItem, direction);
- final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true);
- origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
- }
- hopper.setItem(i, origItemStack);
- destination.setChanged();
- return true;
- }
- origItemStack.setCount(originalItemCount);
- }
- }
- if (foundItem && level.paperConfig().hopper.cooldownWhenFull) { // Inventory was full - cooldown
- hopper.setCooldown(level.spigotConfig.hopperTransfer);
- }
- return false;
- }
-
- private static boolean hopperPull(final Level level, final Hopper hopper, final Container container, ItemStack origItemStack, final int i) {
- ItemStack movedItem = origItemStack;
- final int originalItemCount = origItemStack.getCount();
- final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- container.setChanged(); // original logic always marks source inv as changed even if no move happens.
- movedItem.setCount(movedItemCount);
-
- if (!skipPullModeEventFire) {
- movedItem = callPullMoveEvent(hopper, container, movedItem);
- if (movedItem == null) { // cancelled
- origItemStack.setCount(originalItemCount);
- // Drastically improve performance by returning true.
- // No plugin could have relied on the behavior of false as the other call
- // site for IMIE did not exhibit the same behavior
- return true;
- }
- }
-
- final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
- final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true);
- origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
- }
-
- ignoreBlockEntityUpdates = true;
- container.setItem(i, origItemStack);
- ignoreBlockEntityUpdates = false;
- container.setChanged();
- return true;
- }
- origItemStack.setCount(originalItemCount);
-
- if (level.paperConfig().hopper.cooldownWhenFull) {
- applyCooldown(hopper);
- }
-
- return false;
- }
-
- @Nullable
- private static ItemStack callPushMoveEvent(Container destination, ItemStack itemStack, HopperBlockEntity hopper) {
- 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(),
- org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemStack),
- destinationInventory,
- true
- );
- final boolean result = event.callEvent();
- if (!event.calledGetItem && !event.calledSetItem) {
- skipPushModeEventFire = true;
- }
- if (!result) {
- applyCooldown(hopper);
- return null;
- }
-
- if (event.calledSetItem) {
- return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
- } else {
- return itemStack;
- }
- }
-
- @Nullable
- private static ItemStack callPullMoveEvent(final Hopper hopper, final Container container, final ItemStack itemstack) {
- final org.bukkit.inventory.Inventory sourceInventory = getInventory(container);
- final org.bukkit.inventory.Inventory destination = getInventory(hopper);
-
- // 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, org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack), destination, false);
- final boolean result = event.callEvent();
- if (!event.calledGetItem && !event.calledSetItem) {
- skipPullModeEventFire = true;
- }
- if (!result) {
- applyCooldown(hopper);
- return null;
- }
-
- if (event.calledSetItem) {
- return org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem());
- } else {
- return itemstack;
- }
- }
-
- private static org.bukkit.inventory.Inventory getInventory(final Container container) {
- final org.bukkit.inventory.Inventory sourceInventory;
- if (container instanceof net.minecraft.world.CompoundContainer compoundContainer) {
- // Have to special-case large chests as they work oddly
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- } else if (container instanceof BlockEntity blockEntity) {
- sourceInventory = blockEntity.getOwner(false).getInventory();
- } else if (container.getOwner() != null) {
- sourceInventory = container.getOwner().getInventory();
- } else {
- sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
- }
- return sourceInventory;
- }
-
- private static void applyCooldown(final Hopper hopper) {
- if (hopper instanceof HopperBlockEntity blockEntity && blockEntity.getLevel() != null) {
- blockEntity.setCooldown(blockEntity.getLevel().spigotConfig.hopperTransfer);
- }
- }
-
- private static boolean allMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
- if (container instanceof WorldlyContainer) {
- for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
- if (!test.test(container.getItem(slot), slot)) {
- return false;
- }
- }
- } else {
- int size = container.getContainerSize();
- for (int slot = 0; slot < size; slot++) {
- if (!test.test(container.getItem(slot), slot)) {
- return false;
- }
- }
- }
- return true;
- }
-
- private static boolean anyMatch(Container container, Direction direction, java.util.function.BiPredicate<ItemStack, Integer> test) {
- if (container instanceof WorldlyContainer) {
- for (int slot : ((WorldlyContainer) container).getSlotsForFace(direction)) {
- if (test.test(container.getItem(slot), slot)) {
- return true;
- }
- }
- } else {
- int size = container.getContainerSize();
- for (int slot = 0; slot < size; slot++) {
- if (test.test(container.getItem(slot), slot)) {
- return true;
- }
- }
- }
- return true;
- }
- private static final java.util.function.BiPredicate<ItemStack, Integer> STACK_SIZE_TEST = (itemStack, i) -> itemStack.getCount() >= itemStack.getMaxStackSize();
- private static final java.util.function.BiPredicate<ItemStack, Integer> IS_EMPTY_TEST = (itemStack, i) -> itemStack.isEmpty();
- // Paper end - Perf: Optimize Hoppers
-
private static boolean ejectItems(Level level, BlockPos pos, HopperBlockEntity blockEntity) {
Container attachedContainer = getAttachedContainer(level, pos, blockEntity);
if (attachedContainer == null) {
@@ -421,60 +183,59 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
if (isFullContainer(attachedContainer, opposite)) {
return false;
} else {
- // Paper start - Perf: Optimize Hoppers
- return hopperPush(level, attachedContainer, opposite, blockEntity);
- //for (int i = 0; i < blockEntity.getContainerSize(); i++) {
- // ItemStack item = blockEntity.getItem(i);
- // if (!item.isEmpty()) {
- // int count = item.getCount();
- // // CraftBukkit start - Call event when pushing items into other inventories
- // ItemStack original = item.copy();
- // org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- // blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
- // ); // Spigot
-
- // org.bukkit.inventory.Inventory destinationInventory;
- // // Have to special case large chests as they work oddly
- // if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- // } else if (attachedContainer.getOwner() != null) {
- // destinationInventory = attachedContainer.getOwner().getInventory();
- // } else {
- // destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
- // }
-
- // org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- // blockEntity.getOwner().getInventory(),
- // oitemstack,
- // destinationInventory,
- // true
- // );
- // if (!event.callEvent()) {
- // blockEntity.setItem(i, original);
- // blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
- // return false;
- // }
- // int origCount = event.getItem().getAmount(); // Spigot
- // ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
- // // CraftBukkit end
-
- // if (itemStack.isEmpty()) {
- // attachedContainer.setChanged();
- // return true;
- // }
-
- // item.setCount(count);
- // // Spigot start
- // item.shrink(origCount - itemStack.getCount());
- // if (count <= level.spigotConfig.hopperAmount) {
- // // Spigot end
- // blockEntity.setItem(i, item);
- // }
- // }
- //}
-
- //return false;
- // Paper end - Perf: Optimize Hoppers
+ // DivineMC start - Optimize hoppers
+ for (int i = 0; i < blockEntity.getContainerSize(); i++) {
+ ItemStack item = blockEntity.getItem(i);
+ if (!item.isEmpty()) {
+ int count = item.getCount();
+ // CraftBukkit start - Call event when pushing items into other inventories
+ ItemStack original = item.copy();
+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ blockEntity.removeItem(i, level.spigotConfig.hopperAmount)
+ ); // Spigot
+
+ org.bukkit.inventory.Inventory destinationInventory;
+ // Have to special case large chests as they work oddly
+ if (attachedContainer instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (attachedContainer.getOwner() != null) {
+ destinationInventory = attachedContainer.getOwner().getInventory();
+ } else {
+ destinationInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(attachedContainer);
+ }
+
+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ blockEntity.getOwner().getInventory(),
+ oitemstack,
+ destinationInventory,
+ true
+ );
+ if (!event.callEvent()) {
+ blockEntity.setItem(i, original);
+ blockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Delay hopper checks // Spigot
+ return false;
+ }
+ int origCount = event.getItem().getAmount(); // Spigot
+ ItemStack itemStack = HopperBlockEntity.addItem(blockEntity, attachedContainer, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), opposite);
+ // CraftBukkit end
+
+ if (itemStack.isEmpty()) {
+ attachedContainer.setChanged();
+ return true;
+ }
+
+ item.setCount(count);
+ // Spigot start
+ item.shrink(origCount - itemStack.getCount());
+ if (count <= level.spigotConfig.hopperAmount) {
+ // Spigot end
+ blockEntity.setItem(i, item);
+ }
+ }
+ }
+
+ return false;
+ // DivineMC end - Optimize hoppers
}
}
}
@@ -529,7 +290,6 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
Container sourceContainer = getSourceContainer(level, hopper, blockPos, blockState);
if (sourceContainer != null) {
Direction direction = Direction.DOWN;
- skipPullModeEventFire = skipHopperEvents; // Paper - Perf: Optimize Hoppers
for (int i : getSlots(sourceContainer, direction)) {
if (tryTakeInItemFromSlot(hopper, sourceContainer, i, direction, level)) { // Spigot
@@ -555,59 +315,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
private static boolean tryTakeInItemFromSlot(Hopper hopper, Container container, int slot, Direction direction, Level level) { // Spigot
ItemStack item = container.getItem(slot);
if (!item.isEmpty() && canTakeItemFromContainer(hopper, container, item, slot, direction)) {
- // Paper start - Perf: Optimize Hoppers
- return hopperPull(level, hopper, container, item, slot);
- //int count = item.getCount();
- //// CraftBukkit start - Call event on collection of items from inventories into the hopper
- //ItemStack original = item.copy();
- //org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
- // container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
- //);
-
- //org.bukkit.inventory.Inventory sourceInventory;
- //// Have to special case large chests as they work oddly
- //if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
- // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
- //} else if (container.getOwner() != null) {
- // sourceInventory = container.getOwner().getInventory();
- //} else {
- // sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
- //}
-
- //org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
- // sourceInventory,
- // oitemstack,
- // hopper.getOwner().getInventory(),
- // false
- //);
-
- //if (!event.callEvent()) {
- // container.setItem(slot, original);
-
- // if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
- // hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
- // }
-
- // return false;
- //}
- //int origCount = event.getItem().getAmount(); // Spigot
- //ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
- //// CraftBukkit end
-
- //if (itemStack.isEmpty()) {
- // container.setChanged();
- // return true;
- //}
-
- //item.setCount(count);
- //// Spigot start
- //item.shrink(origCount - itemStack.getCount());
- //if (count <= level.spigotConfig.hopperAmount) {
- // // Spigot end
- // container.setItem(slot, item);
- //}
- // Paper end - Perf: Optimize Hoppers
+ // DivineMC start - Optimize hoppers
+ int count = item.getCount();
+ // CraftBukkit start - Call event on collection of items from inventories into the hopper
+ ItemStack original = item.copy();
+ org.bukkit.craftbukkit.inventory.CraftItemStack oitemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(
+ container.removeItem(slot, level.spigotConfig.hopperAmount) // Spigot
+ );
+
+ org.bukkit.inventory.Inventory sourceInventory;
+ // Have to special case large chests as they work oddly
+ if (container instanceof final net.minecraft.world.CompoundContainer compoundContainer) {
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventoryDoubleChest(compoundContainer);
+ } else if (container.getOwner() != null) {
+ sourceInventory = container.getOwner().getInventory();
+ } else {
+ sourceInventory = new org.bukkit.craftbukkit.inventory.CraftInventory(container);
+ }
+
+ org.bukkit.event.inventory.InventoryMoveItemEvent event = new org.bukkit.event.inventory.InventoryMoveItemEvent(
+ sourceInventory,
+ oitemstack,
+ hopper.getOwner().getInventory(),
+ false
+ );
+
+ if (!event.callEvent()) {
+ container.setItem(slot, original);
+
+ if (hopper instanceof final HopperBlockEntity hopperBlockEntity) {
+ hopperBlockEntity.setCooldown(level.spigotConfig.hopperTransfer); // Spigot
+ }
+
+ return false;
+ }
+ int origCount = event.getItem().getAmount(); // Spigot
+ ItemStack itemStack = HopperBlockEntity.addItem(container, hopper, org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getItem()), null);
+ // CraftBukkit end
+
+ if (itemStack.isEmpty()) {
+ container.setChanged();
+ return true;
+ }
+
+ item.setCount(count);
+ // Spigot start
+ item.shrink(origCount - itemStack.getCount());
+ if (count <= level.spigotConfig.hopperAmount) {
+ // Spigot end
+ container.setItem(slot, item);
+ }
}
+ // DivineMC end - Optimize hoppers
return false;
}
@@ -615,15 +374,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean addItem(Container container, ItemEntity item) {
boolean flag = false;
// CraftBukkit start
- if (org.bukkit.event.inventory.InventoryPickupItemEvent.getHandlerList().getRegisteredListeners().length > 0) { // Paper - optimize hoppers
org.bukkit.event.inventory.InventoryPickupItemEvent event = new org.bukkit.event.inventory.InventoryPickupItemEvent(
- getInventory(container), (org.bukkit.entity.Item) item.getBukkitEntity() // Paper - Perf: Optimize Hoppers; use getInventory() to avoid snapshot creation
+ container.getOwner().getInventory(), (org.bukkit.entity.Item) item.getBukkitEntity() // DivineMC - Optimize hoppers
);
if (!event.callEvent()) {
return false;
}
// CraftBukkit end
- } // Paper - Perf: Optimize Hoppers
ItemStack itemStack = item.getItem().copy();
ItemStack itemStack1 = addItem(null, container, itemStack, null);
if (itemStack1.isEmpty()) {
@@ -678,9 +435,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
stack = stack.split(destination.getMaxStackSize());
}
// Spigot end
- ignoreBlockEntityUpdates = true; // Paper - Perf: Optimize Hoppers
destination.setItem(slot, stack);
- ignoreBlockEntityUpdates = false; // Paper - Perf: Optimize Hoppers
stack = leftover; // Paper - Make hoppers respect inventory max stack size
flag = true;
} else if (canMergeItems(item, stack)) {
@@ -768,19 +523,13 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
public static Container getContainerAt(Level level, BlockPos pos) {
- return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, true); // Paper - Optimize hoppers
+ return getContainerAt(level, pos, level.getBlockState(pos), pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); // DivineMC - Optimize hoppers
}
@Nullable
private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z) {
- // Paper start - Perf: Optimize Hoppers
- return HopperBlockEntity.getContainerAt(level, pos, state, x, y, z, false);
- }
- @Nullable
- private static Container getContainerAt(Level level, BlockPos pos, BlockState state, double x, double y, double z, final boolean optimizeEntities) {
- // Paper end - Perf: Optimize Hoppers
Container blockContainer = getBlockContainer(level, pos, state);
- if (blockContainer == null && (!optimizeEntities || !level.paperConfig().hopper.ignoreOccludingBlocks || !state.getBukkitMaterial().isOccluding())) { // Paper - Perf: Optimize Hoppers
+ if (blockContainer == null) { // DivineMC - Optimize hoppers
blockContainer = getEntityContainer(level, x, y, z);
}
@@ -806,14 +555,14 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@Nullable
private static Container getEntityContainer(Level level, double x, double y, double z) {
- List<Entity> entities = level.getEntitiesOfClass(
- (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
- );
+ List<Entity> entities = level.getEntities(
+ (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
+ ); // DivineMC - Optimize hoppers
return !entities.isEmpty() ? (Container)entities.get(level.random.nextInt(entities.size())) : null;
}
private static boolean canMergeItems(ItemStack stack1, ItemStack stack2) {
- return stack1.getCount() < stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // Paper - Perf: Optimize Hoppers; used to return true for full itemstacks?!
+ return stack1.getCount() <= stack1.getMaxStackSize() && ItemStack.isSameItemSameComponents(stack1, stack2); // DivineMC - Optimize hoppers
}
@Override
diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java
index faf45ac459f7c25309d6ef6dce371d484a0dae7b..6f0d1b28a45b93c51c5476283f1629a86e3420d1 100644
--- a/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -17,7 +17,8 @@ import net.minecraft.core.BlockPos;
import net.minecraft.nbt.ListTag;
import net.minecraft.world.level.ChunkPos;
-public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // Paper - rewrite chunk system
+public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickContainerAccess<T>, ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks { // DivineMC
+ private static final org.apache.logging.log4j.Logger log = org.apache.logging.log4j.LogManager.getLogger(LevelChunkTicks.class); // Paper - rewrite chunk system
private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
@Nullable
private List<SavedTick<T>> pendingTicks;
@@ -71,10 +72,18 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
@Nullable
public ScheduledTick<T> poll() {
- ScheduledTick<T> scheduledTick = this.tickQueue.poll();
- if (scheduledTick != null) {
- this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ // DivineMC start - catch exceptions when polling chunk ticks
+ ScheduledTick<T> scheduledTick = null;
+ try {
+ scheduledTick = this.tickQueue.poll();
+ if (scheduledTick != null) {
+ this.ticksPerPosition.remove(scheduledTick); this.dirty = true; // Paper - rewrite chunk system
+ }
+ } catch (Exception e) {
+ log.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e);
+ return null;
}
+ // DivineMC end - catch exceptions when polling chunk ticks
return scheduledTick;
}