9
0
mirror of https://github.com/BX-Team/DivineMC.git synced 2025-12-21 15:59:23 +00:00

remove hoppers opts; fix another crashes; hopper throttle

This commit is contained in:
NONPLAYT
2025-04-12 18:30:01 +03:00
parent 98d1b170bb
commit ef9d141d16
41 changed files with 400 additions and 702 deletions

View File

@@ -3320,3 +3320,134 @@ index ab1dcbe416e2c3c94cfddf04b7ed053425a71806..a37eb2e29b4577ebc711e8ef7b47fbbc
private Vec3i size = Vec3i.ZERO;
private String author = "?";
// CraftBukkit start - data containers
diff --git a/net/minecraft/world/ticks/LevelChunkTicks.java b/net/minecraft/world/ticks/LevelChunkTicks.java
index faf45ac459f7c25309d6ef6dce371d484a0dae7b..0e862e9c0d9d562e77ce02a35deb761c28fa2f90 100644
--- a/net/minecraft/world/ticks/LevelChunkTicks.java
+++ b/net/minecraft/world/ticks/LevelChunkTicks.java
@@ -18,10 +18,10 @@ 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
- private final Queue<ScheduledTick<T>> tickQueue = new PriorityQueue<>(ScheduledTick.DRAIN_ORDER);
+ private final Queue<ScheduledTick<T>> tickQueue = new java.util.concurrent.PriorityBlockingQueue<>(11, ScheduledTick.DRAIN_ORDER); // DivineMC - Chunk System Optimizations
@Nullable
private List<SavedTick<T>> pendingTicks;
- private final Set<ScheduledTick<?>> ticksPerPosition = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> ticksPerPosition = it.unimi.dsi.fastutil.objects.ObjectSets.synchronize(new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH)); // DivineMC - Chunk System Optimizations
@Nullable
private BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> onTickAdded;
@@ -71,10 +71,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 - Chunk System Optimizations
+ 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) {
+ net.minecraft.server.MinecraftServer.LOGGER.error("Encountered caught exception when polling chunk ticks, blocking and returning null.", e);
+ return null;
}
+ // DivineMC end - Chunk System Optimizations
return scheduledTick;
}
@@ -87,6 +95,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
private void scheduleUnchecked(ScheduledTick<T> tick) {
+ if (tick == null) return; // DivineMC - Chunk System Optimizations
this.tickQueue.add(tick);
if (this.onTickAdded != null) {
this.onTickAdded.accept(this, tick);
@@ -127,6 +136,7 @@ public class LevelChunkTicks<T> implements SerializableTickContainer<T>, TickCon
}
for (ScheduledTick<T> scheduledTick : this.tickQueue) {
+ if (scheduledTick == null) continue; // DivineMC - Chunk System Optimizations - fix NPE
list.add(scheduledTick.toSavedTick(gametime));
}
diff --git a/net/minecraft/world/ticks/LevelTicks.java b/net/minecraft/world/ticks/LevelTicks.java
index 0a9805d42142678ca5213c511235daa6505ddbf3..cd73f1a3ccc80e4ab1766147fccc67d81eeb4cc3 100644
--- a/net/minecraft/world/ticks/LevelTicks.java
+++ b/net/minecraft/world/ticks/LevelTicks.java
@@ -30,17 +30,18 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private static final Comparator<LevelChunkTicks<?>> CONTAINER_DRAIN_ORDER = (levelChunkTicks, levelChunkTicks1) -> ScheduledTick.INTRA_TICK_DRAIN_ORDER
.compare(levelChunkTicks.peek(), levelChunkTicks1.peek());
private final LongPredicate tickCheck;
- private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = new Long2ObjectOpenHashMap<>();
- private final Long2LongMap nextTickForContainer = Util.make(new Long2LongOpenHashMap(), map -> map.defaultReturnValue(Long.MAX_VALUE));
- private final Queue<LevelChunkTicks<T>> containersToTick = new PriorityQueue<>(CONTAINER_DRAIN_ORDER);
- private final Queue<ScheduledTick<T>> toRunThisTick = new ArrayDeque<>();
+ private final Long2ObjectMap<LevelChunkTicks<T>> allContainers = it.unimi.dsi.fastutil.longs.Long2ObjectMaps.synchronize(new Long2ObjectOpenHashMap<>()); // DivineMC - Chunk System Optimizations
+ private final java.util.Map<Long, Long> nextTickForContainer = new java.util.concurrent.ConcurrentHashMap<>(); // DivineMC - Chunk System Optimizations
+ private final Queue<LevelChunkTicks<T>> containersToTick = new java.util.concurrent.PriorityBlockingQueue<>(11, CONTAINER_DRAIN_ORDER); // DivineMC - Chunk System Optimizations
+ private final Queue<ScheduledTick<T>> toRunThisTick = new java.util.concurrent.ConcurrentLinkedQueue<>(); // DivineMC - Chunk System Optimizations
private final List<ScheduledTick<T>> alreadyRunThisTick = new ArrayList<>();
- private final Set<ScheduledTick<?>> toRunThisTickSet = new ObjectOpenCustomHashSet<>(ScheduledTick.UNIQUE_TICK_HASH);
+ private final Set<ScheduledTick<?>> toRunThisTickSet = com.google.common.collect.Sets.newConcurrentHashSet(); // DivineMC - Chunk System Optimizations
private final BiConsumer<LevelChunkTicks<T>, ScheduledTick<T>> chunkScheduleUpdater = (levelChunkTicks, scheduledTick) -> {
if (scheduledTick.equals(levelChunkTicks.peek())) {
this.updateContainerScheduling(scheduledTick);
}
};
+ private final java.util.concurrent.atomic.AtomicInteger toRunThisTickCount = new java.util.concurrent.atomic.AtomicInteger(0); // DivineMC - Chunk System Optimizations
public LevelTicks(LongPredicate tickCheck) {
this.tickCheck = tickCheck;
@@ -90,12 +91,14 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
}
private void sortContainersToTick(long gameTime) {
- ObjectIterator<Entry> objectIterator = Long2LongMaps.fastIterator(this.nextTickForContainer);
+ java.util.Iterator<java.util.Map.Entry<Long, Long>> objectIterator = this.nextTickForContainer.entrySet().iterator(); // DivineMC - Chunk System Optimizations
while (objectIterator.hasNext()) {
- Entry entry = objectIterator.next();
- long longKey = entry.getLongKey();
- long longValue = entry.getLongValue();
+ // DivineMC start - Chunk System Optimizations
+ java.util.Map.Entry<Long, Long> entry = objectIterator.next();
+ long longKey = entry.getKey();
+ long longValue = entry.getValue();
+ // DivineMC end - Chunk System Optimizations
if (longValue <= gameTime) {
LevelChunkTicks<T> levelChunkTicks = this.allContainers.get(longKey);
if (levelChunkTicks == null) {
@@ -162,16 +165,19 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
}
private void scheduleForThisTick(ScheduledTick<T> tick) {
+ if (tick == null) return; // DivineMC - Chunk System Optimizations
this.toRunThisTick.add(tick);
+ this.toRunThisTickCount.incrementAndGet(); // DivineMC - Chunk System Optimizations
}
private boolean canScheduleMoreTicks(int maxAllowedTicks) {
- return this.toRunThisTick.size() < maxAllowedTicks;
+ return this.toRunThisTickCount.get() < maxAllowedTicks; // DivineMC - Chunk System Optimizations
}
private void runCollectedTicks(BiConsumer<BlockPos, T> ticker) {
while (!this.toRunThisTick.isEmpty()) {
ScheduledTick<T> scheduledTick = this.toRunThisTick.poll();
+ this.toRunThisTickCount.decrementAndGet(); // DivineMC - Chunk System Optimizations
if (!this.toRunThisTickSet.isEmpty()) {
this.toRunThisTickSet.remove(scheduledTick);
}
@@ -183,6 +189,7 @@ public class LevelTicks<T> implements LevelTickAccess<T> {
private void cleanupAfterTick() {
this.toRunThisTick.clear();
+ this.toRunThisTickCount.set(0); // DivineMC - Chunk System Optimizations
this.containersToTick.clear();
this.alreadyRunThisTick.clear();
this.toRunThisTickSet.clear();

View File

@@ -1,682 +0,0 @@
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 9f7698f8ce56d5d89cf86f6ea2d5b4d51b18c9a2..351b035d1f3025af28b5147b95b912e0e2ab9212 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1746,7 +1746,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
if (org.bxteam.divinemc.DivineConfig.enableParallelWorldTicking) {
serverLevelTickingSemaphore.acquire();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index e17f5ba74295eb6585520ab9e5cc1cb2e3107098..15e6804a5faccb0a4f514d6b94f5856c7c15ab76 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -194,7 +194,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);
@@ -1730,7 +1730,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"));
}
@@ -1761,13 +1761,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
@@ -2654,7 +2654,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")
@@ -2724,7 +2724,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;
}

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Lag compensation
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 351b035d1f3025af28b5147b95b912e0e2ab9212..1bcccba4df407ec4d53f49c3c2c7493db87b2240 100644
index 9f7698f8ce56d5d89cf86f6ea2d5b4d51b18c9a2..11b89a625b942f5f2f882c54dbfc08c16e983425 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -25,7 +25,7 @@ index 351b035d1f3025af28b5147b95b912e0e2ab9212..1bcccba4df407ec4d53f49c3c2c7493d
this.tickCount++;
this.tickRateManager.tick();
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 15e6804a5faccb0a4f514d6b94f5856c7c15ab76..a7743ea4e5d672e1aa0d0945e19f3469ef81df62 100644
index bab5834741d0f11732ef1d1723868b8701d84961..e034d9f903728cdf7356629694c9f528ba5ebae3 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -218,6 +218,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] MSPT Tracking for each world
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 1bcccba4df407ec4d53f49c3c2c7493db87b2240..54c8605a4e36605208344e39726a4c3bbe972076 100644
index 11b89a625b942f5f2f882c54dbfc08c16e983425..fc9de137ed1681afd1ef51391cf8f30fd4c61c4b 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1684,7 +1684,15 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -25,7 +25,7 @@ index 1bcccba4df407ec4d53f49c3c2c7493db87b2240..54c8605a4e36605208344e39726a4c3b
CrashReport crashReport = CrashReport.forThrowable(levelTickingException, "Exception ticking world");
serverLevel.fillReportDetails(crashReport);
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index a7743ea4e5d672e1aa0d0945e19f3469ef81df62..67a1d115ff5facd2293ac7ba9d5eba890df343dd 100644
index e034d9f903728cdf7356629694c9f528ba5ebae3..561066a2cf769e13ef3cea0881f7a2010ecbf2ec 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -575,6 +575,12 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe

View File

@@ -6,7 +6,7 @@ Subject: [PATCH] Skip EntityScheduler's executeTick checks if there isn't any
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 54c8605a4e36605208344e39726a4c3bbe972076..72ab570ca8b532a1f55408515f34a02aa0c79a6a 100644
index fc9de137ed1681afd1ef51391cf8f30fd4c61c4b..804de864da13ae0be6a1caee88e95a19e35d08c0 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -290,6 +290,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Re-Fix MC-117075
diff --git a/net/minecraft/world/level/Level.java b/net/minecraft/world/level/Level.java
index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c4290634bbae9b 100644
index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..92fc936c6bdbda909b9cdf157ec9d46a4872098c 100644
--- a/net/minecraft/world/level/Level.java
+++ b/net/minecraft/world/level/Level.java
@@ -113,7 +113,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -17,7 +17,14 @@ index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c42906
protected final NeighborUpdater neighborUpdater;
private final List<TickingBlockEntity> pendingBlockEntityTickers = Lists.newArrayList();
private boolean tickingBlockEntities;
@@ -1528,7 +1528,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1521,14 +1521,12 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
boolean runsNormally = this.tickRateManager().runsNormally();
int tickedEntities = 0; // Paper - rewrite chunk system
- var toRemove = new it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet<TickingBlockEntity>(); // Paper - Fix MC-117075; use removeAll
- toRemove.add(null); // Paper - Fix MC-117075
for (tileTickPosition = 0; tileTickPosition < this.blockEntityTickers.size(); tileTickPosition++) { // Paper - Disable tick limiters
this.tileTickPosition = (this.tileTickPosition < this.blockEntityTickers.size()) ? this.tileTickPosition : 0;
TickingBlockEntity tickingBlockEntity = this.blockEntityTickers.get(this.tileTickPosition);
// Spigot end
if (tickingBlockEntity.isRemoved()) {
@@ -26,11 +33,12 @@ index 9608aa7231e1e19ac34f7fcf6cc4051da01f2f3e..440d890d32a6705aa5ebc84040c42906
} else if (runsNormally && this.shouldTickBlocksAt(tickingBlockEntity.getPos())) {
tickingBlockEntity.tick();
// DivineMC start - Parallel world ticking
@@ -1541,6 +1541,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
@@ -1539,7 +1537,7 @@ public abstract class Level implements LevelAccessor, AutoCloseable, ca.spottedl
// DivineMC end - Parallel world ticking
}
this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
}
- this.blockEntityTickers.removeAll(toRemove); // Paper - Fix MC-117075
+ this.blockEntityTickers.removeMarkedEntries(); // DivineMC - optimize block entity removals - Fix MC-117075
this.tickingBlockEntities = false;
this.spigotConfig.currentPrimedTnt = 0; // Spigot
}

View File

@@ -20,7 +20,7 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..aa4dd7517e8be167aef1eaf7aa907e3c
if (var4 instanceof ReportedException reportedException && reportedException.getCause() instanceof OutOfMemoryError) {
throw makeReportedException(var4, packet, processor);
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 72ab570ca8b532a1f55408515f34a02aa0c79a6a..fe2d9328a7e9365f8c7e24e862038bc94ddfe1ca 100644
index 804de864da13ae0be6a1caee88e95a19e35d08c0..5a0c8791495aa522e511918ad0a24d9bbe6b5877 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -1694,6 +1694,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -36,10 +36,10 @@ index 212d2bcfd34f7cb14e18a8af2cd296fc01d371f6..ec76e4f29ba96b31a24a5d195b852342
new java.util.concurrent.LinkedBlockingQueue<>(),
new com.google.common.util.concurrent.ThreadFactoryBuilder()
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index fe2d9328a7e9365f8c7e24e862038bc94ddfe1ca..daf6141a6aed6baf7b8de4030324703a0fe872d3 100644
index 5a0c8791495aa522e511918ad0a24d9bbe6b5877..9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -2709,8 +2709,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2710,8 +2710,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}
}

View File

@@ -5,14 +5,14 @@ Subject: [PATCH] Async Chunk Sending
diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
index 76b8d42ae530b59cdaba0583365a557da6b90ede..4943f57f648d5350e174c995ccb12bf8b2eb700f 100644
index 76b8d42ae530b59cdaba0583365a557da6b90ede..235772cc9a7c878235b97c8d84cacda3016f91ca 100644
--- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
+++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java
@@ -55,6 +55,8 @@ public final class RegionizedPlayerChunkLoader {
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
+ public static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader");
+ private static final org.apache.logging.log4j.Logger LOGGER = org.apache.logging.log4j.LogManager.getLogger("RegionizedPlayerChunkLoader"); // DivineMC - Async Chunk Sending
+
public static final class ViewDistanceHolder {

View File

@@ -54,7 +54,7 @@ index 51c126735ace8fdde89ad97b5cab62f244212db0..c466ce5c669e4b5ed835b13584a5ae5a
+ public void moonrise$write(final org.stupidcraft.linearpaper.region.IRegionFile regionFile) throws IOException; // DivineMC - Linear region file format
}
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index daf6141a6aed6baf7b8de4030324703a0fe872d3..6182c6f7cc6f5199897a5e227dabe9f9738733a5 100644
index 9d6fa3bced0ba5ab3443bdf4ce306598a8e4a31f..34bc5d54de26608e64170bd902baa87da137dab6 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -947,10 +947,10 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Async mob spawning
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
index 6182c6f7cc6f5199897a5e227dabe9f9738733a5..272a87eaa7a6406d0b059c18d7a7aa8c945dffa0 100644
index 34bc5d54de26608e64170bd902baa87da137dab6..ec09a21a71b00031efdd2561a14594b4013a2025 100644
--- a/net/minecraft/server/MinecraftServer.java
+++ b/net/minecraft/server/MinecraftServer.java
@@ -291,6 +291,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

View File

@@ -31,7 +31,7 @@ index ae0a3c3d9d6300293a6d0dff5cae49ebe7c11dab..3b08dad7a9fac7ac9acec0bfb85d4826
}
}
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index 67a1d115ff5facd2293ac7ba9d5eba890df343dd..c7bbadc61f51d04bc675926600e83ee0efb98e4a 100644
index 561066a2cf769e13ef3cea0881f7a2010ecbf2ec..5fe908ce51f95e1eab024dcd41ed108373f17fea 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -818,6 +818,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe

View File

@@ -5,7 +5,7 @@ Subject: [PATCH] Optimize Raids
diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java
index c7bbadc61f51d04bc675926600e83ee0efb98e4a..b31a5daf6acb9e2ef424ad08ccb338fb29dc8e69 100644
index 5fe908ce51f95e1eab024dcd41ed108373f17fea..ca740891611fca528b69bc634c4b1f66407eb763 100644
--- a/net/minecraft/server/level/ServerLevel.java
+++ b/net/minecraft/server/level/ServerLevel.java
@@ -219,6 +219,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe

View File

@@ -0,0 +1,24 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
Date: Sat, 12 Apr 2025 17:40:53 +0300
Subject: [PATCH] SparklyPaper: Allow throttling hopper checks if the target
container is full
Original project: https://github.com/SparklyPower/SparklyPaper
diff --git a/net/minecraft/world/level/block/entity/HopperBlockEntity.java b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
index 5cd1326ad5d046c88b2b3449d610a78fa880b4cd..6ad3388ac45a4d2ef85fc0fafece7de6e387f738 100644
--- a/net/minecraft/world/level/block/entity/HopperBlockEntity.java
+++ b/net/minecraft/world/level/block/entity/HopperBlockEntity.java
@@ -419,6 +419,11 @@ public class HopperBlockEntity extends RandomizableContainerBlockEntity implemen
} else {
Direction opposite = blockEntity.facing.getOpposite();
if (isFullContainer(attachedContainer, opposite)) {
+ // DivineMC start - SparklyPaper: Allow throttling hopper checks if the target container is full
+ if (org.bxteam.divinemc.DivineConfig.hopperThrottleWhenFull && org.bxteam.divinemc.DivineConfig.hopperThrottleSkipTicks > 0) {
+ blockEntity.setCooldown(org.bxteam.divinemc.DivineConfig.hopperThrottleSkipTicks);
+ }
+ // DivineMC end - SparklyPaper: Allow throttling hopper checks if the target container is full
return false;
} else {
// Paper start - Perf: Optimize Hoppers

View File

@@ -296,6 +296,216 @@ index 2bae9949ef325d0001aa638150fbbdf968367e75..11bf4ddb298bb39f7f39a9c33c90b48a
this.count = (short)0;
this.map.clear();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
index 460e27ab0506c83a28934800ee74ee886d4b025e..49e53bf85352f4d1b9997fa3c30e37e40c0ff01c 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed26WayDistancePropagator3D.java
@@ -15,7 +15,7 @@ public final class Delayed26WayDistancePropagator3D {
// Generally updates to positions are made close to other updates, so we link to decrease cache misses when
// propagating updates
- protected final LongLinkedOpenHashSet updatedSources = new LongLinkedOpenHashSet();
+ protected final it.unimi.dsi.fastutil.longs.LongSet updatedSources = it.unimi.dsi.fastutil.longs.LongSets.synchronize(new LongLinkedOpenHashSet()); // DivineMC - Chunk System Optimizations
@FunctionalInterface
public static interface LevelChangeCallback {
@@ -94,29 +94,29 @@ public final class Delayed26WayDistancePropagator3D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelRemoveWorkQueueBitset |= (1L << level);
}
- public boolean propagateUpdates() {
+ public synchronized boolean propagateUpdates() { // DivineMC - Chunk System Optimizations
if (this.updatedSources.isEmpty()) {
return false;
}
@@ -157,15 +157,15 @@ public final class Delayed26WayDistancePropagator3D {
return ret;
}
- protected void propagateIncreases() {
+ protected synchronized void propagateIncreases() { // DivineMC - Chunk System Optimizations
for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset);
this.levelIncreaseWorkQueueBitset != 0L;
this.levelIncreaseWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelIncreaseWorkQueueBitset)) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final boolean neighbourCheck = level < 0;
@@ -226,15 +226,15 @@ public final class Delayed26WayDistancePropagator3D {
}
}
- protected void propagateDecreases() {
+ protected synchronized void propagateDecreases() { // DivineMC - Chunk System Optimizations
for (int queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset);
this.levelRemoveWorkQueueBitset != 0L;
this.levelRemoveWorkQueueBitset ^= (1L << queueIndex), queueIndex = 63 ^ Long.numberOfLeadingZeros(this.levelRemoveWorkQueueBitset)) {
final Delayed8WayDistancePropagator2D.WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
index ab2fa1563d5e32a5313dfcc1da411cab45fb5ca0..1bababc2515d8c805e4ee0c943065f451a38b7b8 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
+++ b/src/main/java/ca/spottedleaf/moonrise/common/misc/Delayed8WayDistancePropagator2D.java
@@ -356,24 +356,24 @@ public final class Delayed8WayDistancePropagator2D {
protected final void addToIncreaseWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << level);
}
protected final void addToIncreaseWorkQueue(final long coordinate, final byte index, final byte level) {
final WorkQueue queue = this.levelIncreaseWorkQueues[index];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelIncreaseWorkQueueBitset |= (1L << index);
}
protected final void addToRemoveWorkQueue(final long coordinate, final byte level) {
final WorkQueue queue = this.levelRemoveWorkQueues[level];
- queue.queuedCoordinates.enqueue(coordinate);
- queue.queuedLevels.enqueue(level);
+ queue.queuedCoordinates.add(coordinate); // DivineMC - Chunk System Optimizations
+ queue.queuedLevels.add(level); // DivineMC - Chunk System Optimizations
this.levelRemoveWorkQueueBitset |= (1L << level);
}
@@ -426,8 +426,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelIncreaseWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final boolean neighbourCheck = level < 0;
@@ -492,8 +492,8 @@ public final class Delayed8WayDistancePropagator2D {
final WorkQueue queue = this.levelRemoveWorkQueues[queueIndex];
while (!queue.queuedLevels.isEmpty()) {
- final long coordinate = queue.queuedCoordinates.removeFirstLong();
- final byte level = queue.queuedLevels.removeFirstByte();
+ final long coordinate = queue.queuedCoordinates.removeFirst(); // DivineMC - Chunk System Optimizations
+ final byte level = queue.queuedLevels.removeFirst(); // DivineMC - Chunk System Optimizations
final byte currentLevel = this.levels.removeIfGreaterOrEqual(coordinate, level);
if (currentLevel == 0) {
@@ -561,7 +561,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private int find(final long k) {
+ private synchronized int find(final long k) { // DivineMC - Chunk System Optimizations
if (k == 0L) {
return this.containsNullKey ? this.n : -(this.n + 1);
} else {
@@ -585,7 +585,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void insert(final int pos, final long k, final byte v) {
+ private synchronized void insert(final int pos, final long k, final byte v) { // DivineMC - Chunk System Optimizations
if (pos == this.n) {
this.containsNullKey = true;
}
@@ -598,7 +598,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- public byte putIfGreater(final long key, final byte value) {
+ public synchronized byte putIfGreater(final long key, final byte value) { // DivineMC - Chunk System Optimizations
final int pos = this.find(key);
if (pos < 0) {
if (this.defRetValue < value) {
@@ -616,7 +616,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void removeEntry(final int pos) {
+ private synchronized void removeEntry(final int pos) { // DivineMC - Chunk System Optimizations
--this.size;
this.shiftKeys(pos);
if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) {
@@ -625,7 +625,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- private void removeNullEntry() {
+ private synchronized void removeNullEntry() { // DivineMC - Chunk System Optimizations
this.containsNullKey = false;
--this.size;
if (this.n > this.minN && this.size < this.maxFill / 4 && this.n > 16) {
@@ -634,7 +634,7 @@ public final class Delayed8WayDistancePropagator2D {
}
// copied from superclass
- public byte removeIfGreaterOrEqual(final long key, final byte value) {
+ public synchronized byte removeIfGreaterOrEqual(final long key, final byte value) { // DivineMC - Chunk System Optimizations
if (key == 0L) {
if (!this.containsNullKey) {
return this.defRetValue;
@@ -679,8 +679,8 @@ public final class Delayed8WayDistancePropagator2D {
protected static final class WorkQueue {
- public final NoResizeLongArrayFIFODeque queuedCoordinates = new NoResizeLongArrayFIFODeque();
- public final NoResizeByteArrayFIFODeque queuedLevels = new NoResizeByteArrayFIFODeque();
+ public final java.util.concurrent.ConcurrentLinkedDeque<Long> queuedCoordinates = new java.util.concurrent.ConcurrentLinkedDeque<>();
+ public final java.util.concurrent.ConcurrentLinkedDeque<Byte> queuedLevels = new java.util.concurrent.ConcurrentLinkedDeque<>();
}
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java b/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java
index 632920e04686d8a0fd0a60e87348be1fe7862a3c..f10c6c156b8dd9acecc8b1ee81bd28260fb6e4d8 100644
--- a/src/main/java/ca/spottedleaf/moonrise/common/util/MoonriseCommon.java

View File

@@ -279,6 +279,8 @@ public class DivineConfig {
public static boolean disableLeafDecay = false;
public static boolean commandBlockParseResultsCaching = true;
public static boolean enableAsyncSpawning = true;
public static boolean hopperThrottleWhenFull = false;
public static int hopperThrottleSkipTicks = 0;
private static void miscSettings() {
skipUselessSecondaryPoiSensor = getBoolean("settings.misc.skip-useless-secondary-poi-sensor", skipUselessSecondaryPoiSensor);
clumpOrbs = getBoolean("settings.misc.clump-orbs", clumpOrbs,
@@ -300,6 +302,11 @@ public class DivineConfig {
"Caches the parse results of command blocks, can significantly reduce performance impact.");
enableAsyncSpawning = getBoolean("settings.misc.enable-async-spawning", enableAsyncSpawning,
"Enables optimization that will offload much of the computational effort involved with spawning new mobs to a different thread.");
hopperThrottleWhenFull = getBoolean("settings.misc.hopper-throttle-when-full.enabled", hopperThrottleWhenFull,
"When enabled, hoppers will throttle if target container is full.");
hopperThrottleSkipTicks = getInt("settings.misc.hopper-throttle-when-full.skip-ticks", hopperThrottleSkipTicks,
"The amount of ticks to skip when the hopper is throttled.");
}
public static String sentryDsn = "";