From 02625b5c0cb9e1857e3aa9910a3998acc528903e Mon Sep 17 00:00:00 2001 From: Carm Date: Wed, 20 Sep 2023 23:39:34 +0800 Subject: [PATCH] =?UTF-8?q?feat(item):=20=E9=87=8D=E6=9E=84=E7=89=A9?= =?UTF-8?q?=E5=93=81=E7=9B=B8=E5=85=B3=E4=BB=A3=E7=A0=81=EF=BC=8C=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E6=9B=B4=E5=A4=9A=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/pom.xml | 2 +- platform/bukkit/pom.xml | 2 +- .../builder/item/ItemConfigBuilder.java | 2 +- .../bukkit/data/ItemConfig.java | 180 ----------- .../bukkit/value/ConfiguredItem.java | 306 ------------------ .../bukkit/value/item/ConfiguredItem.java | 119 +++++++ .../bukkit/value/item/LoreContent.java | 35 ++ .../bukkit/value/item/PreparedItem.java | 247 ++++++++++++++ .../bukkit/src/test/java/LoreInsertTest.java | 38 +-- platform/bungee/pom.xml | 2 +- pom.xml | 2 +- 11 files changed, 421 insertions(+), 514 deletions(-) delete mode 100644 platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/data/ItemConfig.java delete mode 100644 platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/ConfiguredItem.java create mode 100644 platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/ConfiguredItem.java create mode 100644 platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/LoreContent.java create mode 100644 platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/PreparedItem.java diff --git a/common/pom.xml b/common/pom.xml index 15ff34d..fcf1567 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -5,7 +5,7 @@ mineconfiguration-parent cc.carm.lib - 2.8.4 + 2.8.5 4.0.0 diff --git a/platform/bukkit/pom.xml b/platform/bukkit/pom.xml index 6aaa319..453bc6c 100644 --- a/platform/bukkit/pom.xml +++ b/platform/bukkit/pom.xml @@ -5,7 +5,7 @@ mineconfiguration-parent cc.carm.lib - 2.8.4 + 2.8.5 ../../pom.xml 4.0.0 diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/builder/item/ItemConfigBuilder.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/builder/item/ItemConfigBuilder.java index e7b8dc8..b3ae3f5 100644 --- a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/builder/item/ItemConfigBuilder.java +++ b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/builder/item/ItemConfigBuilder.java @@ -2,7 +2,7 @@ package cc.carm.lib.mineconfiguration.bukkit.builder.item; import cc.carm.lib.configuration.core.value.ValueManifest; import cc.carm.lib.mineconfiguration.bukkit.builder.AbstractCraftBuilder; -import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredItem; +import cc.carm.lib.mineconfiguration.bukkit.value.item.ConfiguredItem; import cc.carm.lib.mineconfiguration.common.utils.ParamsUtils; import org.bukkit.Material; import org.bukkit.enchantments.Enchantment; diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/data/ItemConfig.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/data/ItemConfig.java deleted file mode 100644 index 5b27e37..0000000 --- a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/data/ItemConfig.java +++ /dev/null @@ -1,180 +0,0 @@ -package cc.carm.lib.mineconfiguration.bukkit.data; - -import cc.carm.lib.configuration.core.source.ConfigurationWrapper; -import cc.carm.lib.mineconfiguration.bukkit.source.CraftSectionWrapper; -import cc.carm.lib.mineconfiguration.bukkit.utils.TextParser; -import org.bukkit.Material; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.stream.Collectors; - -public class ItemConfig { - - protected @NotNull Material type; - protected short data; - protected @Nullable String name; - protected @NotNull List lore; - - protected @NotNull Map enchants; - protected @NotNull Set flags; - - protected int customModelData = 0; - - public ItemConfig(@NotNull Material type, @Nullable String name) { - this(type, name, Collections.emptyList()); - } - - public ItemConfig(@NotNull Material type, @Nullable String name, @NotNull List lore) { - this(type, (short) 0, name, lore); - } - - public ItemConfig(@NotNull Material type, short damage, - @Nullable String name, @NotNull List lore) { - this(type, damage, name, lore, Collections.emptyMap(), Collections.emptySet()); - } - - public ItemConfig(@NotNull Material type, short damage, - @Nullable String name, @NotNull List lore, - @NotNull Map enchants, - @NotNull Set flags) { - this.type = type; - this.data = damage; - this.name = name; - this.lore = lore; - this.enchants = enchants; - this.flags = flags; - } - - public @NotNull Material getType() { - return type; - } - - public short getData() { - return data; - } - - public @Nullable String getName() { - return name; - } - - public @Nullable String getName(@Nullable Player player, @NotNull Map placeholders) { - return Optional.ofNullable(getName()) - .map(name -> TextParser.parseText(player, name, placeholders)) - .orElse(null); - } - - public @NotNull List getLore() { - return lore; - } - - public @Nullable List getLore(@Nullable Player player, @NotNull Map placeholders) { - if (getLore().isEmpty()) return null; - else return TextParser.parseList(player, getLore(), placeholders); - } - - public final @NotNull ItemStack getItemStack() { - return getItemStack(1); - } - - public @NotNull ItemStack getItemStack(int amount) { - return getItemStack(null, amount, new HashMap<>()); - } - - public @NotNull ItemStack getItemStack(@Nullable Player player) { - return getItemStack(player, new HashMap<>()); - } - - public @NotNull ItemStack getItemStack(@Nullable Player player, @NotNull Map placeholders) { - return getItemStack(player, 1, placeholders); - } - - public @NotNull ItemStack getItemStack(@Nullable Player player, int amount, @NotNull Map placeholders) { - ItemStack item = new ItemStack(type, amount, data); - ItemMeta meta = item.getItemMeta(); - if (meta == null) return item; - Optional.ofNullable(getName(player, placeholders)).ifPresent(meta::setDisplayName); - Optional.ofNullable(getLore(player, placeholders)).ifPresent(meta::setLore); - enchants.forEach((enchant, level) -> meta.addEnchant(enchant, level, true)); - flags.forEach(meta::addItemFlags); - item.setItemMeta(meta); - return item; - } - - public @NotNull Map serialize() { - Map map = new LinkedHashMap<>(); - map.put("type", type.name()); - if (this.data != 0) map.put("data", data); - if (name != null) map.put("name", name); - if (!lore.isEmpty()) map.put("lore", lore); - - Map enchantments = new LinkedHashMap<>(); - enchants.forEach((enchant, level) -> { - if (level > 0) enchantments.put(enchant.getName(), level); - }); - - if (!enchantments.isEmpty()) { - map.put("enchants", enchantments); - } - - if (!flags.isEmpty()) { - map.put("flags", flags.stream().map(ItemFlag::name).collect(Collectors.toList())); - } - return map; - } - - public static @NotNull ItemConfig deserialize(@NotNull ConfigurationSection section) throws Exception { - return deserialize(CraftSectionWrapper.of(section)); - } - - public static @NotNull ItemConfig deserialize(@NotNull ConfigurationWrapper section) throws Exception { - String typeName = section.getString("type"); - if (typeName == null) throw new NullPointerException("Item type name is null"); - - Material type = Material.matchMaterial(typeName); - if (type == null) throw new Exception("Invalid material name: " + typeName); - - short data = section.getShort("data", (short) 0); - String name = section.getString("name"); - List lore = section.getStringList("lore"); - - Map enchantments = readEnchantments(section.getConfigurationSection("enchants")); - Set flags = readFlags(section.getStringList("flags")); - - return new ItemConfig(type, data, name, lore, enchantments, flags); - } - - private static ItemFlag parseFlag(String flagName) { - return Arrays.stream(ItemFlag.values()).filter(flag -> flag.name().equalsIgnoreCase(flagName)).findFirst().orElse(null); - } - - private static Set readFlags(List flagConfig) { - Set flags = new LinkedHashSet<>(); - for (String flagName : flagConfig) { - ItemFlag flag = parseFlag(flagName); - if (flag != null) flags.add(flag); - } - return flags; - } - - private static Map readEnchantments(ConfigurationWrapper section) { - Map enchantments = new LinkedHashMap<>(); - if (section == null) return enchantments; - section.getKeys(false).forEach(key -> { - Enchantment enchantment = Enchantment.getByName(key); - int level = section.getInt(key, 0); - if (enchantment != null && level > 0) { - enchantments.put(enchantment, level); - } - }); - return enchantments; - } - -} diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/ConfiguredItem.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/ConfiguredItem.java deleted file mode 100644 index d8037c8..0000000 --- a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/ConfiguredItem.java +++ /dev/null @@ -1,306 +0,0 @@ -package cc.carm.lib.mineconfiguration.bukkit.value; - -import cc.carm.lib.configuration.core.value.ValueManifest; -import cc.carm.lib.configuration.core.value.type.ConfiguredList; -import cc.carm.lib.configuration.core.value.type.ConfiguredSection; -import cc.carm.lib.mineconfiguration.bukkit.builder.item.ItemConfigBuilder; -import cc.carm.lib.mineconfiguration.bukkit.utils.TextParser; -import cc.carm.lib.mineconfiguration.common.utils.ParamsUtils; -import com.cryptomorin.xseries.XItemStack; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.enchantments.Enchantment; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemFlag; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; -import org.bukkit.inventory.meta.SkullMeta; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class ConfiguredItem extends ConfiguredSection { - - public static final @NotNull Pattern LORE_INSERT_PATTERN = Pattern.compile("^#(.*)#(\\{.*})?$"); - public static final @NotNull Pattern LORE_OFFSET_PATTERN = Pattern.compile("\\{(-?\\d+)(?:,(-?\\d+))?}"); - - public static ItemConfigBuilder create() { - return new ItemConfigBuilder(); - } - - protected final @NotNull String[] params; - - public ConfiguredItem(@NotNull ValueManifest manifest, @NotNull String[] params) { - super( - manifest, ItemStack.class, - (data, v) -> XItemStack.deserialize((ConfigurationSection) data.getSource()), - XItemStack::serialize - ); - this.params = params; - } - - public @NotNull String[] getParams() { - return params; - } - - @Override - public @Nullable ItemStack get() { - return Optional.ofNullable(super.get()).map(ItemStack::clone).orElse(null); - } - - public void modifyItem(Consumer modifier) { - ItemStack item = get(); - if (item == null) return; - modifier.accept(item); - set(item); - } - - public void modifyMeta(Consumer modifier) { - modifyItem(item -> { - ItemMeta meta = item.getItemMeta(); - modifier.accept(meta); - item.setItemMeta(meta); - }); - } - - public void setName(@Nullable String name) { - modifyMeta(meta -> meta.setDisplayName(name)); - } - - public void setLore(@Nullable List lore) { - modifyMeta(meta -> meta.setLore(lore)); - } - - public void setLore(String... lore) { - if (lore.length == 0) setLore((List) null); - else setLore(Arrays.asList(lore)); - } - - public @NotNull PreparedItem prepare(@NotNull Object... values) { - return new PreparedItem(this, values); - } - - public @Nullable ItemStack get(@Nullable Player player) { - return get(player, new HashMap<>()); - } - - public @Nullable ItemStack get(@Nullable Player player, @NotNull Object... values) { - return get(player, ParamsUtils.buildParams(params, values)); - } - - public @Nullable ItemStack get(@Nullable Player player, - @NotNull Object[] values, - @NotNull Map> inserted) { - return get(player, ParamsUtils.buildParams(params, values), inserted); - } - - - public @Nullable ItemStack get(@Nullable Player player, @NotNull String[] params, @NotNull Object[] values) { - return get(player, ParamsUtils.buildParams(params, values)); - } - - public @Nullable ItemStack get(@Nullable Player player, - @NotNull Map placeholders) { - return get(player, placeholders, new HashMap<>()); - } - - public @Nullable ItemStack get(@Nullable Player player, - @NotNull Map placeholders, - @NotNull Map> inserted) { - return get(item -> { - ItemMeta meta = item.getItemMeta(); - if (meta == null) return; - - List lore = insertLore(meta.getLore(), inserted); - if (!lore.isEmpty()) { - meta.setLore(TextParser.parseList(player, lore, placeholders)); - } - - String name = meta.getDisplayName(); - if (!name.isEmpty()) { - meta.setDisplayName(TextParser.parseText(player, name, placeholders)); - } - - item.setItemMeta(meta); - }); - } - - public @Nullable ItemStack get(Consumer modifier) { - return getOptional().map(item -> { - modifier.accept(item); - return item; - }).orElse(null); - } - - public static List insertLore(List original, Map> inserted) { - if (original == null) return Collections.emptyList(); - - List finalLore = new ArrayList<>(); - for (String line : original) { - if (line == null) continue; - - Matcher matcher = LORE_INSERT_PATTERN.matcher(line); - if (!matcher.matches()) { - finalLore.add(line); - } else { - String path = matcher.group(1); - String offset = matcher.group(2); - finalLore.addAll(addLoreOffset(inserted.get(path), offset)); - } - } - - return finalLore; - } - - public static List addLoreOffset(List lore, String offsetSettings) { - if (lore == null || lore.isEmpty()) return Collections.emptyList(); - if (offsetSettings == null) return lore; - - Matcher offsetMatcher = LORE_OFFSET_PATTERN.matcher(offsetSettings); - if (!offsetMatcher.matches()) return lore; - - int upOffset = Optional.ofNullable(offsetMatcher.group(1)).map(Integer::parseInt).orElse(0); - int downOffset = Optional.ofNullable(offsetMatcher.group(2)).map(Integer::parseInt).orElse(0); - - return addLoreOffset(lore, upOffset, downOffset); - } - - public static List addLoreOffset(List lore, int upOffset, int downOffset) { - if (lore == null || lore.isEmpty()) return Collections.emptyList(); - upOffset = Math.max(0, upOffset); - downOffset = Math.max(0, downOffset); - - ArrayList finalLore = new ArrayList<>(lore); - for (int i = 0; i < upOffset; i++) finalLore.add(0, " "); - for (int i = 0; i < downOffset; i++) finalLore.add(finalLore.size(), " "); - - return finalLore; - } - - public static class PreparedItem { - - protected final @NotNull ConfiguredItem itemConfig; - protected final @NotNull Map> insertLore = new HashMap<>(); - - protected @NotNull Object[] values; - - protected @NotNull BiConsumer itemModifier; - protected @NotNull BiConsumer metaModifier; - - protected PreparedItem(@NotNull ConfiguredItem itemConfig, @NotNull Object[] values) { - this.itemConfig = itemConfig; - this.values = values; - itemModifier = (item, player) -> { - }; - metaModifier = (meta, player) -> { - }; - } - - public PreparedItem modifyMeta(@NotNull BiConsumer modifier) { - this.metaModifier = this.metaModifier.andThen(modifier); - return this; - } - - public PreparedItem modifyItem(@NotNull BiConsumer modifier) { - this.itemModifier = this.itemModifier.andThen(modifier); - return this; - } - - public PreparedItem insertLore(String path, List content) { - insertLore.put(path, content); - return this; - } - - public PreparedItem insertLore(String path, String... content) { - return insertLore(path, Arrays.asList(content)); - } - - public PreparedItem insertLore(String path, ConfiguredList content) { - return insertLore(path, content.copy()); - } - - public PreparedItem insertLore(String path, ConfiguredMessage content, Object... params) { - return insertLore(path, content.parse(null, params)); - } - - public PreparedItem insertLore(String path, ConfiguredMessageList content, Object... params) { - return insertLore(path, content.parse(null, params)); - } - - public PreparedItem values(Object... values) { - this.values = values; - return this; - } - - public PreparedItem amount(int amount) { - return modifyItem((item, player) -> item.setAmount(amount)); - } - - public PreparedItem addEnchantment(Enchantment e) { - return addEnchantment(e, 1); - } - - public PreparedItem addEnchantment(Enchantment e, int level) { - return addEnchantment(e, level, true); - } - - public PreparedItem addEnchantment(Enchantment e, int level, boolean ignoreLevelRestriction) { - return modifyMeta((meta, player) -> meta.addEnchant(e, level, ignoreLevelRestriction)); - } - - public PreparedItem addItemFlags(ItemFlag... flags) { - return modifyMeta((meta, player) -> meta.addItemFlags(flags)); - } - - public PreparedItem glow() { - return addItemFlags(ItemFlag.HIDE_ENCHANTS).addEnchantment(Enchantment.DURABILITY); - } - - /** - * @param owner 玩家名 - * @return this - * @deprecated Use {@link #setSkullOwner(OfflinePlayer)} instead. - */ - @Deprecated - public PreparedItem setSkullOwner(String owner) { - return modifyItem((item, player) -> { - if (!(item.getItemMeta() instanceof SkullMeta)) return; - SkullMeta meta = (SkullMeta) item.getItemMeta(); - meta.setOwner(owner); - }); - } - - public PreparedItem setSkullOwner(UUID owner) { - return setSkullOwner(Bukkit.getOfflinePlayer(owner)); - } - - public PreparedItem setSkullOwner(OfflinePlayer owner) { - return modifyItem((item, player) -> { - if (!(item.getItemMeta() instanceof SkullMeta)) return; - SkullMeta meta = (SkullMeta) item.getItemMeta(); - meta.setOwningPlayer(owner); - }); - } - - public @Nullable ItemStack get(Player player) { - return Optional.ofNullable(itemConfig.get(player, values, insertLore)).map(item -> { - itemModifier.accept(item, player); - - ItemMeta meta = item.getItemMeta(); - if (meta == null) return item; - - metaModifier.accept(meta, player); - item.setItemMeta(meta); - - return item; - }).orElse(null); - } - - } -} diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/ConfiguredItem.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/ConfiguredItem.java new file mode 100644 index 0000000..5b3ebb8 --- /dev/null +++ b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/ConfiguredItem.java @@ -0,0 +1,119 @@ +package cc.carm.lib.mineconfiguration.bukkit.value.item; + +import cc.carm.lib.configuration.core.value.ValueManifest; +import cc.carm.lib.configuration.core.value.type.ConfiguredList; +import cc.carm.lib.configuration.core.value.type.ConfiguredSection; +import cc.carm.lib.mineconfiguration.bukkit.builder.item.ItemConfigBuilder; +import cc.carm.lib.mineconfiguration.bukkit.utils.TextParser; +import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessage; +import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessageList; +import cc.carm.lib.mineconfiguration.common.utils.ParamsUtils; +import com.cryptomorin.xseries.XItemStack; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ConfiguredItem extends ConfiguredSection { + + + public static ItemConfigBuilder create() { + return new ItemConfigBuilder(); + } + + protected final @NotNull String[] params; + + public ConfiguredItem(@NotNull ValueManifest manifest, @NotNull String[] params) { + super( + manifest, ItemStack.class, + (data, v) -> XItemStack.deserialize((ConfigurationSection) data.getSource()), + XItemStack::serialize + ); + this.params = params; + } + + public @NotNull String[] getParams() { + return params; + } + + @Override + public @NotNull Optional<@Nullable ItemStack> getOptional() { + return Optional.ofNullable(super.get()); + } + + @Override + public @Nullable ItemStack get() { + return getOptional().map(ItemStack::clone).orElse(null); + } + + public @Nullable ItemStack get(Consumer modifier) { + return getOptional().map(item -> { + modifier.accept(item); + return item; + }).orElse(null); + } + + public @NotNull PreparedItem prepare(@NotNull Object... values) { + return new PreparedItem(this, values); + } + + public @Nullable ItemStack get(@Nullable Player player) { + return get(player, new HashMap<>()); + } + + public @Nullable ItemStack get(@Nullable Player player, @NotNull Object... values) { + return prepare(values).get(player); + } + + public @Nullable ItemStack get(@Nullable Player player, @NotNull String[] params, @NotNull Object[] values) { + return prepare().params(params).values(values).get(player); + } + + public @Nullable ItemStack get(@Nullable Player player, + @NotNull Map placeholders) { + return prepare().placeholders(placeholders).get(player); + } + + + public void modifyItem(Consumer modifier) { + ItemStack item = get(); + if (item == null) return; + modifier.accept(item); + set(item); + } + + public void modifyMeta(Consumer modifier) { + modifyItem(item -> { + ItemMeta meta = item.getItemMeta(); + modifier.accept(meta); + item.setItemMeta(meta); + }); + } + + public void setName(@Nullable String name) { + modifyMeta(meta -> meta.setDisplayName(name)); + } + + public void setLore(@Nullable List lore) { + modifyMeta(meta -> meta.setLore(lore)); + } + + public void setLore(String... lore) { + if (lore.length == 0) setLore((List) null); + else setLore(Arrays.asList(lore)); + } + +} diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/LoreContent.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/LoreContent.java new file mode 100644 index 0000000..4ff2448 --- /dev/null +++ b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/LoreContent.java @@ -0,0 +1,35 @@ +package cc.carm.lib.mineconfiguration.bukkit.value.item; + +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class LoreContent { + + public static LoreContent of(@NotNull List content) { + return of(content, false); + } + + public static LoreContent of(@NotNull List content, boolean original) { + return new LoreContent(content, original); + } + + protected final @NotNull List content; + protected final boolean original; + + public LoreContent(@NotNull List content, boolean original) { + this.content = content; + this.original = original; + } + + + public @NotNull List getContent() { + return content; + } + + public boolean isOriginal() { + return original; + } + + +} diff --git a/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/PreparedItem.java b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/PreparedItem.java new file mode 100644 index 0000000..6e8a893 --- /dev/null +++ b/platform/bukkit/src/main/java/cc/carm/lib/mineconfiguration/bukkit/value/item/PreparedItem.java @@ -0,0 +1,247 @@ +package cc.carm.lib.mineconfiguration.bukkit.value.item; + +import cc.carm.lib.configuration.core.value.type.ConfiguredList; +import cc.carm.lib.mineconfiguration.bukkit.utils.TextParser; +import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessage; +import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredMessageList; +import cc.carm.lib.mineconfiguration.common.utils.ParamsUtils; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.*; +import java.util.function.BiConsumer; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +public class PreparedItem { + + public static final @NotNull Pattern LORE_INSERT_PATTERN = Pattern.compile("^(?:\\{(.*)})?#(.*)#(?:\\{(-?\\d+)(?:,(-?\\d+))?})?$"); + + protected final @NotNull ConfiguredItem itemConfig; + + protected @NotNull Map placeholders = new HashMap<>(); + protected @NotNull String[] params; + protected @NotNull Object[] values; + + protected final @NotNull Map insertLore = new HashMap<>(); + + protected @NotNull BiConsumer itemModifier; + protected @NotNull BiConsumer metaModifier; + + protected PreparedItem(@NotNull ConfiguredItem itemConfig, @NotNull Object[] values) { + this.itemConfig = itemConfig; + this.params = itemConfig.params; + this.values = values; + itemModifier = (item, player) -> { + }; + metaModifier = (meta, player) -> { + }; + } + + public @Nullable ItemStack get(Player player) { + ItemStack item = itemConfig.get(); + if (item == null) return null; + + ItemMeta meta = item.getItemMeta(); + if (meta == null) return item; + + + Map finalPlaceholders = buildPlaceholders(); + + String name = meta.getDisplayName(); + if (!name.isEmpty()) { + meta.setDisplayName(TextParser.parseText(player, name, finalPlaceholders)); + } + + List parsedLore = parseLore(player, meta.getLore(), insertLore, finalPlaceholders); + if (!parsedLore.isEmpty()) { + meta.setLore(parsedLore); + } + + metaModifier.accept(meta, player); + item.setItemMeta(meta); + itemModifier.accept(item, player); + return item; + } + + public PreparedItem handleMeta(@NotNull BiConsumer modifier) { + this.metaModifier = this.metaModifier.andThen(modifier); + return this; + } + + public PreparedItem handleItem(@NotNull BiConsumer modifier) { + this.itemModifier = this.itemModifier.andThen(modifier); + return this; + } + + public PreparedItem params(String[] params) { + this.params = params; + return this; + } + + public PreparedItem values(Object... values) { + this.values = values; + return this; + } + + public PreparedItem placeholders(Map placeholders) { + this.placeholders = placeholders; + return this; + } + + public PreparedItem placeholders(Consumer> consumer) { + Map placeholders = new HashMap<>(); + consumer.accept(placeholders); + return placeholders(placeholders); + } + + public PreparedItem insertLore(String path, LoreContent content) { + insertLore.put(path, content); + return this; + } + + public PreparedItem insertLore(String path, List content) { + return insertLore(path, content, false); + } + + public PreparedItem insertLore(String path, List content, boolean original) { + return insertLore(path, LoreContent.of(content, original)); + } + + public PreparedItem insertLore(String path, String... content) { + return insertLore(path, Arrays.asList(content)); + } + + public PreparedItem insertLore(String path, ConfiguredList content) { + return insertLore(path, content.copy()); + } + + public PreparedItem insertLore(String path, ConfiguredMessage content, Object... params) { + return insertLore(path, content.parse(null, params)); + } + + public PreparedItem insertLore(String path, ConfiguredMessageList content, Object... params) { + return insertLore(path, content.parse(null, params)); + } + + public PreparedItem amount(int amount) { + return handleItem((item, player) -> item.setAmount(amount)); + } + + public PreparedItem addEnchantment(Enchantment e) { + return addEnchantment(e, 1); + } + + public PreparedItem addEnchantment(Enchantment e, int level) { + return addEnchantment(e, level, true); + } + + public PreparedItem addEnchantment(Enchantment e, int level, boolean ignoreLevelRestriction) { + return handleMeta((meta, player) -> meta.addEnchant(e, level, ignoreLevelRestriction)); + } + + public PreparedItem addItemFlags(ItemFlag... flags) { + return handleMeta((meta, player) -> meta.addItemFlags(flags)); + } + + public PreparedItem glow() { + return addItemFlags(ItemFlag.HIDE_ENCHANTS).addEnchantment(Enchantment.DURABILITY); + } + + /** + * @param owner 玩家名 + * @return this + * @deprecated Use {@link #setSkullOwner(OfflinePlayer)} instead. + */ + @Deprecated + public PreparedItem setSkullOwner(String owner) { + return handleItem((item, player) -> { + if (!(item.getItemMeta() instanceof SkullMeta)) return; + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwner(owner); + }); + } + + public PreparedItem setSkullOwner(UUID owner) { + return setSkullOwner(Bukkit.getOfflinePlayer(owner)); + } + + public PreparedItem setSkullOwner(OfflinePlayer owner) { + return handleItem((item, player) -> { + if (!(item.getItemMeta() instanceof SkullMeta)) return; + SkullMeta meta = (SkullMeta) item.getItemMeta(); + meta.setOwningPlayer(owner); + }); + } + + + protected Map buildPlaceholders() { + Map finalPlaceholders = new HashMap<>(); + finalPlaceholders.putAll(ParamsUtils.buildParams(params, values)); + finalPlaceholders.putAll(this.placeholders); + return finalPlaceholders; + } + + public static List parseLore(@Nullable Player player, @Nullable List lore, + @NotNull Map insertedLore, + @NotNull Map placeholders) { + List parsedLore = new ArrayList<>(); + if (lore == null || lore.isEmpty()) return parsedLore; + + for (String line : lore) { + Matcher matcher = PreparedItem.LORE_INSERT_PATTERN.matcher(line); + if (!matcher.matches()) { + parsedLore.add(TextParser.parseText(player, line, placeholders)); + continue; + } + + String path = matcher.group(2); + LoreContent content = insertedLore.get(path); + if (content == null) continue; + + String prefix = matcher.group(1); + int offset1 = Optional.ofNullable(matcher.group(3)) + .map(Integer::parseInt).orElse(0); + Integer offset2 = Optional.ofNullable(matcher.group(4)) + .map(Integer::parseInt).orElse(null); + + List inserted = generateLore( + content.getContent(), prefix, + offset2 == null ? 0 : offset1, offset2 == null ? offset1 : offset2 + ); + + if (content.isOriginal()) { + parsedLore.addAll(inserted); + } else { + parsedLore.addAll(TextParser.parseList(player, inserted, placeholders)); + } + } + return parsedLore; + } + + public static List generateLore(List lore, String prefix, int upOffset, int downOffset) { + if (lore == null || lore.isEmpty()) return Collections.emptyList(); + upOffset = Math.max(0, upOffset); + downOffset = Math.max(0, downOffset); + + String finalPrefix = prefix == null ? "" : prefix; + + ArrayList finalLore = lore.stream().map(s -> finalPrefix + s) + .collect(Collectors.toCollection(ArrayList::new)); + for (int i = 0; i < upOffset; i++) finalLore.add(0, " "); + for (int i = 0; i < downOffset; i++) finalLore.add(finalLore.size(), " "); + + return finalLore; + } + +} \ No newline at end of file diff --git a/platform/bukkit/src/test/java/LoreInsertTest.java b/platform/bukkit/src/test/java/LoreInsertTest.java index 3220389..6c416d3 100644 --- a/platform/bukkit/src/test/java/LoreInsertTest.java +++ b/platform/bukkit/src/test/java/LoreInsertTest.java @@ -1,4 +1,5 @@ -import cc.carm.lib.mineconfiguration.bukkit.value.ConfiguredItem; +import cc.carm.lib.mineconfiguration.bukkit.value.item.LoreContent; +import cc.carm.lib.mineconfiguration.bukkit.value.item.PreparedItem; import org.junit.Test; import java.util.Arrays; @@ -17,47 +18,38 @@ public class LoreInsertTest { "测试lore的第二行", "#click-lore#{1,2}", "测试lore的倒数第二行", + "{--> }#click-lore#{2}", "测试lore的倒数第一行" ); List replace = Arrays.asList("> 插入的点击行1", "> 插入的点击行2"); - Map> inserted = new HashMap<>(); - inserted.put("click-lore", replace); - - System.out.println(ConfiguredItem.insertLore(original, inserted)); + Map inserted = new HashMap<>(); + inserted.put("click-lore", LoreContent.of(replace)); + PreparedItem.parseLore(null, original, inserted, new HashMap<>()).forEach(System.out::println); } @Test public void parse() { - System.out.println(parse("#click-lore#{1,0}")); + System.out.println(parse("{LOVE}#click-lore#{1,0}")); System.out.println(parse("#click-lore#{1,2}")); System.out.println(parse("#click-lore#{1}")); System.out.println(parse("#click-lore#{我}")); } public static String parse(String line) { - Matcher matcher = ConfiguredItem.LORE_INSERT_PATTERN.matcher(line); + Matcher matcher = PreparedItem.LORE_INSERT_PATTERN.matcher(line); if (!matcher.matches()) { - return line; + return "Failed -> [" + line + "]"; } else { - String path = matcher.group(1); - String offset = matcher.group(2); - return "Path -> " + path + " Offset-> " + offset; + String prefix = matcher.group(1); + String path = matcher.group(2); + + String offset1 = matcher.group(3); + String offset2 = matcher.group(4); + return "Prefix -> [" + prefix + "] Path -> [" + path + "] Offset-> [" + offset1 + "/" + offset2 + "]"; } } - @Test - public void offset() { - - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{1,-5}")); - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{1,2}")); - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{1,0}")); - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{2}")); - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{我}")); - System.out.println(ConfiguredItem.addLoreOffset(Arrays.asList("测试lore", "第二行"), "{我,爱你}")); - - } - } diff --git a/platform/bungee/pom.xml b/platform/bungee/pom.xml index 3679815..62d9526 100644 --- a/platform/bungee/pom.xml +++ b/platform/bungee/pom.xml @@ -5,7 +5,7 @@ mineconfiguration-parent cc.carm.lib - 2.8.4 + 2.8.5 ../../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index 3af6027..299e968 100644 --- a/pom.xml +++ b/pom.xml @@ -17,7 +17,7 @@ cc.carm.lib mineconfiguration-parent - 2.8.4 + 2.8.5 pom common