Custom item types commit 1

This commit is contained in:
Jules 2024-01-26 12:26:59 +01:00
parent 5117c77229
commit bb1eeed501
47 changed files with 603 additions and 895 deletions

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>MMOItems</artifactId>
<groupId>net.Indyuce</groupId>
<version>6.9.5-SNAPSHOT</version>
<version>6.10-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>

View File

@ -154,7 +154,7 @@ public class ItemStats {
CUSTOM_SOUNDS = new CustomSounds(),
ELEMENTS = new Elements(),
COMMANDS = new Commands(),
STAFF_SPIRIT = new StaffSpiritStat(),
// STAFF_SPIRIT = new StaffSpiritStat(),
LUTE_ATTACK_SOUND = new LuteAttackSoundStat(),
LUTE_ATTACK_EFFECT = new LuteAttackEffectStat(),
NOTE_WEIGHT = new DoubleStat("NOTE_WEIGHT", VersionMaterial.MUSIC_DISC_MALL.toMaterial(), "Note Weight", new String[]{"Defines how the projectile cast", "by your lute tilts downwards."}, new String[]{"lute"}),

View File

@ -120,7 +120,7 @@ public class MMOItems extends JavaPlugin {
configManager = new ConfigManager();
statManager.load();
typeManager.reload();
typeManager.reload(false);
templateManager.preloadObjects();
PluginUtils.isDependencyPresent("MMOCore", u -> new MMOCoreMMOLoader());
@ -141,6 +141,8 @@ public class MMOItems extends JavaPlugin {
MMOItemUIFilter.register();
RecipeTypeListGUI.registerNativeRecipes();
typeManager.postload();
skillManager.initialize(false);
final int configVersion = getConfig().contains("config-version", true) ? getConfig().getInt("config-version") : -1;
@ -410,10 +412,10 @@ public class MMOItems extends JavaPlugin {
*
* @param value The player inventory subclass
* @deprecated Rather than setting this to the only inventory MMOItems will
* search equipment within, you must add your inventory to the
* handler with <code>getInventory().register()</code>. This method
* will clear all other PlayerInventories for now, as to keep
* backwards compatibility.
* search equipment within, you must add your inventory to the
* handler with <code>getInventory().register()</code>. This method
* will clear all other PlayerInventories for now, as to keep
* backwards compatibility.
*/
@Deprecated
public void setPlayerInventory(PlayerInventory value) {
@ -490,7 +492,7 @@ public class MMOItems extends JavaPlugin {
return templateManager;
}
public LoreFormatManager getLore(){
public LoreFormatManager getLore() {
return loreManager;
}
@ -527,9 +529,9 @@ public class MMOItems extends JavaPlugin {
/**
* @return Generates an item given an item template. The item level will
* scale according to the player RPG level if the template has the
* 'level-item' option. The item will pick a random tier if the
* template has the 'tiered' option
* scale according to the player RPG level if the template has the
* 'level-item' option. The item will pick a random tier if the
* template has the 'tiered' option
*/
@Nullable
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id, @Nullable PlayerData player) {
@ -547,9 +549,9 @@ public class MMOItems extends JavaPlugin {
/**
* @return Generates an item given an item template. The item level will
* scale according to the player RPG level if the template has the
* 'level-item' option. The item will pick a random tier if the
* template has the 'tiered' option
* scale according to the player RPG level if the template has the
* 'level-item' option. The item will pick a random tier if the
* template has the 'tiered' option
*/
@Nullable
public ItemStack getItem(@Nullable Type type, @Nullable String id, @NotNull PlayerData player) {
@ -566,7 +568,7 @@ public class MMOItems extends JavaPlugin {
* @param itemLevel The desired item level
* @param itemTier The desired item tier, can be null
* @return Generates an item given an item template with a
* specific item level and item tier
* specific item level and item tier
*/
@Nullable
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id, int itemLevel, @Nullable ItemTier itemTier) {
@ -586,7 +588,7 @@ public class MMOItems extends JavaPlugin {
* @param itemLevel The desired item level
* @param itemTier The desired item tier, can be null
* @return Generates an item given an item template with a
* specific item level and item tier
* specific item level and item tier
*/
@Nullable
public ItemStack getItem(@Nullable Type type, @Nullable String id, int itemLevel, @Nullable ItemTier itemTier) {
@ -601,10 +603,10 @@ public class MMOItems extends JavaPlugin {
/**
* @return Generates an item given an item template. The item level will be
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
*/
@Nullable
public MMOItem getMMOItem(@Nullable Type type, @Nullable String id) {
@ -613,10 +615,10 @@ public class MMOItems extends JavaPlugin {
/**
* @return Generates an item given an item template. The item level will be
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
*/
@Nullable
@ -629,10 +631,10 @@ public class MMOItems extends JavaPlugin {
/**
* @return Generates an item given an item template. The item level will be
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
* 0 and the item will have no item tier unless one is specified in
* the base item data.
* <p></p>
* Will return <code>null</code> if such MMOItem does not exist.
*/
@Nullable
public ItemStack getItem(@Nullable Type type, @Nullable String id) {

View File

@ -3,12 +3,17 @@ package net.Indyuce.mmoitems.api;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.player.cooldown.CooldownObject;
import io.lumine.mythic.lib.player.modifier.ModifierSource;
import io.lumine.mythic.lib.skill.SimpleSkill;
import io.lumine.mythic.lib.skill.Skill;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.item.util.identify.UnidentifiedItem;
import net.Indyuce.mmoitems.manager.TypeManager;
import net.Indyuce.mmoitems.stat.type.ItemStat;
import org.apache.commons.lang.Validate;
import org.apache.maven.model.ConfigurationContainer;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.inventory.ItemStack;
@ -20,47 +25,46 @@ import java.util.List;
import java.util.Objects;
@SuppressWarnings("unused")
public class Type {
public class Type implements CooldownObject {
// Slashing
public static final Type SWORD = new Type(TypeSet.SLASHING, "SWORD", true, ModifierSource.MELEE_WEAPON);
public static final Type SWORD = new Type("SWORD", true, ModifierSource.MELEE_WEAPON);
// Piercing
public static final Type DAGGER = new Type(TypeSet.PIERCING, "DAGGER", true, ModifierSource.MELEE_WEAPON);
public static final Type SPEAR = new Type(TypeSet.PIERCING, "SPEAR", true, ModifierSource.MELEE_WEAPON);
public static final Type DAGGER = new Type("DAGGER", true, ModifierSource.MELEE_WEAPON);
public static final Type SPEAR = new Type("SPEAR", true, ModifierSource.MELEE_WEAPON);
// Blunt
public static final Type HAMMER = new Type(TypeSet.BLUNT, "HAMMER", true, ModifierSource.MELEE_WEAPON);
public static final Type GAUNTLET = new Type(TypeSet.BLUNT, "GAUNTLET", true, ModifierSource.MELEE_WEAPON);
public static final Type HAMMER = new Type("HAMMER", true, ModifierSource.MELEE_WEAPON);
public static final Type GAUNTLET = new Type("GAUNTLET", true, ModifierSource.MELEE_WEAPON);
// Range
public static final Type WHIP = new Type(TypeSet.RANGE, "WHIP", true, ModifierSource.RANGED_WEAPON);
public static final Type STAFF = new Type(TypeSet.RANGE, "STAFF", true, ModifierSource.RANGED_WEAPON);
public static final Type BOW = new Type(TypeSet.RANGE, "BOW", true, ModifierSource.RANGED_WEAPON);
public static final Type CROSSBOW = new Type(TypeSet.RANGE, "CROSSBOW", false, ModifierSource.RANGED_WEAPON);
public static final Type MUSKET = new Type(TypeSet.RANGE, "MUSKET", true, ModifierSource.RANGED_WEAPON);
public static final Type LUTE = new Type(TypeSet.RANGE, "LUTE", true, ModifierSource.RANGED_WEAPON);
public static final Type WHIP = new Type("WHIP", true, ModifierSource.RANGED_WEAPON);
public static final Type STAFF = new Type("STAFF", true, ModifierSource.RANGED_WEAPON);
public static final Type BOW = new Type("BOW", true, ModifierSource.RANGED_WEAPON);
public static final Type CROSSBOW = new Type("CROSSBOW", false, ModifierSource.RANGED_WEAPON);
public static final Type MUSKET = new Type("MUSKET", true, ModifierSource.RANGED_WEAPON);
public static final Type LUTE = new Type("LUTE", true, ModifierSource.RANGED_WEAPON);
// Hand Accessories
public static final Type CATALYST = new Type(TypeSet.CATALYST, "CATALYST", false, ModifierSource.HAND_ITEM);
public static final Type OFF_CATALYST = new Type(TypeSet.CATALYST, "OFF_CATALYST", false, ModifierSource.OFFHAND_ITEM);
public static final Type MAIN_CATALYST = new Type(TypeSet.CATALYST, "MAIN_CATALYST", false, ModifierSource.MAINHAND_ITEM);
public static final Type CATALYST = new Type("CATALYST", false, ModifierSource.HAND_ITEM);
public static final Type OFF_CATALYST = new Type("OFF_CATALYST", false, ModifierSource.OFFHAND_ITEM);
public static final Type MAIN_CATALYST = new Type("MAIN_CATALYST", false, ModifierSource.MAINHAND_ITEM);
// Any
public static final Type ORNAMENT = new Type(TypeSet.EXTRA, "ORNAMENT", false, ModifierSource.VOID);
public static final Type ORNAMENT = new Type("ORNAMENT", false, ModifierSource.VOID);
// Extra
public static final Type ARMOR = new Type(TypeSet.EXTRA, "ARMOR", false, ModifierSource.ARMOR);
public static final Type TOOL = new Type(TypeSet.EXTRA, "TOOL", false, ModifierSource.MELEE_WEAPON);
public static final Type CONSUMABLE = new Type(TypeSet.EXTRA, "CONSUMABLE", false, ModifierSource.MAINHAND_ITEM);
public static final Type MISCELLANEOUS = new Type(TypeSet.EXTRA, "MISCELLANEOUS", false, ModifierSource.MAINHAND_ITEM);
public static final Type GEM_STONE = new Type(TypeSet.EXTRA, "GEM_STONE", false, ModifierSource.VOID);
public static final Type SKIN = new Type(TypeSet.EXTRA, "SKIN", false, ModifierSource.VOID);
public static final Type ACCESSORY = new Type(TypeSet.EXTRA, "ACCESSORY", false, ModifierSource.ACCESSORY);
public static final Type BLOCK = new Type(TypeSet.EXTRA, "BLOCK", false, ModifierSource.VOID);
public static final Type ARMOR = new Type("ARMOR", false, ModifierSource.ARMOR);
public static final Type TOOL = new Type("TOOL", false, ModifierSource.MELEE_WEAPON);
public static final Type CONSUMABLE = new Type("CONSUMABLE", false, ModifierSource.MAINHAND_ITEM);
public static final Type MISCELLANEOUS = new Type("MISCELLANEOUS", false, ModifierSource.MAINHAND_ITEM);
public static final Type GEM_STONE = new Type("GEM_STONE", false, ModifierSource.VOID);
public static final Type SKIN = new Type("SKIN", false, ModifierSource.VOID);
public static final Type ACCESSORY = new Type("ACCESSORY", false, ModifierSource.ACCESSORY);
public static final Type BLOCK = new Type("BLOCK", false, ModifierSource.VOID);
private final String id;
private final TypeSet set;
private final ModifierSource modifierSource;
private final boolean weapon;
@ -69,6 +73,9 @@ public class Type {
@Nullable
private String loreFormat;
@NotNull
private String attackCooldownKey;
/**
* Used to display the item in the item explorer and in the item recipes
* list in the advanced workbench. can also be edited using the config
@ -77,13 +84,19 @@ public class Type {
private ItemStack item;
/**
* Any type can have a subtype which basically dictates what the item type
* does.
* The parent item type determines:
* - the item options compatible with this new item type
* - if this item type is a weapon or not
* - the lore format
*/
private Type parent;
private UnidentifiedItem unidentifiedTemplate;
private Skill onLeftClick, onRightClick, onAttack, onEntityInteract;
private boolean meleeAttacks;
/**
* List of stats which can be applied onto an item which has this type. This
* improves performance when generating an item by a significant amount.
@ -92,11 +105,10 @@ public class Type {
@Deprecated
public Type(TypeSet set, String id, boolean weapon, ModifierSource modSource, boolean fourGUIMode) {
this(set, id, weapon, modSource);
this(id, weapon, modSource);
}
public Type(TypeSet set, String id, boolean weapon, ModifierSource modSource) {
this.set = set;
public Type(String id, boolean weapon, ModifierSource modSource) {
this.id = id.toUpperCase().replace("-", "_").replace(" ", "_");
this.modifierSource = modSource;
this.weapon = weapon;
@ -108,7 +120,6 @@ public class Type {
parent = manager.get(config.getString("parent", "").toUpperCase().replace("-", "_").replace(" ", "_"));
set = (parent != null ? parent.set : TypeSet.EXTRA);
weapon = (parent != null && parent.weapon);
modifierSource = (parent != null ? parent.modifierSource : ModifierSource.OTHER);
this.loreFormat = config.getString("LoreFormat", (parent != null ? parent.loreFormat : null));
@ -123,7 +134,18 @@ public class Type {
(unidentifiedTemplate = new UnidentifiedItem(this)).update(config.getConfigurationSection("unident-item"));
// Getting overridden?
loreFormat = config.getString("LoreFormat", (parent != null ? parent.loreFormat : loreFormat));
loreFormat = config.getString("LoreFormat", parent != null ? parent.loreFormat : null);
attackCooldownKey = config.getString("attack-cooldown-key", "default");
meleeAttacks = !config.getBoolean("cancel-melee-attacks");
}
public void postload(ConfigurationSection config) {
onLeftClick = config.contains("on-left-click") ? new SimpleSkill(TriggerType.CAST, MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-left-click"))) : null;
onRightClick = config.contains("on-right-click") ? new SimpleSkill(MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-right-click"))) : null;
onAttack = config.contains("on-attack") ? new SimpleSkill(MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-attack"))) : null;
onEntityInteract = config.contains("on-entity-interact") ? new SimpleSkill(MythicLib.plugin.getSkills().loadSkillHandler(config.get("on-entity-interact"))) : null;
}
/**
@ -144,18 +166,19 @@ public class Type {
return id;
}
public TypeSet getItemSet() {
return set;
}
public boolean isWeapon() {
return weapon;
}
public boolean hasMeleeAttacks() {
return meleeAttacks;
}
public String getName() {
return name;
}
@NotNull
public ModifierSource getModifierSource() {
return modifierSource;
}
@ -164,6 +187,31 @@ public class Type {
return item.clone();
}
@Nullable
public Skill onLeftClick() {
return onLeftClick;
}
@Override
public String getCooldownPath() {
return "mmoitems_weapons:" + attackCooldownKey;
}
@Nullable
public Skill onRightClick() {
return onRightClick;
}
@Nullable
public Skill onAttack() {
return onAttack;
}
@Nullable
public Skill onEntityInteract() {
return onEntityInteract;
}
/**
* @deprecated Use {@link #getSupertype()}
*/
@ -213,11 +261,6 @@ public class Type {
return getSupertype().equals(type);
}
@Deprecated
public boolean corresponds(TypeSet set) {
return getSupertype().getItemSet() == set;
}
/**
* @return The collection of all stats which can be applied onto this
* specific item type. This list is cached when types are being

View File

@ -1,35 +1,23 @@
package net.Indyuce.mmoitems.api;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.AttackMetadata;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import org.jetbrains.annotations.NotNull;
import java.util.Random;
@Deprecated
public enum TypeSet {
/**
* Slashing weapons deal damage in a cone behind the player's initial
* target, which makes it a deadly AoE weapon for warriors
*/
@Deprecated
SLASHING((attack, attacker, attackerData, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.slashing.enabled")
/*if (!MMOItems.plugin.getConfig().getBoolean("item-ability.slashing.enabled")
|| attackerData.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
@ -46,7 +34,7 @@ public enum TypeSet {
&& attacker.getPlayer().getEyeLocation().getDirection()
.angle(entity.getLocation().subtract(attacker.getPlayer().getLocation()).toVector()) < Math.PI / 3
&& UtilityMethods.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION) && !entity.equals(target))
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .4, DamageType.WEAPON, DamageType.PHYSICAL);
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .4, DamageType.WEAPON, DamageType.PHYSICAL);*/
}),
/**
@ -55,8 +43,9 @@ public enum TypeSet {
* increased which makes it a perfect 'double or nothing' weapon for
* assassins
*/
@Deprecated
PIERCING((attack, attacker, attackerData, target, weapon) -> {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.piercing.enabled")
/* if (!MMOItems.plugin.getConfig().getBoolean("item-ability.piercing.enabled")
|| attackerData.isOnCooldown(CooldownType.SET_TYPE_ATTACK))
return;
@ -73,15 +62,16 @@ public enum TypeSet {
&& attacker.getPlayer().getEyeLocation().getDirection()
.angle(entity.getLocation().toVector().subtract(attacker.getPlayer().getLocation().toVector())) < Math.PI / 12
&& UtilityMethods.canTarget(attacker.getPlayer(), entity, InteractionType.OFFENSE_ACTION))
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .6, DamageType.WEAPON, DamageType.PHYSICAL);
attacker.attack((LivingEntity) entity, attack.getDamage().getDamage() * .6, DamageType.WEAPON, DamageType.PHYSICAL);*/
}),
/**
* Blunt weapons are like 1.9 sweep attacks. They damage
* all enemies nearby and apply a slight knockback
*/
@Deprecated
BLUNT((attack, attacker, attackerData, target, weapon) -> {
final Random random = new Random();
/* final Random random = new Random();
float pitchRange = 0.7f + random.nextFloat() * (0.9f - 0.7f);
final double bluntPower;
@ -113,7 +103,7 @@ public enum TypeSet {
Location loc = target.getLocation();
loc.setYaw((float) (loc.getYaw() + 2 * (random.nextDouble() - .5) * 90));
loc.setPitch((float) (loc.getPitch() + 2 * (random.nextDouble() - .5) * 30));
}
}*/
}),
/**
@ -121,17 +111,20 @@ public enum TypeSet {
* the middle of the battle-field, these weapons allow him to take some
* distance and still deal some good damage
*/
@Deprecated
RANGE,
/**
* Hand/Mainhand/Offhand catalysts
*/
@Deprecated
CATALYST,
/**
* Any other item type, like armor, consumables, etc. They all have their
* very specific passive depending on their item type
*/
@Deprecated
EXTRA;
private final SetAttackHandler attackHandler;

View File

@ -1,14 +1,14 @@
package net.Indyuce.mmoitems.api.event.item;
import net.Indyuce.mmoitems.api.event.PlayerDataEvent;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import org.bukkit.event.Cancellable;
import org.bukkit.event.HandlerList;
import org.jetbrains.annotations.NotNull;
public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancellable {
private final UntargetedWeapon weapon;
private final Weapon weapon;
private boolean cancelled;
@ -20,7 +20,7 @@ public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancell
* @param who Player attacking
* @param weapon Weapon being used
*/
public UntargetedWeaponUseEvent(@NotNull PlayerData who, @NotNull UntargetedWeapon weapon) {
public UntargetedWeaponUseEvent(@NotNull PlayerData who, @NotNull Weapon weapon) {
super(who);
this.weapon = weapon;
@ -30,7 +30,7 @@ public class UntargetedWeaponUseEvent extends PlayerDataEvent implements Cancell
* @return The weapon used by the player that fired this event
*/
@NotNull
public UntargetedWeapon getWeapon() {
public Weapon getWeapon() {
return weapon;
}

View File

@ -11,6 +11,7 @@ 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.type.ConsumableItemInteraction;
import net.Indyuce.mmoitems.stat.type.PlayerConsumable;
import org.bukkit.Bukkit;
@ -22,10 +23,16 @@ import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
public class Consumable extends UseItem {
@Deprecated
public Consumable(Player player, NBTItem item) {
super(player, item);
}
public Consumable(PlayerData player, NBTItem item) {
super(player, item);
}
@Override
public boolean checkItemRequirements() {
return MythicLib.plugin.getFlags().isFlagAllowed(player, CustomFlag.MI_CONSUMABLES) && playerData.getRPG().canUse(getNBTItem(), true);

View File

@ -6,6 +6,7 @@ import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.event.item.ApplyGemStoneEvent;
import net.Indyuce.mmoitems.api.item.mmoitem.LiveMMOItem;
import net.Indyuce.mmoitems.api.item.mmoitem.MMOItem;
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;
@ -28,11 +29,15 @@ import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public class GemStone extends UseItem {
@Deprecated
public GemStone(Player player, NBTItem item) {
super(player, item);
}
public GemStone(PlayerData player, NBTItem item) {
super(player, item);
}
@NotNull
public ApplyResult applyOntoItem(@NotNull NBTItem target, @NotNull Type targetType) {
@ -60,7 +65,7 @@ public class GemStone extends UseItem {
// Checks if the gem supports the item type, or the item set, or a weapon
String appliableTypes = getNBTItem().getString(ItemStats.ITEM_TYPE_RESTRICTION.getNBTPath());
if (!appliableTypes.equals("") && (!targetType.isWeapon() || !appliableTypes.contains("WEAPON"))
&& !appliableTypes.contains(targetType.getItemSet().name()) && !appliableTypes.contains(targetType.getId()))
&& !appliableTypes.contains(targetType.getId()))
return new ApplyResult(ResultType.NONE);
// Check for success rate

View File

@ -7,6 +7,7 @@ import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
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.data.SkullTextureData;
import net.Indyuce.mmoitems.stat.data.StringListData;
@ -19,16 +20,20 @@ import org.bukkit.inventory.meta.Damageable;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.inventory.meta.LeatherArmorMeta;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.List;
public class ItemSkin extends UseItem {
@Deprecated
public ItemSkin(Player player, NBTItem item) {
super(player, item);
}
public ItemSkin(PlayerData player, NBTItem item) {
super(player, item);
}
public ApplyResult applyOntoItem(NBTItem target, Type targetType) {
if (targetType == Type.SKIN)
return new ApplyResult(ResultType.NONE);
@ -42,9 +47,9 @@ public class ItemSkin extends UseItem {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Applying onto " + MMOUtils.getDisplayName(target.getItem()));
// Types compatibility check
if (getMMOItem().hasData(ItemStats.COMPATIBLE_TYPES)) {
if (mmoitem.hasData(ItemStats.COMPATIBLE_TYPES)) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that TYPE is compatible: ");
final List<String> acceptedTypes = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_TYPES)).getList();
final List<String> acceptedTypes = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_TYPES)).getList();
if (acceptedTypes.size() > 0 && acceptedTypes.stream().noneMatch(s -> s.equalsIgnoreCase(targetType.getId()))) {
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_INCOMPATIBLE.format(ChatColor.RED, "#item#", MMOUtils.getDisplayName(target.getItem()))
@ -54,9 +59,9 @@ public class ItemSkin extends UseItem {
}
// IDs compatibility check
if (getMMOItem().hasData(ItemStats.COMPATIBLE_IDS)) {
if (mmoitem.hasData(ItemStats.COMPATIBLE_IDS)) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that ID is compatible: ");
final List<String> acceptedIDs = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_IDS)).getList();
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()
@ -69,9 +74,9 @@ public class ItemSkin extends UseItem {
}
// Material compatibility check
if (getMMOItem().hasData(ItemStats.COMPATIBLE_MATERIALS)) {
if (mmoitem.hasData(ItemStats.COMPATIBLE_MATERIALS)) {
//SKIN//MMOItems.log("\u00a78SKIN \u00a7eCPT\u00a77 Testing that MATERIAL is compatible: ");
List<String> acceptedMaterials = ((StringListData) getMMOItem().getData(ItemStats.COMPATIBLE_MATERIALS)).getList();
List<String> acceptedMaterials = ((StringListData) mmoitem.getData(ItemStats.COMPATIBLE_MATERIALS)).getList();
if (acceptedMaterials.size() > 0 && acceptedMaterials.stream()
.noneMatch(s -> s.equalsIgnoreCase(target.getItem().getType().name()))) {
@ -93,7 +98,7 @@ public class ItemSkin extends UseItem {
}
// Apply skin
ItemStack item = applySkin(target, getMMOItem());
ItemStack item = applySkin(target, mmoitem);
player.playSound(player.getLocation(), Sound.ENTITY_PLAYER_LEVELUP, 1, 2);
Message.SKIN_APPLIED.format(ChatColor.YELLOW, "#item#", MMOUtils.getDisplayName(target.getItem())).send(player);

View File

@ -6,9 +6,10 @@ import io.lumine.mythic.lib.comp.flags.CustomFlag;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.*;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Crossbow;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Lute;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Musket;
import net.Indyuce.mmoitems.api.item.mmoitem.VolatileMMOItem;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.stat.data.CommandData;
@ -27,11 +28,12 @@ public class UseItem {
protected static final Random RANDOM = new Random();
public UseItem(Player player, NBTItem nbtItem) {
@Deprecated
public UseItem(@NotNull Player player, @NotNull NBTItem nbtItem) {
this(PlayerData.get(player), nbtItem);
}
public UseItem(PlayerData playerData, NBTItem nbtItem) {
public UseItem(@NotNull PlayerData playerData, @NotNull NBTItem nbtItem) {
this.player = playerData.getPlayer();
this.playerData = playerData;
this.mmoitem = new VolatileMMOItem(nbtItem);
@ -85,11 +87,9 @@ public class UseItem {
private void scheduleCommandExecution(CommandData command) {
String parsed = MythicLib.plugin.getPlaceholderParser().parse(player, command.getCommand());
if (!command.hasDelay())
dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms());
if (!command.hasDelay()) dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms());
else
Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms()),
(long) command.getDelay() * 20);
Bukkit.getScheduler().runTaskLater(MMOItems.plugin, () -> dispatchCommand(parsed, command.isConsoleCommand(), command.hasOpPerms()), (long) command.getDelay() * 20);
}
/**
@ -116,8 +116,7 @@ public class UseItem {
} finally {
player.setOp(false);
}
} else
Bukkit.dispatchCommand(player, parsed);
} else Bukkit.dispatchCommand(player, parsed);
}
public static UseItem getItem(Player player, NBTItem item, String type) {
@ -125,24 +124,14 @@ public class UseItem {
}
public static UseItem getItem(@NotNull Player player, @NotNull NBTItem item, @NotNull Type type) {
if (type.corresponds(Type.CONSUMABLE))
return new Consumable(player, item);
if (type.corresponds(Type.SKIN))
return new ItemSkin(player, item);
if (type.corresponds(Type.GEM_STONE))
return new GemStone(player, item);
if (type.corresponds(Type.MUSKET))
return new Musket(player, item);
if (type.corresponds(Type.CROSSBOW))
return new Crossbow(player, item);
if (type.corresponds(Type.GAUNTLET))
return new Gauntlet(player, item);
if (type.corresponds(Type.WHIP))
return new Whip(player, item);
if (type.corresponds(Type.LUTE))
return new Lute(player, item);
if (type.corresponds(Type.STAFF))
return new Staff(player, item);
return type.isWeapon() ? new Weapon(player, item) : new UseItem(player, item);
final PlayerData playerData = PlayerData.get(player);
if (type.corresponds(Type.CONSUMABLE)) return new Consumable(playerData, item);
if (type.corresponds(Type.SKIN)) return new ItemSkin(playerData, item);
if (type.corresponds(Type.GEM_STONE)) return new GemStone(playerData, item);
if (type.corresponds(Type.MUSKET)) return new Musket(playerData, item);
if (type.corresponds(Type.CROSSBOW)) return new Crossbow(playerData, item);
if (type.corresponds(Type.LUTE)) return new Lute(playerData, item);
return type.isWeapon() ? new Weapon(playerData, item) : new UseItem(playerData, item);
}
}

View File

@ -0,0 +1,35 @@
package net.Indyuce.mmoitems.api.interaction;
public enum WeaponAttackResult {
/**
* Attack was performed successfully
*/
SUCCESS,
/**
* Attakc was not performed due to missing resource (mana or stamina)
* or ongoing cooldown.
*/
WEAPON_COSTS,
/**
* Attack was canceled because the item is broken
*/
DURABILITY,
/**
* Attack was canceled due to a precondition of the executed skill
*/
SKILL_SPECIFIC,
/**
* Attack was canceled due to an event
*/
BUKKIT_EVENT,
/**
* No attack effect was detected on the item.
*/
NO_ATTACK,
}

View File

@ -1,33 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon;
import io.lumine.mythic.lib.api.item.NBTItem;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
public class Gauntlet extends Weapon {
public Gauntlet(Player player, NBTItem item) {
super(player, item);
}
public void specialAttack(LivingEntity target) {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.gauntlet.enabled"))
return;
if (!checkWeaponCosts(CooldownType.SPECIAL_ATTACK))
return;
applyWeaponCosts(MMOItems.plugin.getConfig().getDouble("item-ability.gauntlet.cooldown"), CooldownType.SPECIAL_ATTACK);
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 0);
target.removePotionEffect(PotionEffectType.BLINDNESS);
target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, 40, 1));
target.setVelocity(getPlayer().getEyeLocation().getDirection().setY(0).normalize().setY(.8));
target.setVelocity(getPlayer().getEyeLocation().getDirection().setY(0).normalize().multiply(2).setY(.3));
}
}

View File

@ -2,13 +2,26 @@ package net.Indyuce.mmoitems.api.interaction.weapon;
import io.lumine.mythic.lib.MythicLib;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.flags.CustomFlag;
import io.lumine.mythic.lib.damage.AttackMetadata;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.skill.Skill;
import io.lumine.mythic.lib.skill.SkillMetadata;
import io.lumine.mythic.lib.skill.handler.SkillHandler;
import io.lumine.mythic.lib.skill.result.SkillResult;
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.event.item.UntargetedWeaponUseEvent;
import net.Indyuce.mmoitems.api.interaction.UseItem;
import net.Indyuce.mmoitems.api.interaction.WeaponAttackResult;
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.LegacyWeapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.api.util.message.Message;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.entity.LivingEntity;
@ -18,6 +31,8 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
public class Weapon extends UseItem {
@Deprecated
public Weapon(Player player, NBTItem item) {
this(PlayerData.get(player), item);
}
@ -43,18 +58,17 @@ public class Weapon extends UseItem {
* @return If the attack was cast successfully
*/
public boolean checkAndApplyWeaponCosts() {
if (!checkWeaponCosts(null)) return false;
applyWeaponCosts(0, null);
if (!checkWeaponCosts(false)) return false;
applyWeaponCosts(null);
return true;
}
/**
* Checks for cooldown, mana and stamina weapon costs
*
* @return If requirements were met ie the attack can be cast successfully
* @return If instantaneous weapon costs are met.
* @see {@link #applyWeaponCosts(Double)}
*/
public boolean checkWeaponCosts(@Nullable CooldownType cooldown) {
if (cooldown != null && getPlayerData().isOnCooldown(cooldown))
public boolean checkWeaponCosts(boolean cooldowns) {
if (cooldowns && getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(mmoitem.getType()))
return false;
double manaCost = getNBTItem().getStat("MANA_COST");
@ -73,22 +87,25 @@ public class Weapon extends UseItem {
}
/**
* Applies cooldown, mana and stamina weapon costs
* Hard coded instantaneous weapon costs are as follows:
* - mana and stamina (resources)
* - cooldown (given by the item type attack cooldown key)
* <p>
* Other weapon costs are inherent to the item type and are
* fully configurable inside of the types config file.
*
* @param attackDelay The weapon attack period/delay
* @param cooldown The weapon cooldown type. When set to null, no
* cooldown will be applied. This is made to handle
* custom weapons
* @see {@link #checkWeaponCosts(boolean)}
*/
public void applyWeaponCosts(double attackDelay, @Nullable CooldownType cooldown) {
public void applyWeaponCosts(@Nullable Double attackDelay) {
double manaCost = getNBTItem().getStat("MANA_COST");
final double manaCost = getNBTItem().getStat("MANA_COST");
if (manaCost > 0) playerData.getRPG().giveMana(-manaCost);
double staminaCost = getNBTItem().getStat("STAMINA_COST");
final double staminaCost = getNBTItem().getStat("STAMINA_COST");
if (staminaCost > 0) playerData.getRPG().giveStamina(-staminaCost);
if (cooldown != null) getPlayerData().applyCooldown(cooldown, attackDelay);
if (attackDelay != null)
getPlayerData().getMMOPlayerData().getCooldownMap().applyCooldown(mmoitem.getType(), attackDelay);
}
/**
@ -103,20 +120,103 @@ public class Weapon extends UseItem {
public boolean handleTargetedAttack(AttackMetadata attackMeta, @NotNull PlayerMetadata attacker, LivingEntity target) {
// Handle weapon mana and stamina costs ONLY
if (!checkAndApplyWeaponCosts())
return false;
if (!checkAndApplyWeaponCosts()) return false;
// Handle item set attack effects
if (getMMOItem().getType().getItemSet().hasAttackEffect() && !getNBTItem().getBoolean("MMOITEMS_DISABLE_ATTACK_PASSIVE"))
getMMOItem().getType().getItemSet().applyAttackEffect(attackMeta, attacker, playerData, target, this);
// Handle on-hit attack effects
final Skill onHitScript = mmoitem.getType().onAttack();
if (onHitScript != null && !getNBTItem().getBoolean("MMOITEMS_DISABLE_ATTACK_PASSIVE"))
onHitScript.cast(new TriggerMetadata(attacker, TriggerType.API, target, attackMeta));
return true;
}
/**
* Called when the player interacts with the item. This method is used to
* apply durability and cast the weapon attack
*
* @param rightClick Is the click a right click? If false, it's a left click.
* @param actionHand Slot being interacted with
* @return Null if there are no attack detected
* @implNote Since MI 6.7.3 this method handles custom durability, cooldown
* checks and player stat snapshots.
*/
@Nullable
public WeaponAttackResult handleUntargetedAttack(boolean rightClick, @NotNull EquipmentSlot actionHand) {
if (this instanceof LegacyWeapon) return legacyHandleUntargetedAttack(rightClick, actionHand);
// Check for item type attack effect
final Type itemType = mmoitem.getType();
final Skill attackEffect = rightClick ? itemType.onRightClick() : itemType.onLeftClick();
if (attackEffect == null) return WeaponAttackResult.NO_ATTACK;
// Check for attack effect conditions
final SkillHandler handler = attackEffect.getHandler();
final SkillMetadata meta = new TriggerMetadata(getPlayerData().getMMOPlayerData(), TriggerType.API).toSkillMetadata(attackEffect);
final SkillResult result = handler.getResult(meta);
if (!result.isSuccessful(meta)) return WeaponAttackResult.NO_ATTACK;
// Check for durability
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), actionHand);
if (durItem.isBroken()) return WeaponAttackResult.DURABILITY;
// Apply weapon instantaneous costs
PlayerMetadata stats = getPlayerData().getStats().newTemporary(actionHand);
if (!checkWeaponCosts(true)) return WeaponAttackResult.WEAPON_COSTS;
// Check for Bukkit event
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
Bukkit.getPluginManager().callEvent(called);
if (called.isCancelled()) return WeaponAttackResult.BUKKIT_EVENT;
// Attack is ready to be performed.
// Apply weapon costs
final double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
applyWeaponCosts(attackDelay);
// Apply weapon attack effect
handler.whenCast(result, meta);
// Apply durability loss
if (durItem.isValid()) durItem.decreaseDurability(1).inventoryUpdate();
return WeaponAttackResult.SUCCESS;
}
@Deprecated
private WeaponAttackResult legacyHandleUntargetedAttack(boolean rightClick, @NotNull EquipmentSlot actionHand) {
// Check for attack effect conditions
if (((LegacyWeapon) this).canAttack(rightClick, actionHand)) return WeaponAttackResult.NO_ATTACK;
// Check for durability
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), actionHand);
if (durItem.isBroken()) return WeaponAttackResult.DURABILITY;
// Apply weapon instantaneous costs
PlayerMetadata stats = getPlayerData().getStats().newTemporary(actionHand);
if (!checkWeaponCosts(true)) return WeaponAttackResult.WEAPON_COSTS;
// Check for Bukkit event
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
Bukkit.getPluginManager().callEvent(called);
if (called.isCancelled()) return WeaponAttackResult.BUKKIT_EVENT;
// Attack is ready to be performed.
// Apply weapon costs
final double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
applyWeaponCosts(attackDelay);
// Apply weapon attack effect
final PlayerMetadata caster = playerData.getMMOPlayerData().getStatMap().cache(actionHand);
((LegacyWeapon) this).applyAttackEffect(caster, actionHand);
// Apply durability loss
if (durItem.isValid()) durItem.decreaseDurability(1).inventoryUpdate();
return WeaponAttackResult.SUCCESS;
}
protected Location getGround(Location loc) {
for (int j = 0; j < 20; j++) {
if (loc.getBlock().getType().isSolid())
return loc;
if (loc.getBlock().getType().isSolid()) return loc;
loc.add(0, -1, 0);
}
return loc;
@ -125,7 +225,7 @@ public class Weapon extends UseItem {
/**
* @return First argument, or second if zero or lower
*/
public double requireNonZero(double number, double elseNumber) {
protected double requireNonZero(double number, double elseNumber) {
return number <= 0 ? elseNumber : number;
}
}

View File

@ -7,6 +7,8 @@ import io.lumine.mythic.lib.skill.trigger.TriggerType;
import io.lumine.mythic.lib.util.CustomProjectile;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.CustomSound;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.listener.CustomSoundListener;
import org.bukkit.GameMode;
import org.bukkit.Material;
@ -15,15 +17,23 @@ import org.bukkit.entity.Arrow;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
public class Crossbow extends UntargetedWeapon {
@Deprecated
public class Crossbow extends Weapon implements LegacyWeapon {
private boolean consumesArrow;
@Deprecated
public Crossbow(Player player, NBTItem item) {
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
super(player, item);
}
public Crossbow(PlayerData player, NBTItem item) {
super(player, item);
}
@Override
public boolean canAttack(EquipmentSlot slot) {
public boolean canAttack(boolean rightClick, EquipmentSlot slot) {
if (!rightClick) return false;
consumesArrow = !getNBTItem().getBoolean("MMOITEMS_DISABLE_ARROW_CONSUMPTION");
return player.getGameMode() == GameMode.CREATIVE || !consumesArrow || getPlayer().getInventory().containsAtLeast(new ItemStack(Material.ARROW), 1);
}

View File

@ -0,0 +1,17 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.PlayerMetadata;
/**
* These weapon types need to be adapted to
*/
@Deprecated
public interface LegacyWeapon {
@Deprecated
boolean canAttack(boolean rightClick, EquipmentSlot slot);
@Deprecated
void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot);
}

View File

@ -8,6 +8,8 @@ import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.SoundReader;
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat.LuteAttackEffect;
import net.Indyuce.mmoitems.stat.data.ProjectileParticlesData;
@ -23,14 +25,20 @@ import org.jetbrains.annotations.NotNull;
import javax.annotation.Nullable;
import java.util.List;
public class Lute extends UntargetedWeapon {
@Deprecated
public class Lute extends Weapon implements LegacyWeapon {
@Deprecated
public Lute(Player player, NBTItem item) {
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
super(player, item);
}
public Lute(PlayerData player, NBTItem item) {
super(player, item);
}
@Override
public boolean canAttack(EquipmentSlot slot) {
return true;
public boolean canAttack(boolean rightClick, EquipmentSlot slot) {
return rightClick;
}
@Override
@ -40,8 +48,7 @@ public class Lute extends UntargetedWeapon {
final Vector weight = new Vector(0, -.003 * stats.getStat("NOTE_WEIGHT"), 0);
final @Nullable LuteAttackEffect effect = LuteAttackEffect.get(getNBTItem());
@Deprecated
final SoundReader sound = new SoundReader(getNBTItem().getString("MMOITEMS_LUTE_ATTACK_SOUND"), VersionSound.BLOCK_NOTE_BLOCK_BELL.toSound());
@Deprecated final SoundReader sound = new SoundReader(getNBTItem().getString("MMOITEMS_LUTE_ATTACK_SOUND"), VersionSound.BLOCK_NOTE_BLOCK_BELL.toSound());
final @NotNull ProjectileParticlesData projParticle = getNBTItem().hasTag("MMOITEMS_PROJECTILE_PARTICLES") ?
new ProjectileParticlesData(getNBTItem().getString("MMOITEMS_PROJECTILE_PARTICLES")) : ProjectileParticlesData.DEFAULT;

View File

@ -7,21 +7,28 @@ import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.util.RayTrace;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Sound;
import org.bukkit.entity.Player;
public class Musket extends UntargetedWeapon {
@Deprecated
public class Musket extends Weapon implements LegacyWeapon {
@Deprecated
public Musket(Player player, NBTItem item) {
super(player, item, UntargetedWeaponType.RIGHT_CLICK);
super(player, item);
}
public Musket(PlayerData player, NBTItem item) {
super(player, item);
}
@Override
public boolean canAttack(EquipmentSlot slot) {
return true;
public boolean canAttack(boolean rightClick, EquipmentSlot slot) {
return rightClick;
}
@Override

View File

@ -1,72 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.util.RayTrace;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.player.PlayerData.CooldownType;
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
import org.bukkit.EntityEffect;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player;
import org.bukkit.util.Vector;
public class Staff extends UntargetedWeapon {
public Staff(Player player, NBTItem item) {
super(player, item, UntargetedWeaponType.LEFT_CLICK);
}
@Override
public boolean canAttack(EquipmentSlot slot) {
return true;
}
@Override
public void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot) {
double attackDamage = requireNonZero(stats.getStat("ATTACK_DAMAGE"), 1);
double range = requireNonZero(stats.getStat("RANGE"), MMOItems.plugin.getConfig().getDouble("default.range"));
StaffSpirit spirit = StaffSpirit.get(getNBTItem());
if (spirit != null) {
spirit.getAttack().handle(stats, attackDamage, getNBTItem(), slot, range);
return;
}
RayTrace trace = new RayTrace(stats.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
if (trace.hasHit())
stats.attack(trace.getHit(), attackDamage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
trace.draw(.5, tick -> tick.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, tick, 0, .1, .1, .1, 0));
getPlayer().getWorld().playSound(getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_TWINKLE.toSound(), 2, 2);
}
public void specialAttack(LivingEntity target) {
if (!MMOItems.plugin.getConfig().getBoolean("item-ability.staff.enabled"))
return;
if (!checkWeaponCosts(CooldownType.SPECIAL_ATTACK))
return;
applyWeaponCosts(MMOItems.plugin.getConfig().getDouble("item-ability.staff.cooldown"), CooldownType.SPECIAL_ATTACK);
double power = MMOItems.plugin.getConfig().getDouble("item-ability.staff.power");
try {
Vector vec = target.getLocation().toVector().subtract(getPlayer().getLocation().toVector()).setY(0).normalize().multiply(1.75 * power).setY(.65 * power);
target.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, target.getLocation().add(0, 1, 0), 0);
target.getWorld().spawnParticle(Particle.EXPLOSION_NORMAL, target.getLocation().add(0, 1, 0), 16, 0, 0, 0, .1);
target.setVelocity(vec);
target.playEffect(EntityEffect.HURT);
target.getWorld().playSound(target.getLocation(), Sound.BLOCK_ANVIL_LAND, 1, 2);
} catch (IllegalArgumentException ignored) {
}
}
}

View File

@ -1,78 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.item.UntargetedWeaponUseEvent;
import net.Indyuce.mmoitems.api.interaction.util.UntargetedDurabilityItem;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
public abstract class UntargetedWeapon extends Weapon {
protected final UntargetedWeaponType weaponType;
public UntargetedWeapon(Player player, NBTItem item, UntargetedWeaponType weaponType) {
super(player, item);
this.weaponType = weaponType;
}
/**
* Called when the player interacts with the item. This method is used to
* apply durability and cast the weapon attack
*
* @param slot Slot being interacted with
* @implNote Since MI 6.7.3 this method handles custom durability, cooldown
* checks and player stat snapshots.
*/
public void handleTargetFreeAttack(EquipmentSlot slot) {
if (!canAttack(slot))
return;
// Check for durability
UntargetedDurabilityItem durItem = new UntargetedDurabilityItem(getPlayer(), getNBTItem(), slot);
if (durItem.isBroken())
return;
// Apply weapon mana/stamina costs and cooldown
PlayerMetadata stats = getPlayerData().getStats().newTemporary(slot);
if (!checkWeaponCosts(PlayerData.CooldownType.BASIC_ATTACK))
return;
// Check for Bukkit event
UntargetedWeaponUseEvent called = new UntargetedWeaponUseEvent(playerData, this);
Bukkit.getPluginManager().callEvent(called);
if (called.isCancelled())
return;
// Apply weapon costs
double attackDelay = 1 / requireNonZero(stats.getStat("ATTACK_SPEED"), MMOItems.plugin.getConfig().getDouble("default.attack-speed"));
applyWeaponCosts(attackDelay, PlayerData.CooldownType.BASIC_ATTACK);
// Specific weapon attack effect
applyAttackEffect(stats, slot);
// Apply durability loss
if (durItem.isValid())
durItem.decreaseDurability(1).inventoryUpdate();
}
/**
* Used for instance by the Crossbow item type to apply
* ammo requirements. This is the first ever condition checked
* when trying to perform an untargeted attack
*
* @param slot Slot used to attack
* @return Extra attack condition, specific to the untargeted weapon type
*/
public abstract boolean canAttack(EquipmentSlot slot);
public abstract void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot);
public UntargetedWeaponType getWeaponType() {
return weaponType;
}
}

View File

@ -1,22 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
import org.bukkit.event.block.Action;
import org.jetbrains.annotations.NotNull;
/**
* Used to determine if the item must be left or right clicked in order to
* cast a basic attack. Whips, staffs are left click weapons whereas muskets
* are right click weapons
*
* @author cympe
*/
public enum UntargetedWeaponType {
RIGHT_CLICK,
LEFT_CLICK;
public boolean corresponds(@NotNull Action action) {
return this == RIGHT_CLICK ?
action == Action.RIGHT_CLICK_AIR || action == Action.RIGHT_CLICK_BLOCK :
action == Action.LEFT_CLICK_AIR || action == Action.LEFT_CLICK_BLOCK;
}
}

View File

@ -1,38 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.util.RayTrace;
import io.lumine.mythic.lib.version.VersionSound;
import net.Indyuce.mmoitems.ItemStats;
import net.Indyuce.mmoitems.MMOItems;
import org.bukkit.Particle;
import org.bukkit.entity.Player;
public class Whip extends UntargetedWeapon {
public Whip(Player player, NBTItem item) {
super(player, item, UntargetedWeaponType.LEFT_CLICK);
}
@Override
public boolean canAttack(EquipmentSlot slot) {
return true;
}
@Override
public void applyAttackEffect(PlayerMetadata stats, EquipmentSlot slot) {
double attackDamage = requireNonZero(stats.getStat("ATTACK_DAMAGE"), 7);
double range = requireNonZero(getNBTItem().getStat(ItemStats.RANGE.getId()), MMOItems.plugin.getConfig().getDouble("default.range"));
RayTrace trace = new RayTrace(getPlayer(), slot, range, entity -> UtilityMethods.canTarget(stats.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
if (trace.hasHit())
stats.attack(trace.getHit(), attackDamage, DamageType.WEAPON, DamageType.PROJECTILE, DamageType.PHYSICAL);
trace.draw(.5, tick -> tick.getWorld().spawnParticle(Particle.CRIT, tick, 0, .1, .1, .1, 0));
getPlayer().getWorld().playSound(getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 1, 2);
}
}

View File

@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
@Deprecated
public class BruteLuteAttack implements LuteAttackHandler {
@Override

View File

@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
@Deprecated
public class CircularLuteAttack implements LuteAttackHandler {
@Override

View File

@ -9,6 +9,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.Random;
@Deprecated
public interface LuteAttackHandler {
static final Random RANDOM = new Random();

View File

@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
@Deprecated
public class SimpleLuteAttack implements LuteAttackHandler {
@Override

View File

@ -16,6 +16,7 @@ import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import org.jetbrains.annotations.NotNull;
@Deprecated
public class SlashLuteAttack implements LuteAttackHandler {
@Override

View File

@ -18,6 +18,7 @@ import org.jetbrains.annotations.NotNull;
import java.util.List;
@Deprecated
public class WaveLuteAttack implements LuteAttackHandler {
@Override

View File

@ -1,25 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.util.RayTrace;
import io.lumine.mythic.lib.version.VersionSound;
import org.bukkit.Particle;
public class LightningSpirit implements StaffAttackHandler {
@Override
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), VersionSound.ENTITY_FIREWORK_ROCKET_BLAST.toSound(), 2, 2);
RayTrace trace = new RayTrace(caster.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(caster.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
if (trace.hasHit())
caster.attack(trace.getHit(), damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
trace.draw(.5, loc1 -> loc1.getWorld().spawnParticle(Particle.FIREWORKS_SPARK, loc1, 0));
}
}

View File

@ -1,62 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Color;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.List;
public class ManaSpirit implements StaffAttackHandler {
@Override
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
new BukkitRunnable() {
final Vector vec = caster.getPlayer().getEyeLocation().getDirection().multiply(.4);
final Location loc = caster.getPlayer().getEyeLocation();
int ti = 0;
final double r = .2;
public void run() {
if (ti++ > range)
cancel();
if (ti % 2 == 0)
loc.getWorld().playSound(loc, Sound.BLOCK_SNOW_BREAK, 2, 2);
List<Entity> targets = MMOUtils.getNearbyChunkEntities(loc);
for (int j = 0; j < 3; j++) {
loc.add(vec);
if (loc.getBlock().getType().isSolid()) {
cancel();
break;
}
for (double item = 0; item < Math.PI * 2; item += Math.PI / 3.5) {
Vector vec = MMOUtils.rotateFunc(new Vector(r * Math.cos(item), r * Math.sin(item), 0), loc);
if (RANDOM.nextDouble() <= .6)
loc.getWorld().spawnParticle(Particle.REDSTONE, loc.clone().add(vec), 1, new Particle.DustOptions(Color.AQUA, 1));
}
for (Entity target : targets)
if (UtilityMethods.canTarget(caster.getPlayer(), loc, target, InteractionType.OFFENSE_ACTION)) {
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc, 0);
cancel();
return;
}
}
}
}.runTaskTimer(MMOItems.plugin, 0, 1);
}
}

View File

@ -1,56 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.util.MMOUtils;
import org.bukkit.Location;
import org.bukkit.Particle;
import org.bukkit.Sound;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
import java.util.List;
public class NetherSpirit implements StaffAttackHandler {
@Override
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
new BukkitRunnable() {
final Vector vec = caster.getPlayer().getEyeLocation().getDirection().multiply(.3);
final Location loc = caster.getPlayer().getEyeLocation();
int ti = 0;
public void run() {
if (ti++ % 2 == 0)
loc.getWorld().playSound(loc, Sound.BLOCK_FIRE_AMBIENT, 2, 2);
List<Entity> targets = MMOUtils.getNearbyChunkEntities(loc);
for (int j = 0; j < 3; j++) {
loc.add(vec);
if (loc.getBlock().getType().isSolid()) {
cancel();
break;
}
loc.getWorld().spawnParticle(Particle.FLAME, loc, 2, .07, .07, .07, 0);
loc.getWorld().spawnParticle(Particle.SMOKE_NORMAL, loc, 0);
for (Entity target : targets)
if (UtilityMethods.canTarget(caster.getPlayer(), loc, target, InteractionType.OFFENSE_ACTION)) {
caster.attack((LivingEntity) target, damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
loc.getWorld().spawnParticle(Particle.EXPLOSION_LARGE, loc, 0);
cancel();
return;
}
}
if (ti >= range)
cancel();
}
}.runTaskTimer(MMOItems.plugin, 0, 1);
}
}

View File

@ -1,23 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.player.PlayerMetadata;
import org.bukkit.Location;
import java.util.Random;
public interface StaffAttackHandler {
static final Random RANDOM = new Random();
void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range);
default Location getGround(Location loc) {
for (int j = 0; j < 20; j++) {
if (loc.getBlock().getType().isSolid())
return loc;
loc.add(0, -1, 0);
}
return loc;
}
}

View File

@ -16,7 +16,9 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
/*
@Deprecated
public class SunfireSpirit implements StaffAttackHandler {
@Override
@ -57,3 +59,4 @@ public class SunfireSpirit implements StaffAttackHandler {
}.runTaskTimer(MMOItems.plugin, 0, 1);
}
}
*/

View File

@ -16,7 +16,9 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
/*
@Deprecated
public class ThunderSpirit implements StaffAttackHandler {
@Override
@ -55,3 +57,4 @@ public class ThunderSpirit implements StaffAttackHandler {
}.runTaskTimer(MMOItems.plugin, 0, 1);
}
}
*/

View File

@ -1,38 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.damage.DamageMetadata;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.skill.ShulkerMissile;
import org.bukkit.Sound;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.ShulkerBullet;
import org.bukkit.scheduler.BukkitRunnable;
import org.bukkit.util.Vector;
public class VoidSpirit implements StaffAttackHandler {
@Override
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
Vector vec = caster.getPlayer().getEyeLocation().getDirection();
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_WITHER_SHOOT, 2, 2);
ShulkerBullet shulkerBullet = (ShulkerBullet) caster.getPlayer().getWorld().spawnEntity(caster.getPlayer().getLocation().add(0, 1, 0), EntityType.valueOf("SHULKER_BULLET"));
shulkerBullet.setShooter(caster.getPlayer());
new BukkitRunnable() {
double ti = 0;
public void run() {
ti += .1;
if (shulkerBullet.isDead() || ti >= range / 4) {
shulkerBullet.remove();
cancel();
}
shulkerBullet.setVelocity(vec);
}
}.runTaskTimer(MMOItems.plugin, 0, 1);
MMOItems.plugin.getEntities().registerCustomEntity(shulkerBullet, new ShulkerMissile.ShulkerMissileEntityData(caster, new DamageMetadata(damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE), 0, nbt));
}
}

View File

@ -1,25 +0,0 @@
package net.Indyuce.mmoitems.api.interaction.weapon.untargeted.staff;
import io.lumine.mythic.lib.UtilityMethods;
import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.DamageType;
import io.lumine.mythic.lib.player.PlayerMetadata;
import io.lumine.mythic.lib.util.RayTrace;
import org.bukkit.Color;
import org.bukkit.Sound;
public class XRaySpirit implements StaffAttackHandler {
@Override
public void handle(PlayerMetadata caster, double damage, NBTItem nbt, EquipmentSlot slot, double range) {
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, 2, 2);
RayTrace trace = new RayTrace(caster.getPlayer(), slot, range, entity -> UtilityMethods.canTarget(caster.getPlayer(), entity, InteractionType.OFFENSE_ACTION));
if (trace.hasHit())
caster.attack(trace.getHit(), damage, DamageType.WEAPON, DamageType.MAGIC, DamageType.PROJECTILE);
trace.draw(.5, Color.BLACK);
caster.getPlayer().getWorld().playSound(caster.getPlayer().getLocation(), Sound.ENTITY_ZOMBIE_ATTACK_IRON_DOOR, 0.40f, 2);
}
}

View File

@ -408,11 +408,6 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
public enum CooldownType {
/**
* Basic attack cooldown like staffs and lutes
*/
BASIC_ATTACK,
/**
* Elemental attacks cooldown
*/
@ -431,12 +426,6 @@ public class PlayerData extends SynchronizedDataHolder implements Closeable {
*
* @see {@link Tool#miningEffects(Block)}
*/
BOUNCING_CRACK,
/**
* Special item set attack effects including slashing, piercing and
* blunt attack effects
*/
SET_TYPE_ATTACK
BOUNCING_CRACK;
}
}

View File

@ -59,7 +59,7 @@ public class ReloadCommandTreeNode extends CommandTreeNode {
MMOItems.plugin.getLanguage().reload();
MMOItems.plugin.getDropTables().reload();
MMOItems.plugin.getTypes().reload();
MMOItems.plugin.getTypes().reload(true);
MMOItems.plugin.getTiers().reload();
MMOItems.plugin.getSets().reload();
MMOItems.plugin.getUpgrades().reload();

View File

@ -12,7 +12,6 @@ public class ListCommandTreeNode extends CommandTreeNode {
addChild(new AbilityCommandTreeNode(this));
addChild(new LuteAttackCommandTreeNode(this));
addChild(new StaffSpiritCommandTreeNode(this));
addChild(new TypeCommandTreeNode(this));
}
@ -21,7 +20,6 @@ public class ListCommandTreeNode extends CommandTreeNode {
sender.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------[" + ChatColor.LIGHT_PURPLE + " MMOItems: lists "
+ ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "]-----------------");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list type " + ChatColor.WHITE + "shows all item types (sword, axe...)");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list spirit " + ChatColor.WHITE + "shows all available staff spirits");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list lute " + ChatColor.WHITE + "shows all available lute attack effects");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/mi list ability " + ChatColor.WHITE + "shows all available abilities");
if (sender instanceof Player) {

View File

@ -1,24 +0,0 @@
package net.Indyuce.mmoitems.command.mmoitems.list;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
import io.lumine.mythic.lib.command.api.CommandTreeNode;
public class StaffSpiritCommandTreeNode extends CommandTreeNode {
public StaffSpiritCommandTreeNode(CommandTreeNode parent) {
super(parent, "spirit");
}
@Override
public CommandResult execute(CommandSender sender, String[] args) {
sender.sendMessage(ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "-----------------[" + ChatColor.LIGHT_PURPLE + " Staff Spirits "
+ ChatColor.DARK_GRAY + "" + ChatColor.STRIKETHROUGH + "]-----------------");
for (StaffSpirit ss : StaffSpirit.values()) {
String lore = ss.hasLore() ? " " + ChatColor.WHITE + ">> " + ChatColor.GRAY + "" + ChatColor.ITALIC + ss.getDefaultLore() : "";
sender.sendMessage("* " + ChatColor.LIGHT_PURPLE + ss.name() + lore);
}
return CommandResult.SUCCESS;
}
}

View File

@ -12,7 +12,6 @@ import io.lumine.mythic.core.skills.auras.Aura;
import io.lumine.mythic.bukkit.utils.Events;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.event.item.SpecialWeaponAttackEvent;
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.*;
import org.bukkit.scheduler.BukkitRunnable;
import org.jetbrains.annotations.NotNull;
@ -224,11 +223,12 @@ public class MMOItemsOnUseAura extends Aura implements ITargetedEntitySkill {
enum UseItemTypes {
CROSSBOW(Crossbow.class),
GAUNTLET(Gauntlet.class),
// GAUNTLET(Gauntlet.class),
LUTE(Lute.class),
MUSKET(Musket.class),
STAFF(Staff.class),
WHIP(Whip.class);
// WHIP(Whip.class);
;
/**
* @return Class to use InstanceOf and identify a weapon.

View File

@ -7,18 +7,18 @@ import io.lumine.mythic.lib.api.item.NBTItem;
import io.lumine.mythic.lib.api.player.EquipmentSlot;
import io.lumine.mythic.lib.comp.interaction.InteractionType;
import io.lumine.mythic.lib.damage.MeleeAttackMetadata;
import io.lumine.mythic.lib.skill.Skill;
import io.lumine.mythic.lib.skill.trigger.TriggerMetadata;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmoitems.MMOItems;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.api.TypeSet;
import net.Indyuce.mmoitems.api.event.item.SpecialWeaponAttackEvent;
import net.Indyuce.mmoitems.api.interaction.*;
import net.Indyuce.mmoitems.api.interaction.projectile.ProjectileData;
import net.Indyuce.mmoitems.api.interaction.weapon.Gauntlet;
import net.Indyuce.mmoitems.api.interaction.weapon.Weapon;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.Staff;
import net.Indyuce.mmoitems.api.interaction.weapon.untargeted.UntargetedWeapon;
import net.Indyuce.mmoitems.api.player.PlayerData;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.manager.EntityManager;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.GameMode;
@ -31,6 +31,7 @@ import org.bukkit.event.Event;
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.entity.EntityShootBowEvent;
import org.bukkit.event.inventory.InventoryAction;
@ -49,8 +50,7 @@ public class ItemUse implements Listener {
return;
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
if (!item.hasType())
return;
if (!item.hasType()) return;
/*
* Some consumables must be fully eaten through the vanilla eating
@ -58,8 +58,7 @@ public class ItemUse implements Listener {
*/
final Player player = event.getPlayer();
final UseItem useItem = UseItem.getItem(player, item, item.getType());
if (useItem instanceof Consumable && ((Consumable) useItem).hasVanillaEating())
return;
if (useItem instanceof Consumable && ((Consumable) useItem).hasVanillaEating()) return;
// (BUG FIX) Cancel the event to prevent things like shield blocking
if (!useItem.checkItemRequirements()) {
@ -68,12 +67,11 @@ public class ItemUse implements Listener {
}
// Commands & consummables
if (event.getAction().name().contains("RIGHT_CLICK")) {
final boolean rightClick = event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK;
if (rightClick) {
if (useItem.getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(useItem.getMMOItem())) {
final double cd = useItem.getPlayerData().getMMOPlayerData().getCooldownMap().getCooldown(useItem.getMMOItem());
Message.ITEM_ON_COOLDOWN
.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "")
.send(player);
Message.ITEM_ON_COOLDOWN.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "").send(player);
event.setUseItemInHand(Event.Result.DENY);
return;
}
@ -81,8 +79,7 @@ public class ItemUse implements Listener {
if (useItem instanceof Consumable) {
event.setUseItemInHand(Event.Result.DENY);
Consumable.ConsumableConsumeResult result = ((Consumable) useItem).useOnPlayer(event.getHand(), false);
if (result == Consumable.ConsumableConsumeResult.CANCEL)
return;
if (result == Consumable.ConsumableConsumeResult.CANCEL) return;
else if (result == Consumable.ConsumableConsumeResult.CONSUME)
event.getItem().setAmount(event.getItem().getAmount() - 1);
@ -92,48 +89,42 @@ public class ItemUse implements Listener {
useItem.executeCommands();
}
// Target free weapon attack
if (useItem instanceof UntargetedWeapon) {
UntargetedWeapon weapon = (UntargetedWeapon) useItem;
if (weapon.getWeaponType().corresponds(event.getAction()))
weapon.handleTargetFreeAttack(EquipmentSlot.fromBukkit(event.getHand()));
}
// Target-free weapon effects
if (useItem instanceof Weapon)
((Weapon) useItem).handleUntargetedAttack(rightClick, EquipmentSlot.fromBukkit(event.getHand()));
}
@EventHandler(ignoreCancelled = true)
public void meleeAttacks(PlayerAttackEvent event) {
// Checks if it's a melee attack
if (!(event.getAttack() instanceof MeleeAttackMetadata))
// Make sure it's a melee attack
if (!(event.getAttack() instanceof MeleeAttackMetadata)) return;
final Player player = event.getPlayer();
final PlayerData playerData = PlayerData.get(player);
final ItemStack weaponUsed = player.getInventory().getItem(((MeleeAttackMetadata) event.getAttack()).getHand().toBukkit());
final NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(weaponUsed);
if (!item.hasType()) return;
final Type itemType = Type.get(item.getType());
if (itemType == Type.BLOCK) return;
// Prevent melee attacks with non-melee weapons
if (!itemType.hasMeleeAttacks()) {
event.setCancelled(true);
return;
/*
* Must apply attack conditions before apply any effects. the event must
* be cancelled before anything is applied
*/
Player player = event.getPlayer();
PlayerData playerData = PlayerData.get(player);
ItemStack weaponUsed = player.getInventory().getItem(((MeleeAttackMetadata) event.getAttack()).getHand().toBukkit());
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(weaponUsed);
if (item.hasType() && Type.get(item.getType()) != Type.BLOCK) {
Weapon weapon = new Weapon(playerData, item);
if (weapon.getMMOItem().getType().getItemSet() == TypeSet.RANGE) {
event.setCancelled(true);
return;
}
if (!weapon.checkItemRequirements()) {
event.setCancelled(true);
return;
}
if (!weapon.handleTargetedAttack(event.getAttack(), event.getAttacker(), event.getEntity())) {
event.setCancelled(true);
return;
}
}
// Check item requirements
final Weapon weapon = new Weapon(playerData, item);
if (!weapon.checkItemRequirements()) {
event.setCancelled(true);
return;
}
// Apply melee attack
if (!weapon.handleTargetedAttack(event.getAttack(), event.getAttacker(), event.getEntity()))
event.setCancelled(true);
}
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
@ -142,12 +133,10 @@ public class ItemUse implements Listener {
final Player player = event.getPlayer();
final Block block = event.getBlock();
if (player.getGameMode() == GameMode.CREATIVE)
return;
if (player.getGameMode() == GameMode.CREATIVE) return;
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
if (!item.hasType())
return;
if (!item.hasType()) return;
Tool tool = new Tool(player, item);
if (!tool.checkItemRequirements()) {
@ -155,42 +144,31 @@ public class ItemUse implements Listener {
return;
}
if (tool.miningEffects(block))
event.setCancelled(true);
if (tool.miningEffects(block)) event.setCancelled(true);
}
@EventHandler
public void rightClickWeaponInteractions(PlayerInteractEntityEvent event) {
Player player = event.getPlayer();
if (!(event.getRightClicked() instanceof LivingEntity))
return;
if (!(event.getRightClicked() instanceof LivingEntity)) return;
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(player.getInventory().getItemInMainHand());
if (!item.hasType())
return;
if (!item.hasType()) return;
LivingEntity target = (LivingEntity) event.getRightClicked();
if (!UtilityMethods.canTarget(player, target, InteractionType.OFFENSE_ACTION))
return;
if (!UtilityMethods.canTarget(player, target, InteractionType.OFFENSE_ACTION)) return;
UseItem weapon = UseItem.getItem(player, item, item.getType());
if (!weapon.checkItemRequirements())
return;
// Check for usability
final UseItem usableItem = UseItem.getItem(player, item, item.getType());
if (!usableItem.checkItemRequirements()) return;
// Special staff attack
if (weapon instanceof Staff) {
SpecialWeaponAttackEvent attackEvent = new SpecialWeaponAttackEvent(weapon.getPlayerData(), (Weapon) weapon, target);
Bukkit.getPluginManager().callEvent(attackEvent);
if (!attackEvent.isCancelled())
((Staff) weapon).specialAttack(target);
}
// Special gauntlet attack
if (weapon instanceof Gauntlet) {
SpecialWeaponAttackEvent attackEvent = new SpecialWeaponAttackEvent(weapon.getPlayerData(), (Weapon) weapon, target);
Bukkit.getPluginManager().callEvent(attackEvent);
if (!attackEvent.isCancelled())
((Gauntlet) weapon).specialAttack(target);
// Apply type-specific entity interactions
final Skill onEntityInteract = usableItem.getMMOItem().getType().onEntityInteract();
if (onEntityInteract != null) {
SpecialWeaponAttackEvent called = new SpecialWeaponAttackEvent(usableItem.getPlayerData(), (Weapon) usableItem, target);
Bukkit.getPluginManager().callEvent(called);
if (!called.isCancelled())
onEntityInteract.cast(new TriggerMetadata(usableItem.getPlayerData().getMMOPlayerData(), TriggerType.API));
}
}
@ -198,49 +176,40 @@ public class ItemUse implements Listener {
@EventHandler
public void gemStonesAndItemStacks(InventoryClickEvent event) {
Player player = (Player) event.getWhoClicked();
if (event.getAction() != InventoryAction.SWAP_WITH_CURSOR)
return;
if (event.getAction() != InventoryAction.SWAP_WITH_CURSOR) return;
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCursor());
if (!item.hasType())
return;
if (!item.hasType()) return;
UseItem useItem = UseItem.getItem(player, item, item.getType());
if (!useItem.checkItemRequirements())
return;
if (!useItem.checkItemRequirements()) return;
if (useItem instanceof ItemSkin) {
NBTItem picked = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCurrentItem());
if (!picked.hasType())
return;
if (!picked.hasType()) return;
ItemSkin.ApplyResult result = ((ItemSkin) useItem).applyOntoItem(picked, Type.get(picked.getType()));
if (result.getType() == ItemSkin.ResultType.NONE)
return;
if (result.getType() == ItemSkin.ResultType.NONE) return;
event.setCancelled(true);
item.getItem().setAmount(item.getItem().getAmount() - 1);
if (result.getType() == ItemSkin.ResultType.FAILURE)
return;
if (result.getType() == ItemSkin.ResultType.FAILURE) return;
event.setCurrentItem(result.getResult());
}
if (useItem instanceof GemStone) {
NBTItem picked = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getCurrentItem());
if (!picked.hasType())
return;
if (!picked.hasType()) return;
GemStone.ApplyResult result = ((GemStone) useItem).applyOntoItem(picked, Type.get(picked.getType()));
if (result.getType() == GemStone.ResultType.NONE)
return;
if (result.getType() == GemStone.ResultType.NONE) return;
event.setCancelled(true);
item.getItem().setAmount(item.getItem().getAmount() - 1);
if (result.getType() == GemStone.ResultType.FAILURE)
return;
if (result.getType() == GemStone.ResultType.FAILURE) return;
event.setCurrentItem(result.getResult());
}
@ -253,17 +222,13 @@ public class ItemUse implements Listener {
}
/**
* This handler listens to ALL bow shootings, including both
* custom bows from MMOItems AND vanilla bows, since MMOItems needs to
* apply on-hit effects like crits, elemental damage... even if the
* player is using a vanilla bow.
* <p>
* Fixing commit 4aec1433
* This handler registers arrows from custom MMOItems bows
*
* @see {@link EntityManager#onHitEffects(PlayerAttackEvent)}
*/
@EventHandler
public void handleCustomBows(EntityShootBowEvent event) {
if (!(event.getProjectile() instanceof AbstractArrow) || !(event.getEntity() instanceof Player))
return;
if (!(event.getProjectile() instanceof AbstractArrow) || !(event.getEntity() instanceof Player)) return;
final NBTItem item = NBTItem.get(event.getBow());
final Type type = Type.get(item.getType());
@ -284,8 +249,7 @@ public class ItemUse implements Listener {
// Apply arrow velocity
final double arrowVelocity = projData.getShooter().getStat("ARROW_VELOCITY");
if (arrowVelocity > 0)
arrow.setVelocity(arrow.getVelocity().multiply(arrowVelocity));
if (arrowVelocity > 0) arrow.setVelocity(arrow.getVelocity().multiply(arrowVelocity));
}
}
@ -296,8 +260,7 @@ public class ItemUse implements Listener {
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void handleVanillaEatenConsumables(PlayerItemConsumeEvent event) {
NBTItem item = MythicLib.plugin.getVersion().getWrapper().getNBTItem(event.getItem());
if (!item.hasType())
return;
if (!item.hasType()) return;
Player player = event.getPlayer();
UseItem useItem = UseItem.getItem(player, item, item.getType());
@ -310,9 +273,7 @@ public class ItemUse implements Listener {
if (useItem.getPlayerData().getMMOPlayerData().getCooldownMap().isOnCooldown(useItem.getMMOItem())) {
final double cd = useItem.getPlayerData().getMMOPlayerData().getCooldownMap().getCooldown(useItem.getMMOItem());
Message.ITEM_ON_COOLDOWN
.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "")
.send(player);
Message.ITEM_ON_COOLDOWN.format(ChatColor.RED, "#left#", MythicLib.plugin.getMMOConfig().decimal.format(cd), "#s#", cd >= 2 ? "s" : "").send(player);
event.setCancelled(true);
return;
}
@ -326,8 +287,7 @@ public class ItemUse implements Listener {
}
// Item is not consumed but its effects are applied anyways
if (result == Consumable.ConsumableConsumeResult.NOT_CONSUME)
event.setCancelled(true);
if (result == Consumable.ConsumableConsumeResult.NOT_CONSUME) event.setCancelled(true);
useItem.getPlayerData().getMMOPlayerData().getCooldownMap().applyCooldown(useItem.getMMOItem(), useItem.getNBTItem().getStat("ITEM_COOLDOWN"));
useItem.executeCommands();

View File

@ -11,7 +11,7 @@ import net.Indyuce.mmoitems.api.util.NumericStatFormula;
import net.Indyuce.mmoitems.api.util.message.Message;
import net.Indyuce.mmoitems.stat.GemUpgradeScaling;
import net.Indyuce.mmoitems.stat.LuteAttackEffectStat.LuteAttackEffect;
import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
//import net.Indyuce.mmoitems.stat.StaffSpiritStat.StaffSpirit;
import net.Indyuce.mmoitems.util.LanguageFile;
import org.bukkit.Material;
import org.bukkit.configuration.ConfigurationSection;
@ -138,9 +138,9 @@ public class ConfigManager implements Reloadable {
// Staff spirits
final LanguageFile attackEffects = new LanguageFile("attack-effects");
for (StaffSpirit sp : StaffSpirit.values())
/* for (StaffSpirit sp : StaffSpirit.values())
sp.setName(attackEffects.computeTranslation("staff-spirit." + sp.name().toLowerCase().replace("_", "-"),
() -> UtilityMethods.caseOnWords(sp.name().toLowerCase().replace("_", " "))));
() -> UtilityMethods.caseOnWords(sp.name().toLowerCase().replace("_", " "))));*/
// Lute attack effects
for (LuteAttackEffect eff : LuteAttackEffect.values())
@ -262,11 +262,11 @@ public class ConfigManager implements Reloadable {
public String getLuteAttackEffectName(LuteAttackEffect effect) {
return effect.getName();
}
/*
@Deprecated
public String getStaffSpiritName(StaffSpirit spirit) {
return spirit.getName();
}
}*/
/**
* @deprecated See {@link net.Indyuce.mmoitems.api.item.util.LoreUpdate}

View File

@ -5,6 +5,8 @@ import net.Indyuce.mmoitems.api.ConfigFile;
import net.Indyuce.mmoitems.api.Type;
import net.Indyuce.mmoitems.manager.ConfigManager.DefaultFile;
import org.apache.commons.lang.Validate;
import org.bukkit.configuration.ConfigurationSection;
import org.bukkit.configuration.file.FileConfiguration;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -13,100 +15,117 @@ import java.lang.reflect.Modifier;
import java.util.*;
import java.util.logging.Level;
public class TypeManager implements Reloadable {
private final Map<String, Type> map = new LinkedHashMap<>();
public class TypeManager {
private final Map<String, Type> map = new LinkedHashMap<>();
/**
* Reloads the type manager. It entirely empties the currently registered
* item types, registers default item types again and reads item-types.yml
*/
public void reload() {
map.clear();
/**
* Reloads the type manager. It entirely empties the currently registered
* item types, registers default item types again and reads item-types.yml
*/
public void reload(boolean clearBefore) {
if (clearBefore) map.clear();
// Load default types
for (Field field : Type.class.getFields())
try {
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.get(null) instanceof Type)
register((Type) field.get(null));
} catch (Exception exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Couldn't register type called '" + field.getName() + "': " + exception.getMessage());
}
// Load default types
for (Field field : Type.class.getFields())
try {
if (Modifier.isStatic(field.getModifiers()) && Modifier.isFinal(field.getModifiers()) && field.get(null) instanceof Type)
register((Type) field.get(null));
} catch (Exception exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Couldn't register type called '" + field.getName() + "': " + exception.getMessage());
}
/*
* Register all other types. Important: check if the map already
* contains the id, this way the DEFAULT types are not registered twice,
* and only custom types are registered with a parent.
*/
DefaultFile.ITEM_TYPES.checkFile();
/*
* Register all other types. Important: check if the map already
* contains the id, this way the DEFAULT types are not registered twice,
* and only custom types are registered with a parent.
*/
DefaultFile.ITEM_TYPES.checkFile();
ConfigFile config = new ConfigFile("item-types");
for (String id : config.getConfig().getKeys(false))
if (!map.containsKey(id))
try {
register(new Type(this, config.getConfig().getConfigurationSection(id)));
} catch (IllegalArgumentException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + id + "': " + exception.getMessage());
}
FileConfiguration config = new ConfigFile("item-types").getConfig();
for (String id : config.getKeys(false))
if (!map.containsKey(id))
try {
register(new Type(this, config.getConfigurationSection(id)));
} catch (IllegalArgumentException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + id + "': " + exception.getMessage());
}
for (Iterator<Type> iterator = map.values().iterator(); iterator.hasNext();) {
Type type = iterator.next();
for (Iterator<Type> iterator = map.values().iterator(); iterator.hasNext(); ) {
Type type = iterator.next();
try {
type.load(config.getConfig().getConfigurationSection(type.getId()));
} catch (IllegalArgumentException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + type.getId() + "': " + exception.getMessage());
iterator.remove();
continue;
}
try {
ConfigurationSection section = config.getConfigurationSection(type.getId());
type.load(section);
if (clearBefore) type.postload(section);
} catch (RuntimeException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "Could not register type '" + type.getId() + "': " + exception.getMessage());
iterator.remove();
continue;
}
/*
* caches all the stats which the type can have to reduce future
* both item generation (and GUI) calculations. probably the thing
* which takes the most time when loading item types.
*/
type.getAvailableStats().clear();
MMOItems.plugin.getStats().getAll().stream().filter(stat -> stat.isCompatible(type)).forEach(stat -> type.getAvailableStats().add(stat));
}
}
/*
* caches all the stats which the type can have to reduce future
* both item generation (and GUI) calculations. probably the thing
* which takes the most time when loading item types.
*/
type.getAvailableStats().clear();
MMOItems.plugin.getStats().getAll().stream().filter(stat -> stat.isCompatible(type)).forEach(stat -> type.getAvailableStats().add(stat));
}
}
public void register(Type type) {
map.put(type.getId(), type);
}
public void postload() {
FileConfiguration config = new ConfigFile("item-types").getConfig();
for (Type type : map.values())
try {
type.postload(config.getConfigurationSection(type.getId()));
} catch (RuntimeException exception) {
MMOItems.plugin.getLogger().log(Level.WARNING, "An error occured while loading type '" + type.getId() + "': " + exception.getMessage());
}
}
public void registerAll(Type... types) {
for (Type type : types)
register(type);
}
public void register(Type type) {
map.put(type.getId(), type);
}
/**
* @param id Internal ID of the type
*
* @return The MMOItem Type if it found.
*/
@Nullable public Type get(@Nullable String id) {
if (id == null) { return null; }
return map.get(id);
}
public void registerAll(Type... types) {
for (Type type : types)
register(type);
}
@NotNull public Type getOrThrow(@Nullable String id) {
Validate.isTrue(map.containsKey(id), "Could not find item type with ID '" + id + "'");
return map.get(id);
}
/**
* @param id Internal ID of the type
* @return The MMOItem Type if it found.
*/
@Nullable
public Type get(@Nullable String id) {
if (id == null) {
return null;
}
return map.get(id);
}
public boolean has(String id) {
return map.containsKey(id);
}
@NotNull
public Type getOrThrow(@Nullable String id) {
Validate.isTrue(map.containsKey(id), "Could not find item type with ID '" + id + "'");
return map.get(id);
}
public Collection<Type> getAll() {
return map.values();
}
public boolean has(String id) {
return map.containsKey(id);
}
/**
* @return The names of all loaded types.
*/
public ArrayList<String> getAllTypeNames() {
ArrayList<String> ret = new ArrayList<>();
for (Type t : getAll()) { ret.add(t.getId()); }
return ret;
}
public Collection<Type> getAll() {
return map.values();
}
/**
* @return The names of all loaded types.
*/
public ArrayList<String> getAllTypeNames() {
ArrayList<String> ret = new ArrayList<>();
for (Type t : getAll()) {
ret.add(t.getId());
}
return ret;
}
}

View File

@ -13,6 +13,7 @@ import net.Indyuce.mmoitems.stat.type.StringStat;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/*
public class StaffSpiritStat extends StringStat {
public StaffSpiritStat() {
@ -92,3 +93,4 @@ public class StaffSpiritStat extends StringStat {
}
}
}
*/

View File

@ -196,7 +196,7 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
/**
* @return The stat ID
* @deprecated Use getId() instead. Type is no longer an util since they can
* now be registered from external plugins
* now be registered from external plugins
*/
@Deprecated
@NotNull
@ -214,8 +214,8 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
/**
* @return The NBT path used by the stat to save data in an item's NBTTags.
* The format is 'MMOITEMS_' followed by the stat name in capital
* letters only using _
* The format is 'MMOITEMS_' followed by the stat name in capital
* letters only using _
*/
@NotNull
public String getNBTPath() {
@ -234,6 +234,7 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
return lore;
}
@NotNull
public List<String> getCompatibleTypes() {
return compatibleTypes;
}
@ -243,10 +244,13 @@ public abstract class ItemStat<R extends RandomStatData<S>, S extends StatData>
* @return If a certain item type is compatible with this item stat
*/
public boolean isCompatible(Type type) {
String lower = type.getId().toLowerCase();
return type.isSubtype() ? isCompatible(type.getParent())
: !compatibleTypes.contains("!" + lower) && (compatibleTypes.contains("all") || compatibleTypes.contains(lower)
|| compatibleTypes.contains(type.getItemSet().getName().toLowerCase()));
// Recursive call with root types
if (type.isSubtype()) return isCompatible(type.getParent());
// Root item types
final String lower = type.getId().toLowerCase();
return !compatibleTypes.contains("!" + lower) && (compatibleTypes.contains("all") || compatibleTypes.contains(lower));
}
public boolean hasValidMaterial(ItemStack item) {

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>MMOItems</artifactId>
<groupId>net.Indyuce</groupId>
<version>6.9.5-SNAPSHOT</version>
<version>6.10-SNAPSHOT</version>
</parent>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
@ -28,7 +28,7 @@
<dependency>
<groupId>net.Indyuce</groupId>
<artifactId>MMOItems-API</artifactId>
<version>6.9.5-SNAPSHOT</version>
<version>6.10-SNAPSHOT</version>
<optional>true</optional>
</dependency>

View File

@ -5,7 +5,7 @@
<groupId>net.Indyuce</groupId>
<artifactId>MMOItems</artifactId>
<packaging>pom</packaging>
<version>6.9.5-SNAPSHOT</version>
<version>6.10-SNAPSHOT</version>
<modules>
<module>MMOItems-API</module>