Compare commits

...
3 Commits
Author SHA1 Message Date
NanaChiyo0721andCreeam 2edb70257d Fixup leaves vanilla hopper patch
Shiroha CI / build (push) Canceled after 0s
Shiroha CI / Event File (push) Canceled after 0s
Co-Authored-By: Creeam <102713261+HaHaWTH@users.noreply.github.com>
2026-08-17 23:41:15 +08:00
NanaChiyo0721 c9f8dd4595 Annotations 2026-08-17 14:00:50 +08:00
NanaChiyo0721 9eb5c767ed Make ARW to record class 2026-08-17 13:59:46 +08:00
5 changed files with 56 additions and 59 deletions
@@ -1,15 +1,17 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: MrHua269 <mrhua269@gmail.com> From: NanaChiyo0721 <nanachiyo0721@163.com>
Date: Thu, 9 Jul 2026 11:54:24 +0800 Date: Mon, 17 Aug 2026 23:38:00 +0800
Subject: [PATCH] Leaves Vanilla Hopper Subject: [PATCH] Leaves: Vanilla hopper
A part from leaves Co-Authored-By: Creeam <102713261+HaHaWTH@users.noreply.github.com>
Origin patch link: https://github.com/LeavesMC/Leaves/blob/master/leaves-server/minecraft-patches/features/0092-Vanilla-hopper.patch Original license: GPL-3.0-only
Origin license: https://github.com/LeavesMC/Leaves/blob/master/LICENSE.md Original project: https://github.com/LeavesMC/Leaves
This is a temporary solution designed to attempt to restore the vanilla behavior of the funnel while preserving optimizations as much as possible. It should ultimately be replaced by the optimization solution provided by lithium.
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08a5200c95 100644 index a858cb658af70f07614fa1f4d9e8a3435d5c161f..9f7f8edaf3261cc0377dab33404ca1d30c548ff9 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -281,36 +281,67 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen @@ -281,36 +281,67 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
@@ -18,7 +20,25 @@ index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08
final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount); final int movedItemCount = Math.min(level.spigotConfig.hopperAmount, originalItemCount);
- container.setChanged(); // original logic always marks source inv as changed even if no move happens. - container.setChanged(); // original logic always marks source inv as changed even if no move happens.
- movedItem.setCount(movedItemCount); - movedItem.setCount(movedItemCount);
- + // Leaves start - Vanilla hopper
+ if (org.dreeam.leaf.config.modules.gameplay.VanillaHopper.enabled && movedItemCount == 1) {
+ movedItem.setCount(movedItemCount);
+ container.setChanged();
+ 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 boolean removeOriginalItem = movedItem == origItemStack;
+ if (removeOriginalItem) {
+ movedItem = container.removeItem(i, movedItemCount);
+ }
- if (!worldData.skipPullModeEventFire) { // Folia - region threading - if (!worldData.skipPullModeEventFire) { // Folia - region threading
- movedItem = callPullMoveEvent(hopper, container, movedItem); - movedItem = callPullMoveEvent(hopper, container, movedItem);
- if (movedItem == null) { // cancelled - if (movedItem == null) { // cancelled
@@ -26,21 +46,11 @@ index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08
- // Drastically improve performance by returning true. - // Drastically improve performance by returning true.
- // No plugin could have 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
+ // Leaves start - fix vanilla hopper + final int itemCountToMove = movedItem.getCount();
+ if (movedItem.getCount() <= movedItemCount) { + final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
+ if (!worldData.skipPullModeEventFire) { + if (remainingItem.getCount() != itemCountToMove) {
+ movedItem = callPullMoveEvent(hopper, container, movedItem); + origItemStack.setCount(removeOriginalItem ? originalItemCount - movedItemCount : originalItemCount);
+ if (movedItem == null) { // cancelled + container.setItem(i, origItemStack);
+ origItemStack.setCount(originalItemCount);
+ container.setChanged(); // keep parity with vanilla: source inv always marked changed
+ return true;
+ }
+ }
+ final int toRemove = Math.min(movedItem.getCount(), container.getItem(i).getCount());
+ final ItemStack remainingItem = addItem(container, hopper, container.removeItem(i, toRemove), null);
+ final int remainingItemCount = remainingItem.getCount();
+ if (remainingItem.isEmpty()) {
+ container.setChanged();
return true; return true;
} }
- } - }
@@ -49,23 +59,10 @@ index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08
- final int remainingItemCount = remainingItem.getCount(); - final int remainingItemCount = remainingItem.getCount();
- if (remainingItemCount != movedItemCount) { - if (remainingItemCount != movedItemCount) {
- origItemStack = origItemStack.copy(true); - origItemStack = origItemStack.copy(true);
- origItemStack.setCount(originalItemCount); origItemStack.setCount(originalItemCount);
- if (!origItemStack.isEmpty()) { - if (!origItemStack.isEmpty()) {
- origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount); - origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ if (remainingItemCount != toRemove) { + container.setItem(i, origItemStack);
+ IGNORE_TILE_UPDATES.set(true); // Folia - region threading
+ container.setItem(i, remainingItem);
+ IGNORE_TILE_UPDATES.set(false); // Folia - region threading
+ container.setChanged();
+ return true;
}
-
IGNORE_TILE_UPDATES.set(true); // Folia - region threading
- container.setItem(i, origItemStack);
+ container.setItem(i, remainingItem);
IGNORE_TILE_UPDATES.set(false); // Folia - region threading
container.setChanged();
- return true;
+ } else { + } else {
+ container.setChanged(); // original logic always marks source inv as changed even if no move happens. + container.setChanged(); // original logic always marks source inv as changed even if no move happens.
+ movedItem.setCount(movedItemCount); + movedItem.setCount(movedItemCount);
@@ -79,8 +76,13 @@ index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08
+ // site for IMIE did not exhibit the same behavior + // site for IMIE did not exhibit the same behavior
+ return true; + return true;
+ } + }
+ } }
+
- IGNORE_TILE_UPDATES.set(true); // Folia - region threading
- container.setItem(i, origItemStack);
- IGNORE_TILE_UPDATES.set(false); // Folia - region threading
- container.setChanged();
- return true;
+ final ItemStack remainingItem = addItem(container, hopper, movedItem, null); + final ItemStack remainingItem = addItem(container, hopper, movedItem, null);
+ final int remainingItemCount = remainingItem.getCount(); + final int remainingItemCount = remainingItem.getCount();
+ if (remainingItemCount != movedItemCount) { + if (remainingItemCount != movedItemCount) {
@@ -90,16 +92,16 @@ index a858cb658af70f07614fa1f4d9e8a3435d5c161f..95f0b3276137cb9d1fc296e97cc25a08
+ origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount); + origItemStack.setCount(originalItemCount - movedItemCount + remainingItemCount);
+ } + }
+ +
+ IGNORE_TILE_UPDATES.set(true); + IGNORE_TILE_UPDATES.set(true); // Folia - region threading
+ container.setItem(i, origItemStack); + container.setItem(i, origItemStack);
+ IGNORE_TILE_UPDATES.set(false); + IGNORE_TILE_UPDATES.set(false); // Folia - region threading
+ container.setChanged(); + container.setChanged();
+ return true; + return true;
+ } + }
+ origItemStack.setCount(originalItemCount); + origItemStack.setCount(originalItemCount);
} }
- origItemStack.setCount(originalItemCount); - origItemStack.setCount(originalItemCount);
+ // Leaves end - fix vanilla hopper + // Leaves end - Vanilla hopper
if (level.paperConfig().hopper.cooldownWhenFull) { if (level.paperConfig().hopper.cooldownWhenFull) {
applyCooldown(hopper); applyCooldown(hopper);
@@ -1573,7 +1573,7 @@ index 6109d8da984b398bb1eb6cd6ab9a55f0511a615c..d3d6b3aeb24da7f3bf92c327095a9dc9
+ // Leaves end - Lithium Sleeping Block Entity + // Leaves end - Lithium Sleeping Block Entity
} }
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 95f0b3276137cb9d1fc296e97cc25a08a5200c95..26afe1f74b50b60d6c04e08967610a3d50183483 100644 index 9f7f8edaf3261cc0377dab33404ca1d30c548ff9..6dea8c7354708db69406575a03bf847e3e0b1194 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java --- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java +++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -27,8 +27,29 @@ import net.minecraft.world.level.storage.ValueInput; @@ -27,8 +27,29 @@ import net.minecraft.world.level.storage.ValueInput;
@@ -96,22 +96,22 @@ public class CpuAffinityConfig implements IConfigModule {
if (enabledForTickRegion) { if (enabledForTickRegion) {
tickRegionRunnableWrapper = new AffinityRunnableWrapper("tick_region", parseAffinity(tickRegionAffinity)); tickRegionRunnableWrapper = new AffinityRunnableWrapper("tick_region", parseAffinity(tickRegionAffinity));
LOGGER.info("Tick region thread now bound to: {}", tickRegionRunnableWrapper.getAffinity()); LOGGER.info("Tick region thread now bound to: {}", tickRegionRunnableWrapper.affinity());
} }
if (enabledForChunkSystemIo) { if (enabledForChunkSystemIo) {
chunkSystemIoRunnableWrapper = new AffinityRunnableWrapper("chunk_system_io", parseAffinity(chunkSystemIoAffinity)); chunkSystemIoRunnableWrapper = new AffinityRunnableWrapper("chunk_system_io", parseAffinity(chunkSystemIoAffinity));
LOGGER.info("Chunk system I/O thread now bound to: {}", chunkSystemIoRunnableWrapper.getAffinity()); LOGGER.info("Chunk system I/O thread now bound to: {}", chunkSystemIoRunnableWrapper.affinity());
} }
if (enabledForChunkSystemWorker) { if (enabledForChunkSystemWorker) {
chunkSystemWorkerRunnableWrapper = new AffinityRunnableWrapper("chunk_system_worker", parseAffinity(chunkSystemWorkerAffinity)); chunkSystemWorkerRunnableWrapper = new AffinityRunnableWrapper("chunk_system_worker", parseAffinity(chunkSystemWorkerAffinity));
LOGGER.info("Chunk system worker thread now bound to: {}", chunkSystemWorkerRunnableWrapper.getAffinity()); LOGGER.info("Chunk system worker thread now bound to: {}", chunkSystemWorkerRunnableWrapper.affinity());
} }
if (enableForNettyIo) { if (enableForNettyIo) {
nettyIoRunnableWrapper = new AffinityRunnableWrapper("netty_io", parseAffinity(nettyIoAffinity)); nettyIoRunnableWrapper = new AffinityRunnableWrapper("netty_io", parseAffinity(nettyIoAffinity));
LOGGER.info("Netty I/O thread now bound to: {}", nettyIoRunnableWrapper.getAffinity()); LOGGER.info("Netty I/O thread now bound to: {}", nettyIoRunnableWrapper.affinity());
} }
} }
@@ -5,14 +5,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.BitSet; import java.util.BitSet;
public class AffinityRunnableWrapper { public record AffinityRunnableWrapper(String name, BitSet affinity) {
private final BitSet affinity;
private final String name;
public AffinityRunnableWrapper(String name, BitSet affinity) {
this.name = name;
this.affinity = affinity;
}
public Runnable wrap(Runnable original) { public Runnable wrap(Runnable original) {
return () -> { return () -> {
@@ -22,13 +15,15 @@ public class AffinityRunnableWrapper {
}; };
} }
@Override
@NotNull @NotNull
public String getName() { public String name() {
return this.name; return this.name;
} }
@Override
@NotNull @NotNull
public BitSet getAffinity() { public BitSet affinity() {
return this.affinity; return this.affinity;
} }
} }
@@ -17,7 +17,7 @@ import java.util.jar.JarEntry;
import java.util.jar.JarFile; import java.util.jar.JarFile;
public class ClassScanUtil { public class ClassScanUtil {
public static @NotNull Collection<Class<?>> scanClassesUnder(String packag3, ClassLoader loader) { public static @NotNull Collection<Class<?>> scanClassesUnder(@NonNull String packag3, @NonNull ClassLoader loader) {
Set<Class<?>> classes = new HashSet<>(); Set<Class<?>> classes = new HashSet<>();
String packageDirName = packag3.replace('.', '/'); String packageDirName = packag3.replace('.', '/');
Enumeration<URL> dirs; Enumeration<URL> dirs;