package net.glowstone.inventory;
import com.google.common.collect.ImmutableList;
import net.glowstone.util.nbt.CompoundTag;
import net.glowstone.util.nbt.TagType;
import org.bukkit.Color;
import org.bukkit.Material;
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 java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static com.google.common.base.Preconditions.checkNotNull;
public class GlowMetaPotion extends GlowMetaItem implements PotionMeta {
PotionData potion;
List<PotionEffect> effects = new ArrayList<>();
Color color = null;
public GlowMetaPotion(GlowMetaItem meta) {
super(meta);
if (!(meta instanceof GlowMetaPotion)) return;
GlowMetaPotion potion = (GlowMetaPotion) meta;
effects.addAll(potion.effects);
this.potion = potion.potion;
}
public static PotionEffect fromNBT(CompoundTag tag) {
PotionEffectType type = PotionEffectType.getById(tag.getByte("Id"));
int duration = tag.getInt("Duration");
int amplifier = tag.getByte("Amplifier");
boolean ambient = tag.isByte("Ambient") && tag.getBool("Ambient");
boolean particles = !tag.isByte("ShowParticles") || tag.getBool("ShowParticles");
return new PotionEffect(type, duration, amplifier, ambient, particles);
}
public static CompoundTag toNBT(PotionEffect effect) {
CompoundTag tag = new CompoundTag();
tag.putByte("Id", effect.getType().getId());
tag.putInt("Duration", effect.getDuration());
tag.putByte("Amplifier", effect.getAmplifier());
tag.putBool("Ambient", effect.isAmbient());
tag.putBool("ShowParticles", effect.hasParticles());
return tag;
}
@Override
public boolean isApplicable(Material material) {
return material == Material.POTION || material == Material.SPLASH_POTION || material == Material.TIPPED_ARROW || material == Material.LINGERING_POTION;
}
@Override
public GlowMetaPotion clone() {
return new GlowMetaPotion(this);
}
@Override
public Map<String, Object> serialize() {
Map<String, Object> result = super.serialize();
result.put("meta-type", "POTION");
if (hasCustomEffects()) {
result.put("custom-effects", getCustomEffects());
}
return result;
}
@Override
void writeNbt(CompoundTag tag) {
super.writeNbt(tag);
if (hasCustomEffects()) {
List<CompoundTag> customEffects = effects.stream().map(GlowMetaPotion::toNBT).collect(Collectors.toList());
tag.putCompoundList("CustomEffects", customEffects);
}
tag.putString("Potion", dataToString());
if (this.color != null) {
tag.putInt("CustomPotionColor", this.color.asRGB());
}
}
@Override
void readNbt(CompoundTag tag) {
super.readNbt(tag);
if (tag.isList("CustomEffects", TagType.COMPOUND)) {
List<CompoundTag> customEffects = tag.getCompoundList("CustomEffects");
for (CompoundTag effect : customEffects) {
addCustomEffect(fromNBT(effect), true);
}
}
if (tag.isString("Potion")) {
this.potion = dataFromString(tag.getString("Potion"));
}
if (tag.isInt("CustomPotionColor")) {
this.color = Color.fromRGB(tag.getInt("CustomPotionColor"));
}
}
@Override
public void setBasePotionData(PotionData potionData) {
this.potion = potionData;
}
@Override
public PotionData getBasePotionData() {
return this.potion;
}
@Override
public boolean hasCustomEffects() {
return !effects.isEmpty();
}
@Override
public List<PotionEffect> getCustomEffects() {
return ImmutableList.copyOf(effects);
}
@Override
public boolean addCustomEffect(PotionEffect effect, boolean overwrite) {
checkNotNull(effect, "PotionEffect cannot be null.");
for (PotionEffect eff : effects) {
if (eff.getType() == effect.getType() && !overwrite) return false;
}
effects.add(effect);
return true;
}
@Override
public boolean removeCustomEffect(PotionEffectType type) {
Iterator<PotionEffect> it = effects.iterator();
while (it.hasNext()) {
PotionEffect effect = it.next();
if (effect.getType() == type) {
it.remove();
return true;
}
}
return false;
}
@Override
public boolean hasCustomEffect(PotionEffectType type) {
for (PotionEffect effect : effects) {
if (effect.getType() == type) return true;
}
return false;
}
@Override
public boolean setMainEffect(PotionEffectType type) {
PotionEffect main = null;
for (PotionEffect effect : effects) {
if (effect.getType() == type) {
if (effects.indexOf(effect) == 0) return false;
main = effect;
effects.remove(effect);
break;
}
}
if (main == null) return false;
effects.add(0, main);
return true;
}
@Override
public boolean clearCustomEffects() {
if (effects.isEmpty()) return false;
effects.clear();
return true;
}
@Override
public boolean hasColor() {
return color != null;
}
@Override
public Color getColor() {
return color;
}
@Override
public void setColor(Color color) {
this.color = color;
}
/**
* Converts the PotionData of this item meta to a Potion ID string
*
* @return the Potion ID string
*/
private String dataToString() {
String name = "minecraft:";
if (potion.isExtended()) {
name += "long_";
} else if (potion.isUpgraded()) {
name += "strong_";
}
return name + PotionTypeTable.toName(potion.getType());
}
/**
* Converts a Potion ID string to the PotionData of this item meta.
*
* @param string the Potion ID string
* @return the resultant PotionData
*/
private PotionData dataFromString(String string) {
PotionType type;
boolean extended = false, upgraded = false;
if (string.startsWith("minecraft:"))
string = string.replace("minecraft:", "");
if (string.startsWith("long_")) {
string = string.replace("long_", "");
extended = true;
} else if (string.startsWith("strong_")) {
string = string.replace("strong_", "");
upgraded = true;
}
type = PotionTypeTable.fromName(string);
return new PotionData(type, extended, upgraded);
}
/**
* Conversion for Bukkit Potion names to Vanilla Potion names.
*/
enum PotionTypeTable {
EMPTY(PotionType.UNCRAFTABLE, "empty"),
LEAPING(PotionType.JUMP, "leaping"),
SWIFTNESS(PotionType.SPEED, "swiftness"),
HEALING(PotionType.INSTANT_HEAL, "healing"),
HARMING(PotionType.INSTANT_DAMAGE, "harming"),
REGENERATION(PotionType.REGEN, "regeneration");
PotionType type;
String name;
PotionTypeTable(PotionType type, String name) {
this.type = type;
this.name = name;
}
/**
* Converts a Vanilla Potion ID to an equivalent Bukkit PotionType
*
* @param name the Vanilla Potion ID
* @return the PotionType equivalent
*/
static PotionType fromName(String name) {
for (PotionTypeTable table : values()) {
if (name.equalsIgnoreCase(table.name))
return table.type;
}
return PotionType.valueOf(name.toUpperCase());
}
/**
* Converts a Bukkit PotionType to an equivalent Vanilla Potion ID
*
* @param type the Bukkit PotionType
* @return the Vanilla Potion ID equivalent
*/
static String toName(PotionType type) {
for (PotionTypeTable table : values()) {
if (type == table.type)
return table.name;
}
return type.name().toLowerCase();
}
}
}