diff --git a/bukkit/build.gradle b/bukkit/build.gradle
index 49355f55d..42ff68c81 100644
--- a/bukkit/build.gradle
+++ b/bukkit/build.gradle
@@ -52,7 +52,7 @@ repositories {
dependencies {
compileOnly project(':common')
// Paper
- compileOnly('io.papermc.paper:paper-api:1.20.1-R0.1-SNAPSHOT') {
+ compileOnly('io.papermc.paper:paper-api:1.20.2-R0.1-SNAPSHOT') {
exclude(group: 'it.unimi.dsi', module: 'fastutil') // exclude fastutil just to don't use it (for 1.8 support)
}
// Folia
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 8cb3652bc..49c24b75f 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.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.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 void onEnable() {
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 QuestItem getConfiguredQuestItem(String path, ConfigurationSection config
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 @@ private void setActionBarHandle() {
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 ItemGetter getItemGetter() {
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 efbd1a369..999a14610 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 000000000..57e980ca8
--- /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:
+ *
+ * - type (without data support, without namespace support)
+ * - name
+ * - lore
+ * - enchantments (without namespace support)
+ * - item flags
+ * - unbreakability
+ * - attribute modifiers
+ *
+ * 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 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 loreStrings = config.getStringList("lore");
+ if (!loreStrings.isEmpty() && !filters.contains(Filter.LORE)) {
+ loreStrings = Chat.legacyColor(loreStrings);
+
+ meta.setLore(loreStrings);
+ }
+
+ // enchantments
+ List 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 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