Add config option, improve multi-version support
- Added config option to allow multiple types of protection enchantments to be applied to a single armored elytra. - Added XMaterial class that was accidentally omitted in the last commit.
This commit is contained in:
parent
1e986d60da
commit
080b6c6dab
@ -117,32 +117,35 @@ public class EventHandlers implements Listener
|
|||||||
combined.put(entry.getKey(), entry.getValue());
|
combined.put(entry.getKey(), entry.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the protection enchantment rating for both enchantment sets.
|
if (!plugin.getConfigLoader().allowMultipleProtectionEnchantments())
|
||||||
int protVal0 = Util.getProtectionEnchantmentsVal(enchantments0);
|
{
|
||||||
int protVal1 = Util.getProtectionEnchantmentsVal(enchantments1);
|
// Get the protection enchantment rating for both enchantment sets.
|
||||||
|
int protVal0 = Util.getProtectionEnchantmentsVal(enchantments0);
|
||||||
|
int protVal1 = Util.getProtectionEnchantmentsVal(enchantments1);
|
||||||
|
|
||||||
// If they have different protection enchantments, keep enchantment1's enchantments
|
// If they have different protection enchantments, keep enchantment1's enchantments
|
||||||
// And remove the protection enchantment from enchantments0. Yes, this system only works
|
// And remove the protection enchantment from enchantments0. Yes, this system only works
|
||||||
// If there is 1 protection enchantment on
|
// If there is 1 protection enchantment on
|
||||||
if (protVal0 != 0 && protVal1 != 0 && protVal0 != protVal1)
|
if (protVal0 != 0 && protVal1 != 0 && protVal0 != protVal1)
|
||||||
switch(protVal0)
|
switch(protVal0)
|
||||||
{
|
{
|
||||||
case 1:
|
case 1:
|
||||||
combined.remove(Enchantment.PROTECTION_ENVIRONMENTAL);
|
combined.remove(Enchantment.PROTECTION_ENVIRONMENTAL);
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
combined.remove(Enchantment.PROTECTION_EXPLOSIONS);
|
combined.remove(Enchantment.PROTECTION_EXPLOSIONS);
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
combined.remove(Enchantment.PROTECTION_FALL);
|
combined.remove(Enchantment.PROTECTION_FALL);
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
combined.remove(Enchantment.PROTECTION_FIRE);
|
combined.remove(Enchantment.PROTECTION_FIRE);
|
||||||
break;
|
break;
|
||||||
case 16:
|
case 16:
|
||||||
combined.remove(Enchantment.PROTECTION_PROJECTILE);
|
combined.remove(Enchantment.PROTECTION_PROJECTILE);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@ public class ConfigLoader
|
|||||||
private int DIAMONDS_TO_FULL;
|
private int DIAMONDS_TO_FULL;
|
||||||
private boolean noFlightDurability;
|
private boolean noFlightDurability;
|
||||||
private List<String> allowedEnchantments;
|
private List<String> allowedEnchantments;
|
||||||
|
private boolean allowMultipleProtectionEnchantments;
|
||||||
|
|
||||||
private ArrayList<ConfigOption<?>> configOptionsList;
|
private ArrayList<ConfigOption<?>> configOptionsList;
|
||||||
private ArmoredElytra plugin;
|
private ArmoredElytra plugin;
|
||||||
@ -93,6 +94,14 @@ public class ConfigLoader
|
|||||||
{
|
{
|
||||||
"Specify a language file to be used. Note that en_US.txt will get regenerated!"
|
"Specify a language file to be used. Note that en_US.txt will get regenerated!"
|
||||||
};
|
};
|
||||||
|
String[] allowMultipleProtectionEnchantmentsComment =
|
||||||
|
{
|
||||||
|
"Allow more than 1 type of protection enchantment on a single armored elytra. ",
|
||||||
|
"If true, you could have both blast protection and environmental protection at the same time.",
|
||||||
|
"If false, the second enchantment (while crafting) will override the first. So combining an armored",
|
||||||
|
"elytra that has the protection enchantment with an enchanted book that has the blast protection enchantment",
|
||||||
|
"would result in removal of the protection enchantment and addition of the blast protection enchantment."
|
||||||
|
};
|
||||||
|
|
||||||
// Set default list of allowed enchantments.
|
// Set default list of allowed enchantments.
|
||||||
allowedEnchantments = new ArrayList<>(Arrays.asList("DURABILITY", "PROTECTION_FIRE", "PROTECTION_EXPLOSIONS",
|
allowedEnchantments = new ArrayList<>(Arrays.asList("DURABILITY", "PROTECTION_FIRE", "PROTECTION_EXPLOSIONS",
|
||||||
@ -108,6 +117,7 @@ public class ConfigLoader
|
|||||||
IRON_TO_FULL = addNewConfigOption(config, "ironRepair", 4, null);
|
IRON_TO_FULL = addNewConfigOption(config, "ironRepair", 4, null);
|
||||||
DIAMONDS_TO_FULL = addNewConfigOption(config, "diamondsRepair", 3, null);
|
DIAMONDS_TO_FULL = addNewConfigOption(config, "diamondsRepair", 3, null);
|
||||||
allowedEnchantments = addNewConfigOption(config, "allowedEnchantments", allowedEnchantments, enchantmentsComment);
|
allowedEnchantments = addNewConfigOption(config, "allowedEnchantments", allowedEnchantments, enchantmentsComment);
|
||||||
|
allowMultipleProtectionEnchantments = addNewConfigOption(config, "allowMultipleProtectionEnchantments", false, allowMultipleProtectionEnchantmentsComment);
|
||||||
checkForUpdates = addNewConfigOption(config, "checkForUpdates", true, updateComment);
|
checkForUpdates = addNewConfigOption(config, "checkForUpdates", true, updateComment);
|
||||||
allowStats = addNewConfigOption(config, "allowStats", true, bStatsComment);
|
allowStats = addNewConfigOption(config, "allowStats", true, bStatsComment);
|
||||||
enableDebug = addNewConfigOption(config, "enableDebug", false, debugComment);
|
enableDebug = addNewConfigOption(config, "enableDebug", false, debugComment);
|
||||||
@ -205,6 +215,11 @@ public class ConfigLoader
|
|||||||
return DIAMONDS_TO_FULL;
|
return DIAMONDS_TO_FULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean allowMultipleProtectionEnchantments()
|
||||||
|
{
|
||||||
|
return allowMultipleProtectionEnchantments;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean uninstallMode()
|
public boolean uninstallMode()
|
||||||
{
|
{
|
||||||
return uninstallMode;
|
return uninstallMode;
|
||||||
|
@ -76,6 +76,7 @@ public class Util
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Function that returns which/how many protection enchantments there are.
|
// Function that returns which/how many protection enchantments there are.
|
||||||
|
// TODO: Use bit flags for this.
|
||||||
public static int getProtectionEnchantmentsVal(Map<Enchantment, Integer> enchantments)
|
public static int getProtectionEnchantmentsVal(Map<Enchantment, Integer> enchantments)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
656
src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java
Normal file
656
src/main/java/nl/pim16aap2/armoredElytra/util/XMaterial.java
Normal file
@ -0,0 +1,656 @@
|
|||||||
|
package nl.pim16aap2.armoredElytra.util;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The MIT License (MIT)
|
||||||
|
*
|
||||||
|
* Original work Copyright (c) 2018 Hex_27
|
||||||
|
* v2.0 Copyright (c) 2019 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import org.apache.commons.lang.Validate;
|
||||||
|
import org.bukkit.Bukkit;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* References
|
||||||
|
*
|
||||||
|
* * * GitHub: https://github.com/CryptoMorin/XMaterial/blob/master/XMaterial.java
|
||||||
|
* * Thread: https://www.spigotmc.org/threads/378136/
|
||||||
|
* https://minecraft.gamepedia.com/Java_Edition_data_values/Pre-flattening
|
||||||
|
* https://hub.spigotmc.org/javadocs/spigot/org/bukkit/Material.html
|
||||||
|
* http://docs.codelanx.com/Bukkit/1.8/org/bukkit/Material.html
|
||||||
|
* https://www.spigotmc.org/threads/1-8-to-1-13-itemstack-material-version-support.329630/
|
||||||
|
* https://minecraft-ids.grahamedgecombe.com/
|
||||||
|
* v1: https://pastebin.com/Fe65HZnN
|
||||||
|
* v2: 6/15/2019
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* XMaterial v2.2 - Data Values/Pre-flattening Supports 1.8-1.14 1.13 and above
|
||||||
|
* as priority.
|
||||||
|
*/
|
||||||
|
public enum XMaterial
|
||||||
|
{
|
||||||
|
|
||||||
|
CHAINMAIL_CHESTPLATE(0, ""),
|
||||||
|
DIAMOND_CHESTPLATE(0, ""),
|
||||||
|
GOLDEN_CHESTPLATE(0, "GOLD_CHESTPLATE"),
|
||||||
|
IRON_CHESTPLATE(0, ""),
|
||||||
|
LEATHER_CHESTPLATE(0, ""),
|
||||||
|
|
||||||
|
AIR(0, ""),
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A list of material names that can be damaged. Some names are not complete as
|
||||||
|
* this list needs to be checked with {@link String#contains}.
|
||||||
|
*/
|
||||||
|
public static final String[] DAMAGEABLE = { "HELMET", "CHESTPLATE", "LEGGINGS", "BOOTS", "SWORD", "AXE", "PICKAXE",
|
||||||
|
"SHOVEL", "HOE", "ELYTRA", "TRIDENT", "HORSE_ARMOR", "BARDING",
|
||||||
|
"SHEARS", "FLINT_AND_STEEL", "BOW", "FISHING_ROD", "CARROT_ON_A_STICK",
|
||||||
|
"CARROT_STICK" };
|
||||||
|
|
||||||
|
public static final XMaterial[] VALUES = XMaterial.values();
|
||||||
|
private static final HashMap<String, XMaterial> CACHED_SEARCH = new HashMap<>();
|
||||||
|
private static MinecraftVersion version;
|
||||||
|
private static Boolean isNewVersion;
|
||||||
|
private final byte data;
|
||||||
|
private final String[] legacy;
|
||||||
|
|
||||||
|
XMaterial(int data, String... legacy)
|
||||||
|
{
|
||||||
|
this.data = (byte) data;
|
||||||
|
this.legacy = legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the version is 1.13 (Aquatic Update) or higher.
|
||||||
|
*
|
||||||
|
* @return true if 1.13 or higher.
|
||||||
|
*/
|
||||||
|
public static boolean isNewVersion()
|
||||||
|
{
|
||||||
|
if (isNewVersion != null)
|
||||||
|
return isNewVersion;
|
||||||
|
return isNewVersion = isVersionOrHigher(MinecraftVersion.VERSION_1_13);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isOneEight()
|
||||||
|
{
|
||||||
|
return getVersion() == MinecraftVersion.VERSION_1_8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uses newly added materials to minecraft to detect the server version.
|
||||||
|
*
|
||||||
|
* @return the current server version.
|
||||||
|
*/
|
||||||
|
public static MinecraftVersion getVersion()
|
||||||
|
{
|
||||||
|
if (version != null)
|
||||||
|
return version;
|
||||||
|
return version = valueOfVersion(Bukkit.getVersion());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When using newer versions of Minecraft {@link #isNewVersion()} this helps to
|
||||||
|
* find the old material name with its data using a cached search for
|
||||||
|
* optimization.
|
||||||
|
*
|
||||||
|
* @see #matchXMaterial(String, byte)
|
||||||
|
*/
|
||||||
|
private static XMaterial requestOldXMaterial(String name, byte data)
|
||||||
|
{
|
||||||
|
XMaterial cached = CACHED_SEARCH.get(name + "," + data);
|
||||||
|
|
||||||
|
if (cached != null)
|
||||||
|
return cached;
|
||||||
|
Optional<XMaterial> search = data == -1 ?
|
||||||
|
Arrays.stream(XMaterial.VALUES).filter(mat -> mat.matchAnyLegacy(name)).findFirst() :
|
||||||
|
Arrays.stream(XMaterial.VALUES).filter(mat -> mat.matchAnyLegacy(name) && mat.data == data).findFirst();
|
||||||
|
|
||||||
|
if (search.isPresent())
|
||||||
|
{
|
||||||
|
XMaterial found = search.get();
|
||||||
|
CACHED_SEARCH.put(found.legacy[0] + "," + found.getData(), found);
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if XMaterial enum contains a material with this name.
|
||||||
|
*
|
||||||
|
* @param name name of the material
|
||||||
|
* @return true if XMaterial enum has this material.
|
||||||
|
*/
|
||||||
|
public static boolean contains(String name)
|
||||||
|
{
|
||||||
|
String formatted = format(name);
|
||||||
|
return Arrays.stream(XMaterial.VALUES).anyMatch(mat -> mat.name().equals(formatted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given material matches any of the legacy names.
|
||||||
|
*
|
||||||
|
* @param name the material name.
|
||||||
|
* @return true if it's a legacy name.
|
||||||
|
*/
|
||||||
|
public static boolean containsLegacy(String name)
|
||||||
|
{
|
||||||
|
String formatted = format(name);
|
||||||
|
return Arrays.stream(Arrays.stream(XMaterial.VALUES).map(m -> m.legacy).toArray(String[]::new))
|
||||||
|
.anyMatch(mat -> parseLegacyVersionMaterialName(mat).equals(formatted));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #matchXMaterial(String, byte)
|
||||||
|
*/
|
||||||
|
public static XMaterial matchXMaterial(Material material)
|
||||||
|
{
|
||||||
|
return matchXMaterial(material.name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see #matchXMaterial(String, byte)
|
||||||
|
*/
|
||||||
|
public static XMaterial matchXMaterial(String name)
|
||||||
|
{
|
||||||
|
// -1 Determines whether the item's data is unknown and only the name is given.
|
||||||
|
// Checking if the item is damageable won't do anything as the data is not going
|
||||||
|
// to be checked in requestOldMaterial anyway.
|
||||||
|
return matchXMaterial(name, (byte) -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the material name and data argument as a {@link Material}.
|
||||||
|
*
|
||||||
|
* @param name name of the material
|
||||||
|
* @param data data of the material
|
||||||
|
*/
|
||||||
|
public static Material parseMaterial(String name, byte data)
|
||||||
|
{
|
||||||
|
return matchXMaterial(name, data).parseMaterial();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param item the ItemStack to match its material and data.
|
||||||
|
* @see #matchXMaterial(String, byte)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public static XMaterial matchXMaterial(ItemStack item)
|
||||||
|
{
|
||||||
|
return isDamageable(item.getType().name()) ? matchXMaterial(item.getType().name(), (byte) 0) :
|
||||||
|
matchXMaterial(item.getType().name(), (byte) item.getDurability());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Matches the argument string and its data with a XMaterial.
|
||||||
|
*
|
||||||
|
* @param name the name of the material
|
||||||
|
* @param data the data byte of the material
|
||||||
|
* @return a XMaterial from the enum (with the same legacy name and data if in
|
||||||
|
* older versions.)
|
||||||
|
*/
|
||||||
|
public static XMaterial matchXMaterial(String name, byte data)
|
||||||
|
{
|
||||||
|
Validate.notEmpty(name, "Material name cannot be null or empty");
|
||||||
|
name = format(name);
|
||||||
|
|
||||||
|
if ((contains(name) && data <= 0))
|
||||||
|
return valueOf(name);
|
||||||
|
return requestOldXMaterial(name, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the XMaterial based on the Material's ID and data. You should avoid
|
||||||
|
* using this for performance reasons.
|
||||||
|
*
|
||||||
|
* @param id the ID (Magic value) of the material.
|
||||||
|
* @param data the data of the material.
|
||||||
|
* @return some XMaterial, or null.
|
||||||
|
*/
|
||||||
|
public static XMaterial matchXMaterial(int id, byte data)
|
||||||
|
{
|
||||||
|
// Looping through Material.values() will take longer.
|
||||||
|
return Arrays.stream(XMaterial.VALUES).filter(mat -> mat.getId() == id && mat.data == data).findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to build the string like an enum name.
|
||||||
|
*
|
||||||
|
* @param name the material name to modify.
|
||||||
|
* @return a Material enum name.
|
||||||
|
*/
|
||||||
|
private static String format(String name)
|
||||||
|
{
|
||||||
|
return name.toUpperCase().replace("MINECRAFT:", "").replace('-', '_').replaceAll("\\s+", "_").replaceAll("\\W",
|
||||||
|
"");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the material name if the legacy name has a version attached to it.
|
||||||
|
*
|
||||||
|
* @param name the material name to parse.
|
||||||
|
* @return the material name with the version removed.
|
||||||
|
*/
|
||||||
|
private static String parseLegacyVersionMaterialName(String name)
|
||||||
|
{
|
||||||
|
if (!name.contains("/"))
|
||||||
|
return name;
|
||||||
|
return name.substring(0, name.indexOf('/'));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the version argument is the same or higher than the current server
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* @param version the version to be checked.
|
||||||
|
* @return true of the version is equal or higher than the current version.
|
||||||
|
*/
|
||||||
|
public static boolean isVersionOrHigher(MinecraftVersion version)
|
||||||
|
{
|
||||||
|
MinecraftVersion current = getVersion();
|
||||||
|
|
||||||
|
if (version == current)
|
||||||
|
return true;
|
||||||
|
if (version == MinecraftVersion.UNKNOWN)
|
||||||
|
return false;
|
||||||
|
if (current == MinecraftVersion.UNKNOWN)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
int ver = Integer.parseInt(version.name().replace("VERSION_", "").replace("_", ""));
|
||||||
|
int currentVer = Integer.parseInt(current.name().replace("VERSION_", "").replace("_", ""));
|
||||||
|
|
||||||
|
return currentVer >= ver;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the material's name to a string with the first letter uppercase.
|
||||||
|
*
|
||||||
|
* @return a converted string.
|
||||||
|
*/
|
||||||
|
public static String toWord(Material material)
|
||||||
|
{
|
||||||
|
return material.name().charAt(0) + material.name().substring(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compares two major versions. The current server version and the given
|
||||||
|
* version.
|
||||||
|
*
|
||||||
|
* @param version the version to check.
|
||||||
|
* @return true if is the same as the current version or higher.
|
||||||
|
*/
|
||||||
|
public static boolean isVersionOrHigher(String version)
|
||||||
|
{
|
||||||
|
int currentVer = Integer.parseInt(getExactMajorVersion(Bukkit.getVersion()).replace(".", ""));
|
||||||
|
int versionNumber = Integer.parseInt(version.replace(".", ""));
|
||||||
|
|
||||||
|
return currentVer >= versionNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the exact major version (..., 1.9, 1.10, ..., 1.14)
|
||||||
|
*
|
||||||
|
* @param version Supports {@link Bukkit#getVersion()},
|
||||||
|
* {@link Bukkit#getBukkitVersion()} and normal formats such as
|
||||||
|
* "1.14"
|
||||||
|
* @return the exact major version.
|
||||||
|
*/
|
||||||
|
public static String getExactMajorVersion(String version)
|
||||||
|
{
|
||||||
|
// getBukkitVersion()
|
||||||
|
if (version.contains("SNAPSHOT") || version.contains("-R"))
|
||||||
|
version = version.substring(0, version.indexOf("-"));
|
||||||
|
// getVersion()
|
||||||
|
if (version.contains("git"))
|
||||||
|
version = version.substring(version.indexOf("MC:") + 4).replace(")", "");
|
||||||
|
if (version.split(Pattern.quote(".")).length > 2)
|
||||||
|
version = version.substring(0, version.lastIndexOf("."));
|
||||||
|
return version;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the string arugment to a version. Supports
|
||||||
|
* {@link Bukkit#getVersion()}, {@link Bukkit#getBukkitVersion()} and normal
|
||||||
|
* formats such as "1.14"
|
||||||
|
*
|
||||||
|
* @param version the server version.
|
||||||
|
* @return the Minecraft version represented by the string.
|
||||||
|
*/
|
||||||
|
private static MinecraftVersion valueOfVersion(String version)
|
||||||
|
{
|
||||||
|
version = getExactMajorVersion(version);
|
||||||
|
if (version.equals("1.10") || version.equals("1.11") || version.equals("1.12"))
|
||||||
|
return MinecraftVersion.VERSION_1_9;
|
||||||
|
version = version.replace(".", "_");
|
||||||
|
if (!version.startsWith("VERSION_"))
|
||||||
|
version = "VERSION_" + version;
|
||||||
|
String check = version;
|
||||||
|
return Arrays.stream(MinecraftVersion.VALUES).anyMatch(v -> v.name().equals(check)) ?
|
||||||
|
MinecraftVersion.valueOf(version) : MinecraftVersion.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the material can be damaged from {@link #DAMAGEABLE}.
|
||||||
|
*
|
||||||
|
* @param name the name of the material.
|
||||||
|
* @return true of the material can be damaged.
|
||||||
|
*/
|
||||||
|
public static boolean isDamageable(String name)
|
||||||
|
{
|
||||||
|
return Arrays.stream(DAMAGEABLE).anyMatch(name::contains);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the ID (Magic value) of the material. If an
|
||||||
|
* {@link IllegalArgumentException} was thrown from this method, you should
|
||||||
|
* definitely report it.
|
||||||
|
*
|
||||||
|
* @return the ID of the material. -1 if it's a new block.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public int getId()
|
||||||
|
{
|
||||||
|
return isNew() ? -1 : this.parseMaterial().getId();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given string matches any of this material's legacy material
|
||||||
|
* names.
|
||||||
|
*
|
||||||
|
* @param name the name to check
|
||||||
|
* @return true if it's one of the legacy names.
|
||||||
|
*/
|
||||||
|
public boolean matchAnyLegacy(String name)
|
||||||
|
{
|
||||||
|
String formatted = format(name);
|
||||||
|
return Arrays.asList(legacy).contains(formatted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the material's name to a string with the first letter uppercase.
|
||||||
|
*
|
||||||
|
* @return a converted string.
|
||||||
|
*/
|
||||||
|
public String toWord()
|
||||||
|
{
|
||||||
|
return name().charAt(0) + name().substring(1).toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the item can be damaged.
|
||||||
|
* @see #isDamageable(String)
|
||||||
|
*/
|
||||||
|
public boolean isDamageable()
|
||||||
|
{
|
||||||
|
return isDamageable(name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the {@link ItemStack} data of this material in older versions. Which can
|
||||||
|
* be accessed with {@link ItemStack#getData()} then MaterialData#getData() or
|
||||||
|
* {@link ItemStack#getDurability()} if not damageable.
|
||||||
|
*
|
||||||
|
* @return data of this material.
|
||||||
|
*/
|
||||||
|
public int getData()
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of materials names that was previously used by older versions.
|
||||||
|
*
|
||||||
|
* @return a list of string of legacy material names.
|
||||||
|
*/
|
||||||
|
public String[] getLegacy()
|
||||||
|
{
|
||||||
|
return legacy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the XMaterial as an {@link ItemStack}.
|
||||||
|
*
|
||||||
|
* @return an ItemStack with the same material (and data if in older versions.)
|
||||||
|
*/
|
||||||
|
public ItemStack parseItem()
|
||||||
|
{
|
||||||
|
return parseItem(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the XMaterial as an {@link ItemStack}.
|
||||||
|
*
|
||||||
|
* @param suggest if true {@link #parseMaterial(boolean)}
|
||||||
|
* @return an ItemStack with the same material (and data if in older versions.)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public ItemStack parseItem(boolean suggest)
|
||||||
|
{
|
||||||
|
Material material = this.parseMaterial(suggest);
|
||||||
|
return isNewVersion() ? new ItemStack(material) : new ItemStack(material, 1, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the XMaterial as a {@link Material}.
|
||||||
|
*
|
||||||
|
* @return the Material related to this XMaterial based on the server version.
|
||||||
|
*/
|
||||||
|
public Material parseMaterial()
|
||||||
|
{
|
||||||
|
return parseMaterial(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the XMaterial as a {@link Material}.
|
||||||
|
*
|
||||||
|
* @param suggest Use a suggested material if the material is added in the new
|
||||||
|
* version.
|
||||||
|
* @return the Material related to this XMaterial based on the server version.
|
||||||
|
* @see #matchXMaterial(String, byte)
|
||||||
|
*/
|
||||||
|
public Material parseMaterial(boolean suggest)
|
||||||
|
{
|
||||||
|
Material newMat = Material.getMaterial(name());
|
||||||
|
|
||||||
|
// If the name is not null it's probably the new version.
|
||||||
|
// So you can still use this name even if it's a duplicated name.
|
||||||
|
// Since duplicated names only apply to older versions.
|
||||||
|
if (newMat != null && (isNewVersion()))
|
||||||
|
return newMat;
|
||||||
|
return requestOldMaterial(suggest);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses from old material names and can accept suggestions.
|
||||||
|
*
|
||||||
|
* @param suggest Accept suggestions for newly added blocks
|
||||||
|
* @return A parsed Material suitable for this minecraft version.
|
||||||
|
*/
|
||||||
|
private Material requestOldMaterial(boolean suggest)
|
||||||
|
{
|
||||||
|
Material oldMat;
|
||||||
|
boolean isNew = getVersionIfNew() != MinecraftVersion.UNKNOWN;
|
||||||
|
for (int i = legacy.length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
String legacyName = legacy[i];
|
||||||
|
// Slash means it's just another name for the material in another version.
|
||||||
|
if (legacyName.contains("/"))
|
||||||
|
{
|
||||||
|
oldMat = Material.getMaterial(parseLegacyVersionMaterialName(legacyName));
|
||||||
|
|
||||||
|
if (oldMat != null)
|
||||||
|
return oldMat;
|
||||||
|
else
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (isNew)
|
||||||
|
{
|
||||||
|
if (suggest)
|
||||||
|
{
|
||||||
|
oldMat = Material.getMaterial(legacyName);
|
||||||
|
if (oldMat != null)
|
||||||
|
return oldMat;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return null;
|
||||||
|
// According to the suggestion format list, all the other names continuing
|
||||||
|
// from here are considered as a "suggestion" if there's no slash anymore.
|
||||||
|
}
|
||||||
|
oldMat = Material.getMaterial(legacyName);
|
||||||
|
if (oldMat != null)
|
||||||
|
return oldMat;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if an item is similar to the material and its data (if in older
|
||||||
|
* versions.)
|
||||||
|
*
|
||||||
|
* @param item item to check.
|
||||||
|
* @return true if the material is the same as the item's material (and data if
|
||||||
|
* in older versions.)
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
|
public boolean isSimilar(ItemStack item)
|
||||||
|
{
|
||||||
|
Objects.requireNonNull(item, "ItemStack cannot be null");
|
||||||
|
Objects.requireNonNull(item.getType(), "ItemStack's material cannot be null");
|
||||||
|
return (isNewVersion() || this.isDamageable()) ? item.getType() == this.parseMaterial() :
|
||||||
|
item.getType() == this.parseMaterial() && item.getDurability() == data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the suggested material names that can be used instead of this material.
|
||||||
|
*
|
||||||
|
* @return a list of suggested material names.
|
||||||
|
*/
|
||||||
|
public String[] getSuggestions()
|
||||||
|
{
|
||||||
|
if (!legacy[0].contains("."))
|
||||||
|
return new String[0];
|
||||||
|
return Arrays.stream(legacy).filter(mat -> !mat.contains(".")).toArray(String[]::new);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this material is supported in the current version. It'll check both
|
||||||
|
* the newest matetrial name and for legacy names.
|
||||||
|
*
|
||||||
|
* @return true if the material exists in {@link Material} list.
|
||||||
|
*/
|
||||||
|
public boolean isSupported()
|
||||||
|
{
|
||||||
|
return Arrays.stream(Material.values())
|
||||||
|
.anyMatch(mat -> mat.name().equals(name()) || matchAnyLegacy(mat.name()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the added version if the material is newly added after the 1.13 Aquatic
|
||||||
|
* Update and higher.
|
||||||
|
*
|
||||||
|
* @return the version which the material was added in.
|
||||||
|
* {@link MinecraftVersion#UNKNOWN} if not new.
|
||||||
|
* @see #isNew()
|
||||||
|
*/
|
||||||
|
public MinecraftVersion getVersionIfNew()
|
||||||
|
{
|
||||||
|
return isNew() ? valueOfVersion(legacy[0]) : MinecraftVersion.UNKNOWN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the material is newly added after the 1.13 Aquatic Update.
|
||||||
|
*
|
||||||
|
* @return true if it was newly added.
|
||||||
|
*/
|
||||||
|
public boolean isNew()
|
||||||
|
{
|
||||||
|
return legacy[0].contains(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the suggested material instead of returning null for unsupported
|
||||||
|
* versions. This is somehow similar to what ProtcolSupport and ViaVersion are
|
||||||
|
* doing to new materials. Don't use this if you want to parse to a
|
||||||
|
* {@link Material}
|
||||||
|
*
|
||||||
|
* @return The suggested material that is similar.
|
||||||
|
* @see #parseMaterial()
|
||||||
|
*/
|
||||||
|
public XMaterial suggestOldMaterialIfNew()
|
||||||
|
{
|
||||||
|
if (getVersionIfNew() == MinecraftVersion.UNKNOWN || legacy.length == 1)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
// We need a loop because: Newest -> Oldest
|
||||||
|
for (int i = legacy.length - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
String legacyName = legacy[i];
|
||||||
|
|
||||||
|
if (legacyName.contains("/"))
|
||||||
|
continue;
|
||||||
|
XMaterial mat = matchXMaterial(parseLegacyVersionMaterialName(legacyName), data);
|
||||||
|
if (mat != null && this != mat)
|
||||||
|
return mat;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Only major versions related to material changes.
|
||||||
|
*/
|
||||||
|
public enum MinecraftVersion
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Bountiful Update
|
||||||
|
*/
|
||||||
|
VERSION_1_8,
|
||||||
|
/**
|
||||||
|
* Combat Update (Pitiful Update?)
|
||||||
|
*/
|
||||||
|
VERSION_1_9,
|
||||||
|
/**
|
||||||
|
* Aquatic Update
|
||||||
|
*/
|
||||||
|
VERSION_1_13,
|
||||||
|
/**
|
||||||
|
* Village Pillage Update
|
||||||
|
*/
|
||||||
|
VERSION_1_14,
|
||||||
|
/**
|
||||||
|
* 1.7 or below. Using {@link #getVersionIfNew()} it means 1.12 or below.
|
||||||
|
*/
|
||||||
|
UNKNOWN;
|
||||||
|
|
||||||
|
public static final MinecraftVersion[] VALUES = MinecraftVersion.values();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user