Skip to content

Commit 3551a64

Browse files
committed
Add new helpers for working with player experience and experience points.
1 parent a0042ca commit 3551a64

File tree

1 file changed

+138
-0
lines changed

1 file changed

+138
-0
lines changed
Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package net.darkhax.bookshelf.api.util;
2+
3+
import net.minecraft.world.entity.player.Player;
4+
5+
public final class ExperienceHelper {
6+
7+
/**
8+
* Attempts to charge the player an experience point cost. If the player can not afford the full amount they will
9+
* not be charged and false will be returned.
10+
*
11+
* @param player The player to charge.
12+
* @param cost The amount to charge the player in experience points.
13+
* @return True if the amount was paid.
14+
*/
15+
public static boolean chargeExperiencePoints(Player player, int cost) {
16+
17+
final int playerExperience = getExperiencePoints(player);
18+
19+
if (playerExperience >= cost) {
20+
21+
player.giveExperiencePoints(-cost);
22+
23+
// The underlying EXP system uses a float which is prone to rounding errors. This will sometimes leave
24+
// players with a small fraction of exp progress that is worth less than 1 exp point. These rounding errors
25+
// are so small that they do not introduce functionality issues however they can trigger a vanilla bug
26+
// where the EXP bar will still render a few pixels of progress even when the player has no exp points. To
27+
// prevent this issue here we simply reset all progress when the player spends all of their points.
28+
if (getExperiencePoints(player) <= 0) {
29+
30+
player.experienceProgress = 0f;
31+
}
32+
33+
return true;
34+
}
35+
36+
return false;
37+
}
38+
39+
/**
40+
* Calculates the amount of experience points the player currently has. This should be used in favour of {@link
41+
* Player#totalExperience} which deceptively does not track the amount of experience the player currently has.
42+
* <p>
43+
* Contrary to popular belief the {@link Player#totalExperience} value actually loosely represents how much
44+
* experience points the player has earned during their current life. This value is akin to the old player score
45+
* metric and appears to be predominantly legacy code. Relying on this value is often incorrect as negative changes
46+
* to the player level such as enchanting, the anvil, and the level command will not reduce this value.
47+
*
48+
* @param player The player to calculate the total experience points of.
49+
* @return The amount of experience points held by the player.
50+
*/
51+
public static int getExperiencePoints(Player player) {
52+
53+
// Start by calculating how many EXP points the player's current level is worth.
54+
int exp = getTotalPointsForLevel(player.experienceLevel);
55+
56+
// Add the amount of experience points the player has earned towards their next level.
57+
exp += player.experienceProgress * getTotalPointsForLevel(player.experienceLevel + 1);
58+
59+
return exp;
60+
}
61+
62+
/**
63+
* Calculates the amount of additional experience points required to reach the given level when starting from the
64+
* previous level. This will also be the amount of experience points that an individual level is worth.
65+
*
66+
* @param level The level to calculate the point step for.
67+
* @return The amount of points required to reach the given level when starting from the previous level.
68+
*/
69+
public static int getPointForLevel(int level) {
70+
71+
if (level == 0) {
72+
73+
return 0;
74+
}
75+
76+
else if (level > 30) {
77+
78+
return 112 + (level - 31) * 9;
79+
}
80+
81+
else if (level > 15) {
82+
83+
return 37 + (level - 16) * 5;
84+
}
85+
86+
else {
87+
88+
return 7 + (level - 1) * 2;
89+
}
90+
}
91+
92+
/**
93+
* Calculates the amount of additional experience points required to reach the target level when starting from the
94+
* starting level.
95+
*
96+
* @param startingLevel The level to start the calculation at.
97+
* @param targetLevel The level to reach.
98+
* @return The amount of additional experience points required to go from the starting level to the target level.
99+
*/
100+
public static int getPointsForLevel(int startingLevel, int targetLevel) {
101+
102+
if (targetLevel < startingLevel) {
103+
104+
throw new IllegalArgumentException("Starting level must be lower than the target level!");
105+
}
106+
107+
else if (startingLevel < 0) {
108+
109+
throw new IllegalArgumentException("Level bounds must be positive!");
110+
}
111+
112+
// If the levels are the same there is no point difference.
113+
else if (targetLevel == startingLevel) {
114+
115+
return 0;
116+
}
117+
118+
int requiredPoints = 0;
119+
120+
for (int lvl = startingLevel + 1; lvl <= targetLevel; lvl++) {
121+
122+
requiredPoints += getPointForLevel(lvl);
123+
}
124+
125+
return requiredPoints;
126+
}
127+
128+
/**
129+
* Calculates the total amount of experience points required to reach a given level when starting at level 0.
130+
*
131+
* @param level The target level to reach.
132+
* @return The amount of experience points required to reach the target level.
133+
*/
134+
public static int getTotalPointsForLevel(int level) {
135+
136+
return getPointsForLevel(0, level);
137+
}
138+
}

0 commit comments

Comments
 (0)