Skip to content

Commit c7831cb

Browse files
authored
Merge pull request #362 from BentoBoxWorld/develop
2.20.0 release
2 parents 23c2a9d + 0a4a9c6 commit c7831cb

File tree

12 files changed

+478
-211
lines changed

12 files changed

+478
-211
lines changed

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
<!-- Do not change unless you want different name for local builds. -->
6868
<build.number>-LOCAL</build.number>
6969
<!-- This allows to change between versions. -->
70-
<build.version>2.19.3</build.version>
70+
<build.version>2.20.0</build.version>
7171
<sonar.projectKey>BentoBoxWorld_Level</sonar.projectKey>
7272
<sonar.organization>bentobox-world</sonar.organization>
7373
<sonar.host.url>https://sonarcloud.io</sonar.host.url>

src/main/java/world/bentobox/level/Level.java

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -339,12 +339,13 @@ public long getIslandLevel(World world, @Nullable UUID targetPlayer) {
339339
}
340340

341341
/**
342-
* Sets the player's level to a value
343-
*
344-
* @param world - world
345-
* @param targetPlayer - target player
346-
* @param level - level
347-
*/
342+
* Sets the player's level to a value. This will only last until the player reruns the level command
343+
*
344+
* @param world - world
345+
* @param targetPlayer - target player
346+
* @param level - level
347+
* @deprecated This is a useless method.
348+
*/
348349
public void setIslandLevel(World world, UUID targetPlayer, long level) {
349350
getManager().setIslandLevel(world, targetPlayer, level);
350351
}
@@ -355,19 +356,31 @@ public void setIslandLevel(World world, UUID targetPlayer, long level) {
355356
* @param island - island
356357
* @param level - initial calculated island level
357358
*/
358-
public void setInitialIslandLevel(@NonNull Island island, long level) {
359-
getManager().setInitialIslandLevel(island, level);
360-
}
359+
/* TODO
360+
public void setInitialIslandLevel(@NonNull Island island, long level) {
361+
getManager().setInitialIslandLevel(island, level);
362+
}
363+
364+
/**
365+
* Get the initial island level
366+
*
367+
* @param island - island
368+
* @return level or 0 by default
369+
*/
370+
/* TODO
371+
public long getInitialIslandLevel(@NonNull Island island) {
372+
return getManager().getInitialLevel(island);
373+
}*/
361374

362-
/**
363-
* Get the initial island level
364-
*
365-
* @param island - island
366-
* @return level or 0 by default
367-
*/
368-
public long getInitialIslandLevel(@NonNull Island island) {
369-
return getManager().getInitialLevel(island);
370-
}
375+
/**
376+
* Get the initial island count
377+
*
378+
* @param island - island
379+
* @return count or 0 by default
380+
*/
381+
public long getInitialIslandCount(@NonNull Island island) {
382+
return getManager().getInitialCount(island);
383+
}
371384

372385
/**
373386
* Calculates a user's island
@@ -392,21 +405,22 @@ public void calculateIslandLevel(World world, @Nullable User user, @NonNull UUID
392405
* @return LevelsData object or null if not found. Only island levels are set!
393406
* @deprecated Do not use this anymore. Use {@link #getIslandLevel(World, UUID)}
394407
*/
395-
@Deprecated(since = "2.3.0", forRemoval = true)
396-
public LevelsData getLevelsData(UUID targetPlayer) {
397-
LevelsData ld = new LevelsData(targetPlayer);
398-
getPlugin().getAddonsManager().getGameModeAddons().stream()
399-
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
400-
if (getSettings().isZeroNewIslandLevels()) {
401-
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
402-
if (island != null) {
403-
ld.setInitialLevel(gm.getOverWorld(), this.getInitialIslandLevel(island));
404-
}
405-
}
406-
ld.setLevel(gm.getOverWorld(), this.getIslandLevel(gm.getOverWorld(), targetPlayer));
407-
});
408-
return ld;
409-
}
408+
/*
409+
@Deprecated(since = "2.3.0", forRemoval = true)
410+
public LevelsData getLevelsData(UUID targetPlayer) {
411+
LevelsData ld = new LevelsData(targetPlayer);
412+
getPlugin().getAddonsManager().getGameModeAddons().stream()
413+
.filter(gm -> !settings.getGameModes().contains(gm.getDescription().getName())).forEach(gm -> {
414+
if (getSettings().isZeroNewIslandLevels()) {
415+
Island island = getIslands().getIsland(gm.getOverWorld(), targetPlayer);
416+
if (island != null) {
417+
ld.setInitialLevel(gm.getOverWorld(), this.getInitialIslandLevel(island));
418+
}
419+
}
420+
ld.setLevel(gm.getOverWorld(), this.getIslandLevel(gm.getOverWorld(), targetPlayer));
421+
});
422+
return ld;
423+
}*/
410424

411425
/**
412426
* @return the registeredGameModes

src/main/java/world/bentobox/level/LevelsManager.java

Lines changed: 66 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package world.bentobox.level;
22

3+
import java.io.IOException;
34
import java.math.BigInteger;
45
import java.text.DecimalFormat;
6+
import java.text.ParseException;
57
import java.time.Instant;
68
import java.util.AbstractMap;
79
import java.util.Collections;
@@ -26,6 +28,7 @@
2628

2729
import world.bentobox.bentobox.database.Database;
2830
import world.bentobox.bentobox.database.objects.Island;
31+
import world.bentobox.level.calculators.EquationEvaluator;
2932
import world.bentobox.level.calculators.Results;
3033
import world.bentobox.level.events.IslandLevelCalculatedEvent;
3134
import world.bentobox.level.events.IslandPreLevelEvent;
@@ -130,7 +133,7 @@ private boolean fireIslandLevelCalcEvent(UUID targetPlayer, Island island, Resul
130133
return true;
131134
// Set the values if they were altered
132135
results.setLevel((Long) ilce.getKeyValues().getOrDefault("level", results.getLevel()));
133-
results.setInitialLevel((Long) ilce.getKeyValues().getOrDefault("initialLevel", results.getInitialLevel()));
136+
results.setInitialCount((Long) ilce.getKeyValues().getOrDefault("initialCount", results.getInitialCount()));
134137
results.setDeathHandicap((int) ilce.getKeyValues().getOrDefault("deathHandicap", results.getDeathHandicap()));
135138
results.setPointsToNextLevel(
136139
(Long) ilce.getKeyValues().getOrDefault("pointsToNextLevel", results.getPointsToNextLevel()));
@@ -168,13 +171,65 @@ public String formatLevel(@Nullable Long lvl) {
168171
}
169172

170173
/**
171-
* Get the initial level of the island. Used to zero island levels
174+
* Get the initial count of the island. Used to zero island levels
172175
*
173176
* @param island - island
174-
* @return initial level of island
177+
* @return initial count of island
175178
*/
176-
public long getInitialLevel(Island island) {
177-
return getLevelsData(island).getInitialLevel();
179+
@SuppressWarnings("deprecation")
180+
public long getInitialCount(Island island) {
181+
Long initialLevel = getLevelsData(island).getInitialLevel(); // Backward compatibility check. For all new islands, this should be null.
182+
Long initialCount = getLevelsData(island).getInitialCount();
183+
if (initialLevel != null) {
184+
// Initial level exists so convert it
185+
if (initialCount == null) { // If initialCount is not null, then this is an edge case and initialCount will be used and initialLevel discarded
186+
// Convert from level to count
187+
initialCount = 0L;
188+
try {
189+
initialCount = getNumBlocks(initialLevel);
190+
} catch (Exception e) {
191+
addon.logError("Could not convert legacy initial level to count, so it will be set to 0. Error is: "
192+
+ e.getLocalizedMessage());
193+
initialCount = 0L;
194+
}
195+
}
196+
// Null out the old initial level and save
197+
getLevelsData(island).setInitialLevel(null);
198+
// Save
199+
this.setInitialIslandCount(island, initialCount);
200+
}
201+
// If initialCount doesn't exist, set it to 0L
202+
if (initialCount == null) {
203+
initialCount = 0L;
204+
getLevelsData(island).setInitialCount(0L);
205+
}
206+
return initialCount;
207+
}
208+
209+
/**
210+
* Runs the level calculation using the current formula until the level matches the initial value, or fails.
211+
* @param initialLevel - the old initial level
212+
* @return block count to obtain this level now
213+
* @throws ParseException if the formula for level calc is bugged
214+
* @throws IOException if the number of blocks cannot be found for this level
215+
*/
216+
private long getNumBlocks(final long initialLevel) throws ParseException, IOException {
217+
String calcString = addon.getSettings().getLevelCalc();
218+
int result = -1;
219+
long calculatedLevel = 0;
220+
String withCost = calcString.replace("level_cost", String.valueOf(this.addon.getSettings().getLevelCost()));
221+
long time = System.currentTimeMillis() + 10 * 1000; // 10 seconds
222+
do {
223+
result++;
224+
if (System.currentTimeMillis() > time) {
225+
throw new IOException("Timeout: Blocks cannot be found to create this initial level");
226+
}
227+
// Paste in the values to the formula
228+
String withValues = withCost.replace("blocks", String.valueOf(result));
229+
// Try and evaluate it
230+
calculatedLevel = (long) EquationEvaluator.eval(withValues);
231+
} while (calculatedLevel != initialLevel);
232+
return result;
178233
}
179234

180235
/**
@@ -422,15 +477,13 @@ public void removeEntry(World world, String uuid) {
422477
}
423478

424479
/**
425-
* Set an initial island level
480+
* Set an initial island count
426481
*
427-
* @param island - the island to set. Must have a non-null world
428-
* @param lv - initial island level
482+
* @param island - the island to set.
483+
* @param lv - initial island count
429484
*/
430-
public void setInitialIslandLevel(@NonNull Island island, long lv) {
431-
if (island.getWorld() == null)
432-
return;
433-
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialLevel(lv);
485+
public void setInitialIslandCount(@NonNull Island island, long lv) {
486+
levelsCache.computeIfAbsent(island.getUniqueId(), IslandLevels::new).setInitialCount(lv);
434487
handler.saveObjectAsync(levelsCache.get(island.getUniqueId()));
435488
}
436489

@@ -448,12 +501,7 @@ public void setIslandLevel(@NonNull World world, @NonNull UUID targetPlayer, lon
448501
if (island != null) {
449502
String id = island.getUniqueId();
450503
IslandLevels il = levelsCache.computeIfAbsent(id, IslandLevels::new);
451-
// Remove the initial level
452-
if (addon.getSettings().isZeroNewIslandLevels()) {
453-
il.setLevel(lv - il.getInitialLevel());
454-
} else {
455-
il.setLevel(lv);
456-
}
504+
il.setLevel(lv);
457505
handler.saveObjectAsync(levelsCache.get(id));
458506
// Update TopTen
459507
addToTopTen(island, levelsCache.get(id).getLevel());

src/main/java/world/bentobox/level/PlaceholderManager.java

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import java.util.stream.Collectors;
99

1010
import org.bukkit.World;
11+
import org.bukkit.Material;
1112
import org.eclipse.jdt.annotation.Nullable;
13+
import org.bukkit.Bukkit;
1214

1315
import world.bentobox.bentobox.BentoBox;
1416
import world.bentobox.bentobox.api.addons.GameModeAddon;
@@ -97,6 +99,87 @@ protected void registerPlaceholders(GameModeAddon gm) {
9799
// Personal rank
98100
bpm.registerPlaceholder(addon, gm.getDescription().getName().toLowerCase() + "_rank_value",
99101
u -> getRankValue(gm.getOverWorld(), u));
102+
103+
// Register mainhand placeholders
104+
bpm.registerPlaceholder(addon,
105+
gm.getDescription().getName().toLowerCase() + "_island_value_mainhand",
106+
user -> {
107+
if (user.getPlayer() == null || !user.getPlayer().getInventory().getItemInMainHand().getType().isBlock()) {
108+
return "0";
109+
}
110+
String blockName = user.getPlayer().getInventory().getItemInMainHand().getType().getKey().getKey();
111+
return String.valueOf(Objects.requireNonNullElse(
112+
addon.getBlockConfig().getValue(gm.getOverWorld(), blockName),
113+
0
114+
));
115+
}
116+
);
117+
118+
bpm.registerPlaceholder(addon,
119+
gm.getDescription().getName().toLowerCase() + "_island_count_mainhand",
120+
user -> {
121+
if (user.getPlayer() == null || !user.getPlayer().getInventory().getItemInMainHand().getType().isBlock()) {
122+
return "0";
123+
}
124+
Material material = user.getPlayer().getInventory().getItemInMainHand().getType();
125+
return getBlockCount(gm, user, material);
126+
}
127+
);
128+
129+
// Register looking at block placeholders
130+
bpm.registerPlaceholder(addon,
131+
gm.getDescription().getName().toLowerCase() + "_island_value_looking",
132+
user -> {
133+
if (user.getPlayer() == null) return "0";
134+
var targetBlock = user.getPlayer().getTargetBlock(null, 5);
135+
if (targetBlock != null && !targetBlock.getType().isAir()) {
136+
String blockName = targetBlock.getType().getKey().getKey();
137+
return String.valueOf(Objects.requireNonNullElse(
138+
addon.getBlockConfig().getValue(gm.getOverWorld(), blockName),
139+
0
140+
));
141+
}
142+
return "0";
143+
}
144+
);
145+
146+
bpm.registerPlaceholder(addon,
147+
gm.getDescription().getName().toLowerCase() + "_island_count_looking",
148+
user -> {
149+
if (user.getPlayer() == null) return "0";
150+
var targetBlock = user.getPlayer().getTargetBlock(null, 5);
151+
if (targetBlock != null && !targetBlock.getType().isAir()) {
152+
return getBlockCount(gm, user, targetBlock.getType());
153+
}
154+
return "0";
155+
}
156+
);
157+
158+
// Register placeholders for all block materials
159+
if (Bukkit.getServer() != null) {
160+
// Get all materials from the block config
161+
addon.getBlockConfig().getBlockValues().keySet().forEach(blockName -> {
162+
String formattedName = blockName.replace(':', '_').toLowerCase();
163+
164+
// Register value placeholder
165+
bpm.registerPlaceholder(addon,
166+
gm.getDescription().getName().toLowerCase() + "_island_value_" + formattedName,
167+
user -> String.valueOf(Objects.requireNonNullElse(
168+
addon.getBlockConfig().getValue(gm.getOverWorld(), blockName),
169+
0
170+
))
171+
);
172+
173+
// Register count placeholder
174+
bpm.registerPlaceholder(addon,
175+
gm.getDescription().getName().toLowerCase() + "_island_count_" + formattedName,
176+
user -> {
177+
Material material = Material.valueOf(blockName.toUpperCase());
178+
return getBlockCount(gm, user, material);
179+
}
180+
);
181+
});
182+
}
100183
}
101184

102185
/**
@@ -220,4 +303,43 @@ String getVisitedIslandLevel(GameModeAddon gm, User user) {
220303
.orElse("0");
221304
}
222305

306+
/**
307+
* Gets the block count for a specific material in a user's island
308+
* @param gm GameModeAddon
309+
* @param user User requesting the count
310+
* @param material Material to count
311+
* @return String representation of the count
312+
*/
313+
private String getBlockCount(GameModeAddon gm, User user, Object material) {
314+
if (user == null) {
315+
return "0";
316+
}
317+
return getBlockCountForUser(gm, user, material);
318+
}
319+
320+
/**
321+
* Gets the block count for a specific material in a user's island
322+
* @param gm GameModeAddon
323+
* @param user User to get count for
324+
* @param material Material to count
325+
* @return String representation of the count
326+
*/
327+
private String getBlockCountForUser(GameModeAddon gm, User user, Object material) {
328+
// Get the island for the user
329+
Island island = addon.getIslands().getIsland(gm.getOverWorld(), user);
330+
if (island == null) {
331+
return "0";
332+
}
333+
334+
// Get the level data for the island
335+
IslandLevels data = addon.getManager().getLevelsData(island);
336+
if (data == null) {
337+
return "0";
338+
}
339+
340+
// Get the total count from both above sea level and underwater
341+
int count = data.getMdCount().getOrDefault(material, 0) + data.getUwCount().getOrDefault(material, 0);
342+
return String.valueOf(count);
343+
}
344+
223345
}

0 commit comments

Comments
 (0)