From 60d16d7cac3e8dc5aa4b31b233f3ac3db7a29ffc Mon Sep 17 00:00:00 2001 From: DerFrZocker Date: Sun, 10 Dec 2023 10:46:06 +1100 Subject: [PATCH] #1306: Centralize Bukkit and Minecraft entity conversion --- .../craftbukkit/CraftRegionAccessor.java | 601 ++---------------- .../craftbukkit/entity/CraftEntity.java | 385 +---------- .../craftbukkit/entity/CraftEntityTypes.java | 514 +++++++++++++++ .../craftbukkit/entity/EntityTypesTest.java | 183 ++++++ 4 files changed, 754 insertions(+), 929 deletions(-) create mode 100644 src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java create mode 100644 src/test/java/org/bukkit/craftbukkit/entity/EntityTypesTest.java diff --git a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java index 6349d8c72..b5c33a171 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java @@ -3,222 +3,63 @@ package org.bukkit.craftbukkit; import com.google.common.base.Preconditions; import java.util.ArrayList; import java.util.Collection; -import java.util.Iterator; import java.util.List; import java.util.Random; import java.util.function.Consumer; import java.util.function.Predicate; import net.minecraft.core.BlockPosition; -import net.minecraft.core.EnumDirection; import net.minecraft.core.Holder; import net.minecraft.core.registries.Registries; import net.minecraft.data.worldgen.features.TreeFeatures; import net.minecraft.resources.ResourceKey; import net.minecraft.util.RandomSource; -import net.minecraft.world.entity.EntityAreaEffectCloud; -import net.minecraft.world.entity.EntityExperienceOrb; import net.minecraft.world.entity.EntityInsentient; -import net.minecraft.world.entity.EntityTypes; import net.minecraft.world.entity.EnumMobSpawn; import net.minecraft.world.entity.GroupDataEntity; -import net.minecraft.world.entity.decoration.EntityArmorStand; -import net.minecraft.world.entity.decoration.EntityHanging; -import net.minecraft.world.entity.decoration.EntityItemFrame; -import net.minecraft.world.entity.decoration.EntityLeash; -import net.minecraft.world.entity.decoration.EntityPainting; -import net.minecraft.world.entity.item.EntityFallingBlock; -import net.minecraft.world.entity.item.EntityTNTPrimed; -import net.minecraft.world.entity.monster.EntityZombie; -import net.minecraft.world.entity.monster.breeze.Breeze; -import net.minecraft.world.entity.projectile.EntityEgg; -import net.minecraft.world.entity.projectile.EntityEnderSignal; -import net.minecraft.world.entity.projectile.EntityEvokerFangs; -import net.minecraft.world.entity.projectile.EntityFireball; -import net.minecraft.world.entity.projectile.EntityFireworks; import net.minecraft.world.entity.projectile.EntityPotion; -import net.minecraft.world.entity.projectile.EntitySnowball; -import net.minecraft.world.entity.projectile.EntityTippedArrow; -import net.minecraft.world.entity.vehicle.EntityMinecartChest; -import net.minecraft.world.entity.vehicle.EntityMinecartCommandBlock; -import net.minecraft.world.entity.vehicle.EntityMinecartFurnace; -import net.minecraft.world.entity.vehicle.EntityMinecartHopper; -import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner; -import net.minecraft.world.entity.vehicle.EntityMinecartRideable; -import net.minecraft.world.entity.vehicle.EntityMinecartTNT; import net.minecraft.world.level.GeneratorAccessSeed; import net.minecraft.world.level.biome.BiomeBase; import net.minecraft.world.level.block.BlockChorusFlower; -import net.minecraft.world.level.block.BlockDiodeAbstract; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.IBlockData; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.feature.WorldGenFeatureConfigured; -import net.minecraft.world.phys.AxisAlignedBB; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.RegionAccessor; import org.bukkit.TreeType; import org.bukkit.block.Biome; -import org.bukkit.block.BlockFace; import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.block.CraftBiome; import org.bukkit.craftbukkit.block.CraftBlock; import org.bukkit.craftbukkit.block.data.CraftBlockData; import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftEntityTypes; import org.bukkit.craftbukkit.inventory.CraftItemStack; -import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.craftbukkit.util.BlockStateListPopulator; import org.bukkit.craftbukkit.util.CraftLocation; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.RandomSourceWrapper; import org.bukkit.entity.AbstractArrow; import org.bukkit.entity.AbstractHorse; -import org.bukkit.entity.AbstractSkeleton; -import org.bukkit.entity.AbstractVillager; -import org.bukkit.entity.Allay; -import org.bukkit.entity.Ambient; -import org.bukkit.entity.AreaEffectCloud; -import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Arrow; -import org.bukkit.entity.Axolotl; -import org.bukkit.entity.Bat; -import org.bukkit.entity.Bee; -import org.bukkit.entity.Blaze; -import org.bukkit.entity.BlockDisplay; -import org.bukkit.entity.Boat; -import org.bukkit.entity.Camel; -import org.bukkit.entity.Cat; -import org.bukkit.entity.CaveSpider; -import org.bukkit.entity.ChestBoat; -import org.bukkit.entity.ChestedHorse; -import org.bukkit.entity.Chicken; -import org.bukkit.entity.Cod; -import org.bukkit.entity.ComplexLivingEntity; -import org.bukkit.entity.Cow; -import org.bukkit.entity.Creeper; -import org.bukkit.entity.Display; -import org.bukkit.entity.Dolphin; -import org.bukkit.entity.Donkey; -import org.bukkit.entity.DragonFireball; -import org.bukkit.entity.Drowned; -import org.bukkit.entity.Egg; -import org.bukkit.entity.ElderGuardian; -import org.bukkit.entity.EnderCrystal; -import org.bukkit.entity.EnderDragon; -import org.bukkit.entity.EnderPearl; -import org.bukkit.entity.EnderSignal; -import org.bukkit.entity.Enderman; -import org.bukkit.entity.Endermite; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.entity.Evoker; -import org.bukkit.entity.EvokerFangs; -import org.bukkit.entity.ExperienceOrb; -import org.bukkit.entity.FallingBlock; import org.bukkit.entity.Fireball; -import org.bukkit.entity.Firework; -import org.bukkit.entity.Fish; -import org.bukkit.entity.Fox; -import org.bukkit.entity.Frog; -import org.bukkit.entity.Ghast; -import org.bukkit.entity.Giant; -import org.bukkit.entity.GlowItemFrame; -import org.bukkit.entity.GlowSquid; -import org.bukkit.entity.Goat; -import org.bukkit.entity.Golem; -import org.bukkit.entity.Guardian; -import org.bukkit.entity.Hanging; -import org.bukkit.entity.Hoglin; -import org.bukkit.entity.Husk; -import org.bukkit.entity.Illager; -import org.bukkit.entity.Illusioner; -import org.bukkit.entity.Interaction; -import org.bukkit.entity.IronGolem; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.ItemFrame; -import org.bukkit.entity.LeashHitch; -import org.bukkit.entity.LightningStrike; +import org.bukkit.entity.Horse; +import org.bukkit.entity.LargeFireball; import org.bukkit.entity.LingeringPotion; import org.bukkit.entity.LivingEntity; -import org.bukkit.entity.Llama; -import org.bukkit.entity.LlamaSpit; -import org.bukkit.entity.MagmaCube; -import org.bukkit.entity.Marker; import org.bukkit.entity.Minecart; -import org.bukkit.entity.Mule; -import org.bukkit.entity.MushroomCow; -import org.bukkit.entity.Ocelot; -import org.bukkit.entity.Painting; -import org.bukkit.entity.Panda; -import org.bukkit.entity.Parrot; -import org.bukkit.entity.Phantom; -import org.bukkit.entity.Pig; -import org.bukkit.entity.PigZombie; -import org.bukkit.entity.Piglin; -import org.bukkit.entity.PiglinBrute; -import org.bukkit.entity.Pillager; -import org.bukkit.entity.Player; -import org.bukkit.entity.PolarBear; -import org.bukkit.entity.Projectile; -import org.bukkit.entity.PufferFish; -import org.bukkit.entity.Rabbit; -import org.bukkit.entity.Ravager; -import org.bukkit.entity.Salmon; -import org.bukkit.entity.Sheep; -import org.bukkit.entity.Shulker; -import org.bukkit.entity.ShulkerBullet; -import org.bukkit.entity.Silverfish; -import org.bukkit.entity.Skeleton; -import org.bukkit.entity.SkeletonHorse; -import org.bukkit.entity.Slime; -import org.bukkit.entity.SmallFireball; -import org.bukkit.entity.Sniffer; -import org.bukkit.entity.Snowball; -import org.bukkit.entity.Snowman; -import org.bukkit.entity.SpectralArrow; -import org.bukkit.entity.Spellcaster; -import org.bukkit.entity.Spider; -import org.bukkit.entity.Squid; -import org.bukkit.entity.Stray; -import org.bukkit.entity.Strider; -import org.bukkit.entity.TNTPrimed; -import org.bukkit.entity.Tadpole; -import org.bukkit.entity.Tameable; -import org.bukkit.entity.TextDisplay; -import org.bukkit.entity.ThrownExpBottle; +import org.bukkit.entity.SizedFireball; +import org.bukkit.entity.SplashPotion; import org.bukkit.entity.ThrownPotion; import org.bukkit.entity.TippedArrow; -import org.bukkit.entity.TraderLlama; -import org.bukkit.entity.Trident; -import org.bukkit.entity.TropicalFish; -import org.bukkit.entity.Turtle; -import org.bukkit.entity.Vex; -import org.bukkit.entity.Villager; -import org.bukkit.entity.Vindicator; -import org.bukkit.entity.WanderingTrader; -import org.bukkit.entity.Warden; -import org.bukkit.entity.WindCharge; -import org.bukkit.entity.Witch; -import org.bukkit.entity.Wither; -import org.bukkit.entity.WitherSkeleton; -import org.bukkit.entity.WitherSkull; -import org.bukkit.entity.Wolf; -import org.bukkit.entity.Zoglin; -import org.bukkit.entity.Zombie; -import org.bukkit.entity.ZombieHorse; -import org.bukkit.entity.ZombieVillager; -import org.bukkit.entity.minecart.CommandMinecart; -import org.bukkit.entity.minecart.ExplosiveMinecart; -import org.bukkit.entity.minecart.HopperMinecart; -import org.bukkit.entity.minecart.PoweredMinecart; -import org.bukkit.entity.minecart.SpawnerMinecart; -import org.bukkit.entity.minecart.StorageMinecart; +import org.bukkit.entity.minecart.RideableMinecart; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionType; -import org.bukkit.util.Vector; public abstract class CraftRegionAccessor implements RegionAccessor { @@ -620,406 +461,42 @@ public abstract class CraftRegionAccessor implements RegionAccessor { Preconditions.checkArgument(location != null, "Location cannot be null"); Preconditions.checkArgument(clazz != null, "Entity class cannot be null"); - net.minecraft.world.entity.Entity entity = null; - net.minecraft.world.level.World world = getHandle().getMinecraftWorld(); - - double x = location.getX(); - double y = location.getY(); - double z = location.getZ(); - float pitch = location.getPitch(); - float yaw = location.getYaw(); - - // order is important for some of these - if (Boat.class.isAssignableFrom(clazz)) { - if (ChestBoat.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CHEST_BOAT.create(world); - } else { - entity = EntityTypes.BOAT.create(world); - } - entity.moveTo(x, y, z, yaw, pitch); - } else if (FallingBlock.class.isAssignableFrom(clazz)) { - BlockPosition pos = BlockPosition.containing(x, y, z); - entity = EntityFallingBlock.fall(world, pos, getHandle().getBlockState(pos)); - } else if (Projectile.class.isAssignableFrom(clazz)) { - if (Snowball.class.isAssignableFrom(clazz)) { - entity = new EntitySnowball(world, x, y, z); - } else if (Egg.class.isAssignableFrom(clazz)) { - entity = new EntityEgg(world, x, y, z); - } else if (AbstractArrow.class.isAssignableFrom(clazz)) { - if (TippedArrow.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ARROW.create(world); - ((Arrow) entity.getBukkitEntity()).setBasePotionData(new PotionData(PotionType.WATER, false, false)); - } else if (SpectralArrow.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SPECTRAL_ARROW.create(world); - } else if (Trident.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TRIDENT.create(world); - } else { - entity = EntityTypes.ARROW.create(world); - } - entity.moveTo(x, y, z, 0, 0); - } else if (ThrownExpBottle.class.isAssignableFrom(clazz)) { - entity = EntityTypes.EXPERIENCE_BOTTLE.create(world); - entity.moveTo(x, y, z, 0, 0); - } else if (EnderPearl.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ENDER_PEARL.create(world); - entity.moveTo(x, y, z, 0, 0); - } else if (ThrownPotion.class.isAssignableFrom(clazz)) { - if (LingeringPotion.class.isAssignableFrom(clazz)) { - entity = new EntityPotion(world, x, y, z); - ((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1))); - } else { - entity = new EntityPotion(world, x, y, z); - ((EntityPotion) entity).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1))); - } - } else if (Fireball.class.isAssignableFrom(clazz)) { - if (SmallFireball.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SMALL_FIREBALL.create(world); - } else if (WitherSkull.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WITHER_SKULL.create(world); - } else if (DragonFireball.class.isAssignableFrom(clazz)) { - entity = EntityTypes.DRAGON_FIREBALL.create(world); - } else if (WindCharge.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WIND_CHARGE.create(world); - } else { - entity = EntityTypes.FIREBALL.create(world); - } - entity.moveTo(x, y, z, yaw, pitch); - Vector direction = location.getDirection().multiply(10); - ((EntityFireball) entity).setDirection(direction.getX(), direction.getY(), direction.getZ()); - } else if (ShulkerBullet.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SHULKER_BULLET.create(world); - entity.moveTo(x, y, z, yaw, pitch); - } else if (LlamaSpit.class.isAssignableFrom(clazz)) { - entity = EntityTypes.LLAMA_SPIT.create(world); - entity.moveTo(x, y, z, yaw, pitch); - } else if (Firework.class.isAssignableFrom(clazz)) { - entity = new EntityFireworks(world, x, y, z, net.minecraft.world.item.ItemStack.EMPTY); - } - } else if (Minecart.class.isAssignableFrom(clazz)) { - if (PoweredMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartFurnace(world, x, y, z); - } else if (StorageMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartChest(world, x, y, z); - } else if (ExplosiveMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartTNT(world, x, y, z); - } else if (HopperMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartHopper(world, x, y, z); - } else if (SpawnerMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartMobSpawner(world, x, y, z); - } else if (CommandMinecart.class.isAssignableFrom(clazz)) { - entity = new EntityMinecartCommandBlock(world, x, y, z); - } else { // Default to rideable minecart for pre-rideable compatibility - entity = new EntityMinecartRideable(world, x, y, z); - } - } else if (EnderSignal.class.isAssignableFrom(clazz)) { - entity = new EntityEnderSignal(world, x, y, z); - } else if (EnderCrystal.class.isAssignableFrom(clazz)) { - entity = EntityTypes.END_CRYSTAL.create(world); - entity.moveTo(x, y, z, 0, 0); - } else if (LivingEntity.class.isAssignableFrom(clazz)) { - if (Chicken.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CHICKEN.create(world); - } else if (Cow.class.isAssignableFrom(clazz)) { - if (MushroomCow.class.isAssignableFrom(clazz)) { - entity = EntityTypes.MOOSHROOM.create(world); - } else { - entity = EntityTypes.COW.create(world); - } - } else if (Golem.class.isAssignableFrom(clazz)) { - if (Snowman.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SNOW_GOLEM.create(world); - } else if (IronGolem.class.isAssignableFrom(clazz)) { - entity = EntityTypes.IRON_GOLEM.create(world); - } else if (Shulker.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SHULKER.create(world); - } - } else if (Creeper.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CREEPER.create(world); - } else if (Ghast.class.isAssignableFrom(clazz)) { - entity = EntityTypes.GHAST.create(world); - } else if (Pig.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PIG.create(world); - } else if (Player.class.isAssignableFrom(clazz)) { - // need a net server handler for this one - } else if (Sheep.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SHEEP.create(world); - } else if (AbstractHorse.class.isAssignableFrom(clazz)) { - if (ChestedHorse.class.isAssignableFrom(clazz)) { - if (Donkey.class.isAssignableFrom(clazz)) { - entity = EntityTypes.DONKEY.create(world); - } else if (Mule.class.isAssignableFrom(clazz)) { - entity = EntityTypes.MULE.create(world); - } else if (Llama.class.isAssignableFrom(clazz)) { - if (TraderLlama.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TRADER_LLAMA.create(world); - } else { - entity = EntityTypes.LLAMA.create(world); - } - } - } else if (SkeletonHorse.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SKELETON_HORSE.create(world); - } else if (ZombieHorse.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ZOMBIE_HORSE.create(world); - } else if (Camel.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CAMEL.create(world); - } else { - entity = EntityTypes.HORSE.create(world); - } - } else if (AbstractSkeleton.class.isAssignableFrom(clazz)) { - if (Stray.class.isAssignableFrom(clazz)) { - entity = EntityTypes.STRAY.create(world); - } else if (WitherSkeleton.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WITHER_SKELETON.create(world); - } else if (Skeleton.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SKELETON.create(world); - } - } else if (Slime.class.isAssignableFrom(clazz)) { - if (MagmaCube.class.isAssignableFrom(clazz)) { - entity = EntityTypes.MAGMA_CUBE.create(world); - } else { - entity = EntityTypes.SLIME.create(world); - } - } else if (Spider.class.isAssignableFrom(clazz)) { - if (CaveSpider.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CAVE_SPIDER.create(world); - } else { - entity = EntityTypes.SPIDER.create(world); - } - } else if (Squid.class.isAssignableFrom(clazz)) { - if (GlowSquid.class.isAssignableFrom(clazz)) { - entity = EntityTypes.GLOW_SQUID.create(world); - } else { - entity = EntityTypes.SQUID.create(world); - } - } else if (Tameable.class.isAssignableFrom(clazz)) { - if (Wolf.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WOLF.create(world); - } else if (Parrot.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PARROT.create(world); - } else if (Cat.class.isAssignableFrom(clazz)) { - entity = EntityTypes.CAT.create(world); - } - } else if (PigZombie.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ZOMBIFIED_PIGLIN.create(world); - } else if (Zombie.class.isAssignableFrom(clazz)) { - if (Husk.class.isAssignableFrom(clazz)) { - entity = EntityTypes.HUSK.create(world); - } else if (ZombieVillager.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ZOMBIE_VILLAGER.create(world); - } else if (Drowned.class.isAssignableFrom(clazz)) { - entity = EntityTypes.DROWNED.create(world); - } else { - entity = new EntityZombie(world); - } - } else if (Giant.class.isAssignableFrom(clazz)) { - entity = EntityTypes.GIANT.create(world); - } else if (Silverfish.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SILVERFISH.create(world); - } else if (Enderman.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ENDERMAN.create(world); - } else if (Blaze.class.isAssignableFrom(clazz)) { - entity = EntityTypes.BLAZE.create(world); - } else if (AbstractVillager.class.isAssignableFrom(clazz)) { - if (Villager.class.isAssignableFrom(clazz)) { - entity = EntityTypes.VILLAGER.create(world); - } else if (WanderingTrader.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WANDERING_TRADER.create(world); - } - } else if (Witch.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WITCH.create(world); - } else if (Wither.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WITHER.create(world); - } else if (ComplexLivingEntity.class.isAssignableFrom(clazz)) { - if (EnderDragon.class.isAssignableFrom(clazz)) { - Preconditions.checkArgument(this.isNormalWorld(), "Cannot spawn entity %s during world generation", clazz.getName()); - entity = EntityTypes.ENDER_DRAGON.create(getHandle().getMinecraftWorld()); - } - } else if (Ambient.class.isAssignableFrom(clazz)) { - if (Bat.class.isAssignableFrom(clazz)) { - entity = EntityTypes.BAT.create(world); - } - } else if (Rabbit.class.isAssignableFrom(clazz)) { - entity = EntityTypes.RABBIT.create(world); - } else if (Endermite.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ENDERMITE.create(world); - } else if (Guardian.class.isAssignableFrom(clazz)) { - if (ElderGuardian.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ELDER_GUARDIAN.create(world); - } else { - entity = EntityTypes.GUARDIAN.create(world); - } - } else if (ArmorStand.class.isAssignableFrom(clazz)) { - entity = new EntityArmorStand(world, x, y, z); - } else if (PolarBear.class.isAssignableFrom(clazz)) { - entity = EntityTypes.POLAR_BEAR.create(world); - } else if (Vex.class.isAssignableFrom(clazz)) { - entity = EntityTypes.VEX.create(world); - } else if (Illager.class.isAssignableFrom(clazz)) { - if (Spellcaster.class.isAssignableFrom(clazz)) { - if (Evoker.class.isAssignableFrom(clazz)) { - entity = EntityTypes.EVOKER.create(world); - } else if (Illusioner.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ILLUSIONER.create(world); - } - } else if (Vindicator.class.isAssignableFrom(clazz)) { - entity = EntityTypes.VINDICATOR.create(world); - } else if (Pillager.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PILLAGER.create(world); - } - } else if (Turtle.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TURTLE.create(world); - } else if (Phantom.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PHANTOM.create(world); - } else if (Fish.class.isAssignableFrom(clazz)) { - if (Cod.class.isAssignableFrom(clazz)) { - entity = EntityTypes.COD.create(world); - } else if (PufferFish.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PUFFERFISH.create(world); - } else if (Salmon.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SALMON.create(world); - } else if (TropicalFish.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TROPICAL_FISH.create(world); - } else if (Tadpole.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TADPOLE.create(world); - } - } else if (Dolphin.class.isAssignableFrom(clazz)) { - entity = EntityTypes.DOLPHIN.create(world); - } else if (Ocelot.class.isAssignableFrom(clazz)) { - entity = EntityTypes.OCELOT.create(world); - } else if (Ravager.class.isAssignableFrom(clazz)) { - entity = EntityTypes.RAVAGER.create(world); - } else if (Panda.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PANDA.create(world); - } else if (Fox.class.isAssignableFrom(clazz)) { - entity = EntityTypes.FOX.create(world); - } else if (Bee.class.isAssignableFrom(clazz)) { - entity = EntityTypes.BEE.create(world); - } else if (Hoglin.class.isAssignableFrom(clazz)) { - entity = EntityTypes.HOGLIN.create(world); - } else if (Piglin.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PIGLIN.create(world); - } else if (PiglinBrute.class.isAssignableFrom(clazz)) { - entity = EntityTypes.PIGLIN_BRUTE.create(world); - } else if (Strider.class.isAssignableFrom(clazz)) { - entity = EntityTypes.STRIDER.create(world); - } else if (Zoglin.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ZOGLIN.create(world); - } else if (Axolotl.class.isAssignableFrom(clazz)) { - entity = EntityTypes.AXOLOTL.create(world); - } else if (Goat.class.isAssignableFrom(clazz)) { - entity = EntityTypes.GOAT.create(world); - } else if (Allay.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ALLAY.create(world); - } else if (Frog.class.isAssignableFrom(clazz)) { - entity = EntityTypes.FROG.create(world); - } else if (Warden.class.isAssignableFrom(clazz)) { - entity = EntityTypes.WARDEN.create(world); - } else if (Sniffer.class.isAssignableFrom(clazz)) { - entity = EntityTypes.SNIFFER.create(world); - } else if (Breeze.class.isAssignableFrom(clazz)) { - entity = EntityTypes.BREEZE.create(world); - } - - if (entity != null) { - entity.absMoveTo(x, y, z, yaw, pitch); - entity.setYHeadRot(yaw); // SPIGOT-3587 - } - } else if (Hanging.class.isAssignableFrom(clazz)) { - if (LeashHitch.class.isAssignableFrom(clazz)) { - // SPIGOT-5732: LeashHitch has no direction and is always centered at a block - entity = new EntityLeash(world, BlockPosition.containing(x, y, z)); - } else { - BlockFace face = BlockFace.SELF; - BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH}; - - int width = 16; // 1 full block, also painting smallest size. - int height = 16; // 1 full block, also painting smallest size. - - if (ItemFrame.class.isAssignableFrom(clazz)) { - width = 12; - height = 12; - faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN}; - } - - final BlockPosition pos = BlockPosition.containing(x, y, z); - for (BlockFace dir : faces) { - IBlockData nmsBlock = getHandle().getBlockState(pos.relative(CraftBlock.blockFaceToNotch(dir))); - if (nmsBlock.isSolid() || BlockDiodeAbstract.isDiode(nmsBlock)) { - boolean taken = false; - AxisAlignedBB bb = (ItemFrame.class.isAssignableFrom(clazz)) - ? EntityItemFrame.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height) - : EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height); - List list = (List) getHandle().getEntities(null, bb); - for (Iterator it = list.iterator(); !taken && it.hasNext(); ) { - net.minecraft.world.entity.Entity e = it.next(); - if (e instanceof EntityHanging) { - taken = true; // Hanging entities do not like hanging entities which intersect them. - } - } - - if (!taken) { - face = dir; - break; - } - } - } - - // No valid face found - if (face == BlockFace.SELF) { - // SPIGOT-6387: Allow hanging entities to be placed in midair - face = BlockFace.SOUTH; - randomizeData = false; // Don't randomize if no valid face is found, prevents null painting - } - - EnumDirection dir = CraftBlock.blockFaceToNotch(face).getOpposite(); - if (Painting.class.isAssignableFrom(clazz)) { - if (isNormalWorld() && randomizeData) { - entity = EntityPainting.create(world, pos, dir).orElse(null); - } else { - entity = new EntityPainting(EntityTypes.PAINTING, getHandle().getMinecraftWorld()); - entity.absMoveTo(x, y, z, yaw, pitch); - ((EntityPainting) entity).setDirection(dir); - } - } else if (ItemFrame.class.isAssignableFrom(clazz)) { - if (GlowItemFrame.class.isAssignableFrom(clazz)) { - entity = new net.minecraft.world.entity.decoration.GlowItemFrame(world, BlockPosition.containing(x, y, z), dir); - } else { - entity = new EntityItemFrame(world, BlockPosition.containing(x, y, z), dir); - } - } - } - } else if (TNTPrimed.class.isAssignableFrom(clazz)) { - entity = new EntityTNTPrimed(world, x, y, z, null); - } else if (ExperienceOrb.class.isAssignableFrom(clazz)) { - entity = new EntityExperienceOrb(world, x, y, z, 0); - } else if (LightningStrike.class.isAssignableFrom(clazz)) { - entity = EntityTypes.LIGHTNING_BOLT.create(world); - entity.moveTo(location.getX(), location.getY(), location.getZ()); - } else if (AreaEffectCloud.class.isAssignableFrom(clazz)) { - entity = new EntityAreaEffectCloud(world, x, y, z); - } else if (EvokerFangs.class.isAssignableFrom(clazz)) { - entity = new EntityEvokerFangs(world, x, y, z, (float) Math.toRadians(yaw), 0, null); - } else if (Marker.class.isAssignableFrom(clazz)) { - entity = EntityTypes.MARKER.create(world); - entity.setPos(x, y, z); - } else if (Interaction.class.isAssignableFrom(clazz)) { - entity = EntityTypes.INTERACTION.create(world); - entity.setPos(x, y, z); - } else if (Display.class.isAssignableFrom(clazz)) { - if (BlockDisplay.class.isAssignableFrom(clazz)) { - entity = EntityTypes.BLOCK_DISPLAY.create(world); - } else if (ItemDisplay.class.isAssignableFrom(clazz)) { - entity = EntityTypes.ITEM_DISPLAY.create(world); - } else if (TextDisplay.class.isAssignableFrom(clazz)) { - entity = EntityTypes.TEXT_DISPLAY.create(world); - } - - if (entity != null) { - entity.setPos(x, y, z); - } + // Convert classes which have no direct entity type, but where spawn able by the if cases + Consumer runOld = other -> { }; + if (clazz == AbstractArrow.class) { + clazz = Arrow.class; + } else if (clazz == AbstractHorse.class) { + clazz = Horse.class; + } else if (clazz == Fireball.class) { + clazz = LargeFireball.class; + } else if (clazz == LingeringPotion.class) { + clazz = ThrownPotion.class; + runOld = other -> ((EntityPotion) other).setItem(CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1))); + } else if (clazz == Minecart.class) { + clazz = RideableMinecart.class; + } else if (clazz == SizedFireball.class) { + clazz = LargeFireball.class; + } else if (clazz == SplashPotion.class) { + clazz = ThrownPotion.class; + } else if (clazz == TippedArrow.class) { + clazz = Arrow.class; + runOld = other -> ((Arrow) other.getBukkitEntity()).setBasePotionType(PotionType.WATER); } + CraftEntityTypes.EntityTypeData entityTypeData = CraftEntityTypes.getEntityTypeData(clazz); + + if (entityTypeData == null || entityTypeData.spawnFunction() == null) { + throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName()); + } + + if (!entityTypeData.entityType().isEnabledByFeature(getHandle().getMinecraftWorld().getWorld())) { + throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName() + " because it is not an enabled feature"); + } + + net.minecraft.world.entity.Entity entity = entityTypeData.spawnFunction().apply(new CraftEntityTypes.SpawnData(getHandle(), location, randomizeData, isNormalWorld())); + if (entity != null) { + runOld.accept(entity); return entity; } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 09339a7d4..dfe6110ef 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -15,159 +15,15 @@ import net.minecraft.server.level.EntityPlayer; import net.minecraft.server.level.PlayerChunkMap; import net.minecraft.server.level.WorldServer; import net.minecraft.server.network.ServerPlayerConnection; -import net.minecraft.world.entity.Display; import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.EntityAreaEffectCloud; -import net.minecraft.world.entity.EntityCreature; -import net.minecraft.world.entity.EntityExperienceOrb; -import net.minecraft.world.entity.EntityFlying; -import net.minecraft.world.entity.EntityLightning; -import net.minecraft.world.entity.EntityLiving; -import net.minecraft.world.entity.EntityTameableAnimal; import net.minecraft.world.entity.EntityTypes; -import net.minecraft.world.entity.GlowSquid; -import net.minecraft.world.entity.Interaction; -import net.minecraft.world.entity.Marker; -import net.minecraft.world.entity.ambient.EntityAmbient; -import net.minecraft.world.entity.ambient.EntityBat; -import net.minecraft.world.entity.animal.EntityAnimal; -import net.minecraft.world.entity.animal.EntityBee; -import net.minecraft.world.entity.animal.EntityCat; -import net.minecraft.world.entity.animal.EntityChicken; -import net.minecraft.world.entity.animal.EntityCod; -import net.minecraft.world.entity.animal.EntityCow; -import net.minecraft.world.entity.animal.EntityDolphin; -import net.minecraft.world.entity.animal.EntityFish; -import net.minecraft.world.entity.animal.EntityFox; -import net.minecraft.world.entity.animal.EntityGolem; -import net.minecraft.world.entity.animal.EntityIronGolem; -import net.minecraft.world.entity.animal.EntityMushroomCow; -import net.minecraft.world.entity.animal.EntityOcelot; -import net.minecraft.world.entity.animal.EntityPanda; -import net.minecraft.world.entity.animal.EntityParrot; -import net.minecraft.world.entity.animal.EntityPig; -import net.minecraft.world.entity.animal.EntityPolarBear; -import net.minecraft.world.entity.animal.EntityPufferFish; -import net.minecraft.world.entity.animal.EntityRabbit; -import net.minecraft.world.entity.animal.EntitySalmon; -import net.minecraft.world.entity.animal.EntitySheep; -import net.minecraft.world.entity.animal.EntitySnowman; -import net.minecraft.world.entity.animal.EntitySquid; -import net.minecraft.world.entity.animal.EntityTropicalFish; -import net.minecraft.world.entity.animal.EntityTurtle; -import net.minecraft.world.entity.animal.EntityWaterAnimal; -import net.minecraft.world.entity.animal.EntityWolf; -import net.minecraft.world.entity.animal.allay.Allay; -import net.minecraft.world.entity.animal.axolotl.Axolotl; -import net.minecraft.world.entity.animal.camel.Camel; -import net.minecraft.world.entity.animal.frog.Frog; -import net.minecraft.world.entity.animal.frog.Tadpole; -import net.minecraft.world.entity.animal.goat.Goat; -import net.minecraft.world.entity.animal.horse.EntityHorse; -import net.minecraft.world.entity.animal.horse.EntityHorseAbstract; -import net.minecraft.world.entity.animal.horse.EntityHorseChestedAbstract; -import net.minecraft.world.entity.animal.horse.EntityHorseDonkey; -import net.minecraft.world.entity.animal.horse.EntityHorseMule; -import net.minecraft.world.entity.animal.horse.EntityHorseSkeleton; -import net.minecraft.world.entity.animal.horse.EntityHorseZombie; -import net.minecraft.world.entity.animal.horse.EntityLlama; -import net.minecraft.world.entity.animal.horse.EntityLlamaTrader; -import net.minecraft.world.entity.animal.sniffer.Sniffer; import net.minecraft.world.entity.boss.EntityComplexPart; -import net.minecraft.world.entity.boss.enderdragon.EntityEnderCrystal; import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; -import net.minecraft.world.entity.boss.wither.EntityWither; -import net.minecraft.world.entity.decoration.EntityArmorStand; -import net.minecraft.world.entity.decoration.EntityHanging; -import net.minecraft.world.entity.decoration.EntityItemFrame; -import net.minecraft.world.entity.decoration.EntityLeash; -import net.minecraft.world.entity.decoration.EntityPainting; -import net.minecraft.world.entity.decoration.GlowItemFrame; -import net.minecraft.world.entity.item.EntityFallingBlock; -import net.minecraft.world.entity.item.EntityItem; -import net.minecraft.world.entity.item.EntityTNTPrimed; -import net.minecraft.world.entity.monster.EntityBlaze; -import net.minecraft.world.entity.monster.EntityCaveSpider; -import net.minecraft.world.entity.monster.EntityCreeper; -import net.minecraft.world.entity.monster.EntityDrowned; -import net.minecraft.world.entity.monster.EntityEnderman; -import net.minecraft.world.entity.monster.EntityEndermite; -import net.minecraft.world.entity.monster.EntityEvoker; -import net.minecraft.world.entity.monster.EntityGhast; -import net.minecraft.world.entity.monster.EntityGiantZombie; -import net.minecraft.world.entity.monster.EntityGuardian; -import net.minecraft.world.entity.monster.EntityGuardianElder; -import net.minecraft.world.entity.monster.EntityIllagerAbstract; -import net.minecraft.world.entity.monster.EntityIllagerIllusioner; -import net.minecraft.world.entity.monster.EntityIllagerWizard; -import net.minecraft.world.entity.monster.EntityMagmaCube; -import net.minecraft.world.entity.monster.EntityMonster; -import net.minecraft.world.entity.monster.EntityPhantom; -import net.minecraft.world.entity.monster.EntityPigZombie; -import net.minecraft.world.entity.monster.EntityPillager; -import net.minecraft.world.entity.monster.EntityRavager; -import net.minecraft.world.entity.monster.EntityShulker; -import net.minecraft.world.entity.monster.EntitySilverfish; -import net.minecraft.world.entity.monster.EntitySkeleton; -import net.minecraft.world.entity.monster.EntitySkeletonAbstract; -import net.minecraft.world.entity.monster.EntitySkeletonStray; -import net.minecraft.world.entity.monster.EntitySkeletonWither; -import net.minecraft.world.entity.monster.EntitySlime; -import net.minecraft.world.entity.monster.EntitySpider; -import net.minecraft.world.entity.monster.EntityStrider; -import net.minecraft.world.entity.monster.EntityVex; -import net.minecraft.world.entity.monster.EntityVindicator; -import net.minecraft.world.entity.monster.EntityWitch; -import net.minecraft.world.entity.monster.EntityZoglin; -import net.minecraft.world.entity.monster.EntityZombie; -import net.minecraft.world.entity.monster.EntityZombieHusk; -import net.minecraft.world.entity.monster.EntityZombieVillager; -import net.minecraft.world.entity.monster.breeze.Breeze; -import net.minecraft.world.entity.monster.hoglin.EntityHoglin; -import net.minecraft.world.entity.monster.piglin.EntityPiglin; -import net.minecraft.world.entity.monster.piglin.EntityPiglinAbstract; -import net.minecraft.world.entity.monster.piglin.EntityPiglinBrute; -import net.minecraft.world.entity.monster.warden.Warden; -import net.minecraft.world.entity.npc.EntityVillager; -import net.minecraft.world.entity.npc.EntityVillagerAbstract; -import net.minecraft.world.entity.npc.EntityVillagerTrader; import net.minecraft.world.entity.player.EntityHuman; import net.minecraft.world.entity.projectile.EntityArrow; -import net.minecraft.world.entity.projectile.EntityDragonFireball; -import net.minecraft.world.entity.projectile.EntityEgg; -import net.minecraft.world.entity.projectile.EntityEnderPearl; -import net.minecraft.world.entity.projectile.EntityEnderSignal; -import net.minecraft.world.entity.projectile.EntityEvokerFangs; -import net.minecraft.world.entity.projectile.EntityFireball; -import net.minecraft.world.entity.projectile.EntityFireworks; -import net.minecraft.world.entity.projectile.EntityFishingHook; -import net.minecraft.world.entity.projectile.EntityLargeFireball; -import net.minecraft.world.entity.projectile.EntityLlamaSpit; -import net.minecraft.world.entity.projectile.EntityPotion; -import net.minecraft.world.entity.projectile.EntityProjectile; -import net.minecraft.world.entity.projectile.EntityShulkerBullet; -import net.minecraft.world.entity.projectile.EntitySmallFireball; -import net.minecraft.world.entity.projectile.EntitySnowball; -import net.minecraft.world.entity.projectile.EntitySpectralArrow; -import net.minecraft.world.entity.projectile.EntityThrownExpBottle; -import net.minecraft.world.entity.projectile.EntityThrownTrident; -import net.minecraft.world.entity.projectile.EntityTippedArrow; -import net.minecraft.world.entity.projectile.EntityWitherSkull; -import net.minecraft.world.entity.projectile.WindCharge; -import net.minecraft.world.entity.vehicle.ChestBoat; -import net.minecraft.world.entity.vehicle.EntityBoat; -import net.minecraft.world.entity.vehicle.EntityMinecartAbstract; -import net.minecraft.world.entity.vehicle.EntityMinecartChest; -import net.minecraft.world.entity.vehicle.EntityMinecartCommandBlock; -import net.minecraft.world.entity.vehicle.EntityMinecartFurnace; -import net.minecraft.world.entity.vehicle.EntityMinecartHopper; -import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner; -import net.minecraft.world.entity.vehicle.EntityMinecartRideable; -import net.minecraft.world.entity.vehicle.EntityMinecartTNT; import net.minecraft.world.phys.AxisAlignedBB; import org.bukkit.EntityEffect; import org.bukkit.Location; -import org.bukkit.Registry; import org.bukkit.Server; import org.bukkit.Sound; import org.bukkit.World; @@ -181,7 +37,6 @@ import org.bukkit.craftbukkit.persistence.CraftPersistentDataContainer; import org.bukkit.craftbukkit.persistence.CraftPersistentDataTypeRegistry; import org.bukkit.craftbukkit.util.CraftChatMessage; import org.bukkit.craftbukkit.util.CraftLocation; -import org.bukkit.craftbukkit.util.CraftNamespacedKey; import org.bukkit.craftbukkit.util.CraftSpawnCategory; import org.bukkit.craftbukkit.util.CraftVector; import org.bukkit.entity.EntitySnapshot; @@ -218,232 +73,28 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { this.entityType = CraftEntityType.minecraftToBukkit(entity.getType()); } - public static CraftEntity getEntity(CraftServer server, Entity entity) { - /* - * Order is *EXTREMELY* important -- keep it right! =D - */ - // CHECKSTYLE:OFF - if (entity instanceof EntityLiving) { - // Players - if (entity instanceof EntityHuman) { - if (entity instanceof EntityPlayer) { return new CraftPlayer(server, (EntityPlayer) entity); } - else { return new CraftHumanEntity(server, (EntityHuman) entity); } - } - // Water Animals - else if (entity instanceof EntityWaterAnimal) { - if (entity instanceof EntitySquid) { - if (entity instanceof GlowSquid) { return new CraftGlowSquid(server, (GlowSquid) entity); } - else { return new CraftSquid(server, (EntitySquid) entity); } - } - else if (entity instanceof EntityFish) { - if (entity instanceof EntityCod) { return new CraftCod(server, (EntityCod) entity); } - else if (entity instanceof EntityPufferFish) { return new CraftPufferFish(server, (EntityPufferFish) entity); } - else if (entity instanceof EntitySalmon) { return new CraftSalmon(server, (EntitySalmon) entity); } - else if (entity instanceof EntityTropicalFish) { return new CraftTropicalFish(server, (EntityTropicalFish) entity); } - else if (entity instanceof Tadpole) { return new CraftTadpole(server, (Tadpole) entity); } - else { return new CraftFish(server, (EntityFish) entity); } - } - else if (entity instanceof EntityDolphin) { return new CraftDolphin(server, (EntityDolphin) entity); } - else { return new CraftWaterMob(server, (EntityWaterAnimal) entity); } - } - else if (entity instanceof EntityCreature) { - // Animals - if (entity instanceof EntityAnimal) { - if (entity instanceof EntityChicken) { return new CraftChicken(server, (EntityChicken) entity); } - else if (entity instanceof EntityCow) { - if (entity instanceof EntityMushroomCow) { return new CraftMushroomCow(server, (EntityMushroomCow) entity); } - else { return new CraftCow(server, (EntityCow) entity); } - } - else if (entity instanceof EntityPig) { return new CraftPig(server, (EntityPig) entity); } - else if (entity instanceof EntityTameableAnimal) { - if (entity instanceof EntityWolf) { return new CraftWolf(server, (EntityWolf) entity); } - else if (entity instanceof EntityCat) { return new CraftCat(server, (EntityCat) entity); } - else if (entity instanceof EntityParrot) { return new CraftParrot(server, (EntityParrot) entity); } - } - else if (entity instanceof EntitySheep) { return new CraftSheep(server, (EntitySheep) entity); } - else if (entity instanceof EntityHorseAbstract) { - if (entity instanceof EntityHorseChestedAbstract){ - if (entity instanceof EntityHorseDonkey) { return new CraftDonkey(server, (EntityHorseDonkey) entity); } - else if (entity instanceof EntityHorseMule) { return new CraftMule(server, (EntityHorseMule) entity); } - else if (entity instanceof EntityLlamaTrader) { return new CraftTraderLlama(server, (EntityLlamaTrader) entity); } - else if (entity instanceof EntityLlama) { return new CraftLlama(server, (EntityLlama) entity); } - } else if (entity instanceof EntityHorse) { return new CraftHorse(server, (EntityHorse) entity); } - else if (entity instanceof EntityHorseSkeleton) { return new CraftSkeletonHorse(server, (EntityHorseSkeleton) entity); } - else if (entity instanceof EntityHorseZombie) { return new CraftZombieHorse(server, (EntityHorseZombie) entity); } - else if (entity instanceof Camel) { return new CraftCamel(server, (Camel) entity); } - } - else if (entity instanceof EntityRabbit) { return new CraftRabbit(server, (EntityRabbit) entity); } - else if (entity instanceof EntityPolarBear) { return new CraftPolarBear(server, (EntityPolarBear) entity); } - else if (entity instanceof EntityTurtle) { return new CraftTurtle(server, (EntityTurtle) entity); } - else if (entity instanceof EntityOcelot) { return new CraftOcelot(server, (EntityOcelot) entity); } - else if (entity instanceof EntityPanda) { return new CraftPanda(server, (EntityPanda) entity); } - else if (entity instanceof EntityFox) { return new CraftFox(server, (EntityFox) entity); } - else if (entity instanceof EntityBee) { return new CraftBee(server, (EntityBee) entity); } - else if (entity instanceof EntityHoglin) { return new CraftHoglin(server, (EntityHoglin) entity); } - else if (entity instanceof EntityStrider) { return new CraftStrider(server, (EntityStrider) entity); } - else if (entity instanceof Axolotl) { return new CraftAxolotl(server, (Axolotl) entity); } - else if (entity instanceof Goat) { return new CraftGoat(server, (Goat) entity); } - else if (entity instanceof Frog) { return new CraftFrog(server, (Frog) entity); } - else if (entity instanceof Sniffer) { return new CraftSniffer(server, (Sniffer) entity); } - else { return new CraftAnimals(server, (EntityAnimal) entity); } - } - // Monsters - else if (entity instanceof EntityMonster) { - if (entity instanceof EntityZombie) { - if (entity instanceof EntityPigZombie) { return new CraftPigZombie(server, (EntityPigZombie) entity); } - else if (entity instanceof EntityZombieHusk) { return new CraftHusk(server, (EntityZombieHusk) entity); } - else if (entity instanceof EntityZombieVillager) { return new CraftVillagerZombie(server, (EntityZombieVillager) entity); } - else if (entity instanceof EntityDrowned) { return new CraftDrowned(server, (EntityDrowned) entity); } - else { return new CraftZombie(server, (EntityZombie) entity); } - } - else if (entity instanceof EntityCreeper) { return new CraftCreeper(server, (EntityCreeper) entity); } - else if (entity instanceof EntityEnderman) { return new CraftEnderman(server, (EntityEnderman) entity); } - else if (entity instanceof EntitySilverfish) { return new CraftSilverfish(server, (EntitySilverfish) entity); } - else if (entity instanceof EntityGiantZombie) { return new CraftGiant(server, (EntityGiantZombie) entity); } - else if (entity instanceof EntitySkeletonAbstract) { - if (entity instanceof EntitySkeletonStray) { return new CraftStray(server, (EntitySkeletonStray) entity); } - else if (entity instanceof EntitySkeletonWither) { return new CraftWitherSkeleton(server, (EntitySkeletonWither) entity); } - else if (entity instanceof EntitySkeleton){ return new CraftSkeleton(server, (EntitySkeleton) entity); } - } - else if (entity instanceof EntityBlaze) { return new CraftBlaze(server, (EntityBlaze) entity); } - else if (entity instanceof EntityWitch) { return new CraftWitch(server, (EntityWitch) entity); } - else if (entity instanceof EntityWither) { return new CraftWither(server, (EntityWither) entity); } - else if (entity instanceof EntitySpider) { - if (entity instanceof EntityCaveSpider) { return new CraftCaveSpider(server, (EntityCaveSpider) entity); } - else { return new CraftSpider(server, (EntitySpider) entity); } - } - else if (entity instanceof EntityEndermite) { return new CraftEndermite(server, (EntityEndermite) entity); } - else if (entity instanceof EntityGuardian) { - if (entity instanceof EntityGuardianElder) { return new CraftElderGuardian(server, (EntityGuardianElder) entity); } - else { return new CraftGuardian(server, (EntityGuardian) entity); } - } - else if (entity instanceof EntityVex) { return new CraftVex(server, (EntityVex) entity); } - else if (entity instanceof EntityIllagerAbstract) { - if (entity instanceof EntityIllagerWizard) { - if (entity instanceof EntityEvoker) { return new CraftEvoker(server, (EntityEvoker) entity); } - else if (entity instanceof EntityIllagerIllusioner) { return new CraftIllusioner(server, (EntityIllagerIllusioner) entity); } - else { return new CraftSpellcaster(server, (EntityIllagerWizard) entity); } - } - else if (entity instanceof EntityVindicator) { return new CraftVindicator(server, (EntityVindicator) entity); } - else if (entity instanceof EntityPillager) { return new CraftPillager(server, (EntityPillager) entity); } - else { return new CraftIllager(server, (EntityIllagerAbstract) entity); } - } - else if (entity instanceof EntityRavager) { return new CraftRavager(server, (EntityRavager) entity); } - else if (entity instanceof EntityPiglinAbstract) { - if (entity instanceof EntityPiglin) return new CraftPiglin(server, (EntityPiglin) entity); - else if (entity instanceof EntityPiglinBrute) { return new CraftPiglinBrute(server, (EntityPiglinBrute) entity); } - else { return new CraftPiglinAbstract(server, (EntityPiglinAbstract) entity); } - } - else if (entity instanceof EntityZoglin) { return new CraftZoglin(server, (EntityZoglin) entity); } - else if (entity instanceof Warden) { return new CraftWarden(server, (Warden) entity); } - else if (entity instanceof Breeze) { return new CraftBreeze(server, (Breeze) entity); } + public static CraftEntity getEntity(CraftServer server, T entity) { + Preconditions.checkArgument(entity != null, "Unknown entity"); - else { return new CraftMonster(server, (EntityMonster) entity); } - } - else if (entity instanceof EntityGolem) { - if (entity instanceof EntitySnowman) { return new CraftSnowman(server, (EntitySnowman) entity); } - else if (entity instanceof EntityIronGolem) { return new CraftIronGolem(server, (EntityIronGolem) entity); } - else if (entity instanceof EntityShulker) { return new CraftShulker(server, (EntityShulker) entity); } - } - else if (entity instanceof EntityVillagerAbstract) { - if (entity instanceof EntityVillager) { return new CraftVillager(server, (EntityVillager) entity); } - else if (entity instanceof EntityVillagerTrader) { return new CraftWanderingTrader(server, (EntityVillagerTrader) entity); } - else { return new CraftAbstractVillager(server, (EntityVillagerAbstract) entity); } - } - else if (entity instanceof Allay) { return new CraftAllay(server, (Allay) entity); } - else { return new CraftCreature(server, (EntityCreature) entity); } + // Special case human, since bukkit use Player interface for ... + if (entity instanceof EntityHuman && !(entity instanceof EntityPlayer)) { + return new CraftHumanEntity(server, (EntityHuman) entity); + } + + // Special case complex part, since there is no extra entity type for them + if (entity instanceof EntityComplexPart complexPart) { + if (complexPart.parentMob instanceof EntityEnderDragon) { + return new CraftEnderDragonPart(server, complexPart); + } else { + return new CraftComplexPart(server, complexPart); } - // Slimes are a special (and broken) case - else if (entity instanceof EntitySlime) { - if (entity instanceof EntityMagmaCube) { return new CraftMagmaCube(server, (EntityMagmaCube) entity); } - else { return new CraftSlime(server, (EntitySlime) entity); } - } - // Flying - else if (entity instanceof EntityFlying) { - if (entity instanceof EntityGhast) { return new CraftGhast(server, (EntityGhast) entity); } - else if (entity instanceof EntityPhantom) { return new CraftPhantom(server, (EntityPhantom) entity); } - else { return new CraftFlying(server, (EntityFlying) entity); } - } - else if (entity instanceof EntityEnderDragon) { - return new CraftEnderDragon(server, (EntityEnderDragon) entity); - } - // Ambient - else if (entity instanceof EntityAmbient) { - if (entity instanceof EntityBat) { return new CraftBat(server, (EntityBat) entity); } - else { return new CraftAmbient(server, (EntityAmbient) entity); } - } - else if (entity instanceof EntityArmorStand) { return new CraftArmorStand(server, (EntityArmorStand) entity); } - else { return new CraftLivingEntity(server, (EntityLiving) entity); } } - else if (entity instanceof EntityComplexPart) { - EntityComplexPart part = (EntityComplexPart) entity; - if (part.parentMob instanceof EntityEnderDragon) { return new CraftEnderDragonPart(server, (EntityComplexPart) entity); } - else { return new CraftComplexPart(server, (EntityComplexPart) entity); } + + CraftEntityTypes.EntityTypeData entityTypeData = CraftEntityTypes.getEntityTypeData(CraftEntityType.minecraftToBukkit(entity.getType())); + + if (entityTypeData != null) { + return entityTypeData.convertFunction().apply(server, entity); } - else if (entity instanceof EntityExperienceOrb) { return new CraftExperienceOrb(server, (EntityExperienceOrb) entity); } - else if (entity instanceof EntityTippedArrow) { return new CraftTippedArrow(server, (EntityTippedArrow) entity); } - else if (entity instanceof EntitySpectralArrow) { return new CraftSpectralArrow(server, (EntitySpectralArrow) entity); } - else if (entity instanceof EntityArrow) { - if (entity instanceof EntityThrownTrident) { return new CraftTrident(server, (EntityThrownTrident) entity); } - else { return new CraftArrow(server, (EntityArrow) entity); } - } - else if (entity instanceof EntityBoat) { - if (entity instanceof ChestBoat) { return new CraftChestBoat(server, (ChestBoat) entity); } - else { return new CraftBoat(server, (EntityBoat) entity); } - } - else if (entity instanceof EntityProjectile) { - if (entity instanceof EntityEgg) { return new CraftEgg(server, (EntityEgg) entity); } - else if (entity instanceof EntitySnowball) { return new CraftSnowball(server, (EntitySnowball) entity); } - else if (entity instanceof EntityPotion) { return new CraftThrownPotion(server, (EntityPotion) entity); } - else if (entity instanceof EntityEnderPearl) { return new CraftEnderPearl(server, (EntityEnderPearl) entity); } - else if (entity instanceof EntityThrownExpBottle) { return new CraftThrownExpBottle(server, (EntityThrownExpBottle) entity); } - } - else if (entity instanceof EntityFallingBlock) { return new CraftFallingBlock(server, (EntityFallingBlock) entity); } - else if (entity instanceof EntityFireball) { - if (entity instanceof EntitySmallFireball) { return new CraftSmallFireball(server, (EntitySmallFireball) entity); } - else if (entity instanceof EntityLargeFireball) { return new CraftLargeFireball(server, (EntityLargeFireball) entity); } - else if (entity instanceof EntityWitherSkull) { return new CraftWitherSkull(server, (EntityWitherSkull) entity); } - else if (entity instanceof EntityDragonFireball) { return new CraftDragonFireball(server, (EntityDragonFireball) entity); } - else if (entity instanceof WindCharge) { return new CraftWindCharge(server, (WindCharge) entity); } - else { return new CraftFireball(server, (EntityFireball) entity); } - } - else if (entity instanceof EntityEnderSignal) { return new CraftEnderSignal(server, (EntityEnderSignal) entity); } - else if (entity instanceof EntityEnderCrystal) { return new CraftEnderCrystal(server, (EntityEnderCrystal) entity); } - else if (entity instanceof EntityFishingHook) { return new CraftFishHook(server, (EntityFishingHook) entity); } - else if (entity instanceof EntityItem) { return new CraftItem(server, (EntityItem) entity); } - else if (entity instanceof EntityLightning) { return new CraftLightningStrike(server, (EntityLightning) entity); } - else if (entity instanceof EntityMinecartAbstract) { - if (entity instanceof EntityMinecartFurnace) { return new CraftMinecartFurnace(server, (EntityMinecartFurnace) entity); } - else if (entity instanceof EntityMinecartChest) { return new CraftMinecartChest(server, (EntityMinecartChest) entity); } - else if (entity instanceof EntityMinecartTNT) { return new CraftMinecartTNT(server, (EntityMinecartTNT) entity); } - else if (entity instanceof EntityMinecartHopper) { return new CraftMinecartHopper(server, (EntityMinecartHopper) entity); } - else if (entity instanceof EntityMinecartMobSpawner) { return new CraftMinecartMobSpawner(server, (EntityMinecartMobSpawner) entity); } - else if (entity instanceof EntityMinecartRideable) { return new CraftMinecartRideable(server, (EntityMinecartRideable) entity); } - else if (entity instanceof EntityMinecartCommandBlock) { return new CraftMinecartCommand(server, (EntityMinecartCommandBlock) entity); } - } else if (entity instanceof EntityHanging) { - if (entity instanceof EntityPainting) { return new CraftPainting(server, (EntityPainting) entity); } - else if (entity instanceof EntityItemFrame) { - if (entity instanceof GlowItemFrame) { return new CraftGlowItemFrame(server, (GlowItemFrame) entity); } - else { return new CraftItemFrame(server, (EntityItemFrame) entity); } - } - else if (entity instanceof EntityLeash) { return new CraftLeash(server, (EntityLeash) entity); } - else { return new CraftHanging(server, (EntityHanging) entity); } - } - else if (entity instanceof EntityTNTPrimed) { return new CraftTNTPrimed(server, (EntityTNTPrimed) entity); } - else if (entity instanceof EntityFireworks) { return new CraftFirework(server, (EntityFireworks) entity); } - else if (entity instanceof EntityShulkerBullet) { return new CraftShulkerBullet(server, (EntityShulkerBullet) entity); } - else if (entity instanceof EntityAreaEffectCloud) { return new CraftAreaEffectCloud(server, (EntityAreaEffectCloud) entity); } - else if (entity instanceof EntityEvokerFangs) { return new CraftEvokerFangs(server, (EntityEvokerFangs) entity); } - else if (entity instanceof EntityLlamaSpit) { return new CraftLlamaSpit(server, (EntityLlamaSpit) entity); } - else if (entity instanceof Marker) { return new CraftMarker(server, (Marker) entity); } - else if (entity instanceof Interaction) { return new CraftInteraction(server, (Interaction) entity); } - else if (entity instanceof Display) { - if (entity instanceof Display.BlockDisplay) { return new CraftBlockDisplay(server, (Display.BlockDisplay) entity); } - else if (entity instanceof Display.ItemDisplay) { return new CraftItemDisplay(server, (Display.ItemDisplay) entity); } - else if (entity instanceof Display.TextDisplay) { return new CraftTextDisplay(server, (Display.TextDisplay) entity); } - else { return new CraftDisplay(server, (Display) entity); } - } - // CHECKSTYLE:ON throw new AssertionError("Unknown entity " + (entity == null ? null : entity.getClass())); } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java new file mode 100644 index 000000000..11dca45db --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntityTypes.java @@ -0,0 +1,514 @@ +package org.bukkit.craftbukkit.entity; + +import com.google.common.base.Preconditions; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; +import net.minecraft.core.BlockPosition; +import net.minecraft.core.EnumDirection; +import net.minecraft.world.entity.EntityAreaEffectCloud; +import net.minecraft.world.entity.EntityExperienceOrb; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.boss.enderdragon.EntityEnderDragon; +import net.minecraft.world.entity.decoration.EntityHanging; +import net.minecraft.world.entity.decoration.EntityItemFrame; +import net.minecraft.world.entity.decoration.EntityLeash; +import net.minecraft.world.entity.decoration.EntityPainting; +import net.minecraft.world.entity.item.EntityFallingBlock; +import net.minecraft.world.entity.item.EntityItem; +import net.minecraft.world.entity.item.EntityTNTPrimed; +import net.minecraft.world.entity.projectile.EntityEgg; +import net.minecraft.world.entity.projectile.EntityEnderSignal; +import net.minecraft.world.entity.projectile.EntityEvokerFangs; +import net.minecraft.world.entity.projectile.EntityFireball; +import net.minecraft.world.entity.projectile.EntityFireworks; +import net.minecraft.world.entity.projectile.EntityPotion; +import net.minecraft.world.entity.projectile.EntitySnowball; +import net.minecraft.world.entity.vehicle.EntityMinecartChest; +import net.minecraft.world.entity.vehicle.EntityMinecartCommandBlock; +import net.minecraft.world.entity.vehicle.EntityMinecartFurnace; +import net.minecraft.world.entity.vehicle.EntityMinecartHopper; +import net.minecraft.world.entity.vehicle.EntityMinecartMobSpawner; +import net.minecraft.world.entity.vehicle.EntityMinecartRideable; +import net.minecraft.world.entity.vehicle.EntityMinecartTNT; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.GeneratorAccessSeed; +import net.minecraft.world.level.World; +import net.minecraft.world.level.block.BlockDiodeAbstract; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.phys.AxisAlignedBB; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.BlockFace; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.block.CraftBlock; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.Allay; +import org.bukkit.entity.AreaEffectCloud; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Arrow; +import org.bukkit.entity.Axolotl; +import org.bukkit.entity.Bat; +import org.bukkit.entity.Bee; +import org.bukkit.entity.Blaze; +import org.bukkit.entity.BlockDisplay; +import org.bukkit.entity.Boat; +import org.bukkit.entity.Breeze; +import org.bukkit.entity.Camel; +import org.bukkit.entity.Cat; +import org.bukkit.entity.CaveSpider; +import org.bukkit.entity.ChestBoat; +import org.bukkit.entity.Chicken; +import org.bukkit.entity.Cod; +import org.bukkit.entity.Cow; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Dolphin; +import org.bukkit.entity.Donkey; +import org.bukkit.entity.DragonFireball; +import org.bukkit.entity.Drowned; +import org.bukkit.entity.Egg; +import org.bukkit.entity.ElderGuardian; +import org.bukkit.entity.EnderCrystal; +import org.bukkit.entity.EnderDragon; +import org.bukkit.entity.EnderPearl; +import org.bukkit.entity.EnderSignal; +import org.bukkit.entity.Enderman; +import org.bukkit.entity.Endermite; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Evoker; +import org.bukkit.entity.EvokerFangs; +import org.bukkit.entity.ExperienceOrb; +import org.bukkit.entity.FallingBlock; +import org.bukkit.entity.Firework; +import org.bukkit.entity.FishHook; +import org.bukkit.entity.Fox; +import org.bukkit.entity.Frog; +import org.bukkit.entity.Ghast; +import org.bukkit.entity.Giant; +import org.bukkit.entity.GlowItemFrame; +import org.bukkit.entity.GlowSquid; +import org.bukkit.entity.Goat; +import org.bukkit.entity.Guardian; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.Hoglin; +import org.bukkit.entity.Horse; +import org.bukkit.entity.Husk; +import org.bukkit.entity.Illusioner; +import org.bukkit.entity.Interaction; +import org.bukkit.entity.IronGolem; +import org.bukkit.entity.Item; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.ItemFrame; +import org.bukkit.entity.LargeFireball; +import org.bukkit.entity.LeashHitch; +import org.bukkit.entity.LightningStrike; +import org.bukkit.entity.Llama; +import org.bukkit.entity.LlamaSpit; +import org.bukkit.entity.MagmaCube; +import org.bukkit.entity.Marker; +import org.bukkit.entity.Mule; +import org.bukkit.entity.MushroomCow; +import org.bukkit.entity.Ocelot; +import org.bukkit.entity.Painting; +import org.bukkit.entity.Panda; +import org.bukkit.entity.Parrot; +import org.bukkit.entity.Phantom; +import org.bukkit.entity.Pig; +import org.bukkit.entity.PigZombie; +import org.bukkit.entity.Piglin; +import org.bukkit.entity.PiglinBrute; +import org.bukkit.entity.Pillager; +import org.bukkit.entity.Player; +import org.bukkit.entity.PolarBear; +import org.bukkit.entity.PufferFish; +import org.bukkit.entity.Rabbit; +import org.bukkit.entity.Ravager; +import org.bukkit.entity.Salmon; +import org.bukkit.entity.Sheep; +import org.bukkit.entity.Shulker; +import org.bukkit.entity.ShulkerBullet; +import org.bukkit.entity.Silverfish; +import org.bukkit.entity.Skeleton; +import org.bukkit.entity.SkeletonHorse; +import org.bukkit.entity.Slime; +import org.bukkit.entity.SmallFireball; +import org.bukkit.entity.Sniffer; +import org.bukkit.entity.Snowball; +import org.bukkit.entity.Snowman; +import org.bukkit.entity.SpectralArrow; +import org.bukkit.entity.Spider; +import org.bukkit.entity.Squid; +import org.bukkit.entity.Stray; +import org.bukkit.entity.Strider; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.entity.Tadpole; +import org.bukkit.entity.TextDisplay; +import org.bukkit.entity.ThrownExpBottle; +import org.bukkit.entity.ThrownPotion; +import org.bukkit.entity.TraderLlama; +import org.bukkit.entity.Trident; +import org.bukkit.entity.TropicalFish; +import org.bukkit.entity.Turtle; +import org.bukkit.entity.Vex; +import org.bukkit.entity.Villager; +import org.bukkit.entity.Vindicator; +import org.bukkit.entity.WanderingTrader; +import org.bukkit.entity.Warden; +import org.bukkit.entity.WindCharge; +import org.bukkit.entity.Witch; +import org.bukkit.entity.Wither; +import org.bukkit.entity.WitherSkeleton; +import org.bukkit.entity.WitherSkull; +import org.bukkit.entity.Wolf; +import org.bukkit.entity.Zoglin; +import org.bukkit.entity.Zombie; +import org.bukkit.entity.ZombieHorse; +import org.bukkit.entity.ZombieVillager; +import org.bukkit.entity.minecart.CommandMinecart; +import org.bukkit.entity.minecart.ExplosiveMinecart; +import org.bukkit.entity.minecart.HopperMinecart; +import org.bukkit.entity.minecart.PoweredMinecart; +import org.bukkit.entity.minecart.RideableMinecart; +import org.bukkit.entity.minecart.SpawnerMinecart; +import org.bukkit.entity.minecart.StorageMinecart; +import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; + +public final class CraftEntityTypes { + + public record EntityTypeData(EntityType entityType, + Class entityClass, + BiFunction convertFunction, + Function spawnFunction) { + } + + public record SpawnData(GeneratorAccessSeed world, Location location, boolean randomizeData, boolean normalWorld) { + double x() { + return location().getX(); + } + + double y() { + return location().getY(); + } + + double z() { + return location().getZ(); + } + + float yaw() { + return location().getYaw(); + } + + float pitch() { + return location().getPitch(); + } + + World minecraftWorld() { + return world().getMinecraftWorld(); + } + } + + private static final BiConsumer POS = (spawnData, entity) -> entity.setPos(spawnData.x(), spawnData.y(), spawnData.z()); + private static final BiConsumer ABS_MOVE = (spawnData, entity) -> { + entity.absMoveTo(spawnData.x(), spawnData.y(), spawnData.z(), spawnData.yaw(), spawnData.pitch()); + entity.setYHeadRot(spawnData.yaw()); // SPIGOT-3587 + }; + private static final BiConsumer MOVE = (spawnData, entity) -> entity.moveTo(spawnData.x(), spawnData.y(), spawnData.z(), spawnData.yaw(), spawnData.pitch()); + private static final BiConsumer MOVE_EMPTY_ROT = (spawnData, entity) -> entity.moveTo(spawnData.x(), spawnData.y(), spawnData.z(), 0, 0); + private static final BiConsumer DIRECTION = (spawnData, entity) -> { + Vector direction = spawnData.location().getDirection().multiply(10); + entity.setDirection(direction.getX(), direction.getY(), direction.getZ()); + }; + private static final Map, EntityTypeData> CLASS_TYPE_DATA = new HashMap<>(); + private static final Map> ENTITY_TYPE_DATA = new HashMap<>(); + + static { + // Living + register(new EntityTypeData<>(EntityType.ELDER_GUARDIAN, ElderGuardian.class, CraftElderGuardian::new, createLiving(EntityTypes.ELDER_GUARDIAN))); + register(new EntityTypeData<>(EntityType.WITHER_SKELETON, WitherSkeleton.class, CraftWitherSkeleton::new, createLiving(EntityTypes.WITHER_SKELETON))); + register(new EntityTypeData<>(EntityType.STRAY, Stray.class, CraftStray::new, createLiving(EntityTypes.STRAY))); + register(new EntityTypeData<>(EntityType.HUSK, Husk.class, CraftHusk::new, createLiving(EntityTypes.HUSK))); + register(new EntityTypeData<>(EntityType.ZOMBIE_VILLAGER, ZombieVillager.class, CraftVillagerZombie::new, createLiving(EntityTypes.ZOMBIE_VILLAGER))); + register(new EntityTypeData<>(EntityType.SKELETON_HORSE, SkeletonHorse.class, CraftSkeletonHorse::new, createLiving(EntityTypes.SKELETON_HORSE))); + register(new EntityTypeData<>(EntityType.ZOMBIE_HORSE, ZombieHorse.class, CraftZombieHorse::new, createLiving(EntityTypes.ZOMBIE_HORSE))); + register(new EntityTypeData<>(EntityType.ARMOR_STAND, ArmorStand.class, CraftArmorStand::new, createLiving(EntityTypes.ARMOR_STAND))); + register(new EntityTypeData<>(EntityType.DONKEY, Donkey.class, CraftDonkey::new, createLiving(EntityTypes.DONKEY))); + register(new EntityTypeData<>(EntityType.MULE, Mule.class, CraftMule::new, createLiving(EntityTypes.MULE))); + register(new EntityTypeData<>(EntityType.EVOKER, Evoker.class, CraftEvoker::new, createLiving(EntityTypes.EVOKER))); + register(new EntityTypeData<>(EntityType.VEX, Vex.class, CraftVex::new, createLiving(EntityTypes.VEX))); + register(new EntityTypeData<>(EntityType.VINDICATOR, Vindicator.class, CraftVindicator::new, createLiving(EntityTypes.VINDICATOR))); + register(new EntityTypeData<>(EntityType.ILLUSIONER, Illusioner.class, CraftIllusioner::new, createLiving(EntityTypes.ILLUSIONER))); + register(new EntityTypeData<>(EntityType.CREEPER, Creeper.class, CraftCreeper::new, createLiving(EntityTypes.CREEPER))); + register(new EntityTypeData<>(EntityType.SKELETON, Skeleton.class, CraftSkeleton::new, createLiving(EntityTypes.SKELETON))); + register(new EntityTypeData<>(EntityType.SPIDER, Spider.class, CraftSpider::new, createLiving(EntityTypes.SPIDER))); + register(new EntityTypeData<>(EntityType.GIANT, Giant.class, CraftGiant::new, createLiving(EntityTypes.GIANT))); + register(new EntityTypeData<>(EntityType.ZOMBIE, Zombie.class, CraftZombie::new, createLiving(EntityTypes.ZOMBIE))); + register(new EntityTypeData<>(EntityType.SLIME, Slime.class, CraftSlime::new, createLiving(EntityTypes.SLIME))); + register(new EntityTypeData<>(EntityType.GHAST, Ghast.class, CraftGhast::new, createLiving(EntityTypes.GHAST))); + register(new EntityTypeData<>(EntityType.ZOMBIFIED_PIGLIN, PigZombie.class, CraftPigZombie::new, createLiving(EntityTypes.ZOMBIFIED_PIGLIN))); + register(new EntityTypeData<>(EntityType.ENDERMAN, Enderman.class, CraftEnderman::new, createLiving(EntityTypes.ENDERMAN))); + register(new EntityTypeData<>(EntityType.CAVE_SPIDER, CaveSpider.class, CraftCaveSpider::new, createLiving(EntityTypes.CAVE_SPIDER))); + register(new EntityTypeData<>(EntityType.SILVERFISH, Silverfish.class, CraftSilverfish::new, createLiving(EntityTypes.SILVERFISH))); + register(new EntityTypeData<>(EntityType.BLAZE, Blaze.class, CraftBlaze::new, createLiving(EntityTypes.BLAZE))); + register(new EntityTypeData<>(EntityType.MAGMA_CUBE, MagmaCube.class, CraftMagmaCube::new, createLiving(EntityTypes.MAGMA_CUBE))); + register(new EntityTypeData<>(EntityType.WITHER, Wither.class, CraftWither::new, createLiving(EntityTypes.WITHER))); + register(new EntityTypeData<>(EntityType.BAT, Bat.class, CraftBat::new, createLiving(EntityTypes.BAT))); + register(new EntityTypeData<>(EntityType.WITCH, Witch.class, CraftWitch::new, createLiving(EntityTypes.WITCH))); + register(new EntityTypeData<>(EntityType.ENDERMITE, Endermite.class, CraftEndermite::new, createLiving(EntityTypes.ENDERMITE))); + register(new EntityTypeData<>(EntityType.GUARDIAN, Guardian.class, CraftGuardian::new, createLiving(EntityTypes.GUARDIAN))); + register(new EntityTypeData<>(EntityType.SHULKER, Shulker.class, CraftShulker::new, createLiving(EntityTypes.SHULKER))); + register(new EntityTypeData<>(EntityType.PIG, Pig.class, CraftPig::new, createLiving(EntityTypes.PIG))); + register(new EntityTypeData<>(EntityType.SHEEP, Sheep.class, CraftSheep::new, createLiving(EntityTypes.SHEEP))); + register(new EntityTypeData<>(EntityType.COW, Cow.class, CraftCow::new, createLiving(EntityTypes.COW))); + register(new EntityTypeData<>(EntityType.CHICKEN, Chicken.class, CraftChicken::new, createLiving(EntityTypes.CHICKEN))); + register(new EntityTypeData<>(EntityType.SQUID, Squid.class, CraftSquid::new, createLiving(EntityTypes.SQUID))); + register(new EntityTypeData<>(EntityType.WOLF, Wolf.class, CraftWolf::new, createLiving(EntityTypes.WOLF))); + register(new EntityTypeData<>(EntityType.MUSHROOM_COW, MushroomCow.class, CraftMushroomCow::new, createLiving(EntityTypes.MOOSHROOM))); + register(new EntityTypeData<>(EntityType.SNOWMAN, Snowman.class, CraftSnowman::new, createLiving(EntityTypes.SNOW_GOLEM))); + register(new EntityTypeData<>(EntityType.OCELOT, Ocelot.class, CraftOcelot::new, createLiving(EntityTypes.OCELOT))); + register(new EntityTypeData<>(EntityType.IRON_GOLEM, IronGolem.class, CraftIronGolem::new, createLiving(EntityTypes.IRON_GOLEM))); + register(new EntityTypeData<>(EntityType.HORSE, Horse.class, CraftHorse::new, createLiving(EntityTypes.HORSE))); + register(new EntityTypeData<>(EntityType.RABBIT, Rabbit.class, CraftRabbit::new, createLiving(EntityTypes.RABBIT))); + register(new EntityTypeData<>(EntityType.POLAR_BEAR, PolarBear.class, CraftPolarBear::new, createLiving(EntityTypes.POLAR_BEAR))); + register(new EntityTypeData<>(EntityType.LLAMA, Llama.class, CraftLlama::new, createLiving(EntityTypes.LLAMA))); + register(new EntityTypeData<>(EntityType.PARROT, Parrot.class, CraftParrot::new, createLiving(EntityTypes.PARROT))); + register(new EntityTypeData<>(EntityType.VILLAGER, Villager.class, CraftVillager::new, createLiving(EntityTypes.VILLAGER))); + register(new EntityTypeData<>(EntityType.TURTLE, Turtle.class, CraftTurtle::new, createLiving(EntityTypes.TURTLE))); + register(new EntityTypeData<>(EntityType.PHANTOM, Phantom.class, CraftPhantom::new, createLiving(EntityTypes.PHANTOM))); + register(new EntityTypeData<>(EntityType.COD, Cod.class, CraftCod::new, createLiving(EntityTypes.COD))); + register(new EntityTypeData<>(EntityType.SALMON, Salmon.class, CraftSalmon::new, createLiving(EntityTypes.SALMON))); + register(new EntityTypeData<>(EntityType.PUFFERFISH, PufferFish.class, CraftPufferFish::new, createLiving(EntityTypes.PUFFERFISH))); + register(new EntityTypeData<>(EntityType.TROPICAL_FISH, TropicalFish.class, CraftTropicalFish::new, createLiving(EntityTypes.TROPICAL_FISH))); + register(new EntityTypeData<>(EntityType.DROWNED, Drowned.class, CraftDrowned::new, createLiving(EntityTypes.DROWNED))); + register(new EntityTypeData<>(EntityType.DOLPHIN, Dolphin.class, CraftDolphin::new, createLiving(EntityTypes.DOLPHIN))); + register(new EntityTypeData<>(EntityType.CAT, Cat.class, CraftCat::new, createLiving(EntityTypes.CAT))); + register(new EntityTypeData<>(EntityType.PANDA, Panda.class, CraftPanda::new, createLiving(EntityTypes.PANDA))); + register(new EntityTypeData<>(EntityType.PILLAGER, Pillager.class, CraftPillager::new, createLiving(EntityTypes.PILLAGER))); + register(new EntityTypeData<>(EntityType.RAVAGER, Ravager.class, CraftRavager::new, createLiving(EntityTypes.RAVAGER))); + register(new EntityTypeData<>(EntityType.TRADER_LLAMA, TraderLlama.class, CraftTraderLlama::new, createLiving(EntityTypes.TRADER_LLAMA))); + register(new EntityTypeData<>(EntityType.WANDERING_TRADER, WanderingTrader.class, CraftWanderingTrader::new, createLiving(EntityTypes.WANDERING_TRADER))); + register(new EntityTypeData<>(EntityType.FOX, Fox.class, CraftFox::new, createLiving(EntityTypes.FOX))); + register(new EntityTypeData<>(EntityType.BEE, Bee.class, CraftBee::new, createLiving(EntityTypes.BEE))); + register(new EntityTypeData<>(EntityType.HOGLIN, Hoglin.class, CraftHoglin::new, createLiving(EntityTypes.HOGLIN))); + register(new EntityTypeData<>(EntityType.PIGLIN, Piglin.class, CraftPiglin::new, createLiving(EntityTypes.PIGLIN))); + register(new EntityTypeData<>(EntityType.STRIDER, Strider.class, CraftStrider::new, createLiving(EntityTypes.STRIDER))); + register(new EntityTypeData<>(EntityType.ZOGLIN, Zoglin.class, CraftZoglin::new, createLiving(EntityTypes.ZOGLIN))); + register(new EntityTypeData<>(EntityType.PIGLIN_BRUTE, PiglinBrute.class, CraftPiglinBrute::new, createLiving(EntityTypes.PIGLIN_BRUTE))); + register(new EntityTypeData<>(EntityType.AXOLOTL, Axolotl.class, CraftAxolotl::new, createLiving(EntityTypes.AXOLOTL))); + register(new EntityTypeData<>(EntityType.GLOW_SQUID, GlowSquid.class, CraftGlowSquid::new, createLiving(EntityTypes.GLOW_SQUID))); + register(new EntityTypeData<>(EntityType.GOAT, Goat.class, CraftGoat::new, createLiving(EntityTypes.GOAT))); + register(new EntityTypeData<>(EntityType.ALLAY, Allay.class, CraftAllay::new, createLiving(EntityTypes.ALLAY))); + register(new EntityTypeData<>(EntityType.FROG, Frog.class, CraftFrog::new, createLiving(EntityTypes.FROG))); + register(new EntityTypeData<>(EntityType.TADPOLE, Tadpole.class, CraftTadpole::new, createLiving(EntityTypes.TADPOLE))); + register(new EntityTypeData<>(EntityType.WARDEN, Warden.class, CraftWarden::new, createLiving(EntityTypes.WARDEN))); + register(new EntityTypeData<>(EntityType.CAMEL, Camel.class, CraftCamel::new, createLiving(EntityTypes.CAMEL))); + register(new EntityTypeData<>(EntityType.SNIFFER, Sniffer.class, CraftSniffer::new, createLiving(EntityTypes.SNIFFER))); + register(new EntityTypeData<>(EntityType.BREEZE, Breeze.class, CraftBreeze::new, createLiving(EntityTypes.BREEZE))); + + Function dragonFunction = createLiving(EntityTypes.ENDER_DRAGON); + register(new EntityTypeData<>(EntityType.ENDER_DRAGON, EnderDragon.class, CraftEnderDragon::new, spawnData -> { + Preconditions.checkArgument(spawnData.normalWorld(), "Cannot spawn entity %s during world generation", EnderDragon.class.getName()); + return dragonFunction.apply(spawnData); + })); + + // Fireball + register(new EntityTypeData<>(EntityType.FIREBALL, LargeFireball.class, CraftLargeFireball::new, createFireball(EntityTypes.FIREBALL))); + register(new EntityTypeData<>(EntityType.SMALL_FIREBALL, SmallFireball.class, CraftSmallFireball::new, createFireball(EntityTypes.SMALL_FIREBALL))); + register(new EntityTypeData<>(EntityType.WITHER_SKULL, WitherSkull.class, CraftWitherSkull::new, createFireball(EntityTypes.WITHER_SKULL))); + register(new EntityTypeData<>(EntityType.DRAGON_FIREBALL, DragonFireball.class, CraftDragonFireball::new, createFireball(EntityTypes.DRAGON_FIREBALL))); + register(new EntityTypeData<>(EntityType.WIND_CHARGE, WindCharge.class, CraftWindCharge::new, createFireball(EntityTypes.WIND_CHARGE))); + + // Hanging + register(new EntityTypeData<>(EntityType.PAINTING, Painting.class, CraftPainting::new, createHanging(Painting.class, (spawnData, hangingData) -> { + if (spawnData.normalWorld && hangingData.randomize()) { + return EntityPainting.create(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction()).orElse(null); + } else { + EntityPainting entity = new EntityPainting(EntityTypes.PAINTING, spawnData.minecraftWorld()); + entity.absMoveTo(spawnData.x(), spawnData.y(), spawnData.z(), spawnData.yaw(), spawnData.pitch()); + entity.setDirection(hangingData.direction()); + return entity; + } + } + ))); + register(new EntityTypeData<>(EntityType.ITEM_FRAME, ItemFrame.class, CraftItemFrame::new, createHanging(ItemFrame.class, (spawnData, hangingData) -> new EntityItemFrame(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction())))); + register(new EntityTypeData<>(EntityType.GLOW_ITEM_FRAME, GlowItemFrame.class, CraftGlowItemFrame::new, createHanging(GlowItemFrame.class, (spawnData, hangingData) -> new net.minecraft.world.entity.decoration.GlowItemFrame(spawnData.minecraftWorld(), hangingData.position(), hangingData.direction())))); + + // Move no rotation + register(new EntityTypeData<>(EntityType.ARROW, Arrow.class, CraftArrow::new, createAndMoveEmptyRot(EntityTypes.ARROW))); + register(new EntityTypeData<>(EntityType.ENDER_PEARL, EnderPearl.class, CraftEnderPearl::new, createAndMoveEmptyRot(EntityTypes.ENDER_PEARL))); + register(new EntityTypeData<>(EntityType.THROWN_EXP_BOTTLE, ThrownExpBottle.class, CraftThrownExpBottle::new, createAndMoveEmptyRot(EntityTypes.EXPERIENCE_BOTTLE))); + register(new EntityTypeData<>(EntityType.SPECTRAL_ARROW, SpectralArrow.class, CraftSpectralArrow::new, createAndMoveEmptyRot(EntityTypes.SPECTRAL_ARROW))); + register(new EntityTypeData<>(EntityType.ENDER_CRYSTAL, EnderCrystal.class, CraftEnderCrystal::new, createAndMoveEmptyRot(EntityTypes.END_CRYSTAL))); + register(new EntityTypeData<>(EntityType.TRIDENT, Trident.class, CraftTrident::new, createAndMoveEmptyRot(EntityTypes.TRIDENT))); + register(new EntityTypeData<>(EntityType.LIGHTNING, LightningStrike.class, CraftLightningStrike::new, createAndMoveEmptyRot(EntityTypes.LIGHTNING_BOLT))); + + // Move + register(new EntityTypeData<>(EntityType.SHULKER_BULLET, ShulkerBullet.class, CraftShulkerBullet::new, createAndMove(EntityTypes.SHULKER_BULLET))); + register(new EntityTypeData<>(EntityType.BOAT, Boat.class, CraftBoat::new, createAndMove(EntityTypes.BOAT))); + register(new EntityTypeData<>(EntityType.LLAMA_SPIT, LlamaSpit.class, CraftLlamaSpit::new, createAndMove(EntityTypes.LLAMA_SPIT))); + register(new EntityTypeData<>(EntityType.CHEST_BOAT, ChestBoat.class, CraftChestBoat::new, createAndMove(EntityTypes.CHEST_BOAT))); + + // Set pos + register(new EntityTypeData<>(EntityType.MARKER, Marker.class, CraftMarker::new, createAndSetPos(EntityTypes.MARKER))); + register(new EntityTypeData<>(EntityType.BLOCK_DISPLAY, BlockDisplay.class, CraftBlockDisplay::new, createAndSetPos(EntityTypes.BLOCK_DISPLAY))); + register(new EntityTypeData<>(EntityType.INTERACTION, Interaction.class, CraftInteraction::new, createAndSetPos(EntityTypes.INTERACTION))); + register(new EntityTypeData<>(EntityType.ITEM_DISPLAY, ItemDisplay.class, CraftItemDisplay::new, createAndSetPos(EntityTypes.ITEM_DISPLAY))); + register(new EntityTypeData<>(EntityType.TEXT_DISPLAY, TextDisplay.class, CraftTextDisplay::new, createAndSetPos(EntityTypes.TEXT_DISPLAY))); + + // MISC + register(new EntityTypeData<>(EntityType.DROPPED_ITEM, Item.class, CraftItem::new, spawnData -> { + // We use stone instead of empty, to give the plugin developer a visual clue, that the spawn method is working, + // and that the item stack should probably be changed. + net.minecraft.world.item.ItemStack itemStack = new net.minecraft.world.item.ItemStack(Items.STONE); + EntityItem item = new EntityItem(spawnData.minecraftWorld(), spawnData.x(), spawnData.z(), spawnData.z(), itemStack); + item.setPickUpDelay(10); + + return item; + })); + register(new EntityTypeData<>(EntityType.EXPERIENCE_ORB, ExperienceOrb.class, CraftExperienceOrb::new, + spawnData -> new EntityExperienceOrb(spawnData.minecraftWorld(), spawnData.x(), spawnData.z(), spawnData.z(), 0) + )); + register(new EntityTypeData<>(EntityType.AREA_EFFECT_CLOUD, AreaEffectCloud.class, CraftAreaEffectCloud::new, spawnData -> new EntityAreaEffectCloud(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.EGG, Egg.class, CraftEgg::new, spawnData -> new EntityEgg(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.LEASH_HITCH, LeashHitch.class, CraftLeash::new, spawnData -> new EntityLeash(spawnData.minecraftWorld(), BlockPosition.containing(spawnData.x(), spawnData.y(), spawnData.z())))); // SPIGOT-5732: LeashHitch has no direction and is always centered at a block + register(new EntityTypeData<>(EntityType.SNOWBALL, Snowball.class, CraftSnowball::new, spawnData -> new EntitySnowball(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.ENDER_SIGNAL, EnderSignal.class, CraftEnderSignal::new, spawnData -> new EntityEnderSignal(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.SPLASH_POTION, ThrownPotion.class, CraftThrownPotion::new, spawnData -> { + EntityPotion entity = new EntityPotion(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()); + entity.setItem(CraftItemStack.asNMSCopy(new ItemStack(Material.SPLASH_POTION, 1))); + return entity; + })); + register(new EntityTypeData<>(EntityType.PRIMED_TNT, TNTPrimed.class, CraftTNTPrimed::new, spawnData -> new EntityTNTPrimed(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), null))); + register(new EntityTypeData<>(EntityType.FALLING_BLOCK, FallingBlock.class, CraftFallingBlock::new, spawnData -> { + BlockPosition pos = BlockPosition.containing(spawnData.x(), spawnData.y(), spawnData.z()); + return EntityFallingBlock.fall(spawnData.minecraftWorld(), pos, spawnData.world().getBlockState(pos)); + })); + register(new EntityTypeData<>(EntityType.FIREWORK, Firework.class, CraftFirework::new, spawnData -> new EntityFireworks(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), net.minecraft.world.item.ItemStack.EMPTY))); + register(new EntityTypeData<>(EntityType.EVOKER_FANGS, EvokerFangs.class, CraftEvokerFangs::new, spawnData -> new EntityEvokerFangs(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z(), (float) Math.toRadians(spawnData.yaw()), 0, null))); + register(new EntityTypeData<>(EntityType.MINECART_COMMAND, CommandMinecart.class, CraftMinecartCommand::new, spawnData -> new EntityMinecartCommandBlock(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART, RideableMinecart.class, CraftMinecartRideable::new, spawnData -> new EntityMinecartRideable(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART_CHEST, StorageMinecart.class, CraftMinecartChest::new, spawnData -> new EntityMinecartChest(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART_FURNACE, PoweredMinecart.class, CraftMinecartFurnace::new, spawnData -> new EntityMinecartFurnace(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART_TNT, ExplosiveMinecart.class, CraftMinecartTNT::new, spawnData -> new EntityMinecartTNT(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART_HOPPER, HopperMinecart.class, CraftMinecartHopper::new, spawnData -> new EntityMinecartHopper(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + register(new EntityTypeData<>(EntityType.MINECART_MOB_SPAWNER, SpawnerMinecart.class, CraftMinecartMobSpawner::new, spawnData -> new EntityMinecartMobSpawner(spawnData.minecraftWorld(), spawnData.x(), spawnData.y(), spawnData.z()))); + + // None spawn able + register(new EntityTypeData<>(EntityType.FISHING_HOOK, FishHook.class, CraftFishHook::new, null)); // Cannot spawn a fish hook + register(new EntityTypeData<>(EntityType.PLAYER, Player.class, CraftPlayer::new, null)); // Cannot spawn a player + } + + private static void register(EntityTypeData typeData) { + EntityTypeData other = CLASS_TYPE_DATA.put(typeData.entityClass(), typeData); + if (other != null) { + Bukkit.getLogger().warning(String.format("Found multiple entity type data for class %s, replacing '%s' with new value '%s'", typeData.entityClass().getName(), other, typeData)); + } + + other = ENTITY_TYPE_DATA.put(typeData.entityType(), typeData); + if (other != null) { + Bukkit.getLogger().warning(String.format("Found multiple entity type data for entity type %s, replacing '%s' with new value '%s'", typeData.entityType().getKey(), other, typeData)); + } + } + + private static Function fromEntityType(EntityTypes entityTypes) { + return spawnData -> entityTypes.create(spawnData.minecraftWorld()); + } + + private static Function createLiving(EntityTypes entityTypes) { + return combine(fromEntityType(entityTypes), ABS_MOVE); + } + + private static Function createFireball(EntityTypes entityTypes) { + return combine(createAndMove(entityTypes), DIRECTION); + } + + private static Function createAndMove(EntityTypes entityTypes) { + return combine(fromEntityType(entityTypes), MOVE); + } + + private static Function createAndMoveEmptyRot(EntityTypes entityTypes) { + return combine(fromEntityType(entityTypes), MOVE_EMPTY_ROT); + } + + private static Function createAndSetPos(EntityTypes entityTypes) { + return combine(fromEntityType(entityTypes), POS); + } + + private record HangingData(boolean randomize, BlockPosition position, EnumDirection direction) { + } + + private static Function createHanging(Class clazz, BiFunction spawnFunction) { + return spawnData -> { + boolean randomizeData = spawnData.randomizeData(); + BlockFace face = BlockFace.SELF; + BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH}; + + int width = 16; // 1 full block, also painting smallest size. + int height = 16; // 1 full block, also painting smallest size. + + if (ItemFrame.class.isAssignableFrom(clazz)) { + width = 12; + height = 12; + faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH, BlockFace.UP, BlockFace.DOWN}; + } + + final BlockPosition pos = BlockPosition.containing(spawnData.x(), spawnData.y(), spawnData.z()); + for (BlockFace dir : faces) { + IBlockData nmsBlock = spawnData.world().getBlockState(pos.relative(CraftBlock.blockFaceToNotch(dir))); + if (nmsBlock.isSolid() || BlockDiodeAbstract.isDiode(nmsBlock)) { + boolean taken = false; + AxisAlignedBB bb = (ItemFrame.class.isAssignableFrom(clazz)) + ? EntityItemFrame.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height) + : EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).getOpposite(), width, height); + List list = spawnData.world().getEntities(null, bb); + for (Iterator it = list.iterator(); !taken && it.hasNext(); ) { + net.minecraft.world.entity.Entity e = it.next(); + if (e instanceof EntityHanging) { + taken = true; // Hanging entities do not like hanging entities which intersect them. + } + } + + if (!taken) { + face = dir; + break; + } + } + } + + // No valid face found + if (face == BlockFace.SELF) { + // SPIGOT-6387: Allow hanging entities to be placed in midair + face = BlockFace.SOUTH; + randomizeData = false; // Don't randomize if no valid face is found, prevents null painting + } + + EnumDirection dir = CraftBlock.blockFaceToNotch(face).getOpposite(); + return spawnFunction.apply(spawnData, new HangingData(randomizeData, pos, dir)); + }; + } + + private static Function combine(Function before, BiConsumer after) { + return (t) -> { + R r = before.apply(t); + after.accept(t, r); + return r; + }; + } + + public static EntityTypeData getEntityTypeData(EntityType entityType) { + return (EntityTypeData) ENTITY_TYPE_DATA.get(entityType); + } + + public static EntityTypeData getEntityTypeData(Class entityClass) { + return (EntityTypeData) CLASS_TYPE_DATA.get(entityClass); + } + + private CraftEntityTypes() { + } +} diff --git a/src/test/java/org/bukkit/craftbukkit/entity/EntityTypesTest.java b/src/test/java/org/bukkit/craftbukkit/entity/EntityTypesTest.java new file mode 100644 index 000000000..7aaaef5aa --- /dev/null +++ b/src/test/java/org/bukkit/craftbukkit/entity/EntityTypesTest.java @@ -0,0 +1,183 @@ +package org.bukkit.craftbukkit.entity; + +import static org.junit.jupiter.api.Assertions.*; +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Arrays; +import java.util.List; +import java.util.jar.JarFile; +import java.util.stream.Stream; +import java.util.zip.ZipEntry; +import org.bukkit.entity.AbstractArrow; +import org.bukkit.entity.AbstractHorse; +import org.bukkit.entity.AbstractSkeleton; +import org.bukkit.entity.AbstractVillager; +import org.bukkit.entity.Ageable; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Boss; +import org.bukkit.entity.Breedable; +import org.bukkit.entity.ChestedHorse; +import org.bukkit.entity.ComplexEntityPart; +import org.bukkit.entity.ComplexLivingEntity; +import org.bukkit.entity.Creature; +import org.bukkit.entity.Damageable; +import org.bukkit.entity.Display; +import org.bukkit.entity.EnderDragonPart; +import org.bukkit.entity.Enemy; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Explosive; +import org.bukkit.entity.Fireball; +import org.bukkit.entity.Fish; +import org.bukkit.entity.Flying; +import org.bukkit.entity.Golem; +import org.bukkit.entity.Hanging; +import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.Illager; +import org.bukkit.entity.LingeringPotion; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Minecart; +import org.bukkit.entity.Mob; +import org.bukkit.entity.Monster; +import org.bukkit.entity.NPC; +import org.bukkit.entity.PiglinAbstract; +import org.bukkit.entity.Projectile; +import org.bukkit.entity.Raider; +import org.bukkit.entity.SizedFireball; +import org.bukkit.entity.Spellcaster; +import org.bukkit.entity.SplashPotion; +import org.bukkit.entity.Steerable; +import org.bukkit.entity.Tameable; +import org.bukkit.entity.ThrowableProjectile; +import org.bukkit.entity.TippedArrow; +import org.bukkit.entity.Vehicle; +import org.bukkit.entity.WaterMob; +import org.bukkit.support.AbstractTestingBase; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.EnumSource; +import org.junit.jupiter.params.provider.MethodSource; + +public class EntityTypesTest extends AbstractTestingBase { + + private static final URI BUKKIT_CLASSES; + // Entity classes, which do not have any entity type / entity type data + private static final List> EXCLUDE = Arrays.asList( + AbstractArrow.class, + AbstractHorse.class, + AbstractSkeleton.class, + AbstractVillager.class, + Ageable.class, + Ambient.class, + Animals.class, + Breedable.class, + Boss.class, + ChestedHorse.class, + ComplexEntityPart.class, + ComplexLivingEntity.class, + Creature.class, + Damageable.class, + Display.class, + EnderDragonPart.class, + Enemy.class, + Entity.class, + Explosive.class, + Fireball.class, + Fish.class, + Flying.class, + Golem.class, + Hanging.class, + HumanEntity.class, + Illager.class, + LingeringPotion.class, + LivingEntity.class, + Minecart.class, + Mob.class, + Monster.class, + NPC.class, + PiglinAbstract.class, + Projectile.class, + Raider.class, + SizedFireball.class, + Spellcaster.class, + SplashPotion.class, + Steerable.class, + Tameable.class, + ThrowableProjectile.class, + TippedArrow.class, + Vehicle.class, + WaterMob.class + ); + + static { + try { + BUKKIT_CLASSES = Entity.class.getProtectionDomain().getCodeSource().getLocation().toURI(); + } catch (URISyntaxException e) { + throw new RuntimeException(e); + } + } + + private static JarFile jarFile = null; + + public static Stream excludedData() { + return EXCLUDE.stream().map(Arguments::arguments); + } + + public static Stream data() { + return jarFile + .stream() + .map(ZipEntry::getName) + .filter(name -> name.endsWith(".class")) + .filter(name -> name.startsWith("org/bukkit/entity")) + .map(name -> name.substring(0, name.length() - ".class".length())) + .map(name -> name.replace('/', '.')) + .map(name -> { + try { + return Class.forName(name); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + }) + .filter(Entity.class::isAssignableFrom) + .filter(clazz -> !EXCLUDE.contains(clazz)) + .map(Arguments::arguments); + } + + @BeforeAll + public static void beforeAll() throws IOException { + jarFile = new JarFile(new File(BUKKIT_CLASSES)); + } + + @ParameterizedTest + @MethodSource("excludedData") + public void testExcludedClass(Class clazz) { + CraftEntityTypes.EntityTypeData entityTypeData = CraftEntityTypes.getEntityTypeData(clazz); + assertNull(entityTypeData, String.format("Class %s is marked as excluded, because it does not have an entity type data, but we found one entity type data, something is not adding up.", clazz)); + } + + @ParameterizedTest + @MethodSource("data") + public void testEntityClass(Class clazz) { + CraftEntityTypes.EntityTypeData entityTypeData = CraftEntityTypes.getEntityTypeData(clazz); + assertNotNull(entityTypeData, String.format("Class %s does not have an entity type data, please add on to CraftEntityTypes or mark the class as excluded in EntityTypesTest, if the class does not have an entity type.", clazz)); + } + + @ParameterizedTest + @EnumSource(value = EntityType.class, names = "UNKNOWN", mode = EnumSource.Mode.EXCLUDE) + public void testEntityType(EntityType entityType) { + CraftEntityTypes.EntityTypeData entityTypeData = CraftEntityTypes.getEntityTypeData(entityType); + assertNotNull(entityTypeData, String.format("Entity type %s does not have an entity type data, please add on to CraftEntityTypes.", entityType)); + } + + @AfterAll + public static void clear() throws IOException { + if (jarFile != null) { + jarFile.close(); + } + } +}