Fixes ticket 1393

This commit is contained in:
Gunging 2021-04-09 01:35:56 -05:00
parent 3bde9b1b32
commit cdda1b6179
26 changed files with 781 additions and 549 deletions

View File

@ -739,6 +739,8 @@ public class MMOItems extends LuminePlugin {
/**
* Easily log something using the FriendlyFeedbackProvider, nice!
* <p></p>
* Use a null level to use the normal console sender.
*
* @author Gunging
*/

View File

@ -21,6 +21,8 @@ public enum CustomSound {
private final String[] lore;
private final int slot;
CustomSound(Material material, int slot, String... lore) {
this.item = new ItemStack(material);
this.lore = lore;

View File

@ -116,27 +116,34 @@ public class UpgradeTemplate {
// Make sure to not overwrite player's enchantments when upgrading.
Enchants.separateEnchantments(mmoitem);
//UPGR//MMOItems.log(" \u00a73>\u00a7a> \u00a77Separated enchantments");
// Set the items level
UpgradeData dat;
if (mmoitem.hasData(ItemStats.UPGRADE)) { dat = (UpgradeData) mmoitem.getData(ItemStats.UPGRADE); } else { dat = new UpgradeData(null, null, false, false, 0, 100); }
if (mmoitem.hasData(ItemStats.UPGRADE)) {
dat = (UpgradeData) mmoitem.getData(ItemStats.UPGRADE);
} else { dat = new UpgradeData(null, null, false, false, 0, 100); }
dat.setLevel(level);
mmoitem.setData(ItemStats.UPGRADE, dat);
//UPGR//MMOItems.log("\u00a76>\u00a73>\u00a7a> \u00a77Upgrading to level \u00a7e" + dat.getLevel());
// For every Stat-UpgradeInfo pair
for (ItemStat stat : perStatUpgradeInfos.keySet()) {
//UPGR//MMOItems.log(" \u00a73>\u00a7a> \u00a77Upgrading stat \u00a7e" + stat.getId());
// Preprocess
((Upgradable) stat).preprocess(mmoitem);
// Initializes Stat History
StatHistory hist = StatHistory.from(mmoitem, stat);
//UPGR//MMOItems.log(" \u00a73>\u00a7a> \u00a77Stat History Initialized");
// Midprocess
((Upgradable) stat).midprocess(mmoitem);
// The Stat History now manages applying upgrades.
mmoitem.setData(stat, hist.recalculate());
mmoitem.setData(stat, hist.recalculate(level));
//UPGR//MMOItems.log(" \u00a73>\u00a7a> \u00a77Recalculated");
// Postprocess
((Upgradable) stat).postprocess(mmoitem);

View File

@ -24,6 +24,14 @@ public abstract class Ability {
protected static final Random random = new Random();
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Ability)) { return false; }
// Same name means same ability
return ((Ability) obj).getName().equals(getName());
}
public Ability(CastingMode... allowedModes) {
this.id = getClass().getSimpleName().toUpperCase().replace("-", "_").replace(" ", "_").replaceAll("[^A-Z_]", "");
this.name = getClass().getSimpleName().replace("_", " ");

View File

@ -13,6 +13,8 @@ import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.item.util.DynamicLore;
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.EnchantListData;
import net.Indyuce.mmoitems.stat.data.MaterialData;
import net.Indyuce.mmoitems.stat.data.StringListData;
@ -117,7 +119,15 @@ public class ItemStackBuilder {
public NBTItem buildNBT(boolean forDisplay) {
// Clone as to not conflict in any way
MMOItem builtMMOItem = mmoitem.clone();
//GEM//MMOItems.Log("\u00a7e+ \u00a77Building \u00a7c" + mmoitem.getType().getName() + " " + mmoitem.getId() + "\u00a77 (Size \u00a7e" + mmoitem.getStatHistories().size() + "\u00a77 Historic)");
//GEM//MMOItems.log("\u00a7e+ \u00a77Building \u00a7c" + mmoitem.getType().getName() + " " + mmoitem.getId() + "\u00a77 (Size \u00a7e" + mmoitem.getStatHistories().size() + "\u00a77 Historic)");
/*
* As an assumption for several enchantment recognition operations,
* Enchantment data must never be clear and lack history. This is
* the basis for when an item is 'old'
*/
if (!builtMMOItem.hasData(ItemStats.ENCHANTS)) { builtMMOItem.setData(ItemStats.ENCHANTS, ItemStats.ENCHANTS.getClearStatData()); }
//GEM// else {MMOItems.log("\u00a73 -?- \u00a77Apparently found enchantment data \u00a7b" + (mmoitem.getData(ItemStats.ENCHANTS) == null ? "null" : ((EnchantListData) mmoitem.getData(ItemStats.ENCHANTS)).getEnchants().size())); }
// For every stat within this item
for (ItemStat stat : builtMMOItem.getStats())
@ -125,21 +135,21 @@ public class ItemStackBuilder {
// Attempt to add
try {
//GEM//MMOItems.Log("\u00a7e -+- \u00a77Applying \u00a76" + stat.getNBTPath());
//GEM//MMOItems.log("\u00a7e -+- \u00a77Applying \u00a76" + stat.getNBTPath());
// Does the item have any stat history regarding thay?
StatHistory s = builtMMOItem.getStatHistory(stat);
StatHistory s = builtMMOItem.getStatHistory(stat); int l = mmoitem.getUpgradeLevel();
// Found it?
if (s != null) {
if (s != null && (!s.isClear() || stat instanceof Enchants)) {
//GEM//MMOItems.Log("\u00a7a -+- \u00a77Found History");
//GEM//MMOItems.log("\u00a7a -+- \u00a77Recording History");
// Add to NBT
addItemTag(new ItemTag(histroy_keyword + stat.getId(), s.toNBTString()));
// Recalculate
builtMMOItem.setData(stat, s.recalculate(true));
builtMMOItem.setData(stat, s.recalculate(l));
}
if (forDisplay && stat instanceof Previewable) {

View File

@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.UpgradeTemplate;
import net.Indyuce.mmoitems.api.item.ItemReference;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.GemSockets;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
@ -87,7 +88,7 @@ public class MMOItem implements ItemReference {
}
// Recalculate
setData(stat, sHistory.recalculate());
setData(stat, sHistory.recalculate(getUpgradeLevel()));
// Merging means replacing if it cannot be merged
} else {
@ -171,6 +172,17 @@ public class MMOItem implements ItemReference {
* A stat history is basically the memmory of its original stats, from when it was created, its gem stone stats, those added by which gem, and its upgrade bonuses.
*/
@Nullable public StatHistory getStatHistory(@NotNull ItemStat stat) {
/*
* As an assumption for several enchantment recognition operations,
* Enchantment data must never be clear and lack history. This is
* the basis for when an item is 'old'
*/
if (stat instanceof Enchants) { return mergeableStatHistory.getOrDefault(stat.getNBTPath(), StatHistory.from(this, stat, true)); }
/*
* Normal stat, just fetch.
*/
try {
// Well that REALLY should work

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmoitems.api.util;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.Ref;
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
@ -140,9 +141,10 @@ public class MMOItemReforger {
* specified in the config is used.
*/
public void update(@Nullable Player p, @NotNull ReforgeOptions options) {
update(p == null ? null : PlayerData.get(p).getRPG(), options);
if (p == null) { update((RPGPlayer) null, options); } else {
PlayerData dat = PlayerData.get(p);
if (dat == null) { update((RPGPlayer) null, options); } else { update(dat.getRPG(), options); } }
}
/**
* This method updates the base stats of this item to what
* the template currently has, only rerolling RNGs where the
@ -184,157 +186,35 @@ public class MMOItemReforger {
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);
}
if (options.shouldKeepName()) { keepName(meta); }
// 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); }
}
if (options.shouldKeepLore() && mmoItem.hasData(ItemStats.LORE)) { keepLore(); }
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)); }
}
if (options.shouldKeepEnchantments()) { Ref<EnchantListData> rf = new Ref<>(); keepEnchantments(rf); ambiguouslyOriginalEnchantmentCache = rf.getValue(); }
// 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));
}
if (options.shouldKeepUpgrades() && mmoItem.hasData(ItemStats.UPGRADE)) { keepUpgrades(); }
// 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);
}
if (options.shouldKeepGemStones() || options.shouldKeepExternalSH()) { cacheFullHistory(!options.shouldKeepGemStones(), !options.shouldKeepExternalSH()); }
// Soulbound transfer
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) {
//UPDT//MMOItems.log(" \u00a7c> \u00a77Keeping Soulbind");
// Find data
cachedSoulbound = mmoItem.getData(ItemStats.SOULBOUND);
}
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) { keepSoulbound(); }
// Store all the history of stat proceedings.
HashMap<ItemStat, StatHistory> temporalDataHistory = new HashMap<>();
//UPD//MMOItems.log(" \u00a71 * \u00a77Remembering Stats");
//UPDT//MMOItems.log(" \u00a71 * \u00a77Remembering Stats");
for (ItemStat stat : mmoItem.getStats()) {
//UPD//MMOItems.log(" \u00a79 * \u00a77Stat \u00a7f" + stat.getNBTPath());
//UPDT//MMOItems.log(" \u00a79 * \u00a77Stat \u00a7f" + stat.getNBTPath());
// Skip if it cant merge
if (!(stat.getClearStatData() instanceof Mergeable)) { continue; }
StatHistory hist = StatHistory.from(mmoItem, stat);
//UPD//MMOItems.log(" \u00a73 * \u00a77History of \u00a7f" + hist.getItemStat().getNBTPath());
//UPDT//MMOItems.log(" \u00a73 * \u00a77History of \u00a7f" + hist.getItemStat().getNBTPath());
// Clear externals
if (!options.shouldKeepExternalSH()) { hist.getExternalData().clear(); }
@ -346,13 +226,14 @@ public class MMOItemReforger {
* Generate fresh MMOItem, with stats that will be set if the chance is too low
*/
int determinedItemLevel = regenerate(player, template);
//UPD//MMOItems.log("Determined Level: \u00a7e" + determinedItemLevel);
//UPDT//MMOItems.log("Determined Level: \u00a7e" + determinedItemLevel);
/*
* Extra step: Check every stat history
*/
int l = mmoItem.getUpgradeLevel();
for (ItemStat stat : temporalDataHistory.keySet()) {
//UPD//MMOItems.log("\u00a7e @\u00a77 " + stat.getId());
//UPDT//MMOItems.log("\u00a7e @\u00a77 " + stat.getId());
// Get history
StatHistory hist = temporalDataHistory.get(stat);
@ -368,7 +249,7 @@ public class MMOItemReforger {
* If not, its gotten removed = we only keep extraneous
*/
if (source instanceof NumericStatFormula && hist.getOriginalData() instanceof DoubleData) {
//UPD//MMOItems.log("\u00a7a +\u00a77 Valid for Double Data procedure");
//UPDT//MMOItems.log("\u00a7a +\u00a77 Valid for Double Data procedure");
// Very well, chance checking is only available for NumericStatFormula class so
double base = ((NumericStatFormula) source).getBase() + (((NumericStatFormula) source).getScale() * determinedItemLevel);
@ -382,14 +263,14 @@ public class MMOItemReforger {
// How many standard deviations away?
double sD = Math.abs(shift / ((NumericStatFormula) source).getSpread());
if (NumericStatFormula.useRelativeSpread) { sD = Math.abs(shift / (((NumericStatFormula) source).getSpread() * base)); }
//UPD//MMOItems.log("\u00a7b *\u00a77 Base: \u00a73" + base);
//UPD//MMOItems.log("\u00a7b *\u00a77 Curr: \u00a73" + current);
//UPD//MMOItems.log("\u00a7b *\u00a77 Shft: \u00a73" + shift);
//UPD//MMOItems.log("\u00a7b *\u00a77 SDev: \u00a73" + sD);
//UPDT//MMOItems.log("\u00a7b *\u00a77 Base: \u00a73" + base);
//UPDT//MMOItems.log("\u00a7b *\u00a77 Curr: \u00a73" + current);
//UPDT//MMOItems.log("\u00a7b *\u00a77 Shft: \u00a73" + shift);
//UPDT//MMOItems.log("\u00a7b *\u00a77 SDev: \u00a73" + sD);
// Greater than max spread? Or heck, 0.1% Chance or less wth
if (sD > ((NumericStatFormula) source).getMaxSpread() || sD > 3.5) {
//UPD//MMOItems.log("\u00a7c -\u00a77 Ridiculous Range --- reroll");
//UPDT//MMOItems.log("\u00a7c -\u00a77 Ridiculous Range --- reroll");
// Adapt within reason
double reasonableShift = ((NumericStatFormula) source).getSpread() * Math.min(2, ((NumericStatFormula) source).getMaxSpread());
@ -403,14 +284,14 @@ public class MMOItemReforger {
// Data arguably fine tbh, just use previous
} else {
//UPD//MMOItems.log("\u00a7a +\u00a77 Acceptable Range --- kept");
//UPDT//MMOItems.log("\u00a7a +\u00a77 Acceptable Range --- kept");
// Just clone I guess
clear = new StatHistory(mmoItem, stat, ((DoubleData) hist.getOriginalData()).cloneData());
}
} else {
//UPD//MMOItems.log("\u00a7e +\u00a77 Not contained / unmerged --- reroll I suppose");
//UPDT//MMOItems.log("\u00a7e +\u00a77 Not contained / unmerged --- reroll I suppose");
// Make a clear one
clear = new StatHistory(mmoItem, stat, hist.getOriginalData());
@ -423,122 +304,25 @@ public class MMOItemReforger {
// Store
itemDataHistory.put(stat, clear);
mmoItem.setStatHistory(stat, clear);
mmoItem.setData(stat, clear.recalculate(false));
mmoItem.setData(stat, clear.recalculate(false, l));
}
/*
* 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)); }
}
if (options.shouldKeepEnchantments() && ambiguouslyOriginalEnchantmentCache != null) { ambiguouslyOriginalEnchantmentCache.identifyTrueOriginalEnchantments(mmoItem, cachedEnchantments);}
}
/**
* Creates a new item from the template itself
* @param p Player to roll modifies based on level
*/
void regenerate(@Nullable RPGPlayer p) {
loadVolatileMMOItem();
MMOItemTemplate template = MMOItems.plugin.getTemplates().getTemplate(mmoItem.getType(), mmoItem.getId()); ItemMeta meta = nbtItem.getItem().getItemMeta();
//noinspection ConstantConditions
if (template == null) { MMOItems.print(null, "Could not find template for $r{0} {1}$b. ", "MMOItems Reforger", mmoItem.getType().toString(), mmoItem.getId()); mmoItem = null; return; }
Validate.isTrue(meta != null, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Invalid item meta prevented $f{0}$b from updating.", template.getType().toString() + " " + template.getId()));
//UPD//MMOItems.log("\u00a79*\u00a77 Regenerating... \u00a7d" + template.getId() + " " + template.getType());
//UPDT//MMOItems.log("\u00a79*\u00a77 Regenerating... \u00a7d" + template.getId() + " " + template.getType());
if (p != null) {
@ -548,6 +332,11 @@ public class MMOItemReforger {
mmoItem = template.newBuilder((mmoItem.hasData(ItemStats.ITEM_LEVEL) ? (int) ((DoubleData) mmoItem.getData(ItemStats.ITEM_LEVEL)).getValue() : 0 ), null).build();
}
}
/**
* Creates a new item from the template itself
* @param player Player to roll modifies based on level
* @param template Template to generate MMOItem from
*/
int regenerate(@Nullable RPGPlayer player, @NotNull MMOItemTemplate template) {
int determinedItemLevel;
@ -610,9 +399,9 @@ public class MMOItemReforger {
* specified in the config is used.
*/
public void reforge(@Nullable Player p, @NotNull ReforgeOptions options) {
reforge(p == null ? null : PlayerData.get(p).getRPG(), options);
}
if (p == null) { reforge((RPGPlayer) null, options); } else {
PlayerData dat = PlayerData.get(p);
if (dat == null) { reforge((RPGPlayer) null, options); } else { reforge(dat.getRPG(), options); } } }
/**
* Generates a new item of the same Type-ID and transfers the data
* from the old one following the options.
@ -624,6 +413,7 @@ public class MMOItemReforger {
* If empty, it will use the old items level and tier,
* or default values if needed.
*/
@SuppressWarnings("ConstantConditions")
public void reforge(@Nullable RPGPlayer player, @NotNull ReforgeOptions options) {
if (options.isRegenerate()) { regenerate(player); return; }
@ -634,265 +424,198 @@ public class MMOItemReforger {
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);
}
if (options.shouldKeepName()) { keepName(meta);}
// 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); }
}
if (options.shouldKeepLore() && mmoItem.hasData(ItemStats.LORE)) { keepLore(); }
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)); }
}
if (options.shouldKeepEnchantments()) { Ref<EnchantListData> rf = new Ref<>(); keepEnchantments(rf); ambiguouslyOriginalEnchantmentCache = rf.getValue(); }
// 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));
}
if (options.shouldKeepUpgrades() && mmoItem.hasData(ItemStats.UPGRADE)) { keepUpgrades(); }
// Gather Gemstones
if (options.shouldKeepGemStones() || options.shouldKeepExternalSH()) {
// Got any gem sockets bro?
if (mmoItem.hasData(ItemStats.GEM_SOCKETS) && options.shouldKeepGemStones()) {
//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());
// Clear externals
if (!options.shouldKeepExternalSH()) { hist.getExternalData().clear(); }
// Get and set
itemDataHistory.put(hist.getItemStat(), hist);
}
}
if (options.shouldKeepGemStones() || options.shouldKeepExternalSH()) { cacheFullHistory(!options.shouldKeepGemStones(), !options.shouldKeepExternalSH()); }
// Soulbound transfer
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) {
//UPDT//MMOItems.log(" \u00a7c> \u00a77Keeping Soulbind");
// Find data
cachedSoulbound = mmoItem.getData(ItemStats.SOULBOUND);
}
if (options.shouldKeepSoulbind() && mmoItem.hasData(ItemStats.SOULBOUND)) { keepSoulbound(); }
// Recreates this item from the template
regenerate(player, template);
/*
* 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");
if (options.shouldKeepEnchantments() && ambiguouslyOriginalEnchantmentCache != null) { ambiguouslyOriginalEnchantmentCache.identifyTrueOriginalEnchantments(mmoItem, cachedEnchantments);}
}
// 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");
/**
* Literally just copies the name onto the cached name
* @param meta Meta of the item uuuuh
*/
void keepName(@NotNull ItemMeta meta) {
//UPDT//MMOItems.log(" \u00a73> \u00a77Keeping Name");
ambiguouslyOriginalEnchantmentCache.clear();
// Does it have a name?
if (mmoItem.hasData(ItemStats.NAME)) {
//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)); }
// Cache it
cachedName = mmoItem.getData(ItemStats.NAME).toString();
//UPDT//MMOItems.log(" \u00a73> \u00a77Ambiguous:");
//UPDT//for (Enchantment e : ambiguouslyOriginalEnchantmentCache.getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getLevel(e)); }
// No name defined, use display name I guess (pretty unusual btw)
} else if (meta.hasDisplayName()) {
return;
}
if (!mmoItem.hasData(ItemStats.ENCHANTS)) { mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData());}
cachedName = meta.getDisplayName(); }
// 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(" \u00a73 + \u00a77" + cachedName);
}
/**
* Examines the MMOItems Lore of the item being updated, and chooses which lore
* lines are desirable to keep (Those that start with §7)
*/
void keepLore() {
//UPDT//MMOItems.log(" \u00a7d> \u00a77Keeping Lore");
// All right, lets add those to cached enchantments
cachedEnchantments.merge(ambiguouslyOriginalEnchantmentCache);
// Examine every element
for (String str : ((StringListData) mmoItem.getData(ItemStats.LORE)).getList()) {
//UPDT//MMOItems.log(" \u00a7d>\u00a7c-\u00a7e- \u00a77Line:\u00a7f " + str);
//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)); }
// Does it start with the promised...?
if (str.startsWith("\u00a77")) {
//UPDT//MMOItems.log(" \u00a72>\u00a7a-\u00a7e- \u00a77Kept");
cachedLore.add(str); }
}
//UPDT//MMOItems.log(" \u00a7d> \u00a77Result");
//UPDT//for (String lr : cachedLore) { //UPDT//MMOItems.log(" \u00a7d + \u00a77" + lr); }
}
/**
*
* Step #1: Identify the current (not-null) enchantment data (creates one if missing)
*
* Step #2: Caches that data, and stores the current form as 'ambiguously original'
*
* Step #3: Completely merges cached enchantment with all extraneous enchantment list data in the History.
* I don't remember why it does it, "As to not include it in this in the cached data later" is
* what the comment says. Seems I had a reason to do it like that.
*
* @param ambiguouslyOriginalEnchantmentCache For now, we must keep a reference to the supposed 'Original Enchantment Data'
* which may not be original (and thus contain player enchantments)
*/
void keepEnchantments(@NotNull Ref<EnchantListData> ambiguouslyOriginalEnchantmentCache) {
//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, created blanc");
mmoItem.setData(ItemStats.ENCHANTS, new EnchantListData()); }
//UPDT//else { MMOItems.log(" \u00a7b* \u00a77Found Data"); }
// Make sure they are consolidated
Enchants.separateEnchantments(mmoItem);
// Gather
StatHistory hist = StatHistory.from(mmoItem, ItemStats.ENCHANTS);
ambiguouslyOriginalEnchantmentCache.setValue((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.getValue().getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getValue().getLevel(e)); }
// Reap
for (StatData pEnchants : hist.getExternalData()) {
// It really should be but whatever
if (pEnchants instanceof EnchantListData) {
// Merge bruh
((EnchantListData) pEnchants).merge(cachedEnchantments);
// For every stat
for (Enchantment e : ((EnchantListData) pEnchants).getEnchants()) {
// Get result
int calculated = ((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.getValue().getEnchants()) { MMOItems.log(" \u00a7b * \u00a77" + e.getName() + " \u00a7f" + ambiguouslyOriginalEnchantmentCache.getValue().getLevel(e)); }
}
/**
* Just copies the upgrade data, with info on the level of course.
*/
void keepUpgrades() {
//UPDT//MMOItems.log(" \u00a7e> \u00a77Keeping Upgrade Data");
// Get Level
cachedUpgradeLevel = ((UpgradeData) mmoItem.getData(ItemStats.UPGRADE));
}
/**
* Caches the full history of these items.
*
* @param clearGems Should ignore gemstones?
* @param clearExternalSH Should ignore external stat history?
*/
void cacheFullHistory(boolean clearGems, boolean clearExternalSH) {
// Got any gem sockets bro?
if (mmoItem.hasData(ItemStats.GEM_SOCKETS) && !clearGems) {
//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());
// Clear externals
if (clearExternalSH) { hist.getExternalData().clear(); }
// Get and set
itemDataHistory.put(hist.getItemStat(), hist);
}
}
/**
* Just copies the soulbound :B
*/
void keepSoulbound() {
//UPDT//MMOItems.log(" \u00a7c> \u00a77Keeping Soulbind");
// Find data
cachedSoulbound = mmoItem.getData(ItemStats.SOULBOUND);
}
/**
@ -900,21 +623,30 @@ public class MMOItemReforger {
*/
public boolean hasChanges() { return mmoItem != null; }
/**
* Applies all the cached data on to the newly generated MMOItem, then builds
*
* @return Built item with changes applied
*/
public ItemStack toStack() {
MMOItem buildingMMOItem = mmoItem.clone();
// Apply histories
int l = mmoItem.getUpgradeLevel();
for (ItemStat stat : itemDataHistory.keySet()) {
//UPDT//MMOItems.log(" \u00a72@\u00a76@ \u00a77Cached Stat History");
//UPDT//MMOItems.log(" \u00a72@\u00a76@ \u00a77Found Cached Stat History \u00a76" + stat.getId());
// Does it have history too?
StatHistory histOld = itemDataHistory.get(stat);
if (histOld == null) { continue; }
if (histOld == null) {
//UPDT//MMOItems.log(" \u00a72 *\u00a76* \u00a7cMissing");
continue; }
// Is it compltely clear?
if (histOld.isClear()) { continue; }
//UPDT//MMOItems.log(" \u00a72 *\u00a76* \u00a77Of old stat \u00a7f" + histOld.getItemStat().getNBTPath());
if (histOld.isClear()) {
//UPDT//MMOItems.log(" \u00a72 *\u00a76* \u00a7cClear");
continue; }
//UPDT//MMOItems.log(" \u00a72 *\u00a76* \u00a7cNot clear: \u00a73Gems" + histOld.getAllGemstones().size() + " \u00a78|\u00a7b ExSH " + histOld.getExternalData().size());
// Regenerate the original data
StatHistory hist = StatHistory.from(buildingMMOItem, stat);
@ -923,7 +655,7 @@ public class MMOItemReforger {
hist.assimilate(histOld);
// Recalculate
buildingMMOItem.setData(hist.getItemStat(), hist.recalculate(false));
buildingMMOItem.setData(hist.getItemStat(), hist.recalculate(false, l));
}
// Apply soulbound
@ -954,7 +686,7 @@ public class MMOItemReforger {
//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());
buildingMMOItem.setData(ItemStats.ENCHANTS, hist.recalculate(mmoItem.getUpgradeLevel()));
}
// Upgrade Information
@ -977,15 +709,16 @@ public class MMOItemReforger {
// Re-set cuz why not
buildingMMOItem.setData(ItemStats.UPGRADE, processed);
// Otherwise, the level AND template shall prevail
}
// Actually decided that if the upgrade template is removed, server owner probably intends to clear upgrades so...
/*else {
//UPDT//MMOItems.log(" \u00a7e* \u00a77Using Cached");
// New item has no Upgrade data? Then the old level AND template shall prevail
//----//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());
//----//MMOItems.log(" \u00a7e + \u00a77Set to level \u00a7f" + cachedUpgradeLevel.getLevel());
} //*/
}
@ -1073,7 +806,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) { MMOItems.log(" \u00a7d + \u00a77" + lr); }
// Set that as the lore
buildingMMOItem.setData(ItemStats.LORE, sData);
@ -1088,7 +821,10 @@ public class MMOItemReforger {
}
// Apply upgrades
if (buildingMMOItem.hasUpgradeTemplate()) { buildingMMOItem.getUpgradeTemplate().upgradeTo(buildingMMOItem, buildingMMOItem.getUpgradeLevel()); }
if (buildingMMOItem.hasUpgradeTemplate()) {
//UPDT//MMOItems.log(" \u00a7f@ \u00a77Recalculating Upgrades");
buildingMMOItem.getUpgradeTemplate().upgradeTo(buildingMMOItem, buildingMMOItem.getUpgradeLevel()); }
// Build and set amount
ItemStack stack = buildingMMOItem.newBuilder().build();

View File

@ -362,7 +362,7 @@ public class Enchants extends ItemStat implements Upgradable {
//SENCH//for (StatData date : hist.getExternalData()) { MMOItems.Log(" \u00a7b==\u00a73> \u00a77 --------- "); for (Enchantment e : ((EnchantListData) date).getEnchants()) { MMOItems.Log(" \u00a7b *\u00a73* \u00a77" + e.getName() + " \u00a7f" + ((EnchantListData) date).getLevel(e)); } }
// All right, whats the expected enchantment levels?
EnchantListData expected = (EnchantListData) hist.recalculate();
EnchantListData expected = (EnchantListData) hist.recalculate(mmoitem.getUpgradeLevel());
// Gather a list of extraneous enchantments
HashMap<Enchantment, Integer> discrepancies = new HashMap<>();

View File

@ -74,7 +74,7 @@ public class RequiredLevel extends DoubleStat implements ItemRestriction {
String builtRange;
if (SilentNumbers.round(techMinimum, 2) == SilentNumbers.round(techMaximum, 2)) { builtRange = SilentNumbers.readableRounding(techMinimum, 0); }
else { builtRange = SilentNumbers.readableRounding(techMinimum, 0) + "-" + SilentNumbers.readableRounding(techMaximum, 0); }
else { builtRange = SilentNumbers.removeDecimalZeros(String.valueOf(techMinimum)) + "-" + SilentNumbers.removeDecimalZeros(String.valueOf(techMaximum)); }
// Just display normally
item.getLore().insert("required-level", formatNumericStat(techMinimum, "#", builtRange));

View File

@ -18,6 +18,28 @@ public class AbilityData {
private final CastingMode castMode;
private final Map<String, Double> modifiers = new HashMap<>();
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AbilityData)) { return false; }
// Compare casitng mode
if (((AbilityData) obj).getCastingMode() != getCastingMode()) { return false; }
// Not same ability
if (!((AbilityData) obj).getAbility().equals(getAbility())) { return false; }
// Check modifiers
for (String mod : ((AbilityData) obj).getModifiers()) {
// Any difference?
double objMod = ((AbilityData) obj).getModifier(mod);
double thisMod = getModifier(mod);
if (objMod != thisMod) { return false; } }
// Success
return true;
}
public AbilityData(JsonObject object) {
ability = MMOItems.plugin.getAbilities().getAbility(object.get("Id").getAsString());
castMode = CastingMode.valueOf(object.get("CastMode").getAsString());

View File

@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import org.apache.commons.lang.Validate;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
@ -33,6 +34,31 @@ public class AbilityListData implements StatData, Mergeable {
abilities.addAll(((AbilityListData) data).abilities);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof AbilityListData)) { return false; }
// Different number of abilities? Not equal
if (getAbilities().size() != ((AbilityListData) obj).getAbilities().size()) { return false; }
// Examine each
for (AbilityData ab : ((AbilityListData) obj).getAbilities()) {
if (ab == null) { continue; }
boolean unmatched = true;
for (AbilityData thi : getAbilities()) { if (ab.equals(thi)) { unmatched = false; break; } }
// Extraneous ability found, not equal.
if (unmatched) { return false; }
}
return true; }
@Override
public @NotNull StatData cloneData() { return new AbilityListData(getAbilities()); }
@Override
public boolean isClear() { return getAbilities().size() == 0; }
}

View File

@ -7,6 +7,19 @@ public class CommandData {
private final double delay;
private final boolean console, op;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CommandData)) { return false; }
// Any difference in these will cause this to not be equal
if (((CommandData) obj).getDelay() != getDelay()) { return false; }
if (((CommandData) obj).isConsoleCommand() != isConsoleCommand()) { return false; }
if (((CommandData) obj).hasOpPerms() != hasOpPerms()) { return false; }
// Finally, if the command strings match.
return ((CommandData) obj).getCommand().equals(getCommand());
}
public CommandData(String command, double delay, boolean console, boolean op) {
Validate.notNull(command, "Command cannot be null");

View File

@ -4,6 +4,7 @@ import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import org.apache.commons.lang.Validate;
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
@ -33,6 +34,29 @@ public class CommandListData implements StatData, Mergeable, RandomStatData {
return commands;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof CommandListData)) { return false; }
if (((CommandListData) obj).getCommands().size() != getCommands().size()) { return false; }
for (CommandData objCommand : ((CommandListData) obj).getCommands()) {
if (objCommand == null) { continue; }
// Compare to mine
boolean unmatched = true;
for (CommandData thisCommand : getCommands()) {
// Unequal? Fail
if (objCommand.equals(thisCommand)) { unmatched = false; break; } }
if (unmatched) { return false; }
}
// Success
return true;
}
@Override
public void merge(StatData data) {
Validate.isTrue(data instanceof CommandListData, "Cannot merge two different stat data types");
@ -44,6 +68,9 @@ public class CommandListData implements StatData, Mergeable, RandomStatData {
return new CommandListData(commands);
}
@Override
public boolean isClear() { return getCommands().size() == 0; }
@Override
public StatData randomize(MMOItemBuilder builder) {
return new CommandListData(new HashSet<>(commands));

View File

@ -35,6 +35,16 @@ public class DoubleData implements StatData, Mergeable {
value += ((DoubleData) data).value;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof DoubleData)) { return false; }
return ((DoubleData) obj).getValue() == getValue(); }
@Override
public @NotNull StatData cloneData() { return new DoubleData(getValue()); }
@Override
public boolean isClear() { return getValue() == 0; }
}

View File

@ -30,6 +30,24 @@ public class ElementListData implements StatData, Mergeable {
return damage.keySet();
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof ElementListData)) { return false; }
if (((ElementListData) obj).damage.size() != damage.size() || ((ElementListData) obj).defense.size() != defense.size()) { return false; }
for (Element e : Element.values()) {
double expectedDA = getDamage(e);
double expectedDE = getDefense(e);
double realDA = ((ElementListData) obj).getDamage(e);
double realDE = ((ElementListData) obj).getDefense(e);
// Any differene?
if (expectedDA != realDA || expectedDE != realDE) { return false; } }
return true;
}
/**
* No way to add the elements directly from the constructor.
* <p></p>
@ -83,5 +101,10 @@ public class ElementListData implements StatData, Mergeable {
return ret;
}
@Override
public boolean isClear() {
return getDamageElements().size() == 0 && getDefenseElements().size() == 0;
}
}

View File

@ -4,8 +4,11 @@ import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
@ -30,6 +33,18 @@ public class EnchantListData implements StatData, Mergeable {
}
public void clear() { enchants.clear(); }
@Override
public boolean equals(Object obj) {
if (!(obj instanceof EnchantListData)) { return false; }
if (((EnchantListData) obj).enchants.size() != enchants.size()) { return false; }
for (Enchantment e : getEnchants()) {
// Compare
if (getLevel(e) != ((EnchantListData) obj).getLevel(e)) { return false; } }
return true;
}
@Override
public void merge(StatData data) {
Validate.isTrue(data instanceof EnchantListData, "Cannot merge two different stat data types");
@ -70,4 +85,117 @@ public class EnchantListData implements StatData, Mergeable {
return ret;
}
@Override
public boolean isClear() {
// Any non lvl 0 enchantment?
for (Enchantment e : getEnchants()) { if (getLevel(e) != 0) { return false; } }
return true;
}
/**
* 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
*
* @param mmoItem The item, to provide context for adequate guessing.
* @param output Merges all 'Extraneous' enchantments onto this one
*
*/
public void identifyTrueOriginalEnchantments(@NotNull MMOItem mmoItem, @NotNull EnchantListData output) {
//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");
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
output.merge(this);
//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 : getEnchants()) {
//UPDT//MMOItems.log(" \u00a7b = \u00a77Per Enchant - \u00a7f" + e.getName());
// Lets see hmm
int current = 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
output.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)); }
}
}

View File

@ -6,6 +6,7 @@ import java.util.List;
import java.util.Set;
import io.lumine.mythic.lib.api.util.Ref;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.api.interaction.GemStone;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import org.apache.commons.lang.Validate;
@ -29,6 +30,32 @@ public class GemSocketsData implements StatData, Mergeable, RandomStatData {
this.emptySlots = emptySlots;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof GemSocketsData)) { return false; }
if (((GemSocketsData) obj).getEmptySlots().size() != getEmptySlots().size()) { return false; }
if (((GemSocketsData) obj).getGemstones().size() != getGemstones().size()) { return false; }
if (!SilentNumbers.hasAll(((GemSocketsData) obj).getEmptySlots(), getEmptySlots())) { return false; }
for (GemstoneData objGem : ((GemSocketsData) obj).getGemstones()) {
if (objGem == null) { continue; }
// Validate with ours
boolean unmatched = true;
for (GemstoneData thisGem : getGemstones()) {
// Test match
if (objGem.equals(thisGem)) {
unmatched = false;
break; }
}
if (unmatched) { return false; } }
// All equal
return true;
}
/**
* Attempts to find a slot of the same color of this gem within the item.
* <p></p>
@ -103,6 +130,9 @@ public class GemSocketsData implements StatData, Mergeable, RandomStatData {
return ret;
}
@Override
public boolean isClear() { return getGemstones().size() == 0 && getEmptySlots().size() == 0; }
@Override
public StatData randomize(MMOItemBuilder builder) {
return new GemSocketsData(new ArrayList<>(emptySlots));

View File

@ -21,6 +21,20 @@ public class GemstoneData {
@Nullable Integer levelPut = 0;
@NotNull final UUID historicUUID;
/**
* Gemstone equals method is for practical purposes and only checks that
* this other thing is both a GemstoneData and has the same UUID.
*
* @param obj Object to compare with
* @return <code>true</code> if they have the same {@link #getHistoricUUID()}
*/
@Override
public boolean equals(Object obj) {
if (!(obj instanceof GemstoneData)) { return false; }
return ((GemstoneData) obj).getHistoricUUID().equals(getHistoricUUID());
}
@Nullable
public String getMMOItemType() {
return mmoitemType;

View File

@ -10,6 +10,15 @@ public class PotionEffectData {
private final double duration;
private final int level;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PotionEffectData)) { return false; }
if (((PotionEffectData) obj).getLevel() != getLevel()) { return false; }
if (((PotionEffectData) obj).getDuration() != getDuration()) { return false; }
return type.equals(((PotionEffectData) obj).getType());
}
public PotionEffectData(PotionEffectType type, int level) {
this(type, (double) MMOUtils.getEffectDuration(type) / 20d, level);
}

View File

@ -20,6 +20,29 @@ public class PotionEffectListData implements StatData, Mergeable {
// PotionEffectData(config.getConfigurationSection(key)));
// }
@Override
public boolean equals(Object obj) {
if (!(obj instanceof PotionEffectListData)) { return false; }
if (((PotionEffectListData) obj).getEffects().size() != getEffects().size()) { return false; }
for (PotionEffectData eff : ((PotionEffectListData) obj).getEffects()) {
if (eff == null) { continue; }
// COmpare
boolean unmatched = true;
for (PotionEffectData thi : getEffects()) {
if (eff.equals(thi)) {
unmatched = false;
break; } }
if (unmatched) { return false; }
}
return true;
}
public PotionEffectListData(PotionEffectData... effects) {
add(effects);
}
@ -40,4 +63,9 @@ public class PotionEffectListData implements StatData, Mergeable {
@Override
public @NotNull StatData cloneData() { return new PotionEffectListData(getEffects().toArray(new PotionEffectData[0])); }
@Override
public boolean isClear() {
return getEffects().size() == 0;
}
}

View File

@ -39,6 +39,11 @@ public class RestoreData implements StatData, Mergeable {
saturation = value;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof RestoreData)) { return false; }
return ((RestoreData) obj).getFood() == getFood() && ((RestoreData) obj).getHealth() == getHealth() && ((RestoreData) obj).getSaturation() == getSaturation(); }
@Override
public void merge(StatData data) {
Validate.isTrue(data instanceof RestoreData, "Cannot merge two different stat data types");
@ -51,4 +56,9 @@ public class RestoreData implements StatData, Mergeable {
public @NotNull StatData cloneData() {
return new RestoreData(getHealth(), getFood(), getSaturation());
}
@Override
public boolean isClear() {
return getFood() == 0 && getHealth() == 0 && getSaturation() == 0;
}
}

View File

@ -40,6 +40,27 @@ public class SoundListData implements StatData, Mergeable, RandomStatData {
this.sounds.put(type, data);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SoundListData)) { return false; }
if (((SoundListData) obj).getCustomSounds().size() != getCustomSounds().size()) { return false; }
for (CustomSound sound : ((SoundListData) obj).getCustomSounds()) {
if (sound == null) { continue; }
boolean unmatched = true;
for (CustomSound thi : getCustomSounds()) {
if (sound.equals(thi)) {
unmatched = false;
break; } }
if (unmatched) { return false; }
}
return true;
}
@Override
public void merge(StatData data) {
Validate.isTrue(data instanceof SoundListData, "Cannot merge two different stat data types");
@ -50,6 +71,11 @@ public class SoundListData implements StatData, Mergeable, RandomStatData {
@Override
public @NotNull StatData cloneData() { return new SoundListData(mapData()); }
@Override
public boolean isClear() {
return mapData().size() == 0;
}
@Override
public StatData randomize(MMOItemBuilder builder) {
return new SoundListData(new HashMap<>(sounds));

View File

@ -2,7 +2,9 @@ package net.Indyuce.mmoitems.stat.data;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.stat.StoredTags;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import org.apache.commons.lang.Validate;
@ -25,6 +27,23 @@ public class StoredTagsData implements StatData, Mergeable {
}
public StoredTagsData(List<ItemTag> tgs) { tags.addAll(tgs); }
@Override
public boolean equals(Object obj) {
if (!(obj instanceof StoredTagsData)) { return false; }
if (((StoredTagsData) obj).getTags().size() != getTags().size()) { return false; }
for (ItemTag tag : ((StoredTagsData) obj).getTags()) {
if (tag == null) { continue; }
boolean unmatched = true;
for (ItemTag tg : getTags()) {
if (tag.equals(tg)) { unmatched = false; break; } }
if (unmatched) { return false; } }
return true;
}
public StoredTagsData(NBTItem nbt) {
for (String tag : nbt.getTags()) {
// Any vanilla or MMOItem tag should be ignored as those are
@ -100,4 +119,9 @@ public class StoredTagsData implements StatData, Mergeable {
@Override
public @NotNull
StatData cloneData() { return new StoredTagsData(getTags()); }
@Override
public boolean isClear() {
return getTags().size() == 0;
}
}

View File

@ -4,6 +4,7 @@ import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import org.apache.commons.lang.Validate;
import com.google.gson.JsonArray;
@ -17,6 +18,13 @@ import org.jetbrains.annotations.NotNull;
public class StringListData implements StatData, RandomStatData, Mergeable {
@NotNull private final List<String> list;
@Override
public boolean equals(Object obj) {
if (!(obj instanceof StringListData)) { return false; }
if (((StringListData) obj).getList().size() != getList().size()) { return false; }
return SilentNumbers.hasAll(((StringListData) obj).getList(), getList());
}
public StringListData() {
this(new ArrayList<>());
}
@ -52,4 +60,7 @@ public class StringListData implements StatData, RandomStatData, Mergeable {
@Override
public @NotNull StatData cloneData() { return new StringListData(getList()); }
@Override
public boolean isClear() { return getList().size() == 0; }
}

View File

@ -9,6 +9,9 @@ import org.jetbrains.annotations.NotNull;
* when used through Gem Stones. However, this serves a crucial internal
* role in determining which stats generate {@link StatHistory}es, which in
* turn allows them to be {@link Upgradable}.
* <p></p>
* <b>Strongly encouraged to override the <code>equals</code> method
* to something fitting here as Mergeable stats should support comparisons.</b>
*/
public interface Mergeable {
@ -23,4 +26,10 @@ public interface Mergeable {
* Returns a Data with the same values as this, but that is not this.
*/
@NotNull StatData cloneData();
/**
* @return <code>true</code> If this is the default state of the StatData, like an enchantment
* list data having 0 enchantments, or a percent bonus double stat having a value of 0.
*/
boolean isClear();
}

View File

@ -8,6 +8,7 @@ import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.data.*;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
@ -45,12 +46,31 @@ public class StatHistory {
*/
public boolean isClear() {
// Any gemstones? Then its NOT CLEAR
if (getAllGemstones().size() > 0) { return false; }
/*
* Enchant list data is not clear even if redundant.
*
* Its an important assumption in several methods
* like Enchants.separateEnchantments()
*/
if(getOriginalData() instanceof EnchantListData) {
if (((EnchantListData) getOriginalData()).getEnchants().size() != 0) {
//GEM//MMOItems.log("\u00a7a -+- \u00a77Found Enchantments, \u00a7cnot clear.");
return false;
} }
// TRUE if there are no externals
return getExternalData().size() == 0;
}
// Any gemstones or external SH? Then its NOT CLEAR
if (getAllGemstones().size() > 0 || getExternalData().size() > 0) {
//GEM//MMOItems.log("\u00a7a -+- \u00a77Found Gemstones / ESH, \u00a7cnot clear.");
return false; }
// Is it clear?
if (((Mergeable) getOriginalData()).isClear()) {
//GEM//MMOItems.log("\u00a7a -+- \u00a77Original data is clear, \u00a7aclear.");
return true; }
// Exactly the same as the MMOItem? [This check should basically always be true though]
//GEM//if (getOriginalData().equals(getMMOItem().getData(getItemStat()))) { MMOItems.log("\u00a7a -+- \u00a77Original data has never been merged, \u00a7aclear."); }
return getOriginalData().equals(getMMOItem().getData(getItemStat())); }
/*
* What MMOItem is this StatHistory linked to?
@ -136,19 +156,38 @@ public class StatHistory {
* and will be forever unchangeable.
* <p></p>
* <b>Make sure the item has the stat present</b>
*
* @param ofItem MMOItem to extract stat history from
* @param ofStat Stat of which to make history
*/
@NotNull public static StatHistory from(@NotNull MMOItem ofItem, @NotNull ItemStat ofStat) {
@NotNull public static StatHistory from(@NotNull MMOItem ofItem, @NotNull ItemStat ofStat) { return from(ofItem, ofStat, false); }
/**
* Gets the stat history of this item. <b>The stat must be <code>Mergeable</code></b>
* <p></p>
* If the item has no stat history, it will be created anew and appended; the current stat values will become the 'Original' ones,
* and will be forever unchangeable.
* <p></p>
* <b>Make sure the item has the stat present</b>
*
* @param ofItem MMOItem to extract stat history from
* @param ofStat Stat of which to make history
* @param forceNew <b>Only if you know what you are doing</b>, set to true to not check if the item already has stat history of this stat.
*/
@NotNull
public static StatHistory from(@NotNull MMOItem ofItem, @NotNull ItemStat ofStat, boolean forceNew) {
// Get history :B
StatHistory hist = ofItem.getStatHistory(ofStat);
StatHistory hist;
if (!forceNew) {
hist = ofItem.getStatHistory(ofStat);
// Found? Thats it
if (hist != null) {
//UPGRD//MMOItems.Log("Found Stat History of \u00a76" + ofStat.getNBTPath() + "\u00a77 in this \u00a7c" + ofItem.getType().getName() + " " + ofItem.getId());
return hist; }
//UPGRD//MMOItems.Log("\u00a7aCreated Hisotry of \u00a76" + ofStat.getNBTPath() + "\u00a7a of this \u00a7c" + ofItem.getType().getName() + " " + ofItem.getId());
// Found? Thats it
if (hist != null) {
//UPGRD//MMOItems.log("Found Stat History of \u00a76" + ofStat.getNBTPath() + "\u00a77 in this \u00a7c" + ofItem.getType().getName() + " " + ofItem.getId());
return hist; } }
// That is Mergeable right...
//UPGRD//MMOItems.log("\u00a7aCreated Hisotry of \u00a76" + ofStat.getNBTPath() + "\u00a7a of this \u00a7c" + ofItem.getType().getName() + " " + ofItem.getId());
Validate.isTrue(ofStat.getClearStatData() instanceof Mergeable, "Non-Mergeable stat data wont have a Stat History; they cannot be modified dynamically in the first place.");
// Get original data
@ -156,11 +195,11 @@ public class StatHistory {
if (original == null) {
original = ofStat.getClearStatData();
ofItem.setData(ofStat, original);
//UPGRD//MMOItems.Log("\u00a7e +\u00a77 Item didnt have this stat, original set as blanc.");
//UPGRD//MMOItems.log("\u00a7e +\u00a77 Item didnt have this stat, original set as blanc.");
}
else {
original = ((Mergeable) original).cloneData();
//UPGRD//MMOItems.Log("\u00a7a +\u00a77 Found original data");
//UPGRD//MMOItems.log("\u00a7a +\u00a77 Found original data");
}
// Create new
@ -234,7 +273,7 @@ public class StatHistory {
* This will not apply the changes, it will just give you the final
* <code>StatData</code> that shall be applied (used when upgrading).
*/
@NotNull public StatData recalculate() { return recalculate(true); }
@NotNull public StatData recalculate(int level) { return recalculate(true, level); }
/**
* This recalculates final value of the stats of the item.
* <p></p>
@ -244,18 +283,22 @@ public class StatHistory {
* Leave <code>true</code> unless you know
* what you're doing.
*/
@NotNull public StatData recalculate(boolean withPurge) {
@NotNull public StatData recalculate(boolean withPurge, int level) {
//UPGRD//MMOItems.log("\u00a7d|||\u00a77 Recalculating \u00a7f" + getItemStat().getNBTPath() + "\u00a77, Purge? \u00a7e" + withPurge);
if (withPurge) { purgeGemstones(); }
// If its upgradeable and not level ZERO, it must apply upgrades
if ((getMMOItem().getUpgradeLevel() != 0) &&
//UPGRD//MMOItems.log("\u00a7d|\u00a79|\u00a76|\u00a77 Upgradeable Requirements: ");
//UPGRD//MMOItems.log(" \u00a76|\u00a77 Upgrade Level: \u00a7e" + level);
//UPGRD//MMOItems.log(" \u00a76|\u00a77 Upgradeable Stat: \u00a7e" + (getItemStat() instanceof Upgradable));
//UPGRD//MMOItems.log(" \u00a76|\u00a77 Template Exists: \u00a7e" + (getMMOItem().hasUpgradeTemplate()));
if ((level != 0) &&
(getItemStat() instanceof Upgradable) &&
(getMMOItem().hasUpgradeTemplate())) {
// Recalculate upgrading
return recalculateUpgradeable();
return recalculateUpgradeable(level);
}
// Merge Normally
@ -266,7 +309,7 @@ public class StatHistory {
* This recalculates values accounting only for gemstones and external data.
* <p></p>
* In case someone was wondered the contribution of upgrading the item, just
* substract it from {@link #recalculate()}
* substract it from {@link #recalculate(int)}
*/
@NotNull public StatData recalculateUnupgraded() { return recalculateUnupgraded(true); }
@ -274,7 +317,7 @@ public class StatHistory {
* This recalculates values accounting only for gemstones and external data.
* <p></p>
* In case someone was wondered the contribution of upgrading the item, just
* substract it from {@link #recalculate()}
* substract it from {@link #recalculate(int)}
* @param withPurge Check if the gemstones UUIDs are valid.
* Leave <code>true</code> unless you know
* what you're doing.
@ -296,7 +339,7 @@ public class StatHistory {
* </p>4: Sums Gem Stone Data (which should be scaled accordingly [Upgrades are entirely merged into their data])
* <p>5: Sums external data (modifiers that are not linked to an ID, I suppose by external plugins).
*/
private StatData recalculateUpgradeable() {
private StatData recalculateUpgradeable(int lvl) {
//UPGRD//MMOItems.log("\u00a76|||\u00a77 Calculating \u00a7f" + getItemStat().getNBTPath() + "\u00a77 as Upgradeable");
// Get Upgrade Info?
@ -309,11 +352,10 @@ public class StatHistory {
StatData ogCloned = ((Mergeable) originalData).cloneData();
// Level up
int lvl = getMMOItem().getUpgradeLevel();
//UPGRD//MMOItems.Log("\u00a76 ||\u00a77 Item Level: \u00a7e" + lvl);
//DBL//if (ogCloned instanceof DoubleData) MMOItems.Log("\u00a76 >\u00a77 Original Base: \u00a7e" + ((DoubleData) ogCloned).getValue());
//UPGRD//MMOItems.log("\u00a76 ||\u00a77 Item Level: \u00a7e" + lvl);
//DBL//if (ogCloned instanceof DoubleData) MMOItems.log("\u00a76 >\u00a77 Original Base: \u00a7e" + ((DoubleData) ogCloned).getValue());
StatData ret = ((Upgradable) getItemStat()).apply(ogCloned, inf, lvl);
//DBL//if (ret instanceof DoubleData) MMOItems.Log("\u00a76 >\u00a77 Leveled Base: \u00a7e" + ((DoubleData) ret).getValue());
//DBL//if (ret instanceof DoubleData) MMOItems.log("\u00a76 >\u00a77 Leveled Base: \u00a7e" + ((DoubleData) ret).getValue());
// Add up gemstones
for (UUID d : perGemstoneData.keySet()) {
@ -343,13 +385,13 @@ public class StatHistory {
// Calculate level difference
int gLevel = lvl - level;
//UPGRD//MMOItems.Log("\u00a76 |\u00a7b|\u00a76>\u00a77 Gemstone Level: \u00a7e" + gLevel + "\u00a77 (Put at \u00a7b" + level + "\u00a77)");
//UPGRD//MMOItems.log("\u00a76 |\u00a7b|\u00a76>\u00a77 Gemstone Level: \u00a7e" + gLevel + "\u00a77 (Put at \u00a7b" + level + "\u00a77)");
//DBL//if (getGemstoneData(d) instanceof DoubleData) MMOItems. Log("\u00a76 \u00a7b|>\u00a77 Gemstone Base: \u00a7e" + ((DoubleData) getGemstoneData(d)).getValue());
//DBL//if (getGemstoneData(d) instanceof DoubleData) MMOItems.log("\u00a76 \u00a7b|>\u00a77 Gemstone Base: \u00a7e" + ((DoubleData) getGemstoneData(d)).getValue());
// Apply upgrades
//noinspection ConstantConditions
StatData gRet = ((Upgradable) getItemStat()).apply(((Mergeable) getGemstoneData(d)).cloneData(), inf, gLevel);
//DBL//if (gRet instanceof DoubleData) MMOItems.Log("\u00a76 \u00a7b|>\u00a77 Leveled Base: \u00a7e" + ((DoubleData) gRet).getValue());
//DBL//if (gRet instanceof DoubleData) MMOItems.log("\u00a76 \u00a7b|>\u00a77 Leveled Base: \u00a7e" + ((DoubleData) gRet).getValue());
// Merge
((Mergeable) ret).merge(gRet);
@ -358,13 +400,13 @@ public class StatHistory {
// Add up externals
for (StatData d : perExternalData) {
//DBL//if (d instanceof DoubleData) MMOItems.Log("\u00a76 >\u00a7c> \u00a77 Extraneous Base: \u00a7e" + ((DoubleData) d).getValue());
//DBL//if (d instanceof DoubleData) MMOItems.log("\u00a76 >\u00a7c> \u00a77 Extraneous Base: \u00a7e" + ((DoubleData) d).getValue());
// Just merge ig
((Mergeable) ret).merge(((Mergeable) d).cloneData());
}
// Return result
//DBL//if (ret instanceof DoubleData) MMOItems.Log("\u00a76:::\u00a77 Result: \u00a7e" + ((DoubleData) ret).getValue());
//DBL//if (ret instanceof DoubleData) MMOItems.log("\u00a76:::\u00a77 Result: \u00a7e" + ((DoubleData) ret).getValue());
return ret;
}
@ -383,23 +425,23 @@ public class StatHistory {
// Just clone bro
StatData ret = ((Mergeable) getOriginalData()).cloneData();
//DBL//if (ret instanceof DoubleData) MMOItems.Log("\u00a73 > \u00a77 Original Base: \u00a7e" + ((DoubleData) ret).getValue());
//DBL//if (ret instanceof DoubleData) MMOItems.log("\u00a73 > \u00a77 Original Base: \u00a7e" + ((DoubleData) ret).getValue());
// Add up gemstones
for (StatData d : perGemstoneData.values()) {
//DBL//if (d instanceof DoubleData) MMOItems.Log("\u00a73 >\u00a7b> \u00a77 Gemstone Base: \u00a7e" + ((DoubleData) d).getValue());
//DBL//if (d instanceof RequiredLevelData) MMOItems.Log("\u00a73 >\u00a7e> \u00a76 Required Level Data Apparently");
//DBL//if (d instanceof DoubleData) MMOItems.log("\u00a73 >\u00a7b> \u00a77 Gemstone Base: \u00a7e" + ((DoubleData) d).getValue());
//DBL//if (d instanceof RequiredLevelData) MMOItems.log("\u00a73 >\u00a7e> \u00a76 Required Level Data Apparently");
((Mergeable) ret).merge(d);
}
// Add up externals
for (StatData d : perExternalData) {
//DBL//if (d instanceof DoubleData) MMOItems.Log("\u00a73 >\u00a7c> \u00a77 Extraneous Base: \u00a7e" + ((DoubleData) d).getValue());
//DBL//if (d instanceof DoubleData) MMOItems.log("\u00a73 >\u00a7c> \u00a77 Extraneous Base: \u00a7e" + ((DoubleData) d).getValue());
((Mergeable) ret).merge(d);
}
// Return result
//DBL//if (ret instanceof DoubleData) MMOItems.Log("\u00a73:::\u00a77 Result: \u00a7b" + ((DoubleData) ret).getValue());
//DBL//if (ret instanceof DoubleData) MMOItems.log("\u00a73:::\u00a77 Result: \u00a7b" + ((DoubleData) ret).getValue());
return ret;
}
@ -449,6 +491,9 @@ public class StatHistory {
// Compress I suppose
for (StatData ex : perExternalData) {
// Skip clear
if (((Mergeable) ex).isClear()) { continue; }
// Put
externals.add(ItemTag.compressTags(getItemStat().getAppliedNBT(ex)));
}
@ -637,10 +682,10 @@ public class StatHistory {
// Stat must be the same
if (other.getItemStat().getNBTPath().equals(getItemStat().getNBTPath())) {
//UPDT//MMOItems.Log(" \u00a72>\u00a76> \u00a77History Stat Matches");
//UPDT//MMOItems.log(" \u00a72>\u00a76> \u00a77History Stat Matches");
//UPDT//MMOItems.Log(" \u00a76:\u00a72: \u00a77Original Gemstones \u00a7f" + perGemstoneData.size());
//UPDT//MMOItems.Log(" \u00a76:\u00a72: \u00a77Original Externals \u00a7f" + perExternalData.size());
//UPDT//MMOItems.log(" \u00a76:\u00a72: \u00a77Original Gemstones \u00a7f" + perGemstoneData.size());
//UPDT//MMOItems.log(" \u00a76:\u00a72: \u00a77Original Externals \u00a7f" + perExternalData.size());
// Register gemstones
for (UUID exUID : other.perGemstoneData.keySet()) {
@ -650,8 +695,8 @@ public class StatHistory {
// Register externals
for (StatData ex : other.perExternalData) { registerExternalData((ex)); }
//UPDT//MMOItems.Log(" \u00a76:\u00a72: \u00a77Final Gemstones \u00a7f" + perGemstoneData.size());
//UPDT//MMOItems.Log(" \u00a76:\u00a72: \u00a77Final Externals \u00a7f" + perExternalData.size());
//UPDT//MMOItems.log(" \u00a76:\u00a72: \u00a77Final Gemstones \u00a7f" + perGemstoneData.size());
//UPDT//MMOItems.log(" \u00a76:\u00a72: \u00a77Final Externals \u00a7f" + perExternalData.size());
}
}