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