diff --git a/src/main/java/net/Indyuce/mmocore/MMOCore.java b/src/main/java/net/Indyuce/mmocore/MMOCore.java index 5141e462..04096c71 100644 --- a/src/main/java/net/Indyuce/mmocore/MMOCore.java +++ b/src/main/java/net/Indyuce/mmocore/MMOCore.java @@ -10,7 +10,6 @@ import net.Indyuce.mmocore.api.PlayerActionBar; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.attribute.AttributeModifier; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.util.debug.DebugMode; import net.Indyuce.mmocore.command.*; import net.Indyuce.mmocore.comp.citizens.CitizenInteractEventListener; @@ -77,6 +76,7 @@ public class MMOCore extends LuminePlugin { public final LootChestManager lootChests = new LootChestManager(); public final MMOLoadManager loadManager = new MMOLoadManager(); public final RestrictionManager restrictionManager = new RestrictionManager(); + public final StatManager statManager = new StatManager(); @Deprecated public final SkillTreeManager skillTreeManager = new SkillTreeManager(); @@ -385,6 +385,7 @@ public class MMOCore extends LuminePlugin { configManager = new ConfigManager(); + statManager.initialize(clearBefore); if (clearBefore) MythicLib.plugin.getSkills().initialize(true); skillManager.initialize(clearBefore); @@ -414,8 +415,6 @@ public class MMOCore extends LuminePlugin { if (getConfig().isConfigurationSection("action-bar")) actionBarManager.reload(getConfig().getConfigurationSection("action-bar")); - StatType.load(); - if (clearBefore) PlayerData.getAll().forEach(PlayerData::update); } diff --git a/src/main/java/net/Indyuce/mmocore/api/PlayerActionBar.java b/src/main/java/net/Indyuce/mmocore/api/PlayerActionBar.java index 594696b3..0dbd8859 100644 --- a/src/main/java/net/Indyuce/mmocore/api/PlayerActionBar.java +++ b/src/main/java/net/Indyuce/mmocore/api/PlayerActionBar.java @@ -1,73 +1,72 @@ package net.Indyuce.mmocore.api; -import java.text.DecimalFormat; - +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerActivity; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.player.stats.StatInfo; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.attribute.Attribute; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.scheduler.BukkitRunnable; -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; -import net.md_5.bungee.api.ChatMessageType; -import net.md_5.bungee.api.chat.TextComponent; -import io.lumine.mythic.lib.MythicLib; +import java.text.DecimalFormat; public class PlayerActionBar extends BukkitRunnable { - boolean initialized = false; - - private ActionBarConfig config; - private DecimalFormat digit; - - public void reload(ConfigurationSection cfg) { - config = new ActionBarConfig(cfg); - digit = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.digit); + boolean initialized = false; - if(!initialized && config.enabled) { - runTaskTimer(MMOCore.plugin, 0, config.ticks); - initialized = true; - } - } - - public long getTimeOut() { - return config.timeout; - } + private ActionBarConfig config; + private DecimalFormat digit; - @Override - public void run() { - for (PlayerData data : PlayerData.getAll()) - if (data.isOnline() && !data.getPlayer().isDead() && !data.isCasting() && data.getActivityTimeOut(PlayerActivity.ACTION_BAR_MESSAGE) == 0) { - data.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(MMOCore.plugin.placeholderParser.parse(data.getPlayer(), - MythicLib.plugin.parseColors((data.getProfess().hasActionBar() ? data.getProfess().getActionBar() : config.format) - .replace("{health}", digit.format(data.getPlayer().getHealth())) - .replace("{max_health}", "" + StatType.MAX_HEALTH.format(data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue())) - .replace("{mana_icon}", data.getProfess().getManaDisplay().getIcon()) - .replace("{mana}", digit.format(data.getMana())) - .replace("{max_mana}", "" + StatType.MAX_MANA.format(data.getStats().getStat(StatType.MAX_MANA))) - .replace("{stamina}", digit.format(data.getStamina())) - .replace("{max_stamina}", "" + StatType.MAX_STAMINA.format(data.getStats().getStat(StatType.MAX_STAMINA))) - .replace("{stellium}", digit.format(data.getStellium())) - .replace("{max_stellium}", "" + StatType.MAX_STELLIUM.format(data.getStats().getStat(StatType.MAX_STELLIUM))) - .replace("{class}", data.getProfess().getName()) - .replace("{xp}", "" + data.getExperience()) - .replace("{armor}", "" + StatType.ARMOR.format(data.getPlayer().getAttribute(Attribute.GENERIC_ARMOR).getValue())) - .replace("{level}", "" + data.getLevel()) - .replace("{name}", data.getPlayer().getDisplayName()))))); - } - } - - private static class ActionBarConfig { - private final boolean enabled; - private final int ticks, timeout; - private final String digit, format; - - private ActionBarConfig(ConfigurationSection config) { - enabled = config.getBoolean("enabled", false); - timeout = config.getInt("", 60); - digit = config.getString("decimal", "0.#"); - ticks = config.getInt("ticks-to-update", 5); - format = config.getString("format", "please format me :c"); - } - } + public void reload(ConfigurationSection cfg) { + config = new ActionBarConfig(cfg); + digit = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.digit); + + if (!initialized && config.enabled) { + runTaskTimer(MMOCore.plugin, 0, config.ticks); + initialized = true; + } + } + + public long getTimeOut() { + return config.timeout; + } + + @Override + public void run() { + for (PlayerData data : PlayerData.getAll()) + if (data.isOnline() && !data.getPlayer().isDead() && !data.isCasting() && data.getActivityTimeOut(PlayerActivity.ACTION_BAR_MESSAGE) == 0) { + data.getPlayer().spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(MMOCore.plugin.placeholderParser.parse(data.getPlayer(), + MythicLib.plugin.parseColors((data.getProfess().hasActionBar() ? data.getProfess().getActionBar() : config.format) + .replace("{health}", digit.format(data.getPlayer().getHealth())) + .replace("{max_health}", StatInfo.valueOf("MAX_HEALTH").format(data.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue())) + .replace("{mana_icon}", data.getProfess().getManaDisplay().getIcon()) + .replace("{mana}", digit.format(data.getMana())) + .replace("{max_mana}", StatInfo.valueOf("MAX_MANA").format(data.getStats().getStat("MAX_MANA"))) + .replace("{stamina}", digit.format(data.getStamina())) + .replace("{max_stamina}", StatInfo.valueOf("MAX_STAMINA").format(data.getStats().getStat("MAX_STAMINA"))) + .replace("{stellium}", digit.format(data.getStellium())) + .replace("{max_stellium}", StatInfo.valueOf("MAX_STELLIUM").format(data.getStats().getStat("MAX_STELLIUM"))) + .replace("{class}", data.getProfess().getName()) + .replace("{xp}", "" + data.getExperience()) + .replace("{armor}", StatInfo.valueOf("ARMOR").format(data.getPlayer().getAttribute(Attribute.GENERIC_ARMOR).getValue())) + .replace("{level}", "" + data.getLevel()) + .replace("{name}", data.getPlayer().getDisplayName()))))); + } + } + + private static class ActionBarConfig { + private final boolean enabled; + private final int ticks, timeout; + private final String digit, format; + + private ActionBarConfig(ConfigurationSection config) { + enabled = config.getBoolean("enabled", false); + timeout = config.getInt("", 60); + digit = config.getString("decimal", "0.#"); + ticks = config.getInt("ticks-to-update", 5); + format = config.getString("format", "please format me :c"); + } + } } diff --git a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index 8b01f622..8713d21f 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -17,7 +17,6 @@ import net.Indyuce.mmocore.api.player.profess.Subclass; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; import net.Indyuce.mmocore.api.player.social.FriendRequest; import net.Indyuce.mmocore.api.player.stats.PlayerStats; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.api.util.Closable; import net.Indyuce.mmocore.api.util.MMOCoreUtils; @@ -542,7 +541,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc } value = MMOCore.plugin.boosterManager.calculateExp(null, value); - value *= 1 + getStats().getStat(StatType.ADDITIONAL_EXPERIENCE) / 100; + value *= 1 + getStats().getStat("ADDITIONAL_EXPERIENCE") / 100; // Splitting exp through party members AbstractParty party = getParty(); @@ -615,7 +614,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc public void giveMana(double amount, PlayerResourceUpdateEvent.UpdateReason reason) { // Avoid calling useless event - double max = getStats().getStat(StatType.MAX_MANA); + double max = getStats().getStat("MAX_MANA"); double newest = Math.max(0, Math.min(mana + amount, max)); if (mana == newest) return; @@ -640,7 +639,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc public void giveStamina(double amount, PlayerResourceUpdateEvent.UpdateReason reason) { // Avoid calling useless event - double max = getStats().getStat(StatType.MAX_STAMINA); + double max = getStats().getStat("MAX_STAMINA"); double newest = Math.max(0, Math.min(stamina + amount, max)); if (stamina == newest) return; @@ -665,7 +664,7 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc public void giveStellium(double amount, PlayerResourceUpdateEvent.UpdateReason reason) { // Avoid calling useless event - double max = getStats().getStat(StatType.MAX_STELLIUM); + double max = getStats().getStat("MAX_STELLIUM"); double newest = Math.max(0, Math.min(stellium + amount, max)); if (stellium == newest) return; @@ -700,15 +699,15 @@ public class PlayerData extends OfflinePlayerData implements Closable, Experienc } public void setMana(double amount) { - mana = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_MANA))); + mana = Math.max(0, Math.min(amount, getStats().getStat("MAX_MANA"))); } public void setStamina(double amount) { - stamina = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STAMINA))); + stamina = Math.max(0, Math.min(amount, getStats().getStat("MAX_STAMINA"))); } public void setStellium(double amount) { - stellium = Math.max(0, Math.min(amount, getStats().getStat(StatType.MAX_STELLIUM))); + stellium = Math.max(0, Math.min(amount, getStats().getStat("MAX_STELLIUM"))); } public boolean isFullyLoaded() { diff --git a/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java b/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java index 62352c55..af2f7ad5 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java @@ -25,8 +25,8 @@ public class PlayerAttribute implements ExperienceObject { private final ExperienceTable expTable; /** - * Used to store stats using StatType, but attributes also need to access - * non basic MMOCore stats hence the string maps keys + * All buffs granted by an attribute. These are normalized and + * must be multiplied by the player level first */ private final Set buffs = new HashSet<>(); diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java index cbd9dcc4..eb1fc759 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java @@ -13,17 +13,17 @@ import net.Indyuce.mmocore.api.player.profess.event.EventTrigger; import net.Indyuce.mmocore.api.player.profess.resource.ManaDisplayOptions; import net.Indyuce.mmocore.api.player.profess.resource.PlayerResource; import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.experience.EXPSource; -import net.Indyuce.mmocore.loot.chest.particle.CastingParticle; import net.Indyuce.mmocore.experience.ExpCurve; import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.source.type.ExperienceSource; +import net.Indyuce.mmocore.loot.chest.particle.CastingParticle; import net.Indyuce.mmocore.player.playerclass.ClassTrigger; import net.Indyuce.mmocore.player.playerclass.ClassTriggerType; +import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.skill.ClassSkill; import net.Indyuce.mmocore.skill.RegisteredSkill; import net.md_5.bungee.api.ChatColor; @@ -51,7 +51,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { private final ExpCurve expCurve; private final ExperienceTable expTable; - private final Map stats = new HashMap<>(); + private final Map stats = new HashMap<>(); private final Map skills = new LinkedHashMap<>(); private final List subclasses = new ArrayList<>(); @@ -124,7 +124,7 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { if (config.contains("attributes")) for (String key : config.getConfigurationSection("attributes").getKeys(false)) try { - stats.put(StatType.valueOf(key.toUpperCase().replace("-", "_")), + stats.put(UtilityMethods.enumName(key), new LinearValue(config.getConfigurationSection("attributes." + key))); } catch (IllegalArgumentException exception) { MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load stat info '" + key + "' from class '" @@ -331,16 +331,11 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { return eventTriggers.get(name); } - @Deprecated - public void setStat(StatType type, double base, double perLevel) { - setStat(type, new LinearValue(base, perLevel)); + public void setDefaultStatFormula(String type, LinearValue value) { + stats.put(UtilityMethods.enumName(type), value); } - public void setStat(StatType type, LinearValue value) { - stats.put(type, value); - } - - public double calculateStat(StatType stat, int level) { + public double calculateStat(String stat, int level) { return getStatInfo(stat).calculate(level); } @@ -396,8 +391,10 @@ public class PlayerClass extends PostLoadObject implements ExperienceObject { return skills.values(); } - private LinearValue getStatInfo(StatType type) { - return stats.containsKey(type) ? stats.get(type) : type.getDefault(); + @NotNull + private LinearValue getStatInfo(String stat) { + LinearValue found = stats.get(stat); + return found == null ? StatInfo.valueOf(stat).getDefaultFormula() : found; } @Override diff --git a/src/main/java/net/Indyuce/mmocore/api/player/profess/resource/PlayerResource.java b/src/main/java/net/Indyuce/mmocore/api/player/profess/resource/PlayerResource.java index fcbec451..56aeb9b5 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/profess/resource/PlayerResource.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/profess/resource/PlayerResource.java @@ -3,7 +3,6 @@ package net.Indyuce.mmocore.api.player.profess.resource; import net.Indyuce.mmocore.api.event.PlayerResourceUpdateEvent; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.profess.ClassOption; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.quest.trigger.ManaTrigger; import org.bukkit.attribute.Attribute; @@ -20,27 +19,27 @@ public enum PlayerResource { (data, amount) -> data.getPlayer().setHealth(amount)), MANA(PlayerData::getMana, - data -> data.getStats().getStat(StatType.MAX_MANA), + data -> data.getStats().getStat("MAX_MANA"), (data, amount) -> data.giveMana(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION), (data, amount) -> data.giveMana(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.giveMana(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.setMana(amount)), STAMINA(PlayerData::getStamina, - data -> data.getStats().getStat(StatType.MAX_STAMINA), + data -> data.getStats().getStat("MAX_STAMINA"), (data, amount) -> data.giveStamina(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION), (data, amount) -> data.giveStamina(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.giveStamina(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.setStamina(amount)), STELLIUM(PlayerData::getStellium, - data -> data.getStats().getStat(StatType.MAX_STELLIUM), + data -> data.getStats().getStat("MAX_STELLIUM"), (data, amount) -> data.giveStellium(amount, PlayerResourceUpdateEvent.UpdateReason.REGENERATION), (data, amount) -> data.giveStellium(amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.giveStellium(-amount, PlayerResourceUpdateEvent.UpdateReason.COMMAND), (data, amount) -> data.setStellium(amount)); - private final StatType regenStat, maxRegenStat; + private final String regenStat, maxRegenStat; private final ClassOption offCombatRegen; private final Function current, max; private final BiConsumer regen; @@ -54,8 +53,8 @@ public enum PlayerResource { BiConsumer give, BiConsumer take, BiConsumer set) { - this.regenStat = StatType.valueOf(name() + "_REGENERATION"); - this.maxRegenStat = StatType.valueOf("MAX_" + name() + "_REGENERATION"); + this.regenStat = name() + "_REGENERATION"; + this.maxRegenStat = "MAX_" + name() + "_REGENERATION"; this.offCombatRegen = ClassOption.valueOf("OFF_COMBAT_" + name() + "_REGEN"); this.current = current; this.max = max; @@ -68,14 +67,14 @@ public enum PlayerResource { /** * @return Stat which corresponds to flat resource regeneration */ - public StatType getRegenStat() { + public String getRegenStat() { return regenStat; } /** * @return Stat which corresponds to resource regeneration scaling with the player's max health */ - public StatType getMaxRegenStat() { + public String getMaxRegenStat() { return maxRegenStat; } diff --git a/src/main/java/net/Indyuce/mmocore/api/player/stats/PlayerStats.java b/src/main/java/net/Indyuce/mmocore/api/player/stats/PlayerStats.java index be0912c7..0682683c 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/stats/PlayerStats.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/stats/PlayerStats.java @@ -8,17 +8,14 @@ import io.lumine.mythic.lib.player.modifier.ModifierSource; import io.lumine.mythic.lib.player.modifier.ModifierType; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.experience.Profession; +import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.skill.ClassSkill; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Locale; public class PlayerStats { private final PlayerData data; /** - * Utilclass to easily manipulate the MMOLib stat map + * Util class to easily manipulate the MMOLib stat map * * @param data Playerdata */ @@ -34,6 +31,7 @@ public class PlayerStats { return data.getMMOPlayerData().getStatMap(); } + @Deprecated public StatInstance getInstance(StatType stat) { return getMap().getInstance(stat.name()); } @@ -42,35 +40,26 @@ public class PlayerStats { return getMap().getInstance(stat); } - /** - * Allows for stat type enum to have dynamic professions. - * ID FORMAT: STAT_TYPE_HERE_PROFESSION_HERE - * - * @param type the type of stat - * @param profession the stat's specific permission - * @return instance of found stat - * @author Ehhthan - */ - @NotNull - public StatInstance getInstance(StatType type, @Nullable Profession profession) { - if (profession == null) - return getInstance(type); - else { - String id = (type.name() + '_' + profession.getId()).replace('-', '_').replace(' ', '_').toUpperCase(Locale.ROOT); - return getInstance(id); - } - } - - /* - * applies relative attributes on the base stat too - */ - public double getStat(StatType stat) { + public double getStat(String stat) { return getInstance(stat).getTotal(); } - public double getBase(StatType stat) { - return data.getProfess().calculateStat(stat, - stat.hasProfession() ? data.getCollectionSkills().getLevel(stat.getProfession()) : data.getLevel()); + /** + * MMOCore base stat value differs from the on in MythicLib. + *

+ * MythicLib: the base stat value is only defined for stats + * which are based on vanilla player attributes. It corresponds + * to the stat amount any player has with NO attribute modifier whatsoever. + *

+ * MMOCore: the base stat value corresponds to the stat amount + * the player CLASS grants. It can be similar or equal to the one + * in MMOCore but it really is completely different. + * + * @return MMOCore base stat value + */ + public double getBase(String stat) { + Profession profession = StatInfo.valueOf(stat).profession; + return data.getProfess().calculateStat(stat, profession == null ? data.getLevel() : data.getCollectionSkills().getLevel(profession)); } /** @@ -81,7 +70,7 @@ public class PlayerStats { * see {@link PlayerData#update()} for more info */ public synchronized void updateStats() { - for (StatType stat : StatType.values()) { + for (StatType stat : StatType.values()) { // TODO fix StatInstance instance = getMap().getInstance(stat.name()); StatInstance.ModifierPacket packet = instance.newPacket(); @@ -89,7 +78,7 @@ public class PlayerStats { packet.removeIf(str -> str.equals("mmocoreClass")); // Add newest one - double total = getBase(stat) - instance.getBase(); + double total = getBase(stat.name()) - instance.getBase(); if (total != 0) packet.addModifier(new StatModifier("mmocoreClass", stat.name(), total, ModifierType.FLAT, EquipmentSlot.OTHER, ModifierSource.OTHER)); diff --git a/src/main/java/net/Indyuce/mmocore/api/player/stats/StatType.java b/src/main/java/net/Indyuce/mmocore/api/player/stats/StatType.java index 9f66f9bf..6adbde42 100644 --- a/src/main/java/net/Indyuce/mmocore/api/player/stats/StatType.java +++ b/src/main/java/net/Indyuce/mmocore/api/player/stats/StatType.java @@ -1,14 +1,14 @@ package net.Indyuce.mmocore.api.player.stats; -import io.lumine.mythic.lib.MythicLib; -import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.ConfigFile; import net.Indyuce.mmocore.api.util.math.formula.LinearValue; import net.Indyuce.mmocore.experience.Profession; -import org.bukkit.configuration.file.FileConfiguration; +import net.Indyuce.mmocore.player.stats.StatInfo; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; -import java.text.DecimalFormat; +import java.util.Objects; +@Deprecated public enum StatType { // Vanilla stats @@ -87,17 +87,17 @@ public enum StatType { /** * Reduces amount of tugs needed to fish */ - FISHING_STRENGTH("fishing"), + FISHING_STRENGTH, /** * Chance of instant success when fishing */ - CRITICAL_FISHING_CHANCE("fishing"), + CRITICAL_FISHING_CHANCE, /** * Chance of crit fishing failure */ - CRITICAL_FISHING_FAILURE_CHANCE("fishing"), + CRITICAL_FISHING_FAILURE_CHANCE, /** * Chance of dropping more minerals when mining. @@ -114,49 +114,35 @@ public enum StatType { */ LUCK_OF_THE_FIELD; - private String profession; - - private LinearValue defaultInfo; - private DecimalFormat format; - - StatType() { - // Completely custom stat - } - - @SuppressWarnings("SameParameterValue") - StatType(String profession) { - this.profession = profession; - } - + @Deprecated public String getProfession() { - return profession; + return findProfession().getId(); } + @Deprecated + @Nullable public Profession findProfession() { - return MMOCore.plugin.professionManager.get(profession); + return StatInfo.valueOf(name()).profession; } + @Deprecated public boolean hasProfession() { - return profession != null; + return findProfession() != null; } + @Deprecated + @NotNull public LinearValue getDefault() { - return defaultInfo; + return StatInfo.valueOf(name()).getDefaultFormula(); } + @Deprecated public boolean matches(Profession profession) { - return this.profession != null && this.profession.equals(profession.getId()); + return Objects.equals(findProfession(), profession); } + @Deprecated public String format(double value) { - return format.format(value); - } - - public static void load() { - FileConfiguration config = new ConfigFile("stats").getConfig(); - for (StatType stat : values()) { - stat.defaultInfo = config.contains("default." + stat.name()) ? new LinearValue(config.getConfigurationSection("default." + stat.name())) : new LinearValue(0, 0); - stat.format = MythicLib.plugin.getMMOConfig().newDecimalFormat(config.contains("decimal-format." + stat.name()) ? config.getString("decimal-format." + stat.name()) : "0.#"); - } + return StatInfo.valueOf(name()).format(value); } } diff --git a/src/main/java/net/Indyuce/mmocore/api/util/math/formula/LinearValue.java b/src/main/java/net/Indyuce/mmocore/api/util/math/formula/LinearValue.java index 5bd0d5ef..972bf5b2 100644 --- a/src/main/java/net/Indyuce/mmocore/api/util/math/formula/LinearValue.java +++ b/src/main/java/net/Indyuce/mmocore/api/util/math/formula/LinearValue.java @@ -110,4 +110,16 @@ public class LinearValue { return value; } + + @Override + public String toString() { + return "LinearValue{" + + "base=" + base + + ", perLevel=" + perLevel + + ", min=" + min + + ", max=" + max + + ", hasmin=" + hasmin + + ", hasmax=" + hasmax + + '}'; + } } diff --git a/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatModifiersCommandTreeNode.java b/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatModifiersCommandTreeNode.java index 38de283c..d440e4ee 100644 --- a/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatModifiersCommandTreeNode.java +++ b/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatModifiersCommandTreeNode.java @@ -1,11 +1,11 @@ package net.Indyuce.mmocore.command.rpg.debug; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.api.stat.StatInstance; import io.lumine.mythic.lib.api.stat.modifier.StatModifier; import io.lumine.mythic.lib.command.api.CommandTreeNode; import io.lumine.mythic.lib.command.api.Parameter; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -15,10 +15,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode { public StatModifiersCommandTreeNode(CommandTreeNode parent) { super(parent, "statmods"); - addParameter(new Parameter("", (explorer, list) -> { - for (StatType stat : StatType.values()) - list.add(stat.name()); - })); + addParameter(new Parameter("", (explorer, list) -> list.add("STAT_ID"))); } @Override @@ -32,15 +29,7 @@ public class StatModifiersCommandTreeNode extends CommandTreeNode { } PlayerData data = PlayerData.get((Player) sender); - StatType stat; - try { - stat = StatType.valueOf(args[2].toUpperCase().replace("-", "_").replace(" ", "_")); - } catch (IllegalArgumentException exception) { - sender.sendMessage(ChatColor.RED + "Could not find stat: " + args[2] + "."); - return CommandResult.FAILURE; - } - - StatInstance instance = data.getStats().getInstance(stat); + StatInstance instance = data.getStats().getInstance(UtilityMethods.enumName(args[2])); sender.sendMessage("Stat Modifiers (" + instance.getKeys().size() + "):"); for (String key : instance.getKeys()) { StatModifier mod = instance.getModifier(key); diff --git a/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatValueCommandTreeNode.java b/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatValueCommandTreeNode.java index f13d42a4..f582ab31 100644 --- a/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatValueCommandTreeNode.java +++ b/src/main/java/net/Indyuce/mmocore/command/rpg/debug/StatValueCommandTreeNode.java @@ -1,51 +1,36 @@ package net.Indyuce.mmocore.command.rpg.debug; +import io.lumine.mythic.lib.UtilityMethods; +import io.lumine.mythic.lib.command.api.CommandTreeNode; +import io.lumine.mythic.lib.command.api.Parameter; +import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.player.stats.StatInfo; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; -import io.lumine.mythic.lib.command.api.CommandTreeNode; -import io.lumine.mythic.lib.command.api.Parameter; - public class StatValueCommandTreeNode extends CommandTreeNode { - public StatValueCommandTreeNode(CommandTreeNode parent) { - super(parent, "statvalue"); + public StatValueCommandTreeNode(CommandTreeNode parent) { + super(parent, "statvalue"); - addParameter(new Parameter("", (explorer, list) -> { - for (StatType stat : StatType.values()) - list.add(stat.name()); - })); - addParameter(new Parameter("(formatted)", (explorer, list) -> list.add("true"))); - } + addParameter(new Parameter("", (explorer, list) -> list.add("STAT_ID"))); + } - @Override - public CommandResult execute(CommandSender sender, String[] args) { - if (args.length < 3) - return CommandResult.THROW_USAGE; + @Override + public CommandResult execute(CommandSender sender, String[] args) { + if (args.length < 3) + return CommandResult.THROW_USAGE; - if (!(sender instanceof Player)) { - sender.sendMessage(ChatColor.RED + "This command can only be used by a player."); - return CommandResult.FAILURE; - } - PlayerData data = PlayerData.get((Player) sender); + if (!(sender instanceof Player)) { + sender.sendMessage(ChatColor.RED + "This command can only be used by a player."); + return CommandResult.FAILURE; + } + PlayerData data = PlayerData.get((Player) sender); - StatType stat; - try { - stat = StatType.valueOf(args[2].toUpperCase().replace("-", "_").replace(" ", "_")); - } catch (IllegalArgumentException exception) { - sender.sendMessage(ChatColor.RED + "Could not find stat: " + args[2] + "."); - return CommandResult.FAILURE; - } + StatInfo stat = StatInfo.valueOf(UtilityMethods.enumName(args[2])); + sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name + ChatColor.WHITE + "): " + + ChatColor.GREEN + data.getStats().getStat(stat.name)); - if (args.length > 3 && args[3].equals("true")) - sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name() + ChatColor.WHITE + "): " - + ChatColor.GREEN + stat.format(data.getStats().getStat(stat)) + ChatColor.WHITE + " *"); - else - sender.sendMessage(DebugCommandTreeNode.commandPrefix + "Stat Value (" + ChatColor.BLUE + stat.name() + ChatColor.WHITE + "): " - + ChatColor.GREEN + data.getStats().getStat(stat)); - - return CommandResult.SUCCESS; - } + return CommandResult.SUCCESS; + } } diff --git a/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java b/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java index dd9e3433..795ac3a1 100644 --- a/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java +++ b/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java @@ -5,7 +5,7 @@ import io.lumine.mythic.lib.api.util.AltChar; import me.clip.placeholderapi.expansion.PlaceholderExpansion; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; +import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.api.quest.PlayerQuests; import net.Indyuce.mmocore.experience.PlayerProfessions; import net.Indyuce.mmocore.experience.Profession; @@ -72,11 +72,11 @@ public class RPGPlaceholders extends PlaceholderExpansion { } else if (identifier.equals("health") && player.isOnline()) { - return StatType.MAX_HEALTH.format(player.getPlayer().getHealth()); + return StatInfo.valueOf("MAX_HEALTH").format(player.getPlayer().getHealth()); } else if (identifier.equals("max_health") && player.isOnline()) { - return StatType.MAX_HEALTH.format(player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); + return StatInfo.valueOf("MAX_HEALTH").format(player.getPlayer().getAttribute(Attribute.GENERIC_MAX_HEALTH).getValue()); } else if (identifier.equals("health_bar") && player.isOnline()) { @@ -153,7 +153,7 @@ public class RPGPlaceholders extends PlaceholderExpansion { return MythicLib.plugin.getMMOConfig().decimal.format(playerData.getMana()); else if (identifier.equals("mana_bar")) { - return playerData.getProfess().getManaDisplay().generateBar(playerData.getMana(), playerData.getStats().getStat(StatType.MAX_MANA)); + return playerData.getProfess().getManaDisplay().generateBar(playerData.getMana(), playerData.getStats().getStat("MAX_MANA")); } else if (identifier.startsWith("exp_multiplier_")) { @@ -173,7 +173,7 @@ public class RPGPlaceholders extends PlaceholderExpansion { else if (identifier.equals("stamina_bar")) { StringBuilder format = new StringBuilder(); - double ratio = 20 * playerData.getStamina() / playerData.getStats().getStat(StatType.MAX_STAMINA); + double ratio = 20 * playerData.getStamina() / playerData.getStats().getStat("MAX_STAMINA"); for (double j = 1; j < 20; j++) format.append(ratio >= j ? MMOCore.plugin.configManager.staminaFull : ratio >= j - .5 ? MMOCore.plugin.configManager.staminaHalf : MMOCore.plugin.configManager.staminaEmpty) @@ -182,8 +182,8 @@ public class RPGPlaceholders extends PlaceholderExpansion { } else if (identifier.startsWith("stat_")) { - StatType type = StatType.valueOf(identifier.substring(5).toUpperCase()); - return type == null ? "Invalid Stat" : type.format(playerData.getStats().getStat(type)); + StatInfo info = StatInfo.valueOf(identifier.substring(5).toUpperCase()); + return info.format(playerData.getStats().getStat(info.name)); } else if (identifier.equals("stellium")) @@ -191,7 +191,7 @@ public class RPGPlaceholders extends PlaceholderExpansion { else if (identifier.equals("stellium_bar")) { StringBuilder format = new StringBuilder(); - double ratio = 20 * playerData.getStellium() / playerData.getStats().getStat(StatType.MAX_STELLIUM); + double ratio = 20 * playerData.getStellium() / playerData.getStats().getStat("MAX_STELLIUM"); for (double j = 1; j < 20; j++) format.append(ratio >= j ? ChatColor.BLUE : ratio >= j - .5 ? ChatColor.AQUA : ChatColor.WHITE).append(AltChar.listSquare); return format.toString(); diff --git a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java index 2caddb5b..44f3552c 100644 --- a/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java +++ b/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java @@ -4,13 +4,13 @@ import com.google.gson.Gson; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.UtilityMethods; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.ConfigMessage; import net.Indyuce.mmocore.api.SoundEvent; import net.Indyuce.mmocore.api.event.PlayerExperienceGainEvent; import net.Indyuce.mmocore.api.event.PlayerLevelUpEvent; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import org.apache.commons.lang.Validate; @@ -168,7 +168,7 @@ public class PlayerProfessions { value = MMOCore.plugin.boosterManager.calculateExp(profession, value); // Adds functionality for additional experience per profession. - value *= 1 + playerData.getStats().getInstance(StatType.ADDITIONAL_EXPERIENCE, profession).getTotal() / 100; + value *= 1 + playerData.getStats().getInstance("ADDITIONAL_EXPERIENCE_" + UtilityMethods.enumName(profession.getId())).getTotal() / 100; // Display hologram if (hologramLocation != null) diff --git a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java index 49e74717..058694a8 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java +++ b/src/main/java/net/Indyuce/mmocore/gui/AttributeView.java @@ -13,6 +13,7 @@ import net.Indyuce.mmocore.gui.api.item.InventoryItem; import net.Indyuce.mmocore.gui.api.item.Placeholders; import net.Indyuce.mmocore.gui.api.item.SimplePlaceholderItem; import net.Indyuce.mmocore.manager.SoundManager; +import net.Indyuce.mmocore.player.stats.StatInfo; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.event.inventory.InventoryClickEvent; @@ -66,8 +67,9 @@ public class AttributeView extends EditableInventory { holders.register("current", total); holders.register("attribute_points", inv.getPlayerData().getAttributePoints()); attribute.getBuffs().forEach(buff -> { - holders.register("buff_" + buff.getStat().toLowerCase(), buff.getValue()); - holders.register("total_" + buff.getStat().toLowerCase(), buff.multiply(total).getValue()); + StatInfo info = StatInfo.valueOf(buff.getStat()); + holders.register("buff_" + buff.getStat().toLowerCase(), info.format(buff.getValue())); + holders.register("total_" + buff.getStat().toLowerCase(), info.format(buff.multiply(total).getValue())); }); return holders; } diff --git a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java index 0a870c26..63759744 100644 --- a/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java +++ b/src/main/java/net/Indyuce/mmocore/gui/PlayerStats.java @@ -1,14 +1,15 @@ package net.Indyuce.mmocore.gui; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.api.stat.modifier.StatModifier; import io.lumine.mythic.lib.version.VersionMaterial; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.experience.Booster; -import net.Indyuce.mmocore.experience.Profession; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; -import net.Indyuce.mmocore.api.player.stats.StatType; +import net.Indyuce.mmocore.player.stats.StatInfo; import net.Indyuce.mmocore.api.util.math.format.DelayFormat; +import net.Indyuce.mmocore.experience.Booster; +import net.Indyuce.mmocore.experience.Profession; import net.Indyuce.mmocore.gui.api.EditableInventory; import net.Indyuce.mmocore.gui.api.GeneratedInventory; import net.Indyuce.mmocore.gui.api.item.InventoryItem; @@ -18,10 +19,13 @@ import net.Indyuce.mmocore.party.AbstractParty; import org.apache.commons.lang.Validate; import org.bukkit.ChatColor; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.meta.SkullMeta; +import java.util.Objects; + public class PlayerStats extends EditableInventory { public PlayerStats() { super("player-stats"); @@ -78,7 +82,7 @@ public class PlayerStats extends EditableInventory { Placeholders holders = new Placeholders(); net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats(); - double ratio = (double) inv.getPlayerData().getCollectionSkills().getExperience(profession) + double ratio = inv.getPlayerData().getCollectionSkills().getExperience(profession) / (double) inv.getPlayerData().getCollectionSkills().getLevelUpExperience(profession); String bar = "" + ChatColor.BOLD; @@ -91,9 +95,9 @@ public class PlayerStats extends EditableInventory { holders.register("level", "" + inv.getPlayerData().getCollectionSkills().getLevel(profession)); holders.register("xp", inv.getPlayerData().getCollectionSkills().getExperience(profession)); holders.register("percent", decimal.format(ratio * 100)); - for (StatType stat : StatType.values()) - if (stat.matches(profession)) - holders.register(stat.name().toLowerCase(), stat.format(stats.getStat(stat))); + for (StatInfo stat : MMOCore.plugin.statManager.getLoaded()) + if (Objects.equals(stat.profession, profession)) + holders.register(stat.name.toLowerCase(), stat.format(stats.getStat(stat.name))); return holders; } @@ -113,21 +117,35 @@ public class PlayerStats extends EditableInventory { @Override public Placeholders getPlaceholders(GeneratedInventory inv, int n) { + return new Placeholders() { + final net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats(); - net.Indyuce.mmocore.api.player.stats.PlayerStats stats = inv.getPlayerData().getStats(); - Placeholders holders = new Placeholders(); + public String apply(Player player, String str) { + while (str.contains("{") && str.substring(str.indexOf("{")).contains("}")) { + String holder = str.substring(str.indexOf("{") + 1, str.indexOf("}")); + String replaced; - for (StatType stat : StatType.values()) { - double base = stats.getBase(stat), total = stats.getStat(stat), extra = total - base; - holders.register(stat.name().toLowerCase(), stat.format(total)); - holders.register(stat.name().toLowerCase() + "_base", stat.format(base)); - holders.register(stat.name().toLowerCase() + "_extra", stat.format(extra)); - } + if (holder.endsWith("_base")) { + StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder.substring(0, holder.length() - 5))); + replaced = info.format(stats.getBase(info.name)); + } else if (holder.endsWith("_extra")) { + StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder.substring(0, holder.length() - 5))); + replaced = info.format(stats.getStat(info.name) - stats.getBase(info.name)); + } else if (holder.startsWith("attribute_")) { + PlayerAttribute attr = MMOCore.plugin.attributeManager.get(holder.substring(10).replace("_", "-").toLowerCase()); + replaced = String.valueOf(inv.getPlayerData().getAttributes().getAttribute(attr)); + } else { + StatInfo info = StatInfo.valueOf(UtilityMethods.enumName(holder)); + replaced = info.format(stats.getStat(info.name)); + } - for (PlayerAttribute attribute : MMOCore.plugin.attributeManager.getAll()) - holders.register("attribute_" + attribute.getId().replace("-", "_"), inv.getPlayerData().getAttributes().getAttribute(attribute)); + str = str.replace("{" + holder + "}", replaced); + } - return holders; + // External placeholders + return MMOCore.plugin.placeholderParser.parse(player, str); + } + }; } }; diff --git a/src/main/java/net/Indyuce/mmocore/listener/profession/FishingListener.java b/src/main/java/net/Indyuce/mmocore/listener/profession/FishingListener.java index fe678f07..50c1405c 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/profession/FishingListener.java +++ b/src/main/java/net/Indyuce/mmocore/listener/profession/FishingListener.java @@ -4,7 +4,6 @@ import io.lumine.mythic.lib.version.VersionSound; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.event.CustomPlayerFishEvent; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.api.util.MMOCoreUtils; import net.Indyuce.mmocore.experience.EXPSource; import net.Indyuce.mmocore.loot.LootBuilder; @@ -84,7 +83,7 @@ public class FishingListener implements Listener { this.playerData = PlayerData.get(this.player = player); this.hook = hook; - this.fishStrength = (int) Math.floor(caught.rollTugs() * (1 - PlayerData.get(player).getStats().getStat(StatType.FISHING_STRENGTH) / 100)); + this.fishStrength = (int) Math.floor(caught.rollTugs() * (1 - PlayerData.get(player).getStats().getStat("FISHING_STRENGTH") / 100)); this.experienceDropped = caught.rollExperience(); fishing.add(player.getUniqueId()); @@ -148,7 +147,7 @@ public class FishingListener implements Listener { return; } - if (currentPulls == 0 && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat(StatType.CRITICAL_FISHING_CHANCE) / 100) + if (currentPulls == 0 && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat("CRITICAL_FISHING_CHANCE") / 100) setCriticalFish(); // Check if enough pulls; if not, wait till the next fish event @@ -165,7 +164,7 @@ public class FishingListener implements Listener { (mainhand != null && mainhand.getType() == Material.FISHING_ROD) ? EquipmentSlot.HAND : EquipmentSlot.OFF_HAND, 1); // Critical fishing failure - if (!isCriticalFish() && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat(StatType.CRITICAL_FISHING_FAILURE_CHANCE) / 100) { + if (!isCriticalFish() && RANDOM.nextDouble() < PlayerData.get(player).getStats().getStat("CRITICAL_FISHING_FAILURE_CHANCE") / 100) { player.setVelocity(hook.getLocation().subtract(player.getLocation()).toVector().setY(0).multiply(3).setY(.5)); hook.getWorld().spawnParticle(Particle.SMOKE_NORMAL, location, 24, 0, 0, 0, .08); return; diff --git a/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java b/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java index ce81b963..795d6ed7 100644 --- a/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java +++ b/src/main/java/net/Indyuce/mmocore/listener/profession/PlayerCollectStats.java @@ -1,7 +1,8 @@ package net.Indyuce.mmocore.listener.profession; -import java.util.Random; - +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.api.event.CustomBlockMineEvent; +import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; import org.bukkit.Location; import org.bukkit.Particle; import org.bukkit.entity.Player; @@ -11,10 +12,7 @@ import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import net.Indyuce.mmocore.api.event.CustomBlockMineEvent; -import net.Indyuce.mmocore.api.player.stats.StatType; -import net.Indyuce.mmocore.loot.chest.particle.SmallParticleEffect; -import io.lumine.mythic.lib.MythicLib; +import java.util.Random; public class PlayerCollectStats implements Listener { private static final Random random = new Random(); @@ -23,26 +21,26 @@ public class PlayerCollectStats implements Listener { public void a(CustomBlockMineEvent event) { Player player = event.getPlayer(); - // give haste if right enchant - double h = event.getData().getStats().getStat(StatType.GATHERING_HASTE); + // Give haste if right enchant + double h = event.getData().getStats().getStat("GATHERING_HASTE"); if (h > 0 && random.nextDouble() < h * .045) { new SmallParticleEffect(player, Particle.SPELL_INSTANT); player.removePotionEffect(PotionEffectType.FAST_DIGGING); player.addPotionEffect(new PotionEffect(PotionEffectType.FAST_DIGGING, (int) (10 * h), (int) (1 + h / 7))); } - // drop more items if fortune enchant - double f = event.getData().getStats().getStat(StatType.FORTUNE); + // Drop more items if fortune enchant + double f = event.getData().getStats().getStat("FORTUNE"); if (f > 0 && random.nextDouble() < f * .045) { int a = (int) (1.5 * Math.sqrt(f / 1.1)); for (ItemStack item : event.getDrops()) item.setAmount(item.getAmount() + a); } - if(MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock())) - { - // drop more items if fortune enchant - double l = event.getData().getStats().getStat(StatType.LUCK_OF_THE_FIELD); + if (MythicLib.plugin.getVersion().getWrapper().isCropFullyGrown(event.getBlock())) { + + // Drop more CROP items + double l = event.getData().getStats().getStat("LUCK_OF_THE_FIELD"); if (l > 0 && random.nextDouble() < l * .045) { int a = (int) (1.5 * Math.sqrt(l / 1.1)); Location loc = event.getBlock().getLocation().add(.5, .1, .5); diff --git a/src/main/java/net/Indyuce/mmocore/loot/chest/LootChestRegion.java b/src/main/java/net/Indyuce/mmocore/loot/chest/LootChestRegion.java index 6f455b3e..8b39522e 100644 --- a/src/main/java/net/Indyuce/mmocore/loot/chest/LootChestRegion.java +++ b/src/main/java/net/Indyuce/mmocore/loot/chest/LootChestRegion.java @@ -4,7 +4,6 @@ import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.event.LootChestSpawnEvent; import net.Indyuce.mmocore.api.player.PlayerActivity; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.loot.LootBuilder; import org.apache.commons.lang.Validate; import org.bukkit.Bukkit; @@ -125,7 +124,7 @@ public class LootChestRegion { */ @NotNull public ChestTier rollTier(PlayerData player) { - double chance = player.getStats().getStat(StatType.CHANCE) * MMOCore.plugin.configManager.lootChestsChanceWeight; + double chance = player.getStats().getStat("CHANCE") * MMOCore.plugin.configManager.lootChestsChanceWeight; double sum = 0; for (ChestTier tier : tiers) diff --git a/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java b/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java index 143ebbca..8febb7bb 100644 --- a/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java +++ b/src/main/java/net/Indyuce/mmocore/loot/droptable/dropitem/DropItem.java @@ -3,7 +3,6 @@ package net.Indyuce.mmocore.loot.droptable.dropitem; import java.util.Random; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.loot.LootBuilder; import net.Indyuce.mmocore.api.util.math.formula.RandomAmount; import io.lumine.mythic.lib.api.MMOLineConfig; @@ -40,7 +39,7 @@ public abstract class DropItem { * If the player chance is 0 the random value will remain the same. When he get lucks the chance gets closer to one. */ public boolean rollChance(PlayerData player) { - return Math.pow(random.nextDouble(), 1 / Math.log(1 + player.getStats().getStat(StatType.CHANCE))) < chance; + return Math.pow(random.nextDouble(), 1 / Math.log(1 + player.getStats().getStat("CHANCE"))) < chance; } public abstract void collect(LootBuilder builder); diff --git a/src/main/java/net/Indyuce/mmocore/manager/StatManager.java b/src/main/java/net/Indyuce/mmocore/manager/StatManager.java new file mode 100644 index 00000000..ee23b9d6 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/manager/StatManager.java @@ -0,0 +1,71 @@ +package net.Indyuce.mmocore.manager; + +import io.lumine.mythic.lib.MythicLib; +import net.Indyuce.mmocore.api.ConfigFile; +import net.Indyuce.mmocore.player.stats.StatInfo; +import net.Indyuce.mmocore.api.util.math.formula.LinearValue; +import net.Indyuce.mmocore.experience.Profession; +import org.bukkit.configuration.file.FileConfiguration; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.text.DecimalFormat; +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class StatManager implements MMOCoreManager { + private final Map loaded = new HashMap<>(); + + @Override + public void initialize(boolean clearBefore) { + if (clearBefore) + loaded.clear(); + + FileConfiguration config = new ConfigFile("stats").getConfig(); + + // Read decimal formats + for (String key : config.getConfigurationSection("decimal-format").getKeys(false)) + registerDecimalFormat(key, MythicLib.plugin.getMMOConfig().newDecimalFormat(config.getString("decimal-format." + key))); + + // Read default formulas + for (String key : config.getConfigurationSection("default").getKeys(false)) + registerDefaultFormula(key, new LinearValue(config.getConfigurationSection("default." + key))); + } + + public Collection getLoaded() { + return loaded.values(); + } + + @Nullable + public StatInfo getInfo(String stat) { + return loaded.get(stat); + } + + public void registerProfession(String stat, Profession profession) { + compute(stat).profession = profession; + } + + public void registerDefaultFormula(String stat, LinearValue defaultFormula) { + compute(stat).defaultInfo = defaultFormula; + } + + public void registerDecimalFormat(String stat, DecimalFormat format) { + compute(stat).format = format; + } + + /** + * @return A stat info for the specified stat. If it doesn't + * exist when method is called, it is registered into the map + */ + @NotNull + private StatInfo compute(String stat) { + StatInfo found = loaded.get(stat); + if (found != null) + return found; + + StatInfo newInfo = new StatInfo(stat); + loaded.put(stat, newInfo); + return newInfo; + } +} diff --git a/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java b/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java index df083d7a..66d5ed47 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/data/mysql/MySQLPlayerDataManager.java @@ -9,7 +9,6 @@ import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.SavedClassInformation; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.manager.data.PlayerDataManager; import net.Indyuce.mmocore.manager.data.mysql.MySQLTableEditor.Table; @@ -35,6 +34,13 @@ public class MySQLPlayerDataManager extends PlayerDataManager { try { MMOCore.sqlDebug("Loading data for: '" + data.getUniqueId() + "'..."); + // Initialize custom resources + if (!data.hasUsedTemporaryData()) { + data.setMana(data.getStats().getStat("MAX_MANA")); + data.setStamina(data.getStats().getStat("MAX_STAMINA")); + data.setStellium(data.getStats().getStat("MAX_STELLIUM")); + } + if (!result.next()) { data.setLevel(getDefaultData().getLevel()); data.setClassPoints(getDefaultData().getClassPoints()); @@ -44,12 +50,6 @@ public class MySQLPlayerDataManager extends PlayerDataManager { data.setExperience(0); data.getQuestData().updateBossBar(); - if (!data.hasUsedTemporaryData()) { - data.setMana(data.getStats().getStat(StatType.MAX_MANA)); - data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA)); - data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM)); - } - data.setFullyLoaded(); MMOCore.sqlDebug("Loaded DEFAULT data for: '" + data.getUniqueId() + "' as no saved data was found."); return; @@ -69,12 +69,6 @@ public class MySQLPlayerDataManager extends PlayerDataManager { json.entrySet().forEach(entry -> data.getItemClaims().put(entry.getKey(), entry.getValue().getAsInt())); } - if (!data.hasUsedTemporaryData()) { - data.setMana(data.getStats().getStat(StatType.MAX_MANA)); - data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA)); - data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM)); - } - if (!isEmpty(result.getString("guild"))) { Guild guild = provider.getGuildManager().getGuild(result.getString("guild")); data.setGuild(guild.getMembers().has(data.getUniqueId()) ? guild : null); diff --git a/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java b/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java index 7efe48fa..e8eaa739 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLPlayerDataManager.java @@ -6,7 +6,6 @@ import net.Indyuce.mmocore.api.player.OfflinePlayerData; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.profess.PlayerClass; import net.Indyuce.mmocore.api.player.profess.SavedClassInformation; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.guild.provided.Guild; import net.Indyuce.mmocore.manager.data.DataProvider; import net.Indyuce.mmocore.manager.data.PlayerDataManager; @@ -41,9 +40,9 @@ public class YAMLPlayerDataManager extends PlayerDataManager { data.setClass(MMOCore.plugin.classManager.get(config.getString("class"))); if (!data.hasUsedTemporaryData()) { - data.setMana(data.getStats().getStat(StatType.MAX_MANA)); - data.setStamina(data.getStats().getStat(StatType.MAX_STAMINA)); - data.setStellium(data.getStats().getStat(StatType.MAX_STELLIUM)); + data.setMana(data.getStats().getStat("MAX_MANA")); + data.setStamina(data.getStats().getStat("MAX_STAMINA")); + data.setStellium(data.getStats().getStat("MAX_STELLIUM")); } if (config.contains("guild")) { diff --git a/src/main/java/net/Indyuce/mmocore/manager/profession/FishingManager.java b/src/main/java/net/Indyuce/mmocore/manager/profession/FishingManager.java index 93a5a73f..e794c9e3 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/profession/FishingManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/profession/FishingManager.java @@ -3,7 +3,6 @@ package net.Indyuce.mmocore.manager.profession; import io.lumine.mythic.lib.api.MMOLineConfig; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.loot.chest.condition.Condition; import net.Indyuce.mmocore.loot.chest.condition.ConditionInstance; import net.Indyuce.mmocore.loot.droptable.dropitem.fishing.FishingDropItem; @@ -31,6 +30,11 @@ public class FishingManager extends SpecificProfessionManager { } catch (IllegalArgumentException exception) { MMOCore.log(Level.WARNING, "Could not load fishing drop table " + key + ": " + exception.getMessage()); } + + // Link fishing stats to this profession + MMOCore.plugin.statManager.registerProfession("FISHING_STRENGTH", getLinkedProfession()); + MMOCore.plugin.statManager.registerProfession("CRITICAL_FISHING_CHANCE", getLinkedProfession()); + MMOCore.plugin.statManager.registerProfession("CRITICAL_FISHING_FAILURE_CHANCE", getLinkedProfession()); } public FishingDropTable calculateDropTable(Entity entity) { @@ -46,7 +50,6 @@ public class FishingManager extends SpecificProfessionManager { public static class FishingDropTable { private final Set conditions = new HashSet<>(); private final List items = new ArrayList<>(); - private double maxWeight = 0; public FishingDropTable(ConfigurationSection section) { Validate.notNull(section, "Could not load config"); @@ -72,7 +75,6 @@ public class FishingManager extends SpecificProfessionManager { try { FishingDropItem dropItem = new FishingDropItem(new MMOLineConfig(str)); items.add(dropItem); - maxWeight += dropItem.getItem().getWeight(); } catch (RuntimeException exception) { MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load item '" + str + "' from fishing drop table '" + id + "': " + exception.getMessage()); @@ -93,11 +95,13 @@ public class FishingManager extends SpecificProfessionManager { } /** - * The Fishing Drop Item is calculated randomly bu the chance stat will make - * low weight items more likely to be caught. + * The chance stat will make low weight items more + * likely to be chosen by the algorithm + * + * @return Randomly computed fishing drop item */ public FishingDropItem getRandomItem(PlayerData player) { - double chance = player.getStats().getStat(StatType.CHANCE); + double chance = player.getStats().getStat("CHANCE"); //chance=0 ->the tier.chance remains the same //chance ->+inf -> the tier.chance becomes the same for everyone, uniform law diff --git a/src/main/java/net/Indyuce/mmocore/manager/social/PartyManager.java b/src/main/java/net/Indyuce/mmocore/manager/social/PartyManager.java index be3c8358..b6a1f7f0 100644 --- a/src/main/java/net/Indyuce/mmocore/manager/social/PartyManager.java +++ b/src/main/java/net/Indyuce/mmocore/manager/social/PartyManager.java @@ -1,8 +1,8 @@ package net.Indyuce.mmocore.manager.social; +import io.lumine.mythic.lib.UtilityMethods; import io.lumine.mythic.lib.api.stat.modifier.StatModifier; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.stats.StatType; import net.Indyuce.mmocore.manager.MMOCoreManager; import org.bukkit.configuration.ConfigurationSection; @@ -26,8 +26,7 @@ public class PartyManager implements MMOCoreManager { if (config != null) for (String key : config.getKeys(false)) try { - StatType stat = StatType.valueOf(key.toUpperCase().replace("-", "_").replace(" ", "_")); - buffs.add(new StatModifier("mmocoreParty", stat.name(), config.getString(key))); + buffs.add(new StatModifier("mmocoreParty", UtilityMethods.enumName(key), config.getString(key))); } catch (IllegalArgumentException exception) { MMOCore.log(Level.WARNING, "Could not load party buff '" + key + "': " + exception.getMessage()); } diff --git a/src/main/java/net/Indyuce/mmocore/player/stats/StatInfo.java b/src/main/java/net/Indyuce/mmocore/player/stats/StatInfo.java new file mode 100644 index 00000000..078b4af7 --- /dev/null +++ b/src/main/java/net/Indyuce/mmocore/player/stats/StatInfo.java @@ -0,0 +1,71 @@ +package net.Indyuce.mmocore.player.stats; + +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.util.math.formula.LinearValue; +import net.Indyuce.mmocore.experience.Profession; +import org.jetbrains.annotations.NotNull; + +import java.text.DecimalFormat; +import java.util.Objects; + +/** + * @author Jules + * @impl MMOCore used to have a giant enum of all the stat types + * which is now incompatible with MythicLib because the MMO plugins + * now have completely OPEN to edition numeric stat registries + */ +public class StatInfo { + public final String name; + + /** + * Profession linked to that stat. Stats which have a profession linked to + * them do NOT scale on the main player level but rather on that specific + * profession level + */ + public Profession profession; + + /** + * Default formula for the stat + */ + public LinearValue defaultInfo; + + /** + * How that stat displays anywhere in GUIs + */ + public DecimalFormat format; + + private static final DecimalFormat DEFAULT_DECIMAL_FORMAT = new DecimalFormat("0.#"); + + public StatInfo(String name) { + this.name = name; + } + + @NotNull + public String format(double d) { + return (format == null ? DEFAULT_DECIMAL_FORMAT : format).format(d); + } + + @NotNull + public LinearValue getDefaultFormula() { + return defaultInfo == null ? LinearValue.ZERO : defaultInfo; + } + + @NotNull + public static StatInfo valueOf(String str) { + StatInfo found = MMOCore.plugin.statManager.getInfo(str); + return found == null ? new StatInfo(str) : found; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + StatInfo statInfo = (StatInfo) o; + return name.equals(statInfo.name); + } + + @Override + public int hashCode() { + return Objects.hash(name); + } +}