mirror of
https://github.com/BentoBoxWorld/Level.git
synced 2025-02-24 07:31:49 +01:00
Merge pull request #344 from BentoBoxWorld/342_different_spawner_types
342 different spawner types
This commit is contained in:
commit
8390800994
12
.github/workflows/build.yml
vendored
12
.github/workflows/build.yml
vendored
@ -11,22 +11,22 @@ jobs:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
- name: Set up JDK 21
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'adopt'
|
||||
java-version: 17
|
||||
java-version: '21'
|
||||
- name: Cache SonarCloud packages
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.sonar/cache
|
||||
key: ${{ runner.os }}-sonar
|
||||
restore-keys: ${{ runner.os }}-sonar
|
||||
- name: Cache Maven packages
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
|
||||
|
6
pom.xml
6
pom.xml
@ -50,12 +50,12 @@
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||
<java.version>17</java.version>
|
||||
<java.version>21</java.version>
|
||||
<!-- Non-minecraft related dependencies -->
|
||||
<powermock.version>2.0.9</powermock.version>
|
||||
<!-- More visible way how to change dependency versions -->
|
||||
<spigot.version>1.21.3-R0.1-SNAPSHOT</spigot.version>
|
||||
<bentobox.version>2.7.1-SNAPSHOT</bentobox.version>
|
||||
<bentobox.version>3.2.4-SNAPSHOT</bentobox.version>
|
||||
<!-- Warps addon version -->
|
||||
<warps.version>1.12.0</warps.version>
|
||||
<!-- Visit addon version -->
|
||||
@ -67,7 +67,7 @@
|
||||
<!-- Do not change unless you want different name for local builds. -->
|
||||
<build.number>-LOCAL</build.number>
|
||||
<!-- This allows to change between versions. -->
|
||||
<build.version>2.17.1</build.version>
|
||||
<build.version>2.18.0</build.version>
|
||||
<sonar.projectKey>BentoBoxWorld_Level</sonar.projectKey>
|
||||
<sonar.organization>bentobox-world</sonar.organization>
|
||||
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
|
||||
|
@ -106,7 +106,7 @@ public class Level extends Addon {
|
||||
// Register listeners
|
||||
this.registerListener(new IslandActivitiesListeners(this));
|
||||
this.registerListener(new JoinLeaveListener(this));
|
||||
this.registerListener(new MigrationListener(this));
|
||||
this.registerListener(new MigrationListener(this));
|
||||
|
||||
// Register commands for GameModes
|
||||
registeredGameModes.clear();
|
||||
|
@ -30,7 +30,6 @@ import world.bentobox.level.calculators.Results;
|
||||
import world.bentobox.level.events.IslandLevelCalculatedEvent;
|
||||
import world.bentobox.level.events.IslandPreLevelEvent;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.objects.LevelsData;
|
||||
import world.bentobox.level.objects.TopTenData;
|
||||
import world.bentobox.level.util.CachedData;
|
||||
|
||||
@ -67,38 +66,6 @@ public class LevelsManager {
|
||||
|
||||
}
|
||||
|
||||
public void migrate() {
|
||||
Database<LevelsData> oldDb = new Database<>(addon, LevelsData.class);
|
||||
oldDb.loadObjects().forEach(ld -> {
|
||||
try {
|
||||
UUID owner = UUID.fromString(ld.getUniqueId());
|
||||
// Step through each world
|
||||
ld.getLevels().keySet().stream()
|
||||
// World
|
||||
.map(Bukkit::getWorld).filter(Objects::nonNull)
|
||||
// Island
|
||||
.map(w -> addon.getIslands().getIsland(w, owner)).filter(Objects::nonNull).forEach(i -> {
|
||||
// Make new database entry
|
||||
World w = i.getWorld();
|
||||
IslandLevels il = new IslandLevels(i.getUniqueId());
|
||||
il.setInitialLevel(ld.getInitialLevel(w));
|
||||
il.setLevel(ld.getLevel(w));
|
||||
il.setMdCount(ld.getMdCount(w));
|
||||
il.setPointsToNextLevel(ld.getPointsToNextLevel(w));
|
||||
il.setUwCount(ld.getUwCount(w));
|
||||
// Save it
|
||||
handler.saveObjectAsync(il);
|
||||
});
|
||||
// Now delete the old database entry
|
||||
oldDb.deleteID(ld.getUniqueId());
|
||||
} catch (Exception e) {
|
||||
addon.logError("Could not migrate level data database! " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an island to a top ten
|
||||
*
|
||||
@ -289,6 +256,7 @@ public class LevelsManager {
|
||||
if (ld != null) {
|
||||
levelsCache.put(id, ld);
|
||||
} else {
|
||||
// Clean up just in case
|
||||
handler.deleteID(id);
|
||||
levelsCache.put(id, new IslandLevels(id));
|
||||
}
|
||||
|
@ -2,14 +2,15 @@ package world.bentobox.level.calculators;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
@ -31,9 +32,9 @@ import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.block.ShulkerBox;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Slab;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.meta.BlockStateMeta;
|
||||
import org.bukkit.scheduler.BukkitTask;
|
||||
|
||||
import com.bgsoftware.wildstacker.api.WildStackerAPI;
|
||||
import com.bgsoftware.wildstacker.api.objects.StackedBarrel;
|
||||
@ -55,24 +56,11 @@ import world.bentobox.level.calculators.Results.Result;
|
||||
public class IslandLevelCalculator {
|
||||
private static final String LINE_BREAK = "==================================";
|
||||
public static final long MAX_AMOUNT = 10000000;
|
||||
private static final List<Material> CHESTS = Arrays.asList(Material.CHEST, Material.CHEST_MINECART,
|
||||
Material.TRAPPED_CHEST, Material.SHULKER_BOX, Material.BLACK_SHULKER_BOX, Material.BLUE_SHULKER_BOX,
|
||||
Material.BROWN_SHULKER_BOX, Material.CYAN_SHULKER_BOX, Material.GRAY_SHULKER_BOX,
|
||||
Material.GREEN_SHULKER_BOX, Material.LIGHT_BLUE_SHULKER_BOX, Material.LIGHT_GRAY_SHULKER_BOX,
|
||||
Material.LIME_SHULKER_BOX, Material.MAGENTA_SHULKER_BOX, Material.ORANGE_SHULKER_BOX,
|
||||
Material.PINK_SHULKER_BOX, Material.PURPLE_SHULKER_BOX, Material.RED_SHULKER_BOX, Material.RED_SHULKER_BOX,
|
||||
Material.WHITE_SHULKER_BOX, Material.YELLOW_SHULKER_BOX, Material.COMPOSTER, Material.BARREL,
|
||||
Material.DISPENSER, Material.DROPPER, Material.SMOKER, Material.BLAST_FURNACE, Material.BUNDLE,
|
||||
Material.RED_BUNDLE, Material.BLACK_BUNDLE, Material.BLUE_BUNDLE, Material.BROWN_BUNDLE,
|
||||
Material.CYAN_BUNDLE, Material.GRAY_BUNDLE, Material.GREEN_BUNDLE, Material.LIGHT_BLUE_BUNDLE,
|
||||
Material.LIGHT_GRAY_BUNDLE, Material.LIME_BUNDLE, Material.MAGENTA_BUNDLE, Material.ORANGE_BUNDLE,
|
||||
Material.PINK_BUNDLE, Material.PURPLE_BUNDLE, Material.RED_BUNDLE, Material.WHITE_BUNDLE,
|
||||
Material.YELLOW_BUNDLE);
|
||||
private static final int CHUNKS_TO_SCAN = 100;
|
||||
private final Level addon;
|
||||
private final Queue<Pair<Integer, Integer>> chunksToCheck;
|
||||
private final Island island;
|
||||
private final Map<Material, Integer> limitCount;
|
||||
private final Map<Object, Integer> limitCount;
|
||||
private final CompletableFuture<Results> r;
|
||||
|
||||
private final Results results;
|
||||
@ -82,7 +70,7 @@ public class IslandLevelCalculator {
|
||||
private final int seaHeight;
|
||||
private final List<Location> stackedBlocks = new ArrayList<>();
|
||||
private final Set<Chunk> chestBlocks = new HashSet<>();
|
||||
private BukkitTask finishTask;
|
||||
private final Map<Location, Boolean> spawners = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor to get the level for an island
|
||||
@ -101,7 +89,7 @@ public class IslandLevelCalculator {
|
||||
results = new Results();
|
||||
duration = System.currentTimeMillis();
|
||||
chunksToCheck = getChunksToScan(island);
|
||||
this.limitCount = new EnumMap<>(addon.getBlockConfig().getBlockLimits());
|
||||
this.limitCount = new HashMap<>();
|
||||
// Get the initial island level
|
||||
results.initialLevel.set(addon.getInitialIslandLevel(island));
|
||||
// Set up the worlds
|
||||
@ -163,6 +151,26 @@ public class IslandLevelCalculator {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds value to the results based on the material and whether the block is
|
||||
* below sea level or not
|
||||
*
|
||||
* @param mat - material of the block
|
||||
* @param belowSeaLevel - true if below sea level
|
||||
*/
|
||||
private void checkSpawner(EntityType et, boolean belowSeaLevel) {
|
||||
Integer count = limitCount(et);
|
||||
if (count != null) {
|
||||
if (belowSeaLevel) {
|
||||
results.underWaterBlockCount.addAndGet(count);
|
||||
results.uwCount.add(et);
|
||||
} else {
|
||||
results.rawBlockCount.addAndGet(count);
|
||||
results.mdCount.add(et);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a set of all the chunks in island
|
||||
*
|
||||
@ -231,31 +239,17 @@ public class IslandLevelCalculator {
|
||||
|
||||
reportLines.add(
|
||||
"Blocks not counted because they exceeded limits: " + String.format("%,d", results.ofCount.size()));
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = results.ofCount.entrySet();
|
||||
Iterator<Entry<Material>> it = entriesSortedByCount.iterator();
|
||||
Iterable<Multiset.Entry<Object>> entriesSortedByCount = results.ofCount.entrySet();
|
||||
Iterator<Entry<Object>> it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
Integer limit = addon.getBlockConfig().getBlockLimits().get(type.getElement());
|
||||
|
||||
Entry<Object> type = it.next();
|
||||
Integer limit = addon.getBlockConfig().getLimit(type);
|
||||
String explain = ")";
|
||||
if (limit == null) {
|
||||
Material generic = type.getElement();
|
||||
limit = addon.getBlockConfig().getBlockLimits().get(generic);
|
||||
explain = " - All types)";
|
||||
}
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d", type.getCount())
|
||||
reportLines.add(Util.prettifyText(type.toString()) + ": " + String.format("%,d", type.getCount())
|
||||
+ " blocks (max " + limit + explain);
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
reportLines.add("Blocks on island that are not in config.yml");
|
||||
reportLines.add("Total number = " + String.format("%,d", results.ncCount.size()));
|
||||
entriesSortedByCount = results.ncCount.entrySet();
|
||||
it = entriesSortedByCount.iterator();
|
||||
while (it.hasNext()) {
|
||||
Entry<Material> type = it.next();
|
||||
reportLines.add(type.getElement().toString() + ": " + String.format("%,d", type.getCount()) + " blocks");
|
||||
}
|
||||
reportLines.add(LINE_BREAK);
|
||||
|
||||
return reportLines;
|
||||
}
|
||||
|
||||
@ -269,10 +263,10 @@ public class IslandLevelCalculator {
|
||||
/**
|
||||
* Get value of a material World blocks trump regular block values
|
||||
*
|
||||
* @param md - Material to check
|
||||
* @return value of a material
|
||||
* @param md - Material or EntityType to check
|
||||
* @return value
|
||||
*/
|
||||
private int getValue(Material md) {
|
||||
private int getValue(Object md) {
|
||||
Integer value = addon.getBlockConfig().getValue(island.getWorld(), md);
|
||||
if (value == null) {
|
||||
// Not in config
|
||||
@ -333,24 +327,28 @@ public class IslandLevelCalculator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a block has been limited or not and whether a block has any value
|
||||
* or not
|
||||
*
|
||||
* @param md Material
|
||||
* @return value of the block if can be counted
|
||||
* Checks if the given object (Material or EntityType) has reached its limit.
|
||||
* If it hasn't, the object's value is returned and its count is incremented.
|
||||
* If the object is not a Material or EntityType, or if it has exceeded its limit, 0 is returned.
|
||||
*
|
||||
* @param obj A Material or EntityType
|
||||
* @return The object's value if within limit, otherwise 0.
|
||||
*/
|
||||
private int limitCount(Material md) {
|
||||
if (limitCount.containsKey(md)) {
|
||||
int count = limitCount.get(md);
|
||||
if (count > 0) {
|
||||
limitCount.put(md, --count);
|
||||
return getValue(md);
|
||||
} else {
|
||||
results.ofCount.add(md);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return getValue(md);
|
||||
private int limitCount(Object obj) {
|
||||
// Only process if obj is a Material or EntityType
|
||||
if (!(obj instanceof Material) && !(obj instanceof EntityType))
|
||||
return 0;
|
||||
|
||||
Integer limit = addon.getBlockConfig().getLimit(obj);
|
||||
if (limit == null)
|
||||
return getValue(obj);
|
||||
|
||||
int count = limitCount.getOrDefault(obj, 0);
|
||||
if (count > limit)
|
||||
return 0;
|
||||
|
||||
limitCount.put(obj, count + 1);
|
||||
return getValue(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -454,6 +452,8 @@ public class IslandLevelCalculator {
|
||||
BlockData blockData = cp.chunkSnapshot.getBlockData(x, y, z);
|
||||
Material m = blockData.getMaterial();
|
||||
boolean belowSeaLevel = seaHeight > 0 && y <= seaHeight;
|
||||
Location loc = new Location(cp.world, (double) x + cp.chunkSnapshot.getX() * 16, y,
|
||||
(double) z + cp.chunkSnapshot.getZ() * 16);
|
||||
// Slabs can be doubled, so check them twice
|
||||
if (Tag.SLABS.isTagged(m)) {
|
||||
Slab slab = (Slab) blockData;
|
||||
@ -464,22 +464,26 @@ public class IslandLevelCalculator {
|
||||
// Hook for Wild Stackers (Blocks and Spawners Only) - this has to use the real
|
||||
// chunk
|
||||
if (addon.isStackersEnabled() && (m.equals(Material.CAULDRON) || m.equals(Material.SPAWNER))) {
|
||||
stackedBlocks.add(new Location(cp.world, (double) x + cp.chunkSnapshot.getX() * 16, y,
|
||||
(double) z + cp.chunkSnapshot.getZ() * 16));
|
||||
stackedBlocks.add(loc);
|
||||
}
|
||||
|
||||
if (addon.isUltimateStackerEnabled() && !m.isAir()) {
|
||||
Location l = new Location(cp.chunk.getWorld(), x, y, z);
|
||||
UltimateStackerCalc.addStackers(m, l, results, belowSeaLevel, limitCount(m));
|
||||
UltimateStackerCalc.addStackers(m, loc, results, belowSeaLevel, limitCount(m));
|
||||
}
|
||||
|
||||
// Scan chests
|
||||
if (addon.getSettings().isIncludeChests() && CHESTS.contains(m)) {
|
||||
|
||||
if (addon.getSettings().isIncludeChests() && blockData instanceof Container) {
|
||||
chestBlocks.add(cp.chunk);
|
||||
}
|
||||
// Add the value of the block's material
|
||||
checkBlock(m, belowSeaLevel);
|
||||
|
||||
// Spawners
|
||||
if (m == Material.SPAWNER) {
|
||||
// Stash the spawner because the type cannot be obtained from the chunk snapshot
|
||||
this.spawners.put(loc, belowSeaLevel);
|
||||
} else {
|
||||
// Add the value of the block's material
|
||||
checkBlock(m, belowSeaLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -520,16 +524,23 @@ public class IslandLevelCalculator {
|
||||
return result;
|
||||
}
|
||||
|
||||
private Collection<String> sortedReport(int total, Multiset<Material> materialCount) {
|
||||
private Collection<String> sortedReport(int total, Multiset<Object> uwCount) {
|
||||
Collection<String> result = new ArrayList<>();
|
||||
Iterable<Multiset.Entry<Material>> entriesSortedByCount = Multisets.copyHighestCountFirst(materialCount)
|
||||
Iterable<Multiset.Entry<Object>> entriesSortedByCount = Multisets.copyHighestCountFirst(uwCount)
|
||||
.entrySet();
|
||||
for (Entry<Material> en : entriesSortedByCount) {
|
||||
Material type = en.getElement();
|
||||
for (Entry<Object> en : entriesSortedByCount) {
|
||||
|
||||
int value = getValue(type);
|
||||
int value = 0;
|
||||
String name = "";
|
||||
if (en.getElement() instanceof Material md) {
|
||||
value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), md), 0);
|
||||
name = Util.prettifyText(md.name());
|
||||
} else if (en.getElement() instanceof EntityType et) {
|
||||
name = Util.prettifyText(et.name());
|
||||
value = Objects.requireNonNullElse(addon.getBlockConfig().getValue(island.getWorld(), et), 0);
|
||||
}
|
||||
|
||||
result.add(type.toString() + ":" + String.format("%,d", en.getCount()) + " blocks x " + value + " = "
|
||||
result.add(name + " :" + String.format("%,d", en.getCount()) + " blocks x " + value + " = "
|
||||
+ (value * en.getCount()));
|
||||
total += (value * en.getCount());
|
||||
|
||||
@ -616,8 +627,9 @@ public class IslandLevelCalculator {
|
||||
pipeliner.getInProcessQueue().remove(this);
|
||||
BentoBox.getInstance().log("Completed Level scan.");
|
||||
// Chunk finished
|
||||
// This was the last chunk. Handle stacked blocks, then chests and exit
|
||||
handleStackedBlocks().thenCompose(v -> handleChests()).thenRun(() -> {
|
||||
// This was the last chunk. Handle stacked blocks, spawners, chests and exit
|
||||
handleStackedBlocks().thenCompose(v -> handleSpawners()).thenCompose(v -> handleChests())
|
||||
.thenRun(() -> {
|
||||
this.tidyUp();
|
||||
this.getR().complete(getResults());
|
||||
});
|
||||
@ -625,6 +637,27 @@ public class IslandLevelCalculator {
|
||||
});
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> handleSpawners() {
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
for (Map.Entry<Location, Boolean> en : this.spawners.entrySet()) {
|
||||
CompletableFuture<Void> future = Util.getChunkAtAsync(en.getKey()).thenAccept(c -> {
|
||||
if (en.getKey().getBlock().getType() == Material.SPAWNER) {
|
||||
EntityType et = ((CreatureSpawner) en.getKey().getBlock().getState()).getSpawnedType();
|
||||
if (et != null) {
|
||||
checkSpawner(et, en.getValue());
|
||||
} else {
|
||||
// This spawner has no spawning capability. Just list it as a spawner block
|
||||
checkBlock(Material.SPAWNER, en.getValue());
|
||||
}
|
||||
}
|
||||
});
|
||||
futures.add(future);
|
||||
}
|
||||
// Return a CompletableFuture that completes when all futures are done
|
||||
return CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
|
||||
|
||||
}
|
||||
|
||||
private CompletableFuture<Void> handleChests() {
|
||||
List<CompletableFuture<Void>> futures = new ArrayList<>();
|
||||
for (Chunk v : chestBlocks) {
|
||||
|
@ -4,8 +4,6 @@ import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.bukkit.Material;
|
||||
|
||||
import com.google.common.collect.HashMultiset;
|
||||
import com.google.common.collect.Multiset;
|
||||
|
||||
@ -25,10 +23,10 @@ public class Results {
|
||||
TIMEOUT
|
||||
}
|
||||
List<String> report;
|
||||
final Multiset<Material> mdCount = HashMultiset.create();
|
||||
final Multiset<Material> uwCount = HashMultiset.create();
|
||||
final Multiset<Material> ncCount = HashMultiset.create();
|
||||
final Multiset<Material> ofCount = HashMultiset.create();
|
||||
final Multiset<Object> mdCount = HashMultiset.create();
|
||||
final Multiset<Object> uwCount = HashMultiset.create();
|
||||
final Multiset<Object> ncCount = HashMultiset.create();
|
||||
final Multiset<Object> ofCount = HashMultiset.create();
|
||||
// AtomicLong and AtomicInteger must be used because they are changed by multiple concurrent threads
|
||||
AtomicLong rawBlockCount = new AtomicLong(0);
|
||||
AtomicLong underWaterBlockCount = new AtomicLong(0);
|
||||
@ -130,13 +128,13 @@ public class Results {
|
||||
/**
|
||||
* @return the mdCount
|
||||
*/
|
||||
public Multiset<Material> getMdCount() {
|
||||
public Multiset<Object> getMdCount() {
|
||||
return mdCount;
|
||||
}
|
||||
/**
|
||||
* @return the uwCount
|
||||
*/
|
||||
public Multiset<Material> getUwCount() {
|
||||
public Multiset<Object> getUwCount() {
|
||||
return uwCount;
|
||||
}
|
||||
/**
|
||||
|
@ -6,8 +6,6 @@ import org.bukkit.Material;
|
||||
import com.craftaro.ultimatestacker.api.UltimateStackerApi;
|
||||
import com.craftaro.ultimatestacker.api.utils.Stackable;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
|
||||
/**
|
||||
* Isolates UltimateStacker imports so that they are only loaded if the plugin exists
|
||||
*/
|
||||
|
@ -123,8 +123,8 @@ public class IslandValueCommand extends CompositeCommand
|
||||
int count = lvData.getMdCount().getOrDefault(material, 0) + lvData.getUwCount().getOrDefault(material, 0);
|
||||
user.sendMessage("level.conversations.you-have", TextVariables.NUMBER,
|
||||
String.valueOf(count));
|
||||
int limit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(material, -1);
|
||||
if (limit > 0) {
|
||||
Integer limit = this.addon.getBlockConfig().getLimit(material);
|
||||
if (limit != null) {
|
||||
user.sendMessage("level.conversations.you-can-place", TextVariables.NUMBER,
|
||||
String.valueOf(limit));
|
||||
}
|
||||
|
@ -2,8 +2,6 @@ package world.bentobox.level.config;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@ -17,6 +15,7 @@ import org.bukkit.Registry;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import world.bentobox.level.Level;
|
||||
|
||||
@ -27,10 +26,13 @@ import world.bentobox.level.Level;
|
||||
*/
|
||||
public class BlockConfig {
|
||||
|
||||
private Map<Material, Integer> blockLimits = new EnumMap<>(Material.class);
|
||||
private static final String SPAWNER = "_SPAWNER";
|
||||
private Map<String, Integer> blockLimits = new HashMap<>();
|
||||
private Map<Material, Integer> blockValues = new EnumMap<>(Material.class);
|
||||
private final Map<World, Map<Material, Integer>> worldBlockValues = new HashMap<>();
|
||||
private final Map<World, Map<EntityType, Integer>> worldSpawnerValues = new HashMap<>();
|
||||
private final List<Material> hiddenBlocks;
|
||||
private Map<EntityType, Integer> spawnerValues = new EnumMap<>(EntityType.class);
|
||||
private Level addon;
|
||||
|
||||
/**
|
||||
@ -43,10 +45,13 @@ public class BlockConfig {
|
||||
public BlockConfig(Level addon, YamlConfiguration blockValues, File file) throws IOException {
|
||||
this.addon = addon;
|
||||
if (blockValues.isConfigurationSection("limits")) {
|
||||
setBlockLimits(loadBlockLimits(blockValues));
|
||||
for (String key : blockValues.getConfigurationSection("limits").getKeys(false)) {
|
||||
blockLimits.put(key, blockValues.getConfigurationSection("limits").getInt(key));
|
||||
}
|
||||
}
|
||||
if (blockValues.isConfigurationSection("blocks")) {
|
||||
setBlockValues(loadBlockValues(blockValues));
|
||||
setSpawnerValues(loadSpawnerValues(blockValues));
|
||||
} else {
|
||||
addon.logWarning("No block values in blockconfig.yml! All island levels will be zero!");
|
||||
}
|
||||
@ -58,12 +63,12 @@ public class BlockConfig {
|
||||
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
|
||||
blockValues.save(file);
|
||||
}
|
||||
@ -110,31 +115,50 @@ public class BlockConfig {
|
||||
return bv;
|
||||
}
|
||||
|
||||
private Map<Material, Integer> loadBlockLimits(YamlConfiguration blockValues2) {
|
||||
Map<Material, Integer> bl = new EnumMap<>(Material.class);
|
||||
ConfigurationSection limits = Objects.requireNonNull(blockValues2.getConfigurationSection("limits"));
|
||||
for (String material : limits.getKeys(false)) {
|
||||
try {
|
||||
Material mat = Material.valueOf(material);
|
||||
bl.put(mat, limits.getInt(material, 0));
|
||||
} catch (Exception e) {
|
||||
addon.logError("Unknown material (" + material + ") in blockconfig.yml Limits section. Skipping...");
|
||||
/**
|
||||
* Loads the spawner values from the blocks in the config
|
||||
* Format is entityname + _SPANWER, so for example ALLAY_SPAWNER
|
||||
* If they are missing, then they will score 1
|
||||
* @param blockValues config section
|
||||
* @return map of entity types and their score
|
||||
*/
|
||||
private Map<EntityType, Integer> loadSpawnerValues(YamlConfiguration blockValues) {
|
||||
ConfigurationSection blocks = Objects.requireNonNull(blockValues.getConfigurationSection("blocks"));
|
||||
Map<EntityType, Integer> bv = new HashMap<>();
|
||||
|
||||
|
||||
// Update spawners
|
||||
Registry.MATERIAL.stream().filter(Material::isItem)
|
||||
.filter(m -> m.name().endsWith("_SPAWN_EGG")).map(m -> m.name().substring(0, m.name().length() - 10))
|
||||
.forEach(m -> {
|
||||
// Populate missing spawners
|
||||
if (!blocks.contains(m + SPAWNER, true)) {
|
||||
blocks.set(m + SPAWNER, 1);
|
||||
}
|
||||
// Load value
|
||||
try {
|
||||
EntityType et = EntityType.valueOf(m);
|
||||
bv.put(et, blocks.getInt(m + SPAWNER));
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return bl;
|
||||
});
|
||||
return bv;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the blockLimits
|
||||
* Return the limits for any particular material or entity type
|
||||
* @param obj material or entity type
|
||||
* @return the limit or null if there isn't one
|
||||
*/
|
||||
public final Map<Material, Integer> getBlockLimits() {
|
||||
return blockLimits;
|
||||
}
|
||||
/**
|
||||
* @param bl the blockLimits to set
|
||||
*/
|
||||
private void setBlockLimits(Map<Material, Integer> bl) {
|
||||
this.blockLimits = bl;
|
||||
public Integer getLimit(Object obj) {
|
||||
if (obj instanceof Material m) {
|
||||
return blockLimits.get(m.name());
|
||||
}
|
||||
if (obj instanceof EntityType et) {
|
||||
return blockLimits.get(et.name().concat(SPAWNER));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @return the blockValues
|
||||
@ -157,39 +181,78 @@ public class BlockConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of material in world
|
||||
* @return the worldSpawnerValues
|
||||
*/
|
||||
public Map<World, Map<EntityType, Integer>> getWorldSpawnerValues() {
|
||||
return worldSpawnerValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of of a spawner in world
|
||||
* @param world - world
|
||||
* @param md - material
|
||||
* @param obj - entity type that will spawn from this spawner or material
|
||||
* @return value or null if not configured with a value
|
||||
*/
|
||||
public Integer getValue(World world, Material md) {
|
||||
// Check world settings
|
||||
if (getWorldBlockValues().containsKey(world) && getWorldBlockValues().get(world).containsKey(md)) {
|
||||
return getWorldBlockValues().get(world).get(md);
|
||||
}
|
||||
// Check baseline
|
||||
if (getBlockValues().containsKey(md)) {
|
||||
return getBlockValues().get(md);
|
||||
public Integer getValue(World world, Object obj) {
|
||||
if (obj instanceof EntityType et) {
|
||||
// Check world settings
|
||||
if (getWorldSpawnerValues().containsKey(world) && getWorldSpawnerValues().get(world).containsKey(et)) {
|
||||
return getWorldSpawnerValues().get(world).get(et);
|
||||
}
|
||||
// Check baseline
|
||||
if (getSpawnerValues().containsKey(et)) {
|
||||
return getSpawnerValues().get(et);
|
||||
}
|
||||
} else if (obj instanceof Material md) {
|
||||
// Check world settings
|
||||
if (getWorldBlockValues().containsKey(world) && getWorldBlockValues().get(world).containsKey(md)) {
|
||||
return getWorldBlockValues().get(world).get(md);
|
||||
}
|
||||
// Check baseline
|
||||
if (getBlockValues().containsKey(md)) {
|
||||
return getBlockValues().get(md);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the block should be hidden
|
||||
* @param m block material
|
||||
* @param m block material or entity type of spanwer
|
||||
* @return true if hidden
|
||||
*/
|
||||
public boolean isHiddenBlock(Material m) {
|
||||
return hiddenBlocks.contains(m);
|
||||
public boolean isHiddenBlock(Object obj) {
|
||||
if (obj instanceof Material m) {
|
||||
return hiddenBlocks.contains(m);
|
||||
}
|
||||
return hiddenBlocks.contains(Material.SPAWNER);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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);
|
||||
public boolean isNotHiddenBlock(Object obj) {
|
||||
if (obj instanceof Material m) {
|
||||
return !hiddenBlocks.contains(m);
|
||||
} else {
|
||||
return !hiddenBlocks.contains(Material.SPAWNER);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the spawnerValues
|
||||
*/
|
||||
public Map<EntityType, Integer> getSpawnerValues() {
|
||||
return spawnerValues;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param spawnerValues the spawnerValues to set
|
||||
*/
|
||||
public void setSpawnerValues(Map<EntityType, Integer> spawnerValues) {
|
||||
this.spawnerValues = spawnerValues;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -26,8 +26,6 @@ public class MigrationListener implements Listener
|
||||
|
||||
@EventHandler
|
||||
public void onBentoBoxReady(BentoBoxReadyEvent e) {
|
||||
// Perform upgrade check
|
||||
this.addon.getManager().migrate();
|
||||
// Load TopTens
|
||||
this.addon.getManager().loadTopTens();
|
||||
/*
|
||||
|
@ -1,9 +1,11 @@
|
||||
package world.bentobox.level.objects;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
import com.google.gson.annotations.Expose;
|
||||
|
||||
@ -59,13 +61,13 @@ public class IslandLevels implements DataObject {
|
||||
* Underwater count
|
||||
*/
|
||||
@Expose
|
||||
private Map<Material, Integer> uwCount;
|
||||
private Map<Object, Integer> uwCount;
|
||||
|
||||
/**
|
||||
* MaterialData count - count of all blocks excluding under water
|
||||
*/
|
||||
@Expose
|
||||
private Map<Material, Integer> mdCount;
|
||||
private Map<Object, Integer> mdCount;
|
||||
|
||||
/**
|
||||
* Constructor for new island
|
||||
@ -73,8 +75,8 @@ public class IslandLevels implements DataObject {
|
||||
*/
|
||||
public IslandLevels(String islandUUID) {
|
||||
uniqueId = islandUUID;
|
||||
uwCount = new EnumMap<>(Material.class);
|
||||
mdCount = new EnumMap<>(Material.class);
|
||||
uwCount = new HashMap<>();
|
||||
mdCount = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,31 +167,67 @@ public class IslandLevels implements DataObject {
|
||||
* The count of underwater blocks
|
||||
* @return the uwCount
|
||||
*/
|
||||
public Map<Material, Integer> getUwCount() {
|
||||
public Map<Object, Integer> getUwCount() {
|
||||
return uwCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Underwater blocks
|
||||
* @param uwCount the uwCount to set
|
||||
* @param map the uwCount to set
|
||||
*/
|
||||
public void setUwCount(Map<Material, Integer> uwCount) {
|
||||
this.uwCount = uwCount;
|
||||
public void setUwCount(Map<Object, Integer> map) {
|
||||
// Loaded objects come in as strings, so need to be converted to Material Or EntityTypes
|
||||
uwCount = convertMap(uwCount);
|
||||
|
||||
this.uwCount = map;
|
||||
}
|
||||
|
||||
/**
|
||||
* All blocks count except for underwater blocks
|
||||
* @return the mdCount
|
||||
*/
|
||||
public Map<Material, Integer> getMdCount() {
|
||||
public Map<Object, Integer> getMdCount() {
|
||||
// Loaded objects come in as strings, so need to be converted to Material Or EntityTypes
|
||||
mdCount = convertMap(mdCount);
|
||||
return mdCount;
|
||||
}
|
||||
|
||||
private Map<Object, Integer> convertMap(Map<Object, Integer> mdCount) {
|
||||
Map<Object, Integer> convertedMap = new HashMap<>();
|
||||
|
||||
for (Map.Entry<Object, Integer> entry : mdCount.entrySet()) {
|
||||
Object key = entry.getKey();
|
||||
Integer value = entry.getValue();
|
||||
|
||||
if (key instanceof String) {
|
||||
String keyStr = (String) key;
|
||||
// First, try converting to Material
|
||||
Material material = Material.matchMaterial(keyStr);
|
||||
if (material != null) {
|
||||
convertedMap.put(material, value);
|
||||
} else {
|
||||
// Fallback to converting to EntityType (using uppercase as enum constants are uppercase)
|
||||
try {
|
||||
EntityType entityType = EntityType.valueOf(keyStr.toUpperCase(Locale.ENGLISH));
|
||||
convertedMap.put(entityType, value);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
// No valid Material or EntityType found.
|
||||
convertedMap.put(key, value); // Leave the key unchanged.
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the key is not a String, add it directly.
|
||||
convertedMap.put(key, value);
|
||||
}
|
||||
}
|
||||
return convertedMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* All blocks except for underwater blocks
|
||||
* @param mdCount the mdCount to set
|
||||
*/
|
||||
public void setMdCount(Map<Material, Integer> mdCount) {
|
||||
public void setMdCount(Map<Object, Integer> mdCount) {
|
||||
this.mdCount = mdCount;
|
||||
}
|
||||
|
||||
|
@ -4,12 +4,16 @@ import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@ -24,7 +28,6 @@ import world.bentobox.bentobox.api.panels.builders.TemplatedPanelBuilder;
|
||||
import world.bentobox.bentobox.api.panels.reader.ItemTemplateRecord;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.util.Pair;
|
||||
import world.bentobox.level.Level;
|
||||
import world.bentobox.level.objects.IslandLevels;
|
||||
import world.bentobox.level.util.Utils;
|
||||
@ -33,10 +36,112 @@ import world.bentobox.level.util.Utils;
|
||||
* This class opens GUI that shows generator view for user.
|
||||
*/
|
||||
public class DetailsPanel {
|
||||
|
||||
private static final String SPAWNER = "_SPAWNER";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Internal Constructor
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This enum holds possible tabs for current gui.
|
||||
*/
|
||||
private enum Tab {
|
||||
/**
|
||||
* All block Tab
|
||||
*/
|
||||
ALL_BLOCKS,
|
||||
/**
|
||||
* Blocks that have value
|
||||
*/
|
||||
VALUE_BLOCKS,
|
||||
/**
|
||||
* Above Sea level Tab.
|
||||
*/
|
||||
ABOVE_SEA_LEVEL,
|
||||
/**
|
||||
* Underwater Tab.
|
||||
*/
|
||||
UNDERWATER,
|
||||
/**
|
||||
* Spawner Tab.
|
||||
*/
|
||||
SPAWNER
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter {
|
||||
/**
|
||||
* By name
|
||||
*/
|
||||
NAME,
|
||||
/**
|
||||
* By value
|
||||
*/
|
||||
VALUE,
|
||||
/**
|
||||
* By number
|
||||
*/
|
||||
COUNT
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable holds targeted island.
|
||||
*/
|
||||
private final Island island;
|
||||
|
||||
/**
|
||||
* This variable holds targeted island level data.
|
||||
*/
|
||||
private final IslandLevels levelsData;
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* Record that stores a Material or EntityType as a key and a value
|
||||
*/
|
||||
private record BlockRec(Object key, Integer value, Integer limit) {
|
||||
}
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<BlockRec> blockCountList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private Tab activeTab;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid
|
||||
* creating objects everywhere.
|
||||
@ -58,10 +163,10 @@ public class DetailsPanel {
|
||||
this.levelsData = null;
|
||||
}
|
||||
|
||||
// By default no-filters are active.
|
||||
// Default Filters
|
||||
this.activeTab = Tab.VALUE_BLOCKS;
|
||||
this.activeFilter = Filter.NAME;
|
||||
this.materialCountList = new ArrayList<>(Material.values().length);
|
||||
this.blockCountList = new ArrayList<>();
|
||||
|
||||
this.updateFilters();
|
||||
}
|
||||
@ -93,7 +198,7 @@ public class DetailsPanel {
|
||||
|
||||
panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
|
||||
panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
|
||||
panelBuilder.registerTypeBuilder("BLOCK", this::createMaterialButton);
|
||||
panelBuilder.registerTypeBuilder("BLOCK", this::createBlockButton);
|
||||
|
||||
panelBuilder.registerTypeBuilder("FILTER", this::createFilterButton);
|
||||
|
||||
@ -108,101 +213,81 @@ public class DetailsPanel {
|
||||
* This method updates filter of elements based on tabs.
|
||||
*/
|
||||
private void updateFilters() {
|
||||
this.materialCountList.clear();
|
||||
this.blockCountList.clear();
|
||||
|
||||
switch (this.activeTab) {
|
||||
case VALUE_BLOCKS -> {
|
||||
Map<Material, Integer> materialCountMap = new EnumMap<>(Material.class);
|
||||
|
||||
materialCountMap.putAll(this.levelsData.getMdCount());
|
||||
|
||||
// Add underwater blocks.
|
||||
this.levelsData.getUwCount().forEach((material, count) -> materialCountMap.put(material,
|
||||
materialCountMap.computeIfAbsent(material, key -> 0) + count));
|
||||
|
||||
// Remove zero value blocks
|
||||
materialCountMap.entrySet().removeIf(en -> {
|
||||
Integer value = this.addon.getBlockConfig().getValue(world, en.getKey());
|
||||
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 -> {
|
||||
if (entry.getValue() > 0) {
|
||||
this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue()));
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
case ALL_BLOCKS -> {
|
||||
Map<Material, Integer> materialCountMap = new EnumMap<>(Material.class);
|
||||
|
||||
materialCountMap.putAll(this.levelsData.getMdCount());
|
||||
|
||||
// Add underwater blocks.
|
||||
this.levelsData.getUwCount().forEach((material, count) -> materialCountMap.put(material,
|
||||
materialCountMap.computeIfAbsent(material, key -> 0) + count));
|
||||
|
||||
// Remove any hidden blocks
|
||||
materialCountMap.keySet().removeIf(this.addon.getBlockConfig()::isHiddenBlock);
|
||||
|
||||
materialCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey()))
|
||||
.forEachOrdered(entry -> this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
|
||||
}
|
||||
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())));
|
||||
|
||||
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())));
|
||||
|
||||
case SPAWNER -> {
|
||||
if (this.activeTab == Tab.SPAWNER) {
|
||||
if (this.addon.getBlockConfig().isNotHiddenBlock(Material.SPAWNER)) {
|
||||
int aboveWater = this.levelsData.getMdCount().getOrDefault(Material.SPAWNER, 0);
|
||||
int underWater = this.levelsData.getUwCount().getOrDefault(Material.SPAWNER, 0);
|
||||
Map<EntityType, Integer> spawnerCountMap = new EnumMap<>(EntityType.class);
|
||||
spawnerCountMap = this.levelsData.getMdCount().entrySet().stream()
|
||||
.filter(en -> en.getKey() instanceof EntityType)
|
||||
.collect(Collectors.toMap(en -> (EntityType) en.getKey(), Map.Entry::getValue));
|
||||
|
||||
// TODO: spawners need some touch...
|
||||
this.materialCountList.add(new Pair<>(Material.SPAWNER, underWater + aboveWater));
|
||||
spawnerCountMap.entrySet().stream().sorted((Map.Entry.comparingByKey())).forEachOrdered(entry -> {
|
||||
if (entry.getValue() > 0) {
|
||||
this.blockCountList.add(new BlockRec(entry.getKey(), entry.getValue(), 0));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Map<Object, Integer> materialCountMap = new HashMap<>();
|
||||
|
||||
Comparator<Pair<Material, Integer>> sorter;
|
||||
if (this.activeTab != Tab.UNDERWATER) {
|
||||
// All above water blocks
|
||||
materialCountMap.putAll(this.levelsData.getMdCount());
|
||||
}
|
||||
if (this.activeTab != Tab.ABOVE_SEA_LEVEL) {
|
||||
// All underwater blocks.
|
||||
materialCountMap.putAll(this.levelsData.getUwCount());
|
||||
}
|
||||
// Remove any hidden blocks
|
||||
materialCountMap.keySet().removeIf(this.addon.getBlockConfig()::isHiddenBlock);
|
||||
// Remove any zero amount items
|
||||
materialCountMap.values().removeIf(i -> i < 1);
|
||||
|
||||
if (this.activeTab == Tab.VALUE_BLOCKS) {
|
||||
// Remove zero-value blocks
|
||||
materialCountMap.entrySet().removeIf(en -> Optional
|
||||
.ofNullable(this.addon.getBlockConfig().getValue(world, en.getKey())).orElse(0) == 0);
|
||||
}
|
||||
// All done filtering, add the left overs
|
||||
blockCountList.addAll(
|
||||
materialCountMap.entrySet().stream()
|
||||
.map(entry -> new BlockRec(entry.getKey(), entry.getValue(), 0))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
}
|
||||
// Sort and filter
|
||||
Comparator<BlockRec> sorter;
|
||||
|
||||
switch (this.activeFilter) {
|
||||
case COUNT -> {
|
||||
sorter = (o1, o2) -> {
|
||||
if (o1.getValue().equals(o2.getValue())) {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
if (o1.value().equals(o2.value())) {
|
||||
String o1Name = Utils.prettifyObject(o1.key(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.key(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
} else {
|
||||
return Integer.compare(o2.getValue(), o1.getValue());
|
||||
return Integer.compare(o2.value(), o1.value());
|
||||
}
|
||||
};
|
||||
}
|
||||
case VALUE -> {
|
||||
sorter = (o1, o2) -> {
|
||||
int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o1.getKey(), 0);
|
||||
int o1Count = blockLimit > 0 ? Math.min(o1.getValue(), blockLimit) : o1.getValue();
|
||||
int blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(o1.key()), 0);
|
||||
int o1Count = blockLimit > 0 ? Math.min(o1.value(), blockLimit) : o1.value();
|
||||
|
||||
blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o2.getKey(), 0);
|
||||
int o2Count = blockLimit > 0 ? Math.min(o2.getValue(), blockLimit) : o2.getValue();
|
||||
blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(o2.key()), 0);
|
||||
int o2Count = blockLimit > 0 ? Math.min(o2.value(), blockLimit) : o2.value();
|
||||
|
||||
long o1Value = (long) o1Count
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o1.getKey(), 0);
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o1.key(), 0);
|
||||
long o2Value = (long) o2Count
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o2.getKey(), 0);
|
||||
* this.addon.getBlockConfig().getBlockValues().getOrDefault(o2.key(), 0);
|
||||
|
||||
if (o1Value == o2Value) {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.key(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.key(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
} else {
|
||||
@ -212,16 +297,15 @@ public class DetailsPanel {
|
||||
}
|
||||
default -> {
|
||||
sorter = (o1, o2) -> {
|
||||
String o1Name = Utils.prettifyObject(o1.getKey(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.getKey(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.key(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.key(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
this.materialCountList.sort(sorter);
|
||||
|
||||
this.blockCountList.sort(sorter);
|
||||
this.pageIndex = 0;
|
||||
}
|
||||
|
||||
@ -397,7 +481,7 @@ public class DetailsPanel {
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createNextButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
long size = this.materialCountList.size();
|
||||
long size = this.blockCountList.size();
|
||||
|
||||
if (size <= slot.amountMap().getOrDefault("BLOCK", 1)
|
||||
|| 1.0 * size / slot.amountMap().getOrDefault("BLOCK", 1) <= this.pageIndex + 1) {
|
||||
@ -533,73 +617,91 @@ public class DetailsPanel {
|
||||
* @param slot the slot
|
||||
* @return the panel item
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
if (this.materialCountList.isEmpty()) {
|
||||
// Does not contain any generators.
|
||||
private PanelItem createBlockButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) {
|
||||
if (this.blockCountList.isEmpty()) {
|
||||
// Nothing to show
|
||||
return null;
|
||||
}
|
||||
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault("BLOCK", 1) + slot.slot();
|
||||
|
||||
if (index >= this.materialCountList.size()) {
|
||||
if (index >= this.blockCountList.size()) {
|
||||
// Out of index.
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.createMaterialButton(template, this.materialCountList.get(index));
|
||||
return this.createMaterialButton(template, this.blockCountList.get(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates button for material.
|
||||
* This method creates button for block.
|
||||
*
|
||||
* @param template the template of the button
|
||||
* @param materialCount materialCount which button must be created.
|
||||
* @return PanelItem for generator tier.
|
||||
* @param blockCount count
|
||||
* @return PanelItem button
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, Pair<Material, Integer> materialCount) {
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, BlockRec blockCount) {
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
builder.icon(template.icon().clone());
|
||||
} else {
|
||||
builder.icon(PanelUtils.getMaterialItem(materialCount.getKey()));
|
||||
}
|
||||
// Show amount if less than 64.
|
||||
if (blockCount.value() < 64) {
|
||||
builder.amount(blockCount.value());
|
||||
}
|
||||
|
||||
if (materialCount.getValue() < 64) {
|
||||
builder.amount(materialCount.getValue());
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
Object key = blockCount.key();
|
||||
String description = Utils.prettifyDescription(key, this.user);
|
||||
String blockId = "";
|
||||
int blockValue = 0;
|
||||
int blockLimit = 0;
|
||||
String value = "";
|
||||
String limit = "";
|
||||
String displayMaterial = Utils.prettifyObject(key, this.user);
|
||||
|
||||
if (key instanceof Material m) {
|
||||
// Material-specific settings.
|
||||
builder.icon(PanelUtils.getMaterialItem(m));
|
||||
blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", m.name());
|
||||
blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(m, 0);
|
||||
blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(m), 0);
|
||||
} else if (key instanceof EntityType e) {
|
||||
// EntityType-specific settings.
|
||||
builder.icon(PanelUtils.getEntityEgg(e));
|
||||
description += this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name"); // Put spawner on the end
|
||||
blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", e.name().concat(SPAWNER));
|
||||
blockValue = this.addon.getBlockConfig().getSpawnerValues().getOrDefault(e, 0);
|
||||
blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(e), 0);
|
||||
}
|
||||
|
||||
if (template.title() != null) {
|
||||
builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NUMBER,
|
||||
String.valueOf(materialCount.getValue()), "[material]",
|
||||
Utils.prettifyObject(materialCount.getKey(), this.user)));
|
||||
String.valueOf(blockCount.value()), "[material]", displayMaterial));
|
||||
}
|
||||
|
||||
String description = Utils.prettifyDescription(materialCount.getKey(), this.user);
|
||||
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
String blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", materialCount.getKey().name());
|
||||
|
||||
int blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(materialCount.getKey(), 0);
|
||||
String value = blockValue > 0
|
||||
value = blockValue > 0
|
||||
? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER,
|
||||
String.valueOf(blockValue))
|
||||
: "";
|
||||
|
||||
int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(materialCount.getKey(), 0);
|
||||
String limit = blockLimit > 0
|
||||
: "";
|
||||
limit = blockLimit > 0
|
||||
? this.user.getTranslationOrNothing(reference + "limit", TextVariables.NUMBER,
|
||||
String.valueOf(blockLimit))
|
||||
: "";
|
||||
: "";
|
||||
|
||||
String count = this.user.getTranslationOrNothing(reference + "count", TextVariables.NUMBER,
|
||||
String.valueOf(materialCount.getValue()));
|
||||
String.valueOf(blockCount.value()));
|
||||
|
||||
long calculatedValue = (long) Math.min(blockLimit > 0 ? blockLimit : Integer.MAX_VALUE,
|
||||
materialCount.getValue()) * blockValue;
|
||||
blockCount.value()) * blockValue;
|
||||
String valueText = calculatedValue > 0 ? this.user.getTranslationOrNothing(reference + "calculated",
|
||||
TextVariables.NUMBER, String.valueOf(calculatedValue)) : "";
|
||||
|
||||
// Hide block ID unless user is an operator.
|
||||
if (!user.isOp()) {
|
||||
blockId = "";
|
||||
}
|
||||
if (template.description() != null) {
|
||||
builder.description(this.user
|
||||
.getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId,
|
||||
@ -626,100 +728,5 @@ public class DetailsPanel {
|
||||
new DetailsPanel(addon, world, user).build();
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This enum holds possible tabs for current gui.
|
||||
*/
|
||||
private enum Tab {
|
||||
/**
|
||||
* All block Tab
|
||||
*/
|
||||
ALL_BLOCKS,
|
||||
/**
|
||||
* Blocks that have value
|
||||
*/
|
||||
VALUE_BLOCKS,
|
||||
/**
|
||||
* Above Sea level Tab.
|
||||
*/
|
||||
ABOVE_SEA_LEVEL,
|
||||
/**
|
||||
* Underwater Tab.
|
||||
*/
|
||||
UNDERWATER,
|
||||
/**
|
||||
* Spawner Tab.
|
||||
*/
|
||||
SPAWNER
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter {
|
||||
/**
|
||||
* By name
|
||||
*/
|
||||
NAME,
|
||||
/**
|
||||
* By value
|
||||
*/
|
||||
VALUE,
|
||||
/**
|
||||
* By number
|
||||
*/
|
||||
COUNT
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable holds targeted island.
|
||||
*/
|
||||
private final Island island;
|
||||
|
||||
/**
|
||||
* This variable holds targeted island level data.
|
||||
*/
|
||||
private final IslandLevels levelsData;
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<Pair<Material, Integer>> materialCountList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private Tab activeTab;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
}
|
||||
|
@ -6,11 +6,13 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.event.inventory.ClickType;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
@ -34,11 +36,86 @@ import world.bentobox.level.util.Utils;
|
||||
*/
|
||||
public class ValuePanel
|
||||
{
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Internal Constructor
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter {
|
||||
/**
|
||||
* By name asc
|
||||
*/
|
||||
NAME_ASC,
|
||||
/**
|
||||
* By name desc
|
||||
*/
|
||||
NAME_DESC,
|
||||
/**
|
||||
* By value asc
|
||||
*/
|
||||
VALUE_ASC,
|
||||
/**
|
||||
* By value desc
|
||||
*/
|
||||
VALUE_DESC,
|
||||
}
|
||||
|
||||
private record BlockRecord(Object keyl, Integer value, Integer limit) {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private static final String BLOCK = "BLOCK";
|
||||
|
||||
private static final String SPAWNER = "_SPAWNER";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<BlockRecord> blockRecordList;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private List<BlockRecord> elementList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private String searchText;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
|
||||
/**
|
||||
* This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
|
||||
@ -56,7 +133,8 @@ public class ValuePanel
|
||||
this.user = user;
|
||||
|
||||
this.activeFilter = Filter.NAME_ASC;
|
||||
this.materialRecordList = Arrays.stream(Material.values()).
|
||||
|
||||
this.blockRecordList = Arrays.stream(Material.values()).
|
||||
filter(Material::isBlock).
|
||||
filter(Material::isItem). // Remove things like PITCHER_CROP
|
||||
filter(m -> !m.name().startsWith("LEGACY_")).
|
||||
@ -64,13 +142,22 @@ public class ValuePanel
|
||||
map(material ->
|
||||
{
|
||||
Integer value = this.addon.getBlockConfig().getValue(this.world, material);
|
||||
Integer limit = this.addon.getBlockConfig().getBlockLimits().get(material);
|
||||
Integer limit = this.addon.getBlockConfig().getLimit(material);
|
||||
|
||||
return new MaterialRecord(material,
|
||||
return new BlockRecord(material,
|
||||
value != null ? value : 0,
|
||||
limit != null ? limit : 0);
|
||||
}).
|
||||
collect(Collectors.toList());
|
||||
// Add spawn eggs
|
||||
this.blockRecordList.addAll(Arrays.stream(EntityType.values()).filter(EntityType::isSpawnable)
|
||||
.filter(EntityType::isAlive)
|
||||
.filter(this.addon.getBlockConfig()::isNotHiddenBlock).map(et -> {
|
||||
Integer value = this.addon.getBlockConfig().getValue(this.world, et);
|
||||
Integer limit = this.addon.getBlockConfig().getLimit(et);
|
||||
|
||||
return new BlockRecord(et, value != null ? value : 0, limit != null ? limit : 0);
|
||||
}).collect(Collectors.toList()));
|
||||
|
||||
this.elementList = new ArrayList<>(Material.values().length);
|
||||
this.searchText = "";
|
||||
@ -108,7 +195,7 @@ public class ValuePanel
|
||||
*/
|
||||
private void updateFilters()
|
||||
{
|
||||
Comparator<MaterialRecord> sorter;
|
||||
Comparator<BlockRecord> sorter;
|
||||
|
||||
switch (this.activeFilter)
|
||||
{
|
||||
@ -118,8 +205,8 @@ public class ValuePanel
|
||||
{
|
||||
if (o1.value().equals(o2.value()))
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.keyl(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.keyl(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
}
|
||||
@ -135,8 +222,8 @@ public class ValuePanel
|
||||
{
|
||||
if (o1.value().equals(o2.value()))
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.keyl(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.keyl(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
}
|
||||
@ -150,8 +237,8 @@ public class ValuePanel
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.keyl(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.keyl(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o2Name, o1Name);
|
||||
};
|
||||
@ -160,25 +247,26 @@ public class ValuePanel
|
||||
|
||||
sorter = (o1, o2) ->
|
||||
{
|
||||
String o1Name = Utils.prettifyObject(o1.material(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.material(), this.user);
|
||||
String o1Name = Utils.prettifyObject(o1.keyl(), this.user);
|
||||
String o2Name = Utils.prettifyObject(o2.keyl(), this.user);
|
||||
|
||||
return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
this.materialRecordList.sort(sorter);
|
||||
this.blockRecordList.sort(sorter);
|
||||
|
||||
if (!this.searchText.isBlank())
|
||||
{
|
||||
this.elementList = new ArrayList<>(this.materialRecordList.size());
|
||||
this.elementList = new ArrayList<>(this.blockRecordList.size());
|
||||
final String text = this.searchText.toLowerCase();
|
||||
|
||||
this.materialRecordList.forEach(rec ->
|
||||
this.blockRecordList.forEach(rec ->
|
||||
{
|
||||
if (rec.material.name().toLowerCase().contains(text) ||
|
||||
Utils.prettifyObject(rec.material(), this.user).toLowerCase().contains(text))
|
||||
if (rec.keyl.toString().toLowerCase().contains(text)
|
||||
||
|
||||
Utils.prettifyObject(rec.keyl(), this.user).toLowerCase().contains(text))
|
||||
{
|
||||
this.elementList.add(rec);
|
||||
}
|
||||
@ -186,7 +274,7 @@ public class ValuePanel
|
||||
}
|
||||
else
|
||||
{
|
||||
this.elementList = this.materialRecordList;
|
||||
this.elementList = this.blockRecordList;
|
||||
}
|
||||
|
||||
this.pageIndex = 0;
|
||||
@ -585,7 +673,6 @@ public class ValuePanel
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
int index = this.pageIndex * slot.amountMap().getOrDefault(BLOCK, 1) + slot.slot();
|
||||
|
||||
if (index >= this.elementList.size())
|
||||
@ -597,6 +684,84 @@ public class ValuePanel
|
||||
return this.createMaterialButton(template, this.elementList.get(index));
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates button for block.
|
||||
*
|
||||
* @param template the template of the button
|
||||
* @param blockCount count
|
||||
* @return PanelItem button
|
||||
*/
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template, BlockRecord blockCount) {
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
if (template.icon() != null) {
|
||||
builder.icon(template.icon().clone());
|
||||
}
|
||||
// Show amount if less than 64.
|
||||
if (blockCount.value() < 64) {
|
||||
builder.amount(blockCount.value());
|
||||
}
|
||||
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
Object key = blockCount.keyl();
|
||||
String description = Utils.prettifyDescription(key, this.user);
|
||||
String blockId = "";
|
||||
int blockValue = 0;
|
||||
int blockLimit = 0;
|
||||
String value = "";
|
||||
String limit = "";
|
||||
String displayMaterial = Utils.prettifyObject(key, this.user);
|
||||
|
||||
if (key instanceof Material m) {
|
||||
// Material-specific settings.
|
||||
builder.icon(PanelUtils.getMaterialItem(m));
|
||||
blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", m.name());
|
||||
blockValue = this.addon.getBlockConfig().getBlockValues().getOrDefault(m, 0);
|
||||
blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(m), 0);
|
||||
} else if (key instanceof EntityType e) {
|
||||
// EntityType-specific settings.
|
||||
builder.icon(PanelUtils.getEntityEgg(e));
|
||||
description += this.user.getTranslation(this.world, "level.gui.buttons.spawner.block-name"); // Put spawner on the end
|
||||
blockId = this.user.getTranslationOrNothing(reference + "id", "[id]", e.name().concat(SPAWNER));
|
||||
blockValue = this.addon.getBlockConfig().getSpawnerValues().getOrDefault(e, 0);
|
||||
blockLimit = Objects.requireNonNullElse(this.addon.getBlockConfig().getLimit(e), 0);
|
||||
}
|
||||
|
||||
if (template.title() != null) {
|
||||
builder.name(this.user.getTranslation(this.world, template.title(), TextVariables.NUMBER,
|
||||
String.valueOf(blockCount.value()), "[material]", displayMaterial));
|
||||
}
|
||||
|
||||
value = blockValue > 0
|
||||
? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER,
|
||||
String.valueOf(blockValue))
|
||||
: "";
|
||||
limit = blockLimit > 0
|
||||
? this.user.getTranslationOrNothing(reference + "limit", TextVariables.NUMBER,
|
||||
String.valueOf(blockLimit))
|
||||
: "";
|
||||
|
||||
// Hide block ID unless user is an operator.
|
||||
if (!user.isOp()) {
|
||||
blockId = "";
|
||||
}
|
||||
String underWater;
|
||||
|
||||
if (this.addon.getSettings().getUnderWaterMultiplier() > 1.0) {
|
||||
underWater = this.user.getTranslationOrNothing(reference + "underwater", TextVariables.NUMBER,
|
||||
String.valueOf(blockCount.value() * this.addon.getSettings().getUnderWaterMultiplier()));
|
||||
} else {
|
||||
underWater = "";
|
||||
}
|
||||
if (template.description() != null) {
|
||||
builder.description(this.user
|
||||
.getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId,
|
||||
"[value]", value, "[underwater]", underWater, "[limit]", limit)
|
||||
.replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(?<!\\\\)\\|", "\n").replace("\\\\\\|", "|")); // Non regex
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method creates button for material.
|
||||
@ -605,11 +770,12 @@ public class ValuePanel
|
||||
* @param materialRecord materialRecord which button must be created.
|
||||
* @return PanelItem for generator tier.
|
||||
*/
|
||||
/*
|
||||
private PanelItem createMaterialButton(ItemTemplateRecord template,
|
||||
MaterialRecord materialRecord)
|
||||
{
|
||||
PanelItemBuilder builder = new PanelItemBuilder();
|
||||
|
||||
|
||||
if (template.icon() != null)
|
||||
{
|
||||
builder.icon(template.icon().clone());
|
||||
@ -618,29 +784,29 @@ public class ValuePanel
|
||||
{
|
||||
builder.icon(PanelUtils.getMaterialItem(materialRecord.material()));
|
||||
}
|
||||
|
||||
|
||||
if (materialRecord.value() <= 64 && materialRecord.value() > 0)
|
||||
{
|
||||
builder.amount(materialRecord.value());
|
||||
}
|
||||
|
||||
|
||||
if (template.title() != null)
|
||||
{
|
||||
builder.name(this.user.getTranslation(this.world, template.title(),
|
||||
"[material]", Utils.prettifyObject(materialRecord.material(), this.user)));
|
||||
}
|
||||
|
||||
|
||||
String description = Utils.prettifyDescription(materialRecord.material(), this.user);
|
||||
|
||||
|
||||
final String reference = "level.gui.buttons.material.";
|
||||
String blockId = this.user.getTranslationOrNothing(reference + "id",
|
||||
"[id]", materialRecord.material().name());
|
||||
|
||||
|
||||
String value = this.user.getTranslationOrNothing(reference + "value",
|
||||
TextVariables.NUMBER, String.valueOf(materialRecord.value()));
|
||||
|
||||
|
||||
String underWater;
|
||||
|
||||
|
||||
if (this.addon.getSettings().getUnderWaterMultiplier() > 1.0)
|
||||
{
|
||||
underWater = this.user.getTranslationOrNothing(reference + "underwater",
|
||||
@ -650,10 +816,10 @@ public class ValuePanel
|
||||
{
|
||||
underWater = "";
|
||||
}
|
||||
|
||||
|
||||
String limit = materialRecord.limit() > 0 ? this.user.getTranslationOrNothing(reference + "limit",
|
||||
TextVariables.NUMBER, String.valueOf(materialRecord.limit())) : "";
|
||||
|
||||
|
||||
if (template.description() != null)
|
||||
{
|
||||
builder.description(this.user.getTranslation(this.world, template.description(),
|
||||
@ -666,14 +832,14 @@ public class ValuePanel
|
||||
replaceAll("(?<!\\\\)\\|", "\n").
|
||||
replace("\\\\\\|", "|")); // Non regex
|
||||
}
|
||||
|
||||
|
||||
builder.clickHandler((panel, user1, clickType, i) -> {
|
||||
addon.log("Material: " + materialRecord.material());
|
||||
return true;
|
||||
});
|
||||
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
}*/
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
@ -696,87 +862,4 @@ public class ValuePanel
|
||||
new ValuePanel(addon, world, user).build();
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Enums
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
|
||||
/**
|
||||
* Sorting order of blocks.
|
||||
*/
|
||||
private enum Filter
|
||||
{
|
||||
/**
|
||||
* By name asc
|
||||
*/
|
||||
NAME_ASC,
|
||||
/**
|
||||
* By name desc
|
||||
*/
|
||||
NAME_DESC,
|
||||
/**
|
||||
* By value asc
|
||||
*/
|
||||
VALUE_ASC,
|
||||
/**
|
||||
* By value desc
|
||||
*/
|
||||
VALUE_DESC,
|
||||
}
|
||||
|
||||
|
||||
private record MaterialRecord(Material material, Integer value, Integer limit)
|
||||
{
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Constants
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
private static final String BLOCK = "BLOCK";
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Section: Variables
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* This variable allows to access addon object.
|
||||
*/
|
||||
private final Level addon;
|
||||
|
||||
/**
|
||||
* This variable holds user who opens panel. Without it panel cannot be opened.
|
||||
*/
|
||||
private final User user;
|
||||
|
||||
/**
|
||||
* This variable holds a world to which gui referee.
|
||||
*/
|
||||
private final World world;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private final List<MaterialRecord> materialRecordList;
|
||||
|
||||
/**
|
||||
* This variable stores the list of elements to display.
|
||||
*/
|
||||
private List<MaterialRecord> elementList;
|
||||
|
||||
/**
|
||||
* This variable holds current pageIndex for multi-page generator choosing.
|
||||
*/
|
||||
private int pageIndex;
|
||||
|
||||
/**
|
||||
* This variable stores which tab currently is active.
|
||||
*/
|
||||
private String searchText;
|
||||
|
||||
/**
|
||||
* This variable stores active filter for items.
|
||||
*/
|
||||
private Filter activeFilter;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ package world.bentobox.level.util;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
@ -18,7 +19,6 @@ import world.bentobox.bentobox.hooks.LangUtilsHook;
|
||||
|
||||
public class Utils
|
||||
{
|
||||
private static final String LEVEL_MATERIALS = "level.materials.";
|
||||
|
||||
private Utils() {} // Private constructor as this is a utility class only with static methods
|
||||
|
||||
@ -138,92 +138,72 @@ public class Utils
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prettify Material object for user.
|
||||
* @param object Object that must be pretty.
|
||||
* @param user User who will see the object.
|
||||
* @return Prettified string for Material.
|
||||
* Reference string in translations.
|
||||
*/
|
||||
public static String prettifyObject(Material object, User user)
|
||||
{
|
||||
// Nothing to translate
|
||||
if (object == null)
|
||||
{
|
||||
public static final String ENTITIES = "level.entities.";
|
||||
private static final String LEVEL_MATERIALS = "level.materials.";
|
||||
|
||||
public static String prettifyObject(Object object, User user) {
|
||||
if (object == null || !(object instanceof Enum<?>)) {
|
||||
return "";
|
||||
}
|
||||
// All supported objects are enums so we can use name() safely.
|
||||
String key = ((Enum<?>) object).name().toLowerCase();
|
||||
String translation = "";
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]:
|
||||
// name: [name]
|
||||
String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase() + ".name");
|
||||
if (object instanceof Material) {
|
||||
// Try our translations for Material.
|
||||
translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + ".name");
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key);
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
translation = user.getTranslationOrNothing("materials." + key);
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
// Fallback to our hook for Material.
|
||||
return LangUtilsHook.getMaterialName((Material) object, user);
|
||||
} else if (object instanceof EntityType) {
|
||||
// Try our translations for EntityType.
|
||||
translation = user.getTranslationOrNothing(ENTITIES + key + ".name");
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
translation = user.getTranslationOrNothing(ENTITIES + key);
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
translation = user.getTranslationOrNothing("entities." + key);
|
||||
if (!translation.isEmpty())
|
||||
return translation;
|
||||
|
||||
// Fallback to our hook for EntityType.
|
||||
return LangUtilsHook.getEntityName((EntityType) object, user);
|
||||
}
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]: [name]
|
||||
|
||||
translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase());
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// Find general structure with:
|
||||
// materials:
|
||||
// [material]: [name]
|
||||
|
||||
translation = user.getTranslationOrNothing("materials." + object.name().toLowerCase());
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
}
|
||||
|
||||
// Use Lang Utils Hook to translate material
|
||||
return LangUtilsHook.getMaterialName(object, user);
|
||||
// In case of an unexpected type, return an empty string.
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prettify Material object description for user.
|
||||
* @param object Object that must be pretty.
|
||||
* @param user User who will see the object.
|
||||
* @return Prettified description string for Material.
|
||||
*/
|
||||
public static String prettifyDescription(Material object, User user)
|
||||
{
|
||||
// Nothing to translate
|
||||
if (object == null)
|
||||
{
|
||||
public static String prettifyDescription(Object object, User user) {
|
||||
if (object == null || !(object instanceof Enum<?>)) {
|
||||
return "";
|
||||
}
|
||||
String key = ((Enum<?>) object).name().toLowerCase();
|
||||
|
||||
// Find addon structure with:
|
||||
// [addon]:
|
||||
// materials:
|
||||
// [material]:
|
||||
// description: [text]
|
||||
String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + object.name().toLowerCase() + ".description");
|
||||
|
||||
if (!translation.isEmpty())
|
||||
{
|
||||
// We found our translation.
|
||||
return translation;
|
||||
if (object instanceof Material) {
|
||||
String translation = user.getTranslationOrNothing(LEVEL_MATERIALS + key + ".description");
|
||||
return translation != null ? translation : "";
|
||||
} else if (object instanceof EntityType) {
|
||||
String translation = user.getTranslationOrNothing(ENTITIES + key + ".description");
|
||||
return translation != null ? translation : "";
|
||||
}
|
||||
|
||||
// No text to return.
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
@ -142,6 +142,7 @@ level:
|
||||
name: "&f&l Spawners"
|
||||
description: |-
|
||||
&7 Display only spawners.
|
||||
block-name: "&b Spawner"
|
||||
filters:
|
||||
name:
|
||||
name: "&f&l Sort by Name"
|
||||
|
@ -16,7 +16,6 @@ import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -216,7 +215,7 @@ public class LevelsManagerTest {
|
||||
islands.add(il);
|
||||
}
|
||||
// Supply no island levels first (for migrate), then islands
|
||||
when(handler.loadObjects()).thenReturn(Collections.emptyList(), islands);
|
||||
when(handler.loadObjects()).thenReturn(islands);
|
||||
when(handler.objectExists(anyString())).thenReturn(true);
|
||||
when(levelsData.getLevel()).thenReturn(-5L, -4L, -3L, -2L, -1L, 0L, 1L, 2L, 3L, 4L, 5L, 45678L);
|
||||
when(levelsData.getUniqueId()).thenReturn(uuid.toString());
|
||||
@ -231,7 +230,7 @@ public class LevelsManagerTest {
|
||||
when(iwm.getPermissionPrefix(any())).thenReturn("bskyblock.");
|
||||
|
||||
lm = new LevelsManager(addon);
|
||||
lm.migrate();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user