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); } }