summaryrefslogtreecommitdiffstats
path: root/bukkit/src/main/java
diff options
context:
space:
mode:
authorKrakenied <Krakenied1@gmail.com>2023-11-17 14:46:09 +0100
committerLeonardo Bishop <13875753+LMBishop@users.noreply.github.com>2023-11-26 13:01:22 +0000
commit9043a4d22319d84f9b28169c0c33c47c82c9efdb (patch)
tree4ec7a25f3f574d1746c07c9db9230ad31628dc73 /bukkit/src/main/java
parent9aa600d33ef7537b472a552601a3b8204ce8a07d (diff)
Improve item getters
Implement separate skull getters
Diffstat (limited to 'bukkit/src/main/java')
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java69
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java31
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter13.java231
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter14.java238
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter8.java189
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java270
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java260
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java192
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/BukkitSkullGetter.java54
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/LegacySkullGetter.java71
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/ModernSkullGetter.java31
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/PaperSkullGetter.java38
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/SkullGetter.java49
-rw-r--r--bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/CompatUtils.java6
14 files changed, 984 insertions, 745 deletions
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
index 8cb3652b..49c24b75 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/BukkitQuestsPlugin.java
@@ -15,13 +15,18 @@ import com.leonardobishop.quests.bukkit.hook.coreprotect.CoreProtectHook;
import com.leonardobishop.quests.bukkit.hook.essentials.AbstractEssentialsHook;
import com.leonardobishop.quests.bukkit.hook.essentials.EssentialsHook;
import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter;
-import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetterLatest;
-import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter_1_13;
-import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter_Late_1_8;
+import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter13;
+import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter14;
+import com.leonardobishop.quests.bukkit.hook.itemgetter.ItemGetter8;
import com.leonardobishop.quests.bukkit.hook.papi.AbstractPlaceholderAPIHook;
import com.leonardobishop.quests.bukkit.hook.papi.PlaceholderAPIHook;
import com.leonardobishop.quests.bukkit.hook.playerblocktracker.AbstractPlayerBlockTrackerHook;
import com.leonardobishop.quests.bukkit.hook.playerblocktracker.PlayerBlockTrackerHook;
+import com.leonardobishop.quests.bukkit.hook.skullgetter.BukkitSkullGetter;
+import com.leonardobishop.quests.bukkit.hook.skullgetter.LegacySkullGetter;
+import com.leonardobishop.quests.bukkit.hook.skullgetter.ModernSkullGetter;
+import com.leonardobishop.quests.bukkit.hook.skullgetter.PaperSkullGetter;
+import com.leonardobishop.quests.bukkit.hook.skullgetter.SkullGetter;
import com.leonardobishop.quests.bukkit.hook.title.QuestsTitle;
import com.leonardobishop.quests.bukkit.hook.title.Title_Bukkit;
import com.leonardobishop.quests.bukkit.hook.title.Title_BukkitNoTimings;
@@ -116,6 +121,7 @@ import com.leonardobishop.quests.common.storage.StorageProvider;
import com.leonardobishop.quests.common.tasktype.TaskType;
import com.leonardobishop.quests.common.tasktype.TaskTypeManager;
import com.leonardobishop.quests.common.updater.Updater;
+import com.mojang.authlib.GameProfile;
import net.md_5.bungee.api.ChatMessageType;
import net.md_5.bungee.api.chat.BaseComponent;
import org.bstats.bukkit.MetricsLite;
@@ -169,6 +175,7 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
private AbstractEssentialsHook essentialsHook;
private AbstractPlayerBlockTrackerHook playerBlockTrackerHook;
private ItemGetter itemGetter;
+ private SkullGetter skullGetter;
private QuestsTitle titleHandle;
private QuestsBossBar bossBarHandle;
private QuestsActionBar actionBarHandle;
@@ -293,13 +300,10 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
setActionBarHandle();
// (itemstacks)
- if (version <= 12) {
- itemGetter = new ItemGetter_Late_1_8();
- } else if (version == 13) {
- itemGetter = new ItemGetter_1_13();
- } else {
- itemGetter = new ItemGetterLatest();
- }
+ setItemGetter();
+
+ // (skulls)
+ setSkullGetter();
// (version specific handler)
// TODO move above to version specific handlers
@@ -530,7 +534,6 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
return new ParsedQuestItem("defined", null, getConfiguredItemStack(path, config, excludes));
}
-
public ItemStack getConfiguredItemStack(String path, ConfigurationSection config, ItemGetter.Filter... excludes) {
return itemGetter.getItem(path, config, excludes);
}
@@ -678,6 +681,46 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
actionBarHandle = new ActionBar_Nothing();
}
+ private void setItemGetter() {
+ // Spigot 1.14+
+ if (CompatUtils.classWithMethodExists("org.bukkit.inventory.meta.ItemMeta", "setCustomModelData", Integer.class)) {
+ itemGetter = new ItemGetter14(this);
+ return;
+ }
+
+ // Spigot 1.13+
+ if (CompatUtils.classWithMethodExists("org.bukkit.inventory.meta.ItemMeta", "getAttributeModifiers")) {
+ itemGetter = new ItemGetter13(this);
+ return;
+ }
+
+ // Spigot 1.8+
+ itemGetter = new ItemGetter8(this);
+ }
+
+ private void setSkullGetter() {
+ // Paper 1.12+
+ if (CompatUtils.classExists("com.destroystokyo.paper.profile.PlayerProfile")) {
+ skullGetter = new PaperSkullGetter(this);
+ return;
+ }
+
+ if (CompatUtils.classWithMethodExists("org.bukkit.craftbukkit.{}.inventory.CraftMetaSkull", "setProfile", GameProfile.class)) {
+ // Spigot 1.18.1+
+ if (CompatUtils.classExists("org.bukkit.profile.PlayerProfile")) {
+ skullGetter = new ModernSkullGetter(this);
+ return;
+ }
+
+ // Spigot 1.15.1+
+ skullGetter = new BukkitSkullGetter(this);
+ return;
+ }
+
+ // Spigot 1.8+
+ skullGetter = new LegacySkullGetter(this);
+ }
+
public boolean isValidConfiguration() {
return validConfiguration;
}
@@ -710,6 +753,10 @@ public class BukkitQuestsPlugin extends JavaPlugin implements Quests {
return itemGetter;
}
+ public SkullGetter getSkullGetter() {
+ return skullGetter;
+ }
+
public QuestsTitle getTitleHandle() {
return titleHandle;
}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java
index efbd1a36..999a1461 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter.java
@@ -1,46 +1,55 @@
package com.leonardobishop.quests.bukkit.hook.itemgetter;
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
-public interface ItemGetter {
+public abstract class ItemGetter {
+
+ protected static final ItemStack invalidItemStack = new ItemStack(Material.STONE, 1);
+ protected final BukkitQuestsPlugin plugin;
+
+ public ItemGetter(BukkitQuestsPlugin plugin) {
+ this.plugin = plugin;
+ }
/**
* Gets an ItemStack from a configuration.
* Implementations should specific to the server version.
*
- * @param path the path to where the item is defined in the config (null if item is defined in second param)
- * @param config the configuration file
+ * @param path the path to where the item is defined in the config (null if item is defined in second param)
+ * @param config the configuration file
* @param excludes exclude certain fields in the configuration
* @return {@link ItemStack}
*/
- ItemStack getItem(String path, ConfigurationSection config, Filter... excludes);
+ public abstract ItemStack getItem(String path, ConfigurationSection config, Filter... excludes);
/**
* Gets an ItemStack from a given string (which represents a material).
* For pre-1.13 server implementations, the string may use a data code.
*
- * @param material the string
+ * @param typeString the string
* @return {@link ItemStack}
*/
- ItemStack getItemStack(String material);
+ public abstract ItemStack getItemStack(String typeString);
/**
* Validates a material from a string.
* For pre-1.13 server implementations, the string may use a data code.
*
- * @param material the string
+ * @param typeString the string
* @return true if it a material
*/
- boolean isValidMaterial(String material);
+ public abstract boolean isValidMaterial(String typeString);
- enum Filter {
+ public enum Filter {
DISPLAY_NAME,
LORE,
ENCHANTMENTS,
ITEM_FLAGS,
UNBREAKABLE,
ATTRIBUTE_MODIFIER,
- CUSTOM_MODEL_DATA;
+ CUSTOM_MODEL_DATA
}
-} \ No newline at end of file
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter13.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter13.java
new file mode 100644
index 00000000..57e980ca
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter13.java
@@ -0,0 +1,231 @@
+package com.leonardobishop.quests.bukkit.hook.itemgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.leonardobishop.quests.bukkit.util.chat.Chat;
+import org.bukkit.Material;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeModifier;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemFlag;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Reads the following:
+ * <ul>
+ * <li>type (<b>without</b> data support, <b>without</b> namespace support)</li>
+ * <li>name</li>
+ * <li>lore</li>
+ * <li>enchantments (<b>without</b> namespace support)</li>
+ * <li>item flags</li>
+ * <li>unbreakability</li>
+ * <li>attribute modifiers</li>
+ * </ul>
+ * Requires at least API version 1.13.
+ */
+@SuppressWarnings("DuplicatedCode")
+public class ItemGetter13 extends ItemGetter {
+
+ public ItemGetter13(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ public ItemStack getItem(String path, ConfigurationSection config, Filter... excludes) {
+ config = config.getConfigurationSection(path);
+ if (config == null) {
+ return invalidItemStack;
+ }
+
+ List<Filter> filters = Arrays.asList(excludes);
+
+ // type (without data)
+ String typeString = config.getString("item", config.getString("type"));
+ ItemStack item = getItemStack(typeString);
+ ItemMeta meta = item.getItemMeta();
+
+ // skull
+ if (meta instanceof SkullMeta skullMeta) {
+ String ownerName = config.getString("owner-username");
+ String ownerUniqueIdString = config.getString("owner-uuid");
+ String ownerBase64 = config.getString("owner-base64");
+
+ plugin.getSkullGetter().apply(skullMeta, ownerName, ownerUniqueIdString, ownerBase64);
+ }
+
+ // name
+ String nameString = config.getString("name");
+ if (nameString != null && !filters.contains(Filter.DISPLAY_NAME)) {
+ nameString = Chat.legacyColor(nameString);
+
+ meta.setDisplayName(nameString);
+ }
+
+ // lore
+ List<String> loreStrings = config.getStringList("lore");
+ if (!loreStrings.isEmpty() && !filters.contains(Filter.LORE)) {
+ loreStrings = Chat.legacyColor(loreStrings);
+
+ meta.setLore(loreStrings);
+ }
+
+ // enchantments
+ List<String> enchantmentStrings = config.getStringList("enchantments");
+ if (!enchantmentStrings.isEmpty() && !filters.contains(Filter.ENCHANTMENTS)) {
+ for (String enchantmentString : enchantmentStrings) {
+ String[] parts = enchantmentString.split(":");
+ if (parts.length == 0) {
+ continue;
+ }
+
+ Enchantment enchantment = Enchantment.getByName(parts[0]);
+ if (enchantment == null) {
+ continue;
+ }
+
+ int level;
+ if (parts.length == 2) {
+ try {
+ level = Integer.parseUnsignedInt(parts[1]);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+ } else if (parts.length == 1) {
+ level = 1;
+ } else {
+ continue;
+ }
+
+ meta.addEnchant(enchantment, level, true);
+ }
+ }
+
+ // item flags
+ List<String> itemFlagStrings = config.getStringList("itemflags");
+ if (!itemFlagStrings.isEmpty() && !filters.contains(Filter.ITEM_FLAGS)) {
+ for (String itemFlagString : itemFlagStrings) {
+ ItemFlag itemFlag;
+ try {
+ itemFlag = ItemFlag.valueOf(itemFlagString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ meta.addItemFlags(itemFlag);
+ }
+ }
+
+ // unbreakability
+ boolean unbreakable = config.getBoolean("unbreakable", false);
+ if (unbreakable && !filters.contains(Filter.UNBREAKABLE)) {
+ meta.setUnbreakable(true);
+ }
+
+ // attribute modifiers
+ List<Map<?, ?>> attributeModifierMaps = config.getMapList("attributemodifiers");
+ if (!attributeModifierMaps.isEmpty() && !filters.contains(Filter.ATTRIBUTE_MODIFIER)) {
+ for (Map<?, ?> attributeModifierMap : attributeModifierMaps) {
+ // attribute
+ String attributeString = (String) attributeModifierMap.get("attribute");
+ Attribute attribute;
+ try {
+ attribute = Attribute.valueOf(attributeString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ // modifier (map)
+ Map<?, ?> modifierMap = (Map<?, ?>) attributeModifierMap.get("modifier");
+ if (modifierMap == null) {
+ continue;
+ }
+
+ // modifier unique id
+ String modifierUniqueIdString = (String) modifierMap.get("uuid");
+ UUID modifierUniqueId;
+ try {
+ modifierUniqueId = UUID.fromString(modifierUniqueIdString);
+ } catch (IllegalArgumentException e) {
+ modifierUniqueId = null;
+ }
+
+ // modifier name
+ String modifierName = (String) modifierMap.get("name");
+ if (modifierName == null) {
+ continue;
+ }
+
+ // modifier amount
+ Object modifierAmountObject = modifierMap.get("amount");
+ double modifierAmount;
+ if (modifierAmountObject instanceof Number modifierAmountNumber) {
+ modifierAmount = modifierAmountNumber.doubleValue();
+ } else {
+ continue;
+ }
+
+ // modifier operation
+ String modifierOperationString = (String) modifierMap.get("operation");
+ AttributeModifier.Operation modifierOperation;
+ try {
+ modifierOperation = AttributeModifier.Operation.valueOf(modifierOperationString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ // modifier equipment slot
+ String equipmentSlotString = (String) modifierMap.get("equipmentslot");
+ EquipmentSlot equipmentSlot;
+ try {
+ equipmentSlot = EquipmentSlot.valueOf(equipmentSlotString);
+ } catch (IllegalArgumentException e) {
+ equipmentSlot = null;
+ }
+
+ // modifier (ctor)
+ AttributeModifier modifier;
+ if (modifierUniqueId != null) {
+ if (equipmentSlot != null) {
+ modifier = new AttributeModifier(modifierUniqueId, modifierName, modifierAmount, modifierOperation, equipmentSlot);
+ } else {
+ modifier = new AttributeModifier(modifierUniqueId, modifierName, modifierAmount, modifierOperation);
+ }
+ } else {
+ modifier = new AttributeModifier(modifierName, modifierAmount, modifierOperation);
+ }
+
+ meta.addAttributeModifier(attribute, modifier);
+ }
+ }
+
+ item.setItemMeta(meta);
+ return item;
+ }
+
+ @Override
+ public ItemStack getItemStack(String typeString) {
+ if (typeString == null) {
+ return invalidItemStack;
+ }
+
+ Material type = Material.getMaterial(typeString);
+ if (type == null) {
+ return invalidItemStack;
+ }
+
+ return new ItemStack(type, 1);
+ }
+
+ @Override
+ public boolean isValidMaterial(String typeString) {
+ return Material.getMaterial(typeString) != null;
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter14.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter14.java
new file mode 100644
index 00000000..bdab3ad4
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter14.java
@@ -0,0 +1,238 @@
+package com.leonardobishop.quests.bukkit.hook.itemgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.leonardobishop.quests.bukkit.util.chat.Chat;
+import org.bukkit.Material;
+import org.bukkit.attribute.Attribute;
+import org.bukkit.attribute.AttributeModifier;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemFlag;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+/**
+ * Reads the following:
+ * <ul>
+ * <li>type (<b>without</b> data support, <b>without</b> namespace support)</li>
+ * <li>name</li>
+ * <li>lore</li>
+ * <li>enchantments (<b>without</b> namespace support)</li>
+ * <li>item flags</li>
+ * <li>unbreakability</li>
+ * <li>attribute modifiers</li>
+ * <li>custom model data</li>
+ * </ul>
+ * Requires at least API version 1.14.
+ */
+@SuppressWarnings("DuplicatedCode")
+public class ItemGetter14 extends ItemGetter {
+
+ public ItemGetter14(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ public ItemStack getItem(String path, ConfigurationSection config, Filter... excludes) {
+ config = config.getConfigurationSection(path);
+ if (config == null) {
+ return invalidItemStack;
+ }
+
+ List<Filter> filters = Arrays.asList(excludes);
+
+ // type (without data)
+ String typeString = config.getString("item", config.getString("type"));
+ ItemStack item = getItemStack(typeString);
+ ItemMeta meta = item.getItemMeta();
+
+ // skull
+ if (meta instanceof SkullMeta skullMeta) {
+ String ownerName = config.getString("owner-username");
+ String ownerUniqueIdString = config.getString("owner-uuid");
+ String ownerBase64 = config.getString("owner-base64");
+
+ plugin.getSkullGetter().apply(skullMeta, ownerName, ownerUniqueIdString, ownerBase64);
+ }
+
+ // name
+ String nameString = config.getString("name");
+ if (nameString != null && !filters.contains(Filter.DISPLAY_NAME)) {
+ nameString = Chat.legacyColor(nameString);
+
+ meta.setDisplayName(nameString);
+ }
+
+ // lore
+ List<String> loreStrings = config.getStringList("lore");
+ if (!loreStrings.isEmpty() && !filters.contains(Filter.LORE)) {
+ loreStrings = Chat.legacyColor(loreStrings);
+
+ meta.setLore(loreStrings);
+ }
+
+ // enchantments
+ List<String> enchantmentStrings = config.getStringList("enchantments");
+ if (!enchantmentStrings.isEmpty() && !filters.contains(Filter.ENCHANTMENTS)) {
+ for (String enchantmentString : enchantmentStrings) {
+ String[] parts = enchantmentString.split(":");
+ if (parts.length == 0) {
+ continue;
+ }
+
+ Enchantment enchantment = Enchantment.getByName(parts[0]);
+ if (enchantment == null) {
+ continue;
+ }
+
+ int level;
+ if (parts.length == 2) {
+ try {
+ level = Integer.parseUnsignedInt(parts[1]);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+ } else if (parts.length == 1) {
+ level = 1;
+ } else {
+ continue;
+ }
+
+ meta.addEnchant(enchantment, level, true);
+ }
+ }
+
+ // item flags
+ List<String> itemFlagStrings = config.getStringList("itemflags");
+ if (!itemFlagStrings.isEmpty() && !filters.contains(Filter.ITEM_FLAGS)) {
+ for (String itemFlagString : itemFlagStrings) {
+ ItemFlag itemFlag;
+ try {
+ itemFlag = ItemFlag.valueOf(itemFlagString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ meta.addItemFlags(itemFlag);
+ }
+ }
+
+ // unbreakability
+ boolean unbreakable = config.getBoolean("unbreakable", false);
+ if (unbreakable && !filters.contains(Filter.UNBREAKABLE)) {
+ meta.setUnbreakable(true);
+ }
+
+ // attribute modifiers
+ List<Map<?, ?>> attributeModifierMaps = config.getMapList("attributemodifiers");
+ if (!attributeModifierMaps.isEmpty() && !filters.contains(Filter.ATTRIBUTE_MODIFIER)) {
+ for (Map<?, ?> attributeModifierMap : attributeModifierMaps) {
+ // attribute
+ String attributeString = (String) attributeModifierMap.get("attribute");
+ Attribute attribute;
+ try {
+ attribute = Attribute.valueOf(attributeString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ // modifier (map)
+ Map<?, ?> modifierMap = (Map<?, ?>) attributeModifierMap.get("modifier");
+ if (modifierMap == null) {
+ continue;
+ }
+
+ // modifier unique id
+ String modifierUniqueIdString = (String) modifierMap.get("uuid");
+ UUID modifierUniqueId;
+ try {
+ modifierUniqueId = UUID.fromString(modifierUniqueIdString);
+ } catch (IllegalArgumentException e) {
+ modifierUniqueId = null;
+ }
+
+ // modifier name
+ String modifierName = (String) modifierMap.get("name");
+ if (modifierName == null) {
+ continue;
+ }
+
+ // modifier amount
+ Object modifierAmountObject = modifierMap.get("amount");
+ double modifierAmount;
+ if (modifierAmountObject instanceof Number modifierAmountNumber) {
+ modifierAmount = modifierAmountNumber.doubleValue();
+ } else {
+ continue;
+ }
+
+ // modifier operation
+ String modifierOperationString = (String) modifierMap.get("operation");
+ AttributeModifier.Operation modifierOperation;
+ try {
+ modifierOperation = AttributeModifier.Operation.valueOf(modifierOperationString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ // modifier equipment slot
+ String equipmentSlotString = (String) modifierMap.get("equipmentslot");
+ EquipmentSlot equipmentSlot;
+ try {
+ equipmentSlot = EquipmentSlot.valueOf(equipmentSlotString);
+ } catch (IllegalArgumentException e) {
+ equipmentSlot = null;
+ }
+
+ // modifier (ctor)
+ AttributeModifier modifier;
+ if (modifierUniqueId != null) {
+ if (equipmentSlot != null) {
+ modifier = new AttributeModifier(modifierUniqueId, modifierName, modifierAmount, modifierOperation, equipmentSlot);
+ } else {
+ modifier = new AttributeModifier(modifierUniqueId, modifierName, modifierAmount, modifierOperation);
+ }
+ } else {
+ modifier = new AttributeModifier(modifierName, modifierAmount, modifierOperation);
+ }
+
+ meta.addAttributeModifier(attribute, modifier);
+ }
+ }
+
+ // custom model data
+ Integer customModelData = (Integer) config.get("custommodeldata");
+ if (customModelData != null && !filters.contains(Filter.CUSTOM_MODEL_DATA)) {
+ meta.setCustomModelData(customModelData);
+ }
+
+ item.setItemMeta(meta);
+ return item;
+ }
+
+ @Override
+ public ItemStack getItemStack(String typeString) {
+ if (typeString == null) {
+ return invalidItemStack;
+ }
+
+ Material type = Material.getMaterial(typeString);
+ if (type == null) {
+ return invalidItemStack;
+ }
+
+ return new ItemStack(type, 1);
+ }
+
+ @Override
+ public boolean isValidMaterial(String typeString) {
+ return Material.getMaterial(typeString) != null;
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter8.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter8.java
new file mode 100644
index 00000000..5f3746f4
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter8.java
@@ -0,0 +1,189 @@
+package com.leonardobishop.quests.bukkit.hook.itemgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.leonardobishop.quests.bukkit.util.chat.Chat;
+import org.bukkit.Material;
+import org.bukkit.configuration.ConfigurationSection;
+import org.bukkit.enchantments.Enchantment;
+import org.bukkit.inventory.ItemFlag;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Reads the following:
+ * <ul>
+ * <li>type (<b>with</b> data support, <b>without</b> namespace support)</li>
+ * <li>name</li>
+ * <li>lore</li>
+ * <li>enchantments (<b>without</b> namespace support)</li>
+ * <li>item flags</li>
+ * <li>unbreakability</li>
+ * </ul>
+ * Requires at least API version 1.8.
+ */
+@SuppressWarnings({"deprecation", "DuplicatedCode", "JavaReflectionMemberAccess"})
+public class ItemGetter8 extends ItemGetter {
+
+ private static final Method spigotMethod;
+ private static final Method setUnbreakableMethod;
+
+ static {
+ try {
+ spigotMethod = ItemMeta.class.getMethod("spigot"); // removed in 1.15
+
+ Class<?> spigotClass = Class.forName("org.bukkit.inventory.meta.ItemMeta.Spigot");
+ setUnbreakableMethod = spigotClass.getMethod("setUnbreakable", boolean.class);
+ } catch (ClassNotFoundException | NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public ItemGetter8(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ public ItemStack getItem(String path, ConfigurationSection config, Filter... excludes) {
+ config = config.getConfigurationSection(path);
+ if (config == null) {
+ return invalidItemStack;
+ }
+
+ List<Filter> filters = Arrays.asList(excludes);
+
+ // type (with data)
+ String typeString = config.getString("item", config.getString("type"));
+ ItemStack item = getItemStack(typeString);
+ ItemMeta meta = item.getItemMeta();
+
+ // skull
+ if (meta instanceof SkullMeta skullMeta) {
+ String ownerName = config.getString("owner-username");
+ String ownerUniqueIdString = config.getString("owner-uuid");
+ String ownerBase64 = config.getString("owner-base64");
+
+ plugin.getSkullGetter().apply(skullMeta, ownerName, ownerUniqueIdString, ownerBase64);
+ }
+
+ // name
+ String nameString = config.getString("name");
+ if (nameString != null && !filters.contains(Filter.DISPLAY_NAME)) {
+ nameString = Chat.legacyColor(nameString);
+
+ meta.setDisplayName(nameString);
+ }
+
+ // lore
+ List<String> loreStrings = config.getStringList("lore");
+ if (!loreStrings.isEmpty() && !filters.contains(Filter.LORE)) {
+ loreStrings = Chat.legacyColor(loreStrings);
+
+ meta.setLore(loreStrings);
+ }
+
+ // enchantments
+ List<String> enchantmentStrings = config.getStringList("enchantments");
+ if (!enchantmentStrings.isEmpty() && !filters.contains(Filter.ENCHANTMENTS)) {
+ for (String enchantmentString : enchantmentStrings) {
+ String[] parts = enchantmentString.split(":");
+ if (parts.length == 0) {
+ continue;
+ }
+
+ Enchantment enchantment = Enchantment.getByName(parts[0]);
+ if (enchantment == null) {
+ continue;
+ }
+
+ int level;
+ if (parts.length == 2) {
+ try {
+ level = Integer.parseUnsignedInt(parts[1]);
+ } catch (NumberFormatException e) {
+ continue;
+ }
+ } else if (parts.length == 1) {
+ level = 1;
+ } else {
+ continue;
+ }
+
+ meta.addEnchant(enchantment, level, true);
+ }
+ }
+
+ // item flags
+ List<String> itemFlagStrings = config.getStringList("itemflags");
+ if (!itemFlagStrings.isEmpty() && !filters.contains(Filter.ITEM_FLAGS)) {
+ for (String itemFlagString : itemFlagStrings) {
+ ItemFlag itemFlag;
+ try {
+ itemFlag = ItemFlag.valueOf(itemFlagString);
+ } catch (IllegalArgumentException e) {
+ continue;
+ }
+
+ meta.addItemFlags(itemFlag);
+ }
+ }
+
+ // unbreakability
+ boolean unbreakable = config.getBoolean("unbreakable", false);
+ if (unbreakable && !filters.contains(Filter.UNBREAKABLE)) {
+ try {
+ setUnbreakableMethod.invoke(spigotMethod.invoke(meta), true);
+ } catch (IllegalAccessException | InvocationTargetException ignored) {
+ }
+ }
+
+ item.setItemMeta(meta);
+ return item;
+ }
+
+ @Override
+ public ItemStack getItemStack(String typeString) {
+ if (typeString == null) {
+ return invalidItemStack;
+ }
+
+ Material type = Material.getMaterial(typeString);
+ if (type != null) {
+ return new ItemStack(type, 1);
+ }
+
+ String[] parts = typeString.split(":");
+ if (parts.length != 2) {
+ return invalidItemStack;
+ }
+
+ type = Material.getMaterial(parts[0]);
+ if (type == null) {
+ return invalidItemStack;
+ }
+
+ byte data;
+ try {
+ data = Byte.parseByte(parts[1]);
+ } catch (NumberFormatException ignored) {
+ return invalidItemStack;
+ }
+
+ return new ItemStack(type, 1, (short) 0, data);
+ }
+
+ @Override
+ public boolean isValidMaterial(String typeString) {
+ if (Material.getMaterial(typeString) != null) {
+ return true;
+ }
+
+ String[] parts = typeString.split(":");
+ return parts.length == 2 && Material.getMaterial(parts[0]) != null;
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java
deleted file mode 100644
index a7b4e6a7..00000000
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetterLatest.java
+++ /dev/null
@@ -1,270 +0,0 @@
-package com.leonardobishop.quests.bukkit.hook.itemgetter;
-
-import com.leonardobishop.quests.bukkit.util.chat.Chat;
-import com.mojang.authlib.GameProfile;
-import com.mojang.authlib.properties.Property;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.attribute.AttributeModifier;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.inventory.EquipmentSlot;
-import org.bukkit.inventory.ItemFlag;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.SkullMeta;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-public class ItemGetterLatest implements ItemGetter {
-
- private Field profileField;
-
- /*
- supporting:
- - name
- - material
- - lore
- - enchantments (NamespacedKey)
- - itemflags
- - unbreakable
- - attribute modifier
- - custom model data
-
- requires at least API version 1.14
- */
- @Override
- public ItemStack getItem(String path, ConfigurationSection config, ItemGetter.Filter... excludes) {
- if (path != null && !path.equals("")) {
- path = path + ".";
- }
- List<Filter> filters = Arrays.asList(excludes);
-
- String cName = config.getString(path + "name");
- String cType = config.getString(path + "item", config.getString(path + "type", path + "item"));
- boolean hasCustomModelData = config.contains(path + "custommodeldata");
- int customModelData = config.getInt(path + "custommodeldata", 0);
- boolean unbreakable = config.getBoolean(path + "unbreakable", false);
- List<String> cLore = config.getStringList(path + "lore");
- List<String> cItemFlags = config.getStringList(path + "itemflags");
- boolean hasAttributeModifiers = config.contains(path + "attributemodifiers");
- List<Map<?, ?>> cAttributeModifiers = config.getMapList(path + "attributemodifiers");
-
- // material
- ItemStack is = getItemStack(cType);
- ItemMeta ism = is.getItemMeta();
-
- // skull
- if (is.getType() == Material.PLAYER_HEAD) {
- SkullMeta sm = (SkullMeta) ism;
- String cOwnerBase64 = config.getString(path + "owner-base64");
- String cOwnerUsername = config.getString(path + "owner-username");
- String cOwnerUuid = config.getString(path + "owner-uuid");
- if (cOwnerBase64 != null || cOwnerUsername != null || cOwnerUuid != null) {
- if (cOwnerUsername != null) {
- sm.setOwner(cOwnerUsername);
- } else if (cOwnerUuid != null) {
- try {
- sm.setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(cOwnerUuid)));
- } catch (IllegalArgumentException ignored) { }
- } else {
- GameProfile profile = new GameProfile(UUID.randomUUID(), "");
- profile.getProperties().put("textures", new Property("textures", cOwnerBase64));
- if (profileField == null) {
- try {
- profileField = sm.getClass().getDeclaredField("profile");
- profileField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- }
- try {
- profileField.set(sm, profile);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- // name
- if (!filters.contains(Filter.DISPLAY_NAME)) {
- if (cName != null) {
- ism.setDisplayName(Chat.legacyColor(cName));
- }
- }
-
- // lore
- if (!filters.contains(Filter.LORE)) {
- ism.setLore(Chat.legacyColor(cLore));
- }
-
- // attribute modifiers
- if (!filters.contains(Filter.ATTRIBUTE_MODIFIER)) {
- if (hasAttributeModifiers) {
- for (Map<?, ?> attr : cAttributeModifiers) {
- String cAttribute = (String) attr.get("attribute");
- Attribute attribute = null;
- for (Attribute enumattr : Attribute.values()) {
- if (enumattr.toString().equals(cAttribute)) {
- attribute = enumattr;
- break;
- }
- }
-
- if (attribute == null) continue;
-
- Map<?, ?> configurationSection = (Map<?, ?>) attr.get("modifier");
-
- String cUUID = (String) configurationSection.get("uuid");
- String cModifierName = (String) configurationSection.get("name");
- String cModifierOperation = (String) configurationSection.get("operation");
- double cAmount;
- try {
- Object cAmountObj = configurationSection.get("amount");
- if (cAmountObj instanceof Integer) {
- cAmount = ((Integer) cAmountObj).doubleValue();
- } else {
- cAmount = (Double) cAmountObj;
- }
- } catch (Exception e) {
- cAmount = 1;
- }
- String cEquipmentSlot = (String) configurationSection.get("equipmentslot");
-
- UUID uuid = null;
- if (cUUID != null) {
- try {
- uuid = UUID.fromString(cUUID);
- } catch (Exception ignored) {
- // ignored
- }
- }
- EquipmentSlot equipmentSlot = null;
- if (cEquipmentSlot != null) {
- try {
- equipmentSlot = EquipmentSlot.valueOf(cEquipmentSlot);
- } catch (Exception ignored) {
- // ignored
- }
- }
- AttributeModifier.Operation operation = AttributeModifier.Operation.ADD_NUMBER;
- try {
- operation = AttributeModifier.Operation.valueOf(cModifierOperation);
- } catch (Exception ignored) {
- // ignored
- }
-
- AttributeModifier modifier;
- if (uuid == null) {
- modifier = new AttributeModifier(cModifierName, cAmount, operation);
- } else if (equipmentSlot == null) {
- modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation);
- } else {
- modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation, equipmentSlot);
- }
-
- ism.addAttributeModifier(attribute, modifier);
- }
- }
- }
-
- // item flags
- if (!filters.contains(Filter.ITEM_FLAGS)) {
- if (config.isSet(path + "itemflags")) {
- for (String flag : cItemFlags) {
- for (ItemFlag iflag : ItemFlag.values()) {
- if (iflag.toString().equals(flag)) {
- ism.addItemFlags(iflag);
- break;
- }
- }
- }
- }
- }
-
- // custom model data
- if (!filters.contains(Filter.CUSTOM_MODEL_DATA)) {
- if (hasCustomModelData) {
- ism.setCustomModelData(customModelData);
- }
- }
-
- // unbreakable
- if (!filters.contains(Filter.UNBREAKABLE)) {
- ism.setUnbreakable(unbreakable);
- }
-
- // enchantments
- if (!filters.contains(Filter.ENCHANTMENTS)) {
- if (config.isSet(path + "enchantments")) {
- for (String key : config.getStringList(path + "enchantments")) {
- String[] split = key.split(":");
- if (split.length < 2) {
- continue;
- }
- String namespace = split[0];
- String ench = split[1];
- String levelName;
- if (split.length >= 3) {
- levelName = split[2];
- } else {
- levelName = "1";
- }
-
- // TODO i don't know how these namespaces work
-// NamespacedKey namespacedKey;
-// try {
-// namespacedKey = new NamespacedKey(namespace, ench);
-// } catch (Exception e) {
-// plugin.getQuestsLogger().debug("Unrecognised namespace: " + namespace);
-// e.printStackTrace();
-// continue;
-// }
- Enchantment enchantment;
- if ((enchantment = Enchantment.getByName(ench)) == null) {
- continue;
- }
-
- int level;
- try {
- level = Integer.parseInt(levelName);
- } catch (NumberFormatException e) {
- level = 1;
- }
-
- ism.addEnchant(enchantment, level, true);
- }
- }
- }
-
- is.setItemMeta(ism);
- return is;
- }
-
- @Override
- public ItemStack getItemStack(String material) {
- Material type;
- try {
- type = Material.valueOf(material);
- } catch (Exception e) {
- type = Material.STONE;
- }
- return new ItemStack(type, 1);
- }
-
- @Override
- public boolean isValidMaterial(String material) {
- try {
- Material.valueOf(material);
- return true;
- } catch (IllegalArgumentException ex) {
- return false;
- }
- }
-}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java
deleted file mode 100644
index 4d77427c..00000000
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_1_13.java
+++ /dev/null
@@ -1,260 +0,0 @@
-package com.leonardobishop.quests.bukkit.hook.itemgetter;
-
-import com.leonardobishop.quests.bukkit.util.chat.Chat;
-import com.mojang.authlib.GameProfile;
-import com.mojang.authlib.properties.Property;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.attribute.Attribute;
-import org.bukkit.attribute.AttributeModifier;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.inventory.EquipmentSlot;
-import org.bukkit.inventory.ItemFlag;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.SkullMeta;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.UUID;
-
-public class ItemGetter_1_13 implements ItemGetter {
-
- private Field profileField;
-
- /*
- reads the following:
- - name
- - material
- - lore
- - enchantments (NamespacedKey)
- - itemflags
- - unbreakable
- - attribute modifier
-
- requires at least API version 1.13
- */
- @Override
- public ItemStack getItem(String path, ConfigurationSection config, ItemGetter.Filter... excludes) {
- if (path != null && !path.equals("")) {
- path = path + ".";
- }
- List<Filter> filters = Arrays.asList(excludes);
-
- String cName = config.getString(path + "name");
- String cType = config.getString(path + "item", config.getString(path + "type", path + "item"));
- boolean unbreakable = config.getBoolean(path + "unbreakable", false);
- List<String> cLore = config.getStringList(path + "lore");
- List<String> cItemFlags = config.getStringList(path + "itemflags");
- boolean hasAttributeModifiers = config.contains(path + "attributemodifiers");
- List<Map<?, ?>> cAttributeModifiers = config.getMapList(path + "attributemodifiers");
-
- // material
- ItemStack is = getItemStack(cType);
- ItemMeta ism = is.getItemMeta();
-
- // skull
- if (is.getType() == Material.PLAYER_HEAD) {
- SkullMeta sm = (SkullMeta) ism;
- String cOwnerBase64 = config.getString(path + "owner-base64");
- String cOwnerUsername = config.getString(path + "owner-username");
- String cOwnerUuid = config.getString(path + "owner-uuid");
- if (cOwnerBase64 != null || cOwnerUsername != null || cOwnerUuid != null) {
- if (cOwnerUsername != null) {
- sm.setOwner(cOwnerUsername);
- } else if (cOwnerUuid != null) {
- try {
- sm.setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(cOwnerUuid)));
- } catch (IllegalArgumentException ignored) { }
- } else {
- GameProfile profile = new GameProfile(UUID.randomUUID(), "");
- profile.getProperties().put("textures", new Property("textures", cOwnerBase64));
- if (profileField == null) {
- try {
- profileField = sm.getClass().getDeclaredField("profile");
- profileField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- }
- try {
- profileField.set(sm, profile);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- // name
- if (!filters.contains(Filter.DISPLAY_NAME)) {
- if (cName != null) {
- ism.setDisplayName(Chat.legacyColor(cName));
- }
- }
-
- // lore
- if (!filters.contains(Filter.LORE)) {
- ism.setLore(Chat.legacyColor(cLore));
- }
-
- // attribute modifiers
- if (!filters.contains(Filter.ATTRIBUTE_MODIFIER)) {
- if (hasAttributeModifiers) {
- for (Map<?, ?> attr : cAttributeModifiers) {
- String cAttribute = (String) attr.get("attribute");
- Attribute attribute = null;
- for (Attribute enumattr : Attribute.values()) {
- if (enumattr.toString().equals(cAttribute)) {
- attribute = enumattr;
- break;
- }
- }
-
- if (attribute == null) continue;
-
- Map<?, ?> configurationSection = (Map<?, ?>) attr.get("modifier");
-
- String cUUID = (String) configurationSection.get("uuid");
- String cModifierName = (String) configurationSection.get("name");
- String cModifierOperation = (String) configurationSection.get("operation");
- double cAmount;
- try {
- Object cAmountObj = configurationSection.get("amount");
- if (cAmountObj instanceof Integer) {
- cAmount = ((Integer) cAmountObj).doubleValue();
- } else {
- cAmount = (Double) cAmountObj;
- }
- } catch (Exception e) {
- cAmount = 1;
- }
- String cEquipmentSlot = (String) configurationSection.get("equipmentslot");
-
- UUID uuid = null;
- if (cUUID != null) {
- try {
- uuid = UUID.fromString(cUUID);
- } catch (Exception ignored) {
- // ignored
- }
- }
- EquipmentSlot equipmentSlot = null;
- if (cEquipmentSlot != null) {
- try {
- equipmentSlot = EquipmentSlot.valueOf(cEquipmentSlot);
- } catch (Exception ignored) {
- // ignored
- }
- }
- AttributeModifier.Operation operation = AttributeModifier.Operation.ADD_NUMBER;
- try {
- operation = AttributeModifier.Operation.valueOf(cModifierOperation);
- } catch (Exception ignored) {
- // ignored
- }
-
- AttributeModifier modifier;
- if (uuid == null) {
- modifier = new AttributeModifier(cModifierName, cAmount, operation);
- } else if (equipmentSlot == null) {
- modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation);
- } else {
- modifier = new AttributeModifier(uuid, cModifierName, cAmount, operation, equipmentSlot);
- }
-
- ism.addAttributeModifier(attribute, modifier);
- }
- }
- }
-
- // item flags
- if (!filters.contains(Filter.ITEM_FLAGS)) {
- if (config.isSet(path + "itemflags")) {
- for (String flag : cItemFlags) {
- for (ItemFlag iflag : ItemFlag.values()) {
- if (iflag.toString().equals(flag)) {
- ism.addItemFlags(iflag);
- break;
- }
- }
- }
- }
- }
-
- // unbreakable
- if (!filters.contains(Filter.UNBREAKABLE)) {
- ism.setUnbreakable(unbreakable);
- }
-
- // enchantments
- if (!filters.contains(Filter.ENCHANTMENTS)) {
- if (config.isSet(path + "enchantments")) {
- for (String key : config.getStringList(path + "enchantments")) {
- String[] split = key.split(":");
- if (split.length < 2) {
- continue;
- }
- String namespace = split[0];
- String ench = split[1];
- String levelName;
- if (split.length >= 3) {
- levelName = split[2];
- } else {
- levelName = "1";
- }
-
- // TODO i don't know how these namespaces work
-// NamespacedKey namespacedKey;
-// try {
-// namespacedKey = new NamespacedKey(namespace, ench);
-// } catch (Exception e) {
-// plugin.getQuestsLogger().debug("Unrecognised namespace: " + namespace);
-// e.printStackTrace();
-// continue;
-// }
- Enchantment enchantment;
- if ((enchantment = Enchantment.getByName(ench)) == null) {
- continue;
- }
-
- int level;
- try {
- level = Integer.parseInt(levelName);
- } catch (NumberFormatException e) {
- level = 1;
- }
-
- is.addUnsafeEnchantment(enchantment, level);
- }
- }
- }
-
- is.setItemMeta(ism);
- return is;
- }
-
- @Override
- public ItemStack getItemStack(String material) {
- Material type;
- try {
- type = Material.valueOf(material);
- } catch (Exception e) {
- type = Material.STONE;
- }
- return new ItemStack(type, 1);
- }
-
- @Override
- public boolean isValidMaterial(String material) {
- try {
- Material.valueOf(material);
- return true;
- } catch (IllegalArgumentException ex) {
- return false;
- }
- }
-}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java
deleted file mode 100644
index fbef12d8..00000000
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/itemgetter/ItemGetter_Late_1_8.java
+++ /dev/null
@@ -1,192 +0,0 @@
-package com.leonardobishop.quests.bukkit.hook.itemgetter;
-
-import com.leonardobishop.quests.bukkit.util.StringUtils;
-import com.leonardobishop.quests.bukkit.util.chat.Chat;
-import com.mojang.authlib.GameProfile;
-import com.mojang.authlib.properties.Property;
-import org.bukkit.Bukkit;
-import org.bukkit.Material;
-import org.bukkit.configuration.ConfigurationSection;
-import org.bukkit.enchantments.Enchantment;
-import org.bukkit.inventory.ItemFlag;
-import org.bukkit.inventory.ItemStack;
-import org.bukkit.inventory.meta.ItemMeta;
-import org.bukkit.inventory.meta.SkullMeta;
-
-import java.lang.reflect.Field;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.regex.Pattern;
-
-public class ItemGetter_Late_1_8 implements ItemGetter {
-
- private Field profileField;
-
- /*
- reads the following:
- - name
- - material (+ DATA)
- - lore
- - enchantments (NOT NamespacedKey)
- - itemflags
-
- requires at least API version 1.8 (?)
- */
- @Override
- public ItemStack getItem(String path, ConfigurationSection config, Filter... excludes) {
- if (path != null && !path.equals("")) {
- path = path + ".";
- }
- List<Filter> filters = Arrays.asList(excludes);
-
-
- String cName = config.getString(path + "name");
- String cType = config.getString(path + "item", config.getString(path + "type", path + "item"));
- List<String> cLore = config.getStringList(path + "lore");
- List<String> cItemFlags = config.getStringList(path + "itemflags");
-
- // material
- ItemStack is = getItemStack(cType);
- ItemMeta ism = is.getItemMeta();
-
- // skull
-
- // skull
- if (is.getType().toString().equals("SKULL_ITEM")) {
- SkullMeta sm = (SkullMeta) ism;
- String cOwnerBase64 = config.getString(path + "owner-base64");
- String cOwnerUsername = config.getString(path + "owner-username");
- String cOwnerUuid = config.getString(path + "owner-uuid");
- if (cOwnerBase64 != null || cOwnerUsername != null || cOwnerUuid != null) {
- if (cOwnerUsername != null) {
- sm.setOwner(cOwnerUsername);
- } else if (cOwnerUuid != null) {
- try {
- sm.setOwningPlayer(Bukkit.getOfflinePlayer(UUID.fromString(cOwnerUuid)));
- } catch (IllegalArgumentException ignored) { }
- } else {
- GameProfile profile = new GameProfile(UUID.randomUUID(), "");
- profile.getProperties().put("textures", new Property("textures", cOwnerBase64));
- if (profileField == null) {
- try {
- profileField = sm.getClass().getDeclaredField("profile");
- profileField.setAccessible(true);
- } catch (NoSuchFieldException e) {
- e.printStackTrace();
- }
- }
- try {
- profileField.set(sm, profile);
- } catch (IllegalAccessException e) {
- e.printStackTrace();
- }
- }
- }
- }
-
- // lore
- if (!filters.contains(Filter.LORE)) {
- ism.setLore(Chat.legacyColor(cLore));
- }
-
- // name
- if (!filters.contains(Filter.DISPLAY_NAME)) {
- if (cName != null) {
- ism.setDisplayName(Chat.legacyColor(cName));
- }
- }
-
-
- // item flags
- if (!filters.contains(Filter.ITEM_FLAGS)) {
- if (config.isSet(path + "itemflags")) {
- for (String flag : cItemFlags) {
- for (ItemFlag iflag : ItemFlag.values()) {
- if (iflag.toString().equals(flag)) {
- ism.addItemFlags(iflag);
- break;
- }
- }
- }
- }
- }
-
- // enchantments
- if (!filters.contains(Filter.ENCHANTMENTS)) {
- if (config.isSet(path + "enchantments")) {
- for (String key : config.getStringList(path + "enchantments")) {
- String[] split = key.split(":");
- String ench = split[0];
- String levelName;
- if (split.length >= 2) {
- levelName = split[1];
- } else {
- levelName = "1";
- }
-
- Enchantment enchantment;
- if ((enchantment = Enchantment.getByName(ench)) == null) {
- continue;
- }
-
- int level;
- try {
- level = Integer.parseInt(levelName);
- } catch (NumberFormatException e) {
- level = 1;
- }
-
- ism.addEnchant(enchantment, level, true);
- }
- }
- }
-
- is.setItemMeta(ism);
- return is;
- }
-
-
- @Override
- public ItemStack getItemStack(String material) {
- Material type = null;
- int data = 0;
-
- if (Material.getMaterial(material) != null) {
- type = Material.getMaterial(material);
- } else if (material.contains(":")) {
- String[] parts = material.split(Pattern.quote(":"));
- if (parts.length > 1) {
- if (Material.getMaterial(parts[0]) != null) {
- type = Material.getMaterial(parts[0]);
- }
- if (StringUtils.isNumeric(parts[1])) {
- data = Integer.parseInt(parts[1]);
- }
- }
- }
-
- if (type == null) {
- type = Material.STONE;
- }
- return new ItemStack(type, 1, (short) data);
- }
-
- @Override
- public boolean isValidMaterial(String material) {
- Material type = null;
-
- if (Material.getMaterial(material) != null) {
- type = Material.getMaterial(material);
- } else if (material.contains(":")) {
- String[] parts = material.split(Pattern.quote(":"));
- if (parts.length > 1) {
- if (Material.getMaterial(parts[0]) != null) {
- type = Material.getMaterial(parts[0]);
- }
- }
- }
-
- return !(type == null);
- }
-}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/BukkitSkullGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/BukkitSkullGetter.java
new file mode 100644
index 00000000..1390c5d5
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/BukkitSkullGetter.java
@@ -0,0 +1,54 @@
+package com.leonardobishop.quests.bukkit.hook.skullgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import org.bukkit.Bukkit;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+/**
+ * Utilises reflection to set {@link SkullMeta} {@code profile} field value using a dedicated method.
+ */
+@SuppressWarnings("deprecation")
+public class BukkitSkullGetter extends SkullGetter {
+
+ private static Method setProfileMethod; // introduced by Bukkit in 1.15.1
+
+ public BukkitSkullGetter(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ void applyName(SkullMeta meta, String name) {
+ meta.setOwner(name);
+ }
+
+ @Override
+ void applyUniqueId(SkullMeta meta, UUID uniqueId) {
+ meta.setOwningPlayer(Bukkit.getOfflinePlayer(uniqueId));
+ }
+
+ @Override
+ void applyBase64(SkullMeta meta, String base64) {
+ if (setProfileMethod == null) {
+ try {
+ setProfileMethod = meta.getClass().getDeclaredMethod("setProfile", GameProfile.class);
+ setProfileMethod.setAccessible(true);
+ } catch (NoSuchMethodException ignored) {
+ return;
+ }
+ }
+
+ GameProfile profile = new GameProfile(UUID.randomUUID(), "");
+ profile.getProperties().put("textures", new Property("textures", base64));
+
+ try {
+ setProfileMethod.invoke(meta, profile);
+ } catch (IllegalAccessException | InvocationTargetException ignored) {
+ }
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/LegacySkullGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/LegacySkullGetter.java
new file mode 100644
index 00000000..6e7de8d0
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/LegacySkullGetter.java
@@ -0,0 +1,71 @@
+package com.leonardobishop.quests.bukkit.hook.skullgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.properties.Property;
+import org.bukkit.Bukkit;
+import org.bukkit.OfflinePlayer;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.UUID;
+
+/**
+ * Utilises reflection to set {@link SkullMeta} {@code profile} field value.
+ */
+public class LegacySkullGetter extends SkullGetter {
+
+ private static Field profileField;
+ private static Method setOwningPlayerMethod; // introduced in 1.12.1
+
+ static {
+ try {
+ setOwningPlayerMethod = SkullMeta.class.getDeclaredMethod("setOwningPlayer", OfflinePlayer.class);
+ } catch (NoSuchMethodException ignored) {
+ }
+ }
+
+ public LegacySkullGetter(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @SuppressWarnings("deprecation")
+ @Override
+ void applyName(SkullMeta meta, String name) {
+ meta.setOwner(name);
+ }
+
+ @Override
+ void applyUniqueId(SkullMeta meta, UUID uniqueId) {
+ if (setOwningPlayerMethod == null) {
+ return;
+ }
+
+ try {
+ setOwningPlayerMethod.invoke(meta, Bukkit.getOfflinePlayer(uniqueId));
+ } catch (IllegalAccessException | InvocationTargetException ignored) {
+ }
+ }
+
+ @Override
+ void applyBase64(SkullMeta meta, String base64) {
+ if (profileField == null) {
+ try {
+ profileField = meta.getClass().getDeclaredField("profile");
+ profileField.setAccessible(true);
+ } catch (NoSuchFieldException e) {
+ return;
+ }
+ }
+
+ GameProfile profile = new GameProfile(UUID.randomUUID(), "");
+ profile.getProperties().put("textures", new Property("textures", base64));
+
+ try {
+ profileField.set(meta, profile);
+ } catch (IllegalAccessException ignored) {
+ }
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/ModernSkullGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/ModernSkullGetter.java
new file mode 100644
index 00000000..fc02f836
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/ModernSkullGetter.java
@@ -0,0 +1,31 @@
+package com.leonardobishop.quests.bukkit.hook.skullgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import org.bukkit.Bukkit;
+import org.bukkit.inventory.meta.SkullMeta;
+import org.bukkit.profile.PlayerProfile;
+
+import java.util.UUID;
+
+/**
+ * Utilises {@link PlayerProfile} and {@link Bukkit#createPlayerProfile(UUID, String)} introduced by Bukkit in 1.18.1
+ */
+@SuppressWarnings("deprecation")
+public class ModernSkullGetter extends BukkitSkullGetter {
+
+ public ModernSkullGetter(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ void applyName(SkullMeta meta, String name) {
+ PlayerProfile profile = Bukkit.createPlayerProfile(null, name);
+ meta.setOwnerProfile(profile);
+ }
+
+ @Override
+ void applyUniqueId(SkullMeta meta, UUID uniqueId) {
+ PlayerProfile profile = Bukkit.createPlayerProfile(uniqueId, null);
+ meta.setOwnerProfile(profile);
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/PaperSkullGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/PaperSkullGetter.java
new file mode 100644
index 00000000..ed574662
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/PaperSkullGetter.java
@@ -0,0 +1,38 @@
+package com.leonardobishop.quests.bukkit.hook.skullgetter;
+
+import com.destroystokyo.paper.profile.PlayerProfile;
+import com.destroystokyo.paper.profile.ProfileProperty;
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import org.bukkit.Bukkit;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.util.UUID;
+
+/**
+ * Utilises {@link PlayerProfile} and {@link Bukkit#createProfile(UUID, String)} introduced by Paper in 1.12
+ */
+public class PaperSkullGetter extends SkullGetter {
+
+ public PaperSkullGetter(BukkitQuestsPlugin plugin) {
+ super(plugin);
+ }
+
+ @Override
+ void applyName(SkullMeta meta, String name) {
+ PlayerProfile profile = Bukkit.getServer().createProfile(null, name);
+ meta.setPlayerProfile(profile);
+ }
+
+ @Override
+ void applyUniqueId(SkullMeta meta, UUID uniqueId) {
+ PlayerProfile profile = Bukkit.getServer().createProfile(uniqueId, null);
+ meta.setPlayerProfile(profile);
+ }
+
+ @Override
+ void applyBase64(SkullMeta meta, String base64) {
+ PlayerProfile profile = Bukkit.getServer().createProfile(UUID.randomUUID(), null);
+ profile.setProperty(new ProfileProperty("textures", base64));
+ meta.setPlayerProfile(profile);
+ }
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/SkullGetter.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/SkullGetter.java
new file mode 100644
index 00000000..82958ddc
--- /dev/null
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/hook/skullgetter/SkullGetter.java
@@ -0,0 +1,49 @@
+package com.leonardobishop.quests.bukkit.hook.skullgetter;
+
+import com.leonardobishop.quests.bukkit.BukkitQuestsPlugin;
+import org.bukkit.inventory.meta.SkullMeta;
+
+import java.util.UUID;
+
+public abstract class SkullGetter {
+
+ protected final BukkitQuestsPlugin plugin;
+
+ public SkullGetter(BukkitQuestsPlugin plugin) {
+ this.plugin = plugin;
+ }
+
+ public final boolean apply(SkullMeta meta, String name, String uniqueIdString, String base64) {
+ if (name != null) {
+ applyName(meta, name);
+ return true;
+ }
+
+ if (uniqueIdString != null) {
+ UUID uniqueId;
+ try {
+ uniqueId = UUID.fromString(uniqueIdString);
+ } catch (IllegalArgumentException e) {
+ uniqueId = null;
+ }
+
+ if (uniqueId != null) {
+ applyUniqueId(meta, uniqueId);
+ return true;
+ }
+ }
+
+ if (base64 != null) {
+ applyBase64(meta, base64);
+ return true;
+ }
+
+ return false;
+ }
+
+ abstract void applyName(SkullMeta meta, String name);
+
+ abstract void applyUniqueId(SkullMeta meta, UUID uniqueId);
+
+ abstract void applyBase64(SkullMeta meta, String base64);
+}
diff --git a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/CompatUtils.java b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/CompatUtils.java
index e550c509..e6609b44 100644
--- a/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/CompatUtils.java
+++ b/bukkit/src/main/java/com/leonardobishop/quests/bukkit/util/CompatUtils.java
@@ -5,6 +5,8 @@ import org.bukkit.plugin.Plugin;
public class CompatUtils {
+ private static final String version = Bukkit.getServer().getClass().getPackage().getName().replace(".", ",").split(",")[3];
+
public static boolean classExists(String className) {
try {
Class.forName(className);
@@ -15,8 +17,10 @@ public class CompatUtils {
}
public static boolean classWithMethodExists(String className, String methodName, Class<?>... methodParameterTypes) {
+ className = className.replace("{}", version);
+
try {
- Class.forName(className).getMethod(methodName, methodParameterTypes);
+ Class.forName(className).getDeclaredMethod(methodName, methodParameterTypes);
return true;
} catch (ClassNotFoundException | NoSuchMethodException e) {
return false;