9
0
mirror of https://github.com/Samsuik/Sakura.git synced 2025-12-24 01:09:16 +00:00
Files
SakuraMC/patches/server/0077-Optimise-hopper-ticking.patch
Samsuik ca5ff29a0d Updated Upstream (Paper)
Upstream has released updates that appear to apply and compile correctly

Paper Changes:
PaperMC/Paper@691d452 Fix bundled spark permission check (#11355)
PaperMC/Paper@012c527 Update Velocity natives (#11347)
PaperMC/Paper@953e6e9 Fire BlockExpEvent on grindstone use (#11346)
PaperMC/Paper@10f5879 Change condition check order of entity tracking Y (#11348)
PaperMC/Paper@805a974 Improve console completion with brig suggestions (#9251)
PaperMC/Paper@e0021b1 Fix allowSpiderWorldBorderClimbing world config (#11321)
PaperMC/Paper@3db4758 Check dead flag in isAlive() (#11330)
PaperMC/Paper@21f125f Revert velocity natives to 3.1.2 (#11368)
PaperMC/Paper@0e82527 Fix NPE while trying to respawn an already disconnected player (#11353)
PaperMC/Paper@5d91bef Fix shulkerbox loot table replenish (#11366)
PaperMC/Paper@a8e6a93 Deprecate for removal all OldEnum-related methods (#11371)
PaperMC/Paper@925c3b9 Add FeatureFlag API (#8952)
PaperMC/Paper@426f992 Enchantment is data-driven, so not FeatureDependant (#11377)
PaperMC/Paper@1ba1be7 Update Velocity natives again
PaperMC/Paper@7632de5 Tag Lifecycle Events (#10993)
PaperMC/Paper@b09eaf2 Add Item serialization as json api (#11235)
PaperMC/Paper@971a7a5 Add Decorated Pot Cracked API (#11365)
PaperMC/Paper@61fe23c deprecate isEnabledByFeature in Item/BlockType
PaperMC/Paper@e945cfe Fix PaperServerListPingEvent#getPlayerSample not being populated or used (#11387)
PaperMC/Paper@4ff58c4 Update spark
PaperMC/Paper@d1a72ea Updated Upstream (Bukkit/CraftBukkit/Spigot) (#11405)
PaperMC/Paper@0a53f1d Set default drop behavior for player deaths (#11380)
PaperMC/Paper@951e7dd Fix TrialSpawner forgetting assigned mob when placed by player (#11381)
PaperMC/Paper@13a2395 Fix enable-player-collisions playing sounds when set to false (#11390)
PaperMC/Paper@1348e44 Prevent NPE when serializing unresolved profile (#11407)
PaperMC/Paper@2aaf436 Validate slot in PlayerInventory#setSlot (#11399)
PaperMC/Paper@5c82955 Only mark decorations dirty if a removal actually occurs (#11413)
PaperMC/Paper@c5a1066 Remove wall-time / unused skip tick protection (#11412)
2024-09-22 20:38:14 +01:00

317 lines
15 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Samsuik <kfian294ma4@gmail.com>
Date: Mon, 12 Aug 2024 15:35:57 +0100
Subject: [PATCH] Optimise hopper ticking
diff --git a/src/main/java/net/minecraft/world/CompoundContainer.java b/src/main/java/net/minecraft/world/CompoundContainer.java
index 241fec02e6869c638d3a160819b32173a081467b..dc15a12687ce9e8e354bea9825d9cd1882d00782 100644
--- a/src/main/java/net/minecraft/world/CompoundContainer.java
+++ b/src/main/java/net/minecraft/world/CompoundContainer.java
@@ -58,6 +58,15 @@ public class CompoundContainer implements Container {
return this.container1.getLocation(); // TODO: right?
}
// CraftBukkit end
+ // Sakura start - optimise hopper ticking
+ @Override
+ public final boolean addListener(net.minecraft.world.level.block.entity.BlockEntity.BlockEntityChangeListener listener) {
+ boolean result = false;
+ result |= this.container1.addListener(listener);
+ result |= this.container2.addListener(listener);
+ return result;
+ }
+ // Sakura end - optimise hopper ticking
public CompoundContainer(Container first, Container second) {
this.container1 = first;
diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java
index 5db5ba026462ca642dcee718af732f80fadabef5..51e26395b53628b34b1f7f68935a9ba44a1e3feb 100644
--- a/src/main/java/net/minecraft/world/Container.java
+++ b/src/main/java/net/minecraft/world/Container.java
@@ -17,6 +17,12 @@ public interface Container extends Clearable {
float DEFAULT_DISTANCE_BUFFER = 4.0F;
+ // Sakura start - optimise hopper ticking
+ default boolean addListener(BlockEntity.BlockEntityChangeListener container) {
+ return false;
+ }
+ // Sakura end - optimise hopper ticking
+
int getContainerSize();
boolean isEmpty();
diff --git a/src/main/java/net/minecraft/world/level/Level.java b/src/main/java/net/minecraft/world/level/Level.java
index 062bc318e9c4e3b9a6429ce0eaaa29081cd1d227..11e89d518d45b42bb39689e6ac1635b54ec8e41f 100644
--- a/src/main/java/net/minecraft/world/level/Level.java
+++ b/src/main/java/net/minecraft/world/level/Level.java
@@ -1579,7 +1579,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
tilesThisCycle--;
toRemove.add(tickingblockentity); // Paper - Fix MC-117075; use removeAll
// Spigot end
- } else if (flag && this.shouldTickBlocksAt(tickingblockentity.getPos())) {
+ } else if (flag && tickingblockentity.isBlockEntityActive() && this.shouldTickBlocksAt(tickingblockentity.getPos())) { // Sakura - optimise hopper ticking
tickingblockentity.tick();
// Paper start - rewrite chunk system
if ((++tickedEntities & 7) == 0) {
diff --git a/src/main/java/net/minecraft/world/level/block/HopperBlock.java b/src/main/java/net/minecraft/world/level/block/HopperBlock.java
index 3e1c7d62c24dd48a805260d156135dc4f0c3d1fc..ced5fb075349a9b944708aeaabe82b3350ac5d4d 100644
--- a/src/main/java/net/minecraft/world/level/block/HopperBlock.java
+++ b/src/main/java/net/minecraft/world/level/block/HopperBlock.java
@@ -144,6 +144,12 @@ public class HopperBlock extends BaseEntityBlock {
private void checkPoweredState(Level world, BlockPos pos, BlockState state) {
boolean bl = !world.hasNeighborSignal(pos);
if (bl != state.getValue(ENABLED)) {
+ // Sakura start - optimise hopper ticking
+ BlockEntity blockEntity = world.getBlockEntity(pos);
+ if (blockEntity instanceof HopperBlockEntity hbe && world.sakuraConfig().technical.optimiseIdleHopperTicking) {
+ hbe.setBlockEntityTicking(bl);
+ }
+ // Sakura end - optimise hopper ticking
world.setBlock(pos, state.setValue(ENABLED, Boolean.valueOf(bl)), 2);
}
}
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
index 7dfabb11d3c8112f6daef35d204a2e324f4ddb5e..ffd464bd9dccb5f56b123833de4c255a0f11c0a0 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/BlockEntity.java
@@ -54,6 +54,55 @@ public abstract class BlockEntity {
private BlockState blockState;
private DataComponentMap components;
+ // Sakura start - optimise hopper ticking
+ private final Set<BlockEntityChangeListener> listeners = new it.unimi.dsi.fastutil.objects.ReferenceArraySet<>(0);
+ private final java.util.List<BlockEntity> listeningBlocks = new it.unimi.dsi.fastutil.objects.ObjectArrayList<>(0);
+ private boolean blockEntityTicking = true;
+ private int tickCount = 0;
+
+ public final int getIdleTickCount() {
+ return this.tickCount;
+ }
+
+ public final boolean isBlockEntityActive() {
+ this.tickCount++;
+ return this.blockEntityTicking;
+ }
+
+ public final void setBlockEntityTicking(boolean blockEntityTicking) {
+ this.tickCount = 0;
+ this.blockEntityTicking = blockEntityTicking;
+ }
+
+ public final boolean addListener(BlockEntityChangeListener listener) {
+ if (this.listeners.add(listener)) {
+ ((BlockEntity) listener).listeningBlocks.add(this);
+ }
+ return true;
+ }
+
+ public final void updateListeners(boolean onRemove) {
+ for (BlockEntityChangeListener listener : this.listeners) {
+ if (onRemove) {
+ listener.neighborRemoved();
+ } else {
+ listener.neighborChange();
+ }
+ }
+ if (onRemove) {
+ this.listeningBlocks.forEach(blockEntity -> blockEntity.listeners.clear());
+ this.listeningBlocks.clear();
+ this.listeners.clear();
+ }
+ }
+
+ public interface BlockEntityChangeListener {
+ void neighborChange();
+
+ void neighborRemoved();
+ }
+ // Sakura end - optimise hopper ticking
+
public BlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState state) {
this.components = DataComponentMap.EMPTY;
this.type = type;
@@ -231,12 +280,23 @@ public abstract class BlockEntity {
public void setChanged() {
if (this.level != null) {
if (ignoreTileUpdates) return; // Paper - Perf: Optimize Hoppers
- BlockEntity.setChanged(this.level, this.worldPosition, this.blockState);
+ BlockEntity.setChanged(this.level, this.worldPosition, this.blockState, this); // Sakura - optimise hopper ticking
}
}
protected static void setChanged(Level world, BlockPos pos, BlockState state) {
+ // Sakura start - optimise hopper ticking
+ net.minecraft.world.level.chunk.LevelChunk chunk = world.getChunkIfLoaded(pos);
+ BlockEntity blockEntity = chunk != null ? chunk.getBlockEntity(pos) : null;
+ setChanged(world, pos, state, blockEntity);
+ }
+
+ protected static void setChanged(Level world, BlockPos pos, BlockState state, @Nullable BlockEntity blockEntity) {
+ if (blockEntity != null) {
+ blockEntity.updateListeners(false);
+ }
+ // Sakura end - optimise hopper ticking
world.blockEntityChanged(pos);
if (!state.isAir()) {
world.updateNeighbourForOutputSignal(pos, state.getBlock());
@@ -267,6 +327,7 @@ public abstract class BlockEntity {
public void setRemoved() {
this.remove = true;
+ this.updateListeners(true); // Sakura - optimise hopper ticking
}
public void clearRemoved() {
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 cab403efd471bb61835224eea4e99570d34dcaaa..a359b592fb723e839e0a5ae9690da4e040abb13a 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
@@ -42,7 +42,7 @@ import org.bukkit.event.inventory.InventoryPickupItemEvent;
import org.bukkit.inventory.Inventory;
// CraftBukkit end
-public class HopperBlockEntity extends RandomizableContainerBlockEntity implements Hopper {
+public class HopperBlockEntity extends RandomizableContainerBlockEntity implements Hopper, BlockEntity.BlockEntityChangeListener { // Sakura - optimise hopper ticking
public static final int MOVE_ITEM_SPEED = 8;
public static final int HOPPER_CONTAINER_SIZE = 5;
@@ -81,6 +81,58 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
this.maxStack = size;
}
// CraftBukkit end
+ // Sakura start - optimise hopper ticking
+ private static final int SOURCE_CONTAINER = 1 << 0;
+ private static final int ATTACHED_CONTAINER = 1 << 1;
+ private int connectedContainers = 0;
+
+ @Override
+ public final void neighborChange() {
+ this.startTicking();
+ }
+
+ @Override
+ public final void neighborRemoved() {
+ this.connectedContainers = 0;
+ this.startTicking();
+ }
+
+ private void startTicking() {
+ this.cooldownTime -= this.getIdleTickCount();
+ this.setBlockEntityTicking(true);
+ }
+
+ private void waitForChange(int fullState) {
+ if ((fullState == HOPPER_IS_FULL || (this.connectedContainers & SOURCE_CONTAINER) != 0) && (this.connectedContainers & ATTACHED_CONTAINER) != 0) {
+ this.addListener(this);
+ this.setBlockEntityTicking(false);
+ }
+ }
+
+ private static @Nullable Container sakura_getSourceContainer(Level level, Hopper hopper, BlockPos pos, BlockState state) {
+ Container container = getSourceContainer(level, hopper, pos, state);
+ if (hopper instanceof HopperBlockEntity hbe && HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ hbe.listenForContainerChanges(container, SOURCE_CONTAINER);
+ }
+ return container;
+ }
+
+ private static @Nullable Container sakura_getAttachedContainer(Level level, BlockPos pos, HopperBlockEntity hbe) {
+ Container container = getAttachedContainer(level, pos, hbe);
+ if (HopperInventorySearchEvent.getHandlerList().getRegisteredListeners().length == 0) {
+ hbe.listenForContainerChanges(container, ATTACHED_CONTAINER);
+ }
+ return container;
+ }
+
+ private void listenForContainerChanges(@Nullable Container container, int type) {
+ if (container != null && container.addListener(this)) {
+ this.connectedContainers |= type; // set
+ } else if ((this.connectedContainers & type) != 0) {
+ this.connectedContainers ^= type; // unset
+ }
+ }
+ // Sakura end - optimise hopper ticking
public HopperBlockEntity(BlockPos pos, BlockState state) {
super(BlockEntityType.HOPPER, pos, state);
@@ -214,6 +266,12 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
setChanged(world, pos, state);
return true;
}
+
+ // Sakura start - optimise hopper ticking
+ if (world.sakuraConfig().technical.optimiseIdleHopperTicking) {
+ blockEntity.waitForChange(fullState);
+ }
+ // Sakura end - optimise hopper ticking
}
return false;
@@ -433,7 +491,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
// Paper end - Perf: Optimize Hoppers
private static boolean ejectItems(Level world, BlockPos pos, HopperBlockEntity blockEntity) {
- Container iinventory = HopperBlockEntity.getAttachedContainer(world, pos, blockEntity);
+ Container iinventory = HopperBlockEntity.sakura_getAttachedContainer(world, pos, blockEntity); // Sakura
if (iinventory == null) {
return false;
@@ -548,7 +606,7 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
public static boolean suckInItems(Level world, Hopper hopper) {
BlockPos blockposition = BlockPos.containing(hopper.getLevelX(), hopper.getLevelY() + 1.0D, hopper.getLevelZ());
BlockState iblockdata = world.getBlockState(blockposition);
- Container iinventory = HopperBlockEntity.getSourceContainer(world, hopper, blockposition, iblockdata);
+ Container iinventory = HopperBlockEntity.sakura_getSourceContainer(world, hopper, blockposition, iblockdata); // Sakura - optimise hopper ticking
if (iinventory != null) {
Direction enumdirection = Direction.DOWN;
diff --git a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
index 28e3b73507b988f7234cbf29c4024c88180d0aef..a0d247aa883553708c4b92158232425593d50534 100644
--- a/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
+++ b/src/main/java/net/minecraft/world/level/block/entity/TickingBlockEntity.java
@@ -10,4 +10,10 @@ public interface TickingBlockEntity {
BlockPos getPos();
String getType();
+
+ // Sakura start - optimise hopper ticking
+ default boolean isBlockEntityActive() {
+ return true;
+ }
+ // Sakura end - optimise hopper ticking
}
diff --git a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
index 7c11853c5090fbc4fa5b3e73a69acf166158fdec..debd755263d92198b3bafb02cf5eb78f01f0cec1 100644
--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java
@@ -1000,6 +1000,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
return this.ticker.getType();
}
+ // Sakura start - optimise hopper ticking
+ @Override
+ public boolean isBlockEntityActive() {
+ return this.ticker.isBlockEntityActive();
+ }
+ // Sakura end - optimise hopper ticking
+
public String toString() {
return String.valueOf(this.ticker) + " <wrapped>";
}
@@ -1076,6 +1083,13 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p
return BlockEntityType.getKey(this.blockEntity.getType()).toString();
}
+ // Sakura start - optimise hopper ticking
+ @Override
+ public boolean isBlockEntityActive() {
+ return this.blockEntity.isBlockEntityActive();
+ }
+ // Sakura end - optimise hopper ticking
+
public String toString() {
String s = this.getType();