From 0b11279d3fde709ccafb0bfbbd8ba8c1642c16dc Mon Sep 17 00:00:00 2001 From: Joe Johnson <62161622+jh508@users.noreply.github.com> Date: Sun, 19 Jul 2026 05:21:41 +0100 Subject: [PATCH 1/4] feat: add EntityType#getSpawnCategory() Allows retrieving the spawn category of an entity type without needing to spawn an instance of it first. --- .../main/java/io/papermc/paper/InternalAPIBridge.java | 3 +++ .../src/main/java/org/bukkit/entity/EntityType.java | 11 +++++++++++ .../papermc/paper/PaperServerInternalAPIBridge.java | 7 +++++++ .../test/java/org/bukkit/entity/EntityTypesTest.java | 8 ++++++++ 4 files changed, 29 insertions(+) diff --git a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java index 5a039f815a29..1590367ec2ff 100644 --- a/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java +++ b/paper-api/src/main/java/io/papermc/paper/InternalAPIBridge.java @@ -29,6 +29,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Pose; +import org.bukkit.entity.SpawnCategory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -97,6 +98,8 @@ class Holder { String getTranslationKey(EntityType entityType); + SpawnCategory getSpawnCategory(EntityType entityType); + /* * Called once by the version command on first use, then cached. */ diff --git a/paper-api/src/main/java/org/bukkit/entity/EntityType.java b/paper-api/src/main/java/org/bukkit/entity/EntityType.java index 1583067fe6fa..25f937c9acd7 100644 --- a/paper-api/src/main/java/org/bukkit/entity/EntityType.java +++ b/paper-api/src/main/java/org/bukkit/entity/EntityType.java @@ -343,6 +343,17 @@ public String getTranslationKey() { return InternalAPIBridge.get().getTranslationKey(this); } + /** + * Gets the spawn category of this entity type. + * + * @return the spawn category + * @throws IllegalArgumentException if the entity does not have a spawn category (is probably a custom entity) + */ + public @NotNull SpawnCategory getSpawnCategory() { + Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have a spawn category"); + return InternalAPIBridge.get().getSpawnCategory(this); + } + /** * Checks if the entity has default attributes. * diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java index f4d5123d9488..4aca28fa472f 100644 --- a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -59,6 +59,7 @@ import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.util.CraftSpawnCategory; import org.bukkit.damage.DamageEffect; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; @@ -66,6 +67,7 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Pose; +import org.bukkit.entity.SpawnCategory; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -111,6 +113,11 @@ public CombatEntry createCombatEntry( ); } + @Override + public SpawnCategory getSpawnCategory(EntityType entityType) { + return CraftSpawnCategory.toBukkit(CraftEntityType.bukkitToMinecraft(entityType).getCategory()); + } + private CombatEntry createCombatEntry( final net.minecraft.world.damagesource.DamageSource damageSource, final float damage, diff --git a/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java b/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java index a4e2c42e9a5d..0753b9462129 100644 --- a/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java +++ b/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java @@ -17,4 +17,12 @@ public void testTranslationKey() { } } } + + @Test + void testGetSpawnCategory() { + for (EntityType type : EntityType.values()) { + if (type == EntityType.UNKNOWN) continue; + assertNotNull(type.getSpawnCategory(), "SpawnCategory should not be null for " + type); + } + } } From 7404da1a8a80951ef3147cffd7fbfc99b4710d92 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:09:53 +0200 Subject: [PATCH 2/4] tweaks --- .../src/main/java/org/bukkit/entity/EntityType.java | 10 +++++----- .../bukkit/craftbukkit/util/CraftSpawnCategory.java | 6 ++---- .../test/java/org/bukkit/entity/SpawnCategoryTest.java | 6 +++--- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/paper-api/src/main/java/org/bukkit/entity/EntityType.java b/paper-api/src/main/java/org/bukkit/entity/EntityType.java index 25f937c9acd7..543bd4f08285 100644 --- a/paper-api/src/main/java/org/bukkit/entity/EntityType.java +++ b/paper-api/src/main/java/org/bukkit/entity/EntityType.java @@ -335,7 +335,7 @@ public String getTranslationKey() { // Paper start /** - * @throws IllegalArgumentException if the entity does not have a translation key (is probably a custom entity) + * @throws IllegalArgumentException if the entity does not have a translation key */ @Override public @NotNull String translationKey() { @@ -347,7 +347,7 @@ public String getTranslationKey() { * Gets the spawn category of this entity type. * * @return the spawn category - * @throws IllegalArgumentException if the entity does not have a spawn category (is probably a custom entity) + * @throws IllegalArgumentException if the entity does not have a spawn category */ public @NotNull SpawnCategory getSpawnCategory() { Preconditions.checkArgument(this != UNKNOWN, "UNKNOWN entities do not have a spawn category"); @@ -355,7 +355,7 @@ public String getTranslationKey() { } /** - * Checks if the entity has default attributes. + * Checks if the entity type has default attributes. * * @return true if it has default attributes */ @@ -367,10 +367,10 @@ public boolean hasDefaultAttributes() { } /** - * Gets the default attributes for the entity. + * Gets the default attributes for the entity type. * * @return an unmodifiable instance of Attributable for reading default attributes. - * @throws IllegalArgumentException if the entity does not exist of have default attributes (use {@link #hasDefaultAttributes()} first) + * @throws IllegalArgumentException if it doesn't have default attributes (use {@link #hasDefaultAttributes()} first) */ public @NotNull org.bukkit.attribute.Attributable getDefaultAttributes() { Preconditions.checkArgument(this.hasDefaultAttributes(), this.key + " doesn't have default attributes"); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftSpawnCategory.java b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftSpawnCategory.java index cba660a05069..16a2493cb9be 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftSpawnCategory.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/util/CraftSpawnCategory.java @@ -43,8 +43,8 @@ public static long getDefaultTicksPerSpawn(SpawnCategory spawnCategory) { }; } - public static SpawnCategory toBukkit(MobCategory enumCreatureType) { - return switch (enumCreatureType) { + public static SpawnCategory toBukkit(MobCategory category) { + return switch (category) { case MONSTER -> SpawnCategory.MONSTER; case CREATURE -> SpawnCategory.ANIMAL; case AMBIENT -> SpawnCategory.AMBIENT; @@ -53,7 +53,6 @@ public static SpawnCategory toBukkit(MobCategory enumCreatureType) { case WATER_AMBIENT -> SpawnCategory.WATER_AMBIENT; case UNDERGROUND_WATER_CREATURE -> SpawnCategory.WATER_UNDERGROUND_CREATURE; case MISC -> SpawnCategory.MISC; - default -> throw new UnsupportedOperationException("Unknown EnumCreatureType " + enumCreatureType + " for SpawnCategory"); }; } @@ -67,7 +66,6 @@ public static MobCategory toNMS(SpawnCategory spawnCategory) { case WATER_AMBIENT -> MobCategory.WATER_AMBIENT; case WATER_UNDERGROUND_CREATURE -> MobCategory.UNDERGROUND_WATER_CREATURE; case MISC -> MobCategory.MISC; - default -> throw new UnsupportedOperationException("Unknown SpawnCategory " + spawnCategory + " for EnumCreatureType"); }; } diff --git a/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java b/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java index 62816aadf262..8f9165e7ba90 100644 --- a/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java +++ b/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java @@ -10,9 +10,9 @@ public class SpawnCategoryTest { @Test public void testMatch() { - for (MobCategory enumCreatureType : MobCategory.values()) { + for (MobCategory category : MobCategory.values()) { // If it is missing a convert to Bukkit then throw a UnsupportedOperationException - SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumCreatureType); + SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(category); if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { long defaultTicks = CraftSpawnCategory.getDefaultTicksPerSpawn(spawnCategory); @@ -23,7 +23,7 @@ public void testMatch() { for (SpawnCategory spawnCategory : SpawnCategory.values()) { // If it is missing a convert to NMS then throw a UnsupportedOperationException - MobCategory enumCreatureType = CraftSpawnCategory.toNMS(spawnCategory); + MobCategory category = CraftSpawnCategory.toNMS(spawnCategory); } } } From 01063512d4a6b050704e3e533084ac439abefb21 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:18:56 +0200 Subject: [PATCH 3/4] move and remove useless test --- .../paper/PaperServerInternalAPIBridge.java | 10 +++---- .../org/bukkit/entity/EntityTypesTest.java | 28 ------------------- 2 files changed, 5 insertions(+), 33 deletions(-) delete mode 100644 paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java diff --git a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java index 4aca28fa472f..06c0dbd40996 100644 --- a/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java +++ b/paper-server/src/main/java/io/papermc/paper/PaperServerInternalAPIBridge.java @@ -113,11 +113,6 @@ public CombatEntry createCombatEntry( ); } - @Override - public SpawnCategory getSpawnCategory(EntityType entityType) { - return CraftSpawnCategory.toBukkit(CraftEntityType.bukkitToMinecraft(entityType).getCategory()); - } - private CombatEntry createCombatEntry( final net.minecraft.world.damagesource.DamageSource damageSource, final float damage, @@ -186,6 +181,11 @@ public String getTranslationKey(final EntityType entityType) { return CraftEntityType.bukkitToMinecraft(entityType).getDescriptionId(); } + @Override + public SpawnCategory getSpawnCategory(final EntityType entityType) { + return CraftSpawnCategory.toBukkit(CraftEntityType.bukkitToMinecraft(entityType).getCategory()); + } + @Override public VersionFetcher getVersionFetcher() { return new PaperVersionFetcher(); diff --git a/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java b/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java deleted file mode 100644 index 0753b9462129..000000000000 --- a/paper-server/src/test/java/org/bukkit/entity/EntityTypesTest.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.bukkit.entity; - -import static org.junit.jupiter.api.Assertions.*; - -import org.bukkit.support.environment.AllFeatures; -import org.junit.jupiter.api.Test; - -@AllFeatures -public class EntityTypesTest { - - @Test - public void testTranslationKey() { - for (org.bukkit.entity.EntityType entityType : org.bukkit.entity.EntityType.values()) { - // Currently EntityType#getTranslationKey has a validation for null name then for test skip this and check correct names. - if (entityType.getName() != null) { - assertNotNull(entityType.getTranslationKey(), "Nulllable translation key for " + entityType); - } - } - } - - @Test - void testGetSpawnCategory() { - for (EntityType type : EntityType.values()) { - if (type == EntityType.UNKNOWN) continue; - assertNotNull(type.getSpawnCategory(), "SpawnCategory should not be null for " + type); - } - } -} From 75357980219a6a52ddfd9d72a1ff8a6f40d80382 Mon Sep 17 00:00:00 2001 From: Lulu13022002 <41980282+Lulu13022002@users.noreply.github.com> Date: Wed, 5 Aug 2026 16:28:49 +0200 Subject: [PATCH 4/4] [ci skip] update test --- .../org/bukkit/entity/SpawnCategoryTest.java | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java b/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java index 8f9165e7ba90..1ae831c1d68c 100644 --- a/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java +++ b/paper-server/src/test/java/org/bukkit/entity/SpawnCategoryTest.java @@ -1,6 +1,5 @@ package org.bukkit.entity; -import net.minecraft.world.entity.MobCategory; import org.bukkit.craftbukkit.util.CraftSpawnCategory; import org.bukkit.support.environment.Normal; import org.junit.jupiter.api.Test; @@ -10,20 +9,12 @@ public class SpawnCategoryTest { @Test public void testMatch() { - for (MobCategory category : MobCategory.values()) { - // If it is missing a convert to Bukkit then throw a UnsupportedOperationException - SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(category); - - if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { - long defaultTicks = CraftSpawnCategory.getDefaultTicksPerSpawn(spawnCategory); - String nameConfigSpawnLimit = CraftSpawnCategory.getConfigNameSpawnLimit(spawnCategory); - String nameConfigTicksPerSpawn = CraftSpawnCategory.getConfigNameTicksPerSpawn(spawnCategory); + for (SpawnCategory category : SpawnCategory.values()) { + if (CraftSpawnCategory.isValidForLimits(category)) { + long defaultTicks = CraftSpawnCategory.getDefaultTicksPerSpawn(category); + String nameConfigSpawnLimit = CraftSpawnCategory.getConfigNameSpawnLimit(category); + String nameConfigTicksPerSpawn = CraftSpawnCategory.getConfigNameTicksPerSpawn(category); } } - - for (SpawnCategory spawnCategory : SpawnCategory.values()) { - // If it is missing a convert to NMS then throw a UnsupportedOperationException - MobCategory category = CraftSpawnCategory.toNMS(spawnCategory); - } } }