SPIGOT-1638 / SPIGOT-1673: Rework Potions API

By: t00thpick1 <t00thpick1dirko@gmail.com>
This commit is contained in:
Bukkit/Spigot
2016-03-02 20:45:27 -05:00
parent a7e0658387
commit 949890d29d
16 changed files with 407 additions and 312 deletions

View File

@@ -6,17 +6,17 @@ import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.ItemStack;
import com.google.common.collect.ImmutableList;
import org.bukkit.inventory.meta.PotionMeta;
/**
* Represents a minecraft potion
* Potion Adapter for pre-1.9 data values
* see @PotionMeta for 1.9+
*/
@Deprecated
public class Potion {
private boolean extended = false;
private boolean splash = false;
private int level = 1;
private int name = -1;
private PotionType type;
/**
@@ -29,20 +29,13 @@ public class Potion {
* @see #Potion(int)
*/
public Potion(PotionType type) {
Validate.notNull(type, "Null PotionType");
this.type = type;
if (type != null) {
this.name = type.getDamageValue();
}
if (type == null || type == PotionType.WATER) {
this.level = 0;
}
}
/**
* @param type the type of the potion
* @param tier the tier of the potion
* @deprecated In favour of {@link #Potion(PotionType, int)}
*/
*/
@Deprecated
public Potion(PotionType type, Tier tier) {
this(type, tier == Tier.TWO ? 2 : 1);
@@ -50,9 +43,6 @@ public class Potion {
}
/**
* @param type the type of the potion
* @param tier the tier of the potion
* @param splash whether the potion is a splash potion
* @deprecated In favour of {@link #Potion(PotionType, int, boolean)}
*/
@Deprecated
@@ -61,10 +51,6 @@ public class Potion {
}
/**
* @param type the type of the potion
* @param tier the tier of the potion
* @param splash whether the potion is a splash potion
* @param extended whether the potion has an extended duration
* @deprecated In favour of {@link #Potion(PotionType, int, boolean,
* boolean)}
*/
@@ -83,7 +69,6 @@ public class Potion {
public Potion(PotionType type, int level) {
this(type);
Validate.notNull(type, "Type cannot be null");
Validate.isTrue(type != PotionType.WATER, "Water bottles don't have a level!");
Validate.isTrue(level > 0 && level < 3, "Level must be 1 or 2");
this.level = level;
}
@@ -120,17 +105,11 @@ public class Potion {
}
/**
* Create a potion with a specific name.
*
* @param name The name index (0-63)
* @Deprecated
*/
@Deprecated
public Potion(int name) {
this(PotionType.getByDamageValue(name & POTION_BIT));
this.name = name & NAME_BIT;
if ((name & POTION_BIT) == 0) {
// If it's 0 it would've become PotionType.WATER, but it should actually be mundane potion
this.type = null;
}
this(PotionType.WATER);
}
/**
@@ -161,8 +140,11 @@ public class Potion {
*/
public void apply(ItemStack to) {
Validate.notNull(to, "itemstack cannot be null");
Validate.isTrue(to.getType() == Material.POTION, "given itemstack is not a potion");
to.setDurability(toDamageValue());
Validate.isTrue(to.hasItemMeta(), "given itemstack is not a potion");
Validate.isTrue(to.getItemMeta() instanceof PotionMeta, "given itemstack is not a potion");
PotionMeta meta = (PotionMeta) to.getItemMeta();
meta.setBasePotionData(new PotionData(type, level == 2, extended));
to.setItemMeta(meta);
}
/**
@@ -198,8 +180,7 @@ public class Potion {
* @return The effects that this potion applies
*/
public Collection<PotionEffect> getEffects() {
if (type == null) return ImmutableList.<PotionEffect>of();
return getBrewer().getEffectsFromDamage(toDamageValue());
return getBrewer().getEffects(type, level == 2, extended);
}
/**
@@ -215,6 +196,7 @@ public class Potion {
* Returns the {@link Tier} of this potion.
*
* @return The tier of this potion
* @deprecated
*/
@Deprecated
public Tier getTier() {
@@ -307,8 +289,7 @@ public class Potion {
*/
public void setLevel(int level) {
Validate.notNull(this.type, "No-effect potions don't have a level.");
int max = type.getMaxLevel();
Validate.isTrue(level > 0 && level <= max, "Level must be " + (max == 1 ? "" : "between 1 and ") + max + " for this potion");
Validate.isTrue(level > 0 && level <= 2, "Level must be between 1 and 2 for this potion");
this.level = level;
}
@@ -317,28 +298,11 @@ public class Potion {
* item stacks.
*
* @return The damage value of this potion
* @deprecated Magic value
* @deprecated Non-functional
*/
@Deprecated
public short toDamageValue() {
short damage;
if (type == PotionType.WATER) {
return 0;
} else if (type == null) {
// Without this, mundanePotion.toDamageValue() would return 0
damage = (short) (name == 0 ? 8192 : name);
} else {
damage = (short) (level - 1);
damage <<= TIER_SHIFT;
damage |= (short) type.getDamageValue();
}
if (splash) {
damage |= SPLASH_BIT;
}
if (extended) {
damage |= EXTENDED_BIT;
}
return damage;
return 0;
}
/**
@@ -349,7 +313,17 @@ public class Potion {
* @return The created ItemStack
*/
public ItemStack toItemStack(int amount) {
return new ItemStack(Material.POTION, amount, toDamageValue());
Material material;
if (isSplash()) {
material = Material.SPLASH_POTION;
} else {
material = Material.POTION;
}
ItemStack itemStack = new ItemStack(material, amount);
PotionMeta meta = (PotionMeta) itemStack.getItemMeta();
meta.setBasePotionData(new PotionData(type, level == 2, extended));
itemStack.setItemMeta(meta);
return itemStack;
}
@Deprecated
@@ -383,20 +357,63 @@ public class Potion {
private static final int SPLASH_BIT = 0x4000;
private static final int TIER_BIT = 0x20;
private static final int TIER_SHIFT = 5;
private static final int NAME_BIT = 0x3F;
/**
*
* @param damage the damage value
* @return the produced potion
* @deprecated Magic value
*/
@Deprecated
public static Potion fromDamage(int damage) {
PotionType type = PotionType.getByDamageValue(damage & POTION_BIT);
PotionType type;
switch (damage & POTION_BIT) {
case 0:
type = PotionType.WATER;
break;
case 1:
type = PotionType.REGEN;
break;
case 2:
type = PotionType.SPEED;
break;
case 3:
type = PotionType.FIRE_RESISTANCE;
break;
case 4:
type = PotionType.POISON;
break;
case 5:
type = PotionType.INSTANT_HEAL;
break;
case 6:
type = PotionType.NIGHT_VISION;
break;
case 8:
type = PotionType.WEAKNESS;
break;
case 9:
type = PotionType.STRENGTH;
break;
case 10:
type = PotionType.SLOWNESS;
break;
case 11:
type = PotionType.JUMP;
break;
case 12:
type = PotionType.INSTANT_DAMAGE;
break;
case 13:
type = PotionType.WATER_BREATHING;
break;
case 14:
type = PotionType.INVISIBILITY;
break;
default:
type = PotionType.WATER;
}
Potion potion;
if (type == null || type == PotionType.WATER) {
potion = new Potion(damage & NAME_BIT);
potion = new Potion(PotionType.WATER);
} else {
int level = (damage & TIER_BIT) >> TIER_SHIFT;
level++;
@@ -405,7 +422,7 @@ public class Potion {
if ((damage & SPLASH_BIT) > 0) {
potion = potion.splash();
}
if ((type == null || !type.isInstant()) && (damage & EXTENDED_BIT) > 0) {
if ((damage & EXTENDED_BIT) > 0) {
potion = potion.extend();
}
return potion;
@@ -442,10 +459,10 @@ public class Potion {
/**
*
* @return the name id
* @deprecated Magic value
* @deprecated Non-functional
*/
@Deprecated
public int getNameId() {
return name;
return 0;
}
}

View File

@@ -24,8 +24,17 @@ public interface PotionBrewer {
*
* @param damage The data value of the potion
* @return The list of effects
* @deprecated Magic value
* @deprecated Non-Functional
*/
@Deprecated
public Collection<PotionEffect> getEffectsFromDamage(int damage);
/**
* Returns a collection of {@link PotionEffect} that would be applied from
* a potion with the given type.
*
* @param type The type of the potion
* @return The list of effects
*/
public Collection<PotionEffect> getEffects(PotionType type, boolean upgraded, boolean extended);
}

View File

@@ -0,0 +1,64 @@
package org.bukkit.potion;
import org.apache.commons.lang.Validate;
public final class PotionData {
private final PotionType type;
private final boolean extended;
private final boolean upgraded;
/**
* Instantiates a final PotionData object to contain information about a
* Potion
*
* @param type the type of the Potion
* @param extended whether the potion is extended PotionType#isExtendable()
* must be true
* @param upgraded whether the potion is upgraded PotionType#isUpgradable()
* must be true
*/
public PotionData(PotionType type, boolean extended, boolean upgraded) {
Validate.notNull(type, "Potion Type must not be null");
Validate.isTrue(!upgraded || type.isUpgradeable(), "Potion Type is not upgradable");
Validate.isTrue(!extended || type.isExtendable(), "Potion Type is not extendable");
Validate.isTrue(!upgraded || !extended, "Potion cannot be both extended and upgraded");
this.type = type;
this.extended = extended;
this.upgraded = upgraded;
}
public PotionData(PotionType type) {
this(type, false, false);
}
/**
* Gets the type of the potion, Type matches up with each kind of craftable
* potion
*
* @return the potion type
*/
public PotionType getType() {
return type;
}
/**
* Checks if the potion is in an upgraded state. This refers to whether or
* not the potion is Tier 2, such as Potion of Fire Resistance II.
*
* @return true if the potion is upgraded;
*/
public boolean isUpgraded() {
return upgraded;
}
/**
* Checks if the potion is in an extended state. This refers to the extended
* duration potions
*
* @return true if the potion is extended
*/
public boolean isExtended() {
return extended;
}
}

View File

@@ -62,7 +62,7 @@ public class PotionEffect implements ConfigurationSerializable {
* @param particles the particle status, see {@link PotionEffect#hasParticles()}
*/
public PotionEffect(PotionEffectType type, int duration, int amplifier, boolean ambient, boolean particles) {
this(type, duration, amplifier, ambient, true, null);
this(type, duration, amplifier, ambient, particles, null);
}
/**

View File

@@ -162,7 +162,7 @@ public abstract class PotionEffectType {
* @return a resulting potion effect
*/
public PotionEffect createEffect(int duration, int amplifier) {
return Potion.getBrewer().createEffect(this, duration, amplifier);
return new PotionEffect(this, isInstant() ? 1 : (int) (duration * getDurationModifier()), amplifier);
}
/**

View File

@@ -1,73 +1,94 @@
package org.bukkit.potion;
/**
* This enum reflects and matches each potion state that can be obtained from
* the Creative mode inventory
*/
public enum PotionType {
WATER(0, null, 0),
REGEN(1, PotionEffectType.REGENERATION, 2),
SPEED(2, PotionEffectType.SPEED, 2),
FIRE_RESISTANCE(3, PotionEffectType.FIRE_RESISTANCE, 1),
POISON(4, PotionEffectType.POISON, 2),
INSTANT_HEAL(5, PotionEffectType.HEAL, 2),
NIGHT_VISION(6, PotionEffectType.NIGHT_VISION, 1),
WEAKNESS(8, PotionEffectType.WEAKNESS, 1),
STRENGTH(9, PotionEffectType.INCREASE_DAMAGE, 2),
SLOWNESS(10, PotionEffectType.SLOW, 1),
JUMP(11, PotionEffectType.JUMP, 2),
INSTANT_DAMAGE(12, PotionEffectType.HARM, 2),
WATER_BREATHING(13, PotionEffectType.WATER_BREATHING, 1),
INVISIBILITY(14, PotionEffectType.INVISIBILITY, 1),
/**
* @deprecated not representable with a damage value!
*/
@Deprecated
LUCK(-1, PotionEffectType.LUCK, 1),
UNCRAFTABLE(null, false, false),
WATER(null, false, false),
MUNDANE(null, false, false),
THICK(null, false, false),
AWKWARD(null, false, false),
NIGHT_VISION(PotionEffectType.NIGHT_VISION, false, true),
INVISIBILITY(PotionEffectType.INVISIBILITY, false, true),
JUMP(PotionEffectType.JUMP, true, true),
FIRE_RESISTANCE(PotionEffectType.FIRE_RESISTANCE, false, true),
SPEED(PotionEffectType.SPEED, true, true),
SLOWNESS(PotionEffectType.SLOW, false, true),
WATER_BREATHING(PotionEffectType.WATER_BREATHING, false, true),
INSTANT_HEAL(PotionEffectType.HEAL, true, false),
INSTANT_DAMAGE(PotionEffectType.HARM, true, false),
POISON(PotionEffectType.POISON, true, true),
REGEN(PotionEffectType.REGENERATION, true, true),
STRENGTH(PotionEffectType.INCREASE_DAMAGE, true, true),
WEAKNESS(PotionEffectType.WEAKNESS, false, true),
LUCK(PotionEffectType.LUCK, false, false);
;
private final int damageValue, maxLevel;
private final PotionEffectType effect;
private final boolean upgradeable;
private final boolean extendable;
PotionType(int damageValue, PotionEffectType effect, int maxLevel) {
this.damageValue = damageValue;
PotionType(PotionEffectType effect, boolean upgradeable, boolean extendable) {
this.effect = effect;
this.maxLevel = maxLevel;
this.upgradeable = upgradeable;
this.extendable = extendable;
}
public PotionEffectType getEffectType() {
return effect;
}
public boolean isInstant() {
return effect != null && effect.isInstant();
}
/**
*
* @return the damage value
* @deprecated Magic value
* Checks if the potion type has an upgraded state.
* This refers to whether or not the potion type can be Tier 2,
* such as Potion of Fire Resistance II.
*
* @return true if the potion type can be upgraded;
*/
public boolean isUpgradeable() {
return upgradeable;
}
/**
* Checks if the potion type has an extended state.
* This refers to the extended duration potions
*
* @return true if the potion type can be extended
*/
public boolean isExtendable() {
return extendable;
}
/**
* @deprecated Non-functional
*/
@Deprecated
public int getDamageValue() {
return damageValue;
return 0;
}
public int getMaxLevel() {
return maxLevel;
}
public boolean isInstant() {
return effect == null ? true : effect.isInstant();
return upgradeable ? 2 : 1;
}
/**
*
* @param damage the damage value
* @return the matching potion type or null
* @deprecated Magic value
* @deprecated Non-functional
*/
@Deprecated
public static PotionType getByDamageValue(int damage) {
for (PotionType type : PotionType.values()) {
if (type.damageValue == damage)
return type;
}
return null;
}
/**
* @deprecated Misleading
*/
@Deprecated
public static PotionType getByEffect(PotionEffectType effectType) {
if (effectType == null)
return WATER;