diff --git a/pom.xml b/pom.xml
index 17d1dd9..f818b54 100644
--- a/pom.xml
+++ b/pom.xml
@@ -60,6 +60,8 @@
1.16.5-R0.1-SNAPSHOT
1.20.0
+
+ 1.0.0
${build.version}-SNAPSHOT
@@ -176,6 +178,11 @@
${bentobox.version}
provided
+
+ lv.id.bonne
+ panelutils
+ ${panelutils.version}
+
com.github.OmerBenGera
@@ -331,6 +338,38 @@
maven-deploy-plugin
2.8.2
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.3.1-SNAPSHOT
+
+ true
+
+
+ lv.id.bonne:panelutils:*
+
+
+
+
+
+ MANIFEST.MF
+
+
+
+ META-INF/MANIFEST.MF
+ src/main/resources/META-INF/MANIFEST.MF
+
+
+
+
+
+ package
+
+ shade
+
+
+
+
org.jacoco
jacoco-maven-plugin
diff --git a/src/main/java/world/bentobox/level/Level.java b/src/main/java/world/bentobox/level/Level.java
index c91a291..96e0714 100644
--- a/src/main/java/world/bentobox/level/Level.java
+++ b/src/main/java/world/bentobox/level/Level.java
@@ -74,15 +74,16 @@ public class Level extends Addon implements Listener {
} else {
configObject.saveConfigObject(settings);
}
+
+ // Save existing panels.
+ this.saveResource("panels/top_panel.yml", false);
+ this.saveResource("panels/detail_panel.yml", false);
}
private boolean loadSettings() {
// Load settings again to get worlds
settings = configObject.loadConfigObject();
- // Save existing panels.
- this.saveResource("panels/top_panel.yml", false);
-
return settings == null;
}
diff --git a/src/main/java/world/bentobox/level/LevelsManager.java b/src/main/java/world/bentobox/level/LevelsManager.java
index cfa2247..2c182a8 100644
--- a/src/main/java/world/bentobox/level/LevelsManager.java
+++ b/src/main/java/world/bentobox/level/LevelsManager.java
@@ -2,11 +2,9 @@ package world.bentobox.level;
import java.math.BigInteger;
import java.text.DecimalFormat;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
@@ -18,19 +16,12 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
-import org.bukkit.Material;
import org.bukkit.World;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import com.google.common.collect.Maps;
-import world.bentobox.bentobox.api.panels.PanelItem;
-import world.bentobox.bentobox.api.panels.builders.PanelBuilder;
-import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
-import world.bentobox.bentobox.api.panels.builders.TabbedPanelBuilder;
-import world.bentobox.bentobox.api.user.User;
import world.bentobox.bentobox.database.Database;
import world.bentobox.bentobox.database.objects.Island;
import world.bentobox.level.calculators.Results;
@@ -39,8 +30,7 @@ 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.panels.DetailsGUITab;
-import world.bentobox.level.panels.DetailsGUITab.DetailsType;
+
public class LevelsManager {
private static final String INTOPTEN = "intopten";
@@ -57,16 +47,12 @@ public class LevelsManager {
}
private Level addon;
-
// Database handler for level data
private final Database handler;
// A cache of island levels.
private final Map levelsCache;
// Top ten lists
private final Map topTenLists;
- // Background
- private final PanelItem background;
-
public LevelsManager(Level addon) {
@@ -79,8 +65,6 @@ public class LevelsManager {
levelsCache = new HashMap<>();
// Initialize top ten lists
topTenLists = new ConcurrentHashMap<>();
- // Background
- background = new PanelItemBuilder().icon(Material.BLACK_STAINED_GLASS_PANE).name(" ").build();
}
public void migrate() {
@@ -226,102 +210,6 @@ public class LevelsManager {
return level;
}
- /**
- * Displays the Top Ten list
- * @param world - world
- * @param user - the requesting player
- */
- public void getGUI(World world, final User user) {
- // Check world
- Map topTen = getTopTen(world, Level.TEN);
-
- PanelBuilder panel = new PanelBuilder()
- .name(user.getTranslation("island.top.gui-title"))
- .size(54)
- .user(user);
- // Background
- for (int j = 0; j < 54; panel.item(j++, background));
-
- // Top Ten
- int i = 0;
- boolean inTopTen = false;
- for (Entry m : topTen.entrySet()) {
- PanelItem h = getHead((i+1), m.getValue(), m.getKey(), user, world);
- panel.item(SLOTS[i], h);
- // If this is also the asking player
- if (m.getKey().equals(user.getUniqueId())) {
- inTopTen = true;
- addSelf(world, user, panel);
- }
- i++;
- }
- // Show remaining slots
- for (; i < SLOTS.length; i++) {
- panel.item(SLOTS[i], new PanelItemBuilder().icon(Material.GREEN_STAINED_GLASS_PANE).name(String.valueOf(i + 1)).build());
- }
-
- // Add yourself if you were not already in the top ten
- if (!inTopTen) {
- addSelf(world, user, panel);
- }
- panel.build();
- }
-
- private void addSelf(World world, User user, PanelBuilder panel) {
- if (addon.getIslands().hasIsland(world, user) || addon.getIslands().inTeam(world, user.getUniqueId())) {
- PanelItem head = getHead(this.getRank(world, user.getUniqueId()), this.getIslandLevel(world, user.getUniqueId()), user.getUniqueId(), user, world);
- setClickHandler(head, user, world);
- panel.item(49, head);
- }
- }
-
- private void setClickHandler(PanelItem head, User user, World world) {
- head.setClickHandler((p, u, ch, s) -> {
- new TabbedPanelBuilder()
- .user(user)
- .world(world)
- .tab(1, new DetailsGUITab(addon, world, user, DetailsType.ALL_BLOCKS))
- .tab(2, new DetailsGUITab(addon, world, user, DetailsType.ABOVE_SEA_LEVEL_BLOCKS))
- .tab(3, new DetailsGUITab(addon, world, user, DetailsType.UNDERWATER_BLOCKS))
- .tab(4, new DetailsGUITab(addon, world, user, DetailsType.SPAWNERS))
- .startingSlot(1)
- .size(54)
- .build().openPanel();
- return true;
- });
-
- }
-
- /**
- * Get the head panel item
- * @param rank - the top ten rank of this player/team. Can be used in the name of the island for vanity.
- * @param level - the level of the island
- * @param playerUUID - the UUID of the top ten player
- * @param asker - the asker of the top ten
- * @return PanelItem
- */
- private PanelItem getHead(int rank, long level, UUID playerUUID, User asker, World world) {
- final String name = addon.getPlayers().getName(playerUUID);
- List description = new ArrayList<>();
- if (rank > 0) {
- description.add(asker.getTranslation("island.top.gui-heading", "[name]", name, "[rank]", String.valueOf(rank)));
- }
- description.add(asker.getTranslation("island.top.island-level","[level]", formatLevel(level)));
- if (addon.getIslands().inTeam(world, playerUUID)) {
- List memberList = new ArrayList<>();
- for (UUID members : addon.getIslands().getMembers(world, playerUUID)) {
- memberList.add(ChatColor.AQUA + addon.getPlayers().getName(members));
- }
- description.addAll(memberList);
- }
-
- PanelItemBuilder builder = new PanelItemBuilder()
- .icon(name)
- .name(name)
- .description(description);
- return builder.build();
- }
-
/**
* Get the initial level of the island. Used to zero island levels
* @param island - island
diff --git a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java
index 76b2bd3..065f5e0 100644
--- a/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java
+++ b/src/main/java/world/bentobox/level/calculators/IslandLevelCalculator.java
@@ -352,8 +352,7 @@ public class IslandLevelCalculator {
/**
* Get a chunk async
* @param env - the environment
- * @param x - chunk x coordinate
- * @param z - chunk z coordinate
+ * @param pairList - chunk coordinate
* @return a future chunk or future null if there is no chunk to load, e.g., there is no island nether
*/
private CompletableFuture> getWorldChunk(Environment env, Queue> pairList) {
@@ -481,7 +480,7 @@ public class IslandLevelCalculator {
/**
* Count the blocks on the island
- * @param chunk chunk to scan
+ * @param cp chunk to scan
*/
private void scanAsync(ChunkPair cp) {
for (int x = 0; x< 16; x++) {
diff --git a/src/main/java/world/bentobox/level/panels/DetailsGUITab.java b/src/main/java/world/bentobox/level/panels/DetailsGUITab.java
deleted file mode 100644
index 823a4df..0000000
--- a/src/main/java/world/bentobox/level/panels/DetailsGUITab.java
+++ /dev/null
@@ -1,211 +0,0 @@
-/**
- *
- */
-package world.bentobox.level.panels;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.EnumMap;
-import java.util.List;
-import java.util.Map;
-
-import org.bukkit.Material;
-import org.bukkit.Tag;
-import org.bukkit.World;
-import org.bukkit.event.inventory.ClickType;
-import org.eclipse.jdt.annotation.Nullable;
-
-import com.google.common.base.Enums;
-
-import world.bentobox.bentobox.api.localization.TextVariables;
-import world.bentobox.bentobox.api.panels.Panel;
-import world.bentobox.bentobox.api.panels.PanelItem;
-import world.bentobox.bentobox.api.panels.PanelItem.ClickHandler;
-import world.bentobox.bentobox.api.panels.Tab;
-import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
-import world.bentobox.bentobox.api.user.User;
-import world.bentobox.bentobox.database.objects.Island;
-import world.bentobox.bentobox.util.Util;
-import world.bentobox.level.Level;
-import world.bentobox.level.objects.IslandLevels;
-
-/**
- * @author tastybento
- *
- */
-public class DetailsGUITab implements Tab, ClickHandler {
-
- public enum DetailsType {
- ABOVE_SEA_LEVEL_BLOCKS,
- ALL_BLOCKS,
- SPAWNERS,
- UNDERWATER_BLOCKS
- }
-
- /**
- * Converts block materials to item materials
- */
- private static final Map M2I;
- static {
- Map m2i = new EnumMap<>(Material.class);
- m2i.put(Material.WATER, Material.WATER_BUCKET);
- m2i.put(Material.LAVA, Material.LAVA_BUCKET);
- m2i.put(Material.AIR, Material.BLACK_STAINED_GLASS_PANE);
- m2i.put(Material.VOID_AIR, Material.BLACK_STAINED_GLASS_PANE);
- m2i.put(Material.CAVE_AIR, Material.BLACK_STAINED_GLASS_PANE);
- m2i.put(Material.WALL_TORCH, Material.TORCH);
- m2i.put(Material.REDSTONE_WALL_TORCH, Material.REDSTONE_TORCH);
- m2i.put(Material.TALL_SEAGRASS, Material.SEAGRASS);
- m2i.put(Material.PISTON_HEAD, Material.PISTON);
- m2i.put(Material.MOVING_PISTON, Material.PISTON);
- m2i.put(Material.REDSTONE_WIRE, Material.REDSTONE);
- m2i.put(Material.NETHER_PORTAL, Material.MAGENTA_STAINED_GLASS_PANE);
- m2i.put(Material.END_PORTAL, Material.BLACK_STAINED_GLASS_PANE);
- m2i.put(Material.ATTACHED_MELON_STEM, Material.MELON_SEEDS);
- m2i.put(Material.ATTACHED_PUMPKIN_STEM, Material.PUMPKIN_SEEDS);
- m2i.put(Material.MELON_STEM, Material.MELON_SEEDS);
- m2i.put(Material.PUMPKIN_STEM, Material.PUMPKIN_SEEDS);
- m2i.put(Material.COCOA, Material.COCOA_BEANS);
- m2i.put(Material.TRIPWIRE, Material.STRING);
- m2i.put(Material.CARROTS, Material.CARROT);
- m2i.put(Material.POTATOES, Material.POTATO);
- m2i.put(Material.BEETROOTS, Material.BEETROOT);
- m2i.put(Material.END_GATEWAY, Material.BEDROCK);
- m2i.put(Material.FROSTED_ICE, Material.ICE);
- m2i.put(Material.KELP_PLANT, Material.KELP);
- m2i.put(Material.BUBBLE_COLUMN, Material.WATER_BUCKET);
- m2i.put(Material.SWEET_BERRY_BUSH, Material.SWEET_BERRIES);
- m2i.put(Material.BAMBOO_SAPLING, Material.BAMBOO);
- m2i.put(Material.FIRE, Material.FLINT_AND_STEEL);
- // 1.16.1
- if (Enums.getIfPresent(Material.class, "WEEPING_VINES_PLANT").isPresent()) {
- m2i.put(Material.WEEPING_VINES_PLANT, Material.WEEPING_VINES);
- m2i.put(Material.TWISTING_VINES_PLANT, Material.TWISTING_VINES);
- m2i.put(Material.SOUL_WALL_TORCH, Material.SOUL_TORCH);
- }
-
-
- M2I = Collections.unmodifiableMap(m2i);
- }
- private final Level addon;
- private final @Nullable Island island;
- private List items;
- private DetailsType type;
- private final User user;
- private final World world;
-
- public DetailsGUITab(Level addon, World world, User user, DetailsType type) {
- this.addon = addon;
- this.world = world;
- this.user = user;
- this.island = addon.getIslands().getIsland(world, user);
- this.type = type;
- // Generate report
- generateReport(type);
- }
-
- private void createItem(Material m, Integer count) {
- if (count == null || count <= 0) return;
- // Convert walls
- m = Enums.getIfPresent(Material.class, m.name().replace("WALL_", "")).or(m);
- // Tags
- if (Enums.getIfPresent(Material.class, "SOUL_CAMPFIRE").isPresent()) {
- if (Tag.FIRE.isTagged(m)) {
- items.add(new PanelItemBuilder()
- .icon(Material.CAMPFIRE)
- .name(Util.prettifyText(m.name()) + " x " + count)
- .build());
- return;
- }
- }
- if (Tag.FLOWER_POTS.isTagged(m)) {
- m = Enums.getIfPresent(Material.class, m.name().replace("POTTED_", "")).or(m);
- }
- items.add(new PanelItemBuilder()
- .icon(M2I.getOrDefault(m, m))
- .name(user.getTranslation("island.level-details.syntax", TextVariables.NAME,
- Util.prettifyText(m.name()), TextVariables.NUMBER, String.valueOf(count)))
- .build());
-
- }
-
- private void generateReport(DetailsType type) {
- items = new ArrayList<>();
- IslandLevels ld = addon.getManager().getLevelsData(island);
- // Get the items from the report
- Map sumTotal = new EnumMap<>(Material.class);
- sumTotal.putAll(ld.getMdCount());
- sumTotal.putAll(ld.getUwCount());
- switch(type) {
- case ABOVE_SEA_LEVEL_BLOCKS:
- ld.getMdCount().forEach(this::createItem);
- break;
- case SPAWNERS:
- sumTotal.entrySet().stream().filter(m -> m.getKey().equals(Material.SPAWNER)).forEach(e -> createItem(e.getKey(), e.getValue()));
- break;
- case UNDERWATER_BLOCKS:
- ld.getUwCount().forEach(this::createItem);
- break;
- default:
- sumTotal.forEach(this::createItem);
- break;
- }
- if (type.equals(DetailsType.ALL_BLOCKS) && items.isEmpty()) {
- // Nothing here - looks like they need to run level
- items.add(new PanelItemBuilder()
- .name(user.getTranslation("island.level-details.hint")).icon(Material.WRITTEN_BOOK)
- .build());
- }
- }
-
- @Override
- public PanelItem getIcon() {
- switch(type) {
- case ABOVE_SEA_LEVEL_BLOCKS:
- return new PanelItemBuilder().icon(Material.GRASS_BLOCK).name(user.getTranslation("island.level-details.above-sea-level-blocks")).build();
- case SPAWNERS:
- return new PanelItemBuilder().icon(Material.SPAWNER).name(user.getTranslation("island.level-details.spawners")).build();
- case UNDERWATER_BLOCKS:
- return new PanelItemBuilder().icon(Material.WATER_BUCKET).name(user.getTranslation("island.level-details.underwater-blocks")).build();
- default:
- return new PanelItemBuilder().icon(Material.GRASS_BLOCK).name(user.getTranslation("island.level-details.all-blocks")).build();
- }
- }
-
- @Override
- public String getName() {
- String name = user.getTranslation("island.level-details.no-island");
- if (island.getOwner() != null) {
- name = island.getName() != null ? island.getName() :
- user.getTranslation("island.level-details.names-island", TextVariables.NAME, addon.getPlayers().getName(island.getOwner()));
- }
- return name;
- }
-
- @Override
- public List<@Nullable PanelItem> getPanelItems() {
- return items;
- }
-
- @Override
- public String getPermission() {
- String permPrefix = addon.getPlugin().getIWM().getPermissionPrefix(world);
- switch(type) {
- case ABOVE_SEA_LEVEL_BLOCKS:
- return permPrefix + "island.level.details.above-sea-level";
- case SPAWNERS:
- return permPrefix + "island.level.details.spawners";
- case UNDERWATER_BLOCKS:
- return permPrefix + "island.level.details.underwater";
- default:
- return permPrefix + "island.level.details.blocks";
-
- }
- }
-
- @Override
- public boolean onClick(Panel panel, User user, ClickType clickType, int slot) {
- return true;
- }
-
-}
diff --git a/src/main/java/world/bentobox/level/panels/DetailsPanel.java b/src/main/java/world/bentobox/level/panels/DetailsPanel.java
new file mode 100644
index 0000000..f253505
--- /dev/null
+++ b/src/main/java/world/bentobox/level/panels/DetailsPanel.java
@@ -0,0 +1,692 @@
+package world.bentobox.level.panels;
+
+
+import com.google.common.base.Enums;
+import org.bukkit.Material;
+import org.bukkit.World;
+import org.bukkit.event.inventory.ClickType;
+import org.bukkit.inventory.ItemStack;
+import java.io.File;
+import java.util.*;
+import java.util.stream.Collectors;
+
+import lv.id.bonne.panelutils.PanelUtils;
+import world.bentobox.bentobox.api.panels.PanelItem;
+import world.bentobox.bentobox.api.panels.TemplatedPanel;
+import world.bentobox.bentobox.api.panels.builders.PanelItemBuilder;
+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.hooks.LangUtilsHook;
+import world.bentobox.bentobox.util.Pair;
+import world.bentobox.level.Level;
+import world.bentobox.level.objects.IslandLevels;
+import world.bentobox.level.util.Utils;
+
+
+/**
+ * This class opens GUI that shows generator view for user.
+ */
+public class DetailsPanel
+{
+ // ---------------------------------------------------------------------
+ // Section: Internal Constructor
+ // ---------------------------------------------------------------------
+
+
+ /**
+ * This is internal constructor. It is used internally in current class to avoid creating objects everywhere.
+ *
+ * @param addon Level object
+ * @param world World where user is operating
+ * @param user User who opens panel
+ */
+ private DetailsPanel(Level addon,
+ World world,
+ User user)
+ {
+ this.addon = addon;
+ this.world = world;
+ this.user = user;
+
+ this.island = this.addon.getIslands().getIsland(world, user);
+
+ if (this.island != null)
+ {
+ this.levelsData = this.addon.getManager().getLevelsData(this.island);
+ }
+ else
+ {
+ this.levelsData = null;
+ }
+
+ // By default no-filters are active.
+ this.activeTab = Tab.ALL_BLOCKS;
+ this.materialCountList = new ArrayList<>(Material.values().length);
+
+ this.updateFilters();
+ }
+
+
+ /**
+ * This method builds this GUI.
+ */
+ private void build()
+ {
+ if (this.island == null || this.levelsData == null)
+ {
+ // Nothing to see.
+ Utils.sendMessage(this.user, this.user.getTranslation("general.errors.no-island"));
+ return;
+ }
+
+ if (this.levelsData.getMdCount().isEmpty() && this.levelsData.getUwCount().isEmpty())
+ {
+ // Nothing to see.
+ Utils.sendMessage(this.user, this.user.getTranslation("level.conversations.no-data"));
+ return;
+ }
+
+ // Start building panel.
+ TemplatedPanelBuilder panelBuilder = new TemplatedPanelBuilder();
+ panelBuilder.user(this.user);
+ panelBuilder.world(this.user.getWorld());
+
+ panelBuilder.template("detail_panel", new File(this.addon.getDataFolder(), "panels"));
+
+ panelBuilder.parameters("[name]", this.user.getName());
+
+ panelBuilder.registerTypeBuilder("NEXT", this::createNextButton);
+ panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton);
+ panelBuilder.registerTypeBuilder("BLOCK", this::createMaterialButton);
+
+ // Register tabs
+ panelBuilder.registerTypeBuilder("TAB", this::createTabButton);
+
+ // Register unknown type builder.
+ panelBuilder.build();
+ }
+
+
+ /**
+ * This method updates filter of elements based on tabs.
+ */
+ private void updateFilters()
+ {
+ this.materialCountList.clear();
+
+ switch (this.activeTab)
+ {
+ case ALL_BLOCKS -> {
+ Map 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);
+ });
+
+ 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().sorted((Map.Entry.comparingByKey())).
+ forEachOrdered(entry ->
+ this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
+ }
+ case UNDERWATER -> {
+ this.levelsData.getUwCount().entrySet().stream().sorted((Map.Entry.comparingByKey())).
+ forEachOrdered(entry ->
+ this.materialCountList.add(new Pair<>(entry.getKey(), entry.getValue())));
+ }
+ case SPAWNER -> {
+ int aboveWater = this.levelsData.getMdCount().getOrDefault(Material.SPAWNER, 0);
+ int underWater = this.levelsData.getUwCount().getOrDefault(Material.SPAWNER, 0);
+
+ // TODO: spawners need some touch...
+ this.materialCountList.add(new Pair<>(Material.SPAWNER, underWater + aboveWater));
+ }
+ }
+
+ this.pageIndex = 0;
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Tab Button Type
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Create tab button panel item.
+ *
+ * @param template the template
+ * @param slot the slot
+ * @return the panel item
+ */
+ private PanelItem createTabButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ // Set icon
+ builder.icon(template.icon().clone());
+ }
+
+ if (template.title() != null)
+ {
+ // Set title
+ builder.name(this.user.getTranslation(this.world, template.title()));
+ }
+
+ if (template.description() != null)
+ {
+ // Set description
+ builder.description(this.user.getTranslation(this.world, template.description()));
+ }
+
+ Tab tab = Enums.getIfPresent(Tab.class, String.valueOf(template.dataMap().get("tab"))).or(Tab.ALL_BLOCKS);
+
+ // Get only possible actions, by removing all inactive ones.
+ List activeActions = new ArrayList<>(template.actions());
+
+ activeActions.removeIf(action ->
+ "VIEW".equalsIgnoreCase(action.actionType()) && this.activeTab == tab);
+
+ // Add Click handler
+ builder.clickHandler((panel, user, clickType, i) ->
+ {
+ for (ItemTemplateRecord.ActionRecords action : activeActions)
+ {
+ if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
+ {
+ if ("VIEW".equalsIgnoreCase(action.actionType()))
+ {
+ this.activeTab = tab;
+
+ // Update filters.
+ this.updateFilters();
+ this.build();
+ }
+ }
+ }
+
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = activeActions.stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ builder.glow(this.activeTab == tab);
+
+ return builder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Create common buttons
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Create next button panel item.
+ *
+ * @param template the template
+ * @param slot the slot
+ * @return the panel item
+ */
+ private PanelItem createNextButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ long size = this.materialCountList.size();
+
+ if (size <= slot.amountMap().getOrDefault("BLOCK", 1) ||
+ 1.0 * size / slot.amountMap().getOrDefault("BLOCK", 1) <= this.pageIndex + 1)
+ {
+ // There are no next elements
+ return null;
+ }
+
+ int nextPageIndex = this.pageIndex + 2;
+
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ ItemStack clone = template.icon().clone();
+
+ if ((Boolean) template.dataMap().getOrDefault("indexing", false))
+ {
+ clone.setAmount(nextPageIndex);
+ }
+
+ builder.icon(clone);
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title()));
+ }
+
+ if (template.description() != null)
+ {
+ builder.description(this.user.getTranslation(this.world, template.description(),
+ "[number]", String.valueOf(nextPageIndex)));
+ }
+
+ // Add ClickHandler
+ builder.clickHandler((panel, user, clickType, i) ->
+ {
+ for (ItemTemplateRecord.ActionRecords action : template.actions())
+ {
+ if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
+ {
+ if ("NEXT".equalsIgnoreCase(action.actionType()))
+ {
+ this.pageIndex++;
+ this.build();
+ }
+ }
+ }
+
+ // Always return true.
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = template.actions().stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ return builder.build();
+ }
+
+
+ /**
+ * Create previous button panel item.
+ *
+ * @param template the template
+ * @param slot the slot
+ * @return the panel item
+ */
+ private PanelItem createPreviousButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot)
+ {
+ if (this.pageIndex == 0)
+ {
+ // There are no next elements
+ return null;
+ }
+
+ int previousPageIndex = this.pageIndex;
+
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ ItemStack clone = template.icon().clone();
+
+ if ((Boolean) template.dataMap().getOrDefault("indexing", false))
+ {
+ clone.setAmount(previousPageIndex);
+ }
+
+ builder.icon(clone);
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title()));
+ }
+
+ if (template.description() != null)
+ {
+ builder.description(this.user.getTranslation(this.world, template.description(),
+ "[number]", String.valueOf(previousPageIndex)));
+ }
+
+ // Add ClickHandler
+ builder.clickHandler((panel, user, clickType, i) ->
+ {
+ for (ItemTemplateRecord.ActionRecords action : template.actions())
+ {
+ if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType()))
+ {
+ if ("PREVIOUS".equalsIgnoreCase(action.actionType()))
+ {
+ this.pageIndex--;
+ this.build();
+ }
+ }
+ }
+
+ // Always return true.
+ return true;
+ });
+
+ // Collect tooltips.
+ List tooltips = template.actions().stream().
+ filter(action -> action.tooltip() != null).
+ map(action -> this.user.getTranslation(this.world, action.tooltip())).
+ filter(text -> !text.isBlank()).
+ collect(Collectors.toCollection(() -> new ArrayList<>(template.actions().size())));
+
+ // Add tooltips.
+ if (!tooltips.isEmpty())
+ {
+ // Empty line and tooltips.
+ builder.description("");
+ builder.description(tooltips);
+ }
+
+ return builder.build();
+ }
+
+
+// ---------------------------------------------------------------------
+// Section: Create Material Button
+// ---------------------------------------------------------------------
+
+
+ /**
+ * Create material button panel item.
+ *
+ * @param template the template
+ * @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.
+ return null;
+ }
+
+ int index = this.pageIndex * slot.amountMap().getOrDefault("BLOCK", 1) + slot.slot();
+
+ if (index >= this.materialCountList.size())
+ {
+ // Out of index.
+ return null;
+ }
+
+ return this.createMaterialButton(template, this.materialCountList.get(index));
+ }
+
+
+ /**
+ * This method creates button for material.
+ *
+ * @param template the template of the button
+ * @param materialCount materialCount which button must be created.
+ * @return PanelItem for generator tier.
+ */
+ private PanelItem createMaterialButton(ItemTemplateRecord template,
+ Pair materialCount)
+ {
+ PanelItemBuilder builder = new PanelItemBuilder();
+
+ if (template.icon() != null)
+ {
+ builder.icon(template.icon().clone());
+ }
+ else
+ {
+ builder.icon(PanelUtils.getMaterialItem(materialCount.getKey()));
+ }
+
+ if (materialCount.getValue() < 64)
+ {
+ builder.amount(materialCount.getValue());
+ }
+
+ if (template.title() != null)
+ {
+ builder.name(this.user.getTranslation(this.world, template.title(),
+ "[number]", String.valueOf(materialCount.getValue()),
+ "[material]", DetailsPanel.prettifyObject(materialCount.getKey(), this.user)));
+ }
+
+ String description = DetailsPanel.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 ? this.user.getTranslationOrNothing(reference + "value",
+ "[number]", String.valueOf(blockValue)) : "";
+
+ int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(materialCount.getKey(), 0);
+ String limit = blockLimit > 0 ? this.user.getTranslationOrNothing(reference + "limit",
+ "[number]", String.valueOf(blockLimit)) : "";
+
+ String count = this.user.getTranslationOrNothing(reference + "count",
+ "[number]", String.valueOf(materialCount.getValue()));
+
+ if (template.description() != null)
+ {
+ builder.description(this.user.getTranslation(this.world, template.description(),
+ "[description]", description,
+ "[id]", blockId,
+ "[value]", value,
+ "[limit]", limit,
+ "[count]", count).
+ replaceAll("(?m)^[ \\t]*\\r?\\n", "").
+ replaceAll("(?> 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;
+}
diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml
index 144aee9..255e481 100755
--- a/src/main/resources/locales/en-US.yml
+++ b/src/main/resources/locales/en-US.yml
@@ -66,6 +66,7 @@ level:
gui:
titles:
top: "&0&l Top Islands"
+ detail-panel: "&0&l [name]'s island"
buttons:
island:
empty: '&f&l [name]. place'
@@ -89,5 +90,54 @@ level:
place: "&7&o [number]. &r&7 place"
# Section for parsing [level]
level: "&7 Level: &o [number]"
+ material:
+ name: "&f&l [number] x [material]"
+ description: |-
+ [description]
+ [count]
+ [value]
+ [limit]
+ [id]
+ id: "&7 Block id: &e [id]"
+ value: "&7 Block value: &e [number]"
+ limit: "&7 Block limit: &e [number]"
+ count: "&7 Number of blocks: &e [number]"
+ all_blocks:
+ name: "&f&l All Blocks"
+ description: |-
+ &7 Display all blocks
+ &7 on island.
+ above_sea_level:
+ name: "&f&l Blocks Above Sea Level"
+ description: |-
+ &7 Display only blocks
+ &7 that are above sea
+ &7 level.
+ underwater:
+ name: "&f&l Blocks Under Sea level"
+ description: |-
+ &7 Display only blocks
+ &7 that are bellow sea
+ &7 level.
+ spawner:
+ name: "&f&l Spawners"
+ description: |-
+ &7 Display only spawners.
+ # Button that is used in multi-page GUIs which allows to return to previous page.
+ previous:
+ name: "&f&l Previous Page"
+ description: |-
+ &7 Switch to [number] page
+ # Button that is used in multi-page GUIs which allows to go to next page.
+ next:
+ name: "&f&l Next Page"
+ description: |-
+ &7 Switch to [number] page
tips:
click-to-view: "&e Click &7 to view."
+ click-to-previous: "&e Click &7 to view previous page."
+ click-to-next: "&e Click &7 to view next page."
+ conversations:
+ # Prefix for messages that are send from server.
+ prefix: "&l&6 [BentoBox]: &r"
+ no-data: "&c Run level to see the block report."
\ No newline at end of file
diff --git a/src/main/resources/panels/detail_panel.yml b/src/main/resources/panels/detail_panel.yml
new file mode 100644
index 0000000..61daf9c
--- /dev/null
+++ b/src/main/resources/panels/detail_panel.yml
@@ -0,0 +1,109 @@
+detail_panel:
+ title: level.gui.titles.detail-panel
+ type: INVENTORY
+ background:
+ icon: BLACK_STAINED_GLASS_PANE
+ title: "&b&r" # Empty text
+ border:
+ icon: BLACK_STAINED_GLASS_PANE
+ title: "&b&r" # Empty text
+ force-shown: []
+ content:
+ 1:
+ 2:
+ icon: STONE
+ title: level.gui.buttons.all_blocks.name
+ description: level.gui.buttons.all_blocks.description
+ data:
+ type: TAB
+ tab: ALL_BLOCKS
+ actions:
+ view:
+ click-type: unknwon
+ tooltip: level.gui.tips.click-to-view
+ 3:
+ icon: GRASS_BLOCK
+ title: level.gui.buttons.above_sea_level.name
+ description: level.gui.buttons.above_sea_level.description
+ data:
+ type: TAB
+ tab: ABOVE_SEA_LEVEL
+ actions:
+ view:
+ click-type: unknwon
+ tooltip: level.gui.tips.click-to-view
+ 4:
+ icon: WATER_BUCKET
+ title: level.gui.buttons.underwater.name
+ description: level.gui.buttons.underwater.description
+ data:
+ type: TAB
+ tab: UNDERWATER
+ actions:
+ view:
+ click-type: unknwon
+ tooltip: level.gui.tips.click-to-view
+ 5:
+ icon: SPAWNER
+ title: level.gui.buttons.spawner.name
+ description: level.gui.buttons.spawner.description
+ data:
+ type: TAB
+ tab: SPAWNER
+ actions:
+ view:
+ click-type: unknwon
+ tooltip: level.gui.tips.click-to-view
+ 2:
+ 2: material_button
+ 3: material_button
+ 4: material_button
+ 5: material_button
+ 6: material_button
+ 7: material_button
+ 8: material_button
+ 3:
+ 1:
+ icon: TIPPED_ARROW:INSTANT_HEAL::::1
+ title: level.gui.buttons.previous.name
+ description: level.gui.buttons.previous.description
+ data:
+ type: PREVIOUS
+ indexing: true
+ actions:
+ previous:
+ click-type: unknown
+ tooltip: level.gui.tips.click-to-previous
+ 2: material_button
+ 3: material_button
+ 4: material_button
+ 5: material_button
+ 6: material_button
+ 7: material_button
+ 8: material_button
+ 9:
+ icon: TIPPED_ARROW:JUMP::::1
+ title: level.gui.buttons.next.name
+ description: level.gui.buttons.next.description
+ data:
+ type: NEXT
+ indexing: true
+ actions:
+ next:
+ click-type: unknown
+ tooltip: level.gui.tips.click-to-next
+ 4:
+ 2: material_button
+ 3: material_button
+ 4: material_button
+ 5: material_button
+ 6: material_button
+ 7: material_button
+ 8: material_button
+ reusable:
+ material_button:
+ #icon: STONE
+ title: level.gui.buttons.material.name
+ description: level.gui.buttons.material.description
+ data:
+ type: BLOCK
\ No newline at end of file
diff --git a/src/main/resources/panels/top_panel.yml b/src/main/resources/panels/top_panel.yml
index 6f24683..83d49ce 100644
--- a/src/main/resources/panels/top_panel.yml
+++ b/src/main/resources/panels/top_panel.yml
@@ -120,5 +120,6 @@ top_panel:
data:
type: VIEW
actions:
- left:
+ view:
+ click-type: unknown
tooltip: level.gui.tips.click-to-view
\ No newline at end of file