diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java index 05b81ab3..4d5ec411 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/ReforgeOptions.java @@ -119,7 +119,8 @@ public class ReforgeOptions { } /** - * Keeps the display name of the item. + * If the item should be rerolled when updated. In the contrary, + * the previous RNG will be transferred onto the newest item. */ public boolean shouldReRoll() { return reRoll; diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/Type.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/Type.java index 36375eb0..dea5a911 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/Type.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/Type.java @@ -1,6 +1,7 @@ package net.Indyuce.mmoitems.api; import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.api.item.NBTItem; import io.lumine.mythic.lib.player.modifier.ModifierSource; import net.Indyuce.mmoitems.MMOItems; @@ -298,10 +299,9 @@ public class Type { */ @Nullable public static Type get(@Nullable String id) { - if (id == null) { - return null; - } - String format = id.toUpperCase().replace("-", "_").replace(" ", "_"); + if (id == null) return null; + + String format = UtilityMethods.enumName(id); return MMOItems.plugin.getTypes().has(format) ? MMOItems.plugin.getTypes().get(format) : null; } diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java index e913630b..d4b4d08c 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/MMOItemReforger.java @@ -28,18 +28,13 @@ import java.util.ArrayList; import java.util.Objects; /** - * A class to manage modification of items with reference to what they used to be - * (and apparently also used to automatically apply SoulBounds): + * A class to manage modification of items with reference to what + * they used to be. Updating/reforging refers to changing the base + * stats of a MMOItem instance to what the template currently has, + * usually keeping gem stones and upgrade level. This won't reroll + * RNG stats unless the specific option is toggled on. * - *

updating refers to changing the base stats - * of a MMOItem instance to what the template currently has, usually - * keeping gem stones and upgrade level. This wont reroll RNG stats.

- * - *

reforging same thing as updating, but rerolling - * the RNG stats - basically transferring the data specified by the - * {@link ReforgeOptions} into a new item of the same Type-ID

- * - * @author Gunging + * @author Gunging, Jules */ public class MMOItemReforger { @@ -135,7 +130,7 @@ public class MMOItemReforger { /** * @return The meta of {@link #getStack()} but without that - * pesky {@link Nullable} annotation. + * pesky {@link Nullable} annotation. */ @NotNull @Deprecated @@ -183,8 +178,8 @@ public class MMOItemReforger { /** * @return The MMOItem being updated. For safety, it should be cloned, - * in case any plugin decides to make changes in it... though - * this should be entirely for reading purposes only. + * in case any plugin decides to make changes in it... though + * this should be entirely for reading purposes only. */ @SuppressWarnings({"NullableProblems", "ConstantConditions"}) @NotNull @@ -222,7 +217,7 @@ public class MMOItemReforger { /** * @return The Updated version of the MMOItem, with - * its revised stats. + * its revised stats. */ @SuppressWarnings({"NullableProblems", "ConstantConditions"}) @NotNull @@ -241,7 +236,7 @@ public class MMOItemReforger { /** * @return If this is a loaded template. That's all required. * @deprecated Ambigous method, not finding a corresponding item - * template isn't the only fail factor. + * template isn't the only fail factor. */ @Deprecated public boolean canReforge() { @@ -330,7 +325,7 @@ public class MMOItemReforger { /** * @return The item level modifying the values of RandomStatData - * upon creating a new MMOItem from the template. + * upon creating a new MMOItem from the template. */ public int getGenerationItemLevel() { return generationItemLevel; @@ -361,15 +356,13 @@ public class MMOItemReforger { public boolean reforge(@NotNull ReforgeOptions options, @Nullable RPGPlayer player) { // Throw fail - if (!hasTemplate()) - return false; + if (!hasTemplate()) return false; // Prepare everything properly oldMMOItem = new LiveMMOItem(getNBTItem()); // Not blacklisted right!? - if (options.isBlacklisted(getOldMMOItem().getId())) - return false; + if (options.isBlacklisted(getOldMMOItem().getId())) return false; this.player = player; @@ -398,8 +391,7 @@ public class MMOItemReforger { Bukkit.getPluginManager().callEvent(mmoREV); // Cancelled? it ends there - if (mmoREV.isCancelled()) - return false; + if (mmoREV.isCancelled()) return false; // Properly recalculate all based on histories for (StatHistory hist : getFreshMMOItem().getStatHistories()) diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/NumericStatFormula.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/NumericStatFormula.java index 24eef486..6052a90e 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/NumericStatFormula.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/api/util/NumericStatFormula.java @@ -5,8 +5,6 @@ import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder; import net.Indyuce.mmoitems.stat.data.DoubleData; import net.Indyuce.mmoitems.stat.data.random.RandomStatData; import net.Indyuce.mmoitems.stat.data.random.UpdatableRandomStatData; -import net.Indyuce.mmoitems.stat.data.type.Mergeable; -import net.Indyuce.mmoitems.stat.data.type.StatData; import net.Indyuce.mmoitems.stat.type.ItemStat; import org.apache.commons.lang.Validate; import org.bukkit.configuration.ConfigurationSection; @@ -20,7 +18,7 @@ import java.util.Random; * * @author indyuce */ -public class NumericStatFormula implements RandomStatData, UpdatableRandomStatData { +public class NumericStatFormula implements RandomStatData, UpdatableRandomStatData { private final double base, scale, spread, maxSpread; private static final Random RANDOM = new Random(); @@ -155,34 +153,23 @@ public class NumericStatFormula implements RandomStatData, Updatable /** * @param levelScalingFactor Level to scale the scale with - * @param random Result of RANDOM.nextGaussian() or whatever other - * value that you actually want to pass. - * + * @param random Result of RANDOM.nextGaussian() or whatever other + * value that you actually want to pass. * @return The calculated value */ public double calculate(double levelScalingFactor, double random) { - if (useRelativeSpread) { - //SPRD//if (spread > 0) MMOItems.log("\u00a7c༺\u00a77 Using \u00a7eRelative\u00a77 spread formula: \u00a76μ=" + (base + scale * levelScalingFactor) + "\u00a77, \u00a73σ=" + (spread * (base + scale * levelScalingFactor) + "\u00a7b=" + spread + "×" + (base + scale * levelScalingFactor)) + " \u00a7c@" + random + "\u00a7e = " + (base + scale * levelScalingFactor) * (1 + Math.min(Math.max(random * spread, -maxSpread), maxSpread))); - return (base + scale * levelScalingFactor) * (1 + Math.min(Math.max(random * spread, -maxSpread), maxSpread)); - } - // The mean, the center of the distribution - double actualBase = base + (scale * levelScalingFactor); + final double actualBase = base + (scale * levelScalingFactor); /* - * This is one pick from a gaussian distribution - * at mean 0, and standard deviation 1, multiplied - * by the spread chosen. + * This is one pick from a gaussian distribution at mean 0, and + * standard deviation 1, multiplied by the spread chosen. + * Does it exceed the max spread (positive or negative)? Not anymore! */ - double flatSpread = random * spread; + final double spreadCoef = Math.min(Math.max(random * spread, -maxSpread), maxSpread); - // Does it exceed the max spread (positive or negative)? Not anymore! - flatSpread = Math.min(Math.max(flatSpread, -maxSpread), maxSpread); - - // That's it - //SPRD//if (spread > 0) MMOItems.log("\u00a7c༺\u00a77 Using \u00a7aAdditive\u00a77 spread formula, \u00a76μ=" + (base + scale * levelScalingFactor) + "\u00a77, \u00a73σ=" + (spread) + " \u00a7c@" + random + "\u00a7e = " + (actualBase + gaussSpread)); - return actualBase + flatSpread; + return useRelativeSpread ? actualBase * (1 + spreadCoef) : actualBase + spreadCoef; } @Override @@ -235,43 +222,27 @@ public class NumericStatFormula implements RandomStatData, Updatable @NotNull @SuppressWarnings("unchecked") @Override - public T reroll(@NotNull ItemStat stat, @NotNull T original, int determinedItemLevel) { - //UPGRD//MMOItems.log("\u00a7a +\u00a77 Valid for Double Data procedure\u00a78 {Original:\u00a77 " + ((DoubleData) original).getValue() + "\u00a78}"); + public DoubleData reroll(@NotNull ItemStat stat, @NotNull DoubleData original, int determinedItemLevel) { - // Very well, chance checking is only available for NumericStatFormula class so - double scaledBase = getBase() + (getScale() * determinedItemLevel); - - // Determine current - double current = ((DoubleData) original).getValue(); - - // What was the shift? - double shift = current - scaledBase; - - // How many standard deviations away? - double sD = Math.abs(shift / getSpread()); - if (useRelativeSpread) { sD = Math.abs(shift / (getSpread() * scaledBase)); } - //UPGRD//MMOItems.log("\u00a7b *\u00a77 Base: \u00a73" + base); - //UPGRD//MMOItems.log("\u00a7b *\u00a77 Curr: \u00a73" + current); - //UPGRD//MMOItems.log("\u00a7b *\u00a77 Shft: \u00a73" + shift); - //UPGRD//MMOItems.log("\u00a7b *\u00a77 SDev: \u00a73" + sD); + // Very well, chance checking is only available for NumericStatFormula class + final double expectedValue = getBase() + (getScale() * determinedItemLevel); + final double previousValue = original.getValue(); + final double shift = previousValue - expectedValue; + final double shiftSD = useRelativeSpread ? Math.abs(shift / (getSpread() * expectedValue)) : Math.abs(shift / getSpread()); + final double maxSD = getMaxSpread() / getSpread(); // Greater than max spread? Or heck, 0.1% Chance or less wth - if (sD > getMaxSpread() || sD > 3.5) { - //UPGRD//MMOItems.log("\u00a7c -\u00a77 Ridiculous Range --- reroll"); + if (shiftSD > maxSD || shiftSD > 3.5) { - // Adapt within reason - double reasonableShift = getSpread() * Math.min(2, getMaxSpread()); - if (shift < 0) { reasonableShift *= -1;} - - // That's the data we'll use - return (T) new DoubleData(reasonableShift + scaledBase); + // Just fully reroll value + return new DoubleData(calculate(determinedItemLevel)); // Data arguably fine tbh, just use previous } else { //UPGRD//MMOItems.log("\u00a7a +\u00a77 Acceptable Range --- kept"); // Just clone I guess - return (T) ((Mergeable) original).cloneData(); } + return original.cloneData(); } } public enum FormulaSaveOption { diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java index a317977a..e4d35cc5 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/RandomElementListData.java @@ -17,7 +17,7 @@ import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; -public class RandomElementListData implements RandomStatData, UpdatableRandomStatData { +public class RandomElementListData implements RandomStatData, UpdatableRandomStatData { private final Map, NumericStatFormula> stats = new LinkedHashMap<>(); public RandomElementListData(ConfigurationSection config) { @@ -58,7 +58,7 @@ public class RandomElementListData implements RandomStatData, U @NotNull @Override @SuppressWarnings("unchecked") - public T reroll(@NotNull ItemStat stat, @NotNull T original, int determinedItemLevel) { + public ElementListData reroll(@NotNull ItemStat stat, @NotNull ElementListData original, int determinedItemLevel) { // Start brand new ElementListData elements = new ElementListData(); @@ -80,6 +80,6 @@ public class RandomElementListData implements RandomStatData, U } // THats it - return (T) elements; + return elements; } } \ No newline at end of file diff --git a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/UpdatableRandomStatData.java b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/UpdatableRandomStatData.java index 8ebcf2a8..8c4620fe 100644 --- a/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/UpdatableRandomStatData.java +++ b/MMOItems-API/src/main/java/net/Indyuce/mmoitems/stat/data/random/UpdatableRandomStatData.java @@ -10,33 +10,30 @@ import org.jetbrains.annotations.NotNull; * looking into Random Stat Data, because one wouldn't want to reroll a good * roll in a player's item... unless this roll was unobtainable now, perhaps * the reason the item is getting updated is to fix that roll being too good... - * + *

* Example of unobtainable data: the current numeric stat value is now out * of the numeric formula bounds (defined by max-spread). - * + *

* This interface will tell the {@link net.Indyuce.mmoitems.api.util.MMOItemReforger} * if the current roll may be kept, or it is too extreme (under the updated metrics) * to be considered 'obtainable' and thus must be removed. - * + *

* If a RandomStatData does not implement this, it will never be kept when * updating items (always be rerolled with latest settings). * * @author Gunging */ @FunctionalInterface -public interface UpdatableRandomStatData { +public interface UpdatableRandomStatData { /** - * - * @param stat In case its relevant, the stat this Stat Data is linked to - * - * @param original The StatData currently in the item being reforged. - * + * @param stat In case its relevant, the stat this Stat Data is linked to + * @param original The StatData currently in the item being reforged. * @param determinedItemLevel The level of the item - * * @return The rerolled StatData if the original is unreasonable. - *

- * If the original is reasonable, a clone of it, probably using {@link Mergeable#cloneData()} + *

+ * If the original is reasonable, a clone of it, probably using {@link Mergeable#cloneData()} */ - @NotNull T reroll(@NotNull ItemStat stat, @NotNull T original, int determinedItemLevel); + @NotNull + S reroll(@NotNull ItemStat stat, @NotNull S original, int determinedItemLevel); } diff --git a/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepRNG.java b/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepRNG.java index 851c08d9..3151496b 100644 --- a/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepRNG.java +++ b/MMOItems-Dist/src/main/java/net/Indyuce/mmoitems/listener/reforging/RFGKeepRNG.java @@ -1,17 +1,12 @@ package net.Indyuce.mmoitems.listener.reforging; -import net.Indyuce.mmoitems.ItemStats; import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent; import net.Indyuce.mmoitems.stat.data.random.RandomStatData; import net.Indyuce.mmoitems.stat.data.random.UpdatableRandomStatData; -import net.Indyuce.mmoitems.stat.data.type.Mergeable; import net.Indyuce.mmoitems.stat.data.type.StatData; -import net.Indyuce.mmoitems.stat.type.ItemStat; import net.Indyuce.mmoitems.stat.type.StatHistory; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * Prevent previous RNG rolls of base stats @@ -21,64 +16,9 @@ import org.jetbrains.annotations.Nullable; */ public class RFGKeepRNG implements Listener { - @EventHandler - public void onReforge(MMOItemReforgeEvent event) { - // Rerolling stats? Nevermind - if (event.getOptions().shouldReRoll()) { -// event.setCancelled(true); - //RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping new item (Complete RNG Reroll)"); - return; - } - - //RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping old RNG Rolls"); - - /* - * Proceed to go through all stats - */ - event.getOldMMOItem() - .getStats() - .stream() - // Skip if it cant merge - .filter(stat -> stat.getClearStatData() instanceof Mergeable) - /* - * These stats are exempt from this 'keeping' operation. - * Probably because there is a ReforgeOption specifically - * designed for them that keeps them separately - */ - .filter(stat -> !(ItemStats.LORE.equals(stat) || - ItemStats.NAME.equals(stat) || - ItemStats.UPGRADE.equals(stat) || - ItemStats.ENCHANTS.equals(stat) || - ItemStats.SOULBOUND.equals(stat) || - ItemStats.GEM_SOCKETS.equals(stat))) - .forEach(stat -> { - // Stat history in the old item - StatHistory hist = StatHistory.from(event.getOldMMOItem(), stat); - - // Alr what the template say, this roll too rare to be kept? - RandomStatData source = event.getReforger().getTemplate().getBaseItemData().get(stat); - - /* - * Decide if this data is too far from RNG to - * preserve its rolls, even if it should be - * preserving the rolls. - */ - StatData keptData = shouldReRollRegardless(stat, source, hist.getOriginalData(), event.getReforger().getGenerationItemLevel()); - - // Old roll is ridiculously low probability under the new parameters. Forget. - if (keptData == null) - return; - - // Fetch History from the new item - StatHistory clear = StatHistory.from(event.getNewMMOItem(), stat); - - // Replace original data of the new one with the roll from the old one - clear.setOriginalData(keptData); - }); - } /** - * @return The item is supposedly being updated, but that doesnt mean all its stats must remain the same. + * The item is supposedly being updated, but that doesnt mean all its stats must remain the same. *

* In contrast to reforging, in which it is expected its RNG to be rerolled, updating should not do it * except in the most dire scenarios: @@ -91,14 +31,41 @@ public class RFGKeepRNG implements Listener { * + There is a new stat: The original data is null so this method cannot be called, will roll the * new stat to actually add it for the first time. */ - @Nullable StatData shouldReRollRegardless(@NotNull ItemStat stat, @NotNull RandomStatData source, @NotNull StatData original, int determinedItemLevel) { - // Not Mergeable, impossible to keep - if (!(source instanceof UpdatableRandomStatData)) - //RFG// MMOItems.log("§8Reforge §3RNG§7 Stat\u00a7f " + stat.getId() + "\u00a77 is not updatable!"); - return null; + @EventHandler + public void onReforge(MMOItemReforgeEvent event) { + // Rerolling stats? Nevermind + if (event.getOptions().shouldReRoll()) +// event.setCancelled(true); + //RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping new item (Complete RNG Reroll)"); + return; - // Just pass on - return ((UpdatableRandomStatData) source).reroll(stat, original, determinedItemLevel); + //RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping old RNG Rolls"); + + event.getOldMMOItem().getStats() + .forEach(stat -> { + + // Check if stat can be transferred over new item + final RandomStatData source = event.getReforger().getTemplate().getBaseItemData().get(stat); + if (source == null || !(source instanceof UpdatableRandomStatData)) + return; + + /* + * Decide if this data is too far from RNG to + * preserve its rolls, even if it should be + * preserving the rolls. + */ + final StatHistory hist = StatHistory.from(event.getOldMMOItem(), stat); + final StatData keptData = ((UpdatableRandomStatData) source).reroll(stat, hist.getOriginalData(), event.getReforger().getGenerationItemLevel()); + + // Old roll is ridiculously low probability under the new parameters. Forget. + if (keptData == null) + return; + + // Fetch History from the new item + final StatHistory clear = StatHistory.from(event.getNewMMOItem(), stat); + + // Replace original data of the new one with the roll from the old one + clear.setOriginalData(keptData); + }); } - }