diff --git a/Changelog.txt b/Changelog.txt index 188e1f93b..14c4c9b61 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,3 +1,11 @@ +Version 2.1.64 + (API) method to get XP in FormulaManager has been renamed to getXPtoNextLevel(...), this shouldn't break anything as plugins should be using our Experience API methods instead of this + (API) Added method getLevel(Player player, PrimarySkillType primarySkillType) to ExperienceAPI.java + Corrected how Standard mode (1-100 scaling) XP to next level was calculated, it is now a true 1:10 ratio with Retro (1-1000) scale, which is how it was intended to be to begin with + + NOTE: The net result of this change is it will take a bit longer to level with Standard, but it should not be a drastic change. You might not even notice it. + Standard is meant to take the same amount of time to level from levels 1-100 as it takes Retro to do 1-1000, this change corrects from errors in the code that made Standard actually take less XP than Retro despite intending for it to be a cosmetic difference in progression. + Version 2.1.63 Fixed Armor Impact not scaling by skill rank Significantly Buffed the amount of durability damage incurred by a successful Armor Impact diff --git a/pom.xml b/pom.xml index 6670f853a..d7cd7c2de 100755 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 com.gmail.nossr50.mcMMO mcMMO - 2.1.63 + 2.1.64-SNAPSHOT mcMMO https://github.com/mcMMO-Dev/mcMMO @@ -167,7 +167,7 @@ org.spigotmc spigot-api - 1.14.1-R0.1-SNAPSHOT + 1.14.2-R0.1-SNAPSHOT provided diff --git a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java index 93eaef9a3..e018a4cc2 100644 --- a/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java +++ b/src/main/java/com/gmail/nossr50/api/ExperienceAPI.java @@ -649,11 +649,28 @@ public final class ExperienceAPI { * @return the level of a given skill * * @throws InvalidSkillException if the given skill is not valid + * @deprecated Use getLevel(Player player, PrimarySkillType skillType) instead */ + @Deprecated public static int getLevel(Player player, String skillType) { return getPlayer(player).getSkillLevel(getSkillType(skillType)); } + /** + * Get the level a player has in a specific skill. + *
+ * This function is designed for API usage. + * + * @param player The player to get the level for + * @param skillType The skill to get the level for + * @return the level of a given skill + * + * @throws InvalidSkillException if the given skill is not valid + */ + public static int getLevel(Player player, PrimarySkillType skillType) { + return getPlayer(player).getSkillLevel(skillType); + } + /** * Get the level an offline player has in a specific skill. *
@@ -995,7 +1012,7 @@ public final class ExperienceAPI { * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level) { - return mcMMO.getFormulaManager().getCachedXpToLevel(level, ExperienceConfig.getInstance().getFormulaType()); + return mcMMO.getFormulaManager().getXPtoNextLevel(level, ExperienceConfig.getInstance().getFormulaType()); } /** @@ -1009,7 +1026,7 @@ public final class ExperienceAPI { * @throws InvalidFormulaTypeException if the given formulaType is not valid */ public static int getXpNeededToLevel(int level, String formulaType) { - return mcMMO.getFormulaManager().getCachedXpToLevel(level, getFormulaType(formulaType)); + return mcMMO.getFormulaManager().getXPtoNextLevel(level, getFormulaType(formulaType)); } /** diff --git a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java index f30d8b0a1..6629adc2d 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/party/Party.java +++ b/src/main/java/com/gmail/nossr50/datatypes/party/Party.java @@ -203,7 +203,7 @@ public class Party { public int getXpToLevel() { FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return (mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType)) * (getOnlineMembers().size() + Config.getInstance().getPartyXpCurveMultiplier()); + return (mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType)) * (getOnlineMembers().size() + Config.getInstance().getPartyXpCurveMultiplier()); } public String getXpToLevelPercentage() { diff --git a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java index f71ceeca1..b2b0f7803 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java +++ b/src/main/java/com/gmail/nossr50/datatypes/player/PlayerProfile.java @@ -397,7 +397,7 @@ public class PlayerProfile { int level = (ExperienceConfig.getInstance().getCumulativeCurveEnabled()) ? UserManager.getPlayer(playerName).getPowerLevel() : skills.get(primarySkillType); FormulaType formulaType = ExperienceConfig.getInstance().getFormulaType(); - return mcMMO.getFormulaManager().getCachedXpToLevel(level, formulaType); + return mcMMO.getFormulaManager().getXPtoNextLevel(level, formulaType); } private int getChildSkillLevel(PrimarySkillType primarySkillType) { diff --git a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java index 85f29d893..c756017bf 100644 --- a/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java +++ b/src/main/java/com/gmail/nossr50/datatypes/skills/PrimarySkillType.java @@ -66,7 +66,7 @@ public enum PrimarySkillType { ImmutableList.of(SubSkillType.WOODCUTTING_LEAF_BLOWER, SubSkillType.WOODCUTTING_TREE_FELLER, SubSkillType.WOODCUTTING_HARVEST_LUMBER)); private Class managerClass; - private Color runescapeColor; + private Color skillColor; private SuperAbilityType ability; private ToolType tool; private List subSkillTypes; @@ -110,13 +110,13 @@ public enum PrimarySkillType { NON_CHILD_SKILLS = ImmutableList.copyOf(nonChildSkills); } - private PrimarySkillType(Class managerClass, Color runescapeColor, List subSkillTypes) { - this(managerClass, runescapeColor, null, null, subSkillTypes); + private PrimarySkillType(Class managerClass, Color skillColor, List subSkillTypes) { + this(managerClass, skillColor, null, null, subSkillTypes); } - private PrimarySkillType(Class managerClass, Color runescapeColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) { + private PrimarySkillType(Class managerClass, Color skillColor, SuperAbilityType ability, ToolType tool, List subSkillTypes) { this.managerClass = managerClass; - this.runescapeColor = runescapeColor; + this.skillColor = skillColor; this.ability = ability; this.tool = tool; this.subSkillTypes = subSkillTypes; @@ -243,7 +243,7 @@ public enum PrimarySkillType { } /* public void celebrateLevelUp(Player player) { - ParticleEffectUtils.fireworkParticleShower(player, runescapeColor); + ParticleEffectUtils.fireworkParticleShower(player, skillColor); }*/ public boolean shouldProcess(Entity target) { diff --git a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java index ad2145f05..5d770be6d 100644 --- a/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java +++ b/src/main/java/com/gmail/nossr50/util/experience/FormulaManager.java @@ -15,8 +15,10 @@ public class FormulaManager { private static File formulaFile = new File(mcMMO.getFlatFileDirectory() + "formula.yml"); // Experience needed to reach a level, cached values to improve conversion speed - private final Map experienceNeededLinear = new HashMap(); - private final Map experienceNeededExponential = new HashMap(); + private Map experienceNeededRetroLinear; + private Map experienceNeededStandardLinear; + private Map experienceNeededRetroExponential; + private Map experienceNeededStandardExponential; private FormulaType previousFormula; @@ -26,9 +28,20 @@ public class FormulaManager { public FormulaManager() { /* Setting for Classic Mode (Scales a lot of stuff up by * 10) */ retroModeEnabled = Config.getInstance().getIsRetroMode(); + initExperienceNeededMaps(); loadFormula(); } + /** + * Initialize maps used for XP to next level + */ + private void initExperienceNeededMaps() { + experienceNeededRetroLinear = new HashMap<>(); + experienceNeededRetroExponential = new HashMap<>(); + experienceNeededStandardLinear = new HashMap<>(); + experienceNeededStandardExponential = new HashMap<>(); + } + /** * Get the formula type that was used before converting * @@ -60,7 +73,7 @@ public class FormulaManager { int totalXP = 0; for (int level = 0; level < skillLevel; level++) { - totalXP += getCachedXpToLevel(level, previousFormula); + totalXP += getXPtoNextLevel(level, previousFormula); } totalXP += skillXPLevel; @@ -83,7 +96,7 @@ public class FormulaManager { int maxLevel = Config.getInstance().getLevelCap(primarySkillType); while (experience > 0 && newLevel < maxLevel) { - int experienceToNextLevel = getCachedXpToLevel(newLevel, formulaType); + int experienceToNextLevel = getXPtoNextLevel(newLevel, formulaType); if (experience - experienceToNextLevel < 0) { remainder = experience; @@ -106,42 +119,97 @@ public class FormulaManager { * @param formulaType The {@link FormulaType} used * @return amount of experience needed to reach next level */ - public int getCachedXpToLevel(int level, FormulaType formulaType) { - int experience; - + public int getXPtoNextLevel(int level, FormulaType formulaType) { /** * Retro mode XP requirements are the default requirements * Standard mode XP requirements are multiplied by a factor of 10 */ - int xpNeededMultiplier = retroModeEnabled ? 1 : 10; + //TODO: When the heck is Unknown used? if (formulaType == FormulaType.UNKNOWN) { formulaType = FormulaType.LINEAR; } + return processXPToNextLevel(level, formulaType); + } + + /** + * Gets the value of XP needed for the next level based on the level Scaling, the level, and the formula type + * @param level target level + * @param formulaType target formulaType + */ + private int processXPToNextLevel(int level, FormulaType formulaType) { + if(mcMMO.isRetroModeEnabled()) + { + return processXPRetroToNextLevel(level, formulaType); + } else { + return processStandardXPToNextLevel(level, formulaType); + } + } + + /** + * Calculate the XP needed for the next level for the linear formula for Standard scaling (1-100) + * @param level target level + * @return raw xp needed to reach the next level + */ + private int processStandardXPToNextLevel(int level, FormulaType formulaType) { + Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededStandardLinear : experienceNeededStandardExponential; + + if(!experienceMapRef.containsKey(level)) { + int experienceSum = 0; + int retroIndex = (level * 10) + 1; + + //Sum the range of levels in Retro that this Standard level would represent + for(int x = retroIndex; x < (retroIndex + 10); x++) { + //calculateXPNeeded doesn't cache results so we use that instead of invoking the Retro XP methods to avoid memory bloat + experienceSum += calculateXPNeeded(x, formulaType); + } + + experienceMapRef.put(level, experienceSum); + } + + return experienceMapRef.get(level); + } + + /** + * Calculates the XP to next level for Retro Mode scaling + * Results are cached to reduce needless operations + * @param level target level + * @param formulaType target formula type + * @return raw xp needed to reach the next level based on formula type + */ + private int processXPRetroToNextLevel(int level, FormulaType formulaType) { + Map experienceMapRef = formulaType == FormulaType.LINEAR ? experienceNeededRetroLinear : experienceNeededRetroExponential; + + if (!experienceMapRef.containsKey(level)) { + int experience = calculateXPNeeded(level, FormulaType.LINEAR); + experienceMapRef.put(level, experience); + } + + return experienceMapRef.get(level); + } + + /** + * Does the actual math to get the XP needed for a level in RetroMode scaling + * Standard uses a sum of RetroMode XP needed levels for its own thing, so it uses this too + * @param level target level + * @param formulaType target formulatype + * @return the raw XP needed for the next level based on formula type + */ + private int calculateXPNeeded(int level, FormulaType formulaType) { int base = ExperienceConfig.getInstance().getBase(formulaType); double multiplier = ExperienceConfig.getInstance().getMultiplier(formulaType); - double exponent = ExperienceConfig.getInstance().getExponent(formulaType); - switch (formulaType) { + switch(formulaType) { case LINEAR: - if (!experienceNeededLinear.containsKey(level)) { - experience = (int) Math.floor( xpNeededMultiplier * (base + level * multiplier)); - experienceNeededLinear.put(level, experience); - } - - return experienceNeededLinear.get(level); - + return (int) Math.floor(base + level * multiplier); case EXPONENTIAL: - if (!experienceNeededExponential.containsKey(level)) { - experience = (int) Math.floor( xpNeededMultiplier * (multiplier * Math.pow(level, exponent) + base)); - experienceNeededExponential.put(level, experience); - } - - return experienceNeededExponential.get(level); - + double exponent = ExperienceConfig.getInstance().getExponent(formulaType); + return (int) Math.floor(multiplier * Math.pow(level, exponent) + base); default: - return 0; + //TODO: Should never be called + mcMMO.p.getLogger().severe("Invalid formula specified for calculation, defaulting to Linear"); + return calculateXPNeeded(level, FormulaType.LINEAR); } }