/* * The MIT License (MIT) * * Copyright (c) 2022 Crypto Morin * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package dev.brighten.ac.utils; import com.google.common.base.Strings; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.Validate; import org.apache.commons.lang.WordUtils; import org.apache.commons.lang.math.NumberUtils; import org.bukkit.Material; import org.bukkit.entity.LivingEntity; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.bukkit.potion.PotionType; import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; /** * Potion type support for multiple aliases. * Uses EssentialsX potion list for aliases. *
* Duration: The duration of the effect in ticks. Values 0 or lower are treated as 1. Optional, and defaults to 1 tick. * Amplifier: The amplifier of the effect, with level I having value 0. Optional, and defaults to level I. *
* EssentialsX Potions: https://github.com/EssentialsX/Essentials/blob/2.x/Essentials/src/com/earth2me/essentials/Potions.java
* Status Effect: https://minecraft.gamepedia.com/Status_effect
* Potions: https://minecraft.gamepedia.com/Potion
*
* @author Crypto Morin
* @version 3.1.0
* @see PotionEffect
* @see PotionEffectType
* @see PotionType
*/
public enum XPotion {
ABSORPTION("ABSORB"),
BAD_OMEN("OMEN_BAD", "PILLAGER"),
BLINDNESS("BLIND"),
CONDUIT_POWER("CONDUIT", "POWER_CONDUIT"),
CONFUSION("NAUSEA", "SICKNESS", "SICK"),
DAMAGE_RESISTANCE("RESISTANCE", "ARMOR", "DMG_RESIST", "DMG_RESISTANCE"),
DARKNESS,
DOLPHINS_GRACE("DOLPHIN", "GRACE"),
FAST_DIGGING("HASTE", "SUPER_PICK", "DIGFAST", "DIG_SPEED", "QUICK_MINE", "SHARP"),
FIRE_RESISTANCE("FIRE_RESIST", "RESIST_FIRE", "FIRE_RESISTANCE"),
GLOWING("GLOW", "SHINE", "SHINY"),
HARM("INJURE", "DAMAGE", "HARMING", "INFLICT", "INSTANT_DAMAGE"),
HEAL("HEALTH", "INSTA_HEAL", "INSTANT_HEAL", "INSTA_HEALTH", "INSTANT_HEALTH"),
HEALTH_BOOST("BOOST_HEALTH", "BOOST", "HP"),
HERO_OF_THE_VILLAGE("HERO", "VILLAGE_HERO"),
HUNGER("STARVE", "HUNGRY"),
INCREASE_DAMAGE("STRENGTH", "BULL", "STRONG", "ATTACK"),
INVISIBILITY("INVISIBLE", "VANISH", "INVIS", "DISAPPEAR", "HIDE"),
JUMP("LEAP", "JUMP_BOOST"),
LEVITATION("LEVITATE"),
LUCK("LUCKY"),
NIGHT_VISION("VISION", "VISION_NIGHT"),
POISON("VENOM"),
REGENERATION("REGEN"),
SATURATION("FOOD"),
SLOW("SLOWNESS", "SLUGGISH"),
SLOW_DIGGING("FATIGUE", "DULL", "DIGGING", "SLOW_DIG", "DIG_SLOW"),
SLOW_FALLING("SLOW_FALL", "FALL_SLOW"),
SPEED("SPRINT", "RUNFAST", "SWIFT", "FAST"),
UNLUCK("UNLUCKY"),
WATER_BREATHING("WATER_BREATH", "UNDERWATER_BREATHING", "UNDERWATER_BREATH", "AIR"),
WEAKNESS("WEAK"),
WITHER("DECAY");
/**
* Cached list of {@link XPotion#values()} to avoid allocating memory for
* calling the method every time.
*
* @since 1.0.0
*/
public static final XPotion[] VALUES = values();
/**
* An unmodifiable set of "bad" potion effects.
*
* @since 1.1.0
*/
public static final Set
* An invocation of this method yields exactly the same result as the expression:
*
* values.length + 1 is intentional as it allocates one useless space since IDs start from 1
*/
private static final XPotion[] POTIONEFFECTTYPE_MAPPING = new XPotion[VALUES.length + 1];
static {
for (XPotion pot : VALUES)
if (pot.type != null) //noinspection deprecation
POTIONEFFECTTYPE_MAPPING[pot.type.getId()] = pot;
}
private final PotionEffectType type;
XPotion(@Nonnull String... aliases) {
this.type = PotionEffectType.getByName(this.name());
Data.NAMES.put(this.name(), this);
for (String legacy : aliases) Data.NAMES.put(legacy, this);
}
/**
* Attempts to build the string like an enum name.
* Removes all the spaces, numbers and extra non-English characters. Also removes some config/in-game based strings.
* While this method is hard to maintain, it's extremely efficient. It's approximately more than x5 times faster than
* the normal RegEx + String Methods approach for both formatted and unformatted material names.
*
* @param name the potion effect type name to format.
*
* @return an enum name.
* @since 1.0.0
*/
@Nonnull
private static String format(@Nonnull String name) {
int len = name.length();
char[] chs = new char[len];
int count = 0;
boolean appendUnderline = false;
for (int i = 0; i < len; i++) {
char ch = name.charAt(i);
if (!appendUnderline && count != 0 && (ch == '-' || ch == ' ' || ch == '_') && chs[count] != '_') appendUnderline = true;
else {
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
if (appendUnderline) {
chs[count++] = '_';
appendUnderline = false;
}
chs[count++] = (char) (ch & 0x5f);
}
}
}
return new String(chs, 0, count);
}
/**
* Parses a potion effect type from the given string.
* Supports type IDs.
*
* @param potion the type of the type's ID of the potion effect type.
*
* @return a potion effect type.
* @since 1.0.0
*/
@Nonnull
public static Optional
* Format: Potion, Duration (in seconds), Amplifier (level) [%chance]
*
* WEAKNESS, 30, 1
* SLOWNESS 200 10
* 1, 10000, 100 %50
*
* The last argument (the amplifier can also have a chance which if not met, returns null.
*
* @param potion the potion string to parse.
*
* @return a potion effect, or null if the potion type is wrong.
* @see #buildPotionEffect(int, int)
* @since 1.0.0
*/
@Nullable
public static Effect parseEffect(@Nullable String potion) {
if (Strings.isNullOrEmpty(potion) || potion.equalsIgnoreCase("none")) return null;
String[] split = StringUtils.split(StringUtils.deleteWhitespace(potion), ',');
if (split.length == 0) split = StringUtils.split(potion, ' ');
double chance = 100;
int chanceIndex = 0;
if (split.length > 2) {
chanceIndex = split[2].indexOf('%');
if (chanceIndex != -1) chance = NumberUtils.toDouble(split[2].substring(chanceIndex + 1), 100);
}
Optional
* {@link #getPotionEffectType()} != null
*
*
* @return true if the current version has this potion effect type, otherwise false.
* @since 1.0.0
*/
public boolean isSupported() {
return this.type != null;
}
/**
* Gets the PotionType from this PotionEffectType.
* Usually for potion items.
*
* @return a potion type for potions.
* @see #getPotionEffectType()
* @since 1.0.0
* @deprecated not for removal, but use {@link PotionEffectType} instead.
*/
@Nullable
@Deprecated
public PotionType getPotionType() {
return type == null ? null : PotionType.getByEffect(type);
}
/**
* Builds a potion effect with the given duration and amplifier.
*
* @param duration the duration of the potion effect.
* @param amplifier the amplifier of the potion effect.
*
* @return a potion effect.
* @see #parseEffect(String)
* @since 1.0.0
*/
@Nullable
public PotionEffect buildPotionEffect(int duration, int amplifier) {
return type == null ? null : new PotionEffect(type, duration, amplifier);
}
/**
* In most cases you should be using {@link #name()} instead.
*
* @return a friendly readable string name.
*/
@Override
public String toString() {
return WordUtils.capitalize(this.name().replace('_', ' ').toLowerCase(Locale.ENGLISH));
}
/**
* Used for data that need to be accessed during enum initialization.
*
* @since 2.0.0
*/
private static final class Data {
private static final Map