diff options
Diffstat (limited to 'src/main')
13 files changed, 544 insertions, 80 deletions
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 9e0b5afa..2c82ecbb 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -36,6 +36,7 @@ import org.bukkit.craftbukkit.block.CraftBlockState; import org.bukkit.craftbukkit.entity.*; import org.bukkit.craftbukkit.inventory.CraftItemStack; import org.bukkit.craftbukkit.metadata.BlockMetadataStore; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.craftbukkit.util.CraftMagicNumbers; import org.bukkit.craftbukkit.util.LongHash; import org.bukkit.entity.*; @@ -53,6 +54,8 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.metadata.MetadataValue; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.messaging.StandardMessenger; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionType; import org.bukkit.util.Vector; public class CraftWorld implements World { @@ -360,14 +363,28 @@ public class CraftWorld implements World { } public Arrow spawnArrow(Location loc, Vector velocity, float speed, float spread) { + return spawnArrow(loc, velocity, speed, spread, Arrow.class); + } + + public <T extends Arrow> T spawnArrow(Location loc, Vector velocity, float speed, float spread, Class<T> clazz) { Validate.notNull(loc, "Can not spawn arrow with a null location"); Validate.notNull(velocity, "Can not spawn arrow with a null velocity"); + Validate.notNull(clazz, "Can not spawn an arrow with no class"); + + EntityArrow arrow; + if (TippedArrow.class.isAssignableFrom(clazz)) { + arrow = new EntityTippedArrow(world); + ((EntityTippedArrow) arrow).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false))); + } else if (SpectralArrow.class.isAssignableFrom(clazz)) { + arrow = new EntitySpectralArrow(world); + } else { + arrow = new EntityTippedArrow(world); + } - EntityArrow arrow = new EntityTippedArrow(world); arrow.setPositionRotation(loc.getX(), loc.getY(), loc.getZ(), loc.getYaw(), loc.getPitch()); arrow.shoot(velocity.getX(), velocity.getY(), velocity.getZ(), speed, spread); world.addEntity(arrow); - return (Arrow) arrow.getBukkitEntity(); + return (T) arrow.getBukkitEntity(); } public Entity spawnEntity(Location loc, EntityType entityType) { @@ -922,7 +939,14 @@ public class CraftWorld implements World { } else if (Egg.class.isAssignableFrom(clazz)) { entity = new EntityEgg(world, x, y, z); } else if (Arrow.class.isAssignableFrom(clazz)) { - entity = new EntityTippedArrow(world); + if (TippedArrow.class.isAssignableFrom(clazz)) { + entity = new EntityTippedArrow(world); + ((EntityTippedArrow) entity).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false))); + } else if (SpectralArrow.class.isAssignableFrom(clazz)) { + entity = new EntitySpectralArrow(world); + } else { + entity = new EntityTippedArrow(world); + } entity.setPositionRotation(x, y, z, 0, 0); } else if (ThrownExpBottle.class.isAssignableFrom(clazz)) { entity = new EntityThrownExpBottle(world); @@ -931,15 +955,19 @@ public class CraftWorld implements World { entity = new EntityEnderPearl(world, null); entity.setPositionRotation(x, y, z, 0, 0); } else if (ThrownPotion.class.isAssignableFrom(clazz)) { - entity = new EntityPotion(world, x, y, z, CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.POTION, 1))); + if (LingeringPotion.class.isAssignableFrom(clazz)) { + entity = new EntityPotion(world, x, y, z, CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1))); + } else { + entity = new EntityPotion(world, x, y, z, CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1))); + } } else if (Fireball.class.isAssignableFrom(clazz)) { if (SmallFireball.class.isAssignableFrom(clazz)) { entity = new EntitySmallFireball(world); } else if (WitherSkull.class.isAssignableFrom(clazz)) { entity = new EntityWitherSkull(world); - } else if (DragonFireball.class.isAssignableFrom(clazz)){ + } else if (DragonFireball.class.isAssignableFrom(clazz)) { entity = new EntityDragonFireball(world); - }else{ + } else { entity = new EntityLargeFireball(world); } entity.setPositionRotation(x, y, z, yaw, pitch); @@ -1049,7 +1077,7 @@ public class CraftWorld implements World { entity = new EntityRabbit(world); } else if (Endermite.class.isAssignableFrom(clazz)) { entity = new EntityEndermite(world); - } else if (Guardian.class.isAssignableFrom(clazz)){ + } else if (Guardian.class.isAssignableFrom(clazz)) { entity = new EntityGuardian(world); } else if (ArmorStand.class.isAssignableFrom(clazz)) { entity = new EntityArmorStand(world, x, y, z); @@ -1073,13 +1101,13 @@ public class CraftWorld implements World { height = 9; } - BlockFace[] faces = new BlockFace[]{BlockFace.EAST,BlockFace.NORTH,BlockFace.WEST,BlockFace.SOUTH}; + BlockFace[] faces = new BlockFace[]{BlockFace.EAST, BlockFace.NORTH, BlockFace.WEST, BlockFace.SOUTH}; final BlockPosition pos = new BlockPosition((int) x, (int) y, (int) z); for (BlockFace dir : faces) { net.minecraft.server.Block nmsBlock = CraftMagicNumbers.getBlock(block.getRelative(dir)); if (nmsBlock.getBlockData().getMaterial().isBuildable() || BlockDiodeAbstract.isDiode(nmsBlock.getBlockData())) { boolean taken = false; - AxisAlignedBB bb = EntityHanging.calculateBoundingBox(null, pos,CraftBlock.blockFaceToNotch(dir).opposite(),width,height); + AxisAlignedBB bb = EntityHanging.calculateBoundingBox(null, pos, CraftBlock.blockFaceToNotch(dir).opposite(), width, height); List<net.minecraft.server.Entity> list = (List<net.minecraft.server.Entity>) world.getEntities(null, bb); for (Iterator<net.minecraft.server.Entity> it = list.iterator(); !taken && it.hasNext();) { net.minecraft.server.Entity e = it.next(); @@ -1096,7 +1124,6 @@ public class CraftWorld implements World { } EnumDirection dir = CraftBlock.blockFaceToNotch(face).opposite(); - if (Painting.class.isAssignableFrom(clazz)) { entity = new EntityPainting(world, new BlockPosition((int) x, (int) y, (int) z), dir); } else if (ItemFrame.class.isAssignableFrom(clazz)) { diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java index f32b9e2f..e8b8787b 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftAreaEffectCloud.java @@ -2,13 +2,22 @@ package org.bukkit.craftbukkit.entity; import java.util.List; import net.minecraft.server.EntityAreaEffectCloud; +import net.minecraft.server.MobEffect; +import net.minecraft.server.MobEffectList; + +import org.apache.commons.lang.Validate; import org.bukkit.Color; import org.bukkit.Particle; import org.bukkit.craftbukkit.CraftParticle; import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.entity.AreaEffectCloud; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionData; + +import com.google.common.collect.ImmutableList; public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud { @@ -107,32 +116,90 @@ public class CraftAreaEffectCloud extends CraftEntity implements AreaEffectCloud } @Override - public List<PotionEffect> getEffects() { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public Color getColor() { + return Color.fromRGB(getHandle().getColor()); } @Override - public void addEffect(PotionEffect effect) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public void setColor(Color color) { + getHandle().setColor(color.asRGB()); } @Override - public void removeEffect(PotionEffect effect) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public boolean addCustomEffect(PotionEffect effect, boolean override) { + int effectId = effect.getType().getId(); + MobEffect existing = null; + for (MobEffect mobEffect : getHandle().effects) { + if (MobEffectList.getId(mobEffect.getMobEffect()) == effectId) { + existing = mobEffect; + } + } + if (existing != null) { + if (!override) { + return false; + } + getHandle().effects.remove(existing); + } + getHandle().a(CraftPotionUtil.fromBukkit(effect)); + getHandle().refreshEffects(); + return true; } @Override - public void setEffects(List<PotionEffect> effects) { - throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + public void clearCustomEffects() { + getHandle().effects.clear(); + getHandle().refreshEffects(); } @Override - public Color getColor() { - return Color.fromRGB(getHandle().getColor()); + public List<PotionEffect> getCustomEffects() { + ImmutableList.Builder<PotionEffect> builder = ImmutableList.builder(); + for (MobEffect effect : getHandle().effects) { + builder.add(CraftPotionUtil.toBukkit(effect)); + } + return builder.build(); } @Override - public void setColor(Color color) { - getHandle().setColor(color.asRGB()); + public boolean hasCustomEffect(PotionEffectType type) { + for (MobEffect effect : getHandle().effects) { + if (CraftPotionUtil.equals(effect.getMobEffect(), type)) { + return true; + } + } + return false; + } + + @Override + public boolean hasCustomEffects() { + return !getHandle().effects.isEmpty(); + } + + @Override + public boolean removeCustomEffect(PotionEffectType effect) { + int effectId = effect.getId(); + MobEffect existing = null; + for (MobEffect mobEffect : getHandle().effects) { + if (MobEffectList.getId(mobEffect.getMobEffect()) == effectId) { + existing = mobEffect; + } + } + if (existing == null) { + return false; + } + getHandle().effects.remove(existing); + getHandle().refreshEffects(); + return true; + } + + @Override + public void setBasePotionData(PotionData data) { + Validate.notNull(data, "PotionData cannot be null"); + getHandle().setType(CraftPotionUtil.fromBukkit(data)); + } + + @Override + public PotionData getBasePotionData() { + return CraftPotionUtil.toBukkit(getHandle().getType()); } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java index 22d08a20..7f10a0f7 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftEntity.java @@ -138,12 +138,19 @@ public abstract class CraftEntity implements org.bukkit.entity.Entity { else { return new CraftComplexPart(server, (EntityComplexPart) entity); } } else if (entity instanceof EntityExperienceOrb) { return new CraftExperienceOrb(server, (EntityExperienceOrb) entity); } + else if (entity instanceof EntityTippedArrow) { + if (((EntityTippedArrow) entity).isTipped()) { return new CraftTippedArrow(server, (EntityTippedArrow) entity); } + else { return new CraftArrow(server, (EntityArrow) entity); } + } else if (entity instanceof EntityArrow) { return new CraftArrow(server, (EntityArrow) entity); } else if (entity instanceof EntityBoat) { 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 EntityPotion) { + if (!((EntityPotion) entity).n()) { return new CraftSplashPotion(server, (EntityPotion) entity); } + else { return new CraftLingeringPotion(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); } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLingeringPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLingeringPotion.java new file mode 100644 index 00000000..52cd654a --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLingeringPotion.java @@ -0,0 +1,41 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityPotion; +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; + +public class CraftLingeringPotion extends CraftThrownPotion { + + public CraftLingeringPotion(CraftServer server, EntityPotion entity) { + super(server, entity); + } + + public void setItem(ItemStack item) { + // The ItemStack must not be null. + Validate.notNull(item, "ItemStack cannot be null."); + + // The ItemStack must be a potion. + Validate.isTrue(item.getType() == Material.LINGERING_POTION, "ItemStack must be a lingering potion. This item stack was " + item.getType() + "."); + + getHandle().setItem(CraftItemStack.asNMSCopy(item)); + } + + @Override + public EntityPotion getHandle() { + return (EntityPotion) entity; + } + + @Override + public String toString() { + return "CraftLingeringPotion"; + } + + @Override + public EntityType getType() { + return EntityType.LINGERING_POTION; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java index e8aff909..c17b6144 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftLivingEntity.java @@ -26,6 +26,7 @@ import net.minecraft.server.EntitySmallFireball; import net.minecraft.server.EntitySnowball; import net.minecraft.server.EntityThrownExpBottle; import net.minecraft.server.EntityTippedArrow; +import net.minecraft.server.EntitySpectralArrow; import net.minecraft.server.EntityWither; import net.minecraft.server.EntityWitherSkull; import net.minecraft.server.GenericAttributes; @@ -42,6 +43,7 @@ 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.craftbukkit.potion.CraftPotionUtil; import org.bukkit.entity.Arrow; import org.bukkit.entity.DragonFireball; import org.bukkit.entity.Egg; @@ -51,19 +53,24 @@ import org.bukkit.entity.EntityType; import org.bukkit.entity.Fireball; import org.bukkit.entity.Fish; import org.bukkit.entity.HumanEntity; +import org.bukkit.entity.LingeringPotion; 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.SpectralArrow; import org.bukkit.entity.ThrownExpBottle; import org.bukkit.entity.ThrownPotion; +import org.bukkit.entity.TippedArrow; 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.PotionData; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import org.bukkit.util.BlockIterator; import org.bukkit.util.NumberConversions; import org.bukkit.util.Vector; @@ -337,10 +344,21 @@ public class CraftLivingEntity extends CraftEntity implements LivingEntity { launch = new EntityEnderPearl(world, getHandle()); ((EntityProjectile) launch).a(getHandle(), getHandle().pitch, getHandle().yaw, 0.0F, 1.5F, 1.0F); // ItemEnderPearl } else if (Arrow.class.isAssignableFrom(projectile)) { - launch = new EntityTippedArrow(world, getHandle()); + if (TippedArrow.class.isAssignableFrom(projectile)) { + launch = new EntityTippedArrow(world); + ((EntityTippedArrow) launch).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false))); + } else if (SpectralArrow.class.isAssignableFrom(projectile)) { + launch = new EntitySpectralArrow(world); + } else { + launch = new EntityTippedArrow(world); + } ((EntityArrow) launch).a(getHandle(), getHandle().pitch, getHandle().yaw, 0.0F, 3.0F, 1.0F); // ItemBow } else if (ThrownPotion.class.isAssignableFrom(projectile)) { - launch = new EntityPotion(world, getHandle(), CraftItemStack.asNMSCopy(new ItemStack(Material.POTION, 1))); + if (LingeringPotion.class.isAssignableFrom(projectile)) { + launch = new EntityPotion(world, getHandle(), CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1))); + } else { + launch = new EntityPotion(world, getHandle(), CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1))); + } ((EntityProjectile) launch).a(getHandle(), getHandle().pitch, getHandle().yaw, -20.0F, 0.5F, 1.0F); // ItemSplashPotion } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { launch = new EntityThrownExpBottle(world, getHandle()); diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftSplashPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftSplashPotion.java new file mode 100644 index 00000000..863a6c27 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftSplashPotion.java @@ -0,0 +1,42 @@ +package org.bukkit.craftbukkit.entity; + +import net.minecraft.server.EntityPotion; +import org.apache.commons.lang.Validate; +import org.bukkit.Material; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.entity.EntityType; +import org.bukkit.inventory.ItemStack; + +public class CraftSplashPotion extends CraftThrownPotion { + + public CraftSplashPotion(CraftServer server, EntityPotion entity) { + super(server, entity); + } + + @Override + public void setItem(ItemStack item) { + // The ItemStack must not be null. + Validate.notNull(item, "ItemStack cannot be null."); + + // The ItemStack must be a potion. + Validate.isTrue(item.getType() == Material.SPLASH_POTION, "ItemStack must be a splash potion. This item stack was " + item.getType() + "."); + + getHandle().setItem(CraftItemStack.asNMSCopy(item)); + } + + @Override + public EntityPotion getHandle() { + return (EntityPotion) entity; + } + + @Override + public String toString() { + return "CraftSplashPotion"; + } + + @Override + public EntityType getType() { + return EntityType.SPLASH_POTION; + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java index 092e9fba..b1953993 100644 --- a/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftThrownPotion.java @@ -1,55 +1,41 @@ package org.bukkit.craftbukkit.entity; import java.util.Collection; - import net.minecraft.server.EntityPotion; +import net.minecraft.server.MobEffect; +import net.minecraft.server.PotionUtil; import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.craftbukkit.CraftServer; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.entity.EntityType; import org.bukkit.entity.ThrownPotion; import org.bukkit.inventory.ItemStack; -import org.bukkit.potion.Potion; import org.bukkit.potion.PotionEffect; -public class CraftThrownPotion extends CraftProjectile implements ThrownPotion { +import com.google.common.collect.ImmutableList; + +public abstract class CraftThrownPotion extends CraftProjectile implements ThrownPotion { public CraftThrownPotion(CraftServer server, EntityPotion entity) { super(server, entity); } - // TODO: This one does not handle custom NBT potion effects does it? - // In that case this method could be said to be misleading or incorrect public Collection<PotionEffect> getEffects() { - return Potion.getBrewer().getEffectsFromDamage(getHandle().getItem().getData()); + ImmutableList.Builder<PotionEffect> builder = ImmutableList.builder(); + for (MobEffect effect : PotionUtil.getEffects(getHandle().getItem())) { + builder.add(CraftPotionUtil.toBukkit(effect)); + } + return builder.build(); } public ItemStack getItem() { return CraftItemStack.asBukkitCopy(getHandle().getItem()); } - public void setItem(ItemStack item) { - // The ItemStack must not be null. - Validate.notNull(item, "ItemStack cannot be null."); - - // The ItemStack must be a potion. - Validate.isTrue(item.getType() == Material.POTION, "ItemStack must be a potion. This item stack was " + item.getType() + "."); - - getHandle().setItem(CraftItemStack.asNMSCopy(item)); - } - @Override public EntityPotion getHandle() { return (EntityPotion) entity; } - - @Override - public String toString() { - return "CraftThrownPotion"; - } - - public EntityType getType() { - return EntityType.SPLASH_POTION; - } } diff --git a/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java b/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java new file mode 100644 index 00000000..79abae9c --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/entity/CraftTippedArrow.java @@ -0,0 +1,122 @@ +package org.bukkit.craftbukkit.entity; + +import java.util.List; + +import org.apache.commons.lang.Validate; +import org.bukkit.craftbukkit.CraftServer; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.TippedArrow; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; + +import com.google.common.collect.ImmutableList; + +import net.minecraft.server.EntityTippedArrow; +import net.minecraft.server.MobEffect; +import net.minecraft.server.MobEffectList; + +public class CraftTippedArrow extends CraftArrow implements TippedArrow { + + public CraftTippedArrow(CraftServer server, EntityTippedArrow entity) { + super(server, entity); + } + + @Override + public EntityTippedArrow getHandle() { + return (EntityTippedArrow) entity; + } + + @Override + public String toString() { + return "CraftTippedArrow"; + } + + @Override + public EntityType getType() { + return EntityType.TIPPED_ARROW; + } + + @Override + public boolean addCustomEffect(PotionEffect effect, boolean override) { + int effectId = effect.getType().getId(); + MobEffect existing = null; + for (MobEffect mobEffect : getHandle().h) { + if (MobEffectList.getId(mobEffect.getMobEffect()) == effectId) { + existing = mobEffect; + } + } + if (existing != null) { + if (!override) { + return false; + } + getHandle().h.remove(existing); + } + getHandle().a(CraftPotionUtil.fromBukkit(effect)); + getHandle().refreshEffects(); + return true; + } + + @Override + public void clearCustomEffects() { + Validate.isTrue(getBasePotionData().getType() != PotionType.UNCRAFTABLE, "Tipped Arrows must have at least 1 effect"); + getHandle().h.clear(); + getHandle().refreshEffects(); + } + + @Override + public List<PotionEffect> getCustomEffects() { + ImmutableList.Builder<PotionEffect> builder = ImmutableList.builder(); + for (MobEffect effect : getHandle().h) { + builder.add(CraftPotionUtil.toBukkit(effect)); + } + return builder.build(); + } + + @Override + public boolean hasCustomEffect(PotionEffectType type) { + for (MobEffect effect : getHandle().h) { + if (CraftPotionUtil.equals(effect.getMobEffect(), type)) { + return true; + } + } + return false; + } + + @Override + public boolean hasCustomEffects() { + return !getHandle().h.isEmpty(); + } + + @Override + public boolean removeCustomEffect(PotionEffectType effect) { + int effectId = effect.getId(); + MobEffect existing = null; + for (MobEffect mobEffect : getHandle().h) { + if (MobEffectList.getId(mobEffect.getMobEffect()) == effectId) { + existing = mobEffect; + } + } + if (existing == null) { + return false; + } + Validate.isTrue(getBasePotionData().getType() != PotionType.UNCRAFTABLE || getHandle().h.size() != 1, "Tipped Arrows must have at least 1 effect"); + getHandle().h.remove(existing); + getHandle().refreshEffects(); + return true; + } + + @Override + public void setBasePotionData(PotionData data) { + Validate.notNull(data, "PotionData cannot be null"); + Validate.isTrue(data.getType() != PotionType.UNCRAFTABLE || !getHandle().h.isEmpty(), "Tipped Arrows must have at least 1 effect"); + getHandle().setType(CraftPotionUtil.fromBukkit(data)); + } + + @Override + public PotionData getBasePotionData() { + return CraftPotionUtil.toBukkit(getHandle().getType()); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java index 7c3adbbf..294f6c90 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaItem.java @@ -802,6 +802,7 @@ class CraftMetaItem implements ItemMeta, Repairable { HIDEFLAGS.NBT, CraftMetaMap.MAP_SCALING.NBT, CraftMetaPotion.POTION_EFFECTS.NBT, + CraftMetaPotion.DEFAULT_POTION.NBT, CraftMetaSkull.SKULL_OWNER.NBT, CraftMetaSkull.SKULL_PROFILE.NBT, CraftMetaBlockState.BLOCK_ENTITY_TAG.NBT, diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java index f6845307..50612a91 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftMetaPotion.java @@ -12,9 +12,12 @@ import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.configuration.serialization.DelegateDeserialization; import org.bukkit.inventory.meta.PotionMeta; +import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import org.bukkit.craftbukkit.inventory.CraftMetaItem.SerializableMeta; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap.Builder; @@ -27,7 +30,9 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { static final ItemMetaKey SHOW_PARTICLES = new ItemMetaKey("ShowParticles", "has-particles"); static final ItemMetaKey POTION_EFFECTS = new ItemMetaKey("CustomPotionEffects", "custom-effects"); static final ItemMetaKey ID = new ItemMetaKey("Id", "potion-id"); + static final ItemMetaKey DEFAULT_POTION = new ItemMetaKey("Potion", "potion-type"); + private String type; private List<PotionEffect> customEffects; CraftMetaPotion(CraftMetaItem meta) { @@ -36,6 +41,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { return; } CraftMetaPotion potionMeta = (CraftMetaPotion) meta; + this.type = potionMeta.type; if (potionMeta.hasCustomEffects()) { this.customEffects = new ArrayList<PotionEffect>(potionMeta.customEffects); } @@ -43,7 +49,9 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { CraftMetaPotion(NBTTagCompound tag) { super(tag); - + if (tag.hasKey(DEFAULT_POTION.NBT)) { + type = tag.getString(DEFAULT_POTION.NBT); + } if (tag.hasKey(POTION_EFFECTS.NBT)) { NBTTagList list = tag.getList(POTION_EFFECTS.NBT, 10); int length = list.size(); @@ -63,6 +71,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { CraftMetaPotion(Map<String, Object> map) { super(map); + type = SerializableMeta.getString(map, DEFAULT_POTION.BUKKIT, true); Iterable<?> rawEffectList = SerializableMeta.getObject(Iterable.class, map, POTION_EFFECTS.BUKKIT, true); if (rawEffectList == null) { @@ -80,6 +89,9 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { @Override void applyToItem(NBTTagCompound tag) { super.applyToItem(tag); + // NBT expects a PotionType under all circumstances, but ItemMeta API contract expects that a fresh stack have blank meta + // As such we will equate the NMS default type of "Empty"/UNCRAFTABLE to be null + tag.setString(DEFAULT_POTION.NBT, type != null ? type : CraftPotionUtil.fromBukkit(new PotionData(PotionType.UNCRAFTABLE, false, false))); if (customEffects != null) { NBTTagList effectList = new NBTTagList(); tag.set(POTION_EFFECTS.NBT, effectList); @@ -102,7 +114,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { } boolean isPotionEmpty() { - return !(hasCustomEffects()); + return (type == null) && !(hasCustomEffects()); } @Override @@ -121,12 +133,32 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { @Override public CraftMetaPotion clone() { CraftMetaPotion clone = (CraftMetaPotion) super.clone(); + clone.type = type; if (this.customEffects != null) { clone.customEffects = new ArrayList<PotionEffect>(this.customEffects); } return clone; } + @Override + public void setBasePotionData(PotionData data) { + Validate.notNull(data, "PotionData cannot be null"); + PotionType type = data.getType(); + if (type == PotionType.UNCRAFTABLE) { + this.type = null; + return; + } + this.type = CraftPotionUtil.fromBukkit(data); + } + + @Override + public PotionData getBasePotionData() { + if (type == null) { + return new PotionData(PotionType.UNCRAFTABLE, false, false); + } + return CraftPotionUtil.toBukkit(type); + } + public boolean hasCustomEffects() { return customEffects != null; } @@ -225,6 +257,9 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { int applyHash() { final int original; int hash = original = super.applyHash(); + if (type != null) { + hash = 73 * hash + type.hashCode(); + } if (hasCustomEffects()) { hash = 73 * hash + customEffects.hashCode(); } @@ -239,7 +274,7 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { if (meta instanceof CraftMetaPotion) { CraftMetaPotion that = (CraftMetaPotion) meta; - return (this.hasCustomEffects() ? that.hasCustomEffects() && this.customEffects.equals(that.customEffects) : !that.hasCustomEffects()); + return ((type == null && that.type == null) || type.equals(that.type)) && (this.hasCustomEffects() ? that.hasCustomEffects() && this.customEffects.equals(that.customEffects) : !that.hasCustomEffects()); } return true; } @@ -252,6 +287,9 @@ class CraftMetaPotion extends CraftMetaItem implements PotionMeta { @Override Builder<String, Object> serialize(Builder<String, Object> builder) { super.serialize(builder); + if (type != null) { + builder.put(DEFAULT_POTION.BUKKIT, type); + } if (hasCustomEffects()) { builder.put(POTION_EFFECTS.BUKKIT, ImmutableList.copyOf(this.customEffects)); diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java index 5305f9ad..897b7a7a 100644 --- a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java +++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionBrewer.java @@ -5,48 +5,44 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import net.minecraft.server.ItemStack; -import net.minecraft.server.Items; import net.minecraft.server.MobEffect; -import net.minecraft.server.MobEffectList; -import net.minecraft.server.PotionUtil; +import net.minecraft.server.PotionRegistry; -import org.bukkit.Color; import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; import org.bukkit.potion.PotionBrewer; +import org.bukkit.potion.PotionData; import org.bukkit.potion.PotionEffect; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Maps; public class CraftPotionBrewer implements PotionBrewer { - private static final Map<Integer, Collection<PotionEffect>> cache = Maps.newHashMap(); + private static final Map<PotionType, Collection<PotionEffect>> cache = Maps.newHashMap(); - public Collection<PotionEffect> getEffectsFromDamage(int damage) { + public Collection<PotionEffect> getEffects(PotionType damage, boolean upgraded, boolean extended) { if (cache.containsKey(damage)) return cache.get(damage); - List<?> mcEffects = PotionUtil.getEffects(new ItemStack(Items.POTION, 1, damage)); - List<PotionEffect> effects = new ArrayList<PotionEffect>(); - if (mcEffects == null) - return effects; - - for (Object raw : mcEffects) { - if (raw == null || !(raw instanceof MobEffect)) - continue; - MobEffect mcEffect = (MobEffect) raw; - PotionEffect effect = new PotionEffect(PotionEffectType.getById(MobEffectList.getId(mcEffect.getMobEffect())), - mcEffect.getDuration(), mcEffect.getAmplifier(), true, true, Color.fromRGB(mcEffect.getMobEffect().getColor())); - // Minecraft PotionBrewer applies duration modifiers automatically. - effects.add(effect); + List<MobEffect> mcEffects = PotionRegistry.a(CraftPotionUtil.fromBukkit(new PotionData(damage, upgraded, extended))).a(); + + ImmutableList.Builder<PotionEffect> builder = new ImmutableList.Builder<PotionEffect>(); + for (MobEffect effect : mcEffects) { + builder.add(CraftPotionUtil.toBukkit(effect)); } - cache.put(damage, effects); + cache.put(damage, builder.build()); - return effects; + return cache.get(damage); + } + + @Override + public Collection<PotionEffect> getEffectsFromDamage(int damage) { + return new ArrayList<PotionEffect>(); } + @Override public PotionEffect createEffect(PotionEffectType potion, int duration, int amplifier) { - return new PotionEffect(potion, potion.isInstant() ? 1 : (int) (duration * potion.getDurationModifier()), - amplifier); + return new PotionEffect(potion, potion.isInstant() ? 1 : (int) (duration * potion.getDurationModifier()), amplifier); } } diff --git a/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java new file mode 100644 index 00000000..6126c0a9 --- /dev/null +++ b/src/main/java/org/bukkit/craftbukkit/potion/CraftPotionUtil.java @@ -0,0 +1,101 @@ +package org.bukkit.craftbukkit.potion; + +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; + +import net.minecraft.server.MobEffect; +import net.minecraft.server.MobEffectList; + +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.potion.PotionType; +import org.bukkit.potion.PotionData; + +public class CraftPotionUtil { + + private static final BiMap<PotionType, String> regular = ImmutableBiMap.<PotionType, String>builder() + .put(PotionType.UNCRAFTABLE, "minecraft:empty") + .put(PotionType.WATER, "minecraft:water") + .put(PotionType.MUNDANE, "minecraft:mundane") + .put(PotionType.THICK, "minecraft:thick") + .put(PotionType.AWKWARD, "minecraft:awkward") + .put(PotionType.NIGHT_VISION, "minecraft:night_vision") + .put(PotionType.INVISIBILITY, "minecraft:invisibility") + .put(PotionType.JUMP, "minecraft:leaping") + .put(PotionType.FIRE_RESISTANCE, "minecraft:fire_resistance") + .put(PotionType.SPEED, "minecraft:swiftness") + .put(PotionType.SLOWNESS, "minecraft:slowness") + .put(PotionType.WATER_BREATHING, "minecraft:water_breathing") + .put(PotionType.INSTANT_HEAL, "minecraft:healing") + .put(PotionType.INSTANT_DAMAGE, "minecraft:harming") + .put(PotionType.POISON, "minecraft:poison") + .put(PotionType.REGEN, "minecraft:regeneration") + .put(PotionType.STRENGTH, "minecraft:strength") + .put(PotionType.WEAKNESS, "minecraft:weakness") + .put(PotionType.LUCK, "minecraft:luck") + .build(); + private static final BiMap<PotionType, String> upgradeable = ImmutableBiMap.<PotionType, String>builder() + .put(PotionType.JUMP, "minecraft:strong_leaping") + .put(PotionType.SPEED, "minecraft:strong_swiftness") + .put(PotionType.INSTANT_HEAL, "minecraft:strong_healing") + .put(PotionType.INSTANT_DAMAGE, "minecraft:strong_harming") + .put(PotionType.POISON, "minecraft:strong_poison") + .put(PotionType.REGEN, "minecraft:strong_regeneration") + .put(PotionType.STRENGTH, "minecraft:strong_strength") + .build(); + private static final BiMap<PotionType, String> extendable = ImmutableBiMap.<PotionType, String>builder() + .put(PotionType.NIGHT_VISION, "minecraft:long_night_vision") + .put(PotionType.INVISIBILITY, "minecraft:long_invisibility") + .put(PotionType.JUMP, "minecraft:long_leaping") + .put(PotionType.FIRE_RESISTANCE, "minecraft:long_fire_resistance") + .put(PotionType.SPEED, "minecraft:long_swiftness") + .put(PotionType.SLOWNESS, "minecraft:long_slowness") + .put(PotionType.WATER_BREATHING, "minecraft:long_water_breathing") + .put(PotionType.POISON, "minecraft:long_poison") + .put(PotionType.REGEN, "minecraft:long_regeneration") + .put(PotionType.STRENGTH, "minecraft:long_strength") + .put(PotionType.WEAKNESS, "minecraft:long_weakness") + .build(); + + public static String fromBukkit(PotionData data) { + if (data.isUpgraded()) { + return upgradeable.get(data.getType()); + } + if (data.isExtended()) { + return extendable.get(data.getType()); + } + return regular.get(data.getType()); + } + + public static PotionData toBukkit(String type) { + PotionType potionType = null; + potionType = extendable.inverse().get(type); + if (potionType != null) { + return new PotionData(potionType, true, false); + } + potionType = upgradeable.inverse().get(type); + if (potionType != null) { + return new PotionData(potionType, false, true); + } + return new PotionData(regular.inverse().get(type), false, false); + } + + public static MobEffect fromBukkit(PotionEffect effect) { + MobEffectList type = MobEffectList.fromId(effect.getType().getId()); + return new MobEffect(type, effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles()); + } + + public static PotionEffect toBukkit(MobEffect effect) { + PotionEffectType type = PotionEffectType.getById(MobEffectList.getId(effect.getMobEffect())); + int amp = effect.getAmplifier(); + int duration = effect.getDuration(); + boolean ambient = effect.isAmbient(); + boolean particles = effect.isShowParticles(); + return new PotionEffect(type, duration, amp, ambient, particles); + } + + public static boolean equals(MobEffectList mobEffect, PotionEffectType type) { + PotionEffectType typeV = PotionEffectType.getById(MobEffectList.getId(mobEffect)); + return typeV.equals(type); + } +} diff --git a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java index 6c3c1eae..057ae243 100644 --- a/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java +++ b/src/main/java/org/bukkit/craftbukkit/projectiles/CraftBlockProjectileSource.java @@ -6,17 +6,23 @@ import org.apache.commons.lang.Validate; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.potion.CraftPotionUtil; import org.bukkit.entity.Arrow; import org.bukkit.entity.Egg; import org.bukkit.entity.EnderPearl; import org.bukkit.entity.Fireball; +import org.bukkit.entity.LingeringPotion; import org.bukkit.entity.Projectile; import org.bukkit.entity.SmallFireball; import org.bukkit.entity.Snowball; +import org.bukkit.entity.SpectralArrow; import org.bukkit.entity.ThrownExpBottle; import org.bukkit.entity.ThrownPotion; +import org.bukkit.entity.TippedArrow; import org.bukkit.entity.WitherSkull; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionData; +import org.bukkit.potion.PotionType; import org.bukkit.projectiles.BlockProjectileSource; import org.bukkit.util.Vector; @@ -30,6 +36,7 @@ import net.minecraft.server.EntityPotion; import net.minecraft.server.EntityProjectile; import net.minecraft.server.EntitySmallFireball; import net.minecraft.server.EntitySnowball; +import net.minecraft.server.EntitySpectralArrow; import net.minecraft.server.EntityThrownExpBottle; import net.minecraft.server.EntityTippedArrow; import net.minecraft.server.EntityWitherSkull; @@ -78,9 +85,20 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { } else if (ThrownExpBottle.class.isAssignableFrom(projectile)) { launch = new EntityThrownExpBottle(world, iposition.getX(), iposition.getY(), iposition.getZ()); } else if (ThrownPotion.class.isAssignableFrom(projectile)) { - launch = new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), CraftItemStack.asNMSCopy(new ItemStack(Material.POTION, 1))); + if (LingeringPotion.class.isAssignableFrom(projectile)) { + launch = new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.LINGERING_POTION, 1))); + } else { + launch = new EntityPotion(world, iposition.getX(), iposition.getY(), iposition.getZ(), CraftItemStack.asNMSCopy(new ItemStack(org.bukkit.Material.SPLASH_POTION, 1))); + } } else if (Arrow.class.isAssignableFrom(projectile)) { - launch = new EntityTippedArrow(world, iposition.getX(), iposition.getY(), iposition.getZ()); + if (TippedArrow.class.isAssignableFrom(projectile)) { + launch = new EntityTippedArrow(world, iposition.getX(), iposition.getY(), iposition.getZ()); + ((EntityTippedArrow) launch).setType(CraftPotionUtil.fromBukkit(new PotionData(PotionType.WATER, false, false))); + } else if (SpectralArrow.class.isAssignableFrom(projectile)) { + launch = new EntitySpectralArrow(world, iposition.getX(), iposition.getY(), iposition.getZ()); + } else { + launch = new EntityTippedArrow(world, iposition.getX(), iposition.getY(), iposition.getZ()); + } ((EntityArrow) launch).fromPlayer = EntityArrow.PickupStatus.ALLOWED; ((EntityArrow) launch).projectileSource = this; } else if (Fireball.class.isAssignableFrom(projectile)) { @@ -111,7 +129,7 @@ public class CraftBlockProjectileSource implements BlockProjectileSource { ((EntityFireball) launch).dirY = d4 / d6 * 0.1D; ((EntityFireball) launch).dirZ = d5 / d6 * 0.1D; } - + ((EntityFireball) launch).projectileSource = this; } |