Crafting stations now display the items in 'preview mode' (With ranges of RNG in the form X-X instead of a random number), as suggested in #385

Also removed that strange empty slot when crafting stations display ingredients of amount divisible by 64

Implemented suggestion of ticket #403, you may add and edit the following quantities to your config.yml:
```yml
stats-displaying:

    # This will be a prefix to numeric stats,
    # changing their color when they are undesirable.
    color-positive: '&b'
    color-negative: '&9'
    range-dash: '§f§l⎓'
 ```
 https://git.lumine.io/mythiccraft/mmoitems/-/issues/403
This commit is contained in:
Gunging 2021-04-11 01:28:12 -05:00
parent b29ddd96d4
commit 46b17a7f5a
12 changed files with 204 additions and 46 deletions

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import org.jetbrains.annotations.NotNull;
public class ConfigMMOItem {
private final MMOItemTemplate template;
@ -32,7 +33,14 @@ public class ConfigMMOItem {
this.amount = Math.max(1, amount);
}
public ItemStack generate(RPGPlayer player) {
/**
* This actually generates the item the player wanted to craft.
*
* @param player Player to roll RNG in base of
*
* @return A freshly-crafted item to be used by the player.
*/
@NotNull public ItemStack generate(@NotNull RPGPlayer player) {
ItemStack item = template.newBuilder(player).build().newBuilder().build();
item.setAmount(amount);
return item;
@ -47,7 +55,7 @@ public class ConfigMMOItem {
* needs to be displayed
*/
public ItemStack getPreview() {
return preview == null ? (preview = template.newBuilder(0, null).build().newBuilder().build()).clone() : preview.clone();
return preview == null ? (preview = template.newBuilder(0, null).build().newBuilder().build(true)).clone() : preview.clone();
}
public int getAmount() {

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.api.crafting.IngredientInventory.IngredientLookupMod
import net.Indyuce.mmoitems.api.crafting.IngredientInventory.PlayerIngredient;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public abstract class Ingredient {
@ -53,7 +54,7 @@ public abstract class Ingredient {
*/
public abstract String formatDisplay(String string);
public abstract ItemStack generateItemStack(RPGPlayer player);
@NotNull public abstract ItemStack generateItemStack(@NotNull RPGPlayer player);
public CheckedIngredient evaluateIngredient(IngredientInventory inv) {
return new CheckedIngredient(this, inv.getIngredient(this, IngredientLookupMode.BASIC));

View File

@ -11,6 +11,7 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import net.Indyuce.mmoitems.stat.data.MaterialData;
import io.lumine.mythic.lib.api.MMOLineConfig;
import org.jetbrains.annotations.NotNull;
public class MMOItemIngredient extends Ingredient {
private final MMOItemTemplate template;
@ -52,9 +53,12 @@ public class MMOItemIngredient extends Ingredient {
return string.replace("#item#", display).replace("#level#", level != 0 ? "lvl." + level + " " : "").replace("#amount#", "" + getAmount());
}
@NotNull
@Override
public ItemStack generateItemStack(RPGPlayer player) {
ItemStack item = template.newBuilder(player).build().newBuilder().build();
public ItemStack generateItemStack(@NotNull RPGPlayer player) {
// For display, obviously
ItemStack item = template.newBuilder(player).build().newBuilder().build(true);
item.setAmount(getAmount());
return item;
}

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import org.bukkit.Material;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class VanillaIngredient extends Ingredient {
private final Material material;
@ -39,8 +40,9 @@ public class VanillaIngredient extends Ingredient {
return string.replace("#item#", display).replace("#amount#", "" + getAmount());
}
@Override
public ItemStack generateItemStack(RPGPlayer player) {
@NotNull
@Override
public ItemStack generateItemStack(@NotNull RPGPlayer player) {
NBTItem item = NBTItem.get(new ItemStack(material, getAmount()));
if (displayName != null) {
item.setDisplayNameComponent(LegacyComponent.parse(displayName));

View File

@ -246,4 +246,9 @@ public class ItemStackBuilder {
* @return Builds the item
*/
public ItemStack build() { return new DynamicLore(buildNBT()).build(); }
/**
* @return Builds the item
*/
public ItemStack build(boolean forDisplay) { return new DynamicLore(buildNBT(forDisplay)).build(); }
}

View File

@ -11,6 +11,7 @@ import io.lumine.xikage.mythicmobs.items.MythicItem;
import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import io.lumine.mythic.lib.api.MMOLineConfig;
import org.jetbrains.annotations.NotNull;
public class MythicItemIngredient extends Ingredient {
private final MythicItem mythicitem;
@ -38,8 +39,9 @@ public class MythicItemIngredient extends Ingredient {
return string.replace("#item#", display).replace("#amount#", "" + getAmount());
}
@Override
public ItemStack generateItemStack(RPGPlayer player) {
@NotNull
@Override
public ItemStack generateItemStack(@NotNull RPGPlayer player) {
return BukkitAdapter.adapt(mythicitem.generateItemStack(getAmount()));
}

View File

@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.gui;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.LegacyComponent;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import io.lumine.mythic.utils.adventure.text.Component;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.crafting.ingredient.Ingredient.CheckedIngredient;
@ -41,29 +42,56 @@ public class CraftingStationPreview extends PluginInventory {
@Override
public Inventory getInventory() {
// Create inventory of a nice size (5x6)
Inventory inv = Bukkit.createInventory(this, 45, Message.RECIPE_PREVIEW.formatRaw(ChatColor.RESET));
ingredients.clear();
// Include each ingredient
for (CheckedIngredient ing : recipe.getIngredients()) {
// Amount exceeds 64?
if (ing.getIngredient().getAmount() > 64) {
// Generate new item for display
ItemStack sample = ing.getIngredient().generateItemStack(playerData.getRPG());
sample.setAmount(64);
/*
* Time to calculate the stacks and put through the crafting station space.
*/
int amount = ing.getIngredient().getAmount();
// calculate how many full stacks there are
int stacks = amount / 64;
// check for remainders
if ((stacks % 64) == 0)
// simply add the desired amount of ingredients
for (int i = 0; i < stacks; i++)
int stacks = SilentNumbers.floor(amount / 64D);
// Add what must be added
while (amount > 0) {
// Still too large?
if (amount > 64) {
// Put a whole stack
ingredients.add(sample.clone());
else
// iterate stacks + 1 for the final one
for (int i = 0; i < (stacks + 1); i++) {
if (i == stacks)
sample.setAmount(amount - (stacks * 64));
// Subtract a whole stack
amount-= 64;
// No longer greater than 64, :sleep:
} else {
// Add remaining amount
sample.setAmount(amount);
ingredients.add(sample.clone());
}
} else
// Done
amount-=amount;
} }
// Not greater than 64, just put it like that.
} else {
ingredients.add(ing.getIngredient().generateItemStack(playerData.getRPG()));
}
}
int min = (page - 1) * slots.length, max = page * slots.length;

View File

@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import io.lumine.mythic.lib.api.util.AltChar;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.MMOUtils;
import net.Indyuce.mmoitems.api.Element;
@ -12,11 +13,14 @@ import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.api.util.StatFormat;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
import net.Indyuce.mmoitems.gui.edition.ElementsEdition;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.ElementListData;
import net.Indyuce.mmoitems.stat.data.random.RandomElementListData;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.Previewable;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@ -31,7 +35,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Optional;
public class Elements extends ItemStat {
public class Elements extends ItemStat implements Previewable {
public Elements() {
super("ELEMENT", Material.SLIME_BALL, "Elements", new String[] { "The elements of your item." },
new String[] { "slashing", "piercing", "blunt", "offhand", "range", "tool", "armor", "gem_stone" });
@ -126,11 +130,11 @@ public class Elements extends ItemStat {
for (Element element : elements.getDamageElements()) {
String path = element.name().toLowerCase() + "-damage";
double value = elements.getDamage(element);
item.getLore().insert(path, ItemStat.translate(path).replace("#", new StatFormat("##").format(value))); }
item.getLore().insert(path, DoubleStat.formatPath(ItemStat.translate(path), true, value)); }
for (Element element : elements.getDefenseElements()) {
String path = element.name().toLowerCase() + "-defense";
double value = elements.getDefense(element);
item.getLore().insert(path, ItemStat.translate(path).replace("#", new StatFormat("##").format(value))); }
item.getLore().insert(path, DoubleStat.formatPath(ItemStat.translate(path), true, value)); }
// Addtags
item.addItemTag(getAppliedNBT(data));
@ -219,4 +223,61 @@ public class Elements extends ItemStat {
static HashMap<Element, String> defenseNBTpaths = null;
static HashMap<Element, String> damageNBTpaths = null;
@Override
public void whenPreviewed(@NotNull ItemStackBuilder item, @NotNull StatData currentData, @NotNull RandomStatData templateData) throws IllegalArgumentException {
Validate.isTrue(currentData instanceof ElementListData, "Current Data is not ElementListData");
Validate.isTrue(templateData instanceof RandomElementListData, "Template Data is not RandomElementListData");
// Examine every element
for (Element element : Element.values()) {
NumericStatFormula nsf = ((RandomElementListData) templateData).getDamage(element);
NumericStatFormula nsfDEF = ((RandomElementListData) templateData).getDefense(element);
// Get Value
double techMinimum = nsf.calculate(0, -2.5);
double techMaximum = nsf.calculate(0, 2.5);
// Get Value
double techMinimumDEF = nsfDEF.calculate(0, -2.5);
double techMaximumDEF = nsfDEF.calculate(0, 2.5);
// Cancel if it its NEGATIVE and this doesn't support negative stats.
if (techMinimum < (nsf.getBase() - nsf.getMaxSpread())) { techMinimum = nsf.getBase() - nsf.getMaxSpread(); }
if (techMaximum > (nsf.getBase() + nsf.getMaxSpread())) { techMaximum = nsf.getBase() + nsf.getMaxSpread(); }
if (techMinimumDEF < (nsfDEF.getBase() - nsfDEF.getMaxSpread())) { techMinimumDEF = nsfDEF.getBase() - nsfDEF.getMaxSpread(); }
if (techMaximumDEF > (nsfDEF.getBase() + nsfDEF.getMaxSpread())) { techMaximumDEF = nsfDEF.getBase() + nsfDEF.getMaxSpread(); }
// Display if not ZERO
if (techMinimum != 0 || techMaximum != 0) {
// Get path
String path = element.name().toLowerCase() + "-damage";
String builtRange;
if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimum); }
else { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimum, techMaximum); }
// Just display normally
item.getLore().insert(path, builtRange); }
// Display if not ZERO
if (techMinimumDEF != 0 || techMaximumDEF != 0) {
// Get path
String path = element.name().toLowerCase() + "-defense";
String builtRange;
if (SilentNumbers.round(techMinimumDEF, 2) == SilentNumbers.round(techMaximumDEF, 2)) { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimumDEF); }
else { builtRange = DoubleStat.formatPath(ItemStat.translate(path), true, techMinimumDEF, techMaximumDEF); }
// Just display normally
item.getLore().insert(path, builtRange); }
}
// Addtags
item.addItemTag(getAppliedNBT(currentData));
}
}

View File

@ -12,6 +12,7 @@ import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.stat.data.ElementListData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import org.jetbrains.annotations.NotNull;
public class RandomElementListData implements StatData, RandomStatData {
private final Map<Element, NumericStatFormula> damage = new HashMap<>(), defense = new HashMap<>();
@ -36,13 +37,8 @@ public class RandomElementListData implements StatData, RandomStatData {
return defense.containsKey(element);
}
public NumericStatFormula getDefense(Element element) {
return defense.getOrDefault(element, NumericStatFormula.ZERO);
}
public NumericStatFormula getDamage(Element element) {
return damage.getOrDefault(element, NumericStatFormula.ZERO);
}
@NotNull public NumericStatFormula getDefense(@NotNull Element element) { return defense.getOrDefault(element, NumericStatFormula.ZERO); }
@NotNull public NumericStatFormula getDamage(@NotNull Element element) { return damage.getOrDefault(element, NumericStatFormula.ZERO); }
public Set<Element> getDefenseElements() {
return defense.keySet();

View File

@ -34,6 +34,7 @@ import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.regex.Pattern;
@ -97,31 +98,62 @@ public class DoubleStat extends ItemStat implements Upgradable, Previewable {
DoubleData uData = (DoubleData) hist.recalculateUnupgraded();
// Calculate Difference
upgradeShift = value - uData.getValue();
}
}
upgradeShift = value - uData.getValue(); } }
// Display if not ZERO
if (value != 0 || upgradeShift != 0) {
// Get path and modify
String pathFormat = MMOItems.plugin.getLanguage().getStatFormat(getPath());
// Displaying upgrades?
if (upgradeShift != 0) {
item.getLore().insert(getPath(), formatNumericStat(value, "#", new StatFormat("##").format(value))
item.getLore().insert(getPath(), formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), value)
// Add upgrade format
+ MythicLib.plugin.parseColors(UpgradeTemplate.getUpgradeChangeSuffix(plus(upgradeShift) + (new StatFormat("##").format(upgradeShift)), !isGood(upgradeShift))));
} else {
// Just display normally
item.getLore().insert(getPath(), formatNumericStat(value, "#", new StatFormat("##").format(value)));
}
}
item.getLore().insert(getPath(), formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), value));
} }
// Add NBT Path
item.addItemTag(getAppliedNBT(data));
}
@NotNull public static String formatPath(@NotNull String format, boolean moreIsBetter, double value) {
// Thats it
return format
// Replace conditional pluses with +value
.replace("<plus>#",getColorPrefix(value < 0 && moreIsBetter) + (value > 0 ? "+" : "") + new StatFormat("##").format(value))
// Replace loose pounds with the value
.replace("#",getColorPrefix(value < 0 && moreIsBetter) + new StatFormat("##").format(value))
// Replace loose <plus>es
.replace("<plus>", (value > 0 ? "+" : ""));
}
@NotNull public static String formatPath(@NotNull String format, boolean moreIsBetter, double min, double max) {
// Thats it
return format
// Replace conditional pluses with +value
.replace("<plus>","")
// Replace loose pounds with the value
.replace("#", getColorPrefix(min < 0 && moreIsBetter) +
(min > 0 ? "+" : "") + new StatFormat("##").format(min)
+ MMOItems.plugin.getConfig().getString("stats-displaying.range-dash", "\u00a7f\u00a7l⎓") + getColorPrefix(max < 0 && moreIsBetter) +
(min < 0 && max > 0 ? "+" : "") + new StatFormat("##").format(max)); }
@Override
public void whenPreviewed(@NotNull ItemStackBuilder item, @NotNull StatData currentData, @NotNull RandomStatData templateData) throws IllegalArgumentException {
Validate.isTrue(currentData instanceof DoubleData, "Current Data is not Double Data");
@ -144,12 +176,25 @@ public class DoubleStat extends ItemStat implements Upgradable, Previewable {
if (techMinimum != 0 || techMaximum != 0) {
String builtRange;
if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { builtRange = new StatFormat("##").format(techMinimum); }
else { builtRange = new StatFormat("##").format(techMinimum) + "-" + new StatFormat("##").format(techMaximum); }
if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) {
builtRange = formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), techMaximum);
} else {
builtRange = formatPath(MMOItems.plugin.getLanguage().getStatFormat(getPath()), moreIsBetter(), techMinimum, techMaximum); }
// Just display normally
item.getLore().insert(getPath(), formatNumericStat(techMinimum, "#", builtRange));
}
item.getLore().insert(getPath(), builtRange); }
}
@NotNull public static String getColorPrefix(boolean isNegative) {
// Get the base
if (isNegative) {
return Objects.requireNonNull(MMOItems.plugin.getConfig().getString("stats-displaying.color-negative", ""));
} else {
return Objects.requireNonNull(MMOItems.plugin.getConfig().getString("stats-displaying.color-positive", "")); }
}
@NotNull String plus(double amount) { if (amount >= 0) { return "+"; } else return ""; }

View File

@ -220,8 +220,7 @@ public abstract class ItemStat {
public String formatNumericStat(double value, String... replace) {
String format = MMOItems.plugin.getLanguage().getStatFormat(getPath()).replace("<plus>", value > 0 ? "+" : "");
for (int j = 0; j < replace.length; j += 2)
format = format.replace(replace[j], replace[j + 1]);
for (int j = 0; j < replace.length; j += 2) { format = format.replace(replace[j], replace[j + 1]); }
return format;
}

View File

@ -91,6 +91,13 @@ item-upgrading:
stat-change-positive: '&a'
stat-change-negative: '&c'
stats-displaying:
# This will be a prefix to numeric stats,
# changing their color when they are undesirable.
color-positive: ''
color-negative: ''
soulbound:
# Edit soulbound damage when players try to use