Newer
Older
ultramine_bukkit / src / main / java / org / bukkit / craftbukkit / entity / CraftLivingEntity.java
@vlad20012 vlad20012 on 24 Feb 2017 15 KB initial
package org.bukkit.craftbukkit.entity;

import cpw.mods.fml.common.registry.EntityRegistry;
import net.minecraft.entity.player.EntityPlayer;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.CraftServer;
import org.bukkit.craftbukkit.CraftWorld;
import org.bukkit.craftbukkit.inventory.CraftEntityEquipment;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.entity.Arrow;
import org.bukkit.entity.Egg;
import org.bukkit.entity.EnderPearl;
import org.bukkit.entity.Entity;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Fish;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile;
import org.bukkit.entity.SmallFireball;
import org.bukkit.entity.Snowball;
import org.bukkit.entity.ThrownExpBottle;
import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.WitherSkull;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.inventory.EntityEquipment;
import org.bukkit.inventory.ItemStack;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.bukkit.util.BlockIterator;
import org.bukkit.util.NumberConversions;
import org.bukkit.util.Vector;
import org.ultramine.mods.bukkit.interfaces.IMixinEntityRegistry;
import org.ultramine.mods.bukkit.interfaces.entity.IMixinEntity;
import org.ultramine.mods.bukkit.interfaces.entity.IMixinEntityLiving;
import org.ultramine.mods.bukkit.interfaces.entity.IMixinEntityLivingBase;
import org.ultramine.mods.bukkit.interfaces.entity.boss.IMixinEntityDragon;

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;

public class CraftLivingEntity extends CraftEntity implements LivingEntity
{
	private CraftEntityEquipment equipment;
	// Cauldron start
	public Class<? extends net.minecraft.entity.EntityLivingBase> entityClass;
	public String entityName;
	// Cauldron end

	public CraftLivingEntity(final CraftServer server, final net.minecraft.entity.EntityLivingBase entity)
	{
		super(server, entity);
		// Cauldron start
		this.entityClass = entity.getClass();
		this.entityName = ((IMixinEntityRegistry) EntityRegistry.instance()).getCustomEntityTypeName(entityClass);
		if(entityName == null)
			entityName = entity.getCommandSenderName();
		// Cauldron end

		if(entity instanceof net.minecraft.entity.EntityLiving)
		{
			equipment = new CraftEntityEquipment(this);
		}
	}

	public double getHealth()
	{
		return Math.min(Math.max(0, getHandle().getHealth()), getMaxHealth());
	}

	public void setHealth(double health)
	{
		if((health < 0) || (health > getMaxHealth()))
		{
			throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth());
		}

		// Cauldron start - setHealth must be set before onDeath to respect events that may prevent death.
		getHandle().setHealth((float) health);

		if(entity instanceof net.minecraft.entity.player.EntityPlayerMP && health == 0)
		{
			((net.minecraft.entity.player.EntityPlayerMP) entity).onDeath(net.minecraft.util.DamageSource.generic);
		}
		// Cauldron end
	}

	public double getMaxHealth()
	{
		return getHandle().getMaxHealth();
	}

	public void setMaxHealth(double amount)
	{
		Validate.isTrue(amount > 0, "Max health must be greater than 0");

		getHandle().getEntityAttribute(net.minecraft.entity.SharedMonsterAttributes.maxHealth).setBaseValue(amount);

		if(getHealth() > amount)
		{
			setHealth(amount);
		}
	}

	public void resetMaxHealth()
	{
		setMaxHealth(getHandle().getMaxHealth());
	}

	@Deprecated
	public Egg throwEgg()
	{
		return launchProjectile(Egg.class);
	}

	@Deprecated
	public Snowball throwSnowball()
	{
		return launchProjectile(Snowball.class);
	}

	public double getEyeHeight()
	{
		return getHandle().getEyeHeight();
	}

	public double getEyeHeight(boolean ignoreSneaking)
	{
		return getEyeHeight();
	}

	private List<Block> getLineOfSight(HashSet<Byte> transparent, int maxDistance, int maxLength)
	{
		if(maxDistance > 120)
		{
			maxDistance = 120;
		}
		ArrayList<Block> blocks = new ArrayList<Block>();
		Iterator<Block> itr = new BlockIterator(this, maxDistance);
		while(itr.hasNext())
		{
			Block block = itr.next();
			blocks.add(block);
			if(maxLength != 0 && blocks.size() > maxLength)
			{
				blocks.remove(0);
			}
			int id = block.getTypeId();
			if(transparent == null)
			{
				if(id != 0)
				{
					break;
				}
			}
			else
			{
				if(!transparent.contains((byte) id))
				{
					break;
				}
			}
		}
		return blocks;
	}

	public List<Block> getLineOfSight(HashSet<Byte> transparent, int maxDistance)
	{
		return getLineOfSight(transparent, maxDistance, 0);
	}

	public Block getTargetBlock(HashSet<Byte> transparent, int maxDistance)
	{
		List<Block> blocks = getLineOfSight(transparent, maxDistance, 1);
		return blocks.get(0);
	}

	public List<Block> getLastTwoTargetBlocks(HashSet<Byte> transparent, int maxDistance)
	{
		return getLineOfSight(transparent, maxDistance, 2);
	}

	@Deprecated
	public Arrow shootArrow()
	{
		return launchProjectile(Arrow.class);
	}

	public int getRemainingAir()
	{
		return getHandle().getAir();
	}

	public void setRemainingAir(int ticks)
	{
		getHandle().setAir(ticks);
	}

	public int getMaximumAir()
	{
		return ((IMixinEntityLivingBase) getHandle()).getMaxAirTicks();
	}

	public void setMaximumAir(int ticks)
	{
		((IMixinEntityLivingBase) getHandle()).setMaxAirTicks(ticks);
	}

	public void damage(double amount)
	{
		damage(amount, null);
	}

	public void damage(double amount, org.bukkit.entity.Entity source)
	{
		net.minecraft.util.DamageSource reason = net.minecraft.util.DamageSource.generic;

		if(source instanceof HumanEntity)
		{
			reason = net.minecraft.util.DamageSource.causePlayerDamage(((CraftHumanEntity) source).getHandle());
		}
		else if(source instanceof LivingEntity)
		{
			reason = net.minecraft.util.DamageSource.causeMobDamage(((CraftLivingEntity) source).getHandle());
		}

		if(entity instanceof net.minecraft.entity.boss.EntityDragon)
		{
			((IMixinEntityDragon) entity).realAttackEntityFrom(reason, (float) amount);
		}
		else
		{
			entity.attackEntityFrom(reason, (float) amount);
		}
	}

	public Location getEyeLocation()
	{
		Location loc = getLocation();
		loc.setY(loc.getY() + getEyeHeight());
		return loc;
	}

	public int getMaximumNoDamageTicks()
	{
		return getHandle().maxHurtResistantTime;
	}

	public void setMaximumNoDamageTicks(int ticks)
	{
		getHandle().maxHurtResistantTime = ticks;
	}

	public double getLastDamage()
	{
		return ((IMixinEntityLivingBase) getHandle()).getLastDamage();
	}

	public void setLastDamage(double damage)
	{
		((IMixinEntityLivingBase) getHandle()).setLastDamage((float) damage);
	}

	public int getNoDamageTicks()
	{
		return getHandle().hurtResistantTime;
	}

	public void setNoDamageTicks(int ticks)
	{
		getHandle().hurtResistantTime = ticks;
	}

	@Override
	public net.minecraft.entity.EntityLivingBase getHandle()
	{
		return (net.minecraft.entity.EntityLivingBase) entity;
	}

	public void setHandle(final net.minecraft.entity.EntityLivingBase entity)
	{
		super.setHandle(entity);
	}

	@Override
	public String toString()
	{
		return this.entityName; // Cauldron
	}

	public Player getKiller()
	{
		EntityPlayer attackingPlayer = ((IMixinEntityLivingBase) getHandle()).getAttackingPlayer();
		return attackingPlayer == null ? null : (Player) ((IMixinEntity) attackingPlayer).getBukkitEntity();
	}

	public boolean addPotionEffect(PotionEffect effect)
	{
		return addPotionEffect(effect, false);
	}

	public boolean addPotionEffect(PotionEffect effect, boolean force)
	{
		if(hasPotionEffect(effect.getType()))
		{
			if(!force)
			{
				return false;
			}
			removePotionEffect(effect.getType());
		}
		getHandle().addPotionEffect(new net.minecraft.potion.PotionEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier(), effect.isAmbient()));
		return true;
	}

	public boolean addPotionEffects(Collection<PotionEffect> effects)
	{
		boolean success = true;
		for(PotionEffect effect : effects)
		{
			success &= addPotionEffect(effect);
		}
		return success;
	}

	public boolean hasPotionEffect(PotionEffectType type)
	{
		return getHandle().isPotionActive(net.minecraft.potion.Potion.potionTypes[type.getId()]);
	}

	public void removePotionEffect(PotionEffectType type)
	{
		getHandle().removePotionEffect(type.getId()); // Should be removeEffect.
	}

	public Collection<PotionEffect> getActivePotionEffects()
	{
		List<PotionEffect> effects = new ArrayList<PotionEffect>();
		for(net.minecraft.potion.PotionEffect handle : ((IMixinEntityLivingBase) getHandle()).getActivePotionsMap().values())
		{
			if(PotionEffectType.getById(handle.getPotionID()) == null) continue; // Cauldron - ignore null types
			effects.add(new PotionEffect(PotionEffectType.getById(handle.getPotionID()), handle.getDuration(), handle.getAmplifier(), handle.getIsAmbient()));
		}
		return effects;
	}

	public <T extends Projectile> T launchProjectile(Class<? extends T> projectile)
	{
		return launchProjectile(projectile, null);
	}

	@SuppressWarnings("unchecked")
	public <T extends Projectile> T launchProjectile(Class<? extends T> projectile, Vector velocity)
	{
		net.minecraft.world.World world = ((CraftWorld) getWorld()).getHandle();
		net.minecraft.entity.Entity launch = null;

		if(Snowball.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.projectile.EntitySnowball(world, getHandle());
		}
		else if(Egg.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.projectile.EntityEgg(world, getHandle());
		}
		else if(EnderPearl.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.item.EntityEnderPearl(world, getHandle());
		}
		else if(Arrow.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.projectile.EntityArrow(world, getHandle(), 1);
		}
		else if(ThrownPotion.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.projectile.EntityPotion(world, getHandle(), CraftItemStack.asNMSCopy(new ItemStack(Material.POTION, 1)));
		}
		else if(ThrownExpBottle.class.isAssignableFrom(projectile))
		{
			launch = new net.minecraft.entity.item.EntityExpBottle(world, getHandle());
		}
		else if(Fish.class.isAssignableFrom(projectile) && getHandle() instanceof net.minecraft.entity.player.EntityPlayer)
		{
			launch = new net.minecraft.entity.projectile.EntityFishHook(world, (net.minecraft.entity.player.EntityPlayer) getHandle());
		}
		else if(Fireball.class.isAssignableFrom(projectile))
		{
			Location location = getEyeLocation();
			Vector direction = location.getDirection().multiply(10);

			if(SmallFireball.class.isAssignableFrom(projectile))
			{
				launch = new net.minecraft.entity.projectile.EntitySmallFireball(world, getHandle(), direction.getX(), direction.getY(), direction.getZ());
			}
			else if(WitherSkull.class.isAssignableFrom(projectile))
			{
				launch = new net.minecraft.entity.projectile.EntityWitherSkull(world, getHandle(), direction.getX(), direction.getY(), direction.getZ());
			}
			else
			{
				launch = new net.minecraft.entity.projectile.EntityLargeFireball(world, getHandle(), direction.getX(), direction.getY(), direction.getZ());
			}

			((IMixinEntity) launch).setProjectileSource(this);
			launch.setLocationAndAngles(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
		}

		Validate.notNull(launch, "Projectile not supported");

		if(velocity != null)
		{
			((T) ((IMixinEntity) launch).getBukkitEntity()).setVelocity(velocity);
		}

		world.spawnEntityInWorld(launch);
		return (T) ((IMixinEntity) launch).getBukkitEntity();
	}

	public EntityType getType()
	{
		// Cauldron start
		EntityType type = EntityType.fromName(this.entityName);
		if(type != null)
			return type;
		else return EntityType.UNKNOWN;
		// Cauldron end
	}

	public boolean hasLineOfSight(Entity other)
	{
		return getHandle().canEntityBeSeen(((CraftEntity) other).getHandle());
	}

	public boolean getRemoveWhenFarAway()
	{
		return getHandle() instanceof net.minecraft.entity.EntityLiving && !((IMixinEntityLiving) getHandle()).isPersistenceRequired();
	}

	public void setRemoveWhenFarAway(boolean remove)
	{
		if(getHandle() instanceof net.minecraft.entity.EntityLiving)
		{
			((IMixinEntityLiving) getHandle()).setPersistenceRequired(!remove);
		}
	}

	public EntityEquipment getEquipment()
	{
		return equipment;
	}

	public void setCanPickupItems(boolean pickup)
	{
		if(getHandle() instanceof net.minecraft.entity.EntityLiving)
		{
			((IMixinEntityLiving) getHandle()).setCanPickUpLoot(pickup);
		}
	}

	public boolean getCanPickupItems()
	{
		return getHandle() instanceof net.minecraft.entity.EntityLiving && ((IMixinEntityLiving) getHandle()).isCanPickUpLoot();
	}

	@Override
	public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause)
	{
		if(getHealth() == 0)
		{
			return false;
		}

		return super.teleport(location, cause);
	}

	public void setCustomName(String name)
	{
		if(!(getHandle() instanceof net.minecraft.entity.EntityLiving))
		{
			return;
		}

		if(name == null)
		{
			name = "";
		}

		// Names cannot be more than 64 characters due to DataWatcher limitations
		if(name.length() > 64)
		{
			name = name.substring(0, 64);
		}

		((net.minecraft.entity.EntityLiving) getHandle()).setCustomNameTag(name);
	}

	public String getCustomName()
	{
		if(!(getHandle() instanceof net.minecraft.entity.EntityLiving))
		{
			return null;
		}

		String name = ((net.minecraft.entity.EntityLiving) getHandle()).getCustomNameTag();

		if(name == null || name.length() == 0)
		{
			return null;
		}

		return name;
	}

	public void setCustomNameVisible(boolean flag)
	{
		if(getHandle() instanceof net.minecraft.entity.EntityLiving)
		{
			((net.minecraft.entity.EntityLiving) getHandle()).setAlwaysRenderNameTag(flag);
		}
	}

	public boolean isCustomNameVisible()
	{
		return getHandle() instanceof net.minecraft.entity.EntityLiving && ((net.minecraft.entity.EntityLiving) getHandle()).getAlwaysRenderNameTag();
	}

	public boolean isLeashed()
	{
		if(!(getHandle() instanceof net.minecraft.entity.EntityLiving))
		{
			return false;
		}
		return ((net.minecraft.entity.EntityLiving) getHandle()).getLeashedToEntity() != null;
	}

	public Entity getLeashHolder() throws IllegalStateException
	{
		if(!isLeashed())
		{
			throw new IllegalStateException("Entity not leashed");
		}
		return ((IMixinEntity) ((net.minecraft.entity.EntityLiving) getHandle()).getLeashedToEntity()).getBukkitEntity();
	}

	private boolean unleash()
	{
		if(!isLeashed())
		{
			return false;
		}
		((net.minecraft.entity.EntityLiving) getHandle()).clearLeashed(true, false);
		return true;
	}

	public boolean setLeashHolder(Entity holder)
	{
		if((getHandle() instanceof net.minecraft.entity.boss.EntityWither) || !(getHandle() instanceof net.minecraft.entity.EntityLiving))
		{
			return false;
		}

		if(holder == null)
		{
			return unleash();
		}

		if(holder.isDead())
		{
			return false;
		}

		unleash();
		((net.minecraft.entity.EntityLiving) getHandle()).setLeashedToEntity(((CraftEntity) holder).getHandle(), true);
		return true;
	}

	@Deprecated
	public int _INVALID_getLastDamage()
	{
		return NumberConversions.ceil(getLastDamage());
	}

	@Deprecated
	public void _INVALID_setLastDamage(int damage)
	{
		setLastDamage(damage);
	}

	@Deprecated
	public void _INVALID_damage(int amount)
	{
		damage(amount);
	}

	@Deprecated
	public void _INVALID_damage(int amount, Entity source)
	{
		damage(amount, source);
	}

	@Deprecated
	public int _INVALID_getHealth()
	{
		return NumberConversions.ceil(getHealth());
	}

	@Deprecated
	public void _INVALID_setHealth(int health)
	{
		setHealth(health);
	}

	@Deprecated
	public int _INVALID_getMaxHealth()
	{
		return NumberConversions.ceil(getMaxHealth());
	}

	@Deprecated
	public void _INVALID_setMaxHealth(int health)
	{
		setMaxHealth(health);
	}
}