From 0b626d9eaff34fad4490d6dd58791028bc731eb9 Mon Sep 17 00:00:00 2001 From: Ben Woo <30431861+benwoo1110@users.noreply.github.com> Date: Fri, 21 Aug 2026 22:48:27 +0800 Subject: [PATCH] Fix spawn reason check not done for chunk load entity pruning --- .../core/listeners/MVEntityListener.java | 20 ++++++---- .../compatibility/EntityCompatibility.java | 40 +++++++++++++++++++ 2 files changed, 52 insertions(+), 8 deletions(-) create mode 100644 src/main/java/org/mvplugins/multiverse/core/utils/compatibility/EntityCompatibility.java diff --git a/src/main/java/org/mvplugins/multiverse/core/listeners/MVEntityListener.java b/src/main/java/org/mvplugins/multiverse/core/listeners/MVEntityListener.java index 1df4ca702..3497f53a0 100644 --- a/src/main/java/org/mvplugins/multiverse/core/listeners/MVEntityListener.java +++ b/src/main/java/org/mvplugins/multiverse/core/listeners/MVEntityListener.java @@ -22,11 +22,13 @@ import org.bukkit.event.entity.FoodLevelChangeEvent; import org.bukkit.event.world.ChunkLoadEvent; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jvnet.hk2.annotations.Service; import org.mvplugins.multiverse.core.dynamiclistener.EventRunnable; import org.mvplugins.multiverse.core.dynamiclistener.annotations.EventClass; import org.mvplugins.multiverse.core.dynamiclistener.annotations.EventMethod; +import org.mvplugins.multiverse.core.utils.compatibility.EntityCompatibility; import org.mvplugins.multiverse.core.world.WorldManager; import java.util.Arrays; @@ -96,10 +98,7 @@ EventRunnable preCreatureSpawn() { @Override public void onEvent(PreCreatureSpawnEvent event) { // Always allow custom command and plugins to spawn creatures - if (event.getReason() == SpawnReason.CUSTOM - || event.getReason() == SpawnReason.COMMAND - || event.getReason() == SpawnReason.BREEDING - || event.getReason() == SpawnReason.SPAWNER_EGG) { + if (isAlwaysAllowedSpawnReason(event.getReason())) { return; } @@ -127,10 +126,7 @@ void creatureSpawn(CreatureSpawnEvent event) { } // Always allow custom command and plugins to spawn creatures - if (event.getSpawnReason() == SpawnReason.CUSTOM - || event.getSpawnReason() == SpawnReason.COMMAND - || event.getSpawnReason() == SpawnReason.BREEDING - || event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { + if (isAlwaysAllowedSpawnReason(event.getSpawnReason())) { return; } @@ -168,6 +164,7 @@ void chunkLoad(ChunkLoadEvent event) { .peek(world -> { long count = Arrays.stream(event.getChunk().getEntities()) .filter(entity -> !(entity instanceof Player)) + .filter(entity -> !isAlwaysAllowedSpawnReason(EntityCompatibility.getEntitySpawnReason(entity))) .filter(entity -> !world.getEntitySpawnConfig().shouldAllowSpawn(entity)) .peek(Entity::remove) .count(); @@ -177,4 +174,11 @@ void chunkLoad(ChunkLoadEvent event) { } }); } + + private boolean isAlwaysAllowedSpawnReason(@Nullable SpawnReason reason) { + return reason == SpawnReason.CUSTOM + || reason == SpawnReason.COMMAND + || reason == SpawnReason.BREEDING + || reason == SpawnReason.SPAWNER_EGG; + } } diff --git a/src/main/java/org/mvplugins/multiverse/core/utils/compatibility/EntityCompatibility.java b/src/main/java/org/mvplugins/multiverse/core/utils/compatibility/EntityCompatibility.java new file mode 100644 index 000000000..7f12c48b4 --- /dev/null +++ b/src/main/java/org/mvplugins/multiverse/core/utils/compatibility/EntityCompatibility.java @@ -0,0 +1,40 @@ +package org.mvplugins.multiverse.core.utils.compatibility; + +import org.bukkit.entity.Entity; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.mvplugins.multiverse.core.utils.ReflectHelper; + +/** + * Compatibility class used to handle API changes in {@link Entity} class. + */ +// TODO: Consider making this part of the public API in v5.9. +@ApiStatus.Internal +public final class EntityCompatibility { + + private static final boolean HAS_GET_ENTITY_SPAWN_REASON_METHOD; + + static { + HAS_GET_ENTITY_SPAWN_REASON_METHOD = ReflectHelper.hasMethod(Entity.class, "getEntitySpawnReason"); + } + + /** + * Gets the reason that initially spawned the entity when supported by the server. + * + * @param entity The entity to query. + * @return The entity's spawn reason, or null when the API is unavailable. + */ + @Nullable + public static SpawnReason getEntitySpawnReason(@NotNull Entity entity) { + if (HAS_GET_ENTITY_SPAWN_REASON_METHOD) { + return entity.getEntitySpawnReason(); + } + return null; + } + + private EntityCompatibility() { + throw new UnsupportedOperationException("This is a utility class and cannot be instantiated"); + } +}