diff --git a/MMOCore-API/pom.xml b/MMOCore-API/pom.xml index a95c596d..5964ed71 100644 --- a/MMOCore-API/pom.xml +++ b/MMOCore-API/pom.xml @@ -94,17 +94,18 @@ https://maven.enginehub.org/repo/ - - dmulloy2-repo - https://repo.dmulloy2.net/repository/public/ - - simonsators Repo https://simonsator.de/repo + + + codemc-repo + https://repo.codemc.io/repository/maven-public/ + + - me.blackvein - Quests - 4.4.1-b340 + me.pikamug.quests + quests-core + 5.2.7 provided true diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java index 0b2c0966..f3ce33d7 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/PlayerData.java @@ -725,7 +725,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD * @return Experience needed in order to reach next level */ public long getLevelUpExperience() { - return getProfess().getExpCurve().getExperience(getLevel() + 1); + return getProfess().getExpCurve().getExperience(this, getLevel()); } public boolean isOnline() { @@ -752,7 +752,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD public void giveLevels(int value, @NotNull EXPSource source) { long equivalentExp = 0; - while (value-- > 0) equivalentExp += getProfess().getExpCurve().getExperience(getLevel() + value + 1); + while (value-- > 0) equivalentExp += getProfess().getExpCurve().getExperience(this, getLevel() + value); giveExperience(equivalentExp, source); } @@ -1088,7 +1088,7 @@ public class PlayerData extends SynchronizedDataHolder implements OfflinePlayerD * Loop for exp overload when leveling up, will continue * looping until exp is 0 or max currentLevel has been reached */ - while (experience >= (experienceNeeded = getProfess().getExpCurve().getExperience(newLevel + 1))) { + while (experience >= (experienceNeeded = getProfess().getExpCurve().getExperience(this, newLevel))) { if (maxLevel > 0 && newLevel >= maxLevel) { experience = 0; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/MMOCoreAttributeStatHandler.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/MMOCoreAttributeStatHandler.java deleted file mode 100644 index 143b0abc..00000000 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/MMOCoreAttributeStatHandler.java +++ /dev/null @@ -1,38 +0,0 @@ -package net.Indyuce.mmocore.api.player.attribute; - -import io.lumine.mythic.lib.api.stat.StatInstance; -import io.lumine.mythic.lib.api.stat.handler.StatHandler; -import net.Indyuce.mmocore.api.player.PlayerData; -import org.bukkit.configuration.ConfigurationSection; - -/** - * This fixes an issue where registering new stat modifiers in ML - * to add extra attribute points does NOT update the stats granted - * by the attribute. - *

- * This stat handler MAY call subsequent stat handlers. There might - * be infinite recursion problems if another attr. grants extra attribute pts. - */ -public class MMOCoreAttributeStatHandler extends StatHandler { - private final PlayerAttribute attr; - - public MMOCoreAttributeStatHandler(ConfigurationSection config, PlayerAttribute attr) { - super(config, "ADDITIONAL_" + attr.getId().toUpperCase().replace("-", "_")); - - this.attr = attr; - } - - /** - * This method is called on login but the MMOCore playerData - * is not loaded yet, hence the try/catch clause - */ - @Override - public void runUpdate(StatInstance instance) { - try { - final PlayerData playerData = PlayerData.get(instance.getMap().getPlayerData()); - playerData.getAttributes().getInstance(attr).updateStats(); - } catch (NullPointerException exception) { - // Player data is not loaded yet so there's nothing to update. - } - } -} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java index 31f9f8c8..487b3255 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/attribute/PlayerAttribute.java @@ -6,7 +6,7 @@ import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.experience.EXPSource; -import net.Indyuce.mmocore.experience.ExpCurve; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import org.bukkit.Location; @@ -84,7 +84,7 @@ public class PlayerAttribute implements ExperienceObject { } @Override - public String getKey() { + public @NotNull String getKey() { return "attribute:" + getId().replace("-", "_"); } @@ -99,9 +99,9 @@ public class PlayerAttribute implements ExperienceObject { return expTable != null; } - @Nullable + @NotNull @Override - public ExpCurve getExpCurve() { + public ExperienceCurve getExpCurve() { throw new RuntimeException("Attributes don't have experience"); } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java index 52e2cf14..8a093317 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/api/player/profess/PlayerClass.java @@ -25,8 +25,8 @@ import net.Indyuce.mmocore.api.player.profess.resource.ResourceRegeneration; 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.experience.ExpCurve; import net.Indyuce.mmocore.experience.ExperienceObject; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.loot.chest.particle.CastingParticle; import net.Indyuce.mmocore.player.stats.StatInfo; @@ -59,7 +59,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject { private final ManaDisplayOptions manaDisplay; @NotNull - private final ExpCurve expCurve; + private final ExperienceCurve expCurve; @Nullable private final ExperienceTable expTable; @@ -111,10 +111,14 @@ public class PlayerClass implements ExperienceObject, PreloadedObject { actionBarFormat = config.contains("action-bar") ? config.getString("action-bar") : null; // Exp curve - expCurve = config.contains("exp-curve") - ? MMOCore.plugin.experience.getCurveOrThrow( - config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-")) - : ExpCurve.DEFAULT; + ExperienceCurve expCurve = ExperienceCurve.DEFAULT; + try { + expCurve = ExperienceCurve.fromConfig(config.getString("exp-curve")); + } catch (Throwable exception) { + MMOCore.log(Level.WARNING, "Could not load exp curve from class '" + id + "': " + exception.getMessage()); + exception.printStackTrace(); + } + this.expCurve = expCurve; // Main exp table ExperienceTable expTable = null; @@ -261,7 +265,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject { manaDisplay = ManaDisplayOptions.DEFAULT; maxLevel = 0; displayOrder = 0; - expCurve = ExpCurve.DEFAULT; + expCurve = ExperienceCurve.DEFAULT; expTable = null; comboMap = null; castParticle = new CastingParticle(VParticle.INSTANT_EFFECT.get()); @@ -282,7 +286,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject { } @Override - public String getKey() { + public @NotNull String getKey() { return "class_" + getId(); } @@ -315,7 +319,7 @@ public class PlayerClass implements ExperienceObject, PreloadedObject { } @Override - public @NotNull ExpCurve getExpCurve() { + public @NotNull ExperienceCurve getExpCurve() { return expCurve; } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/builtin/mmocore/admin/InfoCommandTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/builtin/mmocore/admin/InfoCommandTreeNode.java index 3828fc08..8dd01bcc 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/builtin/mmocore/admin/InfoCommandTreeNode.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/command/builtin/mmocore/admin/InfoCommandTreeNode.java @@ -43,7 +43,7 @@ public class InfoCommandTreeNode extends CommandTreeNode { for (Profession profession : MMOCore.plugin.professionManager.getAll()) sender.sendMessage( ChatColor.YELLOW + profession.getName() + ": Lvl " + ChatColor.GOLD + playerData.getCollectionSkills().getLevel(profession) - + ChatColor.YELLOW + " - " + ChatColor.GOLD + playerData.getCollectionSkills().getExperience(profession) + + ChatColor.YELLOW + " - " + ChatColor.GOLD + MythicLib.plugin.getMMOConfig().decimal.format(playerData.getCollectionSkills().getExperience(profession)) + ChatColor.YELLOW + " / " + ChatColor.GOLD + playerData.getCollectionSkills().getLevelUpExperience(profession)); sender.sendMessage(ChatColor.YELLOW + "----------------------------------------------------"); return CommandResult.SUCCESS; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java index fb755002..d5f6da2f 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/comp/placeholder/RPGPlaceholders.java @@ -200,14 +200,24 @@ public class RPGPlaceholders extends PlaceholderExpansion { if (playerData.hasSkillBound(slot)) return Double.toString(playerData.getCooldownMap().getCooldown(playerData.getBoundSkill(slot))); else return MMOCore.plugin.configManager.noSkillBoundPlaceholder; - } else if (identifier.startsWith("profession_experience_")) + } + + // Current exp in profession + else if (identifier.startsWith("profession_experience_")) { return MythicLib.plugin.getMMOConfig().decimal.format( playerData.getCollectionSkills().getExperience(identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase())); + } - else if (identifier.startsWith("profession_next_level_")) - return String.valueOf(PlayerData.get(player).getCollectionSkills() - .getLevelUpExperience(identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase())); + // Exp needed to level up profession + else if (identifier.startsWith("profession_next_level_")) { + final var professionId = identifier.substring(22).replace(" ", "-").replace("_", "-").toLowerCase(); + final @Nullable var profession = MMOCore.plugin.professionManager.get(professionId); + if (profession == null) return "{profession_not_found}"; + final var professionLevel = playerData.getCollectionSkills().getLevel(profession); + return String.valueOf(profession.getExpCurve().getExperience(playerData, professionLevel)); + } + // Number of online members in party else if (identifier.startsWith("party_count")) { final @Nullable AbstractParty party = playerData.getParty(); return party == null ? "0" : String.valueOf(party.countMembers()); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExpCurve.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExpCurve.java deleted file mode 100644 index a81422a5..00000000 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExpCurve.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.Indyuce.mmocore.experience; - -import io.lumine.mythic.lib.util.lang3.Validate; -import net.Indyuce.mmocore.api.player.PlayerData; - -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; -import java.util.ArrayList; -import java.util.List; - -public class ExpCurve { - private final String id; - - /** - * Experience needed to level up. Different professions or classes can have - * different exp curves so that it is easier to balance. - */ - private final List experience = new ArrayList<>(); - - /** - * Purely arbitrary but MMOCore needs a default exp curve for everything - * otherwise there might be divisions by 0 when trying to update the vanilla - * exp bar which requires a 0.0 -> 1.0 float as parameter. - * - * See {@link PlayerData#refreshVanillaExp()} - */ - public static final ExpCurve DEFAULT = new ExpCurve("default", 100, 200, 300, 400, 500); - - /** - * Reads an exp curve from a text file, one line after the other. Each exp - * value has to be the only thing written on every line - * - * @param file Text file to read data from - */ - public ExpCurve(File file) { - this.id = file.getName().replace(".txt", "").toLowerCase().replace("_", "-").replace(" ", "-"); - - try { - BufferedReader reader = new BufferedReader(new FileReader(file)); - String readLine; - while ((readLine = reader.readLine()) != null) - experience.add(Long.valueOf(readLine)); - reader.close(); - - Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve"); - } catch(Throwable throwable) { - throw new RuntimeException(throwable); - } - } - - /** - * Public constructor for external plugins - * - * @param id Some unique identifier to let other plugin features refer - * to your exp curve. - * @param values The exp values, at to be at least one or the constructor - * will throw an error - */ - public ExpCurve(String id, long... values) { - this.id = id; - for (long value : values) - experience.add(value); - Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve"); - } - - public String getId() { - return id; - } - - /** - * @param level Level being reached by some player - * @return Experience needed to reach provided level. The level serves - * an index for a list checkup. If the level is higher than - * the list size, it just returns the last value of the list - */ - public long getExperience(int level) { - Validate.isTrue(level > 0, "Level must be stricly positive"); - return experience.get(Math.min(level, experience.size()) - 1); - } -} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExperienceObject.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExperienceObject.java index c80e3819..6f12b789 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExperienceObject.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/ExperienceObject.java @@ -1,10 +1,10 @@ package net.Indyuce.mmocore.experience; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.dispenser.ExperienceDispenser; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; /** * General implementation for professions, classes and attributes. @@ -17,6 +17,7 @@ import org.jetbrains.annotations.Nullable; */ public interface ExperienceObject extends ExperienceDispenser { + @NotNull String getKey(); /** @@ -24,14 +25,14 @@ public interface ExperienceObject extends ExperienceDispenser { * * @return Exp curve of that object */ - @Nullable - ExpCurve getExpCurve(); + @NotNull + ExperienceCurve getExpCurve(); /** - * Should throw an error if called when - * {@link #hasExperienceTable()} returns false + * Throws an exception no experience table * * @return Table read when leveling up + * @see #hasExperienceTable() */ @NotNull ExperienceTable getExperienceTable(); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java index b1ec2403..484cf639 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/PlayerProfessions.java @@ -24,6 +24,7 @@ import org.jetbrains.annotations.Nullable; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.Random; public class PlayerProfessions { private final Map exp = new HashMap<>(); @@ -120,11 +121,14 @@ public class PlayerProfessions { } public long getLevelUpExperience(Profession profession) { - return profession.getExpCurve().getExperience(getLevel(profession) + 1); + return profession.getExpCurve().getExperience(playerData, getLevel(profession)); } + @Deprecated public long getLevelUpExperience(String id) { - return MMOCore.plugin.professionManager.has(id) ? MMOCore.plugin.professionManager.get(id).getExpCurve().getExperience(getLevel(id) + 1) : 0; + final var prof = MMOCore.plugin.professionManager.get(id); + if (prof == null) return 0; + return prof.getExpCurve().getExperience(null, getLevel(id)); } @Deprecated @@ -132,6 +136,12 @@ public class PlayerProfessions { setLevel(profession, value, PlayerLevelChangeEvent.Reason.UNKNOWN); } + @Deprecated + public void takeLevels(@NotNull Profession profession, int value) { + int current = Math.max(1, level.getOrDefault(profession.getId(), 1)); + level.put(profession.getId(), Math.max(1, current - value)); + } + public void setLevel(@NotNull Profession profession, int newLevel, @NotNull PlayerLevelChangeEvent.Reason reason) { if (profession.hasMaxLevel()) newLevel = Math.min(profession.getMaxLevel(), newLevel); final var previousValue = level.put(profession.getId(), Math.max(1, newLevel)); @@ -146,12 +156,6 @@ public class PlayerProfessions { } } - @Deprecated - public void takeLevels(@NotNull Profession profession, int value) { - int current = Math.max(1, level.getOrDefault(profession.getId(), 1)); - level.put(profession.getId(), Math.max(1, current - value)); - } - public void setExperience(Profession profession, double value) { exp.put(profession.getId(), value); } @@ -159,7 +163,8 @@ public class PlayerProfessions { public void giveLevels(Profession profession, int value, EXPSource source) { long equivalentExp = 0; final var currentLevel = getLevel(profession); - while (value-- > 0) equivalentExp += profession.getExpCurve().getExperience(currentLevel + value + 1); + while (value-- > 0) + equivalentExp += profession.getExpCurve().getExperience(playerData, currentLevel + value); giveExperience(profession, equivalentExp, source); } @@ -171,6 +176,8 @@ public class PlayerProfessions { giveExperience(profession, value, source, null, true); } + private static final Random RANDOM = new Random(); + public void giveExperience(@NotNull Profession profession, double value, @NotNull EXPSource source, @Nullable Location hologramLocation, boolean splitExp) { Validate.isTrue(playerData.isOnline(), "Cannot give experience to offline player"); if (value <= 0) { @@ -200,8 +207,11 @@ public class PlayerProfessions { if (event.isCancelled()) return; // Display hologram - if (hologramLocation != null && profession.getOption(Profession.ProfessionOption.EXP_HOLOGRAMS)) - MMOCoreUtils.displayIndicator(hologramLocation.add(.5, 1.5, .5), Language.EXP_HOLOGRAM.getFormat().replace("{exp}", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience()))); + if (hologramLocation != null && profession.getOption(Profession.ProfessionOption.EXP_HOLOGRAMS)) { + // TODO custom location per profession/exp source. + hologramLocation.add(.5 + .7 * RANDOM.nextDouble(), 1.3 + RANDOM.nextDouble() / 3, .5 + .7 * RANDOM.nextDouble()); + MMOCoreUtils.displayIndicator(hologramLocation, Language.EXP_HOLOGRAM.getFormat().replace("{exp}", MythicLib.plugin.getMMOConfig().decimal.format(event.getExperience()))); + } final var maxLevel = profession.getMaxLevel(); var currentExp = Math.max(0d, exp.getOrDefault(profession.getId(), 0d) + event.getExperience()); @@ -213,7 +223,7 @@ public class PlayerProfessions { * Loop for exp overload when leveling up, will continue * looping until exp is 0 or max newLevel has been reached */ - while (currentExp >= (experienceNeeded = profession.getExpCurve().getExperience(newLevel))) { + while (currentExp >= (experienceNeeded = profession.getExpCurve().getExperience(playerData, newLevel))) { if (maxLevel > 0 && newLevel >= maxLevel) { currentExp = 0; diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/Profession.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/Profession.java index a1a8435f..4d45218f 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/Profession.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/Profession.java @@ -6,6 +6,7 @@ import io.lumine.mythic.lib.util.PreloadedObject; import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.util.formula.ScalingFormula; import org.bukkit.Location; @@ -22,7 +23,8 @@ public class Profession implements ExperienceObject, PreloadedObject { private final String id, name; private final int maxLevel; private final Map options = new HashMap<>(); - private final ExpCurve expCurve; + @NotNull + private final ExperienceCurve expCurve; private final ExperienceTable expTable; /** @@ -44,9 +46,7 @@ public class Profession implements ExperienceObject, PreloadedObject { this.name = config.getString("name"); Validate.notNull(name, "Could not load name"); - expCurve = config.contains("exp-curve") - ? MMOCore.plugin.experience.getCurveOrThrow(config.get("exp-curve").toString().toLowerCase().replace("_", "-").replace(" ", "-")) - : ExpCurve.DEFAULT; + expCurve = ExperienceCurve.fromConfig(config.getString("exp-curve")); experience = ScalingFormula.fromConfig(config.get("experience")); ExperienceTable expTable = null; @@ -99,12 +99,12 @@ public class Profession implements ExperienceObject, PreloadedObject { } @Override - public String getKey() { + public @NotNull String getKey() { return "profession_" + getId(); } @Override - public ExpCurve getExpCurve() { + public @NotNull ExperienceCurve getExpCurve() { return expCurve; } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ExperienceCurve.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ExperienceCurve.java new file mode 100644 index 00000000..f0aca45b --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ExperienceCurve.java @@ -0,0 +1,57 @@ +package net.Indyuce.mmocore.experience.curve; + +import io.lumine.mythic.lib.util.FileUtils; +import net.Indyuce.mmocore.MMOCore; +import net.Indyuce.mmocore.api.player.PlayerData; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +public interface ExperienceCurve { + + /** + * Arbitrary values. MMOCore needs a default exp curve for everything otherwise + * it would be swarming be divisions by 0 when trying to update the vanilla + * exp bar which requires a 0.0 -> 1.0 float as parameter. + *

+ * See {@link PlayerData#refreshVanillaExp()} + */ + public static final ExperienceCurve DEFAULT = new ListExperienceCurve(100, 200, 300, 400, 500); + + /** + * If 1 is provided as level, this method returns the experience needed + * to reach level 2. If the exp curve is a formula, it will provide 1 to the formula. + * If the exp curve is a list, it will return the first element of the list. + * + * @param player Player leveling up + * @param level Current level of the player. + * @return Experience needed to reach the next level. + */ + public long getExperience(@NotNull PlayerData player, int level); + + @NotNull + public static ExperienceCurve fromConfig(@Nullable String configInput) { + + // [BACKWARDS COMPATIBILITY] Load from predefined file + try { + if (configInput == null) throw new RuntimeException(); + final var expCurveFile = FileUtils.getFile(MMOCore.plugin, "expcurves/" + configInput + ".txt"); + return new ListExperienceCurve(expCurveFile); + } catch (Exception ignored) { + } + + if (configInput == null) { + return DEFAULT; + } + + // Load from file + else if (configInput.endsWith(".txt")) { + final var expCurveFile = FileUtils.getFile(MMOCore.plugin, configInput); + return new ListExperienceCurve(expCurveFile); + } + + // Load as formula + else { + return new FormulaExperienceCurve(configInput); + } + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/FormulaExperienceCurve.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/FormulaExperienceCurve.java new file mode 100644 index 00000000..5d292309 --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/FormulaExperienceCurve.java @@ -0,0 +1,30 @@ +package net.Indyuce.mmocore.experience.curve; + +import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.util.formula.NumericalExpression; +import io.lumine.mythic.lib.util.lang3.Validate; +import net.Indyuce.mmocore.api.player.PlayerData; +import org.jetbrains.annotations.NotNull; + +public class FormulaExperienceCurve implements ExperienceCurve { + private final String formula; + + public FormulaExperienceCurve(@NotNull String formula) { + this.formula = formula; + } + + @Override + public long getExperience(@NotNull PlayerData player, int level) { + try { + Validate.isTrue(level > 0, "Level must be stricly positive, got " + level); + final var parsed = MythicLib.plugin.getPlaceholderParser().parse(player.getPlayer(), this.formula); + final var value = (int) NumericalExpression.eval(parsed.replace("{level}", String.valueOf(level))); + Validate.isTrue(value > 0, "Exp curve must return a positive value, got " + value); + return value; + + } catch (Exception e) { + MythicLib.plugin.getLogger().warning("Error parsing exp formula '" + this.formula + "' for player " + player.getPlayer().getName() + ", using 100: " + e.getMessage()); + return 100; + } + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ListExperienceCurve.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ListExperienceCurve.java new file mode 100644 index 00000000..8d1b1807 --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/curve/ListExperienceCurve.java @@ -0,0 +1,58 @@ +package net.Indyuce.mmocore.experience.curve; + +import io.lumine.mythic.lib.util.lang3.Validate; +import net.Indyuce.mmocore.api.player.PlayerData; +import org.jetbrains.annotations.NotNull; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.List; + +public class ListExperienceCurve implements ExperienceCurve { + + /** + * Experience needed to level up. At index i, experience needed + * to level up from level N to (N + 1). + */ + private final List experience; + + /** + * Reads an exp curve from a text file, one line after the other. Each + * exp value has to be the only thing written on every line + * + * @param file Text file to read data from + */ + public ListExperienceCurve(@NotNull File file) { + this.experience = new ArrayList<>(); + try { + BufferedReader reader = new BufferedReader(new FileReader(file)); + String readLine; + while ((readLine = reader.readLine()) != null) + experience.add(Long.valueOf(readLine)); + reader.close(); + + Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve"); + } catch (Throwable throwable) { + throw new RuntimeException(throwable); + } + } + + /** + * Exp curve with specific level up exp values + * + * @param values The exp values. There has to be at least one + */ + public ListExperienceCurve(long... values) { + this.experience = new ArrayList<>(values.length); + for (long value : values) experience.add(value); + Validate.isTrue(!experience.isEmpty(), "There must be at least one exp value in your exp curve"); + } + + @Override + public long getExperience(@NotNull PlayerData player, int level) { + Validate.isTrue(level > 0, "Level must be stricly positive"); + return experience.get(Math.min(level, experience.size())); + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/source/CraftItemExperienceSource.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/source/CraftItemExperienceSource.java index 246824d5..0a4bcd86 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/source/CraftItemExperienceSource.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/experience/source/CraftItemExperienceSource.java @@ -15,6 +15,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.inventory.CraftItemEvent; import org.bukkit.event.inventory.InventoryAction; import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; public class CraftItemExperienceSource extends SpecificExperienceSource { @@ -45,7 +46,7 @@ public class CraftItemExperienceSource extends SpecificExperienceSource { - // First check - int newAmount = getAmount(event.getInventory().getMatrix()[index]); + final var newItem = event.getInventory().getMatrix()[index]; + final var newAmount = getEffectiveNewAmount(newItem, oldItem); + if (newAmount >= oldAmount) return; // Deduce amount crafted - int amountCrafted = (event.getClick().isShiftClick() ? oldAmount - newAmount : 1) * itemsCraftedPerRecipe; + final var amountCrafted = (event.getClick().isShiftClick() ? oldAmount - newAmount : 1) * itemsCraftedPerRecipe; for (CraftItemExperienceSource source : getSources()) if (source.matches(data, resultType)) source.giveExperience(data, amountCrafted, event.getInventory().getLocation()); }); } - private int getAmount(@Nullable ItemStack item) { - return item == null || item.getType() == Material.AIR ? 0 : item.getAmount(); + private int getEffectiveNewAmount(@Nullable ItemStack item, @NotNull ItemStack oldItem) { + // Some items are consumed and leave behind a different type (e.g. buckets) + // If that's the case just say all items were crafted + // Fixes https://gitlab.com/phoenix-dvpmt/mmocore/-/issues/1165 + return item == null || item.getType() == Material.AIR || item.getType() != oldItem.getType() ? 0 : item.getAmount(); } private int getLowerAmountIngredientIndex(ItemStack[] matrix) { diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/AttributeManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/AttributeManager.java index 5ea81849..492e114f 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/AttributeManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/AttributeManager.java @@ -1,10 +1,10 @@ package net.Indyuce.mmocore.manager; import io.lumine.mythic.lib.MythicLib; +import io.lumine.mythic.lib.api.stat.StatInstance; import io.lumine.mythic.lib.util.FileUtils; -import io.lumine.mythic.lib.util.config.YamlFile; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.api.player.attribute.MMOCoreAttributeStatHandler; +import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.api.player.attribute.PlayerAttribute; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -40,20 +40,23 @@ public class AttributeManager implements MMOCoreManager { @Override public void initialize(boolean clearBefore) { - if (clearBefore) { + if (clearBefore) map.clear(); - MythicLib.plugin.getStats().clearRegisteredStats(handler -> handler instanceof MMOCoreAttributeStatHandler); - } FileUtils.loadObjectsFromFolder(MMOCore.plugin, "attributes", false, (key, config) -> { final String path = key.toLowerCase().replace("_", "-").replace(" ", "-"); map.put(path, new PlayerAttribute(config)); }, "Could not load attribute '%s' from file '%s': %s"); - final var statsConfig = new YamlFile(MythicLib.plugin, "stats").getContent(); + // MythicLib stat handlers for (PlayerAttribute attr : getAll()) { - final MMOCoreAttributeStatHandler handler = new MMOCoreAttributeStatHandler(statsConfig, attr); - MythicLib.plugin.getStats().registerStat(handler, handler.getStat() + "_PERCENT"); + final var statId = attr.getId().toUpperCase().replace("-", "_") + "_PERCENT"; + MythicLib.plugin.getStats().computeStat(statId).addUpdateListener(ins -> this.updateMMOCoreStatAttributeValue(ins, attr)); } } + + private void updateMMOCoreStatAttributeValue(@NotNull StatInstance instance, PlayerAttribute attribute) { + final var playerData = PlayerData.get(instance.getMap().getPlayerData()); + playerData.getAttributes().getInstance(attribute).updateStats(); + } } diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java index db470987..c8572d22 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ConfigManager.java @@ -69,12 +69,6 @@ public class ConfigManager { if (!FileUtils.getFile(MMOCore.plugin, "exp-tables").exists()) copyDefaultFile("exp-tables/default_exp_tables.yml"); - if (!FileUtils.getFile(MMOCore.plugin, "expcurves").exists()) { - copyDefaultFile("expcurves/levels.txt"); - copyDefaultFile("expcurves/mining.txt"); - copyDefaultFile("expcurves/skill-tree-node.txt"); - } - if (!FileUtils.getFile(MMOCore.plugin, "loot-chests").exists()) copyDefaultFile("loot-chests/default_loot_chests.yml"); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java index 44cb2ca8..7f97950f 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/ExperienceManager.java @@ -1,9 +1,8 @@ package net.Indyuce.mmocore.manager; import io.lumine.mythic.lib.util.FileUtils; -import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; -import net.Indyuce.mmocore.experience.ExpCurve; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.experience.source.type.ExperienceSource; import net.Indyuce.mmocore.manager.profession.ExperienceSourceManager; @@ -14,7 +13,6 @@ import org.jetbrains.annotations.Nullable; import java.util.*; public class ExperienceManager implements MMOCoreManager { - private final Map expCurves = new HashMap<>(); private final Map expTables = new HashMap<>(); /** @@ -45,14 +43,29 @@ public class ExperienceManager implements MMOCoreManager { getManager(path).registerSource(source); } + @Deprecated public boolean hasCurve(String id) { - return expCurves.containsKey(id); + try { + ExperienceCurve.fromConfig("expcurves/" + id + ".txt"); + return true; + } catch (Exception ignored) { + return false; + } } + @Deprecated @NotNull - public ExpCurve getCurveOrThrow(String id) { - Validate.isTrue(hasCurve(id), "Could not find exp curve with ID '" + id + "'"); - return expCurves.get(id); + public ExperienceCurve getCurveOrThrow(String id) { + try { + return ExperienceCurve.fromConfig(id + ".txt"); + } catch (Exception ignored) { + throw new IllegalArgumentException("Could not find exp curve with ID '" + id + "'"); + } + } + + @Deprecated + public Collection getCurves() { + return List.of(); } @Deprecated @@ -82,10 +95,6 @@ public class ExperienceManager implements MMOCoreManager { throw new IllegalArgumentException("Please provide either a string (exp table name) or a config section (locally define an exp table)"); } - public Collection getCurves() { - return expCurves.values(); - } - public Collection getTables() { return expTables.values(); } @@ -100,21 +109,15 @@ public class ExperienceManager implements MMOCoreManager { @Override public void initialize(boolean clearBefore) { if (clearBefore) { - expCurves.clear(); expTables.clear(); managers.forEach((c, manager) -> manager.close()); managers.clear(); } - // Exp curves - FileUtils.loadObjectsFromFolderRaw(MMOCore.plugin, "expcurves", file -> { - final ExpCurve curve = new ExpCurve(file); - expCurves.put(curve.getId(), curve); - }, "Could not load exp curve from file '%s': %s"); // Exp tables - FileUtils.loadObjectsFromFolder(MMOCore.plugin ,"exp-tables", false, (key, config) -> { + FileUtils.loadObjectsFromFolder(MMOCore.plugin, "exp-tables", false, (key, config) -> { final ExperienceTable table = new ExperienceTable(config); expTables.put(table.getId(), table); }, "Could not load exp table '%s' from file '%s': %s"); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLDatabaseImpl.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLDatabaseImpl.java index 58da095b..4f47d43b 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLDatabaseImpl.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/data/yaml/YAMLDatabaseImpl.java @@ -161,7 +161,11 @@ public class YAMLDatabaseImpl extends YAMLFlatDatabase config.set("skill-tree-level." + node.getFullId(), data.getNodeLevel(node))); + config.createSection("skill-tree-level"); + for (var node : MMOCore.plugin.skillTreeManager.getAllNodes()) { + final var nodeLevel = data.getNodeLevel(node); + if (nodeLevel > 0) config.set("skill-tree-level." + node.getFullId(), nodeLevel); + } // Skill levels config.set("skill", null); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/profession/CustomBlockManager.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/profession/CustomBlockManager.java index 8f22f1b7..0e9e7da1 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/profession/CustomBlockManager.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/manager/profession/CustomBlockManager.java @@ -205,12 +205,15 @@ public class CustomBlockManager extends SpecificProfessionManager { this.protectVanillaBlocks = config.getBoolean("protect-vanilla-blocks"); this.enableToolRestrictions = config.getBoolean("enable-tool-restrictions"); - for (String key : config.getStringList("conditions")) - try { - customMineConditions.add(MMOCore.plugin.loadManager.loadCondition(new MMOLineConfig(key))); - } catch (IllegalArgumentException exception) { - MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load custom mining condition '" + key + "': " + exception.getMessage()); - } + // Avoid warnings if disabled + if (enabled) + for (String key : config.getStringList("conditions")) + try { + customMineConditions.add(MMOCore.plugin.loadManager.loadCondition(new MMOLineConfig(key))); + } catch (IllegalArgumentException exception) { + MMOCore.plugin.getLogger().log(Level.WARNING, "Could not load custom mining condition '" + key + "': " + exception.getMessage()); + } + else customMineConditions.clear(); } @Deprecated diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/QuestModuleType.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/QuestModuleType.java index c39d3b76..80067ee7 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/QuestModuleType.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/QuestModuleType.java @@ -1,7 +1,7 @@ package net.Indyuce.mmocore.quest; import net.Indyuce.mmocore.quest.compat.BeautyQuestModule; -import net.Indyuce.mmocore.quest.compat.BlackVeinQuestsModule; +import net.Indyuce.mmocore.quest.compat.QuestsModule; import net.Indyuce.mmocore.quest.compat.QuestCreatorModule; import net.Indyuce.mmocore.quest.compat.QuestModule; import org.bukkit.Bukkit; @@ -10,7 +10,7 @@ import javax.inject.Provider; public enum QuestModuleType { MMOCORE("MMOCore", MMOCoreQuestModule::new), - QUESTS("Quests", BlackVeinQuestsModule::new), + QUESTS("Quests", QuestsModule::new), BEAUTY_QUEST("BeautyQuests", BeautyQuestModule::new), QUEST_CREATOR("QuestCreator", QuestCreatorModule::new); diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/BlackVeinQuestsModule.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/BlackVeinQuestsModule.java deleted file mode 100644 index 8819b5ef..00000000 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/BlackVeinQuestsModule.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.Indyuce.mmocore.quest.compat; - -import me.blackvein.quests.Quest; -import me.blackvein.quests.Quester; -import me.blackvein.quests.Quests; -import net.Indyuce.mmocore.quest.AbstractQuest; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - - -public class BlackVeinQuestsModule implements QuestModule { - private final Quests plugin = (Quests) Bukkit.getPluginManager().getPlugin("Quests"); - - - - @Override - public BlackVeinQuestQuest getQuestOrThrow(String id) { - Quests plugin = (Quests) Bukkit.getPluginManager().getPlugin("Quests"); - return plugin.getQuestById(id)==null?null:new BlackVeinQuestQuest(plugin.getQuestById(id)); - } - - - @Override - public boolean hasCompletedQuest(String questId, Player player) { - Quester quester = plugin.getQuester(player.getUniqueId()); - if(quester==null) - return false; - for(Quest quest:quester.getCompletedQuests()) { - if(quest.getId().equals(questId)) - return true; - } - return false; - } - - - public class BlackVeinQuestQuest implements AbstractQuest { - private final Quest quest; - - public BlackVeinQuestQuest(Quest quest) { - this.quest = quest; - } - - @Override - public String getName() { - return quest.getName(); - } - - @Override - public String getId() { - return quest.getId(); - } - } - -} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/QuestsModule.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/QuestsModule.java new file mode 100644 index 00000000..1b69b47f --- /dev/null +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/quest/compat/QuestsModule.java @@ -0,0 +1,52 @@ +package net.Indyuce.mmocore.quest.compat; + +import me.pikamug.quests.BukkitQuestsPlugin; +import me.pikamug.quests.player.Quester; +import me.pikamug.quests.quests.Quest; +import net.Indyuce.mmocore.quest.AbstractQuest; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +public class QuestsModule implements QuestModule { + private final BukkitQuestsPlugin plugin; + + public QuestsModule() { + plugin = (BukkitQuestsPlugin) Bukkit.getPluginManager().getPlugin("Quests"); + } + + @Override + public QuestImpl getQuestOrThrow(String id) { + final var found = plugin.getQuest(id); + return found == null ? null : new QuestImpl(found); + } + + + @Override + public boolean hasCompletedQuest(String questId, Player player) { + Quester quester = plugin.getQuester(player.getUniqueId()); + if (quester == null) return false; + + for (var quest : quester.getCompletedQuests()) + if (quest.getId().equals(questId)) return true; + + return false; + } + + public static class QuestImpl implements AbstractQuest { + private final Quest quest; + + public QuestImpl(Quest quest) { + this.quest = quest; + } + + @Override + public String getName() { + return quest.getName(); + } + + @Override + public String getId() { + return quest.getId(); + } + } +} diff --git a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skilltree/SkillTreeNode.java b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skilltree/SkillTreeNode.java index 28730015..4192ef0f 100644 --- a/MMOCore-API/src/main/java/net/Indyuce/mmocore/skilltree/SkillTreeNode.java +++ b/MMOCore-API/src/main/java/net/Indyuce/mmocore/skilltree/SkillTreeNode.java @@ -9,7 +9,7 @@ import io.lumine.mythic.lib.util.lang3.Validate; import net.Indyuce.mmocore.MMOCore; import net.Indyuce.mmocore.api.player.PlayerData; import net.Indyuce.mmocore.experience.EXPSource; -import net.Indyuce.mmocore.experience.ExpCurve; +import net.Indyuce.mmocore.experience.curve.ExperienceCurve; import net.Indyuce.mmocore.experience.ExperienceObject; import net.Indyuce.mmocore.experience.droptable.ExperienceTable; import net.Indyuce.mmocore.skilltree.display.DisplayMap; @@ -204,7 +204,7 @@ public class SkillTreeNode implements ExperienceObject { public static final String KEY_PREFIX = "node"; @Override - public String getKey() { + public @NotNull String getKey() { return KEY_PREFIX + ":" + getFullId().replace("-", "_"); } @@ -269,9 +269,9 @@ public class SkillTreeNode implements ExperienceObject { throw new RuntimeException("Skill trees don't have experience"); } - @Nullable + @NotNull @Override - public ExpCurve getExpCurve() { + public ExperienceCurve getExpCurve() { throw new RuntimeException("Skill trees don't have experience"); } diff --git a/MMOCore-Dist/src/main/resources/default/classes/human.yml b/MMOCore-Dist/src/main/resources/default/classes/human.yml index 0159f9f0..feae290f 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/human.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/human.yml @@ -20,8 +20,14 @@ options: off-combat-health-regen: false off-combat-mana-regen: false -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' exp-table: class_exp_table diff --git a/MMOCore-Dist/src/main/resources/default/classes/mage/arcane-mage.yml b/MMOCore-Dist/src/main/resources/default/classes/mage/arcane-mage.yml index 9ff26ae9..42ef55ed 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/mage/arcane-mage.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/mage/arcane-mage.yml @@ -36,8 +36,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' skill-slots: 1: diff --git a/MMOCore-Dist/src/main/resources/default/classes/mage/mage.yml b/MMOCore-Dist/src/main/resources/default/classes/mage/mage.yml index 8b8170a8..aa07a29f 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/mage/mage.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/mage/mage.yml @@ -36,8 +36,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' # The maximum level players can reach max-level: 100 diff --git a/MMOCore-Dist/src/main/resources/default/classes/marksman.yml b/MMOCore-Dist/src/main/resources/default/classes/marksman.yml index ef545ca1..ac99af4b 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/marksman.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/marksman.yml @@ -35,8 +35,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' # The maximum level players can reach max-level: 100 diff --git a/MMOCore-Dist/src/main/resources/default/classes/paladin.yml b/MMOCore-Dist/src/main/resources/default/classes/paladin.yml index 961053b3..f3cc716d 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/paladin.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/paladin.yml @@ -35,8 +35,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' skill-slots: 1: diff --git a/MMOCore-Dist/src/main/resources/default/classes/rogue.yml b/MMOCore-Dist/src/main/resources/default/classes/rogue.yml index 1854bc8b..299f539a 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/rogue.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/rogue.yml @@ -36,8 +36,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' # The maximum level players can reach max-level: 100 diff --git a/MMOCore-Dist/src/main/resources/default/classes/warrior.yml b/MMOCore-Dist/src/main/resources/default/classes/warrior.yml index 76afe9ca..7c9cc689 100644 --- a/MMOCore-Dist/src/main/resources/default/classes/warrior.yml +++ b/MMOCore-Dist/src/main/resources/default/classes/warrior.yml @@ -39,8 +39,14 @@ display: # item-model: 'minecraft:dirt' # texture: '' # Skull texture (set 'item' to 'PLAYER_HEAD') -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/class_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current class level. +# | Example: '{level} * 200' +exp-curve: '{level} * 200' # The maximum level players can reach max-level: 100 diff --git a/MMOCore-Dist/src/main/resources/default/expcurves/levels.txt b/MMOCore-Dist/src/main/resources/default/expcurves/levels.txt deleted file mode 100644 index 426fae7e..00000000 --- a/MMOCore-Dist/src/main/resources/default/expcurves/levels.txt +++ /dev/null @@ -1,25 +0,0 @@ -200 -400 -600 -800 -1000 -1200 -1400 -1600 -1800 -2000 -2200 -2400 -2600 -2800 -3000 -3200 -3400 -3600 -3800 -4000 -4200 -4400 -4600 -4800 -5000 diff --git a/MMOCore-Dist/src/main/resources/default/expcurves/mining.txt b/MMOCore-Dist/src/main/resources/default/expcurves/mining.txt deleted file mode 100644 index c9f11755..00000000 --- a/MMOCore-Dist/src/main/resources/default/expcurves/mining.txt +++ /dev/null @@ -1,25 +0,0 @@ -100 -200 -300 -400 -500 -600 -700 -800 -900 -1000 -1100 -1200 -1300 -1400 -1500 -1600 -1700 -1800 -1900 -2000 -2100 -2200 -2300 -2400 -2500 diff --git a/MMOCore-Dist/src/main/resources/default/expcurves/skill-tree-node.txt b/MMOCore-Dist/src/main/resources/default/expcurves/skill-tree-node.txt deleted file mode 100644 index d82f05d1..00000000 --- a/MMOCore-Dist/src/main/resources/default/expcurves/skill-tree-node.txt +++ /dev/null @@ -1,25 +0,0 @@ -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 \ No newline at end of file diff --git a/MMOCore-Dist/src/main/resources/default/professions/alchemy.yml b/MMOCore-Dist/src/main/resources/default/professions/alchemy.yml index a66fa797..8a9a1cb7 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/alchemy.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/alchemy.yml @@ -8,8 +8,14 @@ experience: base: 20 per-level: 3 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: - 'brewpotion{effect=SPEED}' @@ -20,31 +26,31 @@ exp-sources: alchemy-experience: special: - + # When brewing a potion into a splash potion, # only 40% of the base EXP is earned. splash: 40 - + # When brewing a potion into a splash potion, # only 40% of the base EXP is earned. lingering: 40 - + # When extending a pot duration, # only 40% of base EXP is earned. extend: 40 - + # When upgrading a potion level, # only 40% of base EXP is earned. upgrade: 40 # Base EXP of potions effects: - + # Water bottles AWKWARD: 5 MUNDANE: 5 THICK: 5 - + # Potion effects NIGHT_VISION: 10 INVISIBILITY: 10 diff --git a/MMOCore-Dist/src/main/resources/default/professions/enchanting.yml b/MMOCore-Dist/src/main/resources/default/professions/enchanting.yml index bead3bf5..4e56d02c 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/enchanting.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/enchanting.yml @@ -8,8 +8,14 @@ experience: base: 10 per-level: 2 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' # Remove the 'enchant' parameter from the line config # to make the profession get EXP with ANY enchant. diff --git a/MMOCore-Dist/src/main/resources/default/professions/farming.yml b/MMOCore-Dist/src/main/resources/default/professions/farming.yml index 32ee5d84..078a3fc4 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/farming.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/farming.yml @@ -7,8 +7,14 @@ experience: base: 10 per-level: 2 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: - 'mineblock{type=WHEAT;amount=1-3;crop=true;player-placed=true;silk-touch=false}' diff --git a/MMOCore-Dist/src/main/resources/default/professions/fishing.yml b/MMOCore-Dist/src/main/resources/default/professions/fishing.yml index c16a7d65..673596db 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/fishing.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/fishing.yml @@ -8,8 +8,14 @@ experience: base: 20 per-level: 3 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: {} diff --git a/MMOCore-Dist/src/main/resources/default/professions/mining.yml b/MMOCore-Dist/src/main/resources/default/professions/mining.yml index 49e857b7..be7df223 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/mining.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/mining.yml @@ -8,8 +8,14 @@ experience: base: 20 per-level: 3 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: mining +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' # This part of the config is ONLY for custom mining. # Custom Mining must be setup in config.yml and it diff --git a/MMOCore-Dist/src/main/resources/default/professions/smelting.yml b/MMOCore-Dist/src/main/resources/default/professions/smelting.yml index 807809b3..d7eee550 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/smelting.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/smelting.yml @@ -7,8 +7,14 @@ experience: base: 20 per-level: 3 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: - 'craftitem{type=BLAST_FURNACE;amount=1}' diff --git a/MMOCore-Dist/src/main/resources/default/professions/smithing.yml b/MMOCore-Dist/src/main/resources/default/professions/smithing.yml index 721d14db..94b7537c 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/smithing.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/smithing.yml @@ -8,8 +8,14 @@ experience: base: 20 per-level: 3 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: - 'repairitem{}' diff --git a/MMOCore-Dist/src/main/resources/default/professions/woodcutting.yml b/MMOCore-Dist/src/main/resources/default/professions/woodcutting.yml index a80bd226..1f3113d4 100644 --- a/MMOCore-Dist/src/main/resources/default/professions/woodcutting.yml +++ b/MMOCore-Dist/src/main/resources/default/professions/woodcutting.yml @@ -8,8 +8,14 @@ experience: base: 13 per-level: 2.5 -# Must match an existing exp curve filename from the 'expcurves' folder -exp-curve: levels +# Can be a file path to an existing .txt file inside the MMOCore/ folder. +# | The TXT files contains only the experience required per level, one per line. +# | Example: 'expcurves/profession_exp_curve.txt' +# Or a formula using the {level} and PAPI placeholders. +# | The formula should return the total experience required to reach the next +# | level if {level} is the player's current profession level. +# | Example: '{level} * 150' +exp-curve: '{level} * 150' exp-sources: - 'mineblock{type=OAK_LOG;amount=1-3}'