mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2025-02-08 12:21:21 +01:00
Basic support for array edition in UI
This commit is contained in:
parent
6c8ed33466
commit
fa097127cd
@ -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<Entry> 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<Entry> entries = new ArrayList<>();
|
||||
|
||||
// Collect existing entries
|
||||
if (topmost.model != null)
|
||||
for (Map.Entry<String, Model<?>> 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<Entry> entries = new ArrayList<>();
|
||||
ArrayModel<?> arrayModel = (ArrayModel<?>) topmost.model;
|
||||
|
||||
// Collect existing entries
|
||||
if (topmost.model != null)
|
||||
for (Pair<String, Model<?>> 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,11 +162,22 @@ 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));
|
||||
meta.addItemFlags(ItemFlag.values());
|
||||
meta.getPersistentDataContainer().set(COMPONENT_KEY, PersistentDataType.STRING, entry.key);
|
||||
|
||||
// "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<String> lore = new ArrayList<>();
|
||||
|
||||
// Display stat category
|
||||
@ -138,7 +186,7 @@ public class ItemEdition extends EditionInventory {
|
||||
}
|
||||
|
||||
// Display component type lore
|
||||
List<String> statDesc = (List<String>) entry.ctype.provideDescription(entry.model);
|
||||
List<String> statDesc = (List<String>) 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())));
|
||||
@ -146,20 +194,19 @@ public class ItemEdition extends EditionInventory {
|
||||
|
||||
// Display current value of main stat component
|
||||
try {
|
||||
entry.ctype.editionUiDisplay(new LoreWrapper(lore), entry.model);
|
||||
entry.componentType.editionUiDisplay(new LoreWrapper(lore), entry.model);
|
||||
} catch (Exception ignored) {
|
||||
// Pass
|
||||
}
|
||||
|
||||
// Lore action tags
|
||||
lore.add("");
|
||||
for (String loreActionTag : (List<String>) entry.ctype.getActionLoreTags())
|
||||
for (String loreActionTag : (List<String>) entry.componentType.getActionLoreTags())
|
||||
lore.add(ChatColor.YELLOW + AltChar.listDash + " " + loreActionTag);
|
||||
|
||||
// Set NBT tag for exploration and edition
|
||||
meta.getPersistentDataContainer().set(COMPONENT_KEY, PersistentDataType.STRING, entry.key);
|
||||
|
||||
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,58 +295,128 @@ 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) {
|
||||
// "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
|
||||
});
|
||||
}
|
||||
|
||||
// Add new element to array
|
||||
else if (topmost.componentType instanceof ArrayComponentType) {
|
||||
//TODO support list format
|
||||
|
||||
String newKey = topmost.model == null ? "1" : ((ArrayModel) topmost.model).findNewKey();
|
||||
|
||||
// If inputable OR terminal, input and add
|
||||
if (ctype.isInputable() || ctype.isTerminal()) {
|
||||
|
||||
playerInputWrapper(input -> {
|
||||
Object fromInput = ctype.inputToConfig(input);
|
||||
getEditedSection().set(appendComponentPaths(newKey), fromInput);
|
||||
registerTemplateEdition();
|
||||
});
|
||||
}
|
||||
|
||||
// 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)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Left click basic input
|
||||
// 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 {
|
||||
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<String> callback) {
|
||||
PlayerInputProvider.input(navigator, playerInput -> {
|
||||
try {
|
||||
|
||||
// Read input from player
|
||||
Object fromInput = ctype.inputToConfig(playerInput);
|
||||
|
||||
// Write to config
|
||||
getEditedSection().set(appendComponentPaths(key), fromInput);
|
||||
registerTemplateEdition();
|
||||
|
||||
callback.accept(playerInput);
|
||||
player.sendMessage("{item_edition_input_success}");
|
||||
return true;
|
||||
|
||||
} catch (Exception exception) {
|
||||
player.sendMessage(ChatColor.RED + exception.getMessage());
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
}).enable("{begin_input_edition}");
|
||||
|
||||
}
|
||||
|
||||
// Exploration
|
||||
else {
|
||||
explored.push(new Entry(key, null, ctype, model));
|
||||
refreshInventory();
|
||||
}
|
||||
}
|
||||
|
||||
private String appendComponentPaths(String lastKey) {
|
||||
|
@ -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.")
|
||||
|
@ -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<StringComponent> read(ReadMMOItem mmoitem) {
|
||||
return readStringSeparatedStringArray(mmoitem, ", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(ItemStackBuilder builder, @NotNull ArrayComponent<StringComponent> component) {
|
||||
writeStringSeparatedStringArray(builder, component, ", ");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canUse(RPGPlayer player, NBTItem item, boolean message) {
|
||||
String requiredClass = item.getString(getNBTPath());
|
||||
|
@ -122,9 +122,9 @@ public class UpgradeStat extends ItemStat<UpgradeComponent> 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
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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) {
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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<String, StatComponent> 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
|
||||
|
@ -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<C extends StatComponent> implements Model<ArrayComponent<C>> {
|
||||
@ -33,6 +34,14 @@ public class ArrayModel<C extends StatComponent> implements Model<ArrayComponent
|
||||
return found == null ? null : found.getValue();
|
||||
}
|
||||
|
||||
public String findNewKey() {
|
||||
AtomicInteger counter = new AtomicInteger(1);
|
||||
while (models.stream().anyMatch(pair -> pair.getKey().equals(String.valueOf(counter.get())))) {
|
||||
counter.incrementAndGet();
|
||||
}
|
||||
return String.valueOf(counter);
|
||||
}
|
||||
|
||||
public ArrayComponent<C> randomize(ArrayComponentType<C> componentType, MMOItemBuilder builder) {
|
||||
ArrayComponent<C> randomized = new ArrayComponent<>();
|
||||
|
||||
|
@ -55,12 +55,18 @@ public abstract class ComponentType<M extends Model<C>, C extends StatComponent>
|
||||
private Function<M, String> name;
|
||||
private Function<M, List<String>> description;
|
||||
|
||||
private List<String> actionLoreTags = Arrays.asList("Left click to change this value.", "Right click to reset this value.");
|
||||
protected List<String> actionLoreTags = DEFAULT_ACTION_LORE_TAGS;
|
||||
|
||||
protected static final List<String> 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);
|
||||
|
@ -40,11 +40,6 @@ public class ArrayComponentType<C extends StatComponent> extends ComponentType<A
|
||||
@BackwardsCompatibility(version = "7.0")
|
||||
private Predicate<String> 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<C extends StatComponent> extends ComponentType<A
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder noExploration(boolean val) {
|
||||
ArrayComponentType.this.noExploration = val;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder uiFormat(@Nullable String listCountFormat, @Nullable String listElementPrefix, @Nullable String emptyList) {
|
||||
if (listCountFormat != null) ArrayComponentType.this.listCountFormat = listCountFormat;
|
||||
if (listElementPrefix != null) ArrayComponentType.this.listElementPrefix = listElementPrefix;
|
||||
@ -243,6 +233,12 @@ public class ArrayComponentType<C extends StatComponent> extends ComponentType<A
|
||||
|
||||
public ArrayComponentType<C> 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<C>) super.build();
|
||||
}
|
||||
}
|
||||
|
@ -120,6 +120,13 @@ public class MapComponentType<C extends StatComponent> extends ComponentType<Map
|
||||
return comp;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public ComponentType<?, ?> getChildType(String key) {
|
||||
// No matter the key, subtype is always the same
|
||||
return subtype;
|
||||
}
|
||||
|
||||
//region Merging
|
||||
|
||||
@Override
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user