mirror of
https://gitlab.com/phoenix-dvpmt/mmoitems.git
synced 2024-12-22 04:37:42 +01:00
Fixed an issue with revid rerolling too often
This commit is contained in:
parent
cb11502189
commit
40e0c9ad21
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
* <p><code><b>updating</b></code> 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.</p>
|
||||
*
|
||||
* <p><code><b>reforging</b></code> 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</p>
|
||||
*
|
||||
* @author Gunging
|
||||
* @author Gunging, Jules
|
||||
*/
|
||||
public class MMOItemReforger {
|
||||
|
||||
@ -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())
|
||||
|
@ -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<DoubleData>, UpdatableRandomStatData {
|
||||
public class NumericStatFormula implements RandomStatData<DoubleData>, UpdatableRandomStatData<DoubleData> {
|
||||
private final double base, scale, spread, maxSpread;
|
||||
|
||||
private static final Random RANDOM = new Random();
|
||||
@ -157,32 +155,21 @@ public class NumericStatFormula implements RandomStatData<DoubleData>, Updatable
|
||||
* @param levelScalingFactor Level to scale the scale with
|
||||
* @param random Result of <code>RANDOM.nextGaussian()</code> 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<DoubleData>, Updatable
|
||||
@NotNull
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends StatData> 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 {
|
||||
|
@ -17,7 +17,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class RandomElementListData implements RandomStatData<ElementListData>, UpdatableRandomStatData {
|
||||
public class RandomElementListData implements RandomStatData<ElementListData>, UpdatableRandomStatData<ElementListData> {
|
||||
private final Map<Pair<Element, ElementStatType>, NumericStatFormula> stats = new LinkedHashMap<>();
|
||||
|
||||
public RandomElementListData(ConfigurationSection config) {
|
||||
@ -58,7 +58,7 @@ public class RandomElementListData implements RandomStatData<ElementListData>, U
|
||||
@NotNull
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T extends StatData> 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<ElementListData>, U
|
||||
}
|
||||
|
||||
// THats it
|
||||
return (T) elements;
|
||||
return elements;
|
||||
}
|
||||
}
|
@ -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...
|
||||
*
|
||||
* <p>
|
||||
* Example of unobtainable data: the current numeric stat value is now out
|
||||
* of the numeric formula bounds (defined by max-spread).
|
||||
*
|
||||
* <p>
|
||||
* 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.
|
||||
*
|
||||
* <p>
|
||||
* 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<S extends StatData> {
|
||||
|
||||
/**
|
||||
*
|
||||
* @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.
|
||||
* <br><br>
|
||||
* If the original is reasonable, a clone of it, probably using {@link Mergeable#cloneData()}
|
||||
*/
|
||||
@NotNull <T extends StatData> T reroll(@NotNull ItemStat stat, @NotNull T original, int determinedItemLevel);
|
||||
@NotNull
|
||||
S reroll(@NotNull ItemStat stat, @NotNull S original, int determinedItemLevel);
|
||||
}
|
||||
|
@ -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.
|
||||
* <p>
|
||||
* 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user