**Update MythicLib again pls**

Recipes now work even if the Mango Consumable was deleted.
Sorry about that I just really like the Mango so I based the entire system on top of a 'temporal' test that shuts everything down if the mango was missing....

Also, Updating items with RevID should no longer reroll RNG stats if you have the following in your config:
```
item-revision:
    reroll-when-updated: false
```

Also the spread formula for DoubleData is kind of strange so an alternative has been added, add this to your config to use:
```
additive-spread-formula: true
```
This commit is contained in:
Gunging 2021-03-29 17:02:29 -05:00
parent aa6800b237
commit bf6e37f87a
8 changed files with 584 additions and 139 deletions

View File

@ -76,6 +76,7 @@ public class MMOItemUIFilter implements UIFilter {
@Override
public boolean isValid(@NotNull String argument, @NotNull String data, @Nullable FriendlyFeedbackProvider ffp) {
if (reg) { return true; }
argument = argument.replace(" ", "_").replace("-", "_").toUpperCase();
data = data.replace(" ", "_").replace("-", "_").toUpperCase();
@ -201,7 +202,9 @@ public class MMOItemUIFilter implements UIFilter {
global = new MMOItemUIFilter();
UIFilterManager.registerUIFilter(global);
VanillaMMOItemCountermatch.enable();
}
reg = false; }
private static boolean reg = true;
/**
* @return The general instance of this MMOItem UIFilter.

View File

@ -8,6 +8,7 @@ import io.lumine.mythic.lib.api.crafting.outputs.MythicRecipeOutput;
import io.lumine.mythic.lib.api.crafting.recipes.MythicRecipeBlueprint;
import io.lumine.mythic.lib.api.crafting.recipes.ShapedRecipe;
import io.lumine.mythic.lib.api.crafting.recipes.ShapelessRecipe;
import io.lumine.mythic.lib.api.crafting.uifilters.IngredientUIFilter;
import io.lumine.mythic.lib.api.crafting.uifilters.VanillaUIFilter;
import io.lumine.mythic.lib.api.crafting.uimanager.ProvidedUIFilter;
import io.lumine.mythic.lib.api.crafting.uimanager.UIFilterManager;
@ -216,7 +217,7 @@ public class CustomRecipe implements Comparable<CustomRecipe> {
// Add
ProvidedUIFilter p = readIngredientFrom(str, ffp);
nonAirFound = true;
poofs.add(new MythicRecipeIngredient(new MythicIngredient(p.toString(), p)));
poofs.add(new MythicRecipeIngredient(p));
}
if (!nonAirFound) { throw new IllegalArgumentException(FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Shapeless recipe containing only AIR, $fignored$b.")); }
String recipeName = type + "." + id + "." + recipeCount++;
@ -310,9 +311,9 @@ public class CustomRecipe implements Comparable<CustomRecipe> {
*/
// Bake
ShapedIngredient leftIngredient = new ShapedIngredient(new MythicIngredient(positions[0], left), 0, -rowNumber);
ShapedIngredient centerIngredient = new ShapedIngredient(new MythicIngredient(positions[1], center), 1, -rowNumber);
ShapedIngredient rightIngredient = new ShapedIngredient(new MythicIngredient(positions[2], right), 2, -rowNumber);
ShapedIngredient leftIngredient = new ShapedIngredient(left, 0, -rowNumber);
ShapedIngredient centerIngredient = new ShapedIngredient(center, 1, -rowNumber);
ShapedIngredient rightIngredient = new ShapedIngredient(right, 2, -rowNumber);
// Parse and add
poofs.add(leftIngredient);

View File

@ -16,6 +16,7 @@ import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.RevisionID;
import net.Indyuce.mmoitems.stat.data.*;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
@ -45,6 +46,20 @@ import java.util.*;
* @author Gunging, ? (Indyuce is my guess)
*/
public class MMOItemReforger {
//region Config Values
static int autoSoulboundLevel = 1;
static int defaultItemLevel = -32767;
static boolean rerollWhenUpdated = false;
static boolean keepTiersWhenReroll = true;
public static void reload() {
autoSoulboundLevel = MMOItems.plugin.getConfig().getInt("soulbound.auto-bind.level", 1);
rerollWhenUpdated = MMOItems.plugin.getConfig().getBoolean("item-revision.reroll-when-updated", false);
defaultItemLevel = MMOItems.plugin.getConfig().getInt("item-revision.default-item-level", -32767);
keepTiersWhenReroll = MMOItems.plugin.getConfig().getBoolean("item-revision.keep-tiers");
}
//endregion
// region Item Data
@ -58,7 +73,6 @@ public class MMOItemReforger {
private MMOItem mmoItem;
// Data
private final Map<ItemStat, StatData> itemData = new HashMap<>();
private final Map<ItemStat, StatHistory> itemDataHistory = new HashMap<>();
//endregion
@ -98,7 +112,7 @@ public class MMOItemReforger {
* Apply a quick soulbound based on the config value <code>soulbound.auto-bind.level</code> (default = 1)
*/
public void applySoulbound(@NotNull Player p) {
applySoulbound(p, MMOItems.plugin.getConfig().getInt("soulbound.auto-bind.level", 1));
applySoulbound(p, autoSoulboundLevel);
}
/**
@ -148,8 +162,16 @@ public class MMOItemReforger {
*/
public void update(@Nullable RPGPlayer player, @NotNull ReforgeOptions options) {
// Should it re-roll RNG?
if (rerollWhenUpdated) {
// Reroute to Reforge
reforge(player, options);
return;
}
/*
* todo Has to store every stat into itemData, then check each stat of
* Has to store every stat into itemData, then check each stat of
* the new item to see if they are RNG rolls in order to:
*
* 1: If they arent, the probability of getting the old number
@ -162,7 +184,382 @@ public class MMOItemReforger {
* so it is removed (the updated value of 0 prevailing).
*/
reforge(player, options);
// Initialize as Volatile, find source template. GemStones require a Live MMOItem though (to correctly load all Stat Histories and sh)
if (!options.shouldKeepGemStones() && !options.shouldKeepExternalSH()) { loadVolatileMMOItem(); } else { loadLiveMMOItem(); }
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplate(mmoItem.getType(), mmoItem.getId()); ItemMeta meta = nbtItem.getItem().getItemMeta();
//noinspection ConstantConditions
Validate.isTrue(meta != null, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Invalid item meta prevented $f{0}$b from updating.", template.getType().toString() + " " + template.getId()));
// Keep name
if (options.shouldKeepName()) {
//UPDT//MMOItems.log(" \u00a73> \u00a77Keeping Name");
// Does it have a name?
if (mmoItem.hasData(ItemStats.NAME)) {
// Cache it
cachedName = mmoItem.getData(ItemStats.NAME).toString();
// No name defined, use display name I guess (pretty unusual btw)
} else if (meta.hasDisplayName()) {
cachedName = meta.getDisplayName();
}
//UPDT//MMOItems.log(" \u00a73 + \u00a77" + cachedName);
}
// Keep specific lore components
if (options.shouldKeepLore() && mmoItem.hasData(ItemStats.LORE)) {
//UPDT//MMOItems.log(" \u00a7d> \u00a77Keeping Lore");
// Examine every element
for (String str : ((StringListData) mmoItem.getData(ItemStats.LORE)).getList()) {
// Does it start with the promised...?
if (str.startsWith("\u00a77")) { cachedLore.add(str); }
}
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.log(" \u00a7d + \u00a77" + lr); }
}
EnchantListData ambiguouslyOriginalEnchantmentCache = null; //todo Corresponding to the block at the end of this method.
// Choose enchantments to keep
if (options.shouldKeepEnchantments()) {
//UPDT//MMOItems.log(" \u00a7b> \u00a77Keeping Enchantments");
// Enchant list data
cachedEnchantments = new EnchantListData();
// Does it have MMOItems enchantment data?
if (!mmoItem.hasData(ItemStats.ENCHANTS)) {
//UPDT//MMOItems.log(" \u00a7b* \u00a77No Data");
mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData());
// Nope
}
//UPDT//else { MMOItems.log(" \u00a7b* \u00a77Found Data"); }
// Make sure they are consolidated
Enchants.separateEnchantments(mmoItem);
// Gather
StatHistory hist = StatHistory.from(mmoItem, ItemStats.ENCHANTS);
ambiguouslyOriginalEnchantmentCache = (EnchantListData) ((EnchantListData) hist.getOriginalData()).cloneData();
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Prime Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
// Reap
for (StatData pEnchants : hist.getExternalData()) {
// It really should be but whatever
if (pEnchants instanceof EnchantListData) {
// For every stat
for (Enchantment e : ((EnchantListData) pEnchants).getEnchants()) {
// Get Base/Current
int established = cachedEnchantments.getLevel(e);
// Add
int calculated = established + ((EnchantListData) pEnchants).getLevel(e);
// Put
cachedEnchantments.addEnchant(e, calculated);
//UPDT//MMOItems.log(" \u00a7b + \u00a77" + e.getName() + " " + calculated);
}
}
}
// The cache now stores the full extent of extraneous data. Separate from thy history. (As to not include it in this in the cached data later)
hist.getExternalData().clear();
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
}
// Acquire old upgrade level
if (options.shouldKeepUpgrades() && mmoItem.hasData(ItemStats.UPGRADE)) {
//UPDT//MMOItems.log(" \u00a7e> \u00a77Keeping Upgrade Data");
// Get Level
cachedUpgradeLevel = ((UpgradeData) mmoItem.getData(ItemStats.UPGRADE));
}
// Gather Gemstones
if (options.shouldKeepGemStones() && mmoItem.hasData(ItemStats.GEM_SOCKETS)) {
//UPDT//MMOItems.log(" \u00a7a> \u00a77Keeping Gem Sockets");
// Cache that gemstone data
cachedGemStones = (GemSocketsData) mmoItem.getData(ItemStats.GEM_SOCKETS);
}
// Soulbound transfer
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) {
//UPDT//MMOItems.log(" \u00a7c> \u00a77Keeping Soulbind");
// Find data
cachedSoulbound = mmoItem.getData(ItemStats.SOULBOUND);
}
// Store all the history of stat proceedings.
HashMap<ItemStat, StatHistory> temporalDataHistory = new HashMap<>();
for (StatHistory hist : mmoItem.getStatHistories()) {
//UPDT//MMOItems.log(" \u00a7a + \u00a77History of \u00a7f" + hist.getItemStat().getNBTPath());
// Clear externals
if (!options.shouldKeepExternalSH()) { hist.getExternalData().clear(); }
// Get and set
temporalDataHistory.put(hist.getItemStat(), hist);
}
/*
* Generate fresh MMOItem, with stats that will be set if the chance is too low
*/
int determinedItemLevel;
if (player == null) {
// Get default Item Level
final int iLevel = defaultItemLevel;
// What level with the regenerated item will be hmmmm.....
determinedItemLevel =
// No default level specified?
(iLevel == -32767) ?
// Does the item have level?
(mmoItem.hasData(ItemStats.ITEM_LEVEL) ? (int) ((DoubleData) mmoItem.getData(ItemStats.ITEM_LEVEL)).getValue() : 0 )
// Default level was specified, use that.
: iLevel;
// Identify tier.
ItemTier tier =
// Does the item have a tier, and it should keep it?
(keepTiersWhenReroll && mmoItem.hasData(ItemStats.TIER)) ?
// The tier will be the current tier
MMOItems.plugin.getTiers().get(mmoItem.getData(ItemStats.TIER).toString())
// The item either has no tier, or shouldn't keep it. Null
: null;
// Build it again (Reroll RNG)
mmoItem = template.newBuilder(determinedItemLevel, tier).build();
// No player provided, use defaults.
} else {
// What level with the regenerated item will be hmmmm.....
determinedItemLevel = (mmoItem.hasData(ItemStats.ITEM_LEVEL) ? (int) ((DoubleData) mmoItem.getData(ItemStats.ITEM_LEVEL)).getValue() : 0 );
// Build it again (Reroll RNG)
mmoItem = template.newBuilder(player).build();
}
/*
* Extra step: Check every stat history
*/
for (ItemStat stat : temporalDataHistory.keySet()) {
// Get history
StatHistory hist = temporalDataHistory.get(stat);
if (hist == null) { continue; }
// Alr what the template say
RandomStatData source = template.getBaseItemData().get(stat);
StatHistory clear;
/*
* Does the new item have it?
*
* If not, its gotten removed = we only keep extraneous
*/
if (source instanceof NumericStatFormula && hist.getOriginalData() instanceof DoubleData) {
// Very well, chance checking is only available for NumericStatFormula class so
double base = ((NumericStatFormula) source).getBase() + (((NumericStatFormula) source).getScale() * determinedItemLevel);
// Determine current
double current = ((DoubleData) hist.getOriginalData()).getValue();
// What was the shift?
double shift = current - base;
// How many standard deviations away?
double sD = Math.abs(shift / ((NumericStatFormula) source).getSpread());
if (NumericStatFormula.useRelativeSpread) { sD = Math.abs(shift / (((NumericStatFormula) source).getSpread() * base)); }
// Greater than max spread? Or heck, 0.1% Chance or less wth
if (sD > ((NumericStatFormula) source).getMaxSpread() || sD > 3.5) {
// Adapt within reason
double reasonableShift = ((NumericStatFormula) source).getSpread() * Math.min(2, ((NumericStatFormula) source).getMaxSpread());
if (shift < 0) { reasonableShift *= -1;}
// That's the data we'll use
DoubleData finalData = new DoubleData(reasonableShift + base);
// Make a clear one
clear = new StatHistory(mmoItem, stat, finalData);
// Data arguably fine tbh, just use previous
} else {
// Just clone I guess
clear = new StatHistory(mmoItem, stat, ((DoubleData) hist.getOriginalData()).cloneData());
}
} else {
// Make a clear one
clear = new StatHistory(mmoItem, stat, stat.getClearStatData());
}
// Keep Gemstone and Extraneous data
for (UUID gem : hist.getAllGemstones()) { clear.registerGemstoneData(gem, hist.getGemstoneData(gem)); }
for (StatData ex : hist.getExternalData()) { clear.registerExternalData(ex); }
// Store
itemDataHistory.put(stat, clear);
}
/*
* todo We cannot yet assume (for a few months) that the Original Enchantment Data
* registered into the Stat History is actually true to the template (since it may
* be the enchantments of an old-enchanted item, put by the player).
* _
* Thus this block of code checks the enchantment data of the newly generated
* MMOItem and follows the following logic to give our best guess if the Original
* stats are actually Original:
*
* 1: Is the item unenchantable and unrepairable? Then they must be original
*
* 2: Does the template have no enchantments? Then they must be external
*
* 3: Does the template have this enchantment at an unobtainable level? Then it must be original
*
* 4: Does the template have this enchantment at a lesser level? Then it must be external (player upgraded it)
*
* Original: Included within the template at first creation
* External: Enchanted manually by a player
*
*/
// Choose enchantments to keep
if (options.shouldKeepEnchantments() && ambiguouslyOriginalEnchantmentCache != null) {
//UPDT//MMOItems.log(" \u00a7b> \u00a77Original Enchantments Upkeep");
// 1: The item is unenchantable and unrepairable? Cancel this operation, the cached are Original
if (mmoItem.hasData(ItemStats.DISABLE_ENCHANTING) && mmoItem.hasData(ItemStats.DISABLE_REPAIRING)) {
//UPDT//MMOItems.log(" \u00a7bType-1 \u00a77Original Identification");
ambiguouslyOriginalEnchantmentCache.clear();
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
return;
}
if (!mmoItem.hasData(ItemStats.ENCHANTS)) { mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData());}
// 2: If it has data (It always has) and the amount of enchants is zero, the cached are Extraneous
if (((EnchantListData) mmoItem.getData(ItemStats.ENCHANTS)).getEnchants().size() == 0) {
//UPDT//MMOItems.log(" \u00a73Type-2 \u00a77Extraneous Identification");
// All right, lets add those to cached enchantments
cachedEnchantments.merge(ambiguouslyOriginalEnchantmentCache);
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
return;
}
// Which enchantments are deemed external, after all?
EnchantListData processed = new EnchantListData();
// Identify material
mmoItem.hasData(ItemStats.MATERIAL); MaterialData mData = (MaterialData) mmoItem.getData(ItemStats.MATERIAL); Material mat = mData.getMaterial();
// 3 & 4: Lets examine every stat
for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) {
//UPDT//MMOItems.log(" \u00a7b = \u00a77Per Enchant - \u00a7f" + e.getName());
// Lets see hmm
int current = ambiguouslyOriginalEnchantmentCache.getLevel(e);
int updated = ((EnchantListData) mmoItem.getData(ItemStats.ENCHANTS)).getLevel(e);
//UPDT//MMOItems.log(" \u00a73 <=: \u00a77Current \u00a7f" + current);
//UPDT//MMOItems.log(" \u00a73 <=: \u00a77Updated \u00a7f" + updated);
// 3: Is it at an unobtainable level? Then its Original
if (updated > e.getMaxLevel() || !e.getItemTarget().includes(mat)) {
//UPDT//MMOItems.log(" \u00a7bType-3 \u00a77Original Identification");
continue;
}
// 4: Is it at a lesser level? Player must have enchanted, take them as External
if (updated < current) {
//UPDT//MMOItems.log(" \u00a73Type-4 \u00a77Extraneous Identification");
processed.addEnchant(e, current);
//noinspection UnnecessaryContinue
continue;
}
//UPDT//MMOItems.log(" \u00a73Type-5 \u00a77Original Identification");
}
// All right, lets add those to cached enchantments
cachedEnchantments.merge(processed);
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Processed:");
//UPDT//for (Enchantment e : processed.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + processed.getLevel(e)); }
}
}
/**
@ -197,11 +594,12 @@ public class MMOItemReforger {
// Initialize as Volatile, find source template. GemStones require a Live MMOItem though (to correctly load all Stat Histories and sh)
if (!options.shouldKeepGemStones() && !options.shouldKeepExternalSH()) { loadVolatileMMOItem(); } else { loadLiveMMOItem(); }
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplate(mmoItem.getType(), mmoItem.getId()); ItemMeta meta = nbtItem.getItem().getItemMeta();
//noinspection ConstantConditions
Validate.isTrue(meta != null, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Invalid item meta prevented $f{0}$b from updating.", template.getType().toString() + " " + template.getId()));
// Keep name
if (options.shouldKeepName()) {
//UPDT//MMOItems.Log(" \u00a73> \u00a77Keeping Name");
//UPDT//MMOItems.log(" \u00a73> \u00a77Keeping Name");
// Does it have a name?
if (mmoItem.hasData(ItemStats.NAME)) {
@ -215,12 +613,12 @@ public class MMOItemReforger {
cachedName = meta.getDisplayName();
}
//UPDT//MMOItems.Log(" \u00a73 + \u00a77" + cachedName);
//UPDT//MMOItems.log(" \u00a73 + \u00a77" + cachedName);
}
// Keep specific lore components
if (options.shouldKeepLore() && mmoItem.hasData(ItemStats.LORE)) {
//UPDT//MMOItems.Log(" \u00a7d> \u00a77Keeping Lore");
//UPDT//MMOItems.log(" \u00a7d> \u00a77Keeping Lore");
// Examine every element
for (String str : ((StringListData) mmoItem.getData(ItemStats.LORE)).getList()) {
@ -229,26 +627,25 @@ public class MMOItemReforger {
if (str.startsWith("\u00a77")) { cachedLore.add(str); }
}
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.Log(" \u00a7d + \u00a77" + lr); }
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.log(" \u00a7d + \u00a77" + lr); }
}
EnchantListData ambiguouslyOriginalEnchantmentCache = null; //todo Corresponding to the block at the end of this method.
// Choose enchantments to keep
if (options.shouldKeepEnchantments()) {
//UPDT//MMOItems.Log(" \u00a7b> \u00a77Keeping Enchantments");
//UPDT//MMOItems.log(" \u00a7b> \u00a77Keeping Enchantments");
// Enchant list data
cachedEnchantments = new EnchantListData();
// Does it have MMOItems enchantment data?
if (mmoItem.hasData(ItemStats.ENCHANTS)) {
//UPDT//MMOItems.Log(" \u00a7b* \u00a77Found Data");
if (!mmoItem.hasData(ItemStats.ENCHANTS)) {
//UPDT//MMOItems.log(" \u00a7b* \u00a77No Data");
mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData());
// Nope
} else {
//UPDT//MMOItems.Log(" \u00a7b* \u00a77No Data");
mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData());
}
//UPDT//else { MMOItems.log(" \u00a7b* \u00a77Found Data"); }
// Make sure they are consolidated
Enchants.separateEnchantments(mmoItem);
@ -258,20 +655,20 @@ public class MMOItemReforger {
ambiguouslyOriginalEnchantmentCache = (EnchantListData) ((EnchantListData) hist.getOriginalData()).cloneData();
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Prime Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Prime Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
// Reap
@ -291,7 +688,7 @@ public class MMOItemReforger {
// Put
cachedEnchantments.addEnchant(e, calculated);
//UPDT//MMOItems.Log(" \u00a7b + \u00a77" + e.getName() + " " + calculated);
//UPDT//MMOItems.log(" \u00a7b + \u00a77" + e.getName() + " " + calculated);
}
}
}
@ -299,26 +696,26 @@ public class MMOItemReforger {
// The cache now stores the full extent of extraneous data. Separate from thy history. (As to not include it in this in the cached data later)
hist.getExternalData().clear();
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Arcane Report: \u00a7b-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
}
// Acquire old upgrade level
if (options.shouldKeepUpgrades() && mmoItem.hasData(ItemStats.UPGRADE)) {
//UPDT//MMOItems.Log(" \u00a7e> \u00a77Keeping Upgrade Data");
//UPDT//MMOItems.log(" \u00a7e> \u00a77Keeping Upgrade Data");
// Get Level
cachedUpgradeLevel = ((UpgradeData) mmoItem.getData(ItemStats.UPGRADE));
@ -330,14 +727,14 @@ public class MMOItemReforger {
// Got any gem sockets bro?
if (mmoItem.hasData(ItemStats.GEM_SOCKETS) && options.shouldKeepGemStones()) {
//UPDT//MMOItems.Log(" \u00a7a> \u00a77Keeping Gem Sockets");
//UPDT//MMOItems.log(" \u00a7a> \u00a77Keeping Gem Sockets");
// Cache that gemstone data
cachedGemStones = (GemSocketsData) mmoItem.getData(ItemStats.GEM_SOCKETS); }
// Store all the history of stat proceedings.
for (StatHistory hist : mmoItem.getStatHistories()) {
//UPDT//MMOItems.Log(" \u00a7a + \u00a77History of \u00a7f" + hist.getItemStat().getNBTPath());
//UPDT//MMOItems.log(" \u00a7a + \u00a77History of \u00a7f" + hist.getItemStat().getNBTPath());
// Clear externals
if (!options.shouldKeepExternalSH()) { hist.getExternalData().clear(); }
@ -349,7 +746,7 @@ public class MMOItemReforger {
// Soulbound transfer
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) {
//UPDT//MMOItems.Log(" \u00a7c> \u00a77Keeping Soulbind");
//UPDT//MMOItems.log(" \u00a7c> \u00a77Keeping Soulbind");
// Find data
cachedSoulbound = mmoItem.getData(ItemStats.SOULBOUND);
@ -358,7 +755,7 @@ public class MMOItemReforger {
if (player == null) {
// Get default Item Level
final int iLevel = MMOItems.plugin.getConfig().getInt("item-revision.default-item-level", -32767);
final int iLevel = defaultItemLevel;
// What level with the regenerated item will be hmmmm.....
int level =
@ -377,7 +774,7 @@ public class MMOItemReforger {
ItemTier tier =
// Does the item have a tier, and it should keep it?
(mmoItem.hasData(ItemStats.TIER) && MMOItems.plugin.getConfig().getBoolean("item-revision.keep-tiers")) ?
(keepTiersWhenReroll && mmoItem.hasData(ItemStats.TIER)) ?
// The tier will be the current tier
MMOItems.plugin.getTiers().get(mmoItem.getData(ItemStats.TIER).toString())
@ -418,20 +815,20 @@ public class MMOItemReforger {
*/
// Choose enchantments to keep
if (options.shouldKeepEnchantments() && ambiguouslyOriginalEnchantmentCache != null) {
//UPDT//MMOItems.Log(" \u00a7b> \u00a77Original Enchantments Upkeep");
//UPDT//MMOItems.log(" \u00a7b> \u00a77Original Enchantments Upkeep");
// 1: The item is unenchantable and unrepairable? Cancel this operation, the cached are Original
if (mmoItem.hasData(ItemStats.DISABLE_ENCHANTING) && mmoItem.hasData(ItemStats.DISABLE_REPAIRING)) {
//UPDT//MMOItems.Log(" \u00a7bType-1 \u00a77Original Identification");
//UPDT//MMOItems.log(" \u00a7bType-1 \u00a77Original Identification");
ambiguouslyOriginalEnchantmentCache.clear();
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
return;
}
@ -439,17 +836,17 @@ public class MMOItemReforger {
// 2: If it has data (It always has) and the amount of enchants is zero, the cached are Extraneous
if (((EnchantListData) mmoItem.getData(ItemStats.ENCHANTS)).getEnchants().size() == 0) {
//UPDT//MMOItems.Log(" \u00a73Type-2 \u00a77Extraneous Identification");
//UPDT//MMOItems.log(" \u00a73Type-2 \u00a77Extraneous Identification");
// All right, lets add those to cached enchantments
cachedEnchantments.merge(ambiguouslyOriginalEnchantmentCache);
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
return;
}
@ -462,40 +859,41 @@ public class MMOItemReforger {
// 3 & 4: Lets examine every stat
for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) {
//UPDT//MMOItems.Log(" \u00a7b = \u00a77Per Enchant - \u00a7f" + e.getName());
//UPDT//MMOItems.log(" \u00a7b = \u00a77Per Enchant - \u00a7f" + e.getName());
// Lets see hmm
int current = ambiguouslyOriginalEnchantmentCache.getLevel(e);
int updated = ((EnchantListData) mmoItem.getData(ItemStats.ENCHANTS)).getLevel(e);
//UPDT//MMOItems.Log(" \u00a73 <=: \u00a77Current \u00a7f" + current);
//UPDT//MMOItems.Log(" \u00a73 <=: \u00a77Updated \u00a7f" + updated);
//UPDT//MMOItems.log(" \u00a73 <=: \u00a77Current \u00a7f" + current);
//UPDT//MMOItems.log(" \u00a73 <=: \u00a77Updated \u00a7f" + updated);
// 3: Is it at an unobtainable level? Then its Original
if (updated > e.getMaxLevel() || !e.getItemTarget().includes(mat)) {
//UPDT//MMOItems.Log(" \u00a7bType-3 \u00a77Original Identification");
//UPDT//MMOItems.log(" \u00a7bType-3 \u00a77Original Identification");
continue;
}
// 4: Is it at a lesser level? Player must have enchanted, take them as External
if (updated < current) {
//UPDT//MMOItems.Log(" \u00a73Type-4 \u00a77Extraneous Identification");
//UPDT//MMOItems.log(" \u00a73Type-4 \u00a77Extraneous Identification");
processed.addEnchant(e, current);
//noinspection UnnecessaryContinue
continue;
}
//UPDT//MMOItems.Log(" \u00a73Type-5 \u00a77Original Identification");
//UPDT//MMOItems.log(" \u00a73Type-5 \u00a77Original Identification");
}
// All right, lets add those to cached enchantments
cachedEnchantments.merge(processed);
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Trime Arcane Report: \u00a73-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77Cached:");
//UPDT//for (Enchantment e : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + cachedEnchantments.getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73> \u00a77Processed:");
//UPDT//for (Enchantment e : processed.getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + processed.getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73> \u00a77Processed:");
//UPDT//for (Enchantment e : processed.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + processed.getLevel(e)); }
}
}
@ -507,30 +905,14 @@ public class MMOItemReforger {
public ItemStack toStack() {
MMOItem buildingMMOItem = mmoItem.clone();
// For every cached stat (presumably due to its importance)
for (ItemStat stat : itemData.keySet()) {
//UPDT//MMOItems.Log(" \u00a72@\u00a78@ \u00a77Cached Stat");
// Replace into incoming MMOItem
StatData data = itemData.get(stat);
// Include if nonull
if (data != null) {
//UPDT//MMOItems.Log(" \u00a72@\u00a78@ \u00a77Old stat \u00a7f" + stat.getNBTPath());
// Set, replace, begone the previous!
buildingMMOItem.setData(stat, data);
}
}
// Apply histories
for (ItemStat stat : itemDataHistory.keySet()) {
//UPDT//MMOItems.Log(" \u00a72@\u00a76@ \u00a77Cached Stat History");
//UPDT//MMOItems.log(" \u00a72@\u00a76@ \u00a77Cached Stat History");
// Does it have history too?
StatHistory histOld = itemDataHistory.get(stat);
if (histOld != null) {
//UPDT//MMOItems.Log(" \u00a72 *\u00a76* \u00a77Of old stat \u00a7f" + histOld.getItemStat().getNBTPath());
//UPDT//MMOItems.log(" \u00a72 *\u00a76* \u00a77Of old stat \u00a7f" + histOld.getItemStat().getNBTPath());
// Regenerate the original data
StatHistory hist = StatHistory.from(buildingMMOItem, stat);
@ -545,7 +927,7 @@ public class MMOItemReforger {
// Apply soulbound
if (cachedSoulbound != null) {
//UPDT//MMOItems.Log(" \u00a7c@ \u00a77Applying Soulbind");
//UPDT//MMOItems.log(" \u00a7c@ \u00a77Applying Soulbind");
// Apply
buildingMMOItem.setData(ItemStats.SOULBOUND, cachedSoulbound);
@ -553,22 +935,22 @@ public class MMOItemReforger {
// Contained enchantments huh
if (cachedEnchantments != null) {
//UPDT//MMOItems.Log(" \u00a7b@ \u00a77Applying Enchantments");
//UPDT//for (Enchantment lr : cachedEnchantments.getEnchants()) { MMOItems.Log(" \u00a7b + \u00a77" + lr.getName() + " \u00a7f" + cachedEnchantments.getLevel(lr)); }
//UPDT//MMOItems.log(" \u00a7b@ \u00a77Applying Enchantments");
//UPDT//for (Enchantment lr : cachedEnchantments.getEnchants()) { MMOItems.log(" \u00a7b + \u00a77" + lr.getName() + " \u00a7f" + cachedEnchantments.getLevel(lr)); }
// Register as extraneous obviously
StatHistory hist = StatHistory.from(buildingMMOItem, ItemStats.ENCHANTS);
hist.registerExternalData(cachedEnchantments.cloneData());
//UPDT//MMOItems.Log(" \u00a7b:\u00a73:\u00a7: \u00a77Late Arcane Report: \u00a79-------------------------");
//UPDT//MMOItems.Log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.Log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.Log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a7b:\u00a73:\u00a7: \u00a77Late Arcane Report: \u00a79-------------------------");
//UPDT//MMOItems.log(" \u00a73> \u00a77History:");
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Original:");
//UPDT//for (Enchantment e : ((EnchantListData) hist.getOriginalData()).getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getOriginalData()).getLevel(e)); }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Stones:");
//UPDT//for (UUID data : hist.getAllGemstones()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77" + data.toString()); for (Enchantment e : ((EnchantListData) hist.getGemstoneData(data)).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) hist.getGemstoneData(data)).getLevel(e)); } }
//UPDT//MMOItems.log(" \u00a73=\u00a7b> \u00a77Externals:");
//UPDT//for (StatData data : hist.getExternalData()) { MMOItems.log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) data).getEnchants()) { MMOItems.log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) data).getLevel(e)); } }
// Recalculate and put
buildingMMOItem.setData(ItemStats.ENCHANTS, hist.recalculate());
@ -577,11 +959,11 @@ public class MMOItemReforger {
// Upgrade Information
if (cachedUpgradeLevel != null) {
//UPDT//MMOItems.Log(" \u00a7e@ \u00a77Applying Upgrade");
//UPDT//MMOItems.log(" \u00a7e@ \u00a77Applying Upgrade");
// If has a upgrade template defined, just remember the level
if (buildingMMOItem.hasData(ItemStats.UPGRADE)) {
//UPDT//MMOItems.Log(" \u00a7e* \u00a77Existing Upgrade Detected");
//UPDT//MMOItems.log(" \u00a7e* \u00a77Existing Upgrade Detected");
// Get current ig
UpgradeData current = ((UpgradeData) buildingMMOItem.getData(ItemStats.UPGRADE));
@ -589,7 +971,7 @@ public class MMOItemReforger {
// Edit level
processed.setLevel(Math.min(cachedUpgradeLevel.getLevel(), current.getMaxUpgrades()));
//UPDT//MMOItems.Log(" \u00a7e + \u00a77Set to level \u00a7f" + current.getLevel());
//UPDT//MMOItems.log(" \u00a7e + \u00a77Set to level \u00a7f" + current.getLevel());
// Re-set cuz why not
buildingMMOItem.setData(ItemStats.UPGRADE, processed);
@ -598,21 +980,21 @@ public class MMOItemReforger {
}
/*else {
//UPDT//MMOItems.Log(" \u00a7e* \u00a77Using Cached");
//UPDT//MMOItems.log(" \u00a7e* \u00a77Using Cached");
// Set from the cached
buildingMMOItem.setData(ItemStats.UPGRADE, new UpgradeData(cachedUpgradeLevel.getReference(), cachedUpgradeLevel.getTemplateName(), cachedUpgradeLevel.isWorkbench(), cachedUpgradeLevel.isDestroy(), cachedUpgradeLevel.getMax(), cachedUpgradeLevel.getSuccess()));
//UPDT//MMOItems.Log(" \u00a7e + \u00a77Set to level \u00a7f" + cachedUpgradeLevel.getLevel());
//UPDT//MMOItems.log(" \u00a7e + \u00a77Set to level \u00a7f" + cachedUpgradeLevel.getLevel());
} //*/
}
// Gem Stones
if (cachedGemStones != null) {
//UPDT//MMOItems.Log(" \u00a7a@ \u00a77Applying Gemstones");
//UPDT//MMOItems.log(" \u00a7a@ \u00a77Applying Gemstones");
// If has a upgrade template defined, just remember the level
if (buildingMMOItem.hasData(ItemStats.GEM_SOCKETS)) {
//UPDT//MMOItems.Log(" \u00a7a* \u00a77Existing Data Detected");
//UPDT//MMOItems.log(" \u00a7a* \u00a77Existing Data Detected");
// Get current ig
GemSocketsData current = ((GemSocketsData) buildingMMOItem.getData(ItemStats.GEM_SOCKETS));
@ -623,11 +1005,11 @@ public class MMOItemReforger {
// Remaining
for (GemstoneData data : oldSockets) {
//UPDT//MMOItems.Log(" \u00a7a*\u00a7e* \u00a77Fitting \u00a7f" + data.getHistoricUUID().toString());
//UPDT//MMOItems.log(" \u00a7a*\u00a7e* \u00a77Fitting \u00a7f" + data.getHistoricUUID().toString());
// No more if no more sockets left
if (availableSockets.size() <= 0) {
//UPDT//MMOItems.Log(" \u00a7a +\u00a7c+ \u00a77No More Sockets");
//UPDT//MMOItems.log(" \u00a7a +\u00a7c+ \u00a77No More Sockets");
// They all will fit anyway
break;
@ -657,7 +1039,7 @@ public class MMOItemReforger {
// And guess what... THAT is the colour of this gem! Fabulous huh?
data.setColour(remembrance);
//UPDT//MMOItems.Log(" \u00a7a + \u00a77Fit into color \u00a7f" + remembrance);
//UPDT//MMOItems.log(" \u00a7a + \u00a77Fit into color \u00a7f" + remembrance);
}
}
@ -672,11 +1054,11 @@ public class MMOItemReforger {
// Lore
if (!cachedLore.isEmpty()) {
//UPDT//MMOItems.Log(" \u00a7d@ \u00a77Applying Lore");
//UPDT//MMOItems.log(" \u00a7d@ \u00a77Applying Lore");
// If it has lore, add I guess
if (buildingMMOItem.hasData(ItemStats.LORE)) {
//UPDT//MMOItems.Log(" \u00a7d* \u00a77Inserting first");
//UPDT//MMOItems.log(" \u00a7d* \u00a77Inserting first");
// Get current ig
StringListData current = ((StringListData) buildingMMOItem.getData(ItemStats.LORE));
@ -690,7 +1072,7 @@ public class MMOItemReforger {
// Create stat
StringListData sData = new StringListData(cachedLore);
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.Log(" \u00a7d + \u00a77" + lr); }
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.log(" \u00a7d + \u00a77" + lr); }
// Set that as the lore
buildingMMOItem.setData(ItemStats.LORE, sData);
@ -698,7 +1080,7 @@ public class MMOItemReforger {
// Name
if (cachedName != null) {
//UPDT//MMOItems.Log(" \u00a73@ \u00a77Applying Name \u00a7f" + cachedName);
//UPDT//MMOItems.log(" \u00a73@ \u00a77Applying Name \u00a7f" + cachedName);
// Replace name completely
buildingMMOItem.setData(ItemStats.NAME, new StringData(cachedName));

View File

@ -3,6 +3,7 @@ package net.Indyuce.mmoitems.api.util;
import java.text.DecimalFormat;
import java.util.Random;
import net.Indyuce.mmoitems.MMOItems;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -11,6 +12,9 @@ import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
/**
* That Gaussian spread distribution thing that no one understands.
*/
public class NumericStatFormula implements RandomStatData {
private final double base, scale, spread, maxSpread;
@ -87,33 +91,81 @@ public class NumericStatFormula implements RandomStatData {
this.maxSpread = maxSpread;
}
public double getBase() {
return base;
}
/**
* @return The 'Base' number of the item. This chooses the peak of the Gaussian Distribution.
* @see #getScale()
*/
public double getBase() { return base; }
public double getScale() {
return scale;
}
public double getSpread() {
return spread;
}
/**
* @return When the item has a certain level or tier, this is how much each level shifts
* the peak, so that it is centered at {@code base + scale*level}
* @see #getBase()
*/
public double getScale() { return scale; }
public double getMaxSpread() {
return maxSpread;
}
/**
* @return Standard Deviation of the Gaussian Distribution
*/
public double getSpread() { return spread; }
/**
* @return For gaussian distributions, there always is that INSANELY SMALL chance of getting an INSANELY LARGE number.
* For example: At base atk dmg 10, and standard deviation 1:
* <p>68% of rolls will fall between 9 and 11;
* </p>95% of rolls will fall between 8 and 12;
* <p>99.7% of rolls will fall between 7 and 13;
* </p>10E-42 of a roll that will give you an epic 300 dmg sword
* <p></p>
* Whatever, this constrains to a minimum and maximum of output.
*/
public double getMaxSpread() { return maxSpread; }
public static boolean useRelativeSpread;
/**
* Applies the formula for a given input x.
*
* @param x Numeric input
* @return Let A = {base} + {scale} * x, then the returned value is a
* @param levelScalingFactor When choosing the mean of the distribution,
* the formula is <code>base + (scale*level)</code>.
* This is the <code>level</code>
*
* @return <b>Legacy formula: ???</b><br>
* Let A = {base} + {scale} * lvl, then the returned value is a
* random value taken in respect to a gaussian distribution
* centered on A, with average spread of {spread}%, and with a
* maximum offset of {maxSpread}% (relative to average value)
* <p></p>
* <b>Formula: Spread = Standard Deviation</b>
* The mean, the peak is located at <code>{base} + {scale}*lvl</code>. <br>
* The 'spread' is the standard deviation of the distribution. <br>
* 'Max Spread' constrains the result of this operation at <code>{mean}±{max spread}</code>
*/
public double calculate(double x) {
return (base + scale * x) * (1 + Math.min(Math.max(RANDOM.nextGaussian() * spread, -maxSpread), maxSpread));
public double calculate(double levelScalingFactor) {
if (useRelativeSpread) { return (base + scale * levelScalingFactor) * (1 + Math.min(Math.max(RANDOM.nextGaussian() * spread, -maxSpread), maxSpread)); }
/*
* The mean, the center of the distribution
*/
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.
*/
double gaussSpread = RANDOM.nextGaussian() * spread;
/*
* Does it exceed the max spread (positive or negative)? Not anymore!
*/
if (gaussSpread < (-getMaxSpread())) { gaussSpread = -getMaxSpread(); } else
if (gaussSpread > (getMaxSpread())) { gaussSpread = getMaxSpread(); }
// That's it
return actualBase + gaussSpread;
}
@Override
@ -161,7 +213,9 @@ public class NumericStatFormula implements RandomStatData {
+ (maxSpread != 0 ? ",Max=" + maxSpread : "") + "}";
}
public static enum FormulaSaveOption {
public static void reload() { useRelativeSpread = !MMOItems.plugin.getConfig().getBoolean("additive-spread-formula", false); }
public enum FormulaSaveOption {
/**
* When toggled on, if the formula is set to 0 then the configuration
@ -176,4 +230,5 @@ public class NumericStatFormula implements RandomStatData {
*/
NONE;
}
}

View File

@ -2,6 +2,7 @@ package net.Indyuce.mmoitems.command.mmoitems;
import io.lumine.mythic.lib.mmolibcommands.api.CommandTreeNode;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -64,6 +65,10 @@ public class ReloadCommandTreeNode extends CommandTreeNode {
+ MMOItems.plugin.getSets().getAll().size() + ChatColor.GRAY + " Item Sets");
sender.sendMessage(MMOItems.plugin.getPrefix() + "- " + ChatColor.RED
+ MMOItems.plugin.getUpgrades().getAll().size() + ChatColor.GRAY + " Upgrade Templates");
// *This one is not implementing Reloadable
NumericStatFormula.reload();
}
public void reloadRecipes(CommandSender sender) {

View File

@ -83,10 +83,9 @@ public class ItemListener implements Listener {
// Should this item be updated (via the updater)
if (shouldUpdate(nbt, type)) {
mod.reforge(MMOItems.plugin.getLanguage().rerollOnItemUpdate ? player : null, MMOItems.plugin.getLanguage().revisionOptions);
}
mod.update(MMOItems.plugin.getLanguage().rerollOnItemUpdate ? player : null, MMOItems.plugin.getLanguage().revisionOptions); }
// Should this item be soulbount?
// Should this item be soulbound?
if (shouldSoulbind(nbt, type)) { mod.applySoulbound(player); }
// Return either the changed one or null

View File

@ -138,7 +138,7 @@ public class RecipeManager implements Reloadable {
} catch (IllegalArgumentException exception) {
// Add message
ffp.log(FriendlyFeedbackCategory.ERROR, "Could not load recipe of $f{0} {1}$b: $r{2}",
ffp.log(FriendlyFeedbackCategory.ERROR, "Could not load recipe of $f{0} {1}$b: {2}",
type.getId(), template.getId(), exception.getMessage());
}
}

View File

@ -165,7 +165,7 @@ public class StatHistory {
* <p></p>
* Use <code>StatHistory.From()</code> to get the stat history associated to an item.
*/
StatHistory(@NotNull MMOItem ofItem, @NotNull ItemStat ofStat, @NotNull StatData ogData) { itemStat = ofStat; originalData = ogData; parent = ofItem; }
public StatHistory(@NotNull MMOItem ofItem, @NotNull ItemStat ofStat, @NotNull StatData ogData) { itemStat = ofStat; originalData = ogData; parent = ofItem; }
/**
* Checks the item and makes sure that the UUIDs