More bugfixing

This commit is contained in:
Jules 2025-01-19 19:58:39 +01:00
parent 46652835ef
commit 766affefab
29 changed files with 441 additions and 615 deletions

View File

@ -64,48 +64,48 @@ public class ItemStats {
public static final ItemStat DISABLE_ATTACK_PASSIVE = new DisableStat("ATTACK_PASSIVE", Material.BARRIER, "Disable On-Hit Effect", "Disables on-hit effects granted by the item type.", new String[]{"weapon"});
// RPG Stats
public static final ItemStat REQUIRED_LEVEL = new RequiredLevel();
public static final RequiredLevel REQUIRED_LEVEL = new RequiredLevel();
public static final ItemStat<ArrayComponent<StringComponent>> REQUIRED_CLASS = new RequiredClass();
public static final ItemStat ATTACK_DAMAGE = new AttackDamage();
public static final ItemStat ATTACK_SPEED = new AttackSpeed();
public static final ItemStat CRITICAL_STRIKE_CHANCE = new DoubleStat("CRITICAL_STRIKE_CHANCE", Material.NETHER_STAR, "Critical Strike Chance", "Critical Strikes deal more damage, in % chance.", new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat CRITICAL_STRIKE_POWER = new DoubleStat("CRITICAL_STRIKE_POWER", Material.NETHER_STAR, "Critical Strike Power", new String[]{"The extra damage weapon crits deals.", "(Stacks with default value)", "In %."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat SKILL_CRITICAL_STRIKE_CHANCE = new DoubleStat("SKILL_CRITICAL_STRIKE_CHANCE", Material.NETHER_STAR, "Skill Critical Strike Chance", new String[]{"Increases the chance of dealing skill crits (in %)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat SKILL_CRITICAL_STRIKE_POWER = new DoubleStat("SKILL_CRITICAL_STRIKE_POWER", Material.NETHER_STAR, "Skill Critical Strike Power", new String[]{"Extra damage dealt (in %) by skill crits.", "(Stacks with default value)", "In %."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat BLOCK_POWER = new DoubleStat("BLOCK_POWER", Material.IRON_HELMET, "Block Power", new String[]{"The % of the damage your", "armor/shield can block.", "Default: 25%"}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat BLOCK_RATING = new DoubleStat("BLOCK_RATING", Material.IRON_HELMET, "Block Rating", new String[]{"The chance your piece of armor", "has to block any entity attack."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat BLOCK_COOLDOWN_REDUCTION = new DoubleStat("BLOCK_COOLDOWN_REDUCTION", Material.IRON_HELMET, "Block Cooldown Reduction", new String[]{"Reduces the blocking cooldown (%)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat DODGE_RATING = new DoubleStat("DODGE_RATING", Material.FEATHER, "Dodge Rating", new String[]{"The chance to dodge an attack.", "Dodging completely negates", "the attack damage."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat DODGE_COOLDOWN_REDUCTION = new DoubleStat("DODGE_COOLDOWN_REDUCTION", Material.FEATHER, "Dodge Cooldown Reduction", new String[]{"Reduces the dodging cooldown (%)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat PARRY_RATING = new DoubleStat("PARRY_RATING", Material.BUCKET, "Parry Rating", new String[]{"The chance to parry an attack.", "Parrying negates the damage", "and knocks the attacker back."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
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 AttackDamage ATTACK_DAMAGE = new AttackDamage();
public static final AttackSpeed ATTACK_SPEED = new AttackSpeed();
public static final ItemStat<DoubleComponent> CRITICAL_STRIKE_CHANCE = new DoubleStat("CRITICAL_STRIKE_CHANCE", Material.NETHER_STAR, "Critical Strike Chance", "Critical Strikes deal more damage, in % chance.", new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> CRITICAL_STRIKE_POWER = new DoubleStat("CRITICAL_STRIKE_POWER", Material.NETHER_STAR, "Critical Strike Power", new String[]{"The extra damage weapon crits deals.", "(Stacks with default value)", "In %."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> SKILL_CRITICAL_STRIKE_CHANCE = new DoubleStat("SKILL_CRITICAL_STRIKE_CHANCE", Material.NETHER_STAR, "Skill Critical Strike Chance", new String[]{"Increases the chance of dealing skill crits (in %)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> SKILL_CRITICAL_STRIKE_POWER = new DoubleStat("SKILL_CRITICAL_STRIKE_POWER", Material.NETHER_STAR, "Skill Critical Strike Power", new String[]{"Extra damage dealt (in %) by skill crits.", "(Stacks with default value)", "In %."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> BLOCK_POWER = new DoubleStat("BLOCK_POWER", Material.IRON_HELMET, "Block Power", new String[]{"The % of the damage your", "armor/shield can block.", "Default: 25%"}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> BLOCK_RATING = new DoubleStat("BLOCK_RATING", Material.IRON_HELMET, "Block Rating", new String[]{"The chance your piece of armor", "has to block any entity attack."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> BLOCK_COOLDOWN_REDUCTION = new DoubleStat("BLOCK_COOLDOWN_REDUCTION", Material.IRON_HELMET, "Block Cooldown Reduction", new String[]{"Reduces the blocking cooldown (%)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> DODGE_RATING = new DoubleStat("DODGE_RATING", Material.FEATHER, "Dodge Rating", new String[]{"The chance to dodge an attack.", "Dodging completely negates", "the attack damage."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> DODGE_COOLDOWN_REDUCTION = new DoubleStat("DODGE_COOLDOWN_REDUCTION", Material.FEATHER, "Dodge Cooldown Reduction", new String[]{"Reduces the dodging cooldown (%)."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> PARRY_RATING = new DoubleStat("PARRY_RATING", Material.BUCKET, "Parry Rating", new String[]{"The chance to parry an attack.", "Parrying negates the damage", "and knocks the attacker back."}, new String[]{"!miscellaneous", "!block", "all"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> 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<DoubleComponent> 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<DoubleComponent> 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 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<DoubleComponent> 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<DoubleComponent> 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();
public static final ItemStat PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", Material.PORKCHOP, "PvE Damage", new String[]{"Additional damage against", "non human entities in %."}, new String[]{"equipment", "gem_stone"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", Material.SKELETON_SKULL, "PvP Damage", new String[]{"Additional damage", "against players in %."}, new String[]{"equipment", "gem_stone"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat BLUNT_POWER = new DoubleStat("BLUNT_POWER", Material.IRON_AXE, "Blunt Power", new String[]{"The radius of the AoE attack.", "If set to 2.0, enemies within 2 blocks", "around your target will take damage.", "&9This stat only applies to Blunt weapons."}, new String[]{"weapon", "gem_stone"}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat BLUNT_RATING = new DoubleStat("BLUNT_RATING", Material.BRICK, "Blunt Rating", new String[]{"The force of the blunt attack.", "If set to 50%, enemies hit by the attack", "will take 50% of the initial damage.", "&9This stat only applies to Blunt weapons."}, new String[]{"weapon", "gem_stone"}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat WEAPON_DAMAGE = new DoubleStat("WEAPON_DAMAGE", Material.IRON_SWORD, "Weapon Damage", new String[]{"Additional on-hit weapon damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat SKILL_DAMAGE = new DoubleStat("SKILL_DAMAGE", Material.BOOK, "Skill Damage", new String[]{"Additional ability damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PROJECTILE_DAMAGE = new DoubleStat("PROJECTILE_DAMAGE", Material.ARROW, "Projectile Damage", new String[]{"Additional skill/weapon projectile damage."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat MAGIC_DAMAGE = new DoubleStat("MAGIC_DAMAGE", Material.MAGMA_CREAM, "Magic Damage", new String[]{"Additional magic skill damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PHYSICAL_DAMAGE = new DoubleStat("PHYSICAL_DAMAGE", Material.IRON_AXE, "Physical Damage", new String[]{"Additional skill/weapon physical damage."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat DEFENSE = new DoubleStat("DEFENSE", Material.SHIELD, "Defense", new String[]{"Reduces damage from any source.", "Formula can be set in MMOLib Config."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat DAMAGE_REDUCTION = new DoubleStat("DAMAGE_REDUCTION", Material.IRON_CHESTPLATE, "Damage Reduction", new String[]{"Reduces damage from any source.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat FALL_DAMAGE_REDUCTION = new DoubleStat("FALL_DAMAGE_REDUCTION", Material.FEATHER, "Fall Damage Reduction", new String[]{"Reduces fall damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PROJECTILE_DAMAGE_REDUCTION = new DoubleStat("PROJECTILE_DAMAGE_REDUCTION", Material.SNOWBALL, "Projectile Damage Reduction", new String[]{"Reduces projectile damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PHYSICAL_DAMAGE_REDUCTION = new DoubleStat("PHYSICAL_DAMAGE_REDUCTION", Material.LEATHER_CHESTPLATE, "Physical Damage Reduction", new String[]{"Reduces physical damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat FIRE_DAMAGE_REDUCTION = new DoubleStat("FIRE_DAMAGE_REDUCTION", Material.BLAZE_POWDER, "Fire Damage Reduction", new String[]{"Reduces fire damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat MAGIC_DAMAGE_REDUCTION = new DoubleStat("MAGIC_DAMAGE_REDUCTION", Material.POTION, "Magic Damage Reduction", new String[]{"Reduce magic damage dealt by potions.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PVE_DAMAGE_REDUCTION = new DoubleStat("PVE_DAMAGE_REDUCTION", Material.PORKCHOP, "PvE Damage Reduction", new String[]{"Reduces damage dealt by mobs.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat PVP_DAMAGE_REDUCTION = new DoubleStat("PVP_DAMAGE_REDUCTION", Material.SKELETON_SKULL, "PvP Damage Reduction", new String[]{"Reduces damage dealt by players", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat UNDEAD_DAMAGE = new DoubleStat("UNDEAD_DAMAGE", Material.SKELETON_SKULL, "Undead Damage", new String[]{"Deals additional damage to undead.", "In %."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat LIFESTEAL = new DoubleStat("LIFESTEAL", Material.REDSTONE, "Lifesteal", new String[]{"Percentage of damage you gain back as", "health when inflicting weapon damage."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat SPELL_VAMPIRISM = new DoubleStat("SPELL_VAMPIRISM", Material.REDSTONE, "Spell Vampirism", new String[]{"Percentage of damage you gain back as", "health when inflicting skill damage."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> PVE_DAMAGE = new DoubleStat("PVE_DAMAGE", Material.PORKCHOP, "PvE Damage", new String[]{"Additional damage against", "non human entities in %."}, new String[]{"equipment", "gem_stone"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> PVP_DAMAGE = new DoubleStat("PVP_DAMAGE", Material.SKELETON_SKULL, "PvP Damage", new String[]{"Additional damage", "against players in %."}, new String[]{"equipment", "gem_stone"}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> BLUNT_POWER = new DoubleStat("BLUNT_POWER", Material.IRON_AXE, "Blunt Power", new String[]{"The radius of the AoE attack.", "If set to 2.0, enemies within 2 blocks", "around your target will take damage.", "&9This stat only applies to Blunt weapons."}, new String[]{"weapon", "gem_stone"}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> BLUNT_RATING = new DoubleStat("BLUNT_RATING", Material.BRICK, "Blunt Rating", new String[]{"The force of the blunt attack.", "If set to 50%, enemies hit by the attack", "will take 50% of the initial damage.", "&9This stat only applies to Blunt weapons."}, new String[]{"weapon", "gem_stone"}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> WEAPON_DAMAGE = new DoubleStat("WEAPON_DAMAGE", Material.IRON_SWORD, "Weapon Damage", new String[]{"Additional on-hit weapon damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> SKILL_DAMAGE = new DoubleStat("SKILL_DAMAGE", Material.BOOK, "Skill Damage", new String[]{"Additional ability damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PROJECTILE_DAMAGE = new DoubleStat("PROJECTILE_DAMAGE", Material.ARROW, "Projectile Damage", new String[]{"Additional skill/weapon projectile damage."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> MAGIC_DAMAGE = new DoubleStat("MAGIC_DAMAGE", Material.MAGMA_CREAM, "Magic Damage", new String[]{"Additional magic skill damage in %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PHYSICAL_DAMAGE = new DoubleStat("PHYSICAL_DAMAGE", Material.IRON_AXE, "Physical Damage", new String[]{"Additional skill/weapon physical damage."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> DEFENSE = new DoubleStat("DEFENSE", Material.SHIELD, "Defense", new String[]{"Reduces damage from any source.", "Formula can be set in MMOLib Config."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> DAMAGE_REDUCTION = new DoubleStat("DAMAGE_REDUCTION", Material.IRON_CHESTPLATE, "Damage Reduction", new String[]{"Reduces damage from any source.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> FALL_DAMAGE_REDUCTION = new DoubleStat("FALL_DAMAGE_REDUCTION", Material.FEATHER, "Fall Damage Reduction", new String[]{"Reduces fall damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PROJECTILE_DAMAGE_REDUCTION = new DoubleStat("PROJECTILE_DAMAGE_REDUCTION", Material.SNOWBALL, "Projectile Damage Reduction", new String[]{"Reduces projectile damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PHYSICAL_DAMAGE_REDUCTION = new DoubleStat("PHYSICAL_DAMAGE_REDUCTION", Material.LEATHER_CHESTPLATE, "Physical Damage Reduction", new String[]{"Reduces physical damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> FIRE_DAMAGE_REDUCTION = new DoubleStat("FIRE_DAMAGE_REDUCTION", Material.BLAZE_POWDER, "Fire Damage Reduction", new String[]{"Reduces fire damage.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> MAGIC_DAMAGE_REDUCTION = new DoubleStat("MAGIC_DAMAGE_REDUCTION", Material.POTION, "Magic Damage Reduction", new String[]{"Reduce magic damage dealt by potions.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PVE_DAMAGE_REDUCTION = new DoubleStat("PVE_DAMAGE_REDUCTION", Material.PORKCHOP, "PvE Damage Reduction", new String[]{"Reduces damage dealt by mobs.", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> PVP_DAMAGE_REDUCTION = new DoubleStat("PVP_DAMAGE_REDUCTION", Material.SKELETON_SKULL, "PvP Damage Reduction", new String[]{"Reduces damage dealt by players", "In %."}).setCategory(StatCategories.DAMAGE_MITIGATION);
public static final ItemStat<DoubleComponent> UNDEAD_DAMAGE = new DoubleStat("UNDEAD_DAMAGE", Material.SKELETON_SKULL, "Undead Damage", new String[]{"Deals additional damage to undead.", "In %."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> LIFESTEAL = new DoubleStat("LIFESTEAL", Material.REDSTONE, "Lifesteal", new String[]{"Percentage of damage you gain back as", "health when inflicting weapon damage."}).setCategory(StatCategories.OFFENSE);
public static final ItemStat<DoubleComponent> SPELL_VAMPIRISM = new DoubleStat("SPELL_VAMPIRISM", Material.REDSTONE, "Spell Vampirism", new String[]{"Percentage of damage you gain back as", "health when inflicting skill damage."}).setCategory(StatCategories.OFFENSE);
// Extra Stats
public static final ItemStat<BooleanComponent> UNBREAKABLE = new Unbreakable();
@ -170,13 +170,13 @@ public class ItemStats {
public static final ItemStat MAX_CONSUME = new MaxConsume();
public static final ItemStat SUCCESS_RATE = new SuccessRate();
public static final ItemStat// Crafting Stats
CRAFTING = new Crafting();
public static final ItemStat<StringComponent> CRAFT_PERMISSION = new CraftingPermission();
// Crafting Stats
public static final Crafting CRAFTING = new Crafting();
public static final CraftingPermission CRAFT_PERMISSION = new CraftingPermission();
//CRAFT_AMOUNT = new DoubleStat("CRAFTED_AMOUNT", Material.WOODEN_AXE, "Crafted Amount", new String[]{"The stack count for", "this item when crafted."}, new String[0]),
public static final ItemStat// Unique Stats
AUTOSMELT = new BooleanStat("AUTOSMELT", Material.COAL, "Autosmelt", "When toggled on, your tool will automatically smelt mined ores.", new String[]{"tool"}).setCategory(StatCategories.TOOLS);
// Unique (??) Stats
public static final ItemStat AUTOSMELT = new BooleanStat("AUTOSMELT", Material.COAL, "Autosmelt", "When toggled on, your tool will automatically smelt mined ores.", new String[]{"tool"}).setCategory(StatCategories.TOOLS);
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(),
@ -210,7 +210,7 @@ public class ItemStats {
public static final ItemStat<BooleanComponent> DOWNGRADE_ON_DEATH = new BooleanStat("DEATH_DOWNGRADE", Material.DAMAGED_ANVIL, "Downgrade on Death", "If the wearer of this item dies, it may downgrade (based on &6Death Downgrade Chance &7stat).\nRequired to define an &6Upgrade Template.\nRequires keep-inventory gamerule. ", new String[]{"equipment"}).setCategory(StatCategories.UPGRADING);
public static final ItemStat<DoubleComponent> DOWNGRADE_ON_DEATH_CHANCE = new DoubleStat("DEATH_DOWNGRADE_CHANCE", Material.SKELETON_SKULL, "Death Downgrade Chance", "Probability that an item with &cDowngrade on Death &7will be downgraded when the player dies.\n\n Exceeding 100% will for sure downgrade one item, and roll again to downgrade another (with the excess probability). The same item won't be downgraded twice.", new String[]{"equipment"}, false).setCategory(StatCategories.UPGRADING);
// Unique Item Stats
// Unique (??) Item Stats
public static final DyeColor DYE_COLOR = new DyeColor();
public static final ItemStat<BooleanComponent> HIDE_DYE = new HideDye();
public static final ItemStat<ObjectComponent> ARMOR_TRIM = new ArmorTrimStat();

View File

@ -31,6 +31,7 @@ public class StatCategories {
GENERAL = new StatCategory("GENERAL", "General", "General"),
SPECIAL = new StatCategory("SPECIAL", "Special", "Special"),
TOGGLES = new StatCategory("TOGGLES", "Toggles", "Toggles"),
SOUNDS = new StatCategory("SOUNDS", "Sounds", "Item Sounds"),
MMOCORE_PROFESSIONS = new StatCategory("MMOCORE_PROFESSIONS", "MMOCore Professions", "MMOCore Professions", true),
MMOCORE_ATTRIBUTES = new StatCategory("MMOCORE_ATTRIBUTES", "MMOCore Attributes", "MMOCore Attributes", true),
ITEM = new StatCategory("ITEM", "Item & Texture", "Item & Texture");

View File

@ -10,31 +10,36 @@ public enum CustomSound {
ON_BLOCK_BREAK(Material.COBBLESTONE, 25, "Plays when a block is broken with the item."),
ON_PICKUP(Material.IRON_INGOT, 28, "Plays when you pickup the item from the ground."),
ON_LEFT_CLICK(Material.STONE_AXE, 31, "Plays when item is left-clicked."),
ON_CRAFT(Material.CRAFTING_TABLE, 34, "Plays when item is crafted in a crafting inventory", "or when smelted from someting in a furnace."),
ON_CONSUME(Material.APPLE, 37, "Plays when item has been consumed.", "(After eating/drinking animation)"),
ON_CRAFT(Material.CRAFTING_TABLE, 34, "Plays when item is crafted in a crafting inventory or when smelted from something in a furnace."),
ON_CONSUME(Material.APPLE, 37, "Plays when item has been consumed, after eating or drinking animation."),
ON_ITEM_BREAK(Material.FLINT, 40, "Plays when the item breaks."),
ON_CROSSBOW(Material.ARROW, 38, "Plays when a crossbow shoots an arrow."),
ON_PLACED(Material.STONE, 43, "Plays when the block is placed.");
private final ItemStack item;
private final String[] lore;
private final Material icon;
private final String lore;
private final int slot;
CustomSound(Material material, int slot, String... lore) {
this.item = new ItemStack(material);
CustomSound(Material icon, int slot, String lore) {
this.icon = icon;
this.lore = lore;
this.slot = slot;
}
@Deprecated
public ItemStack getItem() {
return item;
return new ItemStack(icon);
}
public Material getIcon() {
return icon;
}
public String getName() {
return UtilityMethods.caseOnWords(name().toLowerCase().replace('_', ' '));
}
public String[] getLore() {
public String getLore() {
return lore;
}

View File

@ -5,13 +5,16 @@ import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.util.SmartGive;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import io.lumine.mythic.lib.version.Sounds;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.event.item.ConsumableConsumedEvent;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.item.util.LoreUpdate;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.SoundStat;
import net.Indyuce.mmoitems.stat.behaviour.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.behaviour.PlayerConsumable;
import org.bukkit.Bukkit;
@ -80,6 +83,9 @@ public class Consumable extends UseItem {
for (PlayerConsumable sc : MMOItems.plugin.getStats().getPlayerConsumables())
sc.onConsume(mmoitem, player, vanillaEeating);
// Play consume sound
SoundStat.playSound(nbtItem.getItem(), CustomSound.ON_CONSUME, event.getPlayer(), Sounds.ENTITY_GENERIC_EAT);
/**
* If the item does not have a maximum amount of uses, this will always
* return 0 and that portion will just skip.

View File

@ -2,16 +2,12 @@ package net.Indyuce.mmoitems.api.item.mmoitem;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.stat.component.StatComponent;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
// TODO
@Deprecated
public class LiveItemEditor extends MMOItem {
public LiveItemEditor(NBTItem nbtItem) {
public LiveItemEditor(NBTItem item) {
super(Type.get(item.getType()), item.getString("MMOITEMS_ITEM_ID"));
}
}

View File

@ -15,6 +15,7 @@ import net.Indyuce.mmoitems.api.player.RPGPlayer;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.api.util.message.FFPMMOItems;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.component.type.builtin.VoidComponentType;
import net.Indyuce.mmoitems.stat.data.random.RandomStatData;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.apache.commons.lang.Validate;
@ -28,6 +29,7 @@ import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
public class MMOItemTemplate implements ItemReference, PreloadedObject {
private final Type type;
@ -77,11 +79,16 @@ public class MMOItemTemplate implements ItemReference, PreloadedObject {
try {
final String id = UtilityMethods.enumName(key);
final ItemStat<?> stat = MMOItems.plugin.getStats().get(id);
Validate.notNull(stat, FriendlyFeedbackProvider.quickForConsole(FFPMMOItems.get(), "Could not find stat with ID '$i{0}$b'", id));
// Check for a block with alternative syntax
boolean alternativeSyntax = MMOItems.plugin.getStats().checkAlternateYAMLSyntax(MMOItemTemplate.this, key, config::get);
if (alternativeSyntax) continue;
// [BACKWARDS COMPATIBILITY] Check for a block with alternative syntax
if (stat == null) {
boolean alternativeSyntax = MMOItems.plugin.getStats().checkAlternateYAMLSyntax(MMOItemTemplate.this, key, config.get("base." + key));
if (alternativeSyntax) continue;
throw new RuntimeException(String.format("Could not find stat with ID '%s'", id));
}
// Don't load anything
if (stat.getComponentType() instanceof VoidComponentType) continue;
// Load a model
Model<?> model = stat.getComponentType().fromConfig(config.get("base." + key));
@ -91,6 +98,8 @@ public class MMOItemTemplate implements ItemReference, PreloadedObject {
// Log
ffp.log(FriendlyFeedbackCategory.INFORMATION, "Could not load base item data '$f{0}$b': {1}", key, exception.getMessage());
MMOItems.plugin.getLogger().log(Level.INFO, "Could not load base item data '" + key + "'");
exception.printStackTrace();
}
// Print all failures

View File

@ -18,7 +18,7 @@ import net.Indyuce.mmoitems.api.event.PlayerUseCraftingStationEvent;
import net.Indyuce.mmoitems.api.item.util.ConfigItems;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.comp.eco.MoneyCondition;
import net.Indyuce.mmoitems.listener.CustomSoundListener;
import net.Indyuce.mmoitems.stat.SoundStat;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
@ -201,7 +201,7 @@ public class CraftingStationView extends PluginInventory {
recipe.whenClaimed().forEach(trigger -> trigger.whenCrafting(playerData));
// Play sounds
CustomSoundListener.playSound(result, CustomSound.ON_CRAFT, player);
SoundStat.playSound(result, CustomSound.ON_CRAFT, player);
if (!recipe.hasOption(Recipe.RecipeOption.SILENT_CRAFT))
player.playSound(player.getLocation(), station.getSound(), 1, 1);

View File

@ -1,109 +0,0 @@
package net.Indyuce.mmoitems.listener;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.api.util.SoundReader;
import io.lumine.mythic.lib.api.item.NBTItem;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class CustomSoundListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void a(EntityDamageByEntityEvent event) {
if (!(event.getDamager() instanceof Player) || !(event.getEntity() instanceof LivingEntity)) return;
Player player = (Player) event.getDamager();
playSound(player.getInventory().getItemInMainHand(), CustomSound.ON_ATTACK, player);
}
@EventHandler(priority = EventPriority.HIGH)
public void b(EntityPickupItemEvent event) {
if (event.getEntityType().equals(EntityType.PLAYER))
playSound(event.getItem().getItemStack(), CustomSound.ON_PICKUP, (Player) event.getEntity());
}
@EventHandler(priority = EventPriority.HIGH)
public void c(BlockBreakEvent event) {
playSound(event.getPlayer().getInventory().getItemInMainHand(), CustomSound.ON_BLOCK_BREAK, event.getPlayer());
}
@EventHandler
public void d(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL || !event.hasItem()) return;
if (event.getAction().name().contains("RIGHT_CLICK"))
playSound(event.getItem(), CustomSound.ON_RIGHT_CLICK, event.getPlayer());
if (event.getAction().name().contains("LEFT_CLICK"))
playSound(event.getItem(), CustomSound.ON_LEFT_CLICK, event.getPlayer());
}
@EventHandler(priority = EventPriority.HIGH)
public void e(CraftItemEvent event) {
playSound(event.getInventory().getResult(), CustomSound.ON_CRAFT, event.getWhoClicked().getLocation());
}
@EventHandler(priority = EventPriority.HIGH)
public void f(FurnaceSmeltEvent event) {
playSound(event.getResult(), CustomSound.ON_CRAFT, event.getBlock().getLocation());
}
@EventHandler(priority = EventPriority.HIGH)
public void g(PlayerItemConsumeEvent event) {
playSound(event.getItem(), CustomSound.ON_CONSUME, event.getPlayer());
}
@EventHandler(priority = EventPriority.HIGH)
public void h1(PlayerItemBreakEvent event) {
playSound(event.getBrokenItem(), CustomSound.ON_ITEM_BREAK, event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void i(BlockPlaceEvent event) {
playSound(event.getItemInHand(), CustomSound.ON_PLACED, event.getPlayer());
}
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Player player) {
playSound(item, type, player.getLocation(), null);
}
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Player player, @Nullable Sound defaultSound) {
playSound(item, type, player.getLocation(), defaultSound);
}
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Location loc) {
playSound(item, type, loc, null);
}
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Location loc, @Nullable Sound defaultSound) {
if (item == null) return;
final NBTItem nbt = NBTItem.get(item);
final String soundName = nbt.getString("MMOITEMS_SOUND_" + type.name());
if (soundName == null || soundName.isEmpty()) {
if (defaultSound != null) loc.getWorld().playSound(loc, defaultSound, 1, 1);
return;
}
final SoundReader sound = new SoundReader(soundName, defaultSound);
sound.play(loc, (float) nbt.getDouble("MMOITEMS_SOUND_" + type.name() + "_VOL"), (float) nbt.getDouble("MMOITEMS_SOUND_" + type.name() + "_PIT"));
}
}

View File

@ -8,9 +8,12 @@ import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.StatCategories;
import net.Indyuce.mmoitems.api.ConfigFile;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
import net.Indyuce.mmoitems.api.item.template.MMOItemTemplate;
import net.Indyuce.mmoitems.stat.ElementalStat;
import net.Indyuce.mmoitems.stat.SoundStat;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.behaviour.ItemRestriction;
@ -33,6 +36,7 @@ import java.lang.reflect.Modifier;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.logging.Level;
public class StatManager {
@ -73,6 +77,7 @@ public class StatManager {
// Load builtin stats
forEachField(ItemStats.class, ItemStat.class, this::register, "Couldn't register stat called '%s': %s");
loadElementalStats(); // Needed on startup otherwise templates cant use them
loadSoundStats();
// Custom stats
loadCustomStats();
@ -104,6 +109,11 @@ public class StatManager {
register(new ElementalStat(element, type));
}
private void loadSoundStats() {
for (CustomSound sound : CustomSound.values())
register(new SoundStat(sound));
}
public void reload(boolean cleanFirst) {
// Unregister stats that require it
@ -153,10 +163,10 @@ public class StatManager {
@BackwardsCompatibility(version = "6.10.1")
public boolean checkAlternateYAMLSyntax(@NotNull MMOItemTemplate template,
@NotNull String configKey,
@NotNull Function<String, Object> supplier) {
@NotNull Object syntaxBlock) {
final SyntaxAdapter adapter = yamlSyntaxAdapters.get(UtilityMethods.enumName(configKey).toLowerCase()); // Snake case
final boolean result = adapter != null;
if (result) adapter.adapt(template, supplier.apply(configKey));
if (result) adapter.adapt(template, syntaxBlock);
return result;
}

View File

@ -12,9 +12,7 @@ import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.component.model.builtin.NumberModel;
import net.Indyuce.mmoitems.stat.component.model.builtin.ObjectModel;
import net.Indyuce.mmoitems.stat.component.type.ComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.ArrayComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.ObjectComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.StringComponentType;
import net.Indyuce.mmoitems.stat.component.type.builtin.*;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
@ -29,18 +27,25 @@ public class Abilities extends ItemStat<ArrayComponent<AbilityComponent>> {
public Abilities() {
super("ABILITY", new String[]{"!block", "all"});
ComponentType<?, ?> modifierMapType = ObjectComponentType.init()
.build();
ComponentType<?, ?> abilityType = ObjectComponentType.init()
.implementation(AbilityComponent::new)
.addField("ability", StringComponentType.skillHandler()
.addField("Id", "type", StringComponentType.skillHandler()
.icon(Material.FIRE_CHARGE)
.name("Ability").build())
.addField("mode", StringComponentType.triggerType()
.addField("CastMode", "mode", StringComponentType.triggerType()
.icon(Material.COMMAND_BLOCK_MINECART)
.name("Trigger").build())
.addField("modifiers", modifierMapType)
.addField("Modifiers", MapComponentType.mapOf(NumberComponentType.decimal().build())
.validateKeys(str -> !str.equals("mode") && !str.equals("type")) // Backwards compatibility
.name("Ability Modifiers")
.icon(Material.BLAZE_POWDER)
.trimdesc("Edit cooldown, mana usage, damage dealt, duration... or any other numerical parameter of your skill.")
.flattened(true)
.build())
.icon(Material.FIRE_CHARGE)
.name(obj -> {
// UI render name of ability
@ -70,7 +75,6 @@ public class Abilities extends ItemStat<ArrayComponent<AbilityComponent>> {
return lore;
})
//.setFlattened(true)
.build();
// TODO ui display rules
@ -81,8 +85,6 @@ public class Abilities extends ItemStat<ArrayComponent<AbilityComponent>> {
.name("Abilities")
.trimdesc("Make your item cast amazing abilities to kill monsters or buff yourself. Abilities can be actively cast, set on a timer or triggered by specific world events. Custom abilities can be created using MythicLib, MythicMobs, Fabled...")
.build());
// TODO config syntax adapter needed for the modifier part.
}
private String generalFormat, modifierIfAny, modifierForEach, modifierSplitter, abilitySplitter, modifierNewLine;

View File

@ -38,7 +38,7 @@ public class ArrowPotionEffects extends ItemStat<ArrayComponent<ObjectComponent>
.addField("duration", NumberComponentType.decimal()
.icon(Material.CLOCK)
.name("Effect Duration").build())
.stringSeparatedStringFormat(" ")
.stringSeparatedStringFormat(" ", false)
.icon(Material.TIPPED_ARROW)
.name("Potion Effect")
.build();

View File

@ -4,8 +4,8 @@ import net.Indyuce.mmoitems.ItemStats;
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.component.model.builtin.NumberModel;
import net.Indyuce.mmoitems.stat.type.IntegerStat;
import net.Indyuce.mmoitems.stat.type.extra.TemplateOption;
import org.bukkit.Material;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -16,13 +16,15 @@ import java.util.HashMap;
import java.util.Map;
@HasCategory(cat = "template_option")
public class BrowserDisplayIDX extends IntegerStat implements TemplateOption {
public class BrowserDisplayIDX extends IntegerStat {
public BrowserDisplayIDX() {
super("BROWSER_IDX",
Material.GHAST_TEAR,
"Browser Index",
"Used to display similar items together, neatly in the GUI &a/mmoitems browse. &7Items with the same index are grouped.",
null);
setTemplateOption(true);
}
/**
@ -41,7 +43,7 @@ public class BrowserDisplayIDX extends IntegerStat implements TemplateOption {
Double armorIDX = null;
if (template.getType().getAvailableStats().contains(ItemStats.BROWSER_DISPLAY_IDX)) {
NumericStatFormula indexData = (NumericStatFormula) template.getModels().get(ItemStats.BROWSER_DISPLAY_IDX);
NumericStatFormula indexData = ((NumberModel) template.getModels().get(ItemStats.BROWSER_DISPLAY_IDX)).getFormula();
// Get value if it existed
if (indexData != null && indexData.getBase() != 0) { armorIDX = indexData.getBase(); }

View File

@ -16,7 +16,6 @@ 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.extra.TemplateOption;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
@ -26,7 +25,7 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@HasCategory(cat = "misc")
public class Crafting extends ItemStat<VoidComponent> implements TemplateOption {
public class Crafting extends ItemStat<VoidComponent> {
public Crafting() {
super("CRAFTING", null);
@ -35,6 +34,8 @@ public class Crafting extends ItemStat<VoidComponent> implements TemplateOption
.name("Crafting Recipes")
.trimdesc("The crafting recipes of your item. Changing a recipe requires &o/mi reload recipes&7.")
.build());
setTemplateOption(true);
}
@Override
@ -45,7 +46,7 @@ public class Crafting extends ItemStat<VoidComponent> implements TemplateOption
@Nullable
@Override
public VoidComponent read(ReadMMOItem mmoitem) {
throw new RuntimeException("Not supported");
return null;
}
@Deprecated

View File

@ -2,16 +2,14 @@ package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.type.StringStat;
import net.Indyuce.mmoitems.stat.type.extra.TemplateOption;
import org.bukkit.Material;
@HasCategory(cat = "template_option")
public class CraftingPermission extends StringStat implements TemplateOption {
public class CraftingPermission extends StringStat {
public CraftingPermission() {
super("CRAFT_PERMISSION", Material.OAK_SIGN, "Crafting Recipe Permission",
"The permission needed to craft this item. Changing this value requires &o/mi reload recipes&7.",
null);
super("CRAFT_PERMISSION", Material.OAK_SIGN, "Crafting Recipe Permission", "The permission needed to craft this item. Changing this value requires &o/mi reload recipes&7.", null);
setGemstoneTransferable(false);
setTemplateOption(true);
}
}

View File

@ -40,7 +40,7 @@ public class Effects extends ItemStat<ArrayComponent<ObjectComponent>> implement
public static ComponentType<?, ?> potionEffectComponentType() {
return ObjectComponentType.init()
.implementation(PotionEffectComponent::new)
.stringSeparatedStringFormat(" ")
.stringSeparatedStringFormat(" ", false)
.addField("Type", StringComponentType.potionEffectType()
.icon(Material.POTION)
.name("Potion Effect Type")

View File

@ -1,6 +1,7 @@
package net.Indyuce.mmoitems.stat;
import io.lumine.mythic.lib.element.Element;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
@ -11,15 +12,29 @@ import net.Indyuce.mmoitems.stat.yaml.SyntaxAdapter;
import net.Indyuce.mmoitems.util.ElementStatType;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
@HasCategory(cat = "elements")
public class ElementalStat extends DoubleStat {
private final Element element;
private final ElementStatType statType;
public ElementalStat(Element element, ElementStatType statType) {
super(statType.getConcatenatedTagPath(element), new String[]{"equipment", "ornament", "gem_stone"});
super(statType.getConcatenatedTagPath(element),
element.getIcon(),
String.format("%s %s", element.getName(), statType.getName()),
"Elemental stat.",
new String[]{"equipment", "ornament", "gem_stone"});
this.element = element;
this.statType = statType;
setRemoveOnReload(true);
registerAlternateYAMLSyntax(ALTERNATE_SYNTAX);
}
@BackwardsCompatibility(version = "7.0")
public static final SyntaxAdapter ALTERNATE_SYNTAX = new SyntaxAdapter("element", (template, obj) -> {
Validate.isTrue(obj instanceof ConfigurationSection, "Not a configuration section");
@ -38,184 +53,24 @@ public class ElementalStat extends DoubleStat {
}
});
/*
public static void updateComponentType() {
ItemStat<?> stat = MMOItems.plugin.getStats().get("ELEMENT");
ObjectComponentType.Builder builder = ObjectComponentType.object();
for (Element element : MythicLib.plugin.getElements().getAll())
for (ElementStatType statType : ElementStatType.values())
builder.addField(statType.getConcatenatedTagPath(element).toLowerCase(), DoubleComponentType.numeric()
.setIcon(element.getIcon())
.setName(element.getName() + " " + statType.getName())
.build());
stat.setComponentType(builder
.acceptTreedConfigPaths(true)
//.setKey("ELEMENT")
.setIcon(Material.MAGMA_CREAM)
.setName("Elemental Stats")
.trimLore("Have the weapon deal on-hit elemental damage, reduce or increase incoming elemental damage.")
.setActionLoreTags("Click to edit elemental stats.", "Right click to reset elements")
.build());
}
@Override
public RandomElementListData whenInitialized(Object object) {
Validate.isTrue(object instanceof ConfigurationSection, "Must specify a config section");
return new RandomElementListData((ConfigurationSection) object);
}
@Deprecated
public void whenDisplayed(List<String> lore, Optional<RandomElementListData> statData) {
if (statData.isPresent()) {
lore.add(ChatColor.GRAY + "Current Value:");
RandomElementListData data = statData.get();
data.getKeys().forEach(key -> lore.add(ChatColor.GRAY + "* " + key.getKey().getName() + " " + key.getValue().getName() + ": " + ChatColor.RED + data.getStat(key.getKey(), key.getValue())));
} else
lore.add(ChatColor.GRAY + "Current Value: " + ChatColor.RED + "None");
lore.add("");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Click to access the elements edition menu.");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to remove all the elements.");
}
@NotNull
@Override
public ElementListData getClearStatData() {
return new ElementListData();
}
private Map<ElementStatType, String> statFormat = new HashMap<>();
@Override
@BackwardsCompatibility(version = "unspecified")
public void readTranslationFile(@NotNull ConfigurationSection translationFile) {
String ifError = String.format("<TranslationNotFound:%s_%s>", element.getId(), statType.lowerCaseName());
// Up-to-date code
Object configObject = translationFile.get("element");
if (configObject instanceof ConfigurationSection) {
final ConfigurationSection config = (ConfigurationSection) configObject;
for (ElementStatType statType : ElementStatType.values())
statFormat.put(statType, config.getString(statType.lowerCaseName(), "<TranslationNotFound:" + statType.lowerCaseName() + ">"));
parseAndSetGeneralStatFormat(((ConfigurationSection) configObject).getString(statType.lowerCaseName(), ifError));
}
// LEGACY CODE
else {
for (ElementStatType statType : ElementStatType.values())
statFormat.put(statType, translationFile.getString("elemental-" + statType.lowerCaseName(), "<TranslationNotFound:" + statType.name().toLowerCase() + ">"));
parseAndSetGeneralStatFormat(translationFile.getString("elemental-" + statType.lowerCaseName(), ifError));
}
}
@NotNull
private String formatForLore(Element element, ElementStatType statType) {
return statFormat.get(statType)
.replace("{color}", element.getColor())
.replace("{icon}", element.getLoreIcon())
.replace("{element}", element.getName());
private void parseAndSetGeneralStatFormat(@NotNull String format) {
generalStatFormat = format.replace("{color}", element.getColor()).replace("{icon}", element.getLoreIcon()).replace("{element}", element.getName());
}
@Override
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull ElementListData data) {
List<String> lore = new ArrayList<>();
// Write Lore
for (Pair<Element, ElementStatType> pair : data.getKeys()) {
final String format = formatForLore(pair.getKey(), pair.getValue());
final double value = data.getStat(pair.getKey(), pair.getValue());
lore.add(DoubleStat.formatPath("ELEMENTAL_STAT", format, true, value));
}
// Insert non-empty lore
if (!lore.isEmpty())
item.getLore().insert("elements", lore);
// Addtags
item.addItemTag(getAppliedNBT(data));
}
@NotNull
@Override
public ArrayList<ItemTag> getAppliedNBT(@NotNull ElementListData data) {
// Create Array
ArrayList<ItemTag> ret = new ArrayList<>();
for (Pair<Element, ElementStatType> pair : data.getKeys())
ret.add(new ItemTag("MMOITEMS_" + pair.getValue().getConcatenatedTagPath(pair.getKey()), data.getStat(pair.getKey(), pair.getValue())));
// Thats it
return ret;
}
@Override
public void whenLoaded(@NotNull ReadMMOItem mmoitem) {
// Seek the relevant tags
ArrayList<ItemTag> relevantTags = new ArrayList<>();
for (Element element : Element.values())
for (ElementStatType statType : ElementStatType.values()) {
final String path = "MMOITEMS_" + statType.getConcatenatedTagPath(element);
if (mmoitem.getNBT().hasTag(path))
relevantTags.add(ItemTag.getTagAtPath(path, mmoitem.getNBT(), SupportedNBTTagValues.DOUBLE));
}
// Generate Data
StatData data = getLoadedNBT(relevantTags);
// Found?
if (data != null) {
mmoitem.setData(this, data);
}
}
@Nullable
@Override
public ElementListData getLoadedNBT(@NotNull ArrayList<ItemTag> storedTags) {
// Create new
ElementListData elements = new ElementListData();
// Try to find every existing element
for (Element element : Element.values())
for (ElementStatType statType : ElementStatType.values()) {
final String path = "MMOITEMS_" + statType.getConcatenatedTagPath(element);
ItemTag tag = ItemTag.getTagAtPath(path, storedTags);
if (tag != null)
elements.setStat(element, statType, (double) tag.getValue());
}
return elements.isEmpty() ? null : elements;
}
@Override
public void whenPreviewed(@NotNull ItemStackBuilder item, @NotNull ElementListData currentData, @NotNull RandomElementListData templateData) throws IllegalArgumentException {
Validate.isTrue(currentData instanceof ElementListData, "Current Data is not ElementListData");
Validate.isTrue(templateData instanceof RandomElementListData, "Template Data is not RandomElementListData");
List<String> elementLore = new ArrayList<>();
// Examine every element stat possible
for (Element element : Element.values())
for (ElementStatType statType : ElementStatType.values()) {
NumericStatFormula nsf = templateData.getStat(element, statType);
// Get Value
final double techMinimum = nsf.calculate(0, NumericStatFormula.FormulaInputType.LOWER_BOUND);
final double techMaximum = nsf.calculate(0, NumericStatFormula.FormulaInputType.UPPER_BOUND);
// Display if not ZERO
if (techMinimum != 0 || techMaximum != 0) {
final String builtRange = DoubleStat.formatPath(statType.getConcatenatedTagPath(element), formatForLore(element, statType), true, techMinimum, techMaximum);
elementLore.add(builtRange);
}
}
if (!elementLore.isEmpty()) item.getLore().insert("elements", elementLore);
// Add tags
item.addItemTag(getAppliedNBT(currentData));
}
*/
}

View File

@ -34,10 +34,14 @@ public class GemSockets extends ItemStat<GemstonesComponent> {
public GemSockets() {
super("GEM_SOCKETS", new String[]{"!gem_stone", "equipment", "ornament"});
// No description needed, the UI directly skips the "gemsockets/gemstones" level.
setComponentType(ObjectComponentType.init()
// No description needed, the UI directly skips the object level.
.addField("EmptySlots", ArrayComponentType.arrayOf(StringComponentType.init().build()).build())
.addField("EmptySlots", ArrayComponentType.arrayOf(StringComponentType.init().build())
.icon(Material.EMERALD)
.name("Gem Sockets")
.trimdesc("The amount of gem sockets naturally present on your item.")
.build())
// Gemstones (internal) part
.addField("Gemstones", ArrayComponentType.arrayOf(ObjectComponentType.init()
@ -47,9 +51,6 @@ public class GemSockets extends ItemStat<GemstonesComponent> {
.build())
.implementation(GemstonesComponent::new)
.icon(Material.EMERALD)
.name("Gem Sockets")
.trimdesc("The amount of gem sockets naturally present on your item.")
.build());
}
@ -88,9 +89,10 @@ public class GemSockets extends ItemStat<GemstonesComponent> {
// Find upgrade level
int itemLevel = builder.getMMOItem().hasUpgradeTemplate() ? builder.getMMOItem().getUpgradeLevel() : 0;
// Applied gemstones
List<String> lore = new ArrayList<>();
if (component.getGemstones() != null) for (GemstoneComponent gem : component.getGemstones()) {
// Applied gemstones
for (GemstoneComponent gem : component.getGemstones()) {
String gemName = gem.getName();
// Upgrades?

View File

@ -8,7 +8,6 @@ import net.Indyuce.mmoitems.api.interaction.Consumable;
import net.Indyuce.mmoitems.api.interaction.util.DurabilityItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.listener.CustomSoundListener;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.behaviour.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.type.DoubleStat;
@ -67,7 +66,7 @@ public class RepairPower extends DoubleStat implements ConsumableItemInteraction
Message.REPAIRED_ITEM
.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(target.getItem()), "#amount#", String.valueOf(repairPower))
.send(player);
CustomSoundListener.playSound(consumable.getItem(), CustomSound.ON_CONSUME, player);
SoundStat.playSound(consumable.getItem(), CustomSound.ON_CONSUME, player);
return true;
}

View File

@ -51,6 +51,7 @@ public class ShieldPatternStat extends ItemStat<ShieldStyleComponent> {
.icon(Material.SHIELD)
.name("Layers")
.trimdesc("Edit pattern layers here")
.flattened(true)
.build())
.icon(Material.SHIELD)

View File

@ -1,215 +1,132 @@
package net.Indyuce.mmoitems.stat;
import net.Indyuce.mmoitems.stat.type.StringStat;
import io.lumine.mythic.lib.api.item.ItemTag;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.api.item.build.ItemStackBuilder;
import net.Indyuce.mmoitems.api.item.mmoitem.ReadMMOItem;
import net.Indyuce.mmoitems.api.util.SoundReader;
import net.Indyuce.mmoitems.stat.annotation.HasCategory;
import net.Indyuce.mmoitems.stat.component.builtin.DoubleComponent;
import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponent;
import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponentImpl;
import net.Indyuce.mmoitems.stat.component.builtin.StringComponent;
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.type.ItemStat;
import net.Indyuce.mmoitems.stat.yaml.SyntaxAdapter;
import org.apache.commons.lang.Validate;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Sound;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class SoundStat extends StringStat {
public SoundStat(String id, String[] types) {
super("SOUND", null);
import java.util.logging.Level;
/**
* The only not directly mapped stat.
*/
@HasCategory(cat = "sounds")
public class SoundStat extends ItemStat<ObjectComponent> {
private final String pathSound, pathVolume, pathPitch;
public SoundStat(CustomSound sound) {
super(String.format("MMOITEMS_SOUND_%s", sound.name()), null);
pathSound = getNBTPath();
pathVolume = getNBTPath() + "_VOL";
pathPitch = getNBTPath() + "_PIT";
setComponentType(ObjectComponentType.init()
.addField("Sound", StringComponentType.init().build())
.addField("Volume", NumberComponentType.decimal().build())
.addField("Pitch", NumberComponentType.decimal().build())
.stringSeparatedStringFormat(" ", false)
.icon(Material.NOTE_BLOCK)
.name(String.format("%s Sound", sound.getName()))
.inputable(true)
.trimdesc(sound.getLore())
.build());
setDisplayInLore(false);
registerAlternateYAMLSyntax(LEGACY_SYNTAX);
}
/*
@HasCategory(cat = "misc")
public class CustomSounds extends ItemStat<SoundListData, SoundListData> implements GemStoneStat, PlayerConsumable {
public CustomSounds() {
super("SOUNDS", Material.JUKEBOX, "Custom Sounds", new String[]{"The custom sounds your item will use."},
new String[0]);
}
@Override
public SoundListData whenInitialized(Object object) {
Validate.isTrue(object instanceof ConfigurationSection, "Must specify a config section");
private static final SyntaxAdapter LEGACY_SYNTAX = new SyntaxAdapter("sounds", (template, object) -> {
MMOItems.plugin.getLogger().log(Level.INFO, "got: " + object.toString());
Validate.isTrue(object instanceof ConfigurationSection, "Expecting a config section");
ConfigurationSection config = (ConfigurationSection) object;
SoundListData sounds = new SoundListData();
for (CustomSound sound : CustomSound.values()) {
String path = sound.name().replace("_", "-").toLowerCase();
if (config.contains(path))
sounds.set(sound, new SoundData(config.get(path)));
Object configObject = config.get(path);
if (configObject == null) continue;
String statId = String.format("MMOITEMS_SOUND_%s", sound.name());
ItemStat<ObjectComponent> soundStat = (ItemStat<ObjectComponent>) MMOItems.plugin.getStats().get(statId);
Validate.notNull(soundStat, String.format("Could not find sound stat with ID '%s'", statId));
template.getModels().put(soundStat, soundStat.getComponentType().fromConfig(configObject));
}
});
@Nullable
@Override
@BackwardsCompatibility(version = "7.0")
public ObjectComponent read(ReadMMOItem mmoitem) {
String found = mmoitem.getNBT().getString(pathSound);
if (found != null && !found.isEmpty()) {
ObjectComponent comp = new ObjectComponentImpl();
comp.set("Sound", new StringComponent(found));
comp.set("Volume", new DoubleComponent(mmoitem.getNBT().getDouble(pathVolume)));
comp.set("Pitch", new DoubleComponent(mmoitem.getNBT().getDouble(pathPitch)));
return comp;
}
return sounds;
}
@Deprecated
public void whenInput(@NotNull EditionInventory inv, @NotNull String message, Object... info) {
String soundsPath = (String) info[0];
String[] split = message.split(" ");
Validate.isTrue(split.length == 3, message + " is not a valid [SOUND NAME] [VOLUME] [PITCH].");
String soundName = split[0].replace("-", "_");
double volume = MMOUtils.parseDouble(split[1]);
double pitch = MMOUtils.parseDouble(split[2]);
inv.getEditedSection().set("sounds." + soundsPath + ".sound", soundName);
inv.getEditedSection().set("sounds." + soundsPath + ".volume", volume);
inv.getEditedSection().set("sounds." + soundsPath + ".pitch", pitch);
inv.registerTemplateEdition();
inv.getPlayer().sendMessage(MMOItems.plugin.getPrefix() + ChatColor.RED + UtilityMethods.caseOnWords(soundsPath.replace(".", " ")) + ChatColor.GRAY
+ " successfully changed to '" + soundName + "'.");
}
public void whenDisplayed(List<String> lore, Optional<SoundListData> statData) {
if (statData.isPresent()) {
lore.add(ChatColor.GRAY + "Current Value:");
SoundListData data = (SoundListData) statData.get();
data.mapData()
.forEach((sound,
soundData) -> lore.add(ChatColor.GRAY + "* " + ChatColor.GREEN
+ UtilityMethods.caseOnWords(sound.getName().toLowerCase().replace("-", " ").replace("_", " ")) + ChatColor.GRAY + ": "
+ ChatColor.RED + soundData.getVolume() + " " + soundData.getPitch()));
} else
lore.add(ChatColor.GRAY + "Current Value: " + ChatColor.RED + "None");
lore.add("");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Click to access the sounds edition menu.");
lore.add(ChatColor.YELLOW + AltChar.listDash + " Right click to remove all custom sounds.");
return readJsonFromNbt(mmoitem);
}
@Override
public @NotNull SoundListData getClearStatData() {
return new SoundListData();
@BackwardsCompatibility(version = "7.0")
public void write(ItemStackBuilder builder, @NotNull ObjectComponent component) {
builder.addItemTag(new ItemTag(pathSound, component.get("Sound")));
builder.addItemTag(new ItemTag(pathVolume, component.get("Volume")));
builder.addItemTag(new ItemTag(pathPitch, component.get("Pitch")));
}
@Override
public void whenApplied(@NotNull ItemStackBuilder item, @NotNull SoundListData data) {
item.addItemTag(getAppliedNBT(data));
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Player player) {
playSound(item, type, player.getLocation(), null);
}
@Override
public @NotNull ArrayList<ItemTag> getAppliedNBT(@NotNull SoundListData data) {
// Make Array
ArrayList<ItemTag> ret = new ArrayList<>();
// Well that
SoundListData sounds = (SoundListData) data;
// Add
sounds.getCustomSounds().forEach(sound -> {
SoundData value = sounds.get(sound);
ret.add(new ItemTag("MMOITEMS_SOUND_" + sound.name(), value.getSound()));
ret.add(new ItemTag("MMOITEMS_SOUND_" + sound.name() + "_VOL", value.getVolume()));
ret.add(new ItemTag("MMOITEMS_SOUND_" + sound.name() + "_PIT", value.getPitch()));
});
// Yes
return ret;
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Player player, @Nullable Sound defaultSound) {
playSound(item, type, player.getLocation(), defaultSound);
}
public @Nullable SoundListData getLoadedNBT(@NotNull ArrayList<ItemTag> data) {
// Something to build
SoundListData sounds = new SoundListData();
// For each value
for (CustomSound sound : CustomSound.values()) {
// Find tag?
ItemTag soundTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name(), data);
ItemTag volumeTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name() + "_VOL", data);
ItemTag pitchTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name() + "_PIT", data);
// Not null righ
if (soundTag != null && volumeTag != null && pitchTag != null) {
// Get as String
String soundName = (String) soundTag.getValue();
Double volume = (Double) volumeTag.getValue();
Double pitch = (Double) pitchTag.getValue();
// If valid
if (!soundName.isEmpty()) {
// Set
sounds.set(sound, new SoundData(soundName, volume, pitch));
}
}
}
// Return that amount
if (sounds.getCustomSounds().size() > 0) {
// Yes
return sounds;
}
// Failure: No sounds
return null;
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Location loc) {
playSound(item, type, loc, null);
}
@Override
public void whenLoaded(@NotNull ReadMMOItem mmoitem) {
public static void playSound(@Nullable ItemStack item, @NotNull CustomSound type, @NotNull Location loc, @Nullable Sound defaultSound) {
if (item == null) return;
// Get tags
ArrayList<ItemTag> relevantTags = new ArrayList<>();
for (CustomSound sound : CustomSound.values()) {
// Find tag?
ItemTag soundTag = null;
ItemTag volumeTag = null;
ItemTag pitchTag = null;
if (mmoitem.getNBT().hasTag("MMOITEMS_SOUND_" + sound.name()))
soundTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name(), mmoitem.getNBT(), SupportedNBTTagValues.STRING);
if (mmoitem.getNBT().hasTag("MMOITEMS_SOUND_" + sound.name() + "_VOL"))
volumeTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name() + "_VOL", mmoitem.getNBT(), SupportedNBTTagValues.DOUBLE);
if (mmoitem.getNBT().hasTag("MMOITEMS_SOUND_" + sound.name() + "_PIT"))
pitchTag = ItemTag.getTagAtPath("MMOITEMS_SOUND_" + sound.name() + "_PIT", mmoitem.getNBT(), SupportedNBTTagValues.DOUBLE);
// All or none
if (soundTag != null && volumeTag != null && pitchTag != null) {
// Include
relevantTags.add(soundTag);
relevantTags.add(volumeTag);
relevantTags.add(pitchTag);
}
}
// Use that
SoundListData sounds = (SoundListData) getLoadedNBT(relevantTags);
// Valid?
if (sounds != null) {
// Set
mmoitem.setData(ItemStats.CUSTOM_SOUNDS, sounds);
}
}
@Override
public void onConsume(@NotNull VolatileMMOItem mmo, @NotNull Player player, boolean vanillaEating) {
// No sound, straight up default-yo
if (!mmo.hasData(ItemStats.CUSTOM_SOUNDS)) {
playDefaultSound(player);
final NBTItem nbt = NBTItem.get(item);
final String soundName = nbt.getString("MMOITEMS_SOUND_" + type.name());
if (soundName == null || soundName.isEmpty()) {
if (defaultSound != null) loc.getWorld().playSound(loc, defaultSound, 1, 1);
return;
}
// Find data
SoundListData slData = (SoundListData) mmo.getData(ItemStats.CUSTOM_SOUNDS);
SoundData cs = slData.get(CustomSound.ON_CONSUME);
// Default sound :sleep:
if (cs == null) playDefaultSound(player);
// Play custom sound lets go
else {
String fixedSoundName = cs.getSound().toLowerCase().replace("_", ".");
player.getWorld().playSound(player.getLocation(), fixedSoundName, (float) cs.getVolume(), (float) cs.getPitch());
}
final SoundReader sound = new SoundReader(soundName, defaultSound);
sound.play(loc, (float) nbt.getDouble("MMOITEMS_SOUND_" + type.name() + "_VOL"), (float) nbt.getDouble("MMOITEMS_SOUND_" + type.name() + "_PIT"));
}
void playDefaultSound(@NotNull Player player) {
player.getWorld().playSound(player.getLocation(), Sound.ENTITY_GENERIC_EAT, 1, 1);
}
*/
}

View File

@ -49,6 +49,8 @@ public abstract class ComponentType<M extends Model<C>, C extends StatComponent>
*/
private boolean internal;
private boolean flattened;
private boolean inputable;
private Function<M, ItemStack> icon;
@ -85,6 +87,10 @@ public abstract class ComponentType<M extends Model<C>, C extends StatComponent>
return internal;
}
public boolean isFlattened() {
return flattened;
}
/*
public void flatten(@NotNull List<Pair<ComponentType<?>, StatComponent>> list, @Nullable S statComponent) {
Validate.isTrue(terminal, "Basic impl for terminal components");
@ -198,6 +204,11 @@ public abstract class ComponentType<M extends Model<C>, C extends StatComponent>
return this;
}
public Builder flattened(boolean flattened) {
ComponentType.this.flattened = flattened;
return this;
}
public Builder inputable(boolean inputable) {
ComponentType.this.inputable = inputable;
return this;

View File

@ -14,6 +14,7 @@ import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Predicate;
import java.util.function.Supplier;
/**
@ -30,6 +31,8 @@ public class MapComponentType<C extends StatComponent> extends ComponentType<Map
*/
private ComponentType<?, C> subtype;
private Predicate<String> keyValidator;
private MergeMethod mergeMethod = MergeMethod.MERGE_EACH;
@NotNull
@ -53,8 +56,13 @@ public class MapComponentType<C extends StatComponent> extends ComponentType<Map
MapModel<C> model = new MapModel<>();
ConfigurationSection config = (ConfigurationSection) object;
for (String key : config.getKeys(false))
for (String key : config.getKeys(false)) {
// Validate key
if (keyValidator != null && !keyValidator.test(key)) continue;
model.getModels().put(key, subtype.fromConfig(config.get(key)));
}
return model;
}
@ -158,6 +166,11 @@ public class MapComponentType<C extends StatComponent> extends ComponentType<Map
return this;
}
public Builder validateKeys(Predicate<String> keyValidator) {
MapComponentType.this.keyValidator = keyValidator;
return this;
}
public Builder implementation(@NotNull Supplier<? extends MapComponent<C>> componentInstanciator) {
Validate.notNull(componentInstanciator, "Component instanciator cannot be null");

View File

@ -2,41 +2,41 @@ package net.Indyuce.mmoitems.stat.component.type.builtin;
import io.lumine.mythic.lib.gson.JsonElement;
import io.lumine.mythic.lib.gson.JsonObject;
import io.lumine.mythic.lib.util.annotation.BackwardsCompatibility;
import net.Indyuce.mmoitems.api.item.build.MMOItemBuilder;
import net.Indyuce.mmoitems.stat.component.LoreWrapper;
import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponent;
import net.Indyuce.mmoitems.stat.component.builtin.ObjectComponentImpl;
import net.Indyuce.mmoitems.stat.component.builtin.composite.ColorComponent;
import net.Indyuce.mmoitems.stat.component.model.Model;
import net.Indyuce.mmoitems.stat.component.model.builtin.ObjectModel;
import net.Indyuce.mmoitems.stat.component.type.ComponentType;
import net.Indyuce.mmoitems.stat.yaml.SyntaxAdapter;
import net.Indyuce.mmoitems.util.Pair;
import org.apache.commons.lang.Validate;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.*;
import java.util.function.Supplier;
public class ObjectComponentType extends ComponentType<ObjectModel, ObjectComponent> {
private final Map<String, ComponentType<?, ?>> fields = new LinkedHashMap<>();
private final Map<String, String> legacyConfigKeys = new HashMap<>();
@NotNull
private Supplier<ObjectComponent> componentInstanciator = ObjectComponentImpl::new;
//private Supplier<ObjectModel> modelInstanciator = ObjectModel::new;
private String stringFormatSeparatorPattern;
private boolean strictSeparatedStringFormat;
@Nullable
private String uniqueSerializable;
private MergeMethod mergeMethod = MergeMethod.MERGE_EACH;
/**
* There are some stats
*
* @see SyntaxAdapter
*/
private boolean syntacticShortcut;
/*
@Override
@SuppressWarnings({"unchecked", "rawtypes"})
@ -81,7 +81,7 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
// Load input from a string, if allowed
if (stringFormatSeparatorPattern != null) {
String[] split = playerInput.split(stringFormatSeparatorPattern, fields.size());
//Validate.isTrue(split.length == fields.size(), "Invalid number of parameters");
Validate.isTrue(split.length == fields.size(), "Invalid number of parameters");
int counter = 0;
Map<String, Object> ser = new HashMap<>();
@ -100,16 +100,29 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
@Override
public ObjectModel fromConfig(@NotNull Object object) {
// If there's only one subfield that is not internal, should be edited/loaded from config.
// Example: gemstones/gemsockets
if (uniqueSerializable != null) {
ObjectModel model = new ObjectModel();
Model<?> submodel = getChildType(uniqueSerializable).fromConfig(object);
model.getModels().put(uniqueSerializable, submodel);
return model;
}
// Load object from a string, if allowed
if (stringFormatSeparatorPattern != null && object instanceof String) {
String format = object.toString();
String[] split = format.split(stringFormatSeparatorPattern);
Validate.isTrue(split.length == fields.size(), "Invalid number of parameters");
if (strictSeparatedStringFormat)
Validate.isTrue(split.length == fields.size(), "Invalid number of parameters");
ObjectModel comp = new ObjectModel();
int counter = 0;
for (Map.Entry<String, ComponentType<?, ?>> entry : fields.entrySet()) {
if (counter >= split.length) break;
String sub = split[counter++];
comp.getModels().put(entry.getKey(), entry.getValue().fromConfig(sub));
}
@ -124,12 +137,25 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
ObjectModel comp = new ObjectModel();
for (Map.Entry<String, ComponentType<?, ?>> entry : fields.entrySet()) {
// Flattened sub-components
if (entry.getValue().isFlattened()) {
comp.getModels().put(entry.getKey(), entry.getValue().fromConfig(section));
continue;
}
// This snake-case-format is experimentally much better (and required) for backwards compatibility
String configPath = entry.getKey().replace("_", "-").toLowerCase();
Object sub = section.get(configPath);
String legacyConfigPath;
// [BACKWARDS COMPATIBILITY] Support older config syntax without the need to use a config adapter.
if (sub == null && (legacyConfigPath = legacyConfigKeys.get(entry.getKey())) != null)
sub = section.get(legacyConfigPath);
// Null components are well handled in MMOItems
if (sub == null) continue;
// TODO object validation
comp.getModels().put(entry.getKey(), entry.getValue().fromConfig(sub));
}
@ -222,7 +248,7 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
.addField("Red", NumberComponentType.integer().icon(Material.RED_WOOL).name("Red").build())
.addField("Green", NumberComponentType.integer().icon(Material.GREEN_WOOL).name("Green").build())
.addField("Blue", NumberComponentType.integer().icon(Material.BLUE_WOOL).name("Blue").build())
.stringSeparatedStringFormat(" ");
.stringSeparatedStringFormat(" ", true);
}
@NotNull
@ -263,22 +289,46 @@ public class ObjectComponentType extends ComponentType<ObjectModel, ObjectCompon
return this;
}
@BackwardsCompatibility(version = "7.0")
public Builder addField(String key, @NotNull String legacyConfigKey, ComponentType<?, ?> componentType) {
ObjectComponentType.this.legacyConfigKeys.put(key, legacyConfigKey);
return addField(key, componentType);
}
public Builder addField(String key, ComponentType<?, ?> componentType) {
fields.put(key, componentType);
return this;
}
public Builder stringSeparatedStringFormat(String separatorPattern) {
public Builder stringSeparatedStringFormat(String separatorPattern, boolean strict) {
Validate.notNull(separatorPattern, "Separator cannot be null");
strictSeparatedStringFormat = strict;
stringFormatSeparatorPattern = separatorPattern;
return this;
}
@NotNull
public ObjectComponentType build() {
// TODO rules
ObjectComponentType.this.uniqueSerializable = uniqueSerializable();
return (ObjectComponentType) super.build();
}
}
@Nullable
private String uniqueSerializable() {
String unique = null;
for (Map.Entry<String, ComponentType<?, ?>> entry : fields.entrySet())
// Serializable = non-internal OR flattened
if (!entry.getValue().isInternal() || entry.getValue().isFlattened()) {
if (unique != null) return null;
else unique = entry.getKey();
}
return unique;
}
//endregion
}

View File

@ -157,7 +157,6 @@ public class StringComponentType extends ComponentType<StringModel, StringCompon
return new StringComponentType().new Builder().adaptor(input -> {
input = UtilityMethods.enumName(input);
valueSupplier.apply(input); // Ignore result, just trigger an error if necessary
Particle.valueOf(input);
return input;
}).valueIndicator(valuesSupplier);
}

View File

@ -28,8 +28,6 @@ public class IntegerStat extends ItemStat<IntegerComponent> implements Previewab
.icon(mat)
.trimdesc(lore)
.build());
setMergeable(true);
}
@Nullable

View File

@ -49,6 +49,8 @@ public abstract class ItemStat<C extends StatComponent> {
* However, that does not mean they have no corresponding JSON formatting.
* MMOItems still needs to keep the history of these stats. No NBT cache tag
* is formed, but stat history still keeps track of it.
* <p>
* TODO replace by a StatHistory policy that makes sense.
*/
private boolean itemMetaSaved = true;
@ -57,8 +59,6 @@ public abstract class ItemStat<C extends StatComponent> {
*/
private boolean templateOption;
private boolean mergeable;
private boolean gemstoneTransferable = true;
private boolean removeOnReload;
@ -136,12 +136,12 @@ public abstract class ItemStat<C extends StatComponent> {
this.displayInLore = displayInLore;
}
public boolean isMergeable() {
return mergeable;
public boolean isTemplateOption() {
return templateOption;
}
public void setMergeable(boolean mergeable) {
this.mergeable = mergeable;
public void setTemplateOption(boolean templateOption) {
this.templateOption = templateOption;
}
public boolean isRemovedOnReload() {
@ -182,6 +182,7 @@ public abstract class ItemStat<C extends StatComponent> {
this.legacyLanguagePath = legacyLanguagePath;
}
@NotNull
public ComponentType getComponentType() {
return componentType;
}
@ -213,24 +214,24 @@ public abstract class ItemStat<C extends StatComponent> {
/**
* Directly writes data to a live generated MMOItem. This is used both when
* TODO finish description after understanding when this is even used
* <p>
* TODO check all implementations and maybe create a function #isEmpty() for components first for readability?
*
* @param builder Item being built
* @param component Component to be applied onto the item
*/
public abstract void write(ItemStackBuilder builder, @NotNull C component);
// TODO allow to load from a nbttag directly to allow for better complexity when loading an entire item.
/**
* Not used in every stat
* TODO remove it from useless classes
* TODO honestly it's ok
* Used by most primitive type-based stats, including all numerical,
* boolean and string item stats. Composite types like array- or
* object-based types don't use it, but it's so efficient it's okay.
*/
protected String generalStatFormat;
@NotNull
public String getGeneralStatFormat() {
return generalStatFormat;
}
public void readTranslationFile(@NotNull ConfigurationSection translationFile) {
String path = getPath();
Object obj = translationFile.get(path);
@ -238,10 +239,6 @@ public abstract class ItemStat<C extends StatComponent> {
generalStatFormat = obj == null ? "<TranslationNotFound:" + path + ">" : String.valueOf(obj);
}
public String getGeneralStatFormat() {
return generalStatFormat;
}
@Nullable
public StatCategory getCategory() {
return category;

View File

@ -1,14 +0,0 @@
package net.Indyuce.mmoitems.stat.type.extra;
/**
* Some stats are just options related to the template and not the item
* directly. Such stats are called item options since they do not provide
* anything to the holder, and do not store any data inside the item NBT.
* <p>
* 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

@ -6,7 +6,7 @@ import net.Indyuce.mmoitems.api.event.item.RepairItemEvent;
import net.Indyuce.mmoitems.api.interaction.Consumable;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.listener.CustomSoundListener;
import net.Indyuce.mmoitems.stat.SoundStat;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
@ -56,7 +56,7 @@ public class RepairUtils {
"#item#", MMOUtils.getDisplayName(target.getItem()),
"#amount#", String.valueOf(repairAmount))
.send(player);
CustomSoundListener.playSound(consumable.getItem(), CustomSound.ON_CONSUME, player);
SoundStat.playSound(consumable.getItem(), CustomSound.ON_CONSUME, player);
return true;
}
}

View File

@ -0,0 +1,77 @@
package net.Indyuce.mmoitems.listener;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.stat.SoundStat;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityPickupItemEvent;
import org.bukkit.event.inventory.CraftItemEvent;
import org.bukkit.event.inventory.FurnaceSmeltEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerItemBreakEvent;
import org.bukkit.event.player.PlayerItemConsumeEvent;
public class CustomSoundListener implements Listener {
@EventHandler(priority = EventPriority.HIGH)
public void a(EntityDamageByEntityEvent event) {
if (!(event.getDamager() instanceof Player) || !(event.getEntity() instanceof LivingEntity)) return;
Player player = (Player) event.getDamager();
SoundStat.playSound(player.getInventory().getItemInMainHand(), CustomSound.ON_ATTACK, player);
}
@EventHandler(priority = EventPriority.HIGH)
public void b(EntityPickupItemEvent event) {
if (event.getEntityType().equals(EntityType.PLAYER))
SoundStat.playSound(event.getItem().getItemStack(), CustomSound.ON_PICKUP, (Player) event.getEntity());
}
@EventHandler(priority = EventPriority.HIGH)
public void c(BlockBreakEvent event) {
SoundStat.playSound(event.getPlayer().getInventory().getItemInMainHand(), CustomSound.ON_BLOCK_BREAK, event.getPlayer());
}
@EventHandler
public void d(PlayerInteractEvent event) {
if (event.getAction() == Action.PHYSICAL || !event.hasItem()) return;
if (event.getAction().name().contains("RIGHT_CLICK"))
SoundStat.playSound(event.getItem(), CustomSound.ON_RIGHT_CLICK, event.getPlayer());
if (event.getAction().name().contains("LEFT_CLICK"))
SoundStat.playSound(event.getItem(), CustomSound.ON_LEFT_CLICK, event.getPlayer());
}
@EventHandler(priority = EventPriority.HIGH)
public void e(CraftItemEvent event) {
SoundStat.playSound(event.getInventory().getResult(), CustomSound.ON_CRAFT, event.getWhoClicked().getLocation());
}
@EventHandler(priority = EventPriority.HIGH)
public void f(FurnaceSmeltEvent event) {
SoundStat.playSound(event.getResult(), CustomSound.ON_CRAFT, event.getBlock().getLocation());
}
@EventHandler(priority = EventPriority.HIGH)
public void g(PlayerItemConsumeEvent event) {
SoundStat.playSound(event.getItem(), CustomSound.ON_CONSUME, event.getPlayer());
}
@EventHandler(priority = EventPriority.HIGH)
public void h1(PlayerItemBreakEvent event) {
SoundStat.playSound(event.getBrokenItem(), CustomSound.ON_ITEM_BREAK, event.getPlayer());
}
@EventHandler(priority = EventPriority.MONITOR)
public void i(BlockPlaceEvent event) {
SoundStat.playSound(event.getItemInHand(), CustomSound.ON_PLACED, event.getPlayer());
}
}