diff --git a/src/main/java/world/bentobox/level/config/BlockConfig.java b/src/main/java/world/bentobox/level/config/BlockConfig.java index efcb3ee..b4d0025 100644 --- a/src/main/java/world/bentobox/level/config/BlockConfig.java +++ b/src/main/java/world/bentobox/level/config/BlockConfig.java @@ -2,9 +2,12 @@ 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; +import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -26,6 +29,7 @@ public class BlockConfig { private Map blockLimits = new EnumMap<>(Material.class); private Map blockValues = new EnumMap<>(Material.class); private final Map> worldBlockValues = new HashMap<>(); + private final List hiddenBlocks; private Level addon; /** @@ -49,6 +53,16 @@ public BlockConfig(Level addon, YamlConfiguration blockValues, File file) throws if (blockValues.isConfigurationSection("worlds")) { loadWorlds(blockValues); } + // Hidden + hiddenBlocks = blockValues.getStringList("hidden-blocks").stream().map(name -> { + try { + return Material.valueOf(name.toUpperCase(Locale.ENGLISH)); + + } catch (Exception e) { + return null; + } + }).filter(Objects::nonNull).toList(); + // All done blockValues.save(file); } @@ -159,5 +173,22 @@ public Integer getValue(World world, Material md) { return null; } + /** + * Return true if the block should be hidden + * @param m block material + * @return true if hidden + */ + public boolean isHiddenBlock(Material m) { + return hiddenBlocks.contains(m); + } + + /** + * Return true if the block should not be hidden + * @param m block material + * @return false if hidden + */ + public boolean isNotHiddenBlock(Material m) { + return !hiddenBlocks.contains(m); + } } diff --git a/src/main/java/world/bentobox/level/panels/DetailsPanel.java b/src/main/java/world/bentobox/level/panels/DetailsPanel.java index 222174d..90fbf45 100644 --- a/src/main/java/world/bentobox/level/panels/DetailsPanel.java +++ b/src/main/java/world/bentobox/level/panels/DetailsPanel.java @@ -33,84 +33,84 @@ * 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.VALUE_BLOCKS; - this.activeFilter = Filter.NAME; - this.materialCountList = new ArrayList<>(Material.values().length); - - this.updateFilters(); - } + // --------------------------------------------------------------------- + // 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; + } - /** - * 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; - } + // By default no-filters are active. + this.activeTab = Tab.VALUE_BLOCKS; + this.activeFilter = Filter.NAME; + 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; - } + 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()); + // 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.template("detail_panel", new File(this.addon.getDataFolder(), "panels")); - panelBuilder.parameters("[name]", this.user.getName()); + panelBuilder.parameters("[name]", this.user.getName()); - panelBuilder.registerTypeBuilder("NEXT", this::createNextButton); - panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton); - panelBuilder.registerTypeBuilder("BLOCK", this::createMaterialButton); + panelBuilder.registerTypeBuilder("NEXT", this::createNextButton); + panelBuilder.registerTypeBuilder("PREVIOUS", this::createPreviousButton); + panelBuilder.registerTypeBuilder("BLOCK", this::createMaterialButton); - panelBuilder.registerTypeBuilder("FILTER", this::createFilterButton); + panelBuilder.registerTypeBuilder("FILTER", this::createFilterButton); - // Register tabs - panelBuilder.registerTypeBuilder("TAB", this::createTabButton); + // Register tabs + panelBuilder.registerTypeBuilder("TAB", this::createTabButton); - // Register unknown type builder. - panelBuilder.build(); - } + // Register unknown type builder. + panelBuilder.build(); + } - /** - * This method updates filter of elements based on tabs. - */ - private void updateFilters() { - this.materialCountList.clear(); + /** + * This method updates filter of elements based on tabs. + */ + private void updateFilters() { + this.materialCountList.clear(); - switch (this.activeTab) { + switch (this.activeTab) { case VALUE_BLOCKS -> { Map materialCountMap = new EnumMap<>(Material.class); @@ -126,6 +126,9 @@ private void updateFilters() { 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())); @@ -133,581 +136,590 @@ private void updateFilters() { }); } - 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)); - } - } - - Comparator> 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); - - return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); - } else { - return Integer.compare(o2.getValue(), o1.getValue()); - } - }; - } - 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(); - - blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o2.getKey(), 0); - int o2Count = blockLimit > 0 ? Math.min(o2.getValue(), blockLimit) : o2.getValue(); - - long o1Value = (long) o1Count - * this.addon.getBlockConfig().getBlockValues().getOrDefault(o1.getKey(), 0); - long o2Value = (long) o2Count - * this.addon.getBlockConfig().getBlockValues().getOrDefault(o2.getKey(), 0); - - if (o1Value == o2Value) { - String o1Name = Utils.prettifyObject(o1.getKey(), this.user); - String o2Name = Utils.prettifyObject(o2.getKey(), this.user); - - return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); - } else { - return Long.compare(o2Value, o1Value); - } - }; - } - default -> { - sorter = (o1, o2) -> { - String o1Name = Utils.prettifyObject(o1.getKey(), this.user); - String o2Name = Utils.prettifyObject(o2.getKey(), this.user); - - return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); - }; - } - } - - this.materialCountList.sort(sorter); - - 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())); - } + 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)); + + // 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.addon.getBlockConfig().isNotHiddenBlock(Material.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)); + } + } + } + + Comparator> 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); + + return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); + } else { + return Integer.compare(o2.getValue(), o1.getValue()); + } + }; + } + 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(); + + blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(o2.getKey(), 0); + int o2Count = blockLimit > 0 ? Math.min(o2.getValue(), blockLimit) : o2.getValue(); + + long o1Value = (long) o1Count + * this.addon.getBlockConfig().getBlockValues().getOrDefault(o1.getKey(), 0); + long o2Value = (long) o2Count + * this.addon.getBlockConfig().getBlockValues().getOrDefault(o2.getKey(), 0); + + if (o1Value == o2Value) { + String o1Name = Utils.prettifyObject(o1.getKey(), this.user); + String o2Name = Utils.prettifyObject(o2.getKey(), this.user); + + return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); + } else { + return Long.compare(o2Value, o1Value); + } + }; + } + default -> { + sorter = (o1, o2) -> { + String o1Name = Utils.prettifyObject(o1.getKey(), this.user); + String o2Name = Utils.prettifyObject(o2.getKey(), this.user); + + return String.CASE_INSENSITIVE_ORDER.compare(o1Name, o2Name); + }; + } + } + + this.materialCountList.sort(sorter); + + 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.VALUE_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())) - && "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(); - } - - /** - * Create next button panel item. - * - * @param template the template - * @param slot the slot - * @return the panel item - */ - private PanelItem createFilterButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) { - PanelItemBuilder builder = new PanelItemBuilder(); - - if (template.icon() != null) { - // Set icon - builder.icon(template.icon().clone()); - } - - Filter filter; - - if (slot.amountMap().getOrDefault("FILTER", 0) > 1) { - filter = Enums.getIfPresent(Filter.class, String.valueOf(template.dataMap().get("filter"))).or(Filter.NAME); - } else { - filter = this.activeFilter; - } - - final String reference = "level.gui.buttons.filters."; - - if (template.title() != null) { - // Set title - builder.name(this.user.getTranslation(this.world, - template.title().replace("[filter]", filter.name().toLowerCase()))); - } else { - builder.name(this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".name")); - } - - if (template.description() != null) { - // Set description - builder.description(this.user.getTranslation(this.world, - template.description().replace("[filter]", filter.name().toLowerCase()))); - } else { - builder.name( - this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".description")); - } - - // Get only possible actions, by removing all inactive ones. - List activeActions = new ArrayList<>(template.actions()); - - // Add Click handler - builder.clickHandler((panel, user, clickType, i) -> { - for (ItemTemplateRecord.ActionRecords action : activeActions) { - if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType())) { - if ("UP".equalsIgnoreCase(action.actionType())) { - this.activeFilter = Utils.getNextValue(Filter.values(), filter); - - // Update filters. - this.updateFilters(); - this.build(); - } else if ("DOWN".equalsIgnoreCase(action.actionType())) { - this.activeFilter = Utils.getPreviousValue(Filter.values(), filter); - - // Update filters. - this.updateFilters(); - this.build(); - } else if ("SELECT".equalsIgnoreCase(action.actionType())) { - this.activeFilter = filter; - - // 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.activeFilter == filter); - - 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.TRUE.equals(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(), TextVariables.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())) - && "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.TRUE.equals(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(), TextVariables.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())) - && "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(), TextVariables.NUMBER, - String.valueOf(materialCount.getValue()), "[material]", - Utils.prettifyObject(materialCount.getKey(), this.user))); - } - - 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 - ? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER, - String.valueOf(blockValue)) - : ""; - - int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(materialCount.getKey(), 0); - String 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())); - - long calculatedValue = (long) Math.min(blockLimit > 0 ? blockLimit : Integer.MAX_VALUE, - materialCount.getValue()) * blockValue; - String valueText = calculatedValue > 0 ? this.user.getTranslationOrNothing(reference + "calculated", - TextVariables.NUMBER, String.valueOf(calculatedValue)) : ""; - - if (template.description() != null) { - builder.description(this.user - .getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId, - "[value]", value, "[calculated]", valueText, "[limit]", limit, "[count]", count) - .replaceAll("(?m)^[ \\t]*\\r?\\n", "").replaceAll("(? 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())) + && "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(); + } + + /** + * Create next button panel item. + * + * @param template the template + * @param slot the slot + * @return the panel item + */ + private PanelItem createFilterButton(ItemTemplateRecord template, TemplatedPanel.ItemSlot slot) { + PanelItemBuilder builder = new PanelItemBuilder(); + + if (template.icon() != null) { + // Set icon + builder.icon(template.icon().clone()); + } + + Filter filter; + + if (slot.amountMap().getOrDefault("FILTER", 0) > 1) { + filter = Enums.getIfPresent(Filter.class, String.valueOf(template.dataMap().get("filter"))).or(Filter.NAME); + } else { + filter = this.activeFilter; + } + + final String reference = "level.gui.buttons.filters."; + + if (template.title() != null) { + // Set title + builder.name(this.user.getTranslation(this.world, + template.title().replace("[filter]", filter.name().toLowerCase()))); + } else { + builder.name(this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".name")); + } + + if (template.description() != null) { + // Set description + builder.description(this.user.getTranslation(this.world, + template.description().replace("[filter]", filter.name().toLowerCase()))); + } else { + builder.name( + this.user.getTranslation(this.world, reference + filter.name().toLowerCase() + ".description")); + } + + // Get only possible actions, by removing all inactive ones. + List activeActions = new ArrayList<>(template.actions()); + + // Add Click handler + builder.clickHandler((panel, user, clickType, i) -> { + for (ItemTemplateRecord.ActionRecords action : activeActions) { + if (clickType == action.clickType() || ClickType.UNKNOWN.equals(action.clickType())) { + if ("UP".equalsIgnoreCase(action.actionType())) { + this.activeFilter = Utils.getNextValue(Filter.values(), filter); + + // Update filters. + this.updateFilters(); + this.build(); + } else if ("DOWN".equalsIgnoreCase(action.actionType())) { + this.activeFilter = Utils.getPreviousValue(Filter.values(), filter); + + // Update filters. + this.updateFilters(); + this.build(); + } else if ("SELECT".equalsIgnoreCase(action.actionType())) { + this.activeFilter = filter; + + // 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.activeFilter == filter); + + 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.TRUE.equals(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(), TextVariables.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())) + && "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.TRUE.equals(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(), TextVariables.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())) + && "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(), TextVariables.NUMBER, + String.valueOf(materialCount.getValue()), "[material]", + Utils.prettifyObject(materialCount.getKey(), this.user))); + } + + 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 + ? this.user.getTranslationOrNothing(reference + "value", TextVariables.NUMBER, + String.valueOf(blockValue)) + : ""; + + int blockLimit = this.addon.getBlockConfig().getBlockLimits().getOrDefault(materialCount.getKey(), 0); + String 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())); + + long calculatedValue = (long) Math.min(blockLimit > 0 ? blockLimit : Integer.MAX_VALUE, + materialCount.getValue()) * blockValue; + String valueText = calculatedValue > 0 ? this.user.getTranslationOrNothing(reference + "calculated", + TextVariables.NUMBER, String.valueOf(calculatedValue)) : ""; + + if (template.description() != null) { + builder.description(this.user + .getTranslation(this.world, template.description(), "[description]", description, "[id]", blockId, + "[value]", value, "[calculated]", valueText, "[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; - - /** - * This variable stores active filter for items. - */ - private Filter activeFilter; + 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> 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; } diff --git a/src/main/resources/blockconfig.yml b/src/main/resources/blockconfig.yml index 3af622c..e9fe8ba 100644 --- a/src/main/resources/blockconfig.yml +++ b/src/main/resources/blockconfig.yml @@ -10,6 +10,10 @@ limits: COBBLESTONE: 10000 NETHERRACK: 1000 +# These blocks will never be shown in the GUI even if they have value +hidden-blocks: + - BEDROCK + - AIR blocks: ACACIA_BUTTON: 1 ACACIA_DOOR: 2