From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: peaches94 Date: Sun, 10 Jul 2022 13:29:20 -0500 Subject: [PATCH] Petal: reduce work done by game event system Original license: GPL v3 Original project: https://github.com/Bloom-host/Petal 1. going into game event dispatching can be expensive so run the checks before dispatching 2. EuclideanGameEventListenerRegistry is not used concurrently so we ban that usage for improved performance with allays 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 83481539e058e5f428d9951e409fed62ef159e5c..bf9a7c31d557e4521e20851c3569f42a8d224c97 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 @@ -65,7 +65,7 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi return this.catalystListener; } - public static class CatalystListener implements GameEventListener { + public class CatalystListener implements GameEventListener { // petal public static final int PULSE_TICKS = 8; final SculkSpreader sculkSpreader; @@ -135,6 +135,13 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi world.playSound((Player) null, pos, SoundEvents.SCULK_CATALYST_BLOOM, SoundSource.BLOCKS, 2.0F, 0.6F + random.nextFloat() * 0.4F); } + // petal start + @Override + public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { + return !SculkCatalystBlockEntity.this.isRemoved() && gameEvent == GameEvent.ENTITY_DIE && context.sourceEntity() instanceof LivingEntity; + } + // petal end + private void tryAwardItSpreadsAdvancement(Level world, LivingEntity deadEntity) { LivingEntity entityliving1 = deadEntity.getLastHurtByMob(); 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 221a4a3fbeac621ec593c7ba44b83f4b247a5589..33dc213ab5968cbf46a5a670517c0612653e148e 100644 --- a/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java +++ b/src/main/java/net/minecraft/world/level/chunk/LevelChunk.java @@ -80,7 +80,18 @@ public class LevelChunk extends ChunkAccess { private Supplier fullStatus; @Nullable private LevelChunk.PostLoadProcessor postLoad; - private final Int2ObjectMap gameEventListenerRegistrySections; + // petal start + private final GameEventListenerRegistry[] gameEventListenerRegistrySections; + 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; public volatile FullChunkStatus chunkStatus = FullChunkStatus.INACCESSIBLE; // Paper - rewrite chunk system @@ -105,7 +116,7 @@ public class LevelChunk extends ChunkAccess { super(pos, upgradeData, world, net.minecraft.server.MinecraftServer.getServer().registryAccess().registryOrThrow(Registries.BIOME), inhabitedTime, sectionArrayInitializer, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry this.tickersInLevel = Maps.newHashMap(); this.level = (ServerLevel) world; // CraftBukkit - type - this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap(); + this.gameEventListenerRegistrySections = new GameEventListenerRegistry[getGameEventSectionLength(this.getSectionsCount())]; // petal Heightmap.Types[] aheightmap_type = Heightmap.Types.values(); int j = aheightmap_type.length; @@ -303,9 +314,23 @@ public class LevelChunk extends ChunkAccess { if (world instanceof ServerLevel) { ServerLevel worldserver = (ServerLevel) world; - return (GameEventListenerRegistry) this.gameEventListenerRegistrySections.computeIfAbsent(ySectionCoord, (j) -> { - return new EuclideanGameEventListenerRegistry(worldserver, ySectionCoord, this::removeGameEventListenerRegistry); - }); + // 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.gameEventListenerRegistrySections.length) { + return GameEventListenerRegistry.NOOP; + } + + var dispatcher = this.gameEventListenerRegistrySections[sectionIndex]; + + if (dispatcher == null) { + dispatcher = this.gameEventListenerRegistrySections[sectionIndex] = new EuclideanGameEventListenerRegistry(worldserver, ySectionCoord, this::removeGameEventListenerRegistry); + } + + return dispatcher; + // petal end } else { return super.getListenerRegistry(ySectionCoord); } @@ -678,7 +703,7 @@ public class LevelChunk extends ChunkAccess { } private void removeGameEventListenerRegistry(int ySectionCoord) { - this.gameEventListenerRegistrySections.remove(ySectionCoord); + this.gameEventListenerRegistrySections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(ySectionCoord))] = null; // petal } private void removeBlockEntityTicker(BlockPos pos) { diff --git a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java index f30b2e964acdf44014065bd491a577040e61a2c2..14c4de819ce5bd6440f96ea3e9e7df32d15a7f1e 100644 --- a/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java +++ b/src/main/java/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java @@ -13,8 +13,8 @@ import net.minecraft.world.phys.Vec3; public class EuclideanGameEventListenerRegistry implements GameEventListenerRegistry { 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; private final int sectionY; @@ -34,7 +34,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi @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); } @@ -45,7 +45,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi @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); } @@ -66,7 +66,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi 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); @@ -80,6 +80,8 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi this.processing = false; } + // petal start + /* if (!this.listenersToAdd.isEmpty()) { this.listeners.addAll(this.listenersToAdd); this.listenersToAdd.clear(); @@ -89,6 +91,8 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi this.listeners.removeAll(this.listenersToRemove); this.listenersToRemove.clear(); } + */ + // petal end return bl; } diff --git a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java index 37ae0f928440af5b2fdfe68ad6c9c54e8c95c82c..7a63c186101c739344b59de874e31658938641a7 100644 --- a/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java +++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventDispatcher.java @@ -44,6 +44,7 @@ public class GameEventDispatcher { int k1 = SectionPos.blockToSectionCoord(blockposition.getZ() + i); List list = new ArrayList(); GameEventListenerRegistry.ListenerVisitor gameeventlistenerregistry_a = (gameeventlistener, vec3d1) -> { + if (!gameeventlistener.listensToEvent(event, emitter)) return; // petal - if they don't listen, ignore if (gameeventlistener.getDeliveryMode() == GameEventListener.DeliveryMode.BY_DISTANCE) { list.add(new GameEvent.ListenerInfo(event, emitterPos, emitter, gameeventlistener, vec3d1)); } else { 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 a4148dd326b10b0eb2bc7884691d79dcda60e010..5859d7af9052a150f5d115bb0e2cbd102374f162 100644 --- a/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java +++ b/src/main/java/net/minecraft/world/level/gameevent/GameEventListener.java @@ -22,4 +22,10 @@ public interface GameEventListener { public interface Holder { T getListener(); } + + // petal start - add check for seeing if this listener cares about an event + default boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { + return true; + } + // petal end }