Merge pull request #328 from BentoBoxWorld/develop

Release 2.16.0
This commit is contained in:
tastybento 2024-09-16 19:11:04 -07:00 committed by GitHub
commit 5da21b88c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 783 additions and 636 deletions

View File

@ -59,7 +59,7 @@
<powermock.version>2.0.9</powermock.version> <powermock.version>2.0.9</powermock.version>
<!-- More visible way how to change dependency versions --> <!-- More visible way how to change dependency versions -->
<spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version> <spigot.version>1.20.4-R0.1-SNAPSHOT</spigot.version>
<bentobox.version>2.4.0-SNAPSHOT</bentobox.version> <bentobox.version>2.5.1-SNAPSHOT</bentobox.version>
<!-- Warps addon version --> <!-- Warps addon version -->
<warps.version>1.12.0</warps.version> <warps.version>1.12.0</warps.version>
<!-- Visit addon version --> <!-- Visit addon version -->
@ -71,7 +71,7 @@
<!-- Do not change unless you want different name for local builds. --> <!-- Do not change unless you want different name for local builds. -->
<build.number>-LOCAL</build.number> <build.number>-LOCAL</build.number>
<!-- This allows to change between versions. --> <!-- This allows to change between versions. -->
<build.version>2.15.0</build.version> <build.version>2.16.0</build.version>
<sonar.projectKey>BentoBoxWorld_Level</sonar.projectKey> <sonar.projectKey>BentoBoxWorld_Level</sonar.projectKey>
<sonar.organization>bentobox-world</sonar.organization> <sonar.organization>bentobox-world</sonar.organization>
<sonar.host.url>https://sonarcloud.io</sonar.host.url> <sonar.host.url>https://sonarcloud.io</sonar.host.url>

View File

@ -36,16 +36,8 @@ import world.bentobox.level.util.CachedData;
public class LevelsManager { public class LevelsManager {
private static final String INTOPTEN = "intopten"; private static final String INTOPTEN = "intopten";
private static final TreeMap<BigInteger, String> LEVELS; private static final TreeMap<BigInteger, String> LEVELS = new TreeMap<>();
private static final BigInteger THOUSAND = BigInteger.valueOf(1000); private static final BigInteger THOUSAND = BigInteger.valueOf(1000);
static {
LEVELS = new TreeMap<>();
LEVELS.put(THOUSAND, "k");
LEVELS.put(THOUSAND.pow(2), "M");
LEVELS.put(THOUSAND.pow(3), "G");
LEVELS.put(THOUSAND.pow(4), "T");
}
private final Level addon; private final Level addon;
// Database handler for level data // Database handler for level data
@ -67,6 +59,12 @@ public class LevelsManager {
levelsCache = new HashMap<>(); levelsCache = new HashMap<>();
// Initialize top ten lists // Initialize top ten lists
topTenLists = new ConcurrentHashMap<>(); topTenLists = new ConcurrentHashMap<>();
// Units
LEVELS.put(THOUSAND, addon.getSettings().getKilo());
LEVELS.put(THOUSAND.pow(2), addon.getSettings().getMega());
LEVELS.put(THOUSAND.pow(3), addon.getSettings().getGiga());
LEVELS.put(THOUSAND.pow(4), addon.getSettings().getTera());
} }
public void migrate() { public void migrate() {

View File

@ -46,10 +46,20 @@ public class AdminSetInitialLevelCommand extends CompositeCommand {
@Override @Override
public boolean execute(User user, String label, List<String> args) { public boolean execute(User user, String label, List<String> args) {
String initialLevel = String.valueOf(addon.getManager().getInitialLevel(island)); long initialLevel = addon.getManager().getInitialLevel(island);
long lv = Long.parseLong(args.get(1)); long lv = 0;
if (args.get(1).startsWith("+")) {
String change = args.get(1).substring(1);
lv = initialLevel + Long.parseLong(change);
} else if (args.get(1).startsWith("-")) {
String change = args.get(1).substring(1);
lv = initialLevel - Long.parseLong(change);
} else {
lv = Long.parseLong(args.get(1));
}
addon.getManager().setInitialIslandLevel(island, lv); addon.getManager().setInitialIslandLevel(island, lv);
user.sendMessage("admin.level.sethandicap.changed", TextVariables.NUMBER, initialLevel, "[new_number]", String.valueOf(lv)); user.sendMessage("admin.level.sethandicap.changed", TextVariables.NUMBER, String.valueOf(initialLevel),
"[new_number]", String.valueOf(lv));
return true; return true;
} }
@ -64,11 +74,21 @@ public class AdminSetInitialLevelCommand extends CompositeCommand {
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
return false; return false;
} }
// Check if this is a add or remove
if (args.get(1).startsWith("+") || args.get(1).startsWith("-")) {
String change = args.get(1).substring(1);
if (!Util.isInteger(change, true)) {
user.sendMessage("admin.level.sethandicap.invalid-level");
return false;
}
// Value is okay
} else {
// Check value // Check value
if (!Util.isInteger(args.get(1), true)) { if (!Util.isInteger(args.get(1), true)) {
user.sendMessage("admin.level.sethandicap.invalid-level"); user.sendMessage("admin.level.sethandicap.invalid-level");
return false; return false;
} }
}
// Check island // Check island
island = getAddon().getIslands().getIsland(getWorld(), targetUUID); island = getAddon().getIslands().getIsland(getWorld(), targetUUID);
if (island == null) { if (island == null) {

View File

@ -2,9 +2,12 @@ package world.bentobox.level.config;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -26,6 +29,7 @@ public class BlockConfig {
private Map<Material, Integer> blockLimits = new EnumMap<>(Material.class); private Map<Material, Integer> blockLimits = new EnumMap<>(Material.class);
private Map<Material, Integer> blockValues = new EnumMap<>(Material.class); private Map<Material, Integer> blockValues = new EnumMap<>(Material.class);
private final Map<World, Map<Material, Integer>> worldBlockValues = new HashMap<>(); private final Map<World, Map<Material, Integer>> worldBlockValues = new HashMap<>();
private final List<Material> hiddenBlocks;
private Level addon; private Level addon;
/** /**
@ -49,6 +53,16 @@ public class BlockConfig {
if (blockValues.isConfigurationSection("worlds")) { if (blockValues.isConfigurationSection("worlds")) {
loadWorlds(blockValues); loadWorlds(blockValues);
} }
// Hidden
hiddenBlocks = blockValues.getStringList("hidden-blocks").stream().map(name -> {
try {
return Material.valueOf(name.toUpperCase(Locale.ENGLISH));
} catch (Exception e) {
return null;
}
}).filter(Objects::nonNull).toList();
// All done // All done
blockValues.save(file); blockValues.save(file);
} }
@ -159,5 +173,22 @@ public class BlockConfig {
return null; return null;
} }
/**
* Return true if the block should be hidden
* @param m block material
* @return true if hidden
*/
public boolean isHiddenBlock(Material m) {
return hiddenBlocks.contains(m);
}
/**
* Return true if the block should not be hidden
* @param m block material
* @return false if hidden
*/
public boolean isNotHiddenBlock(Material m) {
return !hiddenBlocks.contains(m);
}
} }

View File

@ -3,6 +3,7 @@ package world.bentobox.level.config;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.BentoBox;
import world.bentobox.bentobox.api.configuration.ConfigComment; import world.bentobox.bentobox.api.configuration.ConfigComment;
@ -120,6 +121,17 @@ public class ConfigSettings implements ConfigObject {
@ConfigComment("Shows large level values rounded down, e.g., 10,345 -> 10k") @ConfigComment("Shows large level values rounded down, e.g., 10,345 -> 10k")
@ConfigEntry(path = "shorthand") @ConfigEntry(path = "shorthand")
private boolean shorthand = false; private boolean shorthand = false;
@ConfigComment("Shorthand units")
@ConfigEntry(path = "units.kilo")
private String kilo = "k";
@ConfigEntry(path = "units.mega")
private String mega = "M";
@ConfigEntry(path = "units.giga")
private String giga = "G";
@ConfigEntry(path = "units.tera")
private String tera = "T";
@ConfigComment("") @ConfigComment("")
@ConfigComment("Include Shulker Box content in chests in level calculations.") @ConfigComment("Include Shulker Box content in chests in level calculations.")
@ConfigComment("Will count blocks in Shulker Boxes inside of chests.") @ConfigComment("Will count blocks in Shulker Boxes inside of chests.")
@ -419,4 +431,60 @@ public class ConfigSettings implements ConfigObject {
public void setDisabledPluginHooks(List<String> disabledPluginHooks) { public void setDisabledPluginHooks(List<String> disabledPluginHooks) {
this.disabledPluginHooks = disabledPluginHooks; this.disabledPluginHooks = disabledPluginHooks;
} }
/**
* @return the kilo
*/
public String getKilo() {
return Objects.requireNonNullElse(kilo, "k");
}
/**
* @param kilo the kilo to set
*/
public void setKilo(String kilo) {
this.kilo = kilo;
}
/**
* @return the mega
*/
public String getMega() {
return Objects.requireNonNullElse(mega, "M");
}
/**
* @param mega the mega to set
*/
public void setMega(String mega) {
this.mega = mega;
}
/**
* @return the giga
*/
public String getGiga() {
return Objects.requireNonNullElse(giga, "G");
}
/**
* @param giga the giga to set
*/
public void setGiga(String giga) {
this.giga = giga;
}
/**
* @return the tera
*/
public String getTera() {
return Objects.requireNonNullElse(tera, "T");
}
/**
* @param tera the tera to set
*/
public void setTera(String tera) {
this.tera = tera;
}
} }

View File

@ -126,6 +126,9 @@ public class DetailsPanel {
return value == null || value == 0; return value == null || value == 0;
}); });
// Remove any hidden blocks
materialCountMap.keySet().removeIf(this.addon.getBlockConfig()::isHiddenBlock);
materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey())).forEachOrdered(entry -> { materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey())).forEachOrdered(entry -> {
if (entry.getValue() > 0) { if (entry.getValue() > 0) {
this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())); this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue()));
@ -142,16 +145,24 @@ public class DetailsPanel {
this.levelsData.getUwCount().forEach((material, count) -> materialCountMap.put(material, this.levelsData.getUwCount().forEach((material, count) -> materialCountMap.put(material,
materialCountMap.computeIfAbsent(material, key -> 0) + count)); materialCountMap.computeIfAbsent(material, key -> 0) + count));
// Remove any hidden blocks
materialCountMap.keySet().removeIf(this.addon.getBlockConfig()::isHiddenBlock);
materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey())) materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey()))
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue()))); .forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
} }
case ABOVE_SEA_LEVEL -> this.levelsData.getMdCount().entrySet().stream().sorted((Map.Entry.comparingByKey())) case ABOVE_SEA_LEVEL -> this.levelsData.getMdCount().entrySet().stream()
.filter(en -> this.addon.getBlockConfig().isNotHiddenBlock(en.getKey()))
.sorted((Map.Entry.comparingByKey()))
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue()))); .forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
case UNDERWATER -> this.levelsData.getUwCount().entrySet().stream().sorted((Map.Entry.comparingByKey())) case UNDERWATER -> this.levelsData.getUwCount().entrySet().stream()
.filter(en -> this.addon.getBlockConfig().isNotHiddenBlock(en.getKey()))
.sorted((Map.Entry.comparingByKey()))
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue()))); .forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
case SPAWNER -> { case SPAWNER -> {
if (this.addon.getBlockConfig().isNotHiddenBlock(Material.SPAWNER)) {
int aboveWater = this.levelsData.getMdCount().getOrDefault(Material.SPAWNER, 0); int aboveWater = this.levelsData.getMdCount().getOrDefault(Material.SPAWNER, 0);
int underWater = this.levelsData.getUwCount().getOrDefault(Material.SPAWNER, 0); int underWater = this.levelsData.getUwCount().getOrDefault(Material.SPAWNER, 0);
@ -159,6 +170,7 @@ public class DetailsPanel {
this.materialCountList.add(new Pair<>(Material.SPAWNER, underWater + aboveWater)); this.materialCountList.add(new Pair<>(Material.SPAWNER, underWater + aboveWater));
} }
} }
}
Comparator<Pair<Material, Integer>> sorter; Comparator<Pair<Material, Integer>> sorter;

View File

@ -59,6 +59,7 @@ public class ValuePanel
this.materialRecordList = Arrays.stream(Material.values()). this.materialRecordList = Arrays.stream(Material.values()).
filter(Material::isBlock). filter(Material::isBlock).
filter(m -> !m.name().startsWith("LEGACY_")). filter(m -> !m.name().startsWith("LEGACY_")).
filter(this.addon.getBlockConfig()::isNotHiddenBlock).
map(material -> map(material ->
{ {
Integer value = this.addon.getBlockConfig().getValue(this.world, material); Integer value = this.addon.getBlockConfig().getValue(this.world, material);

View File

@ -2,7 +2,7 @@ name: Level
main: world.bentobox.level.Level main: world.bentobox.level.Level
version: ${version}${build.number} version: ${version}${build.number}
icon: DIAMOND icon: DIAMOND
api-version: 2.4.0 api-version: 2.5.1
authors: tastybento authors: tastybento

View File

@ -10,6 +10,10 @@
limits: limits:
COBBLESTONE: 10000 COBBLESTONE: 10000
NETHERRACK: 1000 NETHERRACK: 1000
# These blocks will never be shown in the GUI even if they have value
hidden-blocks:
- BEDROCK
- AIR
blocks: blocks:
ACACIA_BUTTON: 1 ACACIA_BUTTON: 1
ACACIA_DOOR: 2 ACACIA_DOOR: 2

View File

@ -19,7 +19,7 @@ calculation-timeout: 5
# #
# Zero island levels on new island or island reset # Zero island levels on new island or island reset
# If true, Level will calculate the starter island's level and remove it from any future level calculations. # If true, Level will calculate the starter island's level and remove it from any future level calculations.
# If this is false, the player's starter island blocks will count towards their level. # If false, the player's starter island blocks will count towards their level.
# This will reduce CPU if false. # This will reduce CPU if false.
zero-new-island-levels: true zero-new-island-levels: true
# #
@ -72,3 +72,18 @@ sumteamdeaths: false
# Shorthand island level # Shorthand island level
# Shows large level values rounded down, e.g., 10,345 -> 10k # Shows large level values rounded down, e.g., 10,345 -> 10k
shorthand: false shorthand: false
units:
# Shorthand units
kilo: k
mega: M
giga: G
tera: T
#
# Include Shulker Box content in chests in level calculations.
# Will count blocks in Shulker Boxes inside of chests.
# NOTE: include-chests needs to be enabled for this to work!.
include-shulkers-in-chest: false
#
# Disables hooking with other plugins.
# Example: disabled-plugin-hooks: [UltimateStacker, RoseStacker]
disabled-plugin-hooks: []

View File

@ -8,8 +8,12 @@ admin:
parameters: "<player>" parameters: "<player>"
description: "calculate the island level for player" description: "calculate the island level for player"
sethandicap: sethandicap:
parameters: <player> <handicap> parameters: <player> [+/-]<handicap>
description: "set the island handicap, usually the level of the starter island" description: |
set or change the island *handicap*
e.g. +10 will remove 10 levels,
30 will set handicap to 30,
-20 will add 20 levels
changed: "&a Initial island handicap changed from [number] to [new_number]." changed: "&a Initial island handicap changed from [number] to [new_number]."
invalid-level: "&c Invalid handicap. Use an integer." invalid-level: "&c Invalid handicap. Use an integer."
levelstatus: levelstatus:

View File

@ -132,17 +132,10 @@ detail_panel:
8: material_button 8: material_button
3: 3:
1: 1:
# In this case, the icon is defined as a TIPPED_ARROW with and enchantment applied. The format for the enchantment is # In this case, the icon is defined as a TIPPED_ARROW with a color.
# define in {@link world.bentobox.bentobox.util.ItemParser} and available for POTIONS or TIPPED_ARROWs. # CustomPotionColor uses the Decimal description of a Color, just as leather armor does.
# Format TIPPED_ARROW:NAME:<LEVEL>:<EXTENDED>:<SPLASH/LINGER>:QTY # All you need to do is take a hex code of a color (like #ff00aa) which represents red,
# LEVEL, EXTENDED, SPLASH, LINGER are optional. # green, blue as 2 hex digits each and convert that number into a decimal, using a hex to decimal calculator.
# LEVEL is a number, 1 or 2
# LINGER is for V1.9 servers and later
# Examples:
# TIPPED_ARROW:STRENGTH:1:EXTENDED:SPLASH:1
# TIPPED_ARROW:INSTANT_DAMAGE:2::LINGER:2
# TIPPED_ARROW:JUMP:2:NOTEXTENDED:NOSPLASH:1
# TIPPED_ARROW:WEAKNESS::::1 - any weakness enchantment
icon: tipped_arrow{CustomPotionColor:11546150} icon: tipped_arrow{CustomPotionColor:11546150}
title: level.gui.buttons.previous.name title: level.gui.buttons.previous.name
description: level.gui.buttons.previous.description description: level.gui.buttons.previous.description

View File

@ -95,7 +95,7 @@ public class LevelsManagerTest {
private World world; private World world;
@Mock @Mock
private Player player; private Player player;
@Mock
private ConfigSettings settings; private ConfigSettings settings;
@Mock @Mock
private User user; private User user;
@ -176,6 +176,7 @@ public class LevelsManagerTest {
when(world.getName()).thenReturn("bskyblock-world"); when(world.getName()).thenReturn("bskyblock-world");
// Settings // Settings
settings = new ConfigSettings();
when(addon.getSettings()).thenReturn(settings); when(addon.getSettings()).thenReturn(settings);
// User // User
@ -334,7 +335,7 @@ public class LevelsManagerTest {
@Test @Test
public void testFormatLevel() { public void testFormatLevel() {
assertEquals("123456789", lm.formatLevel(123456789L)); assertEquals("123456789", lm.formatLevel(123456789L));
when(settings.isShorthand()).thenReturn(true); settings.setShorthand(true);
assertEquals("123.5M", lm.formatLevel(123456789L)); assertEquals("123.5M", lm.formatLevel(123456789L));
assertEquals("1.2k", lm.formatLevel(1234L)); assertEquals("1.2k", lm.formatLevel(1234L));
assertEquals("123.5G", lm.formatLevel(123456789352L)); assertEquals("123.5G", lm.formatLevel(123456789352L));