diff --git a/patches/server/0003-Petal-patches.patch b/patches/removed/0003-Async-path-processing.patch similarity index 60% rename from patches/server/0003-Petal-patches.patch rename to patches/removed/0003-Async-path-processing.patch index 5a2d755..1878750 100644 --- a/patches/server/0003-Petal-patches.patch +++ b/patches/removed/0003-Async-path-processing.patch @@ -1,9 +1,9 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: peaches94 Date: Sun, 26 Jun 2022 16:51:37 -0500 -Subject: [PATCH] Petal patches +Subject: [PATCH] Async path processing -Original code by Bloom-host, licensed under GPL-3.0. +Original code by Bloom-host, licensed under GNU General Public License v3.0 You can find the original code on https://github.com/Bloom-host/Petal diff --git a/src/main/java/host/bloom/pathfinding/AsyncPath.java b/src/main/java/host/bloom/pathfinding/AsyncPath.java @@ -411,408 +411,6 @@ index 0000000000000000000000000000000000000000..d5327cb257d63291adc8b5c60cffb4e4 + @NotNull NodeEvaluator generate(); + +} -diff --git a/src/main/java/host/bloom/tracker/MultithreadedTracker.java b/src/main/java/host/bloom/tracker/MultithreadedTracker.java -new file mode 100644 -index 0000000000000000000000000000000000000000..d27b7224ed2bcc63386dc46c33bfb8b272d91f92 ---- /dev/null -+++ b/src/main/java/host/bloom/tracker/MultithreadedTracker.java -@@ -0,0 +1,154 @@ -+package host.bloom.tracker; -+ -+import com.google.common.util.concurrent.ThreadFactoryBuilder; -+import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; -+import io.papermc.paper.world.ChunkEntitySlices; -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ChunkMap; -+import net.minecraft.world.entity.Entity; -+import net.minecraft.world.level.chunk.LevelChunk; -+ -+import java.util.concurrent.ConcurrentLinkedQueue; -+import java.util.concurrent.Executor; -+import java.util.concurrent.Executors; -+import java.util.concurrent.atomic.AtomicInteger; -+ -+public class MultithreadedTracker { -+ -+ private enum TrackerStage { -+ UPDATE_PLAYERS, -+ SEND_CHANGES -+ } -+ -+ private static final int parallelism = Math.max(4, Runtime.getRuntime().availableProcessors()); -+ private static final Executor trackerExecutor = Executors.newFixedThreadPool(parallelism, new ThreadFactoryBuilder() -+ .setNameFormat("petal-tracker-%d") -+ .setPriority(Thread.NORM_PRIORITY - 2) -+ .build()); -+ -+ private final IteratorSafeOrderedReferenceSet entityTickingChunks; -+ private final AtomicInteger taskIndex = new AtomicInteger(); -+ -+ private final ConcurrentLinkedQueue mainThreadTasks; -+ private final AtomicInteger finishedTasks = new AtomicInteger(); -+ -+ public MultithreadedTracker(IteratorSafeOrderedReferenceSet entityTickingChunks, ConcurrentLinkedQueue mainThreadTasks) { -+ this.entityTickingChunks = entityTickingChunks; -+ this.mainThreadTasks = mainThreadTasks; -+ } -+ -+ public void tick() { -+ int iterator = this.entityTickingChunks.createRawIterator(); -+ -+ if (iterator == -1) { -+ return; -+ } -+ -+ // start with updating players -+ try { -+ this.taskIndex.set(iterator); -+ this.finishedTasks.set(0); -+ -+ for (int i = 0; i < parallelism; i++) { -+ trackerExecutor.execute(this::runUpdatePlayers); -+ } -+ -+ while (this.taskIndex.get() < this.entityTickingChunks.getListSize()) { -+ this.runMainThreadTasks(); -+ this.handleChunkUpdates(5); // assist -+ } -+ -+ while (this.finishedTasks.get() != parallelism) { -+ this.runMainThreadTasks(); -+ } -+ -+ this.runMainThreadTasks(); // finish any remaining tasks -+ } finally { -+ this.entityTickingChunks.finishRawIterator(); -+ } -+ -+ // then send changes -+ iterator = this.entityTickingChunks.createRawIterator(); -+ -+ if (iterator == -1) { -+ return; -+ } -+ -+ try { -+ do { -+ LevelChunk chunk = this.entityTickingChunks.rawGet(iterator); -+ -+ if (chunk != null) { -+ this.updateChunkEntities(chunk, TrackerStage.SEND_CHANGES); -+ } -+ } while (++iterator < this.entityTickingChunks.getListSize()); -+ } finally { -+ this.entityTickingChunks.finishRawIterator(); -+ } -+ } -+ -+ private void runMainThreadTasks() { -+ try { -+ Runnable task; -+ while ((task = this.mainThreadTasks.poll()) != null) { -+ task.run(); -+ } -+ } catch (Throwable throwable) { -+ MinecraftServer.LOGGER.warn("Tasks failed while ticking track queue", throwable); -+ } -+ } -+ -+ private void runUpdatePlayers() { -+ try { -+ while (handleChunkUpdates(10)); -+ } finally { -+ this.finishedTasks.incrementAndGet(); -+ } -+ } -+ -+ private boolean handleChunkUpdates(int tasks) { -+ int index; -+ while ((index = this.taskIndex.getAndAdd(tasks)) < this.entityTickingChunks.getListSize()) { -+ for (int i = index; i < index + tasks && i < this.entityTickingChunks.getListSize(); i++) { -+ LevelChunk chunk = this.entityTickingChunks.rawGet(i); -+ if (chunk != null) { -+ try { -+ this.updateChunkEntities(chunk, TrackerStage.UPDATE_PLAYERS); -+ } catch (Throwable throwable) { -+ MinecraftServer.LOGGER.warn("Ticking tracker failed", throwable); -+ } -+ -+ } -+ } -+ -+ return true; -+ } -+ -+ return false; -+ } -+ -+ private void updateChunkEntities(LevelChunk chunk, TrackerStage trackerStage) { -+ final ChunkEntitySlices entitySlices = chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ); -+ if (entitySlices == null) { -+ return; -+ } -+ -+ final Entity[] rawEntities = entitySlices.entities.getRawData(); -+ final ChunkMap chunkMap = chunk.level.chunkSource.chunkMap; -+ -+ for (int i = 0; i < rawEntities.length; i++) { -+ Entity entity = rawEntities[i]; -+ if (entity != null) { -+ ChunkMap.TrackedEntity entityTracker = chunkMap.entityMap.get(entity.getId()); -+ if (entityTracker != null) { -+ if (trackerStage == TrackerStage.SEND_CHANGES) { -+ entityTracker.serverEntity.sendChanges(); -+ } else if (trackerStage == TrackerStage.UPDATE_PLAYERS) { -+ entityTracker.updatePlayers(entityTracker.entity.getPlayersInTrackRange()); -+ } -+ } -+ } -+ } -+ } -+ -+} -diff --git a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java -index 0fd814f1d65c111266a2b20f86561839a4cef755..169ac3ad1b1e8e3e1874ada2471e478233c6ada7 100644 ---- a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java -+++ b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java -@@ -15,7 +15,7 @@ public final class IteratorSafeOrderedReferenceSet { - - /* list impl */ - protected E[] listElements; -- protected int listSize; -+ protected int listSize; public int getListSize() { return this.listSize; } // petal - expose listSize - - protected final double maxFragFactor; - -diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java -index f597d65d56964297eeeed6c7e77703764178fee0..665c377e2d0d342f4dcc89c4cbdfcc9e4b96e95c 100644 ---- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java -+++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java -@@ -35,7 +35,7 @@ public final class ChunkEntitySlices { - protected final EntityCollectionBySection allEntities; - protected final EntityCollectionBySection hardCollidingEntities; - protected final Reference2ObjectOpenHashMap, EntityCollectionBySection> entitiesByClass; -- protected final EntityList entities = new EntityList(); -+ public final EntityList entities = new EntityList(); - - public ChunkHolder.FullChunkStatus status; - -diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 3203b953709ca7cb9172f5912a922131ad7ec9eb..3c99de7bc5b3c5159ad76f63d67877756f152385 100644 ---- a/src/main/java/net/minecraft/server/level/ChunkMap.java -+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java -@@ -1237,8 +1237,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - entity.tracker = null; // Paper - We're no longer tracked - } - -+ // petal start - multithreaded tracker -+ private @Nullable host.bloom.tracker.MultithreadedTracker multithreadedTracker; -+ private final java.util.concurrent.ConcurrentLinkedQueue trackerMainThreadTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); -+ private boolean tracking = false; -+ -+ public void runOnTrackerMainThread(final Runnable runnable) { -+ if (this.tracking) { -+ this.trackerMainThreadTasks.add(runnable); -+ } else { -+ runnable.run(); -+ } -+ } -+ - // Paper start - optimised tracker - private final void processTrackQueue() { -+ if (true) { -+ if (this.multithreadedTracker == null) { -+ this.multithreadedTracker = new host.bloom.tracker.MultithreadedTracker(this.level.chunkSource.entityTickingChunks, this.trackerMainThreadTasks); -+ } -+ -+ this.tracking = true; -+ try { -+ this.multithreadedTracker.tick(); -+ } finally { -+ this.tracking = false; -+ } -+ return; -+ } -+ // petal end -+ -+ this.level.timings.tracker1.startTiming(); - //this.level.timings.tracker1.startTiming(); // Purpur - try { - for (TrackedEntity tracker : this.entityMap.values()) { -@@ -1462,11 +1491,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - public class TrackedEntity { - -- final ServerEntity serverEntity; -- final Entity entity; -+ public final ServerEntity serverEntity; // petal -> public -+ public final Entity entity; // petal -> public - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl -+ public final Set seenBy = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Paper - optimise map impl // petal - sync - - public TrackedEntity(Entity entity, int i, int j, boolean flag) { - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit -@@ -1478,7 +1507,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper start - use distance map to optimise tracker - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet lastTrackerCandidates; - -- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { -+ public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { // petal -> public - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet oldTrackerCandidates = this.lastTrackerCandidates; - this.lastTrackerCandidates = newTrackerCandidates; - -@@ -1550,7 +1579,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void removePlayer(ServerPlayer player) { -- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot -+ //org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot // petal - we can remove async too - if (this.seenBy.remove(player.connection)) { - this.serverEntity.removePairing(player); - } -@@ -1558,7 +1587,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void updatePlayer(ServerPlayer player) { -- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot -+ //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot // petal - we can update async - if (player != this.entity) { - // Paper start - remove allocation of Vec3D here - // Vec3 vec3d = player.position().subtract(this.entity.position()); -diff --git a/src/main/java/net/minecraft/server/level/ServerBossEvent.java b/src/main/java/net/minecraft/server/level/ServerBossEvent.java -index ca42c2642a729b90d22b968af7258f3aee72e14b..40261b80d947a6be43465013fae5532197cfe721 100644 ---- a/src/main/java/net/minecraft/server/level/ServerBossEvent.java -+++ b/src/main/java/net/minecraft/server/level/ServerBossEvent.java -@@ -13,7 +13,7 @@ import net.minecraft.util.Mth; - import net.minecraft.world.BossEvent; - - public class ServerBossEvent extends BossEvent { -- private final Set players = Sets.newHashSet(); -+ private final Set players = Sets.newConcurrentHashSet(); // petal - players can be removed in async tracking - private final Set unmodifiablePlayers = Collections.unmodifiableSet(this.players); - public boolean visible = true; - -diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java -index 3441339e1ba5efb0e25c16fa13cb65d2fbdafc42..555336cf6700566e8a99e0f0cd6f0cc41b6c5ba0 100644 ---- a/src/main/java/net/minecraft/server/level/ServerEntity.java -+++ b/src/main/java/net/minecraft/server/level/ServerEntity.java -@@ -249,14 +249,18 @@ public class ServerEntity { - - public void removePairing(ServerPlayer player) { - this.entity.stopSeenByPlayer(player); -- player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()})); -+ // petal start - ensure main thread -+ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> -+ player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()})) -+ ); -+ // petal end - } - - public void addPairing(ServerPlayer player) { - ServerGamePacketListenerImpl playerconnection = player.connection; - - Objects.requireNonNull(player.connection); -- this.sendPairingData(playerconnection::send, player); // CraftBukkit - add player -+ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> this.sendPairingData(playerconnection::send, player)); // CraftBukkit - add player // petal - main thread - this.entity.startSeenByPlayer(player); - } - -@@ -362,19 +366,30 @@ public class ServerEntity { - SynchedEntityData datawatcher = this.entity.getEntityData(); - - if (datawatcher.isDirty()) { -- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false)); -+ // Petal start - sync -+ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> -+ this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false)) -+ ); -+ // Petal end - } - - if (this.entity instanceof LivingEntity) { - Set set = ((LivingEntity) this.entity).getAttributes().getDirtyAttributes(); - - if (!set.isEmpty()) { -+ // Petal start - sync -+ final var copy = Lists.newArrayList(set); -+ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> { -+ - // CraftBukkit start - Send scaled max health - if (this.entity instanceof ServerPlayer) { -- ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(set, false); -+ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(copy, false); - } - // CraftBukkit end -- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), set)); -+ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy)); -+ -+ }); -+ // Petal end - } - - set.clear(); -diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 571a1cbee376032b6b9f36c9fe3f9199a3ad3197..92e7ba78e18efb8263475ecc076bc49e88b85e84 100644 ---- a/src/main/java/net/minecraft/server/level/ServerLevel.java -+++ b/src/main/java/net/minecraft/server/level/ServerLevel.java -@@ -1703,6 +1703,7 @@ public class ServerLevel extends Level implements WorldGenLevel { - if (chunk != null) { - for (int j2 = k; j2 <= j1; ++j2) { - flag |= chunk.getEventDispatcher(j2).walkListeners(event, emitterPos, emitter, (gameeventlistener, vec3d1) -> { -+ if (!gameeventlistener.listensToEvent(event, emitter)) return; // petal - if they don't listen, ignore - (gameeventlistener.handleEventsImmediately() ? list : this.gameEventMessages).add(new GameEvent.Message(event, emitterPos, emitter, gameeventlistener, vec3d1)); - }); - } -diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 1fc877194950ee754e9ffdbe3ff9b80bb316560f..9fe6d0700f8f4d4cc018bcb4f33fffaa5f51a1d9 100644 ---- a/src/main/java/net/minecraft/world/entity/LivingEntity.java -+++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1012,20 +1012,22 @@ public abstract class LivingEntity extends Entity { - } - - if (entity != null) { -- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -+ // petal start - only do itemstack lookup if we need to -+ //ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); - EntityType entitytypes = entity.getType(); - - // Purpur start -- if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL)) { -+ if (entitytypes == EntityType.SKELETON && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.SKELETON_SKULL)) { - d0 *= entity.level.purpurConfig.skeletonHeadVisibilityPercent; - } -- else if (entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD)) { -+ else if (entitytypes == EntityType.ZOMBIE && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.ZOMBIE_HEAD)) { - d0 *= entity.level.purpurConfig.zombieHeadVisibilityPercent; - } -- else if (entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) { -+ else if (entitytypes == EntityType.CREEPER && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.CREEPER_HEAD)) { - d0 *= entity.level.purpurConfig.creeperHeadVisibilityPercent; - } - // Purpur end -+ // petal end - - // Purpur start - if (entity instanceof LivingEntity entityliving) { -diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index d5e3bd662da349fc2ee58c7800d79c60300f33b3..0981873ee37fc839035b8398bac03d15adecb301 100644 ---- a/src/main/java/net/minecraft/world/entity/Mob.java -+++ b/src/main/java/net/minecraft/world/entity/Mob.java -@@ -884,10 +884,10 @@ public abstract class Mob extends LivingEntity { - return; - } - // Paper end -+ int i = this.level.getServer().getTickCount() + this.getId(); // petal - move up - //this.level.getProfiler().push("sensing"); // Purpur -- this.sensing.tick(); -+ if (i % 10 == 0) this.sensing.tick(); // petal - only refresh line of sight cache every half second - //this.level.getProfiler().pop(); // Purpur -- int i = this.level.getServer().getTickCount() + this.getId(); - - if (i % 2 != 0 && this.tickCount > 1) { - //this.level.getProfiler().push("targetSelector"); // Purpur diff --git a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java b/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java index bf3b8ccb3e031e0ad24cd51e28ea8cbd4f8a8030..e0453df8c0fcdb40ef0ed5ae8865d45df3325e46 100644 --- a/src/main/java/net/minecraft/world/entity/ai/behavior/AcquirePoi.java @@ -1335,186 +933,6 @@ index 68e31cf561f3d76bce6fa4324a75594c776f8964..6ce824a1f74163f60fc3b222f3aaf59c BlockPos blockposition = pathentity.getTarget(); if (blockposition != null) { -diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -index 22c309343299e60ed8028229b7f134109001ff35..d5947d29295ddc93ba8ac1c0fc61f7badad582c4 100644 ---- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -+++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java -@@ -85,6 +85,13 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi - } - } - -+ // petal start -+ @Override -+ public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { -+ return !this.isRemoved() && gameEvent == GameEvent.ENTITY_DIE && context.sourceEntity() instanceof LivingEntity; -+ } -+ // petal end -+ - public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { - org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. - blockEntity.sculkSpreader.updateCursors(world, pos, world.getRandom(), true); -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 620173eef4c2f30a97a4c2f8049ea01fcc60d0b2..bdf67c916fe435f3bd04a61cce6db93c606515ce 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -+++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java -@@ -84,7 +84,18 @@ public class LevelChunk extends ChunkAccess { - private Supplier fullStatus; - @Nullable - private LevelChunk.PostLoadProcessor postLoad; -- private final Int2ObjectMap gameEventDispatcherSections; -+ // petal start -+ private final GameEventDispatcher[] gameEventDispatcherSections; -+ private static final int GAME_EVENT_DISPATCHER_RADIUS = 2; -+ -+ private static int getGameEventSectionIndex(int sectionIndex) { -+ return sectionIndex + GAME_EVENT_DISPATCHER_RADIUS; -+ } -+ -+ private static int getGameEventSectionLength(int sectionCount) { -+ return sectionCount + (GAME_EVENT_DISPATCHER_RADIUS * 2); -+ } -+ // petal end - private final LevelChunkTicks blockTicks; - private final LevelChunkTicks fluidTicks; - -@@ -113,7 +124,7 @@ public class LevelChunk extends ChunkAccess { - this.tickersInLevel = Maps.newHashMap(); - this.clientLightReady = false; - this.level = (ServerLevel) world; // CraftBukkit - type -- this.gameEventDispatcherSections = new Int2ObjectOpenHashMap(); -+ this.gameEventDispatcherSections = new GameEventDispatcher[getGameEventSectionLength(this.getSectionsCount())]; // petal - Heightmap.Types[] aheightmap_type = Heightmap.Types.values(); - int j = aheightmap_type.length; - -@@ -446,9 +457,23 @@ public class LevelChunk extends ChunkAccess { - if (world instanceof ServerLevel) { - ServerLevel worldserver = (ServerLevel) world; - -- return (GameEventDispatcher) this.gameEventDispatcherSections.computeIfAbsent(ySectionCoord, (j) -> { -- return new EuclideanGameEventDispatcher(worldserver); -- }); -+ // petal start -+ int sectionIndex = getGameEventSectionIndex(this.getSectionIndexFromSectionY(ySectionCoord)); -+ -+ // drop game events that are too far away (32 blocks) from loaded sections -+ // this matches the highest radius of game events in the game -+ if (sectionIndex < 0 || sectionIndex >= this.gameEventDispatcherSections.length) { -+ return GameEventDispatcher.NOOP; -+ } -+ -+ var dispatcher = this.gameEventDispatcherSections[sectionIndex]; -+ -+ if (dispatcher == null) { -+ dispatcher = this.gameEventDispatcherSections[sectionIndex] = new EuclideanGameEventDispatcher(worldserver); -+ } -+ -+ return dispatcher; -+ // petal end - } else { - return super.getEventDispatcher(ySectionCoord); - } -@@ -812,7 +837,7 @@ public class LevelChunk extends ChunkAccess { - - gameeventdispatcher.unregister(gameeventlistener); - if (gameeventdispatcher.isEmpty()) { -- this.gameEventDispatcherSections.remove(i); -+ this.gameEventDispatcherSections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(i))] = null; // petal - } - } - } -diff --git a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java -index 0dd708ebe81f73710de51215529c05ec61837dd3..f5b402efa86f824c460db8cac20c1c2b090f82d0 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java -@@ -13,8 +13,8 @@ import net.minecraft.world.phys.Vec3; - - public class EuclideanGameEventDispatcher implements GameEventDispatcher { - private final List listeners = Lists.newArrayList(); -- private final Set listenersToRemove = Sets.newHashSet(); -- private final List listenersToAdd = Lists.newArrayList(); -+ //private final Set listenersToRemove = Sets.newHashSet(); // petal - not necessary -+ //private final List listenersToAdd = Lists.newArrayList(); // petal - private boolean processing; - private final ServerLevel level; - -@@ -30,7 +30,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { - @Override - public void register(GameEventListener listener) { - if (this.processing) { -- this.listenersToAdd.add(listener); -+ throw new java.util.ConcurrentModificationException(); // petal - disallow concurrent modification - } else { - this.listeners.add(listener); - } -@@ -41,7 +41,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { - @Override - public void unregister(GameEventListener listener) { - if (this.processing) { -- this.listenersToRemove.add(listener); -+ throw new java.util.ConcurrentModificationException(); // petal - disallow concurrent modification - } else { - this.listeners.remove(listener); - } -@@ -58,7 +58,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { - - while(iterator.hasNext()) { - GameEventListener gameEventListener = iterator.next(); -- if (this.listenersToRemove.remove(gameEventListener)) { -+ if (false) { // petal - disallow concurrent modification - iterator.remove(); - } else { - Optional optional = getPostableListenerPosition(this.level, pos, gameEventListener); -@@ -72,6 +72,8 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { - this.processing = false; - } - -+ // petal start -+ /* - if (!this.listenersToAdd.isEmpty()) { - this.listeners.addAll(this.listenersToAdd); - this.listenersToAdd.clear(); -@@ -81,6 +83,8 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { - this.listeners.removeAll(this.listenersToRemove); - this.listenersToRemove.clear(); - } -+ */ -+ // petal end - - return bl; - } -diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java b/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java -index e5601afe8b739da518f36ae306f5e0cb252238f0..bc8f04424c5e8c416d6988f0e06d8cadbb400ca7 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java -@@ -12,4 +12,10 @@ public interface GameEventListener { - int getListenerRadius(); - - boolean handleGameEvent(ServerLevel world, GameEvent.Message event); -+ -+ // petal start - add check for seeing if this listener cares about an event -+ default boolean listensToEvent(net.minecraft.world.level.gameevent.GameEvent gameEvent, net.minecraft.world.level.gameevent.GameEvent.Context context) { -+ return true; -+ } -+ // petal end - } -diff --git a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java -index e45f54534bbf054eaf0008546ff459d4c11ddd50..e49d0d1c2a539fcd7e75262c4010475193964287 100644 ---- a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java -+++ b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java -@@ -162,6 +162,13 @@ public class VibrationListener implements GameEventListener { - return true; - } - -+ // petal start -+ @Override -+ public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { -+ return this.receivingEvent == null && gameEvent.is(this.config.getListenableEvents()); -+ } -+ // petal end -+ - public interface VibrationListenerConfig { - - default TagKey getListenableEvents() { diff --git a/src/main/java/net/minecraft/world/level/pathfinder/Path.java b/src/main/java/net/minecraft/world/level/pathfinder/Path.java index 2a335f277bd0e4b8ad0f60d8226eb8aaa80a871f..527f5fb55b596b44c7418a6f70e7243432c160dd 100644 --- a/src/main/java/net/minecraft/world/level/pathfinder/Path.java diff --git a/patches/removed/0004-Multithreaded-tracker.patch b/patches/removed/0004-Multithreaded-tracker.patch new file mode 100644 index 0000000..b5602e3 --- /dev/null +++ b/patches/removed/0004-Multithreaded-tracker.patch @@ -0,0 +1,362 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: peaches94 +Date: Sat, 2 Jul 2022 00:35:56 -0500 +Subject: [PATCH] Multithreaded tracker + +Original code by Bloom-host, licensed under GNU General Public License v3.0 +You can find the original code on https://github.com/Bloom-host/Petal + +Co-authored-by: Paul Sauve +Co-authored-by: Kevin Raneri + +based off the airplane multithreaded tracker this patch properly handles +concurrent accesses everywhere, as well as being much simpler to maintain + +some things are too unsafe to run off the main thread so we don't attempt to do +that. this multithreaded tracker remains accurate, non-breaking and fast + +we also learned from pufferfish core that changes have to be sent ordered +now we do that in an optimized way + +diff --git a/src/main/java/host/bloom/tracker/MultithreadedTracker.java b/src/main/java/host/bloom/tracker/MultithreadedTracker.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d27b7224ed2bcc63386dc46c33bfb8b272d91f92 +--- /dev/null ++++ b/src/main/java/host/bloom/tracker/MultithreadedTracker.java +@@ -0,0 +1,154 @@ ++package host.bloom.tracker; ++ ++import com.google.common.util.concurrent.ThreadFactoryBuilder; ++import io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet; ++import io.papermc.paper.world.ChunkEntitySlices; ++import net.minecraft.server.MinecraftServer; ++import net.minecraft.server.level.ChunkMap; ++import net.minecraft.world.entity.Entity; ++import net.minecraft.world.level.chunk.LevelChunk; ++ ++import java.util.concurrent.ConcurrentLinkedQueue; ++import java.util.concurrent.Executor; ++import java.util.concurrent.Executors; ++import java.util.concurrent.atomic.AtomicInteger; ++ ++public class MultithreadedTracker { ++ ++ private enum TrackerStage { ++ UPDATE_PLAYERS, ++ SEND_CHANGES ++ } ++ ++ private static final int parallelism = Math.max(4, Runtime.getRuntime().availableProcessors()); ++ private static final Executor trackerExecutor = Executors.newFixedThreadPool(parallelism, new ThreadFactoryBuilder() ++ .setNameFormat("petal-tracker-%d") ++ .setPriority(Thread.NORM_PRIORITY - 2) ++ .build()); ++ ++ private final IteratorSafeOrderedReferenceSet entityTickingChunks; ++ private final AtomicInteger taskIndex = new AtomicInteger(); ++ ++ private final ConcurrentLinkedQueue mainThreadTasks; ++ private final AtomicInteger finishedTasks = new AtomicInteger(); ++ ++ public MultithreadedTracker(IteratorSafeOrderedReferenceSet entityTickingChunks, ConcurrentLinkedQueue mainThreadTasks) { ++ this.entityTickingChunks = entityTickingChunks; ++ this.mainThreadTasks = mainThreadTasks; ++ } ++ ++ public void tick() { ++ int iterator = this.entityTickingChunks.createRawIterator(); ++ ++ if (iterator == -1) { ++ return; ++ } ++ ++ // start with updating players ++ try { ++ this.taskIndex.set(iterator); ++ this.finishedTasks.set(0); ++ ++ for (int i = 0; i < parallelism; i++) { ++ trackerExecutor.execute(this::runUpdatePlayers); ++ } ++ ++ while (this.taskIndex.get() < this.entityTickingChunks.getListSize()) { ++ this.runMainThreadTasks(); ++ this.handleChunkUpdates(5); // assist ++ } ++ ++ while (this.finishedTasks.get() != parallelism) { ++ this.runMainThreadTasks(); ++ } ++ ++ this.runMainThreadTasks(); // finish any remaining tasks ++ } finally { ++ this.entityTickingChunks.finishRawIterator(); ++ } ++ ++ // then send changes ++ iterator = this.entityTickingChunks.createRawIterator(); ++ ++ if (iterator == -1) { ++ return; ++ } ++ ++ try { ++ do { ++ LevelChunk chunk = this.entityTickingChunks.rawGet(iterator); ++ ++ if (chunk != null) { ++ this.updateChunkEntities(chunk, TrackerStage.SEND_CHANGES); ++ } ++ } while (++iterator < this.entityTickingChunks.getListSize()); ++ } finally { ++ this.entityTickingChunks.finishRawIterator(); ++ } ++ } ++ ++ private void runMainThreadTasks() { ++ try { ++ Runnable task; ++ while ((task = this.mainThreadTasks.poll()) != null) { ++ task.run(); ++ } ++ } catch (Throwable throwable) { ++ MinecraftServer.LOGGER.warn("Tasks failed while ticking track queue", throwable); ++ } ++ } ++ ++ private void runUpdatePlayers() { ++ try { ++ while (handleChunkUpdates(10)); ++ } finally { ++ this.finishedTasks.incrementAndGet(); ++ } ++ } ++ ++ private boolean handleChunkUpdates(int tasks) { ++ int index; ++ while ((index = this.taskIndex.getAndAdd(tasks)) < this.entityTickingChunks.getListSize()) { ++ for (int i = index; i < index + tasks && i < this.entityTickingChunks.getListSize(); i++) { ++ LevelChunk chunk = this.entityTickingChunks.rawGet(i); ++ if (chunk != null) { ++ try { ++ this.updateChunkEntities(chunk, TrackerStage.UPDATE_PLAYERS); ++ } catch (Throwable throwable) { ++ MinecraftServer.LOGGER.warn("Ticking tracker failed", throwable); ++ } ++ ++ } ++ } ++ ++ return true; ++ } ++ ++ return false; ++ } ++ ++ private void updateChunkEntities(LevelChunk chunk, TrackerStage trackerStage) { ++ final ChunkEntitySlices entitySlices = chunk.level.getEntityLookup().getChunk(chunk.locX, chunk.locZ); ++ if (entitySlices == null) { ++ return; ++ } ++ ++ final Entity[] rawEntities = entitySlices.entities.getRawData(); ++ final ChunkMap chunkMap = chunk.level.chunkSource.chunkMap; ++ ++ for (int i = 0; i < rawEntities.length; i++) { ++ Entity entity = rawEntities[i]; ++ if (entity != null) { ++ ChunkMap.TrackedEntity entityTracker = chunkMap.entityMap.get(entity.getId()); ++ if (entityTracker != null) { ++ if (trackerStage == TrackerStage.SEND_CHANGES) { ++ entityTracker.serverEntity.sendChanges(); ++ } else if (trackerStage == TrackerStage.UPDATE_PLAYERS) { ++ entityTracker.updatePlayers(entityTracker.entity.getPlayersInTrackRange()); ++ } ++ } ++ } ++ } ++ } ++ ++} +diff --git a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java +index 0fd814f1d65c111266a2b20f86561839a4cef755..169ac3ad1b1e8e3e1874ada2471e478233c6ada7 100644 +--- a/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java ++++ b/src/main/java/io/papermc/paper/util/maplist/IteratorSafeOrderedReferenceSet.java +@@ -15,7 +15,7 @@ public final class IteratorSafeOrderedReferenceSet { + + /* list impl */ + protected E[] listElements; +- protected int listSize; ++ protected int listSize; public int getListSize() { return this.listSize; } // petal - expose listSize + + protected final double maxFragFactor; + +diff --git a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java +index f597d65d56964297eeeed6c7e77703764178fee0..665c377e2d0d342f4dcc89c4cbdfcc9e4b96e95c 100644 +--- a/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java ++++ b/src/main/java/io/papermc/paper/world/ChunkEntitySlices.java +@@ -35,7 +35,7 @@ public final class ChunkEntitySlices { + protected final EntityCollectionBySection allEntities; + protected final EntityCollectionBySection hardCollidingEntities; + protected final Reference2ObjectOpenHashMap, EntityCollectionBySection> entitiesByClass; +- protected final EntityList entities = new EntityList(); ++ public final EntityList entities = new EntityList(); + + public ChunkHolder.FullChunkStatus status; + +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index 3203b953709ca7cb9172f5912a922131ad7ec9eb..3c99de7bc5b3c5159ad76f63d67877756f152385 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1237,8 +1237,37 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + entity.tracker = null; // Paper - We're no longer tracked + } + ++ // petal start - multithreaded tracker ++ private @Nullable host.bloom.tracker.MultithreadedTracker multithreadedTracker; ++ private final java.util.concurrent.ConcurrentLinkedQueue trackerMainThreadTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); ++ private boolean tracking = false; ++ ++ public void runOnTrackerMainThread(final Runnable runnable) { ++ if (this.tracking) { ++ this.trackerMainThreadTasks.add(runnable); ++ } else { ++ runnable.run(); ++ } ++ } ++ + // Paper start - optimised tracker + private final void processTrackQueue() { ++ if (true) { ++ if (this.multithreadedTracker == null) { ++ this.multithreadedTracker = new host.bloom.tracker.MultithreadedTracker(this.level.chunkSource.entityTickingChunks, this.trackerMainThreadTasks); ++ } ++ ++ this.tracking = true; ++ try { ++ this.multithreadedTracker.tick(); ++ } finally { ++ this.tracking = false; ++ } ++ return; ++ } ++ // petal end ++ ++ this.level.timings.tracker1.startTiming(); + //this.level.timings.tracker1.startTiming(); // Purpur + try { + for (TrackedEntity tracker : this.entityMap.values()) { +@@ -1462,11 +1491,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + public class TrackedEntity { + +- final ServerEntity serverEntity; +- final Entity entity; ++ public final ServerEntity serverEntity; // petal -> public ++ public final Entity entity; // petal -> public + private final int range; + SectionPos lastSectionPos; +- public final Set seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl ++ public final Set seenBy = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Paper - optimise map impl // petal - sync + + public TrackedEntity(Entity entity, int i, int j, boolean flag) { + this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit +@@ -1478,7 +1507,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + // Paper start - use distance map to optimise tracker + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet lastTrackerCandidates; + +- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { ++ public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { // petal -> public + com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet oldTrackerCandidates = this.lastTrackerCandidates; + this.lastTrackerCandidates = newTrackerCandidates; + +@@ -1550,7 +1579,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public void removePlayer(ServerPlayer player) { +- org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot ++ //org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot // petal - we can remove async too + if (this.seenBy.remove(player.connection)) { + this.serverEntity.removePairing(player); + } +@@ -1558,7 +1587,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + + public void updatePlayer(ServerPlayer player) { +- org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot ++ //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot // petal - we can update async + if (player != this.entity) { + // Paper start - remove allocation of Vec3D here + // Vec3 vec3d = player.position().subtract(this.entity.position()); +diff --git a/src/main/java/net/minecraft/server/level/ServerBossEvent.java b/src/main/java/net/minecraft/server/level/ServerBossEvent.java +index ca42c2642a729b90d22b968af7258f3aee72e14b..40261b80d947a6be43465013fae5532197cfe721 100644 +--- a/src/main/java/net/minecraft/server/level/ServerBossEvent.java ++++ b/src/main/java/net/minecraft/server/level/ServerBossEvent.java +@@ -13,7 +13,7 @@ import net.minecraft.util.Mth; + import net.minecraft.world.BossEvent; + + public class ServerBossEvent extends BossEvent { +- private final Set players = Sets.newHashSet(); ++ private final Set players = Sets.newConcurrentHashSet(); // petal - players can be removed in async tracking + private final Set unmodifiablePlayers = Collections.unmodifiableSet(this.players); + public boolean visible = true; + +diff --git a/src/main/java/net/minecraft/server/level/ServerEntity.java b/src/main/java/net/minecraft/server/level/ServerEntity.java +index 3441339e1ba5efb0e25c16fa13cb65d2fbdafc42..555336cf6700566e8a99e0f0cd6f0cc41b6c5ba0 100644 +--- a/src/main/java/net/minecraft/server/level/ServerEntity.java ++++ b/src/main/java/net/minecraft/server/level/ServerEntity.java +@@ -249,14 +249,18 @@ public class ServerEntity { + + public void removePairing(ServerPlayer player) { + this.entity.stopSeenByPlayer(player); +- player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()})); ++ // petal start - ensure main thread ++ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> ++ player.connection.send(new ClientboundRemoveEntitiesPacket(new int[]{this.entity.getId()})) ++ ); ++ // petal end + } + + public void addPairing(ServerPlayer player) { + ServerGamePacketListenerImpl playerconnection = player.connection; + + Objects.requireNonNull(player.connection); +- this.sendPairingData(playerconnection::send, player); // CraftBukkit - add player ++ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> this.sendPairingData(playerconnection::send, player)); // CraftBukkit - add player // petal - main thread + this.entity.startSeenByPlayer(player); + } + +@@ -362,19 +366,30 @@ public class ServerEntity { + SynchedEntityData datawatcher = this.entity.getEntityData(); + + if (datawatcher.isDirty()) { +- this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false)); ++ // Petal start - sync ++ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> ++ this.broadcastAndSend(new ClientboundSetEntityDataPacket(this.entity.getId(), datawatcher, false)) ++ ); ++ // Petal end + } + + if (this.entity instanceof LivingEntity) { + Set set = ((LivingEntity) this.entity).getAttributes().getDirtyAttributes(); + + if (!set.isEmpty()) { ++ // Petal start - sync ++ final var copy = Lists.newArrayList(set); ++ ((ServerLevel) this.entity.level).chunkSource.chunkMap.runOnTrackerMainThread(() -> { ++ + // CraftBukkit start - Send scaled max health + if (this.entity instanceof ServerPlayer) { +- ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(set, false); ++ ((ServerPlayer) this.entity).getBukkitEntity().injectScaledMaxHealth(copy, false); + } + // CraftBukkit end +- this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), set)); ++ this.broadcastAndSend(new ClientboundUpdateAttributesPacket(this.entity.getId(), copy)); ++ ++ }); ++ // Petal end + } + + set.clear(); diff --git a/patches/removed/0006-Reduce-work-done-by-game-event-system.patch b/patches/removed/0006-Reduce-work-done-by-game-event-system.patch new file mode 100644 index 0000000..b84df95 --- /dev/null +++ b/patches/removed/0006-Reduce-work-done-by-game-event-system.patch @@ -0,0 +1,204 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: peaches94 +Date: Sun, 10 Jul 2022 13:29:20 -0500 +Subject: [PATCH] Reduce work done by game event system + +Original code by Bloom-host, licensed under GNU General Public License v3.0 +You can find the original code on https://github.com/Bloom-host/Petal + +1. going into game event dispatching can be expensive so run the checks before dispatching + +2. euclideangameeventdispatcher is not used concurrently so we ban that usage for improved performance with allays + +diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java +index 571a1cbee376032b6b9f36c9fe3f9199a3ad3197..92e7ba78e18efb8263475ecc076bc49e88b85e84 100644 +--- a/src/main/java/net/minecraft/server/level/ServerLevel.java ++++ b/src/main/java/net/minecraft/server/level/ServerLevel.java +@@ -1703,6 +1703,7 @@ public class ServerLevel extends Level implements WorldGenLevel { + if (chunk != null) { + for (int j2 = k; j2 <= j1; ++j2) { + flag |= chunk.getEventDispatcher(j2).walkListeners(event, emitterPos, emitter, (gameeventlistener, vec3d1) -> { ++ if (!gameeventlistener.listensToEvent(event, emitter)) return; // petal - if they don't listen, ignore + (gameeventlistener.handleEventsImmediately() ? list : this.gameEventMessages).add(new GameEvent.Message(event, emitterPos, emitter, gameeventlistener, vec3d1)); + }); + } +diff --git a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +index 22c309343299e60ed8028229b7f134109001ff35..d5947d29295ddc93ba8ac1c0fc61f7badad582c4 100644 +--- a/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java ++++ b/src/main/java/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +@@ -85,6 +85,13 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi + } + } + ++ // petal start ++ @Override ++ public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { ++ return !this.isRemoved() && gameEvent == GameEvent.ENTITY_DIE && context.sourceEntity() instanceof LivingEntity; ++ } ++ // petal end ++ + public static void serverTick(Level world, BlockPos pos, BlockState state, SculkCatalystBlockEntity blockEntity) { + org.bukkit.craftbukkit.event.CraftEventFactory.sourceBlockOverride = blockEntity.getBlockPos(); // CraftBukkit - SPIGOT-7068: Add source block override, not the most elegant way but better than passing down a BlockPosition up to five methods deep. + blockEntity.sculkSpreader.updateCursors(world, pos, world.getRandom(), true); +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 620173eef4c2f30a97a4c2f8049ea01fcc60d0b2..bdf67c916fe435f3bd04a61cce6db93c606515ce 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +@@ -84,7 +84,18 @@ public class LevelChunk extends ChunkAccess { + private Supplier fullStatus; + @Nullable + private LevelChunk.PostLoadProcessor postLoad; +- private final Int2ObjectMap gameEventDispatcherSections; ++ // petal start ++ private final GameEventDispatcher[] gameEventDispatcherSections; ++ private static final int GAME_EVENT_DISPATCHER_RADIUS = 2; ++ ++ private static int getGameEventSectionIndex(int sectionIndex) { ++ return sectionIndex + GAME_EVENT_DISPATCHER_RADIUS; ++ } ++ ++ private static int getGameEventSectionLength(int sectionCount) { ++ return sectionCount + (GAME_EVENT_DISPATCHER_RADIUS * 2); ++ } ++ // petal end + private final LevelChunkTicks blockTicks; + private final LevelChunkTicks fluidTicks; + +@@ -113,7 +124,7 @@ public class LevelChunk extends ChunkAccess { + this.tickersInLevel = Maps.newHashMap(); + this.clientLightReady = false; + this.level = (ServerLevel) world; // CraftBukkit - type +- this.gameEventDispatcherSections = new Int2ObjectOpenHashMap(); ++ this.gameEventDispatcherSections = new GameEventDispatcher[getGameEventSectionLength(this.getSectionsCount())]; // petal + Heightmap.Types[] aheightmap_type = Heightmap.Types.values(); + int j = aheightmap_type.length; + +@@ -446,9 +457,23 @@ public class LevelChunk extends ChunkAccess { + if (world instanceof ServerLevel) { + ServerLevel worldserver = (ServerLevel) world; + +- return (GameEventDispatcher) this.gameEventDispatcherSections.computeIfAbsent(ySectionCoord, (j) -> { +- return new EuclideanGameEventDispatcher(worldserver); +- }); ++ // petal start ++ int sectionIndex = getGameEventSectionIndex(this.getSectionIndexFromSectionY(ySectionCoord)); ++ ++ // drop game events that are too far away (32 blocks) from loaded sections ++ // this matches the highest radius of game events in the game ++ if (sectionIndex < 0 || sectionIndex >= this.gameEventDispatcherSections.length) { ++ return GameEventDispatcher.NOOP; ++ } ++ ++ var dispatcher = this.gameEventDispatcherSections[sectionIndex]; ++ ++ if (dispatcher == null) { ++ dispatcher = this.gameEventDispatcherSections[sectionIndex] = new EuclideanGameEventDispatcher(worldserver); ++ } ++ ++ return dispatcher; ++ // petal end + } else { + return super.getEventDispatcher(ySectionCoord); + } +@@ -812,7 +837,7 @@ public class LevelChunk extends ChunkAccess { + + gameeventdispatcher.unregister(gameeventlistener); + if (gameeventdispatcher.isEmpty()) { +- this.gameEventDispatcherSections.remove(i); ++ this.gameEventDispatcherSections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(i))] = null; // petal + } + } + } +diff --git a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java +index 0dd708ebe81f73710de51215529c05ec61837dd3..f5b402efa86f824c460db8cac20c1c2b090f82d0 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventDispatcher.java +@@ -13,8 +13,8 @@ import net.minecraft.world.phys.Vec3; + + public class EuclideanGameEventDispatcher implements GameEventDispatcher { + private final List listeners = Lists.newArrayList(); +- private final Set listenersToRemove = Sets.newHashSet(); +- private final List listenersToAdd = Lists.newArrayList(); ++ //private final Set listenersToRemove = Sets.newHashSet(); // petal - not necessary ++ //private final List listenersToAdd = Lists.newArrayList(); // petal + private boolean processing; + private final ServerLevel level; + +@@ -30,7 +30,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { + @Override + public void register(GameEventListener listener) { + if (this.processing) { +- this.listenersToAdd.add(listener); ++ throw new java.util.ConcurrentModificationException(); // petal - disallow concurrent modification + } else { + this.listeners.add(listener); + } +@@ -41,7 +41,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { + @Override + public void unregister(GameEventListener listener) { + if (this.processing) { +- this.listenersToRemove.add(listener); ++ throw new java.util.ConcurrentModificationException(); // petal - disallow concurrent modification + } else { + this.listeners.remove(listener); + } +@@ -58,7 +58,7 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { + + while(iterator.hasNext()) { + GameEventListener gameEventListener = iterator.next(); +- if (this.listenersToRemove.remove(gameEventListener)) { ++ if (false) { // petal - disallow concurrent modification + iterator.remove(); + } else { + Optional optional = getPostableListenerPosition(this.level, pos, gameEventListener); +@@ -72,6 +72,8 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { + this.processing = false; + } + ++ // petal start ++ /* + if (!this.listenersToAdd.isEmpty()) { + this.listeners.addAll(this.listenersToAdd); + this.listenersToAdd.clear(); +@@ -81,6 +83,8 @@ public class EuclideanGameEventDispatcher implements GameEventDispatcher { + this.listeners.removeAll(this.listenersToRemove); + this.listenersToRemove.clear(); + } ++ */ ++ // petal end + + return bl; + } +diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java b/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java +index e5601afe8b739da518f36ae306f5e0cb252238f0..bc8f04424c5e8c416d6988f0e06d8cadbb400ca7 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java +@@ -12,4 +12,10 @@ public interface GameEventListener { + int getListenerRadius(); + + boolean handleGameEvent(ServerLevel world, GameEvent.Message event); ++ ++ // petal start - add check for seeing if this listener cares about an event ++ default boolean listensToEvent(net.minecraft.world.level.gameevent.GameEvent gameEvent, net.minecraft.world.level.gameevent.GameEvent.Context context) { ++ return true; ++ } ++ // petal end + } +diff --git a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java +index e45f54534bbf054eaf0008546ff459d4c11ddd50..e49d0d1c2a539fcd7e75262c4010475193964287 100644 +--- a/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java ++++ b/src/main/java/net/minecraft/world/level/gameevent/vibrations/VibrationListener.java +@@ -162,6 +162,13 @@ public class VibrationListener implements GameEventListener { + return true; + } + ++ // petal start ++ @Override ++ public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { ++ return this.receivingEvent == null && gameEvent.is(this.config.getListenableEvents()); ++ } ++ // petal end ++ + public interface VibrationListenerConfig { + + default TagKey getListenableEvents() { diff --git a/patches/removed/0008-Reduce-sensor-work.patch b/patches/removed/0008-Reduce-sensor-work.patch new file mode 100644 index 0000000..5c17f04 --- /dev/null +++ b/patches/removed/0008-Reduce-sensor-work.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: peaches94 +Date: Sun, 10 Jul 2022 15:44:38 -0500 +Subject: [PATCH] Reduce sensor work + +Original code by Bloom-host, licensed under GNU General Public License v3.0 +You can find the original code on https://github.com/Bloom-host/Petal + +this patch is focused around the sensors used for ai +delete the line of sight cache less often and use a faster nearby comparison + +diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java +index ba673b7e5ae1084caa6b23763c9a83aac60269bb..9d824c56914292810091b358ff7d718add617f21 100644 +--- a/src/main/java/net/minecraft/world/entity/LivingEntity.java ++++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java +@@ -1012,20 +1012,22 @@ public abstract class LivingEntity extends Entity { + } + + if (entity != null) { +- ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); ++ // petal start - only do itemstack lookup if we need to ++ //ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); + EntityType entitytypes = entity.getType(); + + // Purpur start +- if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL)) { ++ if (entitytypes == EntityType.SKELETON && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.SKELETON_SKULL)) { + d0 *= entity.level.purpurConfig.skeletonHeadVisibilityPercent; + } +- else if (entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD)) { ++ else if (entitytypes == EntityType.ZOMBIE && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.ZOMBIE_HEAD)) { + d0 *= entity.level.purpurConfig.zombieHeadVisibilityPercent; + } +- else if (entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) { ++ else if (entitytypes == EntityType.CREEPER && this.getItemBySlot(EquipmentSlot.HEAD).is(Items.CREEPER_HEAD)) { + d0 *= entity.level.purpurConfig.creeperHeadVisibilityPercent; + } + // Purpur end ++ // petal end + + // Purpur start + if (entity instanceof LivingEntity entityliving) { +diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java +index d5e3bd662da349fc2ee58c7800d79c60300f33b3..0981873ee37fc839035b8398bac03d15adecb301 100644 +--- a/src/main/java/net/minecraft/world/entity/Mob.java ++++ b/src/main/java/net/minecraft/world/entity/Mob.java +@@ -884,10 +884,10 @@ public abstract class Mob extends LivingEntity { + return; + } + // Paper end ++ int i = this.level.getServer().getTickCount() + this.getId(); // petal - move up + //this.level.getProfiler().push("sensing"); // Purpur +- this.sensing.tick(); ++ if (i % 10 == 0) this.sensing.tick(); // petal - only refresh line of sight cache every half second + //this.level.getProfiler().pop(); // Purpur +- int i = this.level.getServer().getTickCount() + this.getId(); + + if (i % 2 != 0 && this.tickCount > 1) { + //this.level.getProfiler().push("targetSelector"); // Purpur diff --git a/patches/server/0004-JettPack-patches.patch b/patches/server/0003-JettPack-patches.patch similarity index 100% rename from patches/server/0004-JettPack-patches.patch rename to patches/server/0003-JettPack-patches.patch diff --git a/patches/server/0005-Lithium-optimizations.patch b/patches/server/0004-Lithium-optimizations.patch similarity index 99% rename from patches/server/0005-Lithium-optimizations.patch rename to patches/server/0004-Lithium-optimizations.patch index a8bfb5f..92992fd 100644 --- a/patches/server/0005-Lithium-optimizations.patch +++ b/patches/server/0004-Lithium-optimizations.patch @@ -1083,7 +1083,7 @@ index 6c27b22dd1d497687c0f4d3835e34149bcf952c1..445f21c3764d148de937f558e3f087ae public static Direction getNearest(double x, double y, double z) { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 92e7ba78e18efb8263475ecc076bc49e88b85e84..2a9219e0139670674319a7cf17ad664582b42715 100644 +index 571a1cbee376032b6b9f36c9fe3f9199a3ad3197..df014d5b1b2d3b1d0e7a0b9eedb3c19ee693b836 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -227,6 +227,13 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -1468,7 +1468,7 @@ index bef8f4d080fb6067f87b9df986ac33f7003c2a84..a727875f6db8d9950d1d9ada67dd3948 public InteractionResult interact(Player player, InteractionHand hand) { return InteractionResult.PASS; diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9fe6d0700f8f4d4cc018bcb4f33fffaa5f51a1d9..9d824c56914292810091b358ff7d718add617f21 100644 +index 1fc877194950ee754e9ffdbe3ff9b80bb316560f..ba673b7e5ae1084caa6b23763c9a83aac60269bb 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -577,11 +577,11 @@ public abstract class LivingEntity extends Entity { @@ -1494,7 +1494,7 @@ index 9fe6d0700f8f4d4cc018bcb4f33fffaa5f51a1d9..9d824c56914292810091b358ff7d718a } -@@ -2552,6 +2552,8 @@ public abstract class LivingEntity extends Entity { +@@ -2550,6 +2550,8 @@ public abstract class LivingEntity extends Entity { } protected void updateSwingTime() { @@ -1503,7 +1503,7 @@ index 9fe6d0700f8f4d4cc018bcb4f33fffaa5f51a1d9..9d824c56914292810091b358ff7d718a int i = this.getCurrentSwingDuration(); if (this.swinging) { -@@ -3531,6 +3533,8 @@ public abstract class LivingEntity extends Entity { +@@ -3529,6 +3531,8 @@ public abstract class LivingEntity extends Entity { } private void updateFallFlying() { diff --git a/patches/server/0006-CarpetFixes-optimizations.patch b/patches/server/0005-CarpetFixes-optimizations.patch similarity index 98% rename from patches/server/0006-CarpetFixes-optimizations.patch rename to patches/server/0005-CarpetFixes-optimizations.patch index 21aa5b1..50f2610 100644 --- a/patches/server/0006-CarpetFixes-optimizations.patch +++ b/patches/server/0005-CarpetFixes-optimizations.patch @@ -196,10 +196,10 @@ index ec587cf6592a1dc0d90d6f54af1bdfab97aec7c6..0afd56a8b27fce044f7d43b1e4f86b61 public static double lengthSquared(double a, double b, double c) { diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d63315818f54 100644 +index ba673b7e5ae1084caa6b23763c9a83aac60269bb..b163ad5fb6fea59982e26fdbd4dd5b5dcb4350a5 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java -@@ -1532,7 +1532,7 @@ public abstract class LivingEntity extends Entity { +@@ -1530,7 +1530,7 @@ public abstract class LivingEntity extends Entity { if (this instanceof ServerPlayer) { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, source, f1, amount, flag); if (f2 > 0.0F && f2 < 3.4028235E37F) { @@ -208,7 +208,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } } -@@ -2100,9 +2100,9 @@ public abstract class LivingEntity extends Entity { +@@ -2098,9 +2098,9 @@ public abstract class LivingEntity extends Entity { if (f3 > 0.0F && f3 < 3.4028235E37F) { if (this instanceof ServerPlayer) { @@ -220,7 +220,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } } } -@@ -2214,9 +2214,9 @@ public abstract class LivingEntity extends Entity { +@@ -2212,9 +2212,9 @@ public abstract class LivingEntity extends Entity { float f3 = (float) -event.getDamage(DamageModifier.RESISTANCE); if (f3 > 0.0F && f3 < 3.4028235E37F) { if (this instanceof ServerPlayer) { @@ -232,7 +232,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } } } -@@ -2248,10 +2248,10 @@ public abstract class LivingEntity extends Entity { +@@ -2246,10 +2246,10 @@ public abstract class LivingEntity extends Entity { float f2 = absorptionModifier; if (f2 > 0.0F && f2 < 3.4028235E37F && this instanceof net.minecraft.world.entity.player.Player) { @@ -245,7 +245,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } // Purpur start -@@ -2273,7 +2273,7 @@ public abstract class LivingEntity extends Entity { +@@ -2271,7 +2271,7 @@ public abstract class LivingEntity extends Entity { // PAIL: Be sure to drag all this code from the EntityHuman subclass each update. ((net.minecraft.world.entity.player.Player) this).causeFoodExhaustion(damagesource.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent if (f < 3.4028235E37F) { @@ -254,7 +254,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } } // CraftBukkit end -@@ -2295,7 +2295,7 @@ public abstract class LivingEntity extends Entity { +@@ -2293,7 +2293,7 @@ public abstract class LivingEntity extends Entity { CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f, originalDamage, true); f2 = (float) -event.getDamage(DamageModifier.BLOCKING); if (f2 > 0.0F && f2 < 3.4028235E37F) { @@ -263,7 +263,7 @@ index 9d824c56914292810091b358ff7d718add617f21..4f3cce05807715b978792ffa28f2d633 } } -@@ -3100,13 +3100,13 @@ public abstract class LivingEntity extends Entity { +@@ -3098,13 +3098,13 @@ public abstract class LivingEntity extends Entity { //this.level.getProfiler().push("rangeChecks"); // Purpur // Paper start - stop large pitch and yaw changes from crashing the server diff --git a/patches/server/0007-C2ME-optimizations.patch b/patches/server/0006-C2ME-optimizations.patch similarity index 100% rename from patches/server/0007-C2ME-optimizations.patch rename to patches/server/0006-C2ME-optimizations.patch diff --git a/patches/server/0008-Use-our-logo-instead-of-Purpur-s.patch b/patches/server/0007-Use-our-logo-instead-of-Purpur-s.patch similarity index 100% rename from patches/server/0008-Use-our-logo-instead-of-Purpur-s.patch rename to patches/server/0007-Use-our-logo-instead-of-Purpur-s.patch diff --git a/patches/server/0009-Smarter-statistics-ticking.patch b/patches/server/0008-Smarter-statistics-ticking.patch similarity index 100% rename from patches/server/0009-Smarter-statistics-ticking.patch rename to patches/server/0008-Smarter-statistics-ticking.patch diff --git a/patches/server/0010-Smooth-Teleports.patch b/patches/server/0009-Smooth-Teleports.patch similarity index 100% rename from patches/server/0010-Smooth-Teleports.patch rename to patches/server/0009-Smooth-Teleports.patch diff --git a/patches/server/0011-Fast-speed-check.patch b/patches/server/0010-Fast-speed-check.patch similarity index 100% rename from patches/server/0011-Fast-speed-check.patch rename to patches/server/0010-Fast-speed-check.patch diff --git a/patches/server/0012-PaperPR-Optimize-VarInts.patch b/patches/server/0011-PaperPR-Optimize-VarInts.patch similarity index 100% rename from patches/server/0012-PaperPR-Optimize-VarInts.patch rename to patches/server/0011-PaperPR-Optimize-VarInts.patch diff --git a/patches/server/0013-Options-of-warnings.patch b/patches/server/0012-Options-of-warnings.patch similarity index 100% rename from patches/server/0013-Options-of-warnings.patch rename to patches/server/0012-Options-of-warnings.patch diff --git a/patches/server/0014-Add-an-option-for-tripwire-duping.patch b/patches/server/0013-Add-an-option-for-tripwire-duping.patch similarity index 100% rename from patches/server/0014-Add-an-option-for-tripwire-duping.patch rename to patches/server/0013-Add-an-option-for-tripwire-duping.patch diff --git a/patches/server/0015-Add-an-option-for-spigot-item-merging-mechanism.patch b/patches/server/0014-Add-an-option-for-spigot-item-merging-mechanism.patch similarity index 100% rename from patches/server/0015-Add-an-option-for-spigot-item-merging-mechanism.patch rename to patches/server/0014-Add-an-option-for-spigot-item-merging-mechanism.patch diff --git a/patches/server/0016-Global-Eula-file.patch b/patches/server/0015-Global-Eula-file.patch similarity index 100% rename from patches/server/0016-Global-Eula-file.patch rename to patches/server/0015-Global-Eula-file.patch diff --git a/patches/server/0017-Do-not-save-firework-entities-or-the-server-may-be-l.patch b/patches/server/0016-Do-not-save-firework-entities-or-the-server-may-be-l.patch similarity index 100% rename from patches/server/0017-Do-not-save-firework-entities-or-the-server-may-be-l.patch rename to patches/server/0016-Do-not-save-firework-entities-or-the-server-may-be-l.patch diff --git a/patches/server/0018-Disable-arrow-despawn-counter-by-default.patch b/patches/server/0017-Disable-arrow-despawn-counter-by-default.patch similarity index 100% rename from patches/server/0018-Disable-arrow-despawn-counter-by-default.patch rename to patches/server/0017-Disable-arrow-despawn-counter-by-default.patch diff --git a/patches/server/0019-Use-a-faster-random-implementation.patch b/patches/server/0018-Use-a-faster-random-implementation.patch similarity index 99% rename from patches/server/0019-Use-a-faster-random-implementation.patch rename to patches/server/0018-Use-a-faster-random-implementation.patch index 5bc098b..d400c34 100644 --- a/patches/server/0019-Use-a-faster-random-implementation.patch +++ b/patches/server/0018-Use-a-faster-random-implementation.patch @@ -445,7 +445,7 @@ index a5d3aa309d3fdaab9e0fea2dfb91a080a3ac1193..384733b2b0bc7c5108ebdc725c0d1354 private void fillPositionsWithIterateOutwards(LongList entry, int xRange, int yRange, int zRange) { 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 bdf67c916fe435f3bd04a61cce6db93c606515ce..f01dd420e2ff4f87b00682681a4f7dbf05955d24 100644 +index 620173eef4c2f30a97a4c2f8049ea01fcc60d0b2..1ef5f03a332e832817be132bbbf3ac1021f085d1 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -53,6 +53,10 @@ import net.minecraft.world.level.material.Fluids; @@ -459,7 +459,7 @@ index bdf67c916fe435f3bd04a61cce6db93c606515ce..f01dd420e2ff4f87b00682681a4f7dbf public class LevelChunk extends ChunkAccess { -@@ -957,7 +961,7 @@ public class LevelChunk extends ChunkAccess { +@@ -932,7 +936,7 @@ public class LevelChunk extends ChunkAccess { if (this.needsDecoration) { //try (co.aikar.timings.Timing ignored = this.level.timings.chunkLoadPopulate.startTiming()) { // Paper // Purpur this.needsDecoration = false; diff --git a/patches/server/0020-Don-t-create-new-random-instance.patch b/patches/server/0019-Don-t-create-new-random-instance.patch similarity index 100% rename from patches/server/0020-Don-t-create-new-random-instance.patch rename to patches/server/0019-Don-t-create-new-random-instance.patch diff --git a/patches/server/0021-Skip-entity-move-if-no-movement.patch b/patches/server/0020-Skip-entity-move-if-no-movement.patch similarity index 100% rename from patches/server/0021-Skip-entity-move-if-no-movement.patch rename to patches/server/0020-Skip-entity-move-if-no-movement.patch diff --git a/patches/server/0022-LazyDFU-optimization.patch b/patches/server/0021-LazyDFU-optimization.patch similarity index 100% rename from patches/server/0022-LazyDFU-optimization.patch rename to patches/server/0021-LazyDFU-optimization.patch diff --git a/patches/server/0023-Revert-purpur-spark-profiler.patch b/patches/server/0022-Revert-purpur-spark-profiler.patch similarity index 100% rename from patches/server/0023-Revert-purpur-spark-profiler.patch rename to patches/server/0022-Revert-purpur-spark-profiler.patch diff --git a/patches/server/0025-Optimized-getBiome-method.patch b/patches/server/0023-Optimized-getBiome-method.patch similarity index 100% rename from patches/server/0025-Optimized-getBiome-method.patch rename to patches/server/0023-Optimized-getBiome-method.patch diff --git a/patches/server/0026-Use-optimized-RecipeManager.patch b/patches/server/0024-Use-optimized-RecipeManager.patch similarity index 100% rename from patches/server/0026-Use-optimized-RecipeManager.patch rename to patches/server/0024-Use-optimized-RecipeManager.patch diff --git a/patches/server/0024-Revert-purpur-Remove-Timings.patch b/patches/server/0025-Revert-purpur-Remove-Timings.patch similarity index 90% rename from patches/server/0024-Revert-purpur-Remove-Timings.patch rename to patches/server/0025-Revert-purpur-Remove-Timings.patch index 246e0dc..7221d82 100644 --- a/patches/server/0024-Revert-purpur-Remove-Timings.patch +++ b/patches/server/0025-Revert-purpur-Remove-Timings.patch @@ -1,6 +1,6 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: nostalgic853 -Date: Mon, 24 Oct 2022 23:28:07 +0800 +Date: Tue, 25 Oct 2022 01:29:25 +0800 Subject: [PATCH] Revert purpur "Remove Timings" This reverts commit 0fb6171d @@ -510,7 +510,7 @@ index 383045ae681d5366761c807a0032156203cdf9c9..443aa5012152cb7969147dbbeba259e1 @Override diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index 3c99de7bc5b3c5159ad76f63d67877756f152385..a2a4965aec45f3ff83703b636e46f5c545cfb48e 100644 +index 3203b953709ca7cb9172f5912a922131ad7ec9eb..a2a4965aec45f3ff83703b636e46f5c545cfb48e 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -606,20 +606,20 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider @@ -542,42 +542,12 @@ index 3c99de7bc5b3c5159ad76f63d67877756f152385..a2a4965aec45f3ff83703b636e46f5c5 } public boolean hasWork() { -@@ -1237,55 +1237,26 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - entity.tracker = null; // Paper - We're no longer tracked - } +@@ -1239,24 +1239,24 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider -- // petal start - multithreaded tracker -- private @Nullable host.bloom.tracker.MultithreadedTracker multithreadedTracker; -- private final java.util.concurrent.ConcurrentLinkedQueue trackerMainThreadTasks = new java.util.concurrent.ConcurrentLinkedQueue<>(); -- private boolean tracking = false; -- -- public void runOnTrackerMainThread(final Runnable runnable) { -- if (this.tracking) { -- this.trackerMainThreadTasks.add(runnable); -- } else { -- runnable.run(); -- } -- } -- // Paper start - optimised tracker private final void processTrackQueue() { -- if (true) { -- if (this.multithreadedTracker == null) { -- this.multithreadedTracker = new host.bloom.tracker.MultithreadedTracker(this.level.chunkSource.entityTickingChunks, this.trackerMainThreadTasks); -- } -- -- this.tracking = true; -- try { -- this.multithreadedTracker.tick(); -- } finally { -- this.tracking = false; -- } -- return; -- } -- // petal end -- - this.level.timings.tracker1.startTiming(); - //this.level.timings.tracker1.startTiming(); // Purpur ++ this.level.timings.tracker1.startTiming(); try { for (TrackedEntity tracker : this.entityMap.values()) { // update tracker entry @@ -601,7 +571,7 @@ index 3c99de7bc5b3c5159ad76f63d67877756f152385..a2a4965aec45f3ff83703b636e46f5c5 } } // Paper end - optimised tracker -@@ -1300,7 +1271,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1271,7 +1271,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider List list = Lists.newArrayList(); List list1 = this.level.players(); ObjectIterator objectiterator = this.entityMap.values().iterator(); @@ -610,7 +580,7 @@ index 3c99de7bc5b3c5159ad76f63d67877756f152385..a2a4965aec45f3ff83703b636e46f5c5 ChunkMap.TrackedEntity playerchunkmap_entitytracker; -@@ -1325,17 +1296,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider +@@ -1296,17 +1296,17 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider playerchunkmap_entitytracker.serverEntity.sendChanges(); } } @@ -631,48 +601,6 @@ index 3c99de7bc5b3c5159ad76f63d67877756f152385..a2a4965aec45f3ff83703b636e46f5c5 } } -@@ -1491,11 +1462,11 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - - public class TrackedEntity { - -- public final ServerEntity serverEntity; // petal -> public -- public final Entity entity; // petal -> public -+ final ServerEntity serverEntity; -+ final Entity entity; - private final int range; - SectionPos lastSectionPos; -- public final Set seenBy = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Paper - optimise map impl // petal - sync -+ public final Set seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl - - public TrackedEntity(Entity entity, int i, int j, boolean flag) { - this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, j, flag, this::broadcast, this.seenBy); // CraftBukkit -@@ -1507,7 +1478,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - // Paper start - use distance map to optimise tracker - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet lastTrackerCandidates; - -- public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { // petal -> public -+ final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet newTrackerCandidates) { - com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet oldTrackerCandidates = this.lastTrackerCandidates; - this.lastTrackerCandidates = newTrackerCandidates; - -@@ -1579,7 +1550,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void removePlayer(ServerPlayer player) { -- //org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot // petal - we can remove async too -+ org.spigotmc.AsyncCatcher.catchOp("player tracker clear"); // Spigot - if (this.seenBy.remove(player.connection)) { - this.serverEntity.removePairing(player); - } -@@ -1587,7 +1558,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider - } - - public void updatePlayer(ServerPlayer player) { -- //org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot // petal - we can update async -+ org.spigotmc.AsyncCatcher.catchOp("player tracker update"); // Spigot - if (player != this.entity) { - // Paper start - remove allocation of Vec3D here - // Vec3 vec3d = player.position().subtract(this.entity.position()); diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index cd5533c3c53215c9cc4be0b9097d76efbf5bd0c1..7266e6703d5cd0fea90ec88c74a7d4567f2420ae 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -869,7 +797,7 @@ index cd5533c3c53215c9cc4be0b9097d76efbf5bd0c1..7266e6703d5cd0fea90ec88c74a7d456 } diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java -index 2a9219e0139670674319a7cf17ad664582b42715..55fe8b0f21f00b02e78257a64fd8d63980d50995 100644 +index df014d5b1b2d3b1d0e7a0b9eedb3c19ee693b836..55fe8b0f21f00b02e78257a64fd8d63980d50995 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java +++ b/src/main/java/net/minecraft/server/level/ServerLevel.java @@ -227,13 +227,6 @@ public class ServerLevel extends Level implements WorldGenLevel { @@ -1191,14 +1119,6 @@ index 2a9219e0139670674319a7cf17ad664582b42715..55fe8b0f21f00b02e78257a64fd8d639 // Paper - rewrite chunk system - entity saving moved into ChunkHolder } else if (close) { chunkproviderserver.close(false); } // Paper - rewrite chunk system -@@ -1710,7 +1703,6 @@ public class ServerLevel extends Level implements WorldGenLevel { - if (chunk != null) { - for (int j2 = k; j2 <= j1; ++j2) { - flag |= chunk.getEventDispatcher(j2).walkListeners(event, emitterPos, emitter, (gameeventlistener, vec3d1) -> { -- if (!gameeventlistener.listensToEvent(event, emitter)) return; // petal - if they don't listen, ignore - (gameeventlistener.handleEventsImmediately() ? list : this.gameEventMessages).add(new GameEvent.Message(event, emitterPos, emitter, gameeventlistener, vec3d1)); - }); - } diff --git a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java b/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java index 66c632f9a824e705420b9bb86de294f0e7305c50..4c5d7f00b68e4ec103a5841beaccfbdbef30f130 100644 --- a/src/main/java/net/minecraft/server/network/ServerGamePacketListenerImpl.java @@ -1429,7 +1349,7 @@ index bca69d595ef0f18a5910cbd6f7e6f742830a0800..386ed2c102aaa3ec68e828e20fff6bfe if (entityhuman != null) { double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); 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 f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e2ab7eef7 100644 +index 1ef5f03a332e832817be132bbbf3ac1021f085d1..636c98d04eb4e14eab1fa208d9cb097e2ab7eef7 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -53,10 +53,6 @@ import net.minecraft.world.level.material.Fluids; @@ -1443,72 +1363,7 @@ index f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e public class LevelChunk extends ChunkAccess { -@@ -88,18 +84,7 @@ public class LevelChunk extends ChunkAccess { - private Supplier fullStatus; - @Nullable - private LevelChunk.PostLoadProcessor postLoad; -- // petal start -- private final GameEventDispatcher[] gameEventDispatcherSections; -- private static final int GAME_EVENT_DISPATCHER_RADIUS = 2; -- -- private static int getGameEventSectionIndex(int sectionIndex) { -- return sectionIndex + GAME_EVENT_DISPATCHER_RADIUS; -- } -- -- private static int getGameEventSectionLength(int sectionCount) { -- return sectionCount + (GAME_EVENT_DISPATCHER_RADIUS * 2); -- } -- // petal end -+ private final Int2ObjectMap gameEventDispatcherSections; - private final LevelChunkTicks blockTicks; - private final LevelChunkTicks fluidTicks; - -@@ -128,7 +113,7 @@ public class LevelChunk extends ChunkAccess { - this.tickersInLevel = Maps.newHashMap(); - this.clientLightReady = false; - this.level = (ServerLevel) world; // CraftBukkit - type -- this.gameEventDispatcherSections = new GameEventDispatcher[getGameEventSectionLength(this.getSectionsCount())]; // petal -+ this.gameEventDispatcherSections = new Int2ObjectOpenHashMap(); - Heightmap.Types[] aheightmap_type = Heightmap.Types.values(); - int j = aheightmap_type.length; - -@@ -461,23 +446,9 @@ public class LevelChunk extends ChunkAccess { - if (world instanceof ServerLevel) { - ServerLevel worldserver = (ServerLevel) world; - -- // petal start -- int sectionIndex = getGameEventSectionIndex(this.getSectionIndexFromSectionY(ySectionCoord)); -- -- // drop game events that are too far away (32 blocks) from loaded sections -- // this matches the highest radius of game events in the game -- if (sectionIndex < 0 || sectionIndex >= this.gameEventDispatcherSections.length) { -- return GameEventDispatcher.NOOP; -- } -- -- var dispatcher = this.gameEventDispatcherSections[sectionIndex]; -- -- if (dispatcher == null) { -- dispatcher = this.gameEventDispatcherSections[sectionIndex] = new EuclideanGameEventDispatcher(worldserver); -- } -- -- return dispatcher; -- // petal end -+ return (GameEventDispatcher) this.gameEventDispatcherSections.computeIfAbsent(ySectionCoord, (j) -> { -+ return new EuclideanGameEventDispatcher(worldserver); -+ }); - } else { - return super.getEventDispatcher(ySectionCoord); - } -@@ -841,7 +812,7 @@ public class LevelChunk extends ChunkAccess { - - gameeventdispatcher.unregister(gameeventlistener); - if (gameeventdispatcher.isEmpty()) { -- this.gameEventDispatcherSections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(i))] = null; // petal -+ this.gameEventDispatcherSections.remove(i); - } - } - } -@@ -959,9 +930,9 @@ public class LevelChunk extends ChunkAccess { +@@ -934,9 +930,9 @@ public class LevelChunk extends ChunkAccess { this.chunkHolder.getEntityChunk().callEntitiesLoadEvent(); // Paper - rewrite chunk system if (this.needsDecoration) { @@ -1520,7 +1375,7 @@ index f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e random.setSeed(this.level.getSeed()); long xRand = random.nextLong() / 2L * 2L + 1L; long zRand = random.nextLong() / 2L * 2L + 1L; -@@ -979,7 +950,7 @@ public class LevelChunk extends ChunkAccess { +@@ -954,7 +950,7 @@ public class LevelChunk extends ChunkAccess { } } server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkPopulateEvent(this.bukkitChunk)); @@ -1529,7 +1384,7 @@ index f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e } } } -@@ -1321,10 +1292,10 @@ public class LevelChunk extends ChunkAccess { +@@ -1296,10 +1292,10 @@ public class LevelChunk extends ChunkAccess { if (LevelChunk.this.isTicking(blockposition)) { try { @@ -1543,7 +1398,7 @@ index f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e BlockState iblockdata = LevelChunk.this.getBlockState(blockposition); if (this.blockEntity.getType().isValid(iblockdata)) { -@@ -1335,7 +1306,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1310,7 +1306,7 @@ public class LevelChunk extends ChunkAccess { LevelChunk.LOGGER.warn("Block entity {} @ {} state {} invalid for ticking:", new Object[]{LogUtils.defer(this::getType), LogUtils.defer(this::getPos), iblockdata}); } @@ -1552,7 +1407,7 @@ index f01dd420e2ff4f87b00682681a4f7dbf05955d24..636c98d04eb4e14eab1fa208d9cb097e } catch (Throwable throwable) { if (throwable instanceof ThreadDeath) throw throwable; // Paper // Paper start - Prevent tile entity and entity crashes -@@ -1346,7 +1317,7 @@ public class LevelChunk extends ChunkAccess { +@@ -1321,7 +1317,7 @@ public class LevelChunk extends ChunkAccess { // Paper end // Spigot start } finally {