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/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java b/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java index 2627583ab12d886b1fba0b1d1e599f942926b499..440d70811d96f97d3463c6aff131cbc5bd588254 100644 --- a/net/minecraft/world/level/block/entity/SculkCatalystBlockEntity.java +++ b/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 { // Leaf - petal - reduce work done by game event system public static final int PULSE_TICKS = 8; final SculkSpreader sculkSpreader; private final BlockState blockState; @@ -127,6 +127,13 @@ public class SculkCatalystBlockEntity extends BlockEntity implements GameEventLi level.playSound(null, pos, SoundEvents.SCULK_CATALYST_BLOOM, SoundSource.BLOCKS, 2.0F, 0.6F + random.nextFloat() * 0.4F); } + // Leaf start - petal - reduce work done by game event system + @Override + public boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { + return !SculkCatalystBlockEntity.this.isRemoved() && gameEvent == GameEvent.ENTITY_DIE.value() && context.sourceEntity() instanceof LivingEntity; + } + // Leaf end - petal - reduce work done by game event system + private void tryAwardItSpreadsAdvancement(Level level, LivingEntity entity) { if (entity.getLastHurtByMob() instanceof ServerPlayer serverPlayer) { DamageSource damageSource = entity.getLastDamageSource() == null diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java index a8db2a822deb07ddc707cf73fdc5c269d9842c06..800fc055024c176d1830e1d2686f5d96131c8712 100644 --- a/net/minecraft/world/level/chunk/LevelChunk.java +++ b/net/minecraft/world/level/chunk/LevelChunk.java @@ -80,7 +80,19 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p private Supplier fullStatus; @Nullable private LevelChunk.PostLoadProcessor postLoad; - private final Int2ObjectMap gameEventListenerRegistrySections; + // Leaf start - petal - reduce work done by game event system + 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); + } + + // Leaf end - petal - reduce work done by game event system private final LevelChunkTicks blockTicks; private final LevelChunkTicks fluidTicks; private LevelChunk.UnsavedListener unsavedListener = chunkPos -> {}; @@ -155,7 +167,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p ) { super(pos, data, level, net.minecraft.server.MinecraftServer.getServer().registryAccess().lookupOrThrow(Registries.BIOME), inhabitedTime, sections, blendingData); // Paper - Anti-Xray - The world isn't ready yet, use server singleton for registry this.level = (ServerLevel) level; // CraftBukkit - type - this.gameEventListenerRegistrySections = new Int2ObjectOpenHashMap<>(); + this.gameEventListenerRegistrySections = new GameEventListenerRegistry[getGameEventSectionLength(this.getSectionsCount())]; // Leaf - petal - reduce work done by game event system for (Heightmap.Types types : Heightmap.Types.values()) { if (ChunkStatus.FULL.heightmapsAfter().contains(types)) { @@ -267,10 +279,27 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p @Override public GameEventListenerRegistry getListenerRegistry(int sectionY) { - return this.level instanceof ServerLevel serverLevel - ? this.gameEventListenerRegistrySections - .computeIfAbsent(sectionY, i -> new EuclideanGameEventListenerRegistry(serverLevel, sectionY, this::removeGameEventListenerRegistry)) - : super.getListenerRegistry(sectionY); + // Leaf start - petal - reduce work done by game event system + if (this.level instanceof ServerLevel serverLevel) { + int sectionIndex = getGameEventSectionIndex(this.getSectionIndexFromSectionY(sectionY)); + + // 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(serverLevel, sectionY, this::removeGameEventListenerRegistry); + } + + return dispatcher; + } + + return super.getListenerRegistry(sectionY); + // Leaf end - petal - reduce work done by game event system } // Paper start - Perf: Reduce instructions and provide final method @@ -617,7 +646,7 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p } private void removeGameEventListenerRegistry(int sectionY) { - this.gameEventListenerRegistrySections.remove(sectionY); + this.gameEventListenerRegistrySections[getGameEventSectionIndex(this.getSectionIndexFromSectionY(sectionY))] = null; // Leaf - petal - reduce work done by game event system } private void removeBlockEntityTicker(BlockPos pos) { diff --git a/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java b/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java index 5175fc90a1fc61c832c6697997a97ae199b195ac..fc56ef2d5ed813db51e35b635e373b6f8035593b 100644 --- a/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java +++ b/net/minecraft/world/level/gameevent/EuclideanGameEventListenerRegistry.java @@ -14,8 +14,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(); // Leaf - petal - reduce work done by game event system - Not necessary + //private final List listenersToAdd = Lists.newArrayList(); // Leaf - petal - reduce work done by game event system private boolean processing; private final ServerLevel level; private final int sectionY; @@ -35,7 +35,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi @Override public void register(GameEventListener listener) { if (this.processing) { - this.listenersToAdd.add(listener); + throw new java.util.ConcurrentModificationException(); // Leaf - petal - reduce work done by game event system - Disallow concurrent modification } else { this.listeners.add(listener); } @@ -46,7 +46,7 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi @Override public void unregister(GameEventListener listener) { if (this.processing) { - this.listenersToRemove.add(listener); + throw new java.util.ConcurrentModificationException(); // Leaf - petal - reduce work done by game event system - 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) { // Leaf - petal - reduce work done by game event system - Disallow concurrent modification iterator.remove(); } else { Optional postableListenerPosition = getPostableListenerPosition(this.level, pos, gameEventListener); @@ -80,6 +80,8 @@ public class EuclideanGameEventListenerRegistry implements GameEventListenerRegi this.processing = false; } + // Leaf start - petal - reduce work done by game event system + /* 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(); } + */ + // Leaf end - petal - reduce work done by game event system return flag; } diff --git a/net/minecraft/world/level/gameevent/GameEventDispatcher.java b/net/minecraft/world/level/gameevent/GameEventDispatcher.java index b06ded98c01cd2a71d52b96070a6b23da1e40f9c..a781038d42166e1dd1bfee0fbd5c2db8ec1d08c0 100644 --- a/net/minecraft/world/level/gameevent/GameEventDispatcher.java +++ b/net/minecraft/world/level/gameevent/GameEventDispatcher.java @@ -38,6 +38,7 @@ public class GameEventDispatcher { int sectionPosCoord5 = SectionPos.blockToSectionCoord(blockPos.getZ() + notificationRadius); List list = new ArrayList<>(); GameEventListenerRegistry.ListenerVisitor listenerVisitor = (listener, pos1) -> { + if (!listener.listensToEvent(gameEvent.value(), context)) return; // Leaf - petal - reduce work done by game event system - If they don't listen, ignore if (listener.getDeliveryMode() == GameEventListener.DeliveryMode.BY_DISTANCE) { list.add(new GameEvent.ListenerInfo(gameEvent, pos, context, listener, pos1)); } else { diff --git a/net/minecraft/world/level/gameevent/GameEventListener.java b/net/minecraft/world/level/gameevent/GameEventListener.java index 5a31b5f1e75dd7b412ab577ea6621b7e87fc0590..4d991ab3290646ec3fd6645154abfa5b4e42d00a 100644 --- a/net/minecraft/world/level/gameevent/GameEventListener.java +++ b/net/minecraft/world/level/gameevent/GameEventListener.java @@ -23,4 +23,11 @@ public interface GameEventListener { public interface Provider { T getListener(); } + + // Leaf start - petal - reduce work done by game event system + // Add check for seeing if this listener cares about an event + default boolean listensToEvent(GameEvent gameEvent, GameEvent.Context context) { + return true; + } + // Leaf end - petal - reduce work done by game event system }