package org.bukkit.craftbukkit.entity; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import net.minecraft.server.DamageSource; import net.minecraft.server.EntityArrow; import net.minecraft.server.EntityEgg; import net.minecraft.server.EntityEnderDragon; import net.minecraft.server.EntityEnderPearl; import net.minecraft.server.EntityLargeFireball; import net.minecraft.server.EntityLiving; import net.minecraft.server.EntitySmallFireball; import net.minecraft.server.EntitySnowball; import net.minecraft.server.EntityPlayer; import net.minecraft.server.EntityWitherSkull; import net.minecraft.server.MobEffect; import net.minecraft.server.MobEffectList; import net.minecraft.server.Packet42RemoveMobEffect; import org.apache.commons.lang.Validate; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.CraftWorld; import org.bukkit.craftbukkit.inventory.CraftEntityEquipment; import org.bukkit.entity.Arrow; import org.bukkit.entity.Egg; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.HumanEntity; import org.bukkit.entity.EnderPearl; import org.bukkit.entity.Fireball; 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.WitherSkull; import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.inventory.EntityEquipment; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.util.BlockIterator; import org.bukkit.util.Vector; public class CraftLivingEntity extends CraftEntity implements LivingEntity { private CraftEntityEquipment equipment; public CraftLivingEntity(final CraftServer server, final EntityLiving entity) { super(server, entity); if (!(this instanceof HumanEntity)) { equipment = new CraftEntityEquipment(this); } } public int getHealth() { return Math.min(Math.max(0, getHandle().getHealth()), getMaxHealth()); } public void setHealth(int health) { if ((health < 0) || (health > getMaxHealth())) { throw new IllegalArgumentException("Health must be between 0 and " + getMaxHealth()); } if (entity instanceof EntityPlayer && health == 0) { ((EntityPlayer) entity).die(DamageSource.GENERIC); } getHandle().setHealth(health); } public int getMaxHealth() { return getHandle().maxHealth; } public void setMaxHealth(int amount) { Validate.isTrue(amount > 0, "Max health must be greater than 0"); getHandle().maxHealth = 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().getHeadHeight(); } public double getEyeHeight(boolean ignoreSneaking) { return getEyeHeight(); } private List getLineOfSight(HashSet transparent, int maxDistance, int maxLength) { if (maxDistance > 120) { maxDistance = 120; } ArrayList blocks = new ArrayList(); Iterator 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 getLineOfSight(HashSet transparent, int maxDistance) { return getLineOfSight(transparent, maxDistance, 0); } public Block getTargetBlock(HashSet transparent, int maxDistance) { List blocks = getLineOfSight(transparent, maxDistance, 1); return blocks.get(0); } public List getLastTwoTargetBlocks(HashSet transparent, int maxDistance) { return getLineOfSight(transparent, maxDistance, 2); } @Deprecated public Arrow shootArrow() { return launchProjectile(Arrow.class); } public int getRemainingAir() { return getHandle().getAirTicks(); } public void setRemainingAir(int ticks) { getHandle().setAirTicks(ticks); } public int getMaximumAir() { return getHandle().maxAirTicks; } public void setMaximumAir(int ticks) { getHandle().maxAirTicks = ticks; } public void damage(int amount) { damage(amount, null); } public void damage(int amount, org.bukkit.entity.Entity source) { DamageSource reason = DamageSource.GENERIC; if (source instanceof HumanEntity) { reason = DamageSource.playerAttack(((CraftHumanEntity) source).getHandle()); } else if (source instanceof LivingEntity) { reason = DamageSource.mobAttack(((CraftLivingEntity) source).getHandle()); } if (entity instanceof EntityEnderDragon) { ((EntityEnderDragon) entity).dealDamage(reason, amount); } else { entity.damageEntity(reason, amount); } } public Location getEyeLocation() { Location loc = getLocation(); loc.setY(loc.getY() + getEyeHeight()); return loc; } public int getMaximumNoDamageTicks() { return getHandle().maxNoDamageTicks; } public void setMaximumNoDamageTicks(int ticks) { getHandle().maxNoDamageTicks = ticks; } public int getLastDamage() { return getHandle().lastDamage; } public void setLastDamage(int damage) { getHandle().lastDamage = damage; } public int getNoDamageTicks() { return getHandle().noDamageTicks; } public void setNoDamageTicks(int ticks) { getHandle().noDamageTicks = ticks; } @Override public EntityLiving getHandle() { return (EntityLiving) entity; } public void setHandle(final EntityLiving entity) { super.setHandle(entity); } @Override public String toString() { return "CraftLivingEntity{" + "id=" + getEntityId() + '}'; } public Player getKiller() { return getHandle().killer == null ? null : (Player) getHandle().killer.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().addEffect(new MobEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier())); return true; } public boolean addPotionEffects(Collection effects) { boolean success = true; for (PotionEffect effect : effects) { success &= addPotionEffect(effect); } return success; } public boolean hasPotionEffect(PotionEffectType type) { return getHandle().hasEffect(MobEffectList.byId[type.getId()]); } public void removePotionEffect(PotionEffectType type) { getHandle().effects.remove(type.getId()); getHandle().updateEffects = true; if (getHandle() instanceof EntityPlayer) { if (((EntityPlayer) getHandle()).playerConnection == null) return; ((EntityPlayer) getHandle()).playerConnection.sendPacket(new Packet42RemoveMobEffect(getHandle().id, new MobEffect(type.getId(), 0, 0))); } } public Collection getActivePotionEffects() { List effects = new ArrayList(); for (Object raw : getHandle().effects.values()) { if (!(raw instanceof MobEffect)) continue; MobEffect handle = (MobEffect) raw; effects.add(new PotionEffect(PotionEffectType.getById(handle.getEffectId()), handle.getDuration(), handle.getAmplifier())); } return effects; } @SuppressWarnings("unchecked") public T launchProjectile(Class projectile) { net.minecraft.server.World world = ((CraftWorld) getWorld()).getHandle(); net.minecraft.server.Entity launch = null; if (Snowball.class.isAssignableFrom(projectile)) { launch = new EntitySnowball(world, getHandle()); } else if (Egg.class.isAssignableFrom(projectile)) { launch = new EntityEgg(world, getHandle()); } else if (EnderPearl.class.isAssignableFrom(projectile)) { launch = new EntityEnderPearl(world, getHandle()); } else if (Arrow.class.isAssignableFrom(projectile)) { launch = new EntityArrow(world, getHandle(), 1); } else if (Fireball.class.isAssignableFrom(projectile)) { Location location = getEyeLocation(); Vector direction = location.getDirection().multiply(10); if (SmallFireball.class.isAssignableFrom(projectile)) { launch = new EntitySmallFireball(world, getHandle(), direction.getX(), direction.getY(), direction.getZ()); } else if (WitherSkull.class.isAssignableFrom(projectile)) { launch = new EntityWitherSkull(world, getHandle(), direction.getX(), direction.getY(), direction.getZ()); } else { launch = new EntityLargeFireball(world, getHandle(), direction.getX(), direction.getY(), direction.getZ()); } launch.setPositionRotation(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch()); } Validate.notNull(launch, "Projectile not supported"); world.addEntity(launch); return (T) launch.getBukkitEntity(); } public EntityType getType() { return EntityType.UNKNOWN; } public boolean hasLineOfSight(Entity other) { return getHandle().aA().canSee(((CraftEntity) other).getHandle()); // az should be getEntitySenses } public boolean getRemoveWhenFarAway() { return !getHandle().persistent; } public void setRemoveWhenFarAway(boolean remove) { getHandle().persistent = !remove; } public EntityEquipment getEquipment() { return equipment; } public void setCanPickupItems(boolean pickup) { getHandle().canPickUpLoot = pickup; } public boolean getCanPickupItems() { return getHandle().canPickUpLoot; } @Override public boolean teleport(Location location, PlayerTeleportEvent.TeleportCause cause) { if (getHealth() == 0) { return false; } return super.teleport(location, cause); } }