Refactored classes related to gemstones

This commit is contained in:
Jules 2025-01-17 21:15:02 +01:00
parent b3f1f4055b
commit 769e45eeb3
89 changed files with 1036 additions and 732 deletions

View File

@ -1,8 +1,6 @@
package net.Indyuce.mmoitems;
import com.archyx.aureliumskills.acf.annotation.CommandCompletion;
import io.lumine.mythic.lib.version.VMaterial;
import net.Indyuce.mmoitems.command.mmoitems.AbilityCommandTreeNode;
import net.Indyuce.mmoitems.stat.*;
import net.Indyuce.mmoitems.stat.block.*;
import net.Indyuce.mmoitems.stat.component.builtin.*;
@ -42,7 +40,7 @@ public class ItemStats {
public static final ItemStat<StringComponent> GEN_TEMPLATE = new GenTemplate();
public static final ItemStat<StringComponent> DISPLAYED_TYPE = new DisplayedType();
public static final ItemStat ENCHANTS = new Enchants();
public static final Enchants ENCHANTS = new Enchants();
public static final ItemStat<BooleanComponent> HIDE_ENCHANTS = new HideEnchants();
public static final ItemStat<ArrayComponent<StringComponent>> PERMISSION = new Permission();
public static final ItemStat<ObjectComponent> ITEM_PARTICLES = new ItemParticles();
@ -83,7 +81,7 @@ public class ItemStats {
public static final ItemStat PARRY_COOLDOWN_REDUCTION = new DoubleStat("PARRY_COOLDOWN_REDUCTION", Material.BUCKET, "Parry Cooldown Reduction", new String[]{"Reduces the parrying cooldown (%)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat COOLDOWN_REDUCTION = new DoubleStat("COOLDOWN_REDUCTION", Material.BOOK, "Cooldown Reduction", new String[]{"Reduces cooldowns of item and player skills (%)."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat RANGE = new DoubleStat("RANGE", Material.STICK, "Range", new String[]{"The range of your item attacks."}, new String[]{"staff", "whip", "wand", "musket", "gem_stone"}).setCategory(StatCategories.RANGED_WEAPONS);
public static final ItemStat MANA_COST = new ManaCost();
public static final DoubleStat MANA_COST = new ManaCost();
public static final ItemStat STAMINA_COST = new DoubleStat("STAMINA_COST", Material.LIGHT_GRAY_DYE, "Stamina Cost", new String[]{"Stamina spent by your weapon to be used."}, new String[]{"weapon"}).setCategory(StatCategories.USE_COST);
public static final ItemStat ARROW_VELOCITY = new DoubleStat("ARROW_VELOCITY", Material.ARROW, "Arrow Velocity", new String[]{"Determines how far your", "weapon can shoot.", "Default: 1.0"}, new String[]{"gem_stone", "bow", "crossbow"}).setCategory(StatCategories.RANGED_WEAPONS);
public static final ItemStat ARROW_POTION_EFFECTS = new ArrowPotionEffects();
@ -125,37 +123,36 @@ public class ItemStats {
public static final ItemStat DROP_ON_DEATH = new DisableDeathDrop();
public static final ItemStat HIDE_DURABILITY_BAR = new HideDurabilityBar();
public static final ItemStat// Extra Attributes (1.20.2+)
MAX_ABSORPTION = new MaxAbsorption();
public static final ItemStat BLOCK_BREAK_SPEED = new BlockBreakSpeed();
public static final ItemStat BLOCK_INTERACTION_RANGE = new BlockInteractionRange();
public static final ItemStat ENTITY_INTERACTION_RANGE = new EntityInteractionRange();
public static final ItemStat FALL_DAMAGE_MULTIPLIER = new FallDamageMultiplier();
public static final ItemStat GRAVITY = new Gravity();
public static final ItemStat JUMP_STRENGTH = new JumpStrength();
public static final ItemStat SAFE_FALL_DISTANCE = new SafeFallDistance();
public static final ItemStat SCALE = new Scale();
public static final ItemStat STEP_HEIGHT = new StepHeight();
public static final ItemStat BURNING_TIME = new BurningTime();
public static final ItemStat EXPLOSION_KNOCKBACK_RESISTANCE = new ExplosionKnockbackResistance();
public static final ItemStat MINING_EFFICIENCY = new MiningEfficiency();
public static final ItemStat MOVEMENT_EFFICIENCY = new MovementEfficiency();
public static final ItemStat OXYGEN_BONUS = new OxygenBonus();
public static final ItemStat SNEAKING_SPEED = new SneakingSpeed();
public static final ItemStat SUBMERGED_MINING_SPEED = new SubmergedMiningSpeed();
public static final ItemStat SWEEPING_DAMAGE_RATIO = new SweepingDamageRatio();
public static final ItemStat WATER_MOVEMENT_EFFICIENCY = new WaterMovementEfficiency();
// Extra Attributes (1.20.2+)
public static final DoubleStat MAX_ABSORPTION = new MaxAbsorption();
public static final DoubleStat BLOCK_BREAK_SPEED = new BlockBreakSpeed();
public static final DoubleStat BLOCK_INTERACTION_RANGE = new BlockInteractionRange();
public static final DoubleStat ENTITY_INTERACTION_RANGE = new EntityInteractionRange();
public static final DoubleStat FALL_DAMAGE_MULTIPLIER = new FallDamageMultiplier();
public static final DoubleStat GRAVITY = new Gravity();
public static final DoubleStat JUMP_STRENGTH = new JumpStrength();
public static final DoubleStat SAFE_FALL_DISTANCE = new SafeFallDistance();
public static final DoubleStat SCALE = new Scale();
public static final DoubleStat STEP_HEIGHT = new StepHeight();
public static final DoubleStat BURNING_TIME = new BurningTime();
public static final DoubleStat EXPLOSION_KNOCKBACK_RESISTANCE = new ExplosionKnockbackResistance();
public static final DoubleStat MINING_EFFICIENCY = new MiningEfficiency();
public static final DoubleStat MOVEMENT_EFFICIENCY = new MovementEfficiency();
public static final DoubleStat OXYGEN_BONUS = new OxygenBonus();
public static final DoubleStat SNEAKING_SPEED = new SneakingSpeed();
public static final DoubleStat SUBMERGED_MINING_SPEED = new SubmergedMiningSpeed();
public static final DoubleStat SWEEPING_DAMAGE_RATIO = new SweepingDamageRatio();
public static final DoubleStat WATER_MOVEMENT_EFFICIENCY = new WaterMovementEfficiency();
public static final ItemStat// Permanent Effects
PERM_EFFECTS = new PermanentEffects();
public static final ItemStat GRANTED_PERMISSIONS = new GrantedPermissions();
public static final PermanentEffects PERM_EFFECTS = new PermanentEffects();
public static final StringListStat GRANTED_PERMISSIONS = new GrantedPermissions();
public static final ItemStat// Consumable Stats
RESTORE_HEALTH = new RestoreHealth();
public static final ItemStat RESTORE_FOOD = new RestoreFood();
public static final ItemStat RESTORE_SATURATION = new RestoreSaturation();
public static final ItemStat RESTORE_MANA = new RestoreMana();
public static final ItemStat RESTORE_STAMINA = new RestoreStamina();
// Consumable Stats
public static final DoubleStat RESTORE_HEALTH = new RestoreHealth();
public static final DoubleStat RESTORE_FOOD = new RestoreFood();
public static final DoubleStat RESTORE_SATURATION = new RestoreSaturation();
public static final DoubleStat RESTORE_MANA = new RestoreMana();
public static final DoubleStat RESTORE_STAMINA = new RestoreStamina();
public static final ItemStat CAN_IDENTIFY = new CanIdentify();
public static final ItemStat CAN_DECONSTRUCT = new CanDeconstruct();
public static final ItemStat CAN_DESKIN = new CanDeskin();
@ -183,7 +180,7 @@ public class ItemStats {
public static final ItemStat BOUNCING_CRACK = new BooleanStat("BOUNCING_CRACK", Material.COBBLESTONE_WALL, "Bouncing Crack", "When toggled on, your tool will also break nearby blocks.", new String[]{"tool"}).setCategory(StatCategories.TOOLS);
public static final ItemStat PICKAXE_POWER = new PickaxePower();
//public static final ItemStatCUSTOM_SOUNDS = new CustomSounds(),
//ELEMENTS = new Elements(),
//ELEMENTS = new Elements(),
public static final ItemStat<ArrayComponent<CommandComponent>> COMMANDS = new Commands();
// STAFF_SPIRIT = new StaffSpiritStat(),
public static final ItemStat<StringComponent> LUTE_ATTACK_SOUND = new LuteAttackSoundStat();
@ -227,7 +224,7 @@ public class ItemStats {
public static final ItemStat<ArrayComponent<StringComponent>> NAME_PREFIXES = new DisplayNamePrefixes();
public static final ItemStat<ArrayComponent<StringComponent>> NAME_SUFFIXES = new DisplayNameSuffixes();
public static final ItemStat<ObjectComponent> SOULBOUND = new Soulbound();
public static final ItemStat<IntegerComponent> CUSTOM_DURABILITY = new CustomDurability();
public static final ItemStat<IntegerComponent> ITEM_LEVEL = new ItemLevel();
public static final ItemStat<IntegerComponent> BROWSER_DISPLAY_IDX = new BrowserDisplayIDX();
public static final IntegerStat CUSTOM_DURABILITY = new CustomDurability();
public static final IntegerStat ITEM_LEVEL = new ItemLevel();
public static final IntegerStat BROWSER_DISPLAY_IDX = new BrowserDisplayIDX();
}

View File

@ -5,10 +5,9 @@ import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
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.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.Upgradable;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
@ -49,7 +48,7 @@ public class UpgradeTemplate {
ItemStat stat = MMOItems.plugin.getStats().get(statFormat);
if (stat == null) { ffp.log(FriendlyFeedbackCategory.ERROR, "Stat '$r{0}$b' $fnot found$b.", statFormat); continue; }
if (!(stat instanceof Upgradable)) { ffp.log(FriendlyFeedbackCategory.ERROR, "Stat $r{0}$b is $fnot upgradeable$b.", stat.getId()); continue; }
if (!(stat.getClearStatData() instanceof Mergeable)) { ffp.log(FriendlyFeedbackCategory.ERROR, "Stat Data used by $r{0}$b is $fnot mergeable$b, and thus it cannot be upgradeable. Contact the dev of this ItemStat.", stat.getId()); continue; }
//if (!(stat.getClearStatData() instanceof Mergeable)) { ffp.log(FriendlyFeedbackCategory.ERROR, "Stat Data used by $r{0}$b is $fnot mergeable$b, and thus it cannot be upgradeable. Contact the dev of this ItemStat.", stat.getId()); continue; }
// Attempt to parse Upgrade Info
try {

View File

@ -22,7 +22,7 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.data.EnchantListData;
import net.Indyuce.mmoitems.stat.component.builtin.composite.EnchantMapComponent;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import org.bukkit.Material;
import org.bukkit.enchantments.Enchantment;
@ -572,11 +572,11 @@ public class CustomSmithingRecipe extends MythicRecipeOutput {
/*
* Things must be merged:
*
* 1 Gem Stones - Checks which gem stones can still fit
* 1 Gem Stones - Checks which gemstones can still fit
*
* 2 Upgrades - Performs an operation with the combination of them both
*
* 3 Enchantments - Operation witht he combination of them both
* 3 Enchantments - Operation with the combination of them both
*/
// Extract gemstones
@ -628,9 +628,12 @@ public class CustomSmithingRecipe extends MythicRecipeOutput {
if (getEnchantmentTreatment() != SmithingCombinationType.NONE) {
// Get enchantment data
EnchantListData genEnchants = (EnchantListData) gen.getData(ItemStats.ENCHANTS); if (genEnchants == null) { genEnchants = (EnchantListData) ItemStats.ENCHANTS.getClearStatData(); }
EnchantListData itemEnchants = item != null ? (EnchantListData) item.getData(ItemStats.ENCHANTS) : Enchants.fromVanilla(itemStack);
EnchantListData ingotEnchants = ingot != null ? (EnchantListData) ingot.getData(ItemStats.ENCHANTS) : Enchants.fromVanilla(ingotStack);
EnchantMapComponent genEnchants = gen.getComponent(ItemStats.ENCHANTS);
if (genEnchants == null) {
genEnchants = ItemStats.ENCHANTS.generateEmptyComponent();
}
EnchantMapComponent itemEnchants = item != null ? item.getComponent(ItemStats.ENCHANTS) : Enchants.fromVanilla(itemStack);
EnchantMapComponent ingotEnchants = ingot != null ? ingot.getComponent(ItemStats.ENCHANTS) : Enchants.fromVanilla(ingotStack);
// For every enchant
for (Enchantment observedEnchantment : Enchantment.values()) {
@ -650,11 +653,11 @@ public class CustomSmithingRecipe extends MythicRecipeOutput {
default: if (genLevel == 0) { finalLevel = SilentNumbers.ceil((itemLevel + ingotLevel) / 2D); } else { finalLevel = SilentNumbers.ceil((itemLevel + ingotLevel + genLevel) / 3D); } break; }
//ECH// MMOItems.log("§8Smith §8ENCH§7 Result: \u00a7a" + finalLevel);
genEnchants.addEnchant(observedEnchantment, finalLevel);
genEnchants.setLevel(observedEnchantment, finalLevel);
}
// Set data :wazowksibruhmoment:
gen.setData(ItemStats.ENCHANTS, genEnchants);
gen.setComponent(ItemStats.ENCHANTS, genEnchants);
}
// All right whats the level stuff up now

View File

@ -5,10 +5,6 @@ import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.util.MMOItemReforger;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import org.bukkit.entity.Player;
import org.bukkit.event.Cancellable;
import org.bukkit.event.Event;

View File

@ -10,13 +10,13 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.Enchants;
import net.Indyuce.mmoitems.stat.GemUpgradeScaling;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -51,15 +51,13 @@ public class GemStone extends UseItem {
@NotNull
public ApplyResult applyOntoItem(@NotNull MMOItem targetMMO, @NotNull Type targetType, @NotNull String itemName, boolean buildStack, boolean silent) {
if (!targetMMO.hasData(ItemStats.GEM_SOCKETS))
return new ApplyResult(ResultType.NONE);
// Safecheck
GemstonesComponent sockets = targetMMO.getComponent(ItemStats.GEM_SOCKETS);
if (sockets == null) return new ApplyResult(ResultType.NONE);
String gemType = getNBTItem().getString(ItemStats.GEM_COLOR.getNBTPath());
GemSocketsData sockets = (GemSocketsData) targetMMO.getData(ItemStats.GEM_SOCKETS);
String foundSocketColor = sockets.getEmptySocket(gemType);
if (foundSocketColor == null)
return new ApplyResult(ResultType.NONE);
String foundSocketColor = sockets.findEmptySocket(gemType, false);
if (foundSocketColor == null) return new ApplyResult(ResultType.NONE);
// Checks if the gem supports the item type, or the item set, or a weapon
String appliableTypes = getNBTItem().getString(ItemStats.ITEM_TYPE_RESTRICTION.getNBTPath());
@ -96,21 +94,21 @@ public class GemStone extends UseItem {
* permanent effects. also REGISTER gemstone in the item gemstone list.
*/
LiveMMOItem gemMMOItem = new LiveMMOItem(getNBTItem());
GemstoneData gemData = new GemstoneData(gemMMOItem, foundSocketColor);
GemstoneComponent gemData = new GemstoneComponent(gemMMOItem, foundSocketColor);
/*
* Now must apply the gem sockets data to the Stat History and then recalculate.
* Gotta, however, find the correct StatData to which apply it to.
*/
StatHistory gemStory = targetMMO.computeStatHistory(ItemStats.GEM_SOCKETS);
findEmptySocket(gemStory, gemType, gemData);
targetMMO.setData(ItemStats.GEM_SOCKETS, gemStory.recalculate(targetMMO.getUpgradeLevel()));
StatHistory<GemstonesComponent> gemStory = targetMMO.computeStatHistory(ItemStats.GEM_SOCKETS);
applyThroughStatHistory(gemStory, gemType, gemData);
targetMMO.setComponent(ItemStats.GEM_SOCKETS, gemStory.recalculate(targetMMO.getUpgradeLevel()));
/*
* Get the item's level, important for the GemScalingStat
*/
Integer levelIdentified = null;
final String scaling = gemMMOItem.hasData(ItemStats.GEM_UPGRADE_SCALING) ? gemMMOItem.getData(ItemStats.GEM_UPGRADE_SCALING).toString() : GemUpgradeScaling.defaultValue;
final String scaling = gemMMOItem.hasData(ItemStats.GEM_UPGRADE_SCALING) ? gemMMOItem.getData(ItemStats.GEM_UPGRADE_SCALING).toString() : GemUpgradeScaling.DEFAULT_VALUE;
switch (scaling) {
case "HISTORIC":
levelIdentified = 0;
@ -129,7 +127,7 @@ public class GemStone extends UseItem {
final StatData data = gemMMOItem.getData(stat);
if (data instanceof Mergeable)
targetMMO.mergeData(stat, data, gemData.getHistoricUUID());
targetMMO.mergeData(stat, data, gemData.getUniqueId());
}
if (!silent) {
@ -143,28 +141,23 @@ public class GemStone extends UseItem {
return new ApplyResult(targetMMO, ResultType.SUCCESS);
}
private void findEmptySocket(StatHistory socketHistory, String gemType, GemstoneData gemstone) {
private void applyThroughStatHistory(StatHistory<GemstonesComponent> socketHistory, String gemType, GemstoneComponent gemstone) {
// Og data
GemSocketsData data = ((GemSocketsData) socketHistory.getOriginalData());
if (data.apply(gemType, gemstone)) return;
GemstonesComponent ogData = socketHistory.getOriginalData();
if (ogData.applyGemstone(gemType, gemstone)) return;
// Modifiers
for (UUID modifierId : socketHistory.getAllModifiers()) {
data = (GemSocketsData) socketHistory.getModifiersBonus(modifierId);
if (data.apply(gemType, gemstone)) return;
}
for (UUID modifierId : socketHistory.getAllModifiers())
if (socketHistory.getModifiersBonus(modifierId).applyGemstone(gemType, gemstone)) return;
// External
for (StatData untypedData : socketHistory.getExternalData()) {
data = (GemSocketsData) untypedData;
if (data.apply(gemType, gemstone)) return;
}
for (GemstonesComponent comp : socketHistory.getExternalData())
if (comp.applyGemstone(gemType, gemstone)) return;
// Gems
for (UUID gemId : socketHistory.getAllGemstones()) {
data = (GemSocketsData) socketHistory.getGemstoneData(gemId);
if (data.apply(gemType, gemstone)) return;
if (socketHistory.getGemstoneData(gemId).applyGemstone(gemType, gemstone)) return;
}
throw new RuntimeException("MMOItem contains available socket but not its socket stat history");

View File

@ -9,8 +9,10 @@ import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.MaterialComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.data.SkullTextureData;
import net.Indyuce.mmoitems.stat.data.StringListData;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@ -21,8 +23,6 @@ import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.*;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class ItemSkin extends UseItem {
@Deprecated
public ItemSkin(Player player, NBTItem item) {
@ -46,42 +46,38 @@ public class ItemSkin extends UseItem {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Applying onto " + MMOUtils.getDisplayName(target.getItem()));
// Types compatibility check
if (mmoitem.hasData(ItemStats.COMPATIBLE_TYPES)) {
final ArrayComponent<StringComponent> acceptedTypes = mmoitem.getComponent(ItemStats.COMPATIBLE_TYPES);
if (acceptedTypes != null && !acceptedTypes.asList().isEmpty()) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that TYPE is compatible: ");
final List<String> acceptedTypes = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_TYPES)).getList();
if (acceptedTypes.size() > 0 && acceptedTypes.stream().noneMatch(s -> s.equalsIgnoreCase(targetType.getId()))) {
if (acceptedTypes.asList().stream().noneMatch(s -> s.getValue().equalsIgnoreCase(targetType.getId()))) {
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
.send(player);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem())).send(player);
return new ApplyResult(ResultType.NONE);
}
}
// IDs compatibility check
if (mmoitem.hasData(ItemStats.COMPATIBLE_IDS)) {
final ArrayComponent<StringComponent> acceptedIds = mmoitem.getComponent(ItemStats.COMPATIBLE_IDS);
if (acceptedIds != null && !acceptedIds.asList().isEmpty()) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that ID is compatible: ");
final List<String> acceptedIDs = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_IDS)).getList();
final String targetId = target.getString("MMOITEMS_ITEM_ID");
if (acceptedIDs.size() > 0 && acceptedIDs.stream()
.noneMatch(s -> s.equalsIgnoreCase(targetId))) {
if (acceptedIds.asList().stream().noneMatch(s -> s.getValue().equalsIgnoreCase(targetId))) {
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
.send(player);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem())).send(player);
return new ApplyResult(ResultType.NONE);
}
}
// Material compatibility check
if (mmoitem.hasData(ItemStats.COMPATIBLE_MATERIALS)) {
// TODO unnecessary parsing. can check for material name (Strings) instead.
final ArrayComponent<MaterialComponent> acceptedMaterials = mmoitem.getComponent(ItemStats.COMPATIBLE_MATERIALS);
if (acceptedIds != null && !acceptedMaterials.asList().isEmpty()) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that MATERIAL is compatible: ");
List<String> acceptedMaterials = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_MATERIALS)).getList();
if (acceptedMaterials.size() > 0 && acceptedMaterials.stream()
.noneMatch(s -> s.equalsIgnoreCase(target.getItem().getType().name()))) {
if (acceptedMaterials.asList().stream().noneMatch(s -> s.getMaterial().name().equalsIgnoreCase(target.getItem().getType().name()))) {
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
.send(player);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem())).send(player);
return new ApplyResult(ResultType.NONE);
}
}

View File

@ -11,9 +11,10 @@ import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.GenerateLoreEvent;
import net.Indyuce.mmoitems.api.event.ItemBuildEvent;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.stat.component.builtin.MaterialComponent;
import net.Indyuce.mmoitems.stat.data.MaterialData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@ -64,7 +65,8 @@ public class ItemStackBuilder {
this.mmoitem = mmoitem;
// Generates a new ItemStack of the specified material (Specified in the Material stat, or a DIAMOND_SWORD if missing).
item = new ItemStack(mmoitem.hasData(ItemStats.MATERIAL) ? ((MaterialData) mmoitem.getData(ItemStats.MATERIAL)).getMaterial() : Material.DIAMOND_SWORD);
MaterialComponent materialComponent = mmoitem.getComponent(ItemStats.MATERIAL);
item = new ItemStack(materialComponent != null ? materialComponent.getMaterial() : Material.DIAMOND_SWORD);
// Gets a lore builder, which will be used to apply the chosen lore format (Choose with the lore format stat, or the default one if unspecified)
lore = new LoreBuilder(mmoitem);
@ -146,7 +148,7 @@ public class ItemStackBuilder {
* Enchantment data must never be clear and lack history. This is
* the basis for when an item is 'old'
*/
builtMMOItem.computeData(ItemStats.ENCHANTS);
builtMMOItem.computeComponent(ItemStats.ENCHANTS);
builtMMOItem.computeStatHistory(ItemStats.ENCHANTS);
//GEM// else {MMOItems.log("\u00a73 -?- \u00a77Apparently found enchantment data \u00a7b" + (mmoitem.getData(ItemStats.ENCHANTS) == null ? "null" : ((EnchantListData) mmoitem.getData(ItemStats.ENCHANTS)).getEnchants().size())); }
@ -155,7 +157,7 @@ public class ItemStackBuilder {
* through non-MMOItems supported sources, the name can be changed in
* an anvil, so the very original name must be saved.
*/
builtMMOItem.computeData(ItemStats.NAME);
builtMMOItem.computeComponent(ItemStats.NAME);
builtMMOItem.computeStatHistory(ItemStats.NAME);
// For every stat within this item
@ -176,7 +178,7 @@ public class ItemStackBuilder {
// Recalculate
//GEM//MMOItems.log(" \u00a73-\u00a7a- \u00a77ItemStack Building Recalculation \u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-");
builtMMOItem.setData(stat, s.recalculate(l));
builtMMOItem.setComponent(stat, s.recalculate(l));
// Add to NBT, if the gemstones were not purged
if (!s.isEmpty()) {

View File

@ -8,16 +8,13 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate.TemplateOption;
import net.Indyuce.mmoitems.api.item.template.ModifierNode;
import net.Indyuce.mmoitems.api.item.template.NameModifier;
import net.Indyuce.mmoitems.api.item.template.NameModifier.ModifierType;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.model.builtin.StringModel;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.NameData;
import net.Indyuce.mmoitems.stat.data.StringData;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.util.Buildable;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -68,10 +65,15 @@ public class MMOItemBuilder extends Buildable<MMOItem> {
// Apply base item data
template.getModels().forEach((stat, model) -> applyComponent((ItemStat) stat, stat.getComponentType().randomize(model, this)));
if (tier != null) mmoitem.setData(ItemStats.TIER, new StringData(tier.getId()));
if (level > 0) mmoitem.setData(ItemStats.ITEM_LEVEL, new DoubleData(level));
if (tier != null && tier.getTooltip() != null && !mmoitem.hasData(ItemStats.TOOLTIP))
mmoitem.setData(ItemStats.TOOLTIP, new StringData(tier.getTooltip().getId()));
// Apply tier
if (tier != null) mmoitem.setComponent(ItemStats.TIER, new StringComponent(tier.getId()));
// Apply level
if (level > 0) mmoitem.setComponent(ItemStats.ITEM_LEVEL, new IntegerComponent(level));
// Apply tier item tooltip if item has no tooltip.
if (tier != null && tier.getTooltip() != null && !mmoitem.hasComponent(ItemStats.TOOLTIP))
mmoitem.setComponent(ItemStats.TOOLTIP, StringComponent.tooltip(tier.getTooltip()));
// Apply modifiers from the parent node
if (!forDisplay && template.hasModifierGroup()) template.getModifierGroup().collect(this);
@ -112,6 +114,8 @@ public class MMOItemBuilder extends Buildable<MMOItem> {
*/
@Override
protected MMOItem whenBuilt() {
/*
TODO name
if (!nameModifiers.isEmpty()) {
// Get name data
@ -133,6 +137,7 @@ public class MMOItemBuilder extends Buildable<MMOItem> {
// Recalculate name
mmoitem.setData(ItemStats.NAME, hist.recalculate(mmoitem.getUpgradeLevel()));
}
*/
return mmoitem;
}
@ -156,11 +161,11 @@ public class MMOItemBuilder extends Buildable<MMOItem> {
* @param stat Stat owning the data
* @param data StatData to apply
*/
public void addModifierData(@NotNull ItemStat stat, @NotNull StatData data, @NotNull UUID uuid) {
// TODO stop using ClearStatData
if (stat.getClearStatData() instanceof Mergeable)
mmoitem.computeStatHistory(stat).registerModifierBonus(uuid, data);
else mmoitem.setData(stat, data);
public <C extends StatComponent> void addModifierData(@NotNull ItemStat<C> stat, @NotNull C data, @NotNull UUID uuid) {
// TODO Merging
//if (stat.getClearStatData() instanceof Mergeable)
mmoitem.computeStatHistory(stat).registerModifierBonus(uuid, data);
//else mmoitem.setData(stat, data);
}
/**

View File

@ -5,7 +5,7 @@ import java.util.logging.Level;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.ChatColor;
import org.bukkit.inventory.ItemStack;

View File

@ -1,7 +1,6 @@
package net.Indyuce.mmoitems.api.item.mmoitem;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.ui.SilentNumbers;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.ItemTier;
@ -12,12 +11,14 @@ import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.util.MMOItemReforger;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.UpgradeComponent;
import net.Indyuce.mmoitems.stat.data.*;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.tooltip.TooltipTexture;
import net.Indyuce.mmoitems.util.Pair;
import org.apache.commons.lang.Validate;
@ -63,6 +64,14 @@ public class MMOItem implements ItemReference {
return id;
}
/**
* @return Collection of all item stats which have some data on this mmoitem
*/
@NotNull
public Set<ItemStat<?>> getStats() {
return components.keySet();
}
@Nullable
public <C extends StatComponent> C getComponent(@NotNull ItemStat<C> stat) {
StatComponent found = components.get(stat);
@ -78,12 +87,14 @@ public class MMOItem implements ItemReference {
return (C) components.put(stat, component);
}
/**
* @return Collection of all item stats which have some data on this mmoitem
*/
@NotNull
public Set<ItemStat<?>> getStats() {
return components.keySet();
@Nullable
public <C extends StatComponent> C computeComponent(@NotNull ItemStat<C> stat) {
return (C) components.computeIfAbsent(stat, ItemStat::generateEmptyComponent);
}
public <C extends StatComponent> void mergeComponentInto(@NotNull ItemStat<C> stat, @NotNull C component, @Nullable UUID associatedGemStone) {
}
//region Deprecated
@ -100,6 +111,8 @@ public class MMOItem implements ItemReference {
@Deprecated
public void mergeData(@NotNull ItemStat stat, @NotNull StatData data, @Nullable UUID associatedGemStone) {
/*
TODO
// Merge if possible, otherwise write over
if (data instanceof Mergeable) {
@ -109,6 +122,7 @@ public class MMOItem implements ItemReference {
else sHistory.registerExternalData(data);
setData(stat, sHistory.recalculate(getUpgradeLevel()));
} else setData(stat, data);
*/
}
@Deprecated
@ -132,11 +146,6 @@ public class MMOItem implements ItemReference {
return null;
}
@Deprecated
public StatData computeData(@NotNull ItemStat<?> stat) {
throw new RuntimeException("to be removed");
}
@Deprecated
public boolean hasData(@NotNull ItemStat stat) {
return false;
@ -182,19 +191,19 @@ public class MMOItem implements ItemReference {
* removal of gem stones in the future. This is where that is remembered.
*/
@NotNull
private final Map<ItemStat<?>, StatHistory> mergeableStatHistory = new HashMap<>();
private final Map<ItemStat<?>, StatHistory<?>> mergeableStatHistory = new HashMap<>();
public boolean hasStatHistory(@NotNull ItemStat<?> stat) {
return stat instanceof Mergeable && mergeableStatHistory.containsKey(stat);
}
@Nullable
public StatHistory getStatHistory(@NotNull ItemStat<?> stat) {
public <C extends StatComponent> StatHistory<C> getStatHistory(@NotNull ItemStat<C> stat) {
// TODO refactor
if (stat.equals(ItemStats.ENCHANTS)) return computeStatHistory(stat);
return mergeableStatHistory.get(stat);
return (StatHistory<C>) mergeableStatHistory.get(stat);
}
/**
@ -204,11 +213,11 @@ public class MMOItem implements ItemReference {
* which gem, and its bonuses due to upgrades.
*/
@NotNull
public StatHistory computeStatHistory(@NotNull ItemStat<?> stat) {
return mergeableStatHistory.computeIfAbsent(stat, itemStat -> {
final StatData currentData = computeData(itemStat);
Validate.isTrue(currentData instanceof Mergeable, "Stat " + itemStat.getId() + " is not mergeable");
return new StatHistory(this, itemStat, currentData);
public <C extends StatComponent> StatHistory<C> computeStatHistory(@NotNull ItemStat<C> stat) {
return (StatHistory<C>) mergeableStatHistory.computeIfAbsent(stat, ignore -> {
final C currentData = computeComponent(stat);
//Validate.isTrue(currentData instanceof Mergeable, "Stat " + itemStat.getId() + " is not mergeable");
return new StatHistory<>(this, stat, currentData);
});
}
@ -258,7 +267,7 @@ public class MMOItem implements ItemReference {
public int getDamage() {
// Does it use MMO Durability?
int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
int maxDurability = hasComponent(ItemStats.MAX_DURABILITY) ? getComponent(ItemStats.MAX_DURABILITY).getValue() : -1;
if (maxDurability > 0) {
@ -266,7 +275,7 @@ public class MMOItem implements ItemReference {
NBTItem nbtItem = newBuilder().buildNBT();
// Durability
int durability = hasData(ItemStats.CUSTOM_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.CUSTOM_DURABILITY)).getValue()) : maxDurability;
int durability = hasComponent(ItemStats.CUSTOM_DURABILITY) ? getComponent(ItemStats.CUSTOM_DURABILITY).getValue() : maxDurability;
// Damage is the difference between max and current durability
return maxDurability - durability;
@ -274,7 +283,7 @@ public class MMOItem implements ItemReference {
} else {
// Use vanilla durability
return hasData(ItemStats.ITEM_DAMAGE) ? SilentNumbers.round(((DoubleData) getData(ItemStats.ITEM_DAMAGE)).getValue()) : 0;
return hasComponent(ItemStats.ITEM_DAMAGE) ? getComponent(ItemStats.ITEM_DAMAGE).getValue() : 0;
}
}
@ -288,10 +297,10 @@ public class MMOItem implements ItemReference {
public void setDamage(int damage) {
// Too powerful
if (hasData(ItemStats.UNBREAKABLE)) return;
if (hasComponent(ItemStats.UNBREAKABLE)) return;
// Does it use MMO Durability?
int maxDurability = hasData(ItemStats.MAX_DURABILITY) ? SilentNumbers.round(((DoubleData) getData(ItemStats.MAX_DURABILITY)).getValue()) : -1;
int maxDurability = hasComponent(ItemStats.MAX_DURABILITY) ? getComponent(ItemStats.MAX_DURABILITY).getValue() : -1;
if (maxDurability > 0) {
@ -302,7 +311,7 @@ public class MMOItem implements ItemReference {
setData(ItemStats.CUSTOM_DURABILITY, new DoubleData(maxDurability - damage));
// Scale damage
Material mat = hasData(ItemStats.MATERIAL) ? ((MaterialData) getData(ItemStats.MATERIAL)).getMaterial() : Material.GOLD_INGOT;
Material mat = hasComponent(ItemStats.MATERIAL) ? Objects.requireNonNull(getComponent(ItemStats.MATERIAL).getMaterial(), "Internal error") : Material.GOLD_INGOT;
double multiplier = ((double) damage) * ((double) mat.getMaxDurability()) / ((double) maxDurability);
if (multiplier == 0) return;
@ -375,16 +384,16 @@ public class MMOItem implements ItemReference {
}
@NotNull
public List<GemstoneData> getGemstones() {
final StatData data = getData(ItemStats.GEM_SOCKETS);
return data == null ? new ArrayList<>() : ((GemSocketsData) data).getGems();
public List<GemstoneComponent> getGemstones() {
final GemstonesComponent data = getComponent(ItemStats.GEM_SOCKETS);
return data == null ? new ArrayList<>() : data.getGemstones();
}
/**
* @see #getGemstones()
*/
@Deprecated
public Set<GemstoneData> getGemStones() {
public Set<GemstoneComponent> getGemStones() {
return new HashSet<>(getGemstones());
}
//endregion
@ -402,16 +411,16 @@ public class MMOItem implements ItemReference {
* @return The list of GemStones contained here.
*/
@NotNull
public List<Pair<GemstoneData, MMOItem>> extractGemstones() {
public List<Pair<GemstoneComponent, MMOItem>> extractGemstones() {
// Found?
final @Nullable GemSocketsData thisSocketsData = (GemSocketsData) getData(ItemStats.GEM_SOCKETS);
final @Nullable GemstonesComponent thisSocketsData = getComponent(ItemStats.GEM_SOCKETS);
if (thisSocketsData == null) return new ArrayList<>();
// Find restored items
final List<Pair<GemstoneData, MMOItem>> pairs = new ArrayList<>();
for (GemstoneData gem : thisSocketsData.getGemstones()) {
final MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getMMOItemType()), gem.getMMOItemID());
final List<Pair<GemstoneComponent, MMOItem>> pairs = new ArrayList<>();
for (GemstoneComponent gem : thisSocketsData.getGemstones()) {
final MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getItemType()), gem.getItemId());
if (restored != null) pairs.add(Pair.of(gem, restored));
}
@ -420,9 +429,9 @@ public class MMOItem implements ItemReference {
// Identify actual stats
for (StatHistory hist : mergeableStatHistory.values())
for (Pair<GemstoneData, MMOItem> gem : pairs) {
final StatData historicGemData = hist.getGemstoneData(gem.getKey().getHistoricUUID());
if (historicGemData != null) gem.getValue().setData(hist.getItemStat(), historicGemData);
for (Pair<GemstoneComponent, MMOItem> gem : pairs) {
final StatComponent historicGemData = hist.getGemstoneData(gem.getKey().getUniqueId());
if (historicGemData != null) gem.getValue().setComponent(hist.getItemStat(), historicGemData);
}
return pairs;
@ -430,7 +439,7 @@ public class MMOItem implements ItemReference {
/**
* Extracts a single gemstone. Note that this only builds the original Gemstone MMOItem, and if you
* wish to actually remove the GemStone, you must do so through {@link #removeGemStone(UUID, String)}
* wish to actually remove the GemStone, you must do so through {@link #removeGemstone(UUID, String)}
*
* @param gem Gemstone that you believe is in here
* @return The gemstone as it was when inserted, or <code>null</code>
@ -438,9 +447,9 @@ public class MMOItem implements ItemReference {
* @see #extractGemstones() More optimized method for extracting all gemstones at the same time.
*/
@Nullable
public MMOItem extractGemstone(@NotNull GemstoneData gem) {
public MMOItem extractGemstone(@NotNull GemstoneComponent gem) {
final MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getMMOItemType()), gem.getMMOItemID());
final MMOItem restored = MMOItems.plugin.getMMOItem(MMOItems.plugin.getTypes().get(gem.getItemType()), gem.getItemId());
if (restored == null) return null;
// If RevID updating, no need to identify stats
@ -448,8 +457,8 @@ public class MMOItem implements ItemReference {
// Identify actual stats
for (StatHistory hist : mergeableStatHistory.values()) {
final StatData historicGemData = hist.getGemstoneData(gem.getHistoricUUID());
if (historicGemData != null) restored.setData(hist.getItemStat(), historicGemData);
final StatComponent historicGemData = hist.getGemstoneData(gem.getUniqueId());
if (historicGemData != null) restored.setComponent(hist.getItemStat(), historicGemData);
}
return restored;
@ -461,14 +470,13 @@ public class MMOItem implements ItemReference {
* @param gemUUID UUID of gem to remove
* @param color Color of the gem socket to restore. {@code null} to not restore socket.
*/
@SuppressWarnings("ConstantConditions")
public void removeGemStone(@NotNull UUID gemUUID, @Nullable String color) {
public void removeGemstone(@NotNull UUID gemUUID, @Nullable String color) {
// Get gemstone data
if (!hasData(ItemStats.GEM_SOCKETS)) return;
//GEM//MMOItems.log("\u00a7b-\u00a78-\u00a79-\u00a77 Extracting \u00a7e" + gemUUID.toString());
StatHistory gemStory = computeStatHistory(ItemStats.GEM_SOCKETS);
StatHistory<GemstonesComponent> gemStory = computeStatHistory(ItemStats.GEM_SOCKETS);
/*
* We must only find the StatData where this gem resides,
@ -476,19 +484,19 @@ public class MMOItem implements ItemReference {
* will purge themselves from extraneous gems (that are
* no longer registered onto the GEM_SOCKETS history).
*/
if (((GemSocketsData) gemStory.getOriginalData()).removeGem(gemUUID, color)) return;
if (gemStory.getOriginalData().removeGem(gemUUID, color)) return;
// Attempt gems
for (UUID gemDataUUID : gemStory.getAllGemstones())
if (((GemSocketsData) gemStory.getGemstoneData(gemDataUUID)).removeGem(gemUUID, color)) return;
if (gemStory.getGemstoneData(gemDataUUID).removeGem(gemUUID, color)) return;
// Attempt externals
for (StatData externalData : gemStory.getExternalData())
if (((GemSocketsData) externalData).removeGem(gemUUID, color)) return;
for (GemstonesComponent externalData : gemStory.getExternalData())
if (externalData.removeGem(gemUUID, color)) return;
// Attempt gems
for (UUID gemDataUUID : gemStory.getAllModifiers())
if (((GemSocketsData) gemStory.getModifiersBonus(gemDataUUID)).removeGem(gemUUID, color)) return;
if (gemStory.getModifiersBonus(gemDataUUID).removeGem(gemUUID, color)) return;
}
//endregion
}

View File

@ -6,7 +6,6 @@ import io.lumine.mythic.lib.util.PreloadedObject;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
@ -34,9 +33,6 @@ public class ModifierNode implements PreloadedObject {
@Nullable
private final List<ModifierNode> children;
@Deprecated
private final Map<ItemStat, RandomStatData> data;
private static final Random RANDOM = new Random();
/**
@ -63,7 +59,7 @@ public class ModifierNode implements PreloadedObject {
}
// Post-load stat data
Validate.notNull(ModifierNode.this.data, "Internal error");
Validate.notNull(ModifierNode.this.models, "Internal error");
final ConfigurationSection statSection = config.getConfigurationSection("stats");
if (statSection != null) for (String key : statSection.getKeys(false))
try {
@ -127,7 +123,6 @@ public class ModifierNode implements PreloadedObject {
max = config != null && config.contains("max") ? config.getInt("max") : referenceNode.max;
// Modifier
data = referenceNode.data;
models = referenceNode.models;
}
@ -143,7 +138,6 @@ public class ModifierNode implements PreloadedObject {
postLoadAction.cacheConfig(config);
// Modifier
this.data = new HashMap<>();
this.models = new HashMap<>();
}
}
@ -161,12 +155,6 @@ public class ModifierNode implements PreloadedObject {
return chance;
}
@NotNull
@Deprecated
public Map<ItemStat, RandomStatData> getItemData() {
return data;
}
@NotNull
public Map<ItemStat<?>, Model<?>> getModels() {
return models;
@ -219,7 +207,7 @@ public class ModifierNode implements PreloadedObject {
// VANILLA MODIFIER SECTION
data.forEach((itemStat, statData) -> builder.addModifierData(itemStat, statData.randomize(builder), modifierId));
models.forEach((stat, model) -> builder.addModifierData((ItemStat) stat, stat.getComponentType().randomize(model, builder), modifierId));
// MODIFIER GROUP SECTION

View File

@ -21,10 +21,11 @@ import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.inventory.EquippedItem;
import net.Indyuce.mmoitems.api.player.inventory.InventoryUpdateHandler;
import net.Indyuce.mmoitems.particle.api.ParticleRunnable;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.AbilityComponent;
import net.Indyuce.mmoitems.stat.data.ParticleData;
import net.Indyuce.mmoitems.stat.data.PotionEffectListData;
import net.Indyuce.mmoitems.stat.data.StringListData;
import net.Indyuce.mmoitems.util.PlayerAbility;
import net.milkbowl.vault.permission.Permission;
import org.bukkit.Bukkit;
@ -179,9 +180,9 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
continue;
// Abilities
if (item.hasData(ItemStats.ABILITIES))
for (AbilityComponent abilityComponent : item.getComponent(ItemStats.ABILITIES))
getMMOPlayerData().getPassiveSkillMap().addModifier(new PassiveSkill("MMOItemsItem", abilityComponent.toPlayerAbility(), equipmentSlot, source));
ArrayComponent<AbilityComponent> abilities = item.getComponent(ItemStats.ABILITIES);
if (abilities != null) for (AbilityComponent abilityComponent : abilities)
getMMOPlayerData().getPassiveSkillMap().addModifier(new PassiveSkill("MMOItemsItem", abilityComponent.toPlayerAbility(), equipmentSlot, source));
// Apply permanent potion effects
if (item.hasData(ItemStats.PERM_EFFECTS))
@ -202,9 +203,14 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
}
// Apply permissions if Vault exists
if (MMOItems.plugin.hasPermissions() && item.hasData(ItemStats.GRANTED_PERMISSIONS)) {
ArrayComponent<StringComponent> grantedPerms;
if (MMOItems.plugin.hasPermissions() && (grantedPerms = item.getComponent(ItemStats.GRANTED_PERMISSIONS)) != null) {
final Permission perms = MMOItems.plugin.getVault().getPermissions();
permissions.addAll(((StringListData) item.getData(ItemStats.GRANTED_PERMISSIONS)).getList());
// Add permission
grantedPerms.forEach(comp -> permissions.add(comp.getValue()));
// Upgrade current permissions
permissions.forEach(perm -> {
if (!perms.has(getPlayer(), perm))
perms.playerAdd(getPlayer(), perm);

View File

@ -14,8 +14,8 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -119,7 +119,7 @@ public class MMOItemReforger {
/**
* @return The meta of {@link #getStack()} but without that
* pesky {@link Nullable} annotation.
* pesky {@link Nullable} annotation.
*/
@NotNull
@Deprecated
@ -167,8 +167,8 @@ public class MMOItemReforger {
/**
* @return The MMOItem being updated. For safety, it should be cloned,
* in case any plugin decides to make changes in it... though
* this should be entirely for <b>reading purposes only</b>.
* in case any plugin decides to make changes in it... though
* this should be entirely for <b>reading purposes only</b>.
*/
@SuppressWarnings({"NullableProblems", "ConstantConditions"})
@NotNull
@ -206,7 +206,7 @@ public class MMOItemReforger {
/**
* @return The Updated version of the MMOItem, with
* its revised stats.
* its revised stats.
*/
@SuppressWarnings({"NullableProblems", "ConstantConditions"})
@NotNull
@ -225,7 +225,7 @@ public class MMOItemReforger {
/**
* @return If this is a loaded template. That's all required.
* @deprecated Ambigous method, not finding a corresponding item
* template isn't the only fail factor.
* template isn't the only fail factor.
*/
@Deprecated
public boolean canReforge() {
@ -314,7 +314,7 @@ public class MMOItemReforger {
/**
* @return The item level modifying the values of RandomStatData
* upon creating a new MMOItem from the template.
* upon creating a new MMOItem from the template.
*/
public int getGenerationItemLevel() {
return generationItemLevel;
@ -385,17 +385,16 @@ public class MMOItemReforger {
// Properly recalculate all based on histories
for (StatHistory hist : getFreshMMOItem().getStatHistories())
// Recalculate that shit
getFreshMMOItem().setData(hist.getItemStat(), hist.recalculate(getFreshMMOItem().getUpgradeLevel()));
getFreshMMOItem().setComponent(hist.getItemStat(), hist.recalculate(getFreshMMOItem().getUpgradeLevel()));
if (getFreshMMOItem().hasUpgradeTemplate())
for (ItemStat stat : getFreshMMOItem().getUpgradeTemplate().getKeys()) {
// That stat yes
StatHistory hist = getFreshMMOItem().computeStatHistory(stat);
// Recalculate that shit
getFreshMMOItem().setData(hist.getItemStat(), hist.recalculate(getFreshMMOItem().getUpgradeLevel()));
getFreshMMOItem().setComponent(hist.getItemStat(), hist.recalculate(getFreshMMOItem().getUpgradeLevel()));
}
// Build ItemStack

View File

@ -14,7 +14,6 @@ import net.Indyuce.mmoitems.gui.Navigator;
import net.Indyuce.mmoitems.gui.PluginInventory;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.apache.commons.lang.Validate;
import org.bukkit.Bukkit;

View File

@ -178,7 +178,7 @@ public class ConfigManager implements Reloadable {
soulboundBaseDamage = MMOItems.plugin.getConfig().getDouble("soulbound.damage.base");
soulboundPerLvlDamage = MMOItems.plugin.getConfig().getDouble("soulbound.damage.per-lvl");
upgradeRequirementsCheck = MMOItems.plugin.getConfig().getBoolean("item-upgrade-requirements-check");
GemUpgradeScaling.defaultValue = MMOItems.plugin.getConfig().getString("gem-upgrade-default", GemUpgradeScaling.SUBSEQUENT.getId());
GemUpgradeScaling.DEFAULT_VALUE = MMOItems.plugin.getConfig().getString("gem-upgrade-default", GemUpgradeScaling.SUBSEQUENT.getId());
keepSoulboundOnDeath = MMOItems.plugin.getConfig().getBoolean("soulbound.keep-on-death");
rerollOnItemUpdate = MMOItems.plugin.getConfig().getBoolean("item-revision.reroll-when-updated");
levelSpread = MMOItems.plugin.getConfig().getDouble("item-level-spread");

View File

@ -5,7 +5,7 @@ import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.type.IntegerStat;
import net.Indyuce.mmoitems.stat.type.TemplateOption;
import net.Indyuce.mmoitems.stat.type.extra.TemplateOption;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

View File

@ -11,8 +11,8 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.type.BooleanStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import net.Indyuce.mmoitems.util.Pair;
@ -55,8 +55,8 @@ public class CanUnsocket extends BooleanStat implements ConsumableItemInteractio
if (!mmo.hasData(ItemStats.GEM_SOCKETS)) {
return false;
}
GemSocketsData mmoGems = (GemSocketsData) mmo.getData(ItemStats.GEM_SOCKETS);
if (mmoGems == null || mmoGems.getGemstones().size() == 0) {
GemstonesComponent mmoGems = mmo.getComponent(ItemStats.GEM_SOCKETS);
if (mmoGems == null || mmoGems.getGemstones().isEmpty()) {
return false;
}
Player player = playerData.getPlayer();
@ -67,7 +67,7 @@ public class CanUnsocket extends BooleanStat implements ConsumableItemInteractio
* Cancel if no gem could be extracted.
*/
mmo = new LiveMMOItem(target);
final List<Pair<GemstoneData, MMOItem>> mmoGemStones = mmo.extractGemstones();
final List<Pair<GemstoneComponent, MMOItem>> mmoGemStones = mmo.extractGemstones();
if (mmoGemStones.isEmpty()) {
Message.RANDOM_UNSOCKET_GEM_TOO_OLD.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(event.getCurrentItem())).send(player);
return false;

View File

@ -16,7 +16,7 @@ import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.component.builtin.VoidComponent;
import net.Indyuce.mmoitems.stat.component.type.builtin.VoidComponentType;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.TemplateOption;
import net.Indyuce.mmoitems.stat.type.extra.TemplateOption;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;

View File

@ -3,7 +3,7 @@ package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.type.StringStat;
import net.Indyuce.mmoitems.stat.type.TemplateOption;
import net.Indyuce.mmoitems.stat.type.extra.TemplateOption;
import org.bukkit.Material;
@HasCategory(cat = "template_option")

View File

@ -1,15 +1,11 @@
package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.type.builtin.ArrayComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.StringComponentType;
import net.Indyuce.mmoitems.stat.type.StringListStat;
import org.jetbrains.annotations.NotNull;
@BackwardsCompatibility(version = "7.0")
@HasCategory(cat = "tooltip")

View File

@ -12,19 +12,16 @@ import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.comp.enchants.EnchantPlugin;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.EnchantComponent;
import net.Indyuce.mmoitems.stat.component.type.ComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.ArrayComponentType;
import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.EnchantMapComponent;
import net.Indyuce.mmoitems.stat.component.type.builtin.MapComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.ObjectComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.StringComponentType;
import net.Indyuce.mmoitems.stat.data.EnchantListData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.type.Upgradable;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.NamespacedKey;
@ -35,16 +32,14 @@ import org.bukkit.inventory.meta.ItemMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.*;
@HasCategory(cat = "item")
public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> implements Upgradable {
public class Enchants extends ItemStat<EnchantMapComponent> implements Upgradable {
public Enchants() {
super("ENCHANTS", Material.ENCHANTED_BOOK, "Enchantments", new String[]{"The item enchants."}, new String[0]);
super("ENCHANTS", null);
/*
ComponentType<?, ?> enchantComponentType = ObjectComponentType.init()
.stringSeparatedStringFormat(" ")
.implementation(EnchantComponent::new)
@ -57,8 +52,10 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
})
.inputable(true)
.build();
*/
setComponentType(ArrayComponentType.arrayOf(enchantComponentType)
setComponentType(MapComponentType.mapOf(NumberComponentType.integer().build())
.implementation(EnchantMapComponent::new)
.icon(Material.ENCHANTED_BOOK)
.name("Enchantments")
.trimdesc("The item enchants.")
@ -71,10 +68,10 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
@Nullable
@Override
public ArrayComponent<EnchantComponent> read(ReadMMOItem mmoitem) {
public EnchantMapComponent read(ReadMMOItem mmoitem) {
// Create enchant data from this items' enchantments
ArrayComponent<EnchantComponent> enchants = new ArrayComponent<>();
EnchantMapComponent enchants = new EnchantMapComponent();
// Get the Item Meta
ItemStack item = mmoitem.getNBT().getItem();
@ -85,24 +82,24 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
if (itemMeta != null) {
// For each enchantment, in the usual way
for (Enchantment enchant : itemMeta.getEnchants().keySet()) {
enchants.asList().add(new EnchantComponent(enchant, itemMeta.getEnchantLevel(enchant)));
for (Map.Entry<Enchantment, Integer> entry : itemMeta.getEnchants().entrySet()) {
enchants.asMap().put(entry.getKey().toString(), new IntegerComponent(entry.getValue()));
}
// For each enchantment 'stored' in the item
if (itemMeta instanceof EnchantmentStorageMeta) {
// For each enchantment
for (Enchantment enchant : ((EnchantmentStorageMeta) itemMeta).getStoredEnchants().keySet()) {
for (Map.Entry<Enchantment, Integer> entry : ((EnchantmentStorageMeta) itemMeta).getStoredEnchants().entrySet()) {
// Add Level
enchants.asList().add(new EnchantComponent(enchant, ((EnchantmentStorageMeta) itemMeta).getStoredEnchantLevel(enchant)));
enchants.asMap().put(entry.getKey().toString(), new IntegerComponent(entry.getValue()));
}
}
}
}
return enchants.asList().isEmpty() ? null : enchants;
return enchants.asMap().isEmpty() ? null : enchants;
/*
TODO this code is fucking garbage
@ -139,37 +136,26 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
* @return Enchantments of this extracted as a list of enchants data.
*/
@NotNull
public static EnchantListData fromVanilla(@Nullable ItemStack source) {
// List
EnchantListData eld = new EnchantListData();
// Null is clear
if (source == null) {
return eld;
}
public static EnchantMapComponent fromVanilla(@Nullable ItemStack source) {
EnchantMapComponent eld = new EnchantMapComponent();
if (source == null) return eld;
// For each enchants
for (Enchantment e : source.getEnchantments().keySet()) {
// Get level
int l = source.getEnchantmentLevel(e);
// Add if significant
if (l != 0) {
eld.addEnchant(e, l);
}
for (Map.Entry<Enchantment, Integer> entry : source.getEnchantments().entrySet()) {
int l = entry.getValue();
if (l != 0) eld.setLevel(entry.getKey(), l);
}
return eld;
}
@Override
public void write(ItemStackBuilder builder, @NotNull ArrayComponent<EnchantComponent> component) {
public void write(ItemStackBuilder builder, @NotNull EnchantMapComponent component) {
for (EnchantComponent enchantComponent : component.asList()) {
int lvl = enchantComponent.getLevel();
Enchantment enchant = enchantComponent.getEnchant();
for (Map.Entry<String, IntegerComponent> entry : component.asMap().entrySet()) {
int lvl = entry.getValue().getValue();
Enchantment enchant = Enchants.getEnchant(entry.getKey());
Validate.notNull(enchant, String.format("Could not find enchant with ID '%s'", entry.getKey()));
// If it's an enchanted item, has to be registered as a stored enchant instead
if (builder.getItemStack().getType() == Material.ENCHANTED_BOOK) {
@ -288,18 +274,18 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
public static void separateEnchantments(@NotNull MMOItem mmoitem) {
// Cancellation because the player could not have done so HMMM
if (mmoitem.hasData(ItemStats.DISABLE_REPAIRING) && mmoitem.hasData(ItemStats.DISABLE_ENCHANTING)) {
if (mmoitem.hasComponent(ItemStats.DISABLE_REPAIRING) && mmoitem.hasComponent(ItemStats.DISABLE_ENCHANTING))
return;
}
boolean additiveMerge = MMOItems.plugin.getConfig().getBoolean("stat-merging.additive-enchantments", false);
//SENCH//MMOItems.log(" \u00a79>\u00a73>\u00a77 Separating Enchantments");
// Does it have enchantment data?
if (mmoitem.hasData(ItemStats.ENCHANTS)) {
if (mmoitem.hasComponent(ItemStats.ENCHANTS)) {
// Get that data
EnchantListData data = (EnchantListData) mmoitem.getData(ItemStats.ENCHANTS);
StatHistory hist = mmoitem.computeStatHistory(ItemStats.ENCHANTS);
EnchantMapComponent data = mmoitem.getComponent(ItemStats.ENCHANTS);
StatHistory<EnchantMapComponent> hist = mmoitem.computeStatHistory(ItemStats.ENCHANTS);
//SENCH//MMOItems.log(" \u00a7b:\u00a73:\u00a79: \u00a77Early Analysis: \u00a73o-o-o-o-o-o-o-o-o-o-o-o-o-o-o-o");
//SENCH//MMOItems.log(" \u00a73=\u00a7b> \u00a77Active:");
@ -315,7 +301,7 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
// All right, whats the expected enchantment levels?
//HSY//MMOItems.log(" \u00a73-\u00a7a- \u00a77Enchantment Separation Recalculation \u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-");
EnchantListData expected = (EnchantListData) hist.recalculate(mmoitem.getUpgradeLevel());
EnchantMapComponent expected = hist.recalculate(mmoitem.getUpgradeLevel());
// Gather a list of extraneous enchantments
HashMap<Enchantment, Integer> discrepancies = new HashMap<>();
@ -349,13 +335,13 @@ public class Enchants extends ItemStat<ArrayComponent<EnchantComponent>> impleme
}
// It has been extracted
if (discrepancies.size() > 0) {
if (!discrepancies.isEmpty()) {
// Generate enchantment list with offsets
EnchantListData extraneous = new EnchantListData();
EnchantMapComponent extraneous = new EnchantMapComponent();
for (Enchantment e : discrepancies.keySet()) {
//SENCH//MMOItems.log("\u00a77 Discrepancy of \u00a7f" + discrepancies.get(e) + " \u00a77 -- in \u00a7b" + e.getName() );
extraneous.addEnchant(e, discrepancies.get(e));
extraneous.setLevel(e, discrepancies.get(e));
}
// Register extraneous

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
@ -107,4 +108,10 @@ public class GemSockets extends ItemStat<GemstonesComponent> {
builder.getLore().insert("gem-stones", lore);
}
@NotNull
public static String getUncoloredGemSlot() {
String s = MMOItems.plugin.getConfig().getString("gem-sockets.uncolored");
return s == null ? "Uncolored" : s;
}
}

View File

@ -3,11 +3,9 @@ package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.component.type.builtin.StringComponentType;
import net.Indyuce.mmoitems.stat.data.StringData;
import net.Indyuce.mmoitems.stat.type.StringStat;
import net.Indyuce.mmoitems.util.HintedString;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
/**
* Defines how gem stats will scale when the item they are put on upgrades.
@ -22,7 +20,7 @@ public class GemUpgradeScaling extends StringStat implements GemStoneStat {
/**
* Can't be final as it is a plugin configuration option
*/
public static String defaultValue = SUBSEQUENT.getId();
public static String DEFAULT_VALUE = SUBSEQUENT.getId();
public GemUpgradeScaling() {
super("GEM_UPGRADE_SCALING", new String[]{"gem_stone"});
@ -33,10 +31,4 @@ public class GemUpgradeScaling extends StringStat implements GemStoneStat {
.trimdesc("Gem stones add their stats to items, but you may also upgrade your items via crafting stations or consumables.\n\u00a76Should this gem stone stats be affected by upgrading?")
.build());
}
@NotNull
@Override
public StringData getClearStatData() {
return new StringData(defaultValue);
}
}

View File

@ -9,7 +9,7 @@ import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.ItemRestriction;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import org.bukkit.ChatColor;
import org.bukkit.Material;
@ -24,30 +24,26 @@ import org.jetbrains.annotations.NotNull;
*/
@HasCategory(cat = "use_cost")
public class ManaCost extends DoubleStat implements ItemRestriction, PlayerConsumable {
public ManaCost() {
super("MANA_COST", Material.LAPIS_LAZULI, "Mana Cost", new String[]{"Mana spent by your weapon to be used."}, new String[]{"weapon"});
super("MANA_COST", Material.LAPIS_LAZULI, "Mana Cost", "Mana spent by your weapon to be used.", new String[]{"weapon"});
}
@Override
public boolean canUse(RPGPlayer player, NBTItem item, boolean message) {
// No data no service
if (!item.hasTag(ItemStats.MANA_COST.getNBTPath()))
return true;
double manaCost = item.getDouble(ItemStats.MANA_COST.getNBTPath());
boolean hasMana = manaCost > 0 && player.getMana() >= manaCost;
if (!hasMana)
Message.NOT_ENOUGH_MANA.format(ChatColor.RED).send(player.getPlayer());
return hasMana;
if (manaCost <= 0) return true;
boolean result = manaCost > 0 && player.getMana() >= manaCost;
if (!result) Message.NOT_ENOUGH_MANA.format(ChatColor.RED).send(player.getPlayer());
return result;
}
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
// No data no service
if (!mmo.hasData(ItemStats.MANA_COST)) return;
DoubleComponent d = mmo.getComponent(this);
if (d == null) return;
// Get value
DoubleData d = (DoubleData) mmo.getData(ItemStats.MANA_COST);
if (d.getValue() > 0) {
final RPGPlayer rpgPlayer = PlayerData.get(player).getRPG();
rpgPlayer.setMana(rpgPlayer.getMana() - d.getValue());

View File

@ -14,7 +14,7 @@ import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.MaterialData;
import net.Indyuce.mmoitems.stat.type.IntegerStat;
import net.Indyuce.mmoitems.stat.type.Upgradable;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;

View File

@ -1,34 +1,14 @@
package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.util.AltChar;
import io.lumine.mythic.lib.gson.JsonArray;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.gui.edition.EditionInventory;
import net.Indyuce.mmoitems.input.LegacyItemInputHandler;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.builtin.VoidComponent;
import net.Indyuce.mmoitems.stat.data.StringListData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StringListStat;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.event.inventory.InventoryAction;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
@HasCategory(cat = "misc")
public class NBTTags extends ItemStat<VoidComponent> {
public NBTTags() {

View File

@ -14,9 +14,9 @@ import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import net.Indyuce.mmoitems.util.Pair;
@ -65,9 +65,8 @@ public class RandomUnsocket extends DoubleStat implements ConsumableItemInteract
* No Gemstones? No service
*/
MMOItem mmoVol = new VolatileMMOItem(target);
if (!mmoVol.hasData(ItemStats.GEM_SOCKETS)) { return false; }
GemSocketsData mmoGems = (GemSocketsData) mmoVol.getData(ItemStats.GEM_SOCKETS);
if (mmoGems == null || mmoGems.getGemstones().size() == 0) { return false; }
GemstonesComponent mmoGems = mmoVol.getComponent(ItemStats.GEM_SOCKETS);
if (mmoGems == null || mmoGems.getGemstones().isEmpty()) return false;
Player player = playerData.getPlayer();
/*
@ -76,13 +75,13 @@ public class RandomUnsocket extends DoubleStat implements ConsumableItemInteract
* Cancel if no gem could be extracted.
*/
MMOItem mmo = new LiveMMOItem(target);
List<Pair<GemstoneData, MMOItem>> mmoGemStones = mmo.extractGemstones();
List<Pair<GemstoneComponent, MMOItem>> mmoGemStones = mmo.extractGemstones();
if (mmoGemStones.isEmpty()) {
Message.RANDOM_UNSOCKET_GEM_TOO_OLD.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(event.getCurrentItem())).send(player);
return false; }
// Get removed gems amount
DoubleData unsocket = (DoubleData) consumable.getMMOItem().getData(ItemStats.RANDOM_UNSOCKET);
DoubleComponent unsocket = consumable.getMMOItem().getComponent(ItemStats.RANDOM_UNSOCKET);
int s = 1; if (unsocket != null) { s = SilentNumbers.floor(unsocket.getValue()); }
//GEM//for (String str : SilentNumbers.transcribeList(mmoGemStones, (lam) -> "\u00a73Found \u00a77 " + ((MMOItem) lam).getType().getId() + " " + ((MMOItem) lam).getId() )) { MMOItems.log(str); };
@ -102,9 +101,9 @@ public class RandomUnsocket extends DoubleStat implements ConsumableItemInteract
if (randomGem >= mmoGemStones.size()) { randomGem = mmoGemStones.size() - 1;}
// Choose gem
final Pair<GemstoneData, MMOItem> pair = mmoGemStones.get(randomGem);
final Pair<GemstoneComponent, MMOItem> pair = mmoGemStones.get(randomGem);
final MMOItem gem = pair.getValue();
final GemstoneData gemData = pair.getKey();
final GemstoneComponent gemData = pair.getKey();
mmoGemStones.remove(randomGem);
//GEM//MMOItems.log("\u00a73 *\u00a77 Chose to remove\u00a7b " + gem.getType() + " " + gem.getId());
@ -120,15 +119,10 @@ public class RandomUnsocket extends DoubleStat implements ConsumableItemInteract
// Drop
items2Drop.add(builtGem);
String chosenColor;
if (gemData.getSocketColor() != null) {
//GEM//MMOItems.log("\u00a7b *\u00a77 Restored slot\u00a7e " + gem.getAsGemColor());
chosenColor = gemData.getSocketColor(); } else {
//GEM//MMOItems.log("\u00a7b *\u00a77 Restored slot\u00a76 " + GemSocketsData.getUncoloredGemSlot() + " \u00a78(Uncolored Def)");
chosenColor = GemSocketsData.getUncoloredGemSlot(); }
String chosenColor = gemData.getSocketColor() != null ? gemData.getSocketColor() : GemSockets.getUncoloredGemSlot();
// Unregister
mmo.removeGemStone(gemData.getHistoricUUID(), chosenColor);
mmo.removeGemstone(gemData.getUniqueId(), chosenColor);
// Gem Removal Count Decreased
s--;
@ -142,7 +136,7 @@ public class RandomUnsocket extends DoubleStat implements ConsumableItemInteract
// Replace
//HSY//MMOItems.log(" \u00a73-\u00a7a- \u00a77Gem Unsocketing Recalculation \u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-\u00a73-\u00a7a-");
mmo.setData(ItemStats.GEM_SOCKETS, mmo.computeStatHistory(ItemStats.GEM_SOCKETS).recalculate(mmo.getUpgradeLevel()));
mmo.setComponent(ItemStats.GEM_SOCKETS, mmo.computeStatHistory(ItemStats.GEM_SOCKETS).recalculate(mmo.getUpgradeLevel()));
//GEM//MMOItems.log("\u00a7b*\u00a77 Final at \u00a7b" + ((GemSocketsData) mmo.getData(ItemStats.GEM_SOCKETS)).getEmptySlots().size() + " Empty\u00a77 and \u00a7e" + ((GemSocketsData) mmo.getData(ItemStats.GEM_SOCKETS)).getGemstones().size() + " Gems");
event.setCurrentItem(mmo.newBuilder().build());

View File

@ -1,7 +1,6 @@
package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;

View File

@ -4,12 +4,10 @@ import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.api.player.RPGPlayer;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.data.RequiredLevelData;
import net.Indyuce.mmoitems.stat.type.RequirementStat;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.jetbrains.annotations.NotNull;
@HasCategory(cat = "requirement")
public class RequiredLevel extends RequirementStat {
@ -95,10 +93,4 @@ public class RequiredLevel extends RequirementStat {
// Upgraded
return original;
} ///*/
@Override
public @NotNull
RequiredLevelData getClearStatData() {
return new RequiredLevelData(0D);
}
}

View File

@ -7,7 +7,7 @@ import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.stat.yaml.SyntaxAdapter;
import net.Indyuce.mmoitems.util.MMOUtils;
@ -37,13 +37,9 @@ public class RestoreFood extends DoubleStat implements PlayerConsumable {
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
DoubleComponent d = mmo.getComponent(this);
if (d == null) return;
// No data no service
if (!mmo.hasData(ItemStats.RESTORE_FOOD))
return;
// Get value
DoubleData d = (DoubleData) mmo.getData(ItemStats.RESTORE_FOOD);
int actualValue = SilentNumbers.ceil(d.getValue() - (vanillaEating ? getFoodRestored(mmo.getNBT().getItem()) : 0));
// Any food being provided?

View File

@ -4,7 +4,7 @@ import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Material;
@ -29,9 +29,9 @@ public class RestoreHealth extends DoubleStat implements PlayerConsumable {
// (Fixes MMOItems#1579) Cannot restore health if player is dying
if (player.isDead() || player.getHealth() <= 0) return;
if (!mmo.hasData(ItemStats.RESTORE_HEALTH)) return;
final DoubleComponent d = mmo.getComponent(ItemStats.RESTORE_HEALTH);
if (d == null) return;
final DoubleData d = (DoubleData) mmo.getData(ItemStats.RESTORE_HEALTH);
if (d.getValue() != 0) MMOUtils.heal(player, d.getValue());
}
}

View File

@ -5,7 +5,7 @@ import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -24,9 +24,9 @@ public class RestoreMana extends DoubleStat implements PlayerConsumable {
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
if (!mmo.hasData(ItemStats.RESTORE_MANA)) return;
final DoubleComponent d = mmo.getComponent(ItemStats.RESTORE_MANA);
if (d == null) return;
final DoubleData d = (DoubleData) mmo.getData(ItemStats.RESTORE_MANA);
if (d.getValue() != 0) PlayerData.get(player).getRPG().giveMana(d.getValue());
}
}

View File

@ -1,11 +1,10 @@
package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.MythicLib;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Material;
@ -21,14 +20,15 @@ import org.jetbrains.annotations.NotNull;
@HasCategory(cat = "consumables")
public class RestoreSaturation extends DoubleStat implements PlayerConsumable {
public RestoreSaturation() {
super("RESTORE_SATURATION", Material.GOLDEN_CARROT, "Saturation Restoration", new String[]{"Saturation given when consumed."}, new String[]{"consumable"});
super("RESTORE_SATURATION", Material.GOLDEN_CARROT, "Saturation Restoration", "Saturation given when consumed.", new String[]{"consumable"});
}
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
DoubleComponent component = mmo.getComponent(this);
final double vanillaSaturation = getSaturationRestored(mmo.getNBT().getItem());
double saturation = mmo.hasData(ItemStats.RESTORE_SATURATION) ? ((DoubleData) mmo.getData(ItemStats.RESTORE_SATURATION)).getValue() : vanillaSaturation;
double saturation = component != null ? component.getValue() : vanillaSaturation;
if (vanillaEating) saturation -= vanillaSaturation;
// Any saturation being provided?

View File

@ -5,7 +5,7 @@ import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -19,20 +19,17 @@ import org.jetbrains.annotations.NotNull;
@HasCategory(cat = "consumables")
public class RestoreStamina extends DoubleStat implements PlayerConsumable {
public RestoreStamina() {
super("RESTORE_STAMINA", Material.LIGHT_GRAY_DYE, "Restore Stamina", new String[]{"The amount of stamina/power", "your consumable restores."}, new String[]{"consumable"});
super("RESTORE_STAMINA", Material.LIGHT_GRAY_DYE, "Restore Stamina", "The amount of stamina/power your consumable restores.", new String[]{"consumable"});
}
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
// No data no service
if (!mmo.hasData(ItemStats.RESTORE_STAMINA)) return;
// Get value
DoubleData d = (DoubleData) mmo.getData(ItemStats.RESTORE_STAMINA);
DoubleComponent d = mmo.getComponent(ItemStats.RESTORE_STAMINA);
if (d == null) return;
// Any stamina being provided?
if (d.getValue() != 0)
PlayerData.get(player).getRPG().giveStamina(d.getValue());
if (d.getValue() != 0) PlayerData.get(player).getRPG().giveStamina(d.getValue());
}
}

View File

@ -1,7 +1,6 @@
package net.Indyuce.mmoitems.stat.block;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
import net.Indyuce.mmoitems.stat.type.IntegerStat;
import org.bukkit.Material;

View File

@ -8,7 +8,7 @@ import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
//TODO define isEmpty()
//TODO define isEmpty()?
public abstract class StatComponent {
@Nullable
@ -16,6 +16,10 @@ public abstract class StatComponent {
throw new TerminalComponentException(this);
}
public abstract boolean isEmpty();
public abstract StatComponent clone();
public String getAsString() {
// Same return value as #toString() but casting will throw an error
// if it's not a string, which is expected behaviour.
@ -45,4 +49,9 @@ public abstract class StatComponent {
return current.get(split[n]);
}
@Nullable
public static <C extends StatComponent> C clone(@Nullable C component) {
return component == null ? null : (C) component.clone();
}
}

View File

@ -11,7 +11,15 @@ import java.util.Spliterator;
import java.util.function.Consumer;
public class ArrayComponent<C extends StatComponent> extends StatComponent implements Iterable<C> {
private final List<C> components = new ArrayList<>();
private final List<C> components;
public ArrayComponent() {
this(new ArrayList<>());
}
public ArrayComponent(List<C> components) {
this.components = components;
}
@Nullable
public C getComponent(int index) {
@ -35,6 +43,21 @@ public class ArrayComponent<C extends StatComponent> extends StatComponent imple
action.accept(component);
}
@Override
public boolean isEmpty() {
return components.isEmpty();
}
@Override
public StatComponent clone() {
ArrayComponent<C> clone = new ArrayComponent<>();
for (StatComponent component : components)
clone.components.add((C) component.clone());
return clone;
}
@Override
public Spliterator<C> spliterator() {
return components.spliterator();

View File

@ -20,6 +20,16 @@ public class BooleanComponent extends StatComponent implements Mergeable<Boolean
this.value = value;
}
@Override
public boolean isEmpty() {
return !value;
}
@Override
public StatComponent clone() {
return new BooleanComponent(value);
}
@Override
public void merge(BooleanComponentType componentType, BooleanComponent component) {
switch (componentType.mergeMecanism) {

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.stat.component.builtin;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType;
public class DoubleComponent extends NumberComponent {
@ -20,6 +21,16 @@ public class DoubleComponent extends NumberComponent {
return (int) value;
}
@Override
public boolean isEmpty() {
return value == 0;
}
@Override
public StatComponent clone() {
return new DoubleComponent(value);
}
@Override
public void doubleValue(double value) {
this.value = value;

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.stat.component.builtin;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType;
public class IntegerComponent extends NumberComponent {
@ -24,6 +25,16 @@ public class IntegerComponent extends NumberComponent {
return value;
}
@Override
public boolean isEmpty() {
return value == 0;
}
@Override
public StatComponent clone() {
return new IntegerComponent(value);
}
@Override
public void intValue(int value) {
this.value = value;

View File

@ -1,6 +1,8 @@
package net.Indyuce.mmoitems.stat.component.builtin;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
@ -8,7 +10,31 @@ import java.util.Map;
public class MapComponent<V extends StatComponent> extends StatComponent {
private final Map<String, V> map = new HashMap<>();
public MapComponent() {
// Empty
}
public Map<String, V> asMap() {
return map;
}
@Nullable
@Override
public V get(@NotNull String key) {
return map.get(key);
}
@Override
public boolean isEmpty() {
return map.isEmpty();
}
@Override
public StatComponent clone() {
MapComponent<V> clone = new MapComponent<>();
map.forEach((key, val) -> clone.map.put(key, (V) val.clone()));
return clone;
}
}

View File

@ -18,6 +18,10 @@ import org.jetbrains.annotations.Nullable;
public class MaterialComponent extends StatComponent implements Model<MaterialComponent> {
private Material mat;
public MaterialComponent() {
}
public MaterialComponent(@Nullable Material mat) {
this.mat = mat;
}
@ -26,6 +30,16 @@ public class MaterialComponent extends StatComponent implements Model<MaterialCo
return mat;
}
@Override
public boolean isEmpty() {
return mat == null;
}
@Override
public StatComponent clone() {
return new MaterialComponent(mat);
}
/*
@Override
public void merge(MaterialComponent component) {

View File

@ -33,4 +33,10 @@ public abstract class ObjectComponent extends StatComponent {
@NotNull
public abstract Collection<String> getComponentKeys();
@Override
public boolean isEmpty() {
// By principle, objects are never empty
return false;
}
}

View File

@ -33,4 +33,13 @@ public class ObjectComponentImpl extends ObjectComponent {
public Set<String> getComponentKeys() {
return components.keySet();
}
@Override
public StatComponent clone() {
ObjectComponentImpl clone = new ObjectComponentImpl();
components.forEach((key, component) -> clone.components.put(key, component.clone()));
return clone;
}
}

View File

@ -2,7 +2,9 @@ package net.Indyuce.mmoitems.stat.component.builtin;
import net.Indyuce.mmoitems.stat.component.StatComponent;
// TODO abstraction for simple components?
/**
* Simple components are components with no component types.
*/
public class SimpleComponent<T> extends StatComponent {
private T value;
@ -17,4 +19,15 @@ public class SimpleComponent<T> extends StatComponent {
public void setValue(T value) {
this.value = value;
}
@Override
public boolean isEmpty() {
return value == null;
}
@Override
public StatComponent clone() {
// Does not support cloning. Non deterministic behaviour
return this;
}
}

View File

@ -2,11 +2,17 @@ package net.Indyuce.mmoitems.stat.component.builtin;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.tooltip.TooltipTexture;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.Nullable;
public class StringComponent extends StatComponent {
private String value;
public StringComponent() {
// Empty
}
public StringComponent(@Nullable String value) {
this.value = value;
}
@ -23,8 +29,28 @@ public class StringComponent extends StatComponent {
}
*/
@Override
public StatComponent clone() {
return new StringComponent(value == null ? null : value);
}
@Override
public String toString() {
return String.valueOf(value);
}
@Override
public boolean isEmpty() {
return value == null || value.isEmpty();
}
public static StringComponent tooltip(TooltipTexture tooltipTexture) {
Validate.notNull(tooltipTexture, "Tooltip texture cannot be null");
return new StringComponent(tooltipTexture.getId());
}
@Nullable
public static String getValue(@Nullable StringComponent component) {
return component == null ? null : component.getValue();
}
}

View File

@ -4,5 +4,14 @@ import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.model.Model;
public class VoidComponent extends StatComponent implements Model<VoidComponent> {
// On se fait chier par ici
@Override
public boolean isEmpty() {
throw new RuntimeException("Not supported");
}
@Override
public StatComponent clone() {
throw new RuntimeException("Not supported");
}
}

View File

@ -23,7 +23,7 @@ public class AbilityComponent extends ObjectComponent {
private MapComponent<DoubleComponent> modifiers;
public AbilityComponent() {
// super(value);
// Nothing
}
private static final String SKILL = "Id";
@ -106,5 +106,16 @@ public class AbilityComponent extends ObjectComponent {
return List.of(SKILL, CASTING_MODE, MODIFIERS);
}
@Override
public StatComponent clone() {
AbilityComponent clone = new AbilityComponent();
clone.skill = StatComponent.clone(skill);
clone.castingMode = StatComponent.clone(castingMode);
clone.modifiers = StatComponent.clone(modifiers);
return clone;
}
//endregion
}

View File

@ -29,6 +29,16 @@ public class ColorComponent extends ObjectComponent {
blue = new DoubleComponent(color.getBlue());
}
//region API
public Color toColor() {
return Color.fromRGB((int) red.getValue(), (int) green.getValue(), (int) blue.getValue());
}
//endregion
//region
@Override
public void set(@NotNull String key, @NotNull StatComponent component) {
switch (key) {
@ -74,7 +84,17 @@ public class ColorComponent extends ObjectComponent {
return List.of(RED, GREEN, BLUE);
}
public Color toColor() {
return Color.fromRGB((int) red.getValue(), (int) green.getValue(), (int) blue.getValue());
@Override
public StatComponent clone() {
ColorComponent clone = new ColorComponent();
clone.red = StatComponent.clone(red);
clone.green = StatComponent.clone(green);
clone.blue = StatComponent.clone(blue);
return clone;
}
//endregion
}

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.stat.component.builtin.composite;
import com.sun.tools.javac.util.List;
import net.Indyuce.mmoitems.stat.annotation.InvalidComponentKeyException;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.BooleanComponent;
@ -97,7 +98,19 @@ public class CommandComponent extends ObjectComponent {
@NotNull
@Override
public Collection<String> getComponentKeys() {
return null;
return List.of(COMMAND, DELAY, CONSOLE, OP);
}
@Override
public StatComponent clone() {
CommandComponent clone = new CommandComponent();
clone.command = StatComponent.clone(command);
clone.delay = StatComponent.clone(delay);
clone.console = StatComponent.clone(console);
clone.op = StatComponent.clone(op);
return clone;
}
//endregion

View File

@ -15,6 +15,7 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.function.BiConsumer;
@Deprecated
public class EnchantComponent extends ObjectComponent {
private StringComponent enchant;
private IntegerComponent level;
@ -93,5 +94,16 @@ public class EnchantComponent extends ObjectComponent {
return Arrays.asList("enchant", "level");
}
@Override
public StatComponent clone() {
EnchantComponent clone = new EnchantComponent();
clone.enchant = StatComponent.clone(enchant);
clone.level = StatComponent.clone(level);
return clone;
}
//endregion
}

View File

@ -0,0 +1,23 @@
package net.Indyuce.mmoitems.stat.component.builtin.composite;
import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent;
import net.Indyuce.mmoitems.stat.component.builtin.MapComponent;
import org.bukkit.enchantments.Enchantment;
import org.jetbrains.annotations.NotNull;
public class EnchantMapComponent extends MapComponent<IntegerComponent> {
//region API
public int getLevel(@NotNull Enchantment enchantment) {
IntegerComponent found = super.asMap().get(enchantment.getKey().toString());
return found == null ? 0 : found.getValue();
}
public void setLevel(@NotNull Enchantment enchantment, int level) {
if (level == 0) super.asMap().remove(enchantment.getKey().toString());
else super.asMap().put(enchantment.getKey().toString(), new IntegerComponent(level));
}
//endregion
}

View File

@ -1,4 +0,0 @@
package net.Indyuce.mmoitems.stat.component.builtin.composite;
public class GemSocketsComponent {
}

View File

@ -1,10 +1,12 @@
package net.Indyuce.mmoitems.stat.component.builtin.composite;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.stat.annotation.InvalidComponentKeyException;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.IntegerComponent;
import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -23,7 +25,19 @@ public class GemstoneComponent extends ObjectComponent {
private IntegerComponent level;
public GemstoneComponent() {
// Nothing
}
public GemstoneComponent(@NotNull LiveMMOItem gemStoneMMOItem, @Nullable String color) {
this(gemStoneMMOItem, color, UUID.randomUUID());
}
public GemstoneComponent(@NotNull LiveMMOItem gemStoneMMOItem, @Nullable String color, @NotNull UUID forcedHistoryUUID) {
setName(MMOUtils.getDisplayName(gemStoneMMOItem.getNBT().getItem()));
setUniqueId(forcedHistoryUUID); // Generate own historic UUID
setItemId(gemStoneMMOItem.getId());
setItemType(gemStoneMMOItem.getType().getId());
setSocketColor(color);
}
private static final String NAME = "Name";
@ -48,12 +62,54 @@ public class GemstoneComponent extends ObjectComponent {
this.name = new StringComponent(Objects.requireNonNull(name, "Name cannot be null"));
}
public void setUUID(@NotNull UUID uuid) {
public void setUniqueId(@NotNull UUID uuid) {
this.uuid = new StringComponent(Objects.requireNonNull(uuid, "UUID cannot be null").toString());
}
public int getLevel() {
return level == null ? 0 : level.getValue();
/**
* This is at which level (of the item) the gemstone was placed onto the item.
* <p>A null level means this gem does not scale.</p>
* <p></p>
* For scaling purposes of stat {@link net.Indyuce.mmoitems.stat.GemUpgradeScaling}
*/
@Nullable
public Integer getLevel() {
return level == null ? null : level.getValue();
}
public void setLevel(@Nullable Integer level) {
this.level = level == null ? null : new IntegerComponent(level);
}
@Nullable
public String getSocketColor() {
return socketColor == null ? null : socketColor.getValue();
}
public void setSocketColor(@Nullable String socketColor) {
this.socketColor = socketColor == null ? null : new StringComponent(socketColor);
}
public boolean isScaling() {
return level != null;
}
@Nullable
public String getItemId() {
return StringComponent.getValue(mmoitemId);
}
public void setItemId(@Nullable String mmoitemId) {
this.mmoitemId = mmoitemId == null ? null : new StringComponent(mmoitemId);
}
@Nullable
public String getItemType() {
return StringComponent.getValue(mmoitemType);
}
public void setItemType(String mmoitemType) {
this.mmoitemType = mmoitemType == null ? null : new StringComponent(mmoitemType);
}
//endregion
@ -123,6 +179,20 @@ public class GemstoneComponent extends ObjectComponent {
return List.of(NAME, HISTORIC_UUID, MMOITEM_TYPE, MMOITEM_ID, SOCKET_COLOR, LEVEL);
}
@Override
public StatComponent clone() {
GemstoneComponent clone = new GemstoneComponent();
clone.name = StatComponent.clone(name);
clone.uuid = StatComponent.clone(uuid);
clone.mmoitemType = StatComponent.clone(mmoitemType);
clone.mmoitemId = StatComponent.clone(mmoitemId);
clone.socketColor = StatComponent.clone(socketColor);
clone.level = StatComponent.clone(level);
return clone;
}
//endregion
}

View File

@ -1,5 +1,6 @@
package net.Indyuce.mmoitems.stat.component.builtin.composite;
import net.Indyuce.mmoitems.stat.GemSockets;
import net.Indyuce.mmoitems.stat.annotation.InvalidComponentKeyException;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
@ -10,6 +11,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.function.BiConsumer;
public class GemstonesComponent extends ObjectComponent {
@ -19,24 +21,84 @@ public class GemstonesComponent extends ObjectComponent {
private static final String SOCKETS = "EmptySlots";
private static final String GEMSTONES = "Gemstones";
public void setGemstones(@Nullable ArrayComponent<GemstoneComponent> gemstones) {
this.gemstones = gemstones;
//region API
public void setGemstones(@Nullable List<GemstoneComponent> gemstones) {
this.gemstones = new ArrayComponent<>(gemstones);
}
public void setSockets(@Nullable ArrayComponent<StringComponent> sockets) {
this.sockets = sockets;
public void setSockets(@Nullable List<StringComponent> sockets) {
this.sockets = new ArrayComponent<>(sockets);
}
@NotNull
public List<GemstoneComponent> getGemstones() {
if (gemstones == null) gemstones = new ArrayComponent<>();
return gemstones.asList();
}
@NotNull
public List<StringComponent> getSockets() {
if (sockets == null) sockets = new ArrayComponent<>();
return sockets.asList();
}
public void addGemstone(@NotNull GemstoneComponent component) {
getGemstones().add(component);
}
public boolean applyGemstone(String gem, GemstoneComponent gemstone) {
final String matchingSocket = findEmptySocket(gem, true);
if (matchingSocket == null) return false;
getGemstones().add(gemstone);
return true;
}
/**
* Get the first empty gem socket that matches this color.
*
* @return <code>null</code> if none matched.
*/
@Nullable
public ArrayComponent<GemstoneComponent> getGemstones() {
return gemstones;
public String findEmptySocket(@NotNull String gem, boolean remove) {
for (StringComponent slot : getSockets())
if (gem.isEmpty() || slot.getValue().equals(GemSockets.getUncoloredGemSlot()) || slot.getValue().equals(gem)) {
if (remove) getSockets().remove(slot);
return slot.getValue();
}
return null;
}
@Nullable
public ArrayComponent<StringComponent> getSockets() {
return sockets;
/**
* Removes such gem from this GemSocketsData, if it exists and
* registers again an empty gem socket if required
*
* @param gemId The unique ID of the gem to remove
* @param socket The socket color to replace the gem with, <code>null</code> for no socket.
* @return Whether a gem was removed from the data.
*/
public boolean removeGem(@NotNull UUID gemId, @Nullable String socket) {
List<GemstoneComponent> gemstones = getGemstones();
for (GemstoneComponent data : gemstones)
if (data.getUniqueId().equals(gemId)) {
// Add socket again
if (socket != null) getSockets().add(new StringComponent(socket));
// Remove gemstone
gemstones.remove(data);
return true;
}
return false;
}
//endregion
//region
@Override
public void set(@NotNull String key, @NotNull StatComponent component) {
switch (key) {
@ -75,4 +137,16 @@ public class GemstonesComponent extends ObjectComponent {
public Collection<String> getComponentKeys() {
return List.of(SOCKETS, GEMSTONES);
}
@Override
public StatComponent clone() {
GemstonesComponent clone = new GemstonesComponent();
clone.gemstones = StatComponent.clone(gemstones);
clone.sockets = StatComponent.clone(sockets);
return clone;
}
//endregion
}

View File

@ -54,5 +54,10 @@ public class NameComponent extends ObjectComponent {
return List.of();
}
@Override
public StatComponent clone() {
return null;
}
//endregion
}

View File

@ -119,5 +119,16 @@ public class PotionEffectComponent extends ObjectComponent {
return List.of(TYPE, DURATION, LEVEL);
}
@Override
public StatComponent clone() {
PotionEffectComponent clone = new PotionEffectComponent();
clone.type = StatComponent.clone(type);
clone.duration = StatComponent.clone(duration);
clone.level = StatComponent.clone(level);
return clone;
}
//endregion
}

View File

@ -106,5 +106,15 @@ public class ShieldPatternComponent extends ObjectComponent {
return List.of(DYE_COLOR, PATTERN_TYPE);
}
@Override
public StatComponent clone() {
ShieldPatternComponent clone = new ShieldPatternComponent();
clone.dyeColor = StatComponent.clone(dyeColor);
clone.patternType = StatComponent.clone(patternType);
return clone;
}
//endregion
}

View File

@ -18,7 +18,7 @@ import java.util.function.BiConsumer;
public class ShieldStyleComponent extends ObjectComponent {
private StringComponent baseColor;
private ArrayComponent<ShieldPatternComponent> patterns;
private ArrayComponent<ShieldPatternComponent> layers;
public ShieldStyleComponent() {
// Empty constructor
@ -47,19 +47,19 @@ public class ShieldStyleComponent extends ObjectComponent {
return baseColor == null ? null : DyeColor.valueOf(baseColor.getValue());
}
public void setPatterns(@Nullable ArrayComponent<ShieldPatternComponent> patterns) {
this.patterns = patterns;
public void setLayers(@Nullable ArrayComponent<ShieldPatternComponent> layers) {
this.layers = layers;
}
@Nullable
public ArrayComponent<ShieldPatternComponent> getPatterns() {
return patterns;
public ArrayComponent<ShieldPatternComponent> getLayers() {
return layers;
}
@NotNull
public List<Pattern> patternsToBukkit() {
List<Pattern> list = new ArrayList<>();
if (patterns != null) for (ShieldPatternComponent layer : patterns.asList())
if (layers != null) for (ShieldPatternComponent layer : layers.asList())
try {
list.add(layer.toBukkit());
} catch (NullPointerException exception) {
@ -69,9 +69,9 @@ public class ShieldStyleComponent extends ObjectComponent {
}
public void patternsFromBukkit(List<Pattern> patterns) {
this.patterns = new ArrayComponent<>();
this.layers = new ArrayComponent<>();
for (Pattern pattern : patterns)
this.patterns.asList().add(new ShieldPatternComponent(pattern));
this.layers.asList().add(new ShieldPatternComponent(pattern));
}
//endregion
@ -85,7 +85,7 @@ public class ShieldStyleComponent extends ObjectComponent {
baseColor = (StringComponent) component;
return;
case LAYERS:
patterns = (ArrayComponent<ShieldPatternComponent>) component;
layers = (ArrayComponent<ShieldPatternComponent>) component;
return;
default:
throw new InvalidComponentKeyException(this, key);
@ -99,7 +99,7 @@ public class ShieldStyleComponent extends ObjectComponent {
case BASE_COLOR:
return baseColor;
case LAYERS:
return patterns;
return layers;
default:
throw new InvalidComponentKeyException(this, key);
}
@ -108,7 +108,7 @@ public class ShieldStyleComponent extends ObjectComponent {
@Override
public void forEachComponent(@NotNull BiConsumer<String, StatComponent> action) {
if (baseColor != null) action.accept(BASE_COLOR, baseColor);
if (patterns != null) action.accept(LAYERS, patterns);
if (layers != null) action.accept(LAYERS, layers);
}
@NotNull
@ -117,5 +117,15 @@ public class ShieldStyleComponent extends ObjectComponent {
return List.of(BASE_COLOR, LAYERS);
}
@Override
public StatComponent clone() {
ShieldStyleComponent clone = new ShieldStyleComponent();
clone.baseColor = StatComponent.clone(baseColor);
clone.layers = StatComponent.clone(layers);
return clone;
}
//endregion
}

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmoitems.stat.component.builtin.api;
package net.Indyuce.mmoitems.stat.component.builtin.composite;
import net.Indyuce.mmoitems.stat.annotation.InvalidComponentKeyException;
import net.Indyuce.mmoitems.stat.component.StatComponent;
@ -50,5 +50,14 @@ public class TemplateClass extends ObjectComponent {
return List.of();
}
@Override
public StatComponent clone() {
AbilityComponent clone = new AbilityComponent();
return clone;
}
//endregion
}

View File

@ -26,7 +26,7 @@ public class MapModel<V extends StatComponent> implements Model<MapComponent<V>>
}
public MapComponent<V> randomize(MapComponentType<V> componentType, MMOItemBuilder builder) {
MapComponent<V> comp = new MapComponent<>();
MapComponent<V> comp = componentType.generateEmptyComponent();
for (Map.Entry<String, Model<?>> entry : models.entrySet()) {
comp.asMap().put(entry.getKey(), (V) ((ComponentType) componentType.getSubtype()).randomize(entry.getValue(), builder));

View File

@ -26,7 +26,7 @@ public class ObjectModel implements Model<ObjectComponent> {
}
public ObjectComponent randomize(ObjectComponentType componentType, MMOItemBuilder builder) {
ObjectComponentImpl comp = new ObjectComponentImpl();
ObjectComponent comp = componentType.generateEmptyComponent();
for (Map.Entry<String, Model<?>> entry : models.entrySet()) {
ComponentType subtype = componentType.getChildType(entry.getKey());

View File

@ -113,7 +113,7 @@ public class ArrayComponentType<C extends StatComponent>
@Override
public Object inputToConfig(@NotNull String playerInput) {
// TODO make it possible to input this
throw new RuntimeException("Cannot input non terminal component type");
throw new RuntimeException("Cannot directly input arrays");
}
/*

View File

@ -1,6 +1,8 @@
package net.Indyuce.mmoitems.stat.component.type.builtin;
import dev.aurelium.slate.util.Validate;
import io.lumine.mythic.lib.gson.JsonElement;
import io.lumine.mythic.lib.gson.JsonObject;
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
import net.Indyuce.mmoitems.stat.component.LoreWrapper;
import net.Indyuce.mmoitems.stat.component.StatComponent;
@ -8,16 +10,18 @@ import net.Indyuce.mmoitems.stat.component.builtin.MapComponent;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.component.model.builtin.MapModel;
import net.Indyuce.mmoitems.stat.component.type.ComponentType;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Supplier;
/**
* A dynamic map with key validation if necessary. Objects are structures with
* a set number of fields, maps can contain any field. This comes handy for
* modifier maps (abilities) or even enchant maps.
*/
public class MapComponentType<C extends StatComponent>
extends ComponentType<MapModel<C>, MapComponent<C>> {
public class MapComponentType<C extends StatComponent> extends ComponentType<MapModel<C>, MapComponent<C>> {
/**
* The component type that you can find inside the map.
@ -26,46 +30,77 @@ public class MapComponentType<C extends StatComponent>
*/
private ComponentType<?, C> subtype;
private Supplier<MapComponent> componentInstanciator = MapComponent::new;
public ComponentType<?, C> getSubtype() {
return subtype;
}
@Override
public void displayInEditor(LoreWrapper lore, MapModel<C> model) {
//TODO
lore.append("MAP{..}");
}
@Override
public MapModel<C> fromConfig(@NotNull Object object) {
return null;
// From config section
if (object instanceof ConfigurationSection) {
MapModel<C> model = new MapModel<>();
ConfigurationSection config = (ConfigurationSection) object;
for (String key : config.getKeys(false))
model.getModels().put(key, subtype.fromConfig(config.get(key)));
return model;
}
// Invalid format
else throw new IllegalArgumentException("Must be a configuration section");
}
@Nullable
@Override
public Object inputToConfig(@NotNull String playerInput) {
return null;
throw new RuntimeException("Cannot directly input maps");
}
@NotNull
@Override
public MapComponent<C> fromJson(@NotNull JsonElement json) {
return null;
MapComponent<C> map = generateEmptyComponent();
// Parse json object as map
JsonObject obj = json.getAsJsonObject();
for (String key : obj.keySet())
map.asMap().put(key, getSubtype().fromJson(obj.get(key)));
return map;
}
@Nullable
@Override
public JsonElement toJson(@NotNull MapComponent<C> component) {
return null;
JsonObject object = new JsonObject();
component.asMap().forEach((key, val) -> object.add(key, subtype.toJson(val)));
return object;
}
@Override
public MapComponent<C> generateEmptyComponent() {
return null;
return new MapComponent<>();
}
@Override
public MapComponent<C> randomize(MapModel<C> model, MMOItemBuilder builder) {
return null;
MapComponent<C> comp = generateEmptyComponent();
model.getModels().forEach((key, submodel) -> comp.asMap().put(key, (C) ((ComponentType) subtype).randomize(submodel, builder)));
return comp;
}
//region Build
@ -84,8 +119,15 @@ public class MapComponentType<C extends StatComponent>
return this;
}
public Builder implementation(Supplier<MapComponent> componentInstanciator) {
MapComponentType.this.componentInstanciator = componentInstanciator;
return this;
}
@NotNull
public MapComponentType<C> build() {
Validate.notNull(subtype, "Subtype cannot be null");
return (MapComponentType<C>) super.build();
}
}

View File

@ -166,10 +166,22 @@ public class NumberComponentType extends ComponentType<NumberModel, NumberCompon
public static enum MergeMecanism {
/**
* Used for numeric (level, profession, exp...) requirements.
* Sum could work too but this one makes the most sense
*
* TODO fix config option 'stat-merging.additive-levels'
*/
HIGHEST,
/**
* Not used atm
*/
LOWEST,
/**
* Used for all numeric stats
*/
SUM,
}
@ -192,6 +204,13 @@ public class NumberComponentType extends ComponentType<NumberModel, NumberCompon
inputable(true);
}
public Builder mergeMethod(@NotNull MergeMecanism method) {
Validate.notNull(method, "Merge method cannot be null");
NumberComponentType.this.mergeMecanism = method;
return this;
}
public Builder attribute(@Nullable Attribute attribute) {
NumberComponentType.this.attribute = attribute;
return this;

View File

@ -22,7 +22,7 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
private final Map<String, ComponentType<?, ?>> fields = new LinkedHashMap<>();
private Supplier<ObjectComponent> componentInstanciator = ObjectComponentImpl::new;
private Supplier<ObjectModel> modelInstanciator = ObjectModel::new;
//private Supplier<ObjectModel> modelInstanciator = ObjectModel::new;
private String stringFormatSeparatorPattern;
@ -135,12 +135,14 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
@NotNull
@Override
public ObjectComponent fromJson(@NotNull JsonElement json) {
ObjectComponent obj = new ObjectComponentImpl();
ObjectComponent obj = generateEmptyComponent();
for (Map.Entry<String, JsonElement> entry : json.getAsJsonObject().entrySet()) {
ComponentType<?, ?> subComponentType = fields.get(entry.getKey());
// TODO adapt JSON format
obj.set(entry.getKey(), subComponentType.fromJson(entry.getValue()));
}
return obj;
}
@ -152,12 +154,9 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
@Override
public ObjectComponent generateEmptyComponent() {
ObjectComponent comp = new ObjectComponentImpl();
for (Map.Entry<String, ComponentType<?, ?>> entry : fields.entrySet())
comp.set(entry.getKey(), entry.getValue().generateEmptyComponent());
return comp;
//for (Map.Entry<String, ComponentType<?, ?>> entry : fields.entrySet())
// comp.set(entry.getKey(), entry.getValue().generateEmptyComponent());
return componentInstanciator == null ? new ObjectComponentImpl() : componentInstanciator.get();
}
@Override

View File

@ -60,7 +60,7 @@ public class StringComponentType extends ComponentType<StringModel, StringCompon
@Override
public StringComponent generateEmptyComponent() {
return new StringComponent("");
return new StringComponent();
}
@Override

View File

@ -1,69 +0,0 @@
package net.Indyuce.mmoitems.stat.data;
import io.lumine.mythic.lib.element.Element;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.util.ElementStatType;
import net.Indyuce.mmoitems.util.Pair;
import org.jetbrains.annotations.NotNull;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
@Deprecated
public class ElementListData implements StatData, Mergeable<ElementListData> {
private final Map<Pair<Element, ElementStatType>, Double> stats = new LinkedHashMap<>();
public double getStat(Element element, ElementStatType statType) {
Double found = stats.get(Pair.of(element, statType));
return found == null ? 0 : found;
}
public Set<Pair<Element, ElementStatType>> getKeys() {
return stats.keySet();
}
public void setStat(Element element, ElementStatType statType, double value) {
stats.put(Pair.of(element, statType), value);
}
@Override
public void mergeWith(@NotNull ElementListData targetData) {
//Includes old values if any, fixes stacking of element double values I believe - Kilo
targetData.stats.forEach((key, value) -> stats.put(key, value + stats.getOrDefault(key,0.0)));
}
@NotNull
@Override
public ElementListData clone() {
ElementListData ret = new ElementListData();
for (Map.Entry<Pair<Element, ElementStatType>, Double> entry : stats.entrySet()) {
Pair<Element, ElementStatType> key = entry.getKey();
Double value = entry.getValue();
if (value != 0) {
ret.stats.put(key, value);
}
}
return ret;
}
@Override
public boolean isEmpty() {
return stats.isEmpty();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
ElementListData that = (ElementListData) o;
return stats.equals(that.stats);
}
@Override
public int hashCode() {
return Objects.hash(stats);
}
}

View File

@ -104,6 +104,8 @@ public class EnchantListData implements StatData, Mergeable<EnchantListData> {
return true;
}
/*
TODO enchants
/**
* 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
@ -125,7 +127,7 @@ public class EnchantListData implements StatData, Mergeable<EnchantListData> {
* External: Enchanted manually by a player
*
* @param mmoItem The item, to provide context for adequate guessing.
*/
*
public void identifyTrueOriginalEnchantments(@NotNull MMOItem mmoItem) {
//RFG//MMOItems.log(" \u00a7b> \u00a77Original Enchantments Upkeep");
@ -138,7 +140,7 @@ public class EnchantListData implements StatData, Mergeable<EnchantListData> {
return;
}
EnchantListData mmoData = (EnchantListData) mmoItem.computeData(ItemStats.ENCHANTS);
EnchantListData mmoData = (EnchantListData) mmoItem.computeComponent(ItemStats.ENCHANTS);
// 2: If it has data (It always has) and the amount of enchants is zero, the cached are Extraneous
if (mmoData.getEnchants().size() == 0) {
@ -193,4 +195,5 @@ public class EnchantListData implements StatData, Mergeable<EnchantListData> {
mmoItem.mergeData(ItemStats.ENCHANTS, processed, null);
}
}
*/
}

View File

@ -1,31 +0,0 @@
package net.Indyuce.mmoitems.stat.data;
import net.Indyuce.mmoitems.MMOItems;
/**
* When a gem stone is applied onto an item with a lower level
* requirement, the new item must save the HIGHEST level requirement
* of the two so that newbies cannot use over powered items.
* <p>
* Hence the need to create a RequiredLevelData for that custom merge function.
* <p>
* Used by the 'required level' item stat as well as the 'required profession'
* stats for both MMOCore and AureliumSkills
*/
@Deprecated
public class RequiredLevelData extends DoubleData {
public RequiredLevelData(double value) {
super(value);
}
@Override
public void mergeWith(DoubleData data) {
final boolean additiveMerge = MMOItems.plugin.getConfig().getBoolean("stat-merging.additive-levels", false);
setValue(additiveMerge ? data.getValue() + getValue() : Math.max(data.getValue(), getValue()));
}
@Override
public DoubleData clone() {
return new RequiredLevelData(getValue());
}
}

View File

@ -1,63 +0,0 @@
package net.Indyuce.mmoitems.stat.data;
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import org.bukkit.DyeColor;
import org.bukkit.block.banner.Pattern;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Deprecated
public class ShieldPatternData implements StatData, RandomStatData<ShieldPatternData> {
private DyeColor base;
private final List<Pattern> patterns = new ArrayList<>();
public ShieldPatternData(DyeColor base, Pattern... patterns) {
this.base = base;
this.patterns.addAll(Arrays.asList(patterns));
}
public void setBase(@Nullable DyeColor base) {
this.base = base;
}
@Nullable
public DyeColor getBaseColor() {
return base;
}
@NotNull
public List<Pattern> getPatterns() {
return patterns;
}
public void add(Pattern pattern) {
patterns.add(pattern);
}
public void addAll(List<Pattern> patterns) {
this.patterns.addAll(patterns);
}
@Override
public ShieldPatternData clone() {
final ShieldPatternData clone = new ShieldPatternData(base);
clone.patterns.addAll(patterns);
return clone;
}
@Override
public boolean isEmpty() {
return base == null && patterns.isEmpty();
}
@Override
public ShieldPatternData randomize(MMOItemBuilder builder) {
return this;
}
}

View File

@ -1,7 +1,7 @@
package net.Indyuce.mmoitems.stat.data.type;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.type.Upgradable;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -1,5 +1,7 @@
package net.Indyuce.mmoitems.stat.data.type;
import net.Indyuce.mmoitems.stat.history.StatHistory;
/**
* <code>StatData</code> by itself is just a number, a boolean, an object...
* <p>
@ -11,7 +13,7 @@ package net.Indyuce.mmoitems.stat.data.type;
* an item.
*
* @author jules
* @see {@link net.Indyuce.mmoitems.stat.type.StatHistory}
* @see {@link StatHistory}
*/
public interface StatData {

View File

@ -0,0 +1,23 @@
package net.Indyuce.mmoitems.stat.history;
/**
* TODO sortof supposed to decide how stat history behaves. some internal stats are meant to have no stat history at
* all, like "Item Level" or "Current Item Durability" or anything related to item progression.
* <p>
* in MI7, the problem is no longer stats being non-Mergeable, all stats since all component types are mergeable.
* problem is, do we really want to save stat history for a certain stat?
*/
public enum HistoryPolicy {
/**
* Any stat managed by MMOItems has a classic
*/
CLASSIC,
/**
* No stat history at all
*/
NONE,
}

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmoitems.stat.type;
package net.Indyuce.mmoitems.stat.history;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
@ -11,12 +11,12 @@ 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.data.EnchantListData;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.apache.commons.lang.Validate;
import org.jetbrains.annotations.NotNull;
@ -33,16 +33,16 @@ import java.util.*;
* <p></p>
* This class will store the different sources of each stat UPON being modified.
*/
public class StatHistory {
private final ItemStat itemStat;
private StatData originalData;
public class StatHistory<C extends StatComponent> {
private final ItemStat<C> itemStat;
private C originalData;
private MMOItem parent;
private HashMap<UUID, StatData> perModifierBonus = new HashMap<>();
private ArrayList<StatData> perExternalData = new ArrayList<>();
private HashMap<UUID, StatData> perGemstoneData = new HashMap<>();
private HashMap<UUID, C> perModifierBonus = new HashMap<>();
private ArrayList<C> perExternalData = new ArrayList<>();
private HashMap<UUID, C> perGemstoneData = new HashMap<>();
public StatHistory(@NotNull MMOItem parentItem, @NotNull ItemStat parentStat, @NotNull StatData parentData) {
public StatHistory(@NotNull MMOItem parentItem, @NotNull ItemStat<C> parentStat, @NotNull C parentData) {
itemStat = parentStat;
originalData = parentData;
parent = parentItem;
@ -52,7 +52,7 @@ public class StatHistory {
* Which stat is this the history of?
*/
@NotNull
public ItemStat getItemStat() {
public ItemStat<C> getItemStat() {
return itemStat;
}
@ -69,7 +69,7 @@ public class StatHistory {
* Presumably from when it was first generated.
*/
@NotNull
public StatData getOriginalData() {
public C getOriginalData() {
return originalData;
}
@ -84,7 +84,7 @@ public class StatHistory {
*
* Its an important assumption in several methods
* like Enchants.separateEnchantments()
*/
*
// TODO enchantments.
if (getOriginalData() instanceof EnchantListData) {
if (((EnchantListData) getOriginalData()).getEnchants().size() != 0) {
@ -92,9 +92,10 @@ public class StatHistory {
return false;
}
}
*/
// Any gemstones or external SH? Then its NOT CLEAR
if (getAllGemstones().size() > 0 || getExternalData().size() > 0 || getAllModifiers().size() > 0) {
if (!getAllGemstones().isEmpty() || !getExternalData().isEmpty() || !getAllModifiers().isEmpty()) {
//CLR//MMOItems.log("\u00a7a -+- \u00a77Found Gemstones / ESH, \u00a7cnot clear. \u00a78{\u00a77" + getItemStat().getId() + "\u00a78}");
return false;
}
@ -111,7 +112,7 @@ public class StatHistory {
}
@NotNull
public StatHistory setParent(@NotNull MMOItem parent) {
public StatHistory<C> setParent(@NotNull MMOItem parent) {
this.parent = parent;
return this;
}
@ -120,9 +121,9 @@ public class StatHistory {
* The first value ever recorded of this stat, in this item.
* Presumably from when it was first generated.
*/
public void setOriginalData(@NotNull StatData s) {
Validate.notNull(s, "Original data cannot be null");
originalData = s;
public void setOriginalData(@NotNull C c) {
Validate.notNull(c, "Original data cannot be null");
originalData = c;
}
/**
@ -130,7 +131,7 @@ public class StatHistory {
* were rolled when the item was first created.
*/
@Nullable
public StatData getModifiersBonus(@NotNull UUID of) {
public C getModifiersBonus(@NotNull UUID of) {
return perModifierBonus.get(of);
}
@ -139,7 +140,7 @@ public class StatHistory {
* @param data The total bonus given by modifiers that
* were rolled when the item was first created.
*/
public void registerModifierBonus(@NotNull UUID of, @NotNull StatData data) {
public void registerModifierBonus(@NotNull UUID of, @NotNull C data) {
Validate.notNull(of, "Modifier UUID cannot be null");
Validate.notNull(data, "Stat data cannot be null");
if (data.isEmpty()) return;
@ -176,7 +177,7 @@ public class StatHistory {
* GemStones may have scaled with upgrades, that will be accounted for.
*/
@Nullable
public StatData getGemstoneData(@NotNull UUID of) {
public C getGemstoneData(@NotNull UUID of) {
return perGemstoneData.get(of);
}
@ -205,7 +206,7 @@ public class StatHistory {
* <p>originally <code>+5</code>, now at level 2, with <code>+0.25</code> per level</p>
* The value of this stat data will be <b><code>+5.5</code></b>
*/
public void registerGemstoneData(@NotNull UUID of, @NotNull StatData data) {
public void registerGemstoneData(@NotNull UUID of, @NotNull C data) {
Validate.notNull(of, "Gemstone ID cannot be null");
Validate.notNull(data, "Stat data cannot be null");
if (data.isEmpty()) return;
@ -231,7 +232,7 @@ public class StatHistory {
* Well, I guess whatever plugin is putting them here may remove them by editing the list directly with <code>StatHistory.getExternalData()</code>
*/
@NotNull
public ArrayList<StatData> getExternalData() {
public ArrayList<C> getExternalData() {
return perExternalData;
}
@ -242,8 +243,8 @@ public class StatHistory {
public void fuseExternalData() {
// Create Clear
StatData theEXSH = getItemStat().getClearStatData();
for (StatData ex : getExternalData()) ((Mergeable) theEXSH).mergeWith((Mergeable) ex);
C theEXSH = getItemStat().generateEmptyComponent();
for (C ex : getExternalData()) ((Mergeable) theEXSH).mergeWith((Mergeable) ex);
// Clear and Register
getExternalData().clear();
@ -258,7 +259,7 @@ public class StatHistory {
* <p>They act as gem stones, adding together to produce the total of the item, but cannot be removed, since there is no way to tell them from each other.</p>
* Well, I guess whatever plugin is putting them here may remove them by editing the list directly with <code>StatHistory.getExternalData()</code>
*/
public void registerExternalData(@NotNull StatData data) {
public void registerExternalData(@NotNull C data) {
Validate.notNull(data, "Stat data cannot be null");
if (data.isEmpty()) return;
@ -280,17 +281,17 @@ public class StatHistory {
// No socket history can be found => clear all gems
// TODO invent a gem stone UUID cache in the MMOItem class.
GemSocketsData data = (GemSocketsData) getMMOItem().getData(ItemStats.GEM_SOCKETS);
GemstonesComponent data = getMMOItem().getComponent(ItemStats.GEM_SOCKETS);
if (data == null) {
perGemstoneData.clear();
return;
}
// Pb: intersecting between List and HashTable
HashMap<UUID, StatData> newPerGemstoneData = new HashMap<>();
for (GemstoneData gemData : data.getGemstones()) {
final StatData found = perGemstoneData.get(gemData.getHistoricUUID());
if (found != null) newPerGemstoneData.put(gemData.getHistoricUUID(), found);
HashMap<UUID, C> newPerGemstoneData = new HashMap<>();
for (GemstoneComponent gemData : data.getGemstones()) {
final C found = perGemstoneData.get(gemData.getUniqueId());
if (found != null) newPerGemstoneData.put(gemData.getUniqueId(), found);
}
perGemstoneData = newPerGemstoneData;
}
@ -302,7 +303,7 @@ public class StatHistory {
* <code>StatData</code> that shall be applied (used when upgrading).
*/
@NotNull
public StatData recalculate(int level) {
public C recalculate(int level) {
return recalculate(true, level);
}
@ -312,13 +313,13 @@ public class StatHistory {
* subtract it from {@link #recalculate(int)}.
*/
@NotNull
public StatData recalculateUnupgraded() {
public C recalculateUnupgraded() {
return recalculate(true, null);
}
private int findLevel(int upgradeLevel, UUID gemstoneId) {
for (GemstoneData gemstone : getMMOItem().getGemstones())
if (gemstone.getHistoricUUID().equals(gemstoneId))
for (GemstoneComponent gemstone : getMMOItem().getGemstones())
if (gemstone.getUniqueId().equals(gemstoneId))
return gemstone.isScaling() ? gemstone.getLevel() : upgradeLevel;
throw new IllegalArgumentException("Could not find level of gem " + gemstoneId);
}
@ -334,36 +335,45 @@ public class StatHistory {
* <p>5: Sums external data (modifiers that are not linked to an ID, I suppose by external plugins).
*/
@NotNull
public StatData recalculate(boolean purgeFirst, @Nullable Integer upgradeLevel) {
public C recalculate(boolean purgeFirst, @Nullable Integer upgradeLevel) {
if (purgeFirst) purgeGemstones();
/*
//TODO Upgrade
final UpgradeInfo upgradeInfo = upgradeLevel != null &&
upgradeLevel != 0 &&
getItemStat() instanceof Upgradable ?
getMMOItem().getUpgradeTemplate().getUpgradeInfo(getItemStat()) : null;
*/
// Clone original
Mergeable finalData = ((Mergeable) originalData).clone();
C finalData = (C) originalData.clone();
// Add modifiers (affected by upgrades as if they were base item data)
for (StatData data : perModifierBonus.values()) finalData.mergeWith((Mergeable) data);
for (C data : perModifierBonus.values()) finalData.mergeWith((Mergeable) data);
//TODO Upgrade
/*
// Level up
if (upgradeInfo != null)
finalData = (Mergeable) ((Upgradable) getItemStat()).apply(finalData, upgradeInfo, upgradeLevel);
*/
// Add up gemstones
for (UUID gemstoneId : perGemstoneData.keySet()) {
Mergeable gsData = (Mergeable) getGemstoneData(gemstoneId);
/*
TODO Upgrade
if (upgradeInfo != null) {
int levelDifference = upgradeLevel - findLevel(upgradeLevel, gemstoneId);
gsData = (Mergeable) ((Upgradable) getItemStat()).apply(gsData.clone(), upgradeInfo, levelDifference);
}
*/
finalData.mergeWith(gsData);
}
// Add up externals (who don't suffer upgrades)
for (StatData externalData : getExternalData()) finalData.mergeWith((Mergeable) externalData);
for (C externalData : getExternalData()) finalData.mergeWith((Mergeable) externalData);
return finalData;
}
@ -745,7 +755,7 @@ public class StatHistory {
public void assimilate(@NotNull StatHistory other) {
if (other.getItemStat().getNBTPath().equals(getItemStat().getNBTPath())) {
for (UUID exUID : other.getAllGemstones()) registerGemstoneData(exUID, other.getGemstoneData(exUID));
for (StatData ex : other.getExternalData()) registerExternalData((ex));
for (C ex : other.getExternalData()) registerExternalData((ex));
for (UUID exUID : other.getAllModifiers()) registerModifierBonus(exUID, other.getModifiersBonus(exUID));
}
}
@ -784,7 +794,7 @@ public class StatHistory {
@NotNull
@Deprecated
public StatData recalculateUnupgraded(boolean withPurge) {
public C recalculateUnupgraded(boolean withPurge) {
return recalculate(withPurge, null);
}

View File

@ -2,7 +2,6 @@ package net.Indyuce.mmoitems.stat.type;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.SupportedNBTTagValues;
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackCategory;
import io.lumine.mythic.lib.api.util.ui.FriendlyFeedbackProvider;
import io.lumine.mythic.lib.api.util.ui.PlusMinusPercent;
@ -21,6 +20,9 @@ import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.extra.Previewable;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.apache.commons.lang.Validate;
import org.bukkit.ChatColor;
@ -31,7 +33,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.text.DecimalFormat;
import java.util.ArrayList;
public class DoubleStat extends ItemStat<DoubleComponent> implements Upgradable, Previewable<NumericStatFormula, DoubleData> {
@ -126,9 +127,7 @@ public class DoubleStat extends ItemStat<DoubleComponent> implements Upgradable,
double value = component.getValue();
// Cancel if it its NEGATIVE and this doesn't support negative stats.
if (value < 0 && !handleNegativeStats()) {
return;
}
if (value < 0 && !handleNegativeStats()) return;
// Identify the upgrade amount
double upgradeShift = 0;
@ -137,12 +136,12 @@ public class DoubleStat extends ItemStat<DoubleComponent> implements Upgradable,
if (UpgradeTemplate.isDisplayingUpgrades() && builder.getMMOItem().getUpgradeLevel() != 0) {
// Get stat history
StatHistory hist = builder.getMMOItem().getStatHistory(this);
StatHistory<DoubleComponent> hist = builder.getMMOItem().getStatHistory(this);
if (hist != null) {
// Get as if it had never been upgraded
//HSY//MMOItems.log(" \u00a73-\u00a7a- \u00a77Stat Change Display Recalculation \u00a73-\u00a7a-\u00a73-");
DoubleData uData = (DoubleData) hist.recalculateUnupgraded();
DoubleComponent uData = hist.recalculateUnupgraded();
// Calculate Difference
upgradeShift = value - uData.getValue();
@ -166,9 +165,7 @@ public class DoubleStat extends ItemStat<DoubleComponent> implements Upgradable,
* It is important that the tags are not excluded in getAppliedNBT() because the StatHistory does
* need that blanc tag information to remember when an Item did not initially have any of a stat.
*/
if (component.getValue() != 0) {
builder.addItemTag(new ItemTag(getNBTPath(), component.getValue()));
}
if (component.getValue() != 0) writeDoubleToNbt(builder, component);
}
@NotNull
@ -285,12 +282,6 @@ public class DoubleStat extends ItemStat<DoubleComponent> implements Upgradable,
+ formula.getMin() + " -> " + formula.getMax() + ") }");
}
@Override
@NotNull
public DoubleData getClearStatData() {
return new DoubleData(0D);
}
protected void writeDoubleToNbt(ItemStackBuilder builder, DoubleComponent component) {
builder.addItemTag(new ItemTag(getNBTPath(), component.getValue()));
}

View File

@ -1,10 +0,0 @@
package net.Indyuce.mmoitems.stat.type;
public enum HistoryPolicy {
/**
* Any stat managed by MMOItems has a classic
*/
CLASSIC,
}

View File

@ -9,6 +9,8 @@ import net.Indyuce.mmoitems.stat.component.type.builtin.NumberComponentType;
import net.Indyuce.mmoitems.stat.data.DoubleData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.type.extra.Previewable;
import net.Indyuce.mmoitems.stat.type.extra.Upgradable;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -26,6 +28,8 @@ public class IntegerStat extends ItemStat<IntegerComponent> implements Previewab
.icon(mat)
.trimdesc(lore)
.build());
setMergeable(true);
}
@Nullable
@ -42,7 +46,7 @@ public class IntegerStat extends ItemStat<IntegerComponent> implements Previewab
public void write(ItemStackBuilder builder, @NotNull IntegerComponent component) {
if (component.getValue() == 0) return;
// TODO same thing as doubles you know what i mean
// TODO same thing as doubles you know what i mean (non zero rules?)
writeIntToNbt(builder, component);

View File

@ -55,6 +55,8 @@ public abstract class ItemStat<C extends StatComponent> {
*/
private boolean itemMetaSaved = true;
private boolean mergeable;
/**
* @see #readTranslationFile(ConfigurationSection)
*/
@ -128,6 +130,14 @@ public abstract class ItemStat<C extends StatComponent> {
this.displayInLore = displayInLore;
}
public boolean isMergeable() {
return mergeable;
}
public void setMergeable(boolean mergeable) {
this.mergeable = mergeable;
}
public boolean displaysInLore() {
return displayInLore;
}
@ -426,8 +436,8 @@ public abstract class ItemStat<C extends StatComponent> {
* @author gunging
*/
@NotNull
public StatData getClearStatData() {
throw new RuntimeException("not called anymore");
public C generateEmptyComponent() {
return (C) getComponentType().generateEmptyComponent();
}
//region Util Methods for NBT application and reading

View File

@ -19,6 +19,7 @@ public abstract class RequirementStat extends IntegerStat implements ItemRestric
super("REQUIRED_" + idKey, new String[]{"!block", "all"});
setComponentType(NumberComponentType.integer()
.mergeMethod(NumberComponentType.MergeMecanism.HIGHEST)
.moreIsBetter(false)
.name("Required " + nameKey)
.icon(mat)
@ -33,6 +34,7 @@ public abstract class RequirementStat extends IntegerStat implements ItemRestric
super(idKey, mat, "Required " + nameKey, lore, new String[]{"!block", "all"});
setComponentType(NumberComponentType.integer()
.mergeMethod(NumberComponentType.MergeMecanism.HIGHEST)
.moreIsBetter(false)
.name(nameKey)
.icon(mat)

View File

@ -1,8 +1,9 @@
package net.Indyuce.mmoitems.stat.type;
package net.Indyuce.mmoitems.stat.type.extra;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.jetbrains.annotations.NotNull;
/**

View File

@ -1,4 +1,4 @@
package net.Indyuce.mmoitems.stat.type;
package net.Indyuce.mmoitems.stat.type.extra;
/**
* Some stats are just options related to the template and not the item
@ -8,6 +8,7 @@ package net.Indyuce.mmoitems.stat.type;
* They can be edited just like a regular stat, but don't need to be loaded
* from the item when checking its NBT.
*/
@Deprecated
public interface TemplateOption {
}

View File

@ -1,8 +1,9 @@
package net.Indyuce.mmoitems.stat.type;
package net.Indyuce.mmoitems.stat.type.extra;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.data.type.UpgradeInfo;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -16,6 +17,7 @@ import org.jetbrains.annotations.Nullable;
* TODO add abilities so that ability damage, effect duration etc. can
* increase as well when upgrading an item.
*/
@Deprecated
public interface Upgradable {
/**

View File

@ -3,7 +3,7 @@ package net.Indyuce.mmoitems.listener.reforging;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

View File

@ -8,18 +8,19 @@ import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.util.MMOItemReforger;
import net.Indyuce.mmoitems.stat.data.EnchantListData;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.data.GemstoneData;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.behaviour.GemStoneStat;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstoneComponent;
import net.Indyuce.mmoitems.stat.component.builtin.composite.GemstonesComponent;
import net.Indyuce.mmoitems.stat.data.GemSocketsData;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import java.util.ArrayList;
import java.util.List;
/**
* Prevents gems from being lost when reforging.
@ -32,20 +33,22 @@ public class RFGKeepGems implements Listener {
@EventHandler
public void onReforge(MMOItemReforgeEvent event) {
if (!event.getOptions().shouldKeepGemStones()) { return; }
if (!event.getOptions().shouldKeepGemStones()) {
return;
}
//RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping Gems");
// Get those gems
GemSocketsData oldGemstoneData = (GemSocketsData) event.getOldMMOItem().getData(ItemStats.GEM_SOCKETS);
GemstonesComponent oldGemstoneData = event.getOldMMOItem().getComponent(ItemStats.GEM_SOCKETS);
// No gems? why are we here
if (oldGemstoneData == null) { return; }
if (oldGemstoneData == null) return;
// Get those gems
GemSocketsData newGemstoneData = (GemSocketsData) event.getNewMMOItem().getData(ItemStats.GEM_SOCKETS);
GemstonesComponent newGemstoneData = event.getNewMMOItem().getComponent(ItemStats.GEM_SOCKETS);
//RFG//MMOItems.log(" \u00a7a@ \u00a77Applying Gemstones");
ArrayList<GemstoneData> lostGems = new ArrayList<>();
ArrayList<GemstoneComponent> lostGems = new ArrayList<>();
// If it has an upgrade template defined, just remember the level
if (newGemstoneData != null) {
@ -54,16 +57,16 @@ public class RFGKeepGems implements Listener {
//RFG//MMOItems.log(" \u00a7a* \u00a77Existing Data Detected\u00a7a " + oldGemstoneData.toString());
// Get those damn empty sockets
ArrayList<GemstoneData> transferredGems = new ArrayList<>();
ArrayList<String> availableSockets = new ArrayList<>(newGemstoneData.getEmptySlots());
ArrayList<GemstoneData> oldSockets = new ArrayList<>(oldGemstoneData.getGemstones());
ArrayList<GemstoneComponent> transferredGems = new ArrayList<>();
List<StringComponent> availableSockets = newGemstoneData.getSockets();
List<GemstoneComponent> oldSockets = oldGemstoneData.getGemstones();
// Remaining
for (GemstoneData oldSocketedGem : oldSockets) {
for (GemstoneComponent oldSocketedGem : oldSockets) {
//RFG//MMOItems.log(" \u00a7a*\u00a7e* \u00a77Fitting \u00a7f" + oldSocketedGem.getHistoricUUID().toString() + "\u00a77 '" + oldSocketedGem.getName() + "\u00a7'");
// No more if no more sockets left
if (availableSockets.size() == 0) {
if (availableSockets.isEmpty()) {
//RFG//MMOItems.log(" \u00a7a +\u00a7c+ \u00a77No More Sockets");
// This gemstone could not be inserted, it is thus lost
@ -75,11 +78,15 @@ public class RFGKeepGems implements Listener {
// Get colour, uncolored if Unknown
String colour = oldSocketedGem.getSocketColor();
if (colour == null) { colour = GemSocketsData.getUncoloredGemSlot(); }
if (colour == null) {
colour = GemSocketsData.getUncoloredGemSlot();
}
String newColorToInsertInto = null;
// Does the gem data have an available socket?
for (String slot : availableSockets) { if (slot.equals(GemSocketsData.getUncoloredGemSlot()) || colour.equals(slot)) { newColorToInsertInto = slot; } }
for (StringComponent slot : availableSockets)
if (slot.getValue().equals(GemSocketsData.getUncoloredGemSlot()) || slot.getValue().equals(colour))
newColorToInsertInto = slot.getValue();
// Existed?
if (newColorToInsertInto != null) {
@ -93,7 +100,8 @@ public class RFGKeepGems implements Listener {
// Include as lost gem
lostGems.add(oldSocketedGem);
continue; }
continue;
}
// Reforge gemstone
MMOItemReforger gemReforge = new MMOItemReforger(restoredGem.newBuilder().build());
@ -119,7 +127,7 @@ public class RFGKeepGems implements Listener {
// Whatever
LiveMMOItem gemResult = new LiveMMOItem(gemReforge.getResult());
GemstoneData reforgedGemData = new GemstoneData(gemResult, newColorToInsertInto, oldSocketedGem.getHistoricUUID());
GemstoneComponent reforgedGemData = new GemstoneComponent(gemResult, newColorToInsertInto, oldSocketedGem.getUniqueId());
reforgedGemData.setLevel(oldSocketedGem.getLevel());
// Remove, we have succeeded
@ -135,69 +143,76 @@ public class RFGKeepGems implements Listener {
if (!(stat instanceof GemStoneStat)) {
// Get the stat data
StatData data = gemResult.getData(stat);
StatComponent data = gemResult.getComponent(stat);
// If the data is MERGEABLE
if (data instanceof Mergeable) {
// Just ignore that lol
if (data instanceof EnchantListData && data.isEmpty()) { continue; }
// Just ignore that lol
// TODO why keep this??????
//if (data instanceof EnchantListData && data.isEmpty()) continue;
//RFG//MMOItems.log("\u00a79>>> \u00a77Gem-Merging \u00a7c" + stat.getNBTPath() + "\u00a7e" + data.toString() + "\u00a78 " + reforgedGemData.getHistoricUUID().toString());
//RFG//MMOItems.log("\u00a79>>> \u00a77Gem-Merging \u00a7c" + stat.getNBTPath() + "\u00a7e" + data.toString() + "\u00a78 " + reforgedGemData.getHistoricUUID().toString());
/*
* The gem data is registered directly into the history (emphasis on not recalculating with purge)
*/
StatHistory hist = event.getNewMMOItem().computeStatHistory(stat);
hist.registerGemstoneData(reforgedGemData.getHistoricUUID(), data);
/*
* The gem data is registered directly into the history (emphasis on not recalculating with purge)
*/
StatHistory hist = event.getNewMMOItem().computeStatHistory(stat);
hist.registerGemstoneData(reforgedGemData.getUniqueId(), data);
//RFG//MMOItems.log("\u00a79>>> \u00a77 Stat history of this stat");
//RFG//hist.log();
}
//RFG//MMOItems.log("\u00a79>>> \u00a77 Stat history of this stat");
//RFG//hist.log();
}
}
// No space/valid socket hmm
// No space/valid socket hmm
} else {
//RFG//MMOItems.log("\u00a7c *\u00a7e*\u00a77 Gemstone lost - \u00a7cno color \u00a78" + oldSocketedGem.getHistoricUUID());
// Include as lost gem
lostGems.add(oldSocketedGem); }
lostGems.add(oldSocketedGem);
}
}
}
// Create with select socket slots and gems
GemSocketsData reforgedGemstoneData = new GemSocketsData(availableSockets);
for (GemstoneData gem : transferredGems) { if (gem == null) { continue; } reforgedGemstoneData.add(gem); }
GemstonesComponent reforgedGemstoneData = new GemstonesComponent();
reforgedGemstoneData.setSockets(availableSockets);
for (GemstoneComponent gem : transferredGems) {
if (gem == null) continue;
reforgedGemstoneData.addGemstone(gem);
}
//RFG//MMOItems.log(" \u00a7a* \u00a77Operation Result\u00a7a " + reforgedGemstoneData.toString());
//RFG//for (String s : reforgedGemstoneData.getEmptySlots()) { MMOItems.log(" \u00a7a* \u00a77Empty\u00a7f " + s); }
//RFG//for (GemstoneData s : reforgedGemstoneData.getGemstones()) { MMOItems.log(" \u00a7a*\u00a7f " + s.getName() + "\u00a77 " + s.getHistoricUUID()); }
// That's the original data
StatHistory gemStory = event.getNewMMOItem().computeStatHistory(ItemStats.GEM_SOCKETS);
StatHistory<GemstonesComponent> gemStory = event.getNewMMOItem().computeStatHistory(ItemStats.GEM_SOCKETS);
gemStory.setOriginalData(reforgedGemstoneData);
event.getNewMMOItem().setData(ItemStats.GEM_SOCKETS, gemStory.recalculate(event.getNewMMOItem().getUpgradeLevel()));
event.getNewMMOItem().setComponent(ItemStats.GEM_SOCKETS, gemStory.recalculate(event.getNewMMOItem().getUpgradeLevel()));
//RFG//MMOItems.log(" \u00a7a* \u00a77History Final\u00a7a --------");
//RFG//gemStory.log();
// Could not fit any gems: No gem sockets!
// Could not fit any gems: No gem sockets!
} else {
//RFG//MMOItems.log("\u00a7c *\u00a7e*\u00a77 All gemstones were lost - \u00a7cno data");
// ALl were lost
lostGems.addAll(oldGemstoneData.getGemstones()); }
lostGems.addAll(oldGemstoneData.getGemstones());
}
// Config option enabled? Build the lost gem MMOItems!
if (ReforgeOptions.dropRestoredGems) {
for (GemstoneData lost : lostGems) {
for (GemstoneComponent lost : lostGems) {
// Get MMOItem
MMOItem restoredGem = event.getOldMMOItem().extractGemstone(lost);
if (restoredGem == null) {
// Mention the loss
MMOItems.print(null, "$bGemstone $r{0} {1} $bno longer exists, it was$f deleted$b from $u{2}$b's {3}$b. ", "RevID", lost.getMMOItemType(), lost.getMMOItemID(), event.getPlayer() == null ? "null" : event.getPlayer().getName(), SilentNumbers.getItemName(event.getReforger().getStack(), false));
continue; }
MMOItems.print(null, "$bGemstone $r{0} {1} $bno longer exists, it was$f deleted$b from $u{2}$b's {3}$b. ", "RevID", lost.getItemType(), lost.getItemId(), event.getPlayer() == null ? "null" : event.getPlayer().getName(), SilentNumbers.getItemName(event.getReforger().getStack(), false));
continue;
}
// Reforge gemstone if it can be reforged
MMOItemReforger gemReforge = new MMOItemReforger(restoredGem.newBuilder().build());
@ -219,6 +234,7 @@ public class RFGKeepGems implements Listener {
// Success? Add that gem (without reforging) there
event.getReforger().addReforgingOutput(restoredGem.newBuilder().build());
}
} }
}
}
}
}

View File

@ -1,10 +1,11 @@
package net.Indyuce.mmoitems.listener.reforging;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.stat.component.builtin.ArrayComponent;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
import net.Indyuce.mmoitems.stat.data.StringListData;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.jetbrains.annotations.NotNull;
@ -28,14 +29,14 @@ public class RFGKeepLore implements Listener {
//RFG// MMOItems.log("§8Reforge §4EFG§7 Keeping Lore");
// No lore I sleep
StringListData loreData = (StringListData) event.getOldMMOItem().getData(ItemStats.LORE);
if (loreData == null) { return; }
ArrayComponent<StringComponent> loreData = event.getOldMMOItem().getComponent(ItemStats.LORE);
if (loreData == null) return;
// Get lore of the item wth
ArrayList<String> extraLore = extractLore(loreData.getList(), event.getOptions().getKeepCase());
ArrayList<String> extraLore = extractLore(loreData.asList(), event.getOptions().getKeepCase());
// No entries? snooze
if (extraLore.size() == 0) { return; }
if (extraLore.isEmpty()) return;
// All right set it as the original in the Stat History
StatHistory hist = event.getNewMMOItem().computeStatHistory(ItemStats.LORE);
@ -57,19 +58,19 @@ public class RFGKeepLore implements Listener {
*
* @return The lines which were successfully kept
*/
@NotNull ArrayList<String> extractLore(@NotNull List<String> lore, @NotNull String keepCase) {
@NotNull ArrayList<String> extractLore(@NotNull List<StringComponent> lore, @NotNull String keepCase) {
//UPGRD//MMOItems.log(" \u00a7d> \u00a77Keeping Lore");
ArrayList<String> ret = new ArrayList<>();
// Examine every element
for (String str : lore) {
for (StringComponent str : lore) {
//UPGRD//MMOItems.log(" \u00a7d>\u00a7c-\u00a7e- \u00a77Line:\u00a7f " + str);
// Does it start with the promised...?
if (str.startsWith(keepCase)) {
if (str.getValue().startsWith(keepCase)) {
//UPGRD//MMOItems.log(" \u00a72>\u00a7a-\u00a7e- \u00a77Kept");
ret.add(str); }
ret.add(str.getValue()); }
}
//UPGRD//MMOItems.log(" \u00a7d> \u00a77Result");

View File

@ -1,10 +1,9 @@
package net.Indyuce.mmoitems.listener.reforging;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.stat.data.type.Mergeable;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

View File

@ -1,9 +1,6 @@
package net.Indyuce.mmoitems.listener.reforging;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.stat.data.NameData;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;

View File

@ -2,10 +2,9 @@ package net.Indyuce.mmoitems.listener.reforging;
import net.Indyuce.mmoitems.api.event.MMOItemReforgeEvent;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.data.random.UpdatableRandomStatData;
import net.Indyuce.mmoitems.stat.data.type.StatData;
import net.Indyuce.mmoitems.stat.type.StatHistory;
import net.Indyuce.mmoitems.stat.history.StatHistory;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;