Fix build

This commit is contained in:
nostalgic853
2022-10-25 01:41:45 +08:00
parent 256119c313
commit e645b7774f
27 changed files with 654 additions and 756 deletions

View File

@@ -1,9 +1,9 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: peaches94 <peachescu94@gmail.com>
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<LevelChunk> entityTickingChunks;
+ private final AtomicInteger taskIndex = new AtomicInteger();
+
+ private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
+ private final AtomicInteger finishedTasks = new AtomicInteger();
+
+ public MultithreadedTracker(IteratorSafeOrderedReferenceSet<LevelChunk> entityTickingChunks, ConcurrentLinkedQueue<Runnable> 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<E> {
/* 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<Class<? extends Entity>, 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<Runnable> 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<ServerPlayerConnection> seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl
+ public final Set<ServerPlayerConnection> 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<ServerPlayer> lastTrackerCandidates;
- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
+ public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) { // petal -> public
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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<ServerPlayer> players = Sets.newHashSet();
+ private final Set<ServerPlayer> players = Sets.newConcurrentHashSet(); // petal - players can be removed in async tracking
private final Set<ServerPlayer> 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<AttributeInstance> 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<ChunkHolder.FullChunkStatus> fullStatus;
@Nullable
private LevelChunk.PostLoadProcessor postLoad;
- private final Int2ObjectMap<GameEventDispatcher> 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<Block> blockTicks;
private final LevelChunkTicks<Fluid> 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<GameEventListener> listeners = Lists.newArrayList();
- private final Set<GameEventListener> listenersToRemove = Sets.newHashSet();
- private final List<GameEventListener> listenersToAdd = Lists.newArrayList();
+ //private final Set<GameEventListener> listenersToRemove = Sets.newHashSet(); // petal - not necessary
+ //private final List<GameEventListener> 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<Vec3> 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<GameEvent> 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

View File

@@ -0,0 +1,362 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: peaches94 <peachescu94@gmail.com>
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 <paul@technove.co>
Co-authored-by: Kevin Raneri <kevin.raneri@gmail.com>
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<LevelChunk> entityTickingChunks;
+ private final AtomicInteger taskIndex = new AtomicInteger();
+
+ private final ConcurrentLinkedQueue<Runnable> mainThreadTasks;
+ private final AtomicInteger finishedTasks = new AtomicInteger();
+
+ public MultithreadedTracker(IteratorSafeOrderedReferenceSet<LevelChunk> entityTickingChunks, ConcurrentLinkedQueue<Runnable> 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<E> {
/* 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<Class<? extends Entity>, 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<Runnable> 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<ServerPlayerConnection> seenBy = new ReferenceOpenHashSet<>(); // Paper - optimise map impl
+ public final Set<ServerPlayerConnection> 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<ServerPlayer> lastTrackerCandidates;
- final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
+ public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) { // petal -> public
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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<ServerPlayer> players = Sets.newHashSet();
+ private final Set<ServerPlayer> players = Sets.newConcurrentHashSet(); // petal - players can be removed in async tracking
private final Set<ServerPlayer> 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<AttributeInstance> 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();

View File

@@ -0,0 +1,204 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: peaches94 <peachescu94@gmail.com>
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<ChunkHolder.FullChunkStatus> fullStatus;
@Nullable
private LevelChunk.PostLoadProcessor postLoad;
- private final Int2ObjectMap<GameEventDispatcher> 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<Block> blockTicks;
private final LevelChunkTicks<Fluid> 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<GameEventListener> listeners = Lists.newArrayList();
- private final Set<GameEventListener> listenersToRemove = Sets.newHashSet();
- private final List<GameEventListener> listenersToAdd = Lists.newArrayList();
+ //private final Set<GameEventListener> listenersToRemove = Sets.newHashSet(); // petal - not necessary
+ //private final List<GameEventListener> 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<Vec3> 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<GameEvent> getListenableEvents() {

View File

@@ -0,0 +1,59 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: peaches94 <peachescu94@gmail.com>
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

View File

@@ -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() {

View File

@@ -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

View File

@@ -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;

View File

@@ -1,6 +1,6 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: nostalgic853 <yuu8583@proton.me>
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<Runnable> 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<ServerPlayer> list = Lists.newArrayList();
List<ServerPlayer> 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<ServerPlayerConnection> seenBy = it.unimi.dsi.fastutil.objects.ReferenceSets.synchronize(new ReferenceOpenHashSet<>()); // Paper - optimise map impl // petal - sync
+ public final Set<ServerPlayerConnection> 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<ServerPlayer> lastTrackerCandidates;
- public final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) { // petal -> public
+ final void updatePlayers(com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> newTrackerCandidates) {
com.destroystokyo.paper.util.misc.PooledLinkedHashSets.PooledObjectLinkedOpenHashSet<ServerPlayer> 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<ChunkHolder.FullChunkStatus> 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<GameEventDispatcher> gameEventDispatcherSections;
private final LevelChunkTicks<Block> blockTicks;
private final LevelChunkTicks<Fluid> 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 {