From 15ff5150789e0adb2544ee723ab3cb187188f829 Mon Sep 17 00:00:00 2001 From: BONNe Date: Sun, 13 Mar 2022 14:28:08 +0200 Subject: [PATCH] Implement customizable DetailsPanel. Remove old DetailsGUITab due to new implementation. --- pom.xml | 39 + src/main/java/world/bentobox/level/Level.java | 7 +- .../world/bentobox/level/LevelsManager.java | 114 +-- .../calculators/IslandLevelCalculator.java | 5 +- .../bentobox/level/panels/DetailsGUITab.java | 211 ------ .../bentobox/level/panels/DetailsPanel.java | 692 ++++++++++++++++++ src/main/resources/locales/en-US.yml | 50 ++ src/main/resources/panels/detail_panel.yml | 109 +++ src/main/resources/panels/top_panel.yml | 3 +- 9 files changed, 899 insertions(+), 331 deletions(-) delete mode 100644 src/main/java/world/bentobox/level/panels/DetailsGUITab.java create mode 100644 src/main/java/world/bentobox/level/panels/DetailsPanel.java create mode 100644 src/main/resources/panels/detail_panel.yml 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