From fa097127cd2aaf2b128e1e359bd93f78ecabbe89 Mon Sep 17 00:00:00 2001 From: Jules Date: Mon, 20 Jan 2025 21:30:43 +0100 Subject: [PATCH] Basic support for array edition in UI --- .../mmoitems/gui/edition/ItemEdition.java | 295 +++++++++++++----- .../java/net/Indyuce/mmoitems/stat/Lore.java | 1 + .../Indyuce/mmoitems/stat/RequiredClass.java | 27 +- .../Indyuce/mmoitems/stat/UpgradeStat.java | 4 +- .../component/builtin/BooleanComponent.java | 10 + .../component/builtin/DoubleComponent.java | 10 + .../component/builtin/IntegerComponent.java | 7 +- .../component/builtin/StringComponent.java | 5 + .../builtin/composite/ColorComponent.java | 6 +- .../builtin/composite/CommandComponent.java | 24 +- .../builtin/composite/SoulboundComponent.java | 2 +- .../builtin/composite/UpgradeComponent.java | 172 ++++++---- .../component/model/builtin/ArrayModel.java | 9 + .../stat/component/type/ComponentType.java | 8 +- .../type/builtin/ArrayComponentType.java | 16 +- .../type/builtin/MapComponentType.java | 7 + .../listener/reforging/RFGKeepUpgrades.java | 4 +- 17 files changed, 435 insertions(+), 172 deletions(-) diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/gui/edition/ItemEdition.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/gui/edition/ItemEdition.java index 27c8a5a2..f96ef880 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/gui/edition/ItemEdition.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/gui/edition/ItemEdition.java @@ -15,11 +15,15 @@ import net.Indyuce.mmoitems.stat.category.StatCategory; import net.Indyuce.mmoitems.stat.component.LoreWrapper; import net.Indyuce.mmoitems.stat.component.model.Model; import net.Indyuce.mmoitems.stat.component.model.builtin.ArrayModel; +import net.Indyuce.mmoitems.stat.component.model.builtin.MapModel; import net.Indyuce.mmoitems.stat.component.type.ComponentType; import net.Indyuce.mmoitems.stat.component.type.builtin.ArrayComponentType; +import net.Indyuce.mmoitems.stat.component.type.builtin.MapComponentType; import net.Indyuce.mmoitems.stat.component.type.builtin.ObjectComponentType; import net.Indyuce.mmoitems.stat.type.ItemStat; import net.Indyuce.mmoitems.util.MMOUtils; +import net.Indyuce.mmoitems.util.Pair; +import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -31,18 +35,17 @@ import org.bukkit.inventory.ItemFlag; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.ItemMeta; import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.Stack; -import java.util.concurrent.atomic.AtomicInteger; +import java.util.*; +import java.util.function.Consumer; import java.util.stream.Collectors; public class ItemEdition extends EditionInventory { private static final int[] SLOTS = {19, 20, 21, 22, 23, 24, 25, 28, 29, 30, 31, 32, 33, 34, 37, 38, 39, 40, 41, 42, 43, 46, 47, 48, 49, 50, 51, 52}; private static final NamespacedKey COMPONENT_KEY = new NamespacedKey(MMOItems.plugin, "component_key"); + private static final NamespacedKey NEW_ELEMENT = new NamespacedKey(MMOItems.plugin, "new_element"); private Stack explored = new Stack<>(); @@ -63,18 +66,33 @@ public class ItemEdition extends EditionInventory { int downmostPage = 1; private static class Entry { + @NotNull final String key; + @Nullable final StatCategory category; - final ComponentType ctype; + @NotNull + final ComponentType componentType; + @Nullable final Model model; + final boolean newElement; + int page = 1; - private Entry(String key, StatCategory category, ComponentType ctype, Model model) { + Entry(@NotNull String key, @Nullable StatCategory category, @NotNull ComponentType componentType, @Nullable Model model) { this.key = key; this.category = category; - this.ctype = ctype; + this.componentType = componentType; this.model = model; + this.newElement = false; + } + + Entry(@NotNull ComponentType componentType) { + this.key = "newItem"; + this.category = null; + this.componentType = componentType; + this.model = null; + this.newElement = true; } } @@ -87,26 +105,45 @@ public class ItemEdition extends EditionInventory { .map(stat -> new Entry(stat.getId(), stat.getCategory(), stat.getComponentType(), template.getModels().get(stat))) .collect(Collectors.toList()); - // TODO abstraction over objects, arrays and dicts - // If topmost is an object, explore its keys - if (topmost.ctype instanceof ObjectComponentType) - return ((ObjectComponentType) topmost.ctype).getChildrenTypes().stream() + if (topmost.componentType instanceof ObjectComponentType) + return ((ObjectComponentType) topmost.componentType).getChildrenTypes().stream() .map(pair -> new Entry(pair.getKey(), null, pair.getValue(), topmost.model == null ? null : topmost.model.getModel(pair.getKey()))) .collect(Collectors.toList()); - // If topmost is an array, explore its elements - if (topmost.ctype instanceof ArrayComponentType) { - AtomicInteger counter = new AtomicInteger(); - ComponentType subtype = ((ArrayComponentType) topmost.ctype).getSubType(); - return topmost.model == null ? new ArrayList<>() : - ((ArrayModel) topmost.model).getKeyedModels().stream() - .map(submodel -> new Entry(String.valueOf(counter.getAndIncrement()), null, subtype, submodel.getValue())) - .collect(Collectors.toList()); - // return ((ArrayComponentType) topmost.ctype).get + if (topmost.componentType instanceof MapComponentType) { + ComponentType subtype = ((MapComponentType) topmost.componentType).getSubtype(); + List entries = new ArrayList<>(); + + // Collect existing entries + if (topmost.model != null) + for (Map.Entry> entry : ((MapModel) topmost.model).getModels().entrySet()) + entries.add(new Entry(entry.getKey(), null, subtype, entry.getValue())); + + // Add "new element" entry + entries.add(new Entry(subtype)); + + return entries; } - throw new TerminalComponentException(topmost.ctype); + // If topmost is an array, explore its elements + if (topmost.componentType instanceof ArrayComponentType) { + ComponentType subtype = ((ArrayComponentType) topmost.componentType).getSubType(); + List entries = new ArrayList<>(); + ArrayModel arrayModel = (ArrayModel) topmost.model; + + // Collect existing entries + if (topmost.model != null) + for (Pair> entry : arrayModel.getKeyedModels()) + entries.add(new Entry(entry.getKey(), null, subtype, entry.getValue())); + + // Add "new element" entry + entries.add(new Entry(subtype)); + + return entries; + } + + throw new TerminalComponentException(topmost.componentType); } @Override @@ -125,41 +162,51 @@ public class ItemEdition extends EditionInventory { for (int j = min; j < max; j++) { Entry entry = entries.get(j); - ItemStack item = entry.ctype.provideIcon(entry.model); + ItemStack item = entry.componentType.provideIcon(entry.model); ItemMeta meta = item.getItemMeta(); - meta.addItemFlags(ItemFlag.values()); VersionUtils.addEmptyAttributeModifier(meta); - meta.setDisplayName(ChatColor.GREEN + entry.ctype.provideName(entry.model)); - List lore = new ArrayList<>(); - - // Display stat category - if (entry.category != null) { - lore.add(ChatColor.BLUE + entry.category.getLoreTag()); - } - - // Display component type lore - List statDesc = (List) entry.ctype.provideDescription(entry.model); - if (statDesc != null) { - lore.add(""); - lore.addAll(MythicLib.plugin.parseColors(statDesc.stream().map(s -> ChatColor.GRAY + s).collect(Collectors.toList()))); - } - - // Display current value of main stat component - try { - entry.ctype.editionUiDisplay(new LoreWrapper(lore), entry.model); - } catch (Exception ignored) { - // Pass - } - - // Lore action tags - lore.add(""); - for (String loreActionTag : (List) entry.ctype.getActionLoreTags()) - lore.add(ChatColor.YELLOW + AltChar.listDash + " " + loreActionTag); - - // Set NBT tag for exploration and edition + meta.addItemFlags(ItemFlag.values()); meta.getPersistentDataContainer().set(COMPONENT_KEY, PersistentDataType.STRING, entry.key); - meta.setLore(lore); + // "Add New" entry + if (entry.newElement) { + meta.setDisplayName(ChatColor.GREEN + "Add New"); + meta.getPersistentDataContainer().set(NEW_ELEMENT, PersistentDataType.BOOLEAN, true); + } + + // Normal entry + else { + + meta.setDisplayName(ChatColor.GREEN + entry.componentType.provideName(entry.model)); + List lore = new ArrayList<>(); + + // Display stat category + if (entry.category != null) { + lore.add(ChatColor.BLUE + entry.category.getLoreTag()); + } + + // Display component type lore + List statDesc = (List) entry.componentType.provideDescription(entry.model); + if (statDesc != null) { + lore.add(""); + lore.addAll(MythicLib.plugin.parseColors(statDesc.stream().map(s -> ChatColor.GRAY + s).collect(Collectors.toList()))); + } + + // Display current value of main stat component + try { + entry.componentType.editionUiDisplay(new LoreWrapper(lore), entry.model); + } catch (Exception ignored) { + // Pass + } + + // Lore action tags + lore.add(""); + for (String loreActionTag : (List) entry.componentType.getActionLoreTags()) + lore.add(ChatColor.YELLOW + AltChar.listDash + " " + loreActionTag); + + meta.setLore(lore); + } + item.setItemMeta(meta); inventory.setItem(SLOTS[slotc++], item); } @@ -192,21 +239,21 @@ public class ItemEdition extends EditionInventory { ItemStack item = event.getCurrentItem(); if (!MMOUtils.isMetaItem(item, false) || event.getInventory().getItem(4) == null) return; - if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Next Page")) { + if (Objects.equals(item.getItemMeta().getDisplayName(), ChatColor.GREEN + "Next Page")) { Entry topmost = explored.isEmpty() ? null : explored.peek(); if (topmost == null) downmostPage++; else topmost.page++; refreshInventory(); } - if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Previous Page")) { + if (Objects.equals(item.getItemMeta().getDisplayName(), ChatColor.GREEN + "Previous Page")) { Entry topmost = explored.isEmpty() ? null : explored.peek(); if (topmost == null) downmostPage--; else topmost.page--; refreshInventory(); } - if (item.getItemMeta().getDisplayName().equals(ChatColor.GREEN + "Back")) { + if (Objects.equals(item.getItemMeta().getDisplayName(), ChatColor.GREEN + "Back")) { // Back to type browser if (explored.isEmpty()) { @@ -220,14 +267,22 @@ public class ItemEdition extends EditionInventory { } } + /////////////////////////////////////////////////////////////////////// + // + // Reading Entry + // + /////////////////////////////////////////////////////////////////////// + // Check tag final String tag = item.getItemMeta().getPersistentDataContainer().get(COMPONENT_KEY, PersistentDataType.STRING); if (tag == null) return; // Exploration + Entry topmost; ComponentType ctype; Model model; String key; + boolean newElement; if (explored.isEmpty()) { ItemStat stat = Objects.requireNonNull(MMOItems.plugin.getStats().get(tag.toUpperCase()), "No stat found with ID '" + tag + "'"); @@ -240,60 +295,130 @@ public class ItemEdition extends EditionInventory { return; } + topmost = null; ctype = stat.getComponentType(); model = template.getModels().get(stat); key = stat.getId().toLowerCase(); + newElement = false; } else { - Entry topmost = explored.peek(); + topmost = explored.peek(); - ctype = topmost.ctype.getChildType(tag); + ctype = topmost.componentType.getChildType(tag); model = topmost.model == null ? null : topmost.model.getModel(tag); - key = tag; + key = "newItem"; + newElement = item.getItemMeta().getPersistentDataContainer().has(NEW_ELEMENT); } - Bukkit.broadcastMessage("Clicked " + key + " " + ctype.isTerminal() + " " + ctype + " " + model); + /////////////////////////////////////////////////////////////////////// + // + // Player Input and Exploration + // + /////////////////////////////////////////////////////////////////////// - // Input handling - if (ctype.isTerminal()) { + Bukkit.broadcastMessage(String.format("Clicked key='%s' ctype_terminal=%b ctype=%s model=%s", key, ctype.isTerminal(), String.valueOf(ctype), String.valueOf(model))); - // Right click basic - if (event.getClick() == ClickType.RIGHT) { - getEditedSection().set(appendComponentPaths(key), null); - registerTemplateEdition(); - player.sendMessage(ChatColor.GRAY + String.format("Successfully deleted %s", ((ComponentType) ctype).provideName(model))); - return; + // "Add New" Button + if (newElement) { + + // Add new element to map + if (topmost.componentType instanceof MapComponentType) { + // TODO support non-inputable map value types. there are none atm + Validate.isTrue(ctype.isInputable(), "Non-inputable map value types are not supported yet"); + + playerInputWrapper(input -> { + String[] firstSplit = input.split(" ", 2); // TODO edit splitter + Validate.isTrue(firstSplit.length == 2, "Invalid format"); + String newKey = firstSplit[0]; + + Object fromInput = ctype.inputToConfig(firstSplit[1]); // Read input from player + getEditedSection().set(appendComponentPaths(newKey), fromInput); // Write to config + registerTemplateEdition(); // Register edition + }); } - // Left click basic input - PlayerInputProvider.input(navigator, playerInput -> { - try { + // Add new element to array + else if (topmost.componentType instanceof ArrayComponentType) { + //TODO support list format - // Read input from player - Object fromInput = ctype.inputToConfig(playerInput); + String newKey = topmost.model == null ? "1" : ((ArrayModel) topmost.model).findNewKey(); - // Write to config - getEditedSection().set(appendComponentPaths(key), fromInput); - registerTemplateEdition(); + // If inputable OR terminal, input and add + if (ctype.isInputable() || ctype.isTerminal()) { - player.sendMessage("{item_edition_input_success}"); - return true; - - } catch (Exception exception) { - player.sendMessage(ChatColor.RED + exception.getMessage()); - return null; + playerInputWrapper(input -> { + Object fromInput = ctype.inputToConfig(input); + getEditedSection().set(appendComponentPaths(newKey), fromInput); + registerTemplateEdition(); + }); } - }).enable("{begin_input_edition}"); + // Otherwise, create and explore + else { + getEditedSection().createSection(appendComponentPaths(newKey)); // Write to config + registerTemplateEdition(); + callExploration(newKey, ctype, null); + } + } + + // Not implemented + else throw new RuntimeException("Not implemented"); + } + + // Remove content + else if (event.getClick() == ClickType.RIGHT) { + getEditedSection().set(appendComponentPaths(key), null); + registerTemplateEdition(); + player.sendMessage(ChatColor.GRAY + String.format("Successfully deleted %s", ((ComponentType) ctype).provideName(model))); + } + + // Inputable Component + else if (ctype.isInputable()) { + + // TODO remove last, input next for maps and dicts + + // Shift-left click: explore instead of input non-terminal inputable + if (event.getClick() == ClickType.SHIFT_LEFT && !ctype.isTerminal() && model != null) { + callExploration(key, ctype, model); + } + + // Simple player input + else callSimplePlayerInput(key, ctype); } // Exploration else { - explored.push(new Entry(key, null, ctype, model)); - refreshInventory(); + callExploration(key, ctype, model); } } + private void callExploration(String key, ComponentType ctype, Model model) { + explored.push(new Entry(key, null, ctype, model)); + refreshInventory(); + } + + private void callSimplePlayerInput(String key, ComponentType componentType) { + playerInputWrapper(playerInput -> { + Object fromInput = componentType.inputToConfig(playerInput); // Read input from player + getEditedSection().set(appendComponentPaths(key), fromInput); // Write to config + registerTemplateEdition(); // Register edition + }); + } + + private void playerInputWrapper(Consumer callback) { + PlayerInputProvider.input(navigator, playerInput -> { + try { + callback.accept(playerInput); + player.sendMessage("{item_edition_input_success}"); + return true; + + } catch (Exception exception) { + player.sendMessage(ChatColor.RED + exception.getMessage()); + return false; + } + }).enable("{begin_input_edition}"); + } + private String appendComponentPaths(String lastKey) { StringBuilder fullPath = new StringBuilder(); for (Entry entry : explored) { diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/Lore.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/Lore.java index 4d7a03f9..a55fa2d3 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/Lore.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/Lore.java @@ -25,6 +25,7 @@ public class Lore extends StringListStat { super("LORE", null); setComponentType(ArrayComponentType.arrayOf(StringComponentType.init().build()) + .fullUiDisplay(true) .icon(Material.WRITABLE_BOOK) .name("Lore") .trimdesc("Give some tooltip lore to your item. You can't change the whole lore format from here.") diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/RequiredClass.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/RequiredClass.java index a338ee80..835e6d00 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/RequiredClass.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/RequiredClass.java @@ -1,16 +1,20 @@ package net.Indyuce.mmoitems.stat; import io.lumine.mythic.lib.api.item.NBTItem; +import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder; +import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem; import net.Indyuce.mmoitems.api.player.RPGPlayer; import net.Indyuce.mmoitems.api.util.message.Message; import net.Indyuce.mmoitems.stat.annotation.HasCategory; import net.Indyuce.mmoitems.stat.behaviour.ItemRestriction; -import net.Indyuce.mmoitems.stat.component.type.builtin.ArrayComponentType; -import net.Indyuce.mmoitems.stat.component.type.builtin.StringComponentType; +import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent; +import net.Indyuce.mmoitems.stat.component.builtin.StringComponent; import net.Indyuce.mmoitems.stat.type.StringListStat; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.Sound; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.regex.Pattern; @@ -23,17 +27,20 @@ public class RequiredClass extends StringListStat implements ItemRestriction { "The class you need to profess to use your item.", new String[]{"!block", "all"}); - // TODO fix old NBT syntax: - // this should be self explanatory: - // ret.add(new ItemTag(getNBTPath(), String.join(", ", ((StringListData) data).getList()))); - - setComponentType(ArrayComponentType.arrayOf(StringComponentType.init().build()) - .noExploration(true) - .build()); - setGemstoneTransferable(false); } + @Nullable + @Override + public ArrayComponent read(ReadMMOItem mmoitem) { + return readStringSeparatedStringArray(mmoitem, ", "); + } + + @Override + public void write(ItemStackBuilder builder, @NotNull ArrayComponent component) { + writeStringSeparatedStringArray(builder, component, ", "); + } + @Override public boolean canUse(RPGPlayer player, NBTItem item, boolean message) { String requiredClass = item.getString(getNBTPath()); diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/UpgradeStat.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/UpgradeStat.java index 6d6f072b..0bb97b82 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/UpgradeStat.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/UpgradeStat.java @@ -122,9 +122,9 @@ public class UpgradeStat extends ItemStat implements Consumabl builder.getLore().registerPlaceholder("upgrade_level", String.valueOf(component.getLevel())); // Write to lore - if (component.getMaxUpgrades() > 0) + if (component.getMax() > 0) builder.getLore().insert(getPath(), - getGeneralStatFormat().replace("{value}", String.valueOf(component.getMaxUpgrades()))); + getGeneralStatFormat().replace("{value}", String.valueOf(component.getMax()))); } @Deprecated diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/BooleanComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/BooleanComponent.java index 97007422..1da58c3e 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/BooleanComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/BooleanComponent.java @@ -4,6 +4,7 @@ package net.Indyuce.mmoitems.stat.component.builtin; import net.Indyuce.mmoitems.stat.component.StatComponent; import net.Indyuce.mmoitems.stat.component.type.builtin.BooleanComponentType; import org.apache.commons.lang.NotImplementedException; +import org.jetbrains.annotations.Nullable; public class BooleanComponent extends StatComponent { private boolean value; @@ -45,4 +46,13 @@ public class BooleanComponent extends StatComponent { throw new NotImplementedException(); } } + + public static boolean getValue(@Nullable BooleanComponent component) { + return component != null && component.value; + } + + @Nullable + public static BooleanComponent from(boolean value){ + return value ? new BooleanComponent(true) : null; + } } diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/DoubleComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/DoubleComponent.java index d7aad4b8..91965ac9 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/DoubleComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/DoubleComponent.java @@ -2,6 +2,7 @@ package net.Indyuce.mmoitems.stat.component.builtin; import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType; import org.apache.commons.lang.NotImplementedException; +import org.jetbrains.annotations.Nullable; public class DoubleComponent extends NumberComponent { private double value; @@ -73,4 +74,13 @@ public class DoubleComponent extends NumberComponent { throw new NotImplementedException(); } } + + public static double getValue(@Nullable DoubleComponent component) { + return component == null ? 0 : component.value; + } + + @Nullable + public static DoubleComponent from(double value) { + return value == 0 ? null : new DoubleComponent(value); + } } diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/IntegerComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/IntegerComponent.java index 37ff5dc0..423dee56 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/IntegerComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/IntegerComponent.java @@ -71,7 +71,12 @@ public class IntegerComponent extends NumberComponent { } } - public static int asInteger(@Nullable IntegerComponent component) { + public static int getValue(@Nullable IntegerComponent component) { return component == null ? 0 : component.value; } + + @Nullable + public static IntegerComponent from(int value) { + return value == 0 ? null : new IntegerComponent(value); + } } diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/StringComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/StringComponent.java index c1bbda12..5bf01b81 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/StringComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/StringComponent.java @@ -70,6 +70,11 @@ public class StringComponent extends StatComponent { return component == null ? null : component.value; } + @Nullable + public static StringComponent fromString(@Nullable String input) { + return input == null || input.isEmpty() ? null : new StringComponent(input); + } + @Nullable public static UUID asUniqueId(@Nullable StringComponent component) { return component == null ? null : UUID.fromString(component.toString()); diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/ColorComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/ColorComponent.java index c0d396e7..ab9fab04 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/ColorComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/ColorComponent.java @@ -34,7 +34,7 @@ public class ColorComponent extends ObjectComponent { } public int getRed() { - return IntegerComponent.asInteger(red); + return IntegerComponent.getValue(red); } public void setRed(int red) { @@ -42,7 +42,7 @@ public class ColorComponent extends ObjectComponent { } public int getGreen() { - return IntegerComponent.asInteger(green); + return IntegerComponent.getValue(green); } public void setGreen(int green) { @@ -50,7 +50,7 @@ public class ColorComponent extends ObjectComponent { } public int getBlue() { - return IntegerComponent.asInteger(blue); + return IntegerComponent.getValue(blue); } public void setBlue(int blue) { diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/CommandComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/CommandComponent.java index 89c421c6..7cbf4e81 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/CommandComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/CommandComponent.java @@ -29,19 +29,35 @@ public class CommandComponent extends ObjectComponent { @Nullable public String getCommand() { - return command == null ? null : command.getValue(); + return StringComponent.getValue(command); + } + + public void setCommand(@Nullable String command) { + this.command = StringComponent.fromString(command); } public double getDelay() { - return delay == null ? 0 : delay.getValue(); + return DoubleComponent.getValue(delay); + } + + public void setDelay(double delay) { + this.delay = DoubleComponent.from(delay); } public boolean isConsoleCommand() { - return console != null && console.getValue(); + return BooleanComponent.getValue(console); + } + + public void setConsole(boolean console) { + this.console = BooleanComponent.from(console); } public boolean hasOpPerms() { - return op != null && op.getValue(); + return BooleanComponent.getValue(op); + } + + public void setOp(boolean op) { + this.op = BooleanComponent.from(op); } //endregion diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/SoulboundComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/SoulboundComponent.java index ae1fad1e..9473dd99 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/SoulboundComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/SoulboundComponent.java @@ -43,7 +43,7 @@ public class SoulboundComponent extends ObjectComponent { } public int getLevel() { - return IntegerComponent.asInteger(level); + return IntegerComponent.getValue(level); } public void setLevel(int level) { diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/UpgradeComponent.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/UpgradeComponent.java index 2fb48e2c..86ed26ae 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/UpgradeComponent.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/builtin/composite/UpgradeComponent.java @@ -5,50 +5,85 @@ import net.Indyuce.mmoitems.api.UpgradeTemplate; import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem; import net.Indyuce.mmoitems.stat.annotation.InvalidComponentKeyException; import net.Indyuce.mmoitems.stat.component.StatComponent; -import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent; -import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponent; -import net.Indyuce.mmoitems.stat.component.builtin.StringComponent; +import net.Indyuce.mmoitems.stat.component.builtin.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.function.BiConsumer; -// TODO Finish -@Deprecated public class UpgradeComponent extends ObjectComponent { private IntegerComponent level, min, max; private StringComponent template; - /* - private String reference; - private boolean workbench; - private boolean destroy; - private double success; - */ + private DoubleComponent success; + private BooleanComponent destroyOnFail, workbench; + private StringComponent reference; + + public UpgradeComponent() { + // Empty constructor + } + + public static final String LEVEL = "Level"; + public static final String MIN = "Min"; + public static final String MAX = "Max"; + public static final String TEMPLATE = "Template"; + public static final String SUCCESS = "Success"; + public static final String DESTROY_ON_FAIL = "Destroy"; + public static final String WORKBENCH = "Workbench"; + public static final String REFERENCE = "Reference"; //region API public double getSuccess() { - return 0; + return DoubleComponent.getValue(success); } - public int getMaxUpgrades() { - return 0; + public void setSuccess(double success) { + this.success = success <= 0 ? null : new DoubleComponent(Math.min(1, success)); + } + + public int getMin() { + return IntegerComponent.getValue(min); + } + + public void setMin(int min) { + this.min = IntegerComponent.from(min); + } + + public int getMax() { + return IntegerComponent.getValue(max); + } + + public void setMax(int max) { + this.max = IntegerComponent.from(max); } public boolean destroysOnFail() { - return false; + return BooleanComponent.getValue(destroyOnFail); + } + + public void setDestroyOnFail(boolean destroyOnFail) { + this.destroyOnFail = BooleanComponent.from(destroyOnFail); } public boolean canLevelUp() { - return false; + int max = getMax(); + return max == 0 || getLevel() < max; } public boolean isWorkbench() { - return false; + return BooleanComponent.getValue(workbench); + } + + public void setWorkbench(boolean workbench) { + this.workbench = BooleanComponent.from(workbench); } public String getReference() { - return ""; + return StringComponent.getValue(reference); + } + + public void setReference(@Nullable String reference) { + this.reference = StringComponent.fromString(reference); } @Nullable @@ -56,48 +91,16 @@ public class UpgradeComponent extends ObjectComponent { return template == null ? null : MMOItems.plugin.getUpgrades().getTemplate(template.getValue()); } - /* - public String getTemplateName() { -return template==null ? null - } - */ - public void setTemplate(@Nullable UpgradeTemplate template) { this.template = template == null ? null : new StringComponent(template.getId()); } - public int getMax() { - return max == null ? 0 : max.getValue(); - } - - public void setMax(int max) { - this.max = max == 0 ? null : new IntegerComponent(max); - } - - public int getMin() { - return min == null ? 0 : min.getValue(); - } - - public void setMin(int min) { - this.min = min == 0 ? null : new IntegerComponent(min); - } - public int getLevel() { - return level == null ? 0 : level.getValue(); + return IntegerComponent.getValue(level); } public void setLevel(int level) { - this.level = level == 0 ? null : new IntegerComponent(level); - } - - @NotNull - public UpgradeComponent clone() { - UpgradeComponent clone = new UpgradeComponent(); - clone.setTemplate(getTemplate()); - clone.setLevel(getLevel()); - clone.setMax(getMax()); - clone.setMin(getMin()); - return clone; + this.level = IntegerComponent.from(level); } public void upgrade(@NotNull MMOItem mmoitem) { @@ -112,11 +115,51 @@ return template==null ? null //endregion + @NotNull + public UpgradeComponent clone() { + UpgradeComponent clone = new UpgradeComponent(); + + clone.level = StatComponent.clone(level); + clone.min = StatComponent.clone(min); + clone.max = StatComponent.clone(max); + clone.template = StatComponent.clone(template); + clone.success = StatComponent.clone(success); + clone.destroyOnFail = StatComponent.clone(destroyOnFail); + clone.workbench = StatComponent.clone(workbench); + clone.reference = StatComponent.clone(reference); + + return clone; + } + //region ObjectComponent Interface @Override public void set(@NotNull String key, @Nullable StatComponent component) { switch (key) { + case LEVEL: + level = (IntegerComponent) component; + return; + case MIN: + min = (IntegerComponent) component; + return; + case MAX: + max = (IntegerComponent) component; + return; + case TEMPLATE: + template = (StringComponent) component; + return; + case SUCCESS: + success = (DoubleComponent) component; + return; + case DESTROY_ON_FAIL: + destroyOnFail = (BooleanComponent) component; + return; + case WORKBENCH: + workbench = (BooleanComponent) component; + return; + case REFERENCE: + reference = (StringComponent) component; + return; default: throw new InvalidComponentKeyException(this, key); } @@ -126,6 +169,22 @@ return template==null ? null @Override public StatComponent get(@NotNull String key) { switch (key) { + case LEVEL: + return level; + case MIN: + return min; + case MAX: + return max; + case TEMPLATE: + return template; + case SUCCESS: + return success; + case DESTROY_ON_FAIL: + return destroyOnFail; + case WORKBENCH: + return workbench; + case REFERENCE: + return reference; default: throw new InvalidComponentKeyException(this, key); } @@ -133,7 +192,14 @@ return template==null ? null @Override public void forEachComponent(@NotNull BiConsumer action) { - + if (level != null) action.accept(LEVEL, level); + if (min != null) action.accept(MIN, min); + if (max != null) action.accept(MAX, max); + if (template != null) action.accept(TEMPLATE, template); + if (success != null) action.accept(SUCCESS, success); + if (destroyOnFail != null) action.accept(DESTROY_ON_FAIL, destroyOnFail); + if (workbench != null) action.accept(WORKBENCH, workbench); + if (reference != null) action.accept(REFERENCE, reference); } //endregion diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/model/builtin/ArrayModel.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/model/builtin/ArrayModel.java index 38daba23..9be46442 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/model/builtin/ArrayModel.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/model/builtin/ArrayModel.java @@ -12,6 +12,7 @@ import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; public class ArrayModel implements Model> { @@ -33,6 +34,14 @@ public class ArrayModel implements Model pair.getKey().equals(String.valueOf(counter.get())))) { + counter.incrementAndGet(); + } + return String.valueOf(counter); + } + public ArrayComponent randomize(ArrayComponentType componentType, MMOItemBuilder builder) { ArrayComponent randomized = new ArrayComponent<>(); diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/ComponentType.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/ComponentType.java index ce2ce2ef..3f12e20c 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/ComponentType.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/ComponentType.java @@ -55,12 +55,18 @@ public abstract class ComponentType, C extends StatComponent> private Function name; private Function> description; - private List actionLoreTags = Arrays.asList("Left click to change this value.", "Right click to reset this value."); + protected List actionLoreTags = DEFAULT_ACTION_LORE_TAGS; + + protected static final List DEFAULT_ACTION_LORE_TAGS = Arrays.asList("Left click to change this value.", "Right click to reset this value."); public boolean isTerminal() { return terminal; } + public boolean isInputable() { + return inputable; + } + @NotNull public ItemStack provideIcon(@Nullable M model) { return icon.apply(model); diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/ArrayComponentType.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/ArrayComponentType.java index c04485bd..9edb5d52 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/ArrayComponentType.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/ArrayComponentType.java @@ -40,11 +40,6 @@ public class ArrayComponentType extends ComponentType keyValidator; - /** - * - */ - private boolean noExploration; - private String listCountFormat = "Element Count: %s"; private String listElementPrefix = ""; private String emptyList = ChatColor.RED + "None"; @@ -228,11 +223,6 @@ public class ArrayComponentType extends ComponentType extends ComponentType build() { Validate.notNull(subtype, "Subtype cannot be null"); + + // Better action lore tags + if (actionLoreTags.equals(DEFAULT_ACTION_LORE_TAGS) && subtype.isInputable()) { + actionLoreTags("Left click to edit.", "Shift-left click to input one value.", "Right click to remove.", "Shift-right click to remove the last value."); + } + return (ArrayComponentType) super.build(); } } diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/MapComponentType.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/MapComponentType.java index 41c717f1..59e449e5 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/MapComponentType.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/component/type/builtin/MapComponentType.java @@ -120,6 +120,13 @@ public class MapComponentType extends ComponentType getChildType(String key) { + // No matter the key, subtype is always the same + return subtype; + } + //region Merging @Override diff --git a/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepUpgrades.java b/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepUpgrades.java index 611429df..029b37f7 100644 --- a/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepUpgrades.java +++ b/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepUpgrades.java @@ -21,13 +21,13 @@ public class RFGKeepUpgrades implements Listener { if (!event.getOptions().shouldKeepUpgrades() || upgrade == null || newOne == null - || newOne.getMaxUpgrades() <= 0) + || newOne.getMax() <= 0) return; // Clone existing, set level and reset // TODO unnecessary cloning? Just edit current. UpgradeComponent processed = newOne.clone(); - processed.setLevel(Math.min(upgrade.getLevel(), newOne.getMaxUpgrades())); + processed.setLevel(Math.min(upgrade.getLevel(), newOne.getMax())); event.getNewMMOItem().setComponent(ItemStats.UPGRADE, processed); } }