CraftBukkit/src/main/java/org/bukkit/craftbukkit/CraftRegionAccessor.java
DerFrZocker 6cd975d07e
SPIGOT-5732, SPIGOT-6387: Overhaul Hanging entities
- SPIGOT-5732: Fix issue with spawning leash hitches and painting, by using the right block faces

- SPIGOT-6387: Allow hanging entities to be spawned mid air

- Use randomize parameter to determine if a random painting should be chosen or not

- Return BlockFace self by leash hitches entity

- Throw a standardised exception when trying to set a BlockFace to a hanging entity which the entity does not support, instead of using BlockFace south or throwing a null pointer
2021-09-10 17:46:38 +10:00

907 lines
41 KiB
Java

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 net.minecraft.core.BlockPosition;
import net.minecraft.core.EnumDirection;
import net.minecraft.core.IRegistry;
import net.minecraft.data.worldgen.BiomeDecoratorGroups;
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.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.EntityBoat;
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.FeaturePlaceContext;
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.CraftBlock;
import org.bukkit.craftbukkit.block.data.CraftBlockData;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.craftbukkit.potion.CraftPotionUtil;
import org.bukkit.craftbukkit.util.BlockStateListPopulator;
import org.bukkit.craftbukkit.util.CraftMagicNumbers;
import org.bukkit.entity.AbstractArrow;
import org.bukkit.entity.AbstractHorse;
import org.bukkit.entity.AbstractSkeleton;
import org.bukkit.entity.AbstractVillager;
import org.bukkit.entity.Ambient;
import org.bukkit.entity.AreaEffectCloud;
import org.bukkit.entity.ArmorStand;
import org.bukkit.entity.Axolotl;
import org.bukkit.entity.Bat;
import org.bukkit.entity.Bee;
import org.bukkit.entity.Blaze;
import org.bukkit.entity.Boat;
import org.bukkit.entity.Cat;
import org.bukkit.entity.CaveSpider;
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.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.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.IronGolem;
import org.bukkit.entity.ItemFrame;
import org.bukkit.entity.LeashHitch;
import org.bukkit.entity.LightningStrike;
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.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.Tameable;
import org.bukkit.entity.ThrownExpBottle;
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.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.event.entity.CreatureSpawnEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionData;
import org.bukkit.potion.PotionType;
import org.bukkit.util.Consumer;
import org.bukkit.util.Vector;
public abstract class CraftRegionAccessor implements RegionAccessor {
public abstract GeneratorAccessSeed getHandle();
public boolean isNormalWorld() {
return getHandle() instanceof net.minecraft.server.level.WorldServer;
}
@Override
public Biome getBiome(Location location) {
return getBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public Biome getBiome(int x, int y, int z) {
return CraftBlock.biomeBaseToBiome(getHandle().t().d(IRegistry.BIOME_REGISTRY), getHandle().getBiome(x >> 2, y >> 2, z >> 2));
}
@Override
public void setBiome(Location location, Biome biome) {
setBiome(location.getBlockX(), location.getBlockY(), location.getBlockZ(), biome);
}
@Override
public void setBiome(int x, int y, int z, Biome biome) {
Preconditions.checkArgument(biome != Biome.CUSTOM, "Cannot set the biome to %s", biome);
BiomeBase biomeBase = CraftBlock.biomeToBiomeBase(getHandle().t().d(IRegistry.BIOME_REGISTRY), biome);
setBiome(x, y, z, biomeBase);
}
public abstract void setBiome(int x, int y, int z, BiomeBase biomeBase);
@Override
public BlockState getBlockState(Location location) {
return getBlockState(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public BlockState getBlockState(int x, int y, int z) {
return CraftBlock.at(getHandle(), new BlockPosition(x, y, z)).getState();
}
@Override
public BlockData getBlockData(Location location) {
return getBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public BlockData getBlockData(int x, int y, int z) {
return CraftBlockData.fromData(getData(x, y, z));
}
@Override
public Material getType(Location location) {
return getType(location.getBlockX(), location.getBlockY(), location.getBlockZ());
}
@Override
public Material getType(int x, int y, int z) {
return CraftMagicNumbers.getMaterial(getData(x, y, z).getBlock());
}
private IBlockData getData(int x, int y, int z) {
return getHandle().getType(new BlockPosition(x, y, z));
}
@Override
public void setBlockData(Location location, BlockData blockData) {
setBlockData(location.getBlockX(), location.getBlockY(), location.getBlockZ(), blockData);
}
@Override
public void setBlockData(int x, int y, int z, BlockData blockData) {
CraftBlock.at(getHandle(), new BlockPosition(x, y, z)).setTypeAndData(((CraftBlockData) blockData).getState(), true);
}
@Override
public void setType(Location location, Material material) {
setType(location.getBlockX(), location.getBlockY(), location.getBlockZ(), material);
}
@Override
public void setType(int x, int y, int z, Material material) {
setBlockData(x, y, z, material.createBlockData());
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType) {
BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
return generateTree(getHandle(), getHandle().getMinecraftWorld().getChunkProvider().generator, pos, random, treeType);
}
@Override
public boolean generateTree(Location location, Random random, TreeType treeType, Consumer<BlockState> consumer) {
BlockPosition pos = new BlockPosition(location.getBlockX(), location.getBlockY(), location.getBlockZ());
BlockStateListPopulator populator = new BlockStateListPopulator(getHandle());
boolean result = generateTree(populator, getHandle().getMinecraftWorld().getChunkProvider().generator, pos, random, treeType);
populator.refreshTiles();
for (BlockState blockState : populator.getList()) {
if (consumer != null) {
consumer.accept(blockState);
}
blockState.update(true, true);
}
return result;
}
public boolean generateTree(GeneratorAccessSeed access, ChunkGenerator chunkGenerator, BlockPosition pos, Random random, TreeType treeType) {
net.minecraft.world.level.levelgen.feature.WorldGenFeatureConfigured gen;
switch (treeType) {
case BIG_TREE:
gen = BiomeDecoratorGroups.FANCY_OAK;
break;
case BIRCH:
gen = BiomeDecoratorGroups.BIRCH;
break;
case REDWOOD:
gen = BiomeDecoratorGroups.SPRUCE;
break;
case TALL_REDWOOD:
gen = BiomeDecoratorGroups.PINE;
break;
case JUNGLE:
gen = BiomeDecoratorGroups.MEGA_JUNGLE_TREE;
break;
case SMALL_JUNGLE:
gen = BiomeDecoratorGroups.JUNGLE_TREE_NO_VINE;
break;
case COCOA_TREE:
gen = BiomeDecoratorGroups.JUNGLE_TREE;
break;
case JUNGLE_BUSH:
gen = BiomeDecoratorGroups.JUNGLE_BUSH;
break;
case RED_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_RED_MUSHROOM;
break;
case BROWN_MUSHROOM:
gen = BiomeDecoratorGroups.HUGE_BROWN_MUSHROOM;
break;
case SWAMP:
gen = BiomeDecoratorGroups.SWAMP_OAK;
break;
case ACACIA:
gen = BiomeDecoratorGroups.ACACIA;
break;
case DARK_OAK:
gen = BiomeDecoratorGroups.DARK_OAK;
break;
case MEGA_REDWOOD:
gen = BiomeDecoratorGroups.MEGA_PINE;
break;
case TALL_BIRCH:
gen = BiomeDecoratorGroups.SUPER_BIRCH_BEES_0002;
break;
case CHORUS_PLANT:
((BlockChorusFlower) Blocks.CHORUS_FLOWER).a(access, pos, random, 8);
return true;
case CRIMSON_FUNGUS:
gen = BiomeDecoratorGroups.CRIMSON_FUNGI_PLANTED;
break;
case WARPED_FUNGUS:
gen = BiomeDecoratorGroups.WARPED_FUNGI_PLANTED;
break;
case AZALEA:
gen = BiomeDecoratorGroups.AZALEA_TREE;
break;
case TREE:
default:
gen = BiomeDecoratorGroups.OAK;
break;
}
return gen.feature.generate(new FeaturePlaceContext(access, chunkGenerator, random, pos, gen.config));
}
@Override
public Entity spawnEntity(Location location, EntityType entityType) {
return spawn(location, entityType.getEntityClass());
}
@Override
public Entity spawnEntity(Location loc, EntityType type, boolean randomizeData) {
return spawn(loc, type.getEntityClass(), null, CreatureSpawnEvent.SpawnReason.CUSTOM, randomizeData);
}
@Override
public List<Entity> getEntities() {
List<Entity> list = new ArrayList<Entity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add(bukkitEntity);
}
});
return list;
}
@Override
public List<LivingEntity> getLivingEntities() {
List<LivingEntity> list = new ArrayList<LivingEntity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
// Assuming that bukkitEntity isn't null
if (bukkitEntity != null && bukkitEntity instanceof LivingEntity && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add((LivingEntity) bukkitEntity);
}
});
return list;
}
@Override
@SuppressWarnings("unchecked")
public <T extends Entity> Collection<T> getEntitiesByClass(Class<T> clazz) {
Collection<T> list = new ArrayList<T>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
if (clazz.isAssignableFrom(bukkitClass) && (!isNormalWorld() || bukkitEntity.isValid())) {
list.add((T) bukkitEntity);
}
});
return list;
}
@Override
public Collection<Entity> getEntitiesByClasses(Class<?>... classes) {
Collection<Entity> list = new ArrayList<Entity>();
getNMSEntities().forEach(entity -> {
Entity bukkitEntity = entity.getBukkitEntity();
if (bukkitEntity == null) {
return;
}
Class<?> bukkitClass = bukkitEntity.getClass();
for (Class<?> clazz : classes) {
if (clazz.isAssignableFrom(bukkitClass)) {
if (!isNormalWorld() || bukkitEntity.isValid()) {
list.add(bukkitEntity);
}
break;
}
}
});
return list;
}
public abstract Iterable<net.minecraft.world.entity.Entity> getNMSEntities();
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz) throws IllegalArgumentException {
return spawn(location, clazz, null, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function) throws IllegalArgumentException {
return spawn(location, clazz, function, CreatureSpawnEvent.SpawnReason.CUSTOM);
}
@Override
public <T extends Entity> T spawn(Location location, Class<T> clazz, boolean randomizeData, Consumer<T> function) throws IllegalArgumentException {
return spawn(location, clazz, function, CreatureSpawnEvent.SpawnReason.CUSTOM, randomizeData);
}
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function, CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException {
return spawn(location, clazz, function, reason, true);
}
public <T extends Entity> T spawn(Location location, Class<T> clazz, Consumer<T> function, CreatureSpawnEvent.SpawnReason reason, boolean randomizeData) throws IllegalArgumentException {
net.minecraft.world.entity.Entity entity = createEntity(location, clazz, randomizeData);
return addEntity(entity, reason, function, randomizeData);
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason) throws IllegalArgumentException {
return addEntity(entity, reason, null, true);
}
@SuppressWarnings("unchecked")
public <T extends Entity> T addEntity(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason, Consumer<T> function, boolean randomizeData) throws IllegalArgumentException {
Preconditions.checkArgument(entity != null, "Cannot spawn null entity");
if (randomizeData && entity instanceof EntityInsentient) {
((EntityInsentient) entity).prepare(getHandle(), getHandle().getDamageScaler(entity.getChunkCoordinates()), EnumMobSpawn.COMMAND, (GroupDataEntity) null, null);
}
if (!isNormalWorld()) {
entity.generation = true;
}
if (function != null) {
function.accept((T) entity.getBukkitEntity());
}
addEntityToWorld(entity, reason);
return (T) entity.getBukkitEntity();
}
public abstract void addEntityToWorld(net.minecraft.world.entity.Entity entity, CreatureSpawnEvent.SpawnReason reason);
@SuppressWarnings("unchecked")
public net.minecraft.world.entity.Entity createEntity(Location location, Class<? extends Entity> clazz) throws IllegalArgumentException {
return createEntity(location, clazz, true);
}
@SuppressWarnings("unchecked")
public net.minecraft.world.entity.Entity createEntity(Location location, Class<? extends Entity> clazz, boolean randomizeData) throws IllegalArgumentException {
if (location == null || clazz == null) {
throw new IllegalArgumentException("Location or 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)) {
entity = new EntityBoat(world, x, y, z);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (FallingBlock.class.isAssignableFrom(clazz)) {
entity = new EntityFallingBlock(world, x, y, z, getHandle().getType(new BlockPosition(x, y, z)));
} 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.a(world);
((EntityTippedArrow) entity).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false)));
} else if (SpectralArrow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SPECTRAL_ARROW.a(world);
} else if (Trident.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRIDENT.a(world);
} else {
entity = EntityTypes.ARROW.a(world);
}
entity.setPositionRotation(x, y, z, 0, 0);
} else if (ThrownExpBottle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EXPERIENCE_BOTTLE.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (EnderPearl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDER_PEARL.a(world);
entity.setPositionRotation(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.a(world);
} else if (WitherSkull.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKULL.a(world);
} else if (DragonFireball.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DRAGON_FIREBALL.a(world);
} else {
entity = EntityTypes.FIREBALL.a(world);
}
entity.setPositionRotation(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.a(world);
entity.setPositionRotation(x, y, z, yaw, pitch);
} else if (LlamaSpit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.LLAMA_SPIT.a(world);
entity.setPositionRotation(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.a(world);
entity.setPositionRotation(x, y, z, 0, 0);
} else if (LivingEntity.class.isAssignableFrom(clazz)) {
if (Chicken.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CHICKEN.a(world);
} else if (Cow.class.isAssignableFrom(clazz)) {
if (MushroomCow.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MOOSHROOM.a(world);
} else {
entity = EntityTypes.COW.a(world);
}
} else if (Golem.class.isAssignableFrom(clazz)) {
if (Snowman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SNOW_GOLEM.a(world);
} else if (IronGolem.class.isAssignableFrom(clazz)) {
entity = EntityTypes.IRON_GOLEM.a(world);
} else if (Shulker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHULKER.a(world);
}
} else if (Creeper.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CREEPER.a(world);
} else if (Ghast.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GHAST.a(world);
} else if (Pig.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIG.a(world);
} else if (Player.class.isAssignableFrom(clazz)) {
// need a net server handler for this one
} else if (Sheep.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SHEEP.a(world);
} else if (AbstractHorse.class.isAssignableFrom(clazz)) {
if (ChestedHorse.class.isAssignableFrom(clazz)) {
if (Donkey.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DONKEY.a(world);
} else if (Mule.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MULE.a(world);
} else if (Llama.class.isAssignableFrom(clazz)) {
if (TraderLlama.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TRADER_LLAMA.a(world);
} else {
entity = EntityTypes.LLAMA.a(world);
}
}
} else if (SkeletonHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON_HORSE.a(world);
} else if (ZombieHorse.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_HORSE.a(world);
} else {
entity = EntityTypes.HORSE.a(world);
}
} else if (AbstractSkeleton.class.isAssignableFrom(clazz)) {
if (Stray.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRAY.a(world);
} else if (WitherSkeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER_SKELETON.a(world);
} else if (Skeleton.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SKELETON.a(world);
}
} else if (Slime.class.isAssignableFrom(clazz)) {
if (MagmaCube.class.isAssignableFrom(clazz)) {
entity = EntityTypes.MAGMA_CUBE.a(world);
} else {
entity = EntityTypes.SLIME.a(world);
}
} else if (Spider.class.isAssignableFrom(clazz)) {
if (CaveSpider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAVE_SPIDER.a(world);
} else {
entity = EntityTypes.SPIDER.a(world);
}
} else if (Squid.class.isAssignableFrom(clazz)) {
if (GlowSquid.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GLOW_SQUID.a(world);
} else {
entity = EntityTypes.SQUID.a(world);
}
} else if (Tameable.class.isAssignableFrom(clazz)) {
if (Wolf.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WOLF.a(world);
} else if (Parrot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PARROT.a(world);
} else if (Cat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.CAT.a(world);
}
} else if (PigZombie.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIFIED_PIGLIN.a(world);
} else if (Zombie.class.isAssignableFrom(clazz)) {
if (Husk.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HUSK.a(world);
} else if (ZombieVillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOMBIE_VILLAGER.a(world);
} else if (Drowned.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DROWNED.a(world);
} else {
entity = new EntityZombie(world);
}
} else if (Giant.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GIANT.a(world);
} else if (Silverfish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SILVERFISH.a(world);
} else if (Enderman.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMAN.a(world);
} else if (Blaze.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BLAZE.a(world);
} else if (AbstractVillager.class.isAssignableFrom(clazz)) {
if (Villager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VILLAGER.a(world);
} else if (WanderingTrader.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WANDERING_TRADER.a(world);
}
} else if (Witch.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITCH.a(world);
} else if (Wither.class.isAssignableFrom(clazz)) {
entity = EntityTypes.WITHER.a(world);
} else if (ComplexLivingEntity.class.isAssignableFrom(clazz)) {
if (EnderDragon.class.isAssignableFrom(clazz)) {
if (isNormalWorld()) {
entity = EntityTypes.ENDER_DRAGON.a(getHandle().getMinecraftWorld());
} else {
throw new IllegalArgumentException("Cannot spawn entity " + clazz.getName() + " during world generation");
}
}
} else if (Ambient.class.isAssignableFrom(clazz)) {
if (Bat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BAT.a(world);
}
} else if (Rabbit.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RABBIT.a(world);
} else if (Endermite.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ENDERMITE.a(world);
} else if (Guardian.class.isAssignableFrom(clazz)) {
if (ElderGuardian.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ELDER_GUARDIAN.a(world);
} else {
entity = EntityTypes.GUARDIAN.a(world);
}
} else if (ArmorStand.class.isAssignableFrom(clazz)) {
entity = new EntityArmorStand(world, x, y, z);
} else if (PolarBear.class.isAssignableFrom(clazz)) {
entity = EntityTypes.POLAR_BEAR.a(world);
} else if (Vex.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VEX.a(world);
} else if (Illager.class.isAssignableFrom(clazz)) {
if (Spellcaster.class.isAssignableFrom(clazz)) {
if (Evoker.class.isAssignableFrom(clazz)) {
entity = EntityTypes.EVOKER.a(world);
} else if (Illusioner.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ILLUSIONER.a(world);
}
} else if (Vindicator.class.isAssignableFrom(clazz)) {
entity = EntityTypes.VINDICATOR.a(world);
} else if (Pillager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PILLAGER.a(world);
}
} else if (Turtle.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TURTLE.a(world);
} else if (Phantom.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PHANTOM.a(world);
} else if (Fish.class.isAssignableFrom(clazz)) {
if (Cod.class.isAssignableFrom(clazz)) {
entity = EntityTypes.COD.a(world);
} else if (PufferFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PUFFERFISH.a(world);
} else if (Salmon.class.isAssignableFrom(clazz)) {
entity = EntityTypes.SALMON.a(world);
} else if (TropicalFish.class.isAssignableFrom(clazz)) {
entity = EntityTypes.TROPICAL_FISH.a(world);
}
} else if (Dolphin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.DOLPHIN.a(world);
} else if (Ocelot.class.isAssignableFrom(clazz)) {
entity = EntityTypes.OCELOT.a(world);
} else if (Ravager.class.isAssignableFrom(clazz)) {
entity = EntityTypes.RAVAGER.a(world);
} else if (Panda.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PANDA.a(world);
} else if (Fox.class.isAssignableFrom(clazz)) {
entity = EntityTypes.FOX.a(world);
} else if (Bee.class.isAssignableFrom(clazz)) {
entity = EntityTypes.BEE.a(world);
} else if (Hoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.HOGLIN.a(world);
} else if (Piglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN.a(world);
} else if (PiglinBrute.class.isAssignableFrom(clazz)) {
entity = EntityTypes.PIGLIN_BRUTE.a(world);
} else if (Strider.class.isAssignableFrom(clazz)) {
entity = EntityTypes.STRIDER.a(world);
} else if (Zoglin.class.isAssignableFrom(clazz)) {
entity = EntityTypes.ZOGLIN.a(world);
} else if (Axolotl.class.isAssignableFrom(clazz)) {
entity = EntityTypes.AXOLOTL.a(world);
} else if (Goat.class.isAssignableFrom(clazz)) {
entity = EntityTypes.GOAT.a(world);
}
if (entity != null) {
entity.setLocation(x, y, z, yaw, pitch);
entity.setHeadRotation(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, new BlockPosition(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 = new BlockPosition(x, y, z);
for (BlockFace dir : faces) {
IBlockData nmsBlock = getHandle().getType(pos.shift(CraftBlock.blockFaceToNotch(dir)));
if (nmsBlock.getMaterial().isBuildable() || BlockDiodeAbstract.isDiode(nmsBlock)) {
boolean taken = false;
AxisAlignedBB bb = (ItemFrame.class.isAssignableFrom(clazz))
? EntityItemFrame.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height)
: EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height);
List<net.minecraft.world.entity.Entity> list = (List<net.minecraft.world.entity.Entity>) getHandle().getEntities(null, bb);
for (Iterator<net.minecraft.world.entity.Entity> 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).opposite();
if (Painting.class.isAssignableFrom(clazz)) {
if (isNormalWorld() && randomizeData) {
entity = new EntityPainting(getHandle().getMinecraftWorld(), new BlockPosition(x, y, z), dir);
} else {
entity = new EntityPainting(EntityTypes.PAINTING, getHandle().getMinecraftWorld());
entity.setLocation(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, new BlockPosition(x, y, z), dir);
} else {
entity = new EntityItemFrame(world, new BlockPosition(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.a(world);
entity.teleportAndSync(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.a(world);
entity.setPosition(x, y, z);
}
if (entity != null) {
return entity;
}
throw new IllegalArgumentException("Cannot spawn an entity for " + clazz.getName());
}
}