diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesPanel.java b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesPanel.java index 6df3930..a1534d9 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesPanel.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntitiesPanel.java @@ -5,15 +5,16 @@ import java.util.List; import java.util.Map; import org.bukkit.Material; +import org.bukkit.Tag; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; -import lv.id.bonne.panelutils.PanelUtils; 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.challenges.panel.CommonPanel; import world.bentobox.challenges.panel.util.MultiEntitySelector; +import world.bentobox.challenges.panel.util.SingleEntitySelector; import world.bentobox.challenges.utils.Constants; import world.bentobox.challenges.utils.Utils; @@ -32,17 +33,12 @@ import world.bentobox.challenges.utils.Utils; public class ManageEntitiesPanel extends AbstractManageEnumPanel { /** - * Flag to indicate whether entities should be displayed as eggs (true) or mob heads (false). - */ - private boolean asEggs = true; - - /** - * Private constructor that initializes the ManageEntitiesPanel with the provided - * entities map. - * - * @param parentGUI The parent panel that spawns this panel. - * @param requiredEntities A map of EntityType objects to their required counts. - */ + * Private constructor that initializes the ManageEntitiesPanel with the provided + * entities map. + * + * @param parentGUI The parent panel that spawns this panel. + * @param requiredEntities A map of EntityType objects to their required counts. + */ private ManageEntitiesPanel(CommonPanel parentGUI, Map requiredEntities) { super(parentGUI, requiredEntities); } @@ -69,7 +65,12 @@ public class ManageEntitiesPanel extends AbstractManageEnumPanel { */ @Override protected ItemStack getElementIcon(EntityType entity, int count) { - return asEggs ? PanelUtils.getEntityEgg(entity, count) : PanelUtils.getEntityHead(entity, count); + if (Tag.ENTITY_TYPES_CAN_TURN_IN_BOATS.isTagged(entity) && count > 1) { + return new ItemStack(Material.OAK_PLANKS, count); // Boats cannot be stacked + } + ItemStack icon = SingleEntitySelector.getIcon(entity); + icon.setAmount(count); + return icon; } /** @@ -113,8 +114,6 @@ public class ManageEntitiesPanel extends AbstractManageEnumPanel { panelBuilder.item(3, createButton(Button.ADD_ENTITY)); // Position 5: Button for removing selected entities. panelBuilder.item(5, createButton(Button.REMOVE_ENTITY)); - // Position 8: Button to switch between displaying entity eggs and mob heads. - panelBuilder.item(8, createButton(Button.SWITCH_ENTITY)); } /** @@ -138,7 +137,7 @@ public class ManageEntitiesPanel extends AbstractManageEnumPanel { icon = new ItemStack(Material.BUCKET); clickHandler = (panel, user, clickType, slot) -> { // Open a multi-selection tool to add new entities. - MultiEntitySelector.open(this.user, this.asEggs, MultiEntitySelector.Mode.ALIVE, this.itemsMap.keySet(), + MultiEntitySelector.open(this.user, MultiEntitySelector.Mode.ALIVE, this.itemsMap.keySet(), (status, entities) -> { if (status) { // For each selected entity, add it to the map with a default count. @@ -179,19 +178,6 @@ public class ManageEntitiesPanel extends AbstractManageEnumPanel { description.add(""); description.add(this.user.getTranslation(Constants.TIPS + "click-to-remove")); } - case SWITCH_ENTITY -> { - // Button to toggle the display mode between entity eggs and mob heads. - icon = new ItemStack(asEggs ? Material.EGG : Material.PLAYER_HEAD); - clickHandler = (panel, user, clickType, slot) -> { - // Toggle the display mode flag and rebuild the panel. - this.asEggs = !this.asEggs; - this.build(); - return true; - }; - glow = false; - description.add(""); - description.add(this.user.getTranslation(Constants.TIPS + "click-to-toggle")); - } default -> { icon = new ItemStack(Material.PAPER); clickHandler = null; diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ManageEntityGroupsPanel.java b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntityGroupsPanel.java index 5bac964..a8c8cf0 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/ManageEntityGroupsPanel.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/ManageEntityGroupsPanel.java @@ -26,6 +26,7 @@ import world.bentobox.challenges.panel.CommonPagedPanel; import world.bentobox.challenges.panel.CommonPanel; import world.bentobox.challenges.panel.ConversationUtils; import world.bentobox.challenges.panel.util.MultiEntityTypeTagsSelector; +import world.bentobox.challenges.panel.util.SingleEntitySelector; import world.bentobox.challenges.panel.util.UnifiedMultiSelector.Mode; import world.bentobox.challenges.utils.Constants; import world.bentobox.challenges.utils.Utils; @@ -316,18 +317,12 @@ public class ManageEntityGroupsPanel extends CommonPagedPanel> if (entityTag.getKey().getKey().contains("boat")) { return new ItemStack(Material.OAK_PLANKS, quantity); // Boats cannot be stacked } - EntityType entType = Registry.ENTITY_TYPE.stream().filter(entityTag::isTagged).findAny().orElse(null); + EntityType entType = Registry.ENTITY_TYPE.stream() + .filter(entityTag::isTagged).findAny().orElse(null); if (entType == null) { return new ItemStack(Material.PAPER, quantity); } - String eggName = entType.getKey().getKey().toUpperCase(Locale.ENGLISH) + "_SPAWN_EGG"; - Material result; - try { - result = Material.valueOf(eggName); - } catch (Exception e) { - result = Material.PAPER; - } - return new ItemStack(result, quantity); + return SingleEntitySelector.getIcon(entType); } diff --git a/src/main/java/world/bentobox/challenges/panel/admin/ManageStatisticsPanel.java b/src/main/java/world/bentobox/challenges/panel/admin/ManageStatisticsPanel.java index 199dbce..2a8f68a 100644 --- a/src/main/java/world/bentobox/challenges/panel/admin/ManageStatisticsPanel.java +++ b/src/main/java/world/bentobox/challenges/panel/admin/ManageStatisticsPanel.java @@ -14,10 +14,8 @@ import java.util.stream.Collectors; import org.bukkit.Material; import org.bukkit.Statistic; import org.bukkit.inventory.ItemStack; -import org.eclipse.jdt.annotation.Nullable; import lv.id.bonne.panelutils.PanelUtils; -import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.api.panels.Panel; import world.bentobox.bentobox.api.panels.PanelItem; import world.bentobox.bentobox.api.panels.builders.PanelBuilder; @@ -584,7 +582,7 @@ public class ManageStatisticsPanel extends CommonPagedPanel icon = req.entity() == null ? new ItemStack(Material.BARRIER) : new ItemStack(PanelUtils.getEntityEgg(req.entity())); clickHandler = (panel, user, clickType, slot) -> { - SingleEntitySelector.open(this.user, true, (status, entity) -> { + SingleEntitySelector.open(this.user, (status, entity) -> { if (status) { // Replace the old with the new statisticsList.removeIf(sr -> sr.equals(req)); diff --git a/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java b/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java index c5211ab..7df90a5 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/MultiEntitySelector.java @@ -11,7 +11,6 @@ import java.util.stream.Collectors; import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; -import lv.id.bonne.panelutils.PanelUtils; import world.bentobox.bentobox.api.user.User; import world.bentobox.challenges.utils.Utils; @@ -22,22 +21,19 @@ import world.bentobox.challenges.utils.Utils; */ public class MultiEntitySelector extends UnifiedMultiSelector { - private final boolean asEgg; private final Set excluded; /** * Private constructor. * * @param user the user opening the selector - * @param asEgg if true, display entities using their spawn egg icon; otherwise, use the entity head * @param mode determines whether to show only living entities (ALIVE) or all (ANY) * @param excluded a set of EntityType values to exclude * @param consumer the callback to be invoked when the user confirms or cancels */ - private MultiEntitySelector(User user, boolean asEgg, Mode mode, Set excluded, + private MultiEntitySelector(User user, Mode mode, Set excluded, java.util.function.BiConsumer> consumer) { super(user, mode, consumer); - this.asEgg = asEgg; this.excluded = excluded; } @@ -45,26 +41,24 @@ public class MultiEntitySelector extends UnifiedMultiSelector { * Opens the MultiEntitySelector GUI with the specified parameters. * * @param user the user who opens the GUI - * @param asEgg if true, show the entity spawn egg icon; otherwise, show the entity head * @param mode the filtering mode (ALIVE or ANY) * @param excluded a set of EntityType values to exclude from the list * @param consumer a callback to receive the result */ - public static void open(User user, boolean asEgg, Mode mode, Set excluded, + public static void open(User user, Mode mode, Set excluded, java.util.function.BiConsumer> consumer) { - new MultiEntitySelector(user, asEgg, mode, excluded, consumer).build(); + new MultiEntitySelector(user, mode, excluded, consumer).build(); } /** * Opens the MultiEntitySelector GUI with default parameters (mode ANY and no exclusions). * * @param user the user who opens the GUI - * @param asEgg if true, show the entity spawn egg icon; otherwise, show the entity head * @param consumer a callback to receive the result */ - public static void open(User user, boolean asEgg, + public static void open(User user, java.util.function.BiConsumer> consumer) { - new MultiEntitySelector(user, asEgg, Mode.ANY, new HashSet<>(), consumer).build(); + new MultiEntitySelector(user, Mode.ANY, new HashSet<>(), consumer).build(); } /** @@ -73,7 +67,7 @@ public class MultiEntitySelector extends UnifiedMultiSelector { @Override protected List getElements() { return Arrays.stream(EntityType.values()).filter(entity -> excluded == null || !excluded.contains(entity)) - .filter(entity -> mode == Mode.ALIVE ? entity.isAlive() : true) + .filter(entity -> !SingleEntitySelector.NON_ENTITIES.contains(entity)) .sorted(Comparator.comparing(EntityType::name)).collect(Collectors.toList()); } @@ -99,7 +93,7 @@ public class MultiEntitySelector extends UnifiedMultiSelector { */ @Override protected ItemStack getIcon(EntityType element) { - return asEgg ? PanelUtils.getEntityEgg(element) : PanelUtils.getEntityHead(element); + return SingleEntitySelector.getIcon(element); } /** diff --git a/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java b/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java index f22080f..aa2355a 100644 --- a/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java +++ b/src/main/java/world/bentobox/challenges/panel/util/SingleEntitySelector.java @@ -6,6 +6,7 @@ import java.util.Arrays; import java.util.Comparator; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; @@ -28,216 +29,231 @@ import world.bentobox.challenges.utils.Utils; */ public class SingleEntitySelector extends PagedSelector { - /** - * Instantiates a new Single entity selector. - * - * @param user the user - * @param asEggs the boolean - * @param mode the mode - * @param excluded the excluded - * @param consumer the consumer - */ - private SingleEntitySelector(User user, boolean asEggs, Mode mode, Set excluded, BiConsumer consumer) - { - super(user); - this.consumer = consumer; - this.asEggs = asEggs; - this.elements = Arrays.stream(EntityType.values()). - filter(entity -> !excluded.contains(entity)). - filter(entity -> { - if (mode == Mode.ALIVE) - { - return entity.isAlive(); - } - else - { - return true; - } - }). - // Sort by names - sorted(Comparator.comparing(EntityType::name)). - collect(Collectors.toList()); - // Init without filters applied. - this.filterElements = this.elements; - } + + /** + * Non entities that really cannot be used + */ + public static final List NON_ENTITIES = List.of(EntityType.UNKNOWN, EntityType.BLOCK_DISPLAY, + EntityType.ITEM_DISPLAY, + EntityType.TEXT_DISPLAY, EntityType.FALLING_BLOCK, EntityType.FIREBALL, EntityType.FISHING_BOBBER, + EntityType.GIANT, EntityType.ILLUSIONER, EntityType.INTERACTION, EntityType.LIGHTNING_BOLT, + EntityType.LLAMA_SPIT, EntityType.MARKER, EntityType.SHULKER_BULLET, EntityType.SMALL_FIREBALL, + EntityType.DRAGON_FIREBALL, EntityType.EVOKER_FANGS, EntityType.BREEZE_WIND_CHARGE, + EntityType.AREA_EFFECT_CLOUD); + + /** + * Instantiates a new Single entity selector. + * + * @param user the user + * @param asEggs the boolean + * @param mode the mode + * @param excluded the excluded + * @param consumer the consumer + */ + private SingleEntitySelector(User user, Mode mode, Set excluded, + BiConsumer consumer) + { + super(user); + this.consumer = consumer; + this.elements = Arrays.stream(EntityType.values()).filter(entity -> !excluded.contains(entity)) + .filter(entity -> !NON_ENTITIES.contains(entity)) + .filter(entity -> { + if (mode == Mode.ALIVE) { + return entity.isAlive(); + } else { + return true; + } + }). + // Sort by names + sorted(Comparator.comparing(EntityType::name)).collect(Collectors.toList()); + // Init without filters applied. + this.filterElements = this.elements; + } - /** - * This method opens GUI that allows to select challenge type. - * - * @param user User who opens GUI. - * @param consumer Consumer that allows to get clicked type. - */ - public static void open(User user, boolean asEggs, Mode mode, Set excluded, BiConsumer consumer) - { - new SingleEntitySelector(user, asEggs, mode, excluded, consumer).build(); - } + /** + * This method opens GUI that allows to select challenge type. + * + * @param user User who opens GUI. + * @param consumer Consumer that allows to get clicked type. + */ + public static void open(User user, Mode mode, Set excluded, BiConsumer consumer) + { + new SingleEntitySelector(user, mode, excluded, consumer).build(); + } - /** - * This method opens GUI that allows to select challenge type. - * - * @param user User who opens GUI. - * @param consumer Consumer that allows to get clicked type. - */ - public static void open(User user, boolean asEggs, BiConsumer consumer) - { - new SingleEntitySelector(user, asEggs, Mode.ANY, new HashSet<>(), consumer).build(); - } + /** + * This method opens GUI that allows to select challenge type. + * + * @param user User who opens GUI. + * @param consumer Consumer that allows to get clicked type. + */ + public static void open(User user, BiConsumer consumer) + { + new SingleEntitySelector(user, Mode.ANY, new HashSet<>(), consumer).build(); + } - /** - * This method opens GUI that allows to select challenge type. - * - * @param user User who opens GUI. - * @param consumer Consumer that allows to get clicked type. - */ - public static void open(User user, boolean asEggs, Mode mode, BiConsumer consumer) - { - new SingleEntitySelector(user, asEggs, mode, new HashSet<>(), consumer).build(); - } + /** + * This method opens GUI that allows to select challenge type. + * + * @param user User who opens GUI. + * @param consumer Consumer that allows to get clicked type. + */ + public static void open(User user, Mode mode, BiConsumer consumer) + { + new SingleEntitySelector(user, mode, new HashSet<>(), consumer).build(); + } -// --------------------------------------------------------------------- -// Section: Methods -// --------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Section: Methods + // --------------------------------------------------------------------- - /** - * This method builds - */ - @Override - protected void build() - { - PanelBuilder panelBuilder = new PanelBuilder().user(this.user); - panelBuilder.name(this.user.getTranslation(Constants.TITLE + "entity-selector")); + /** + * This method builds + */ + @Override + protected void build() { + PanelBuilder panelBuilder = new PanelBuilder().user(this.user); + panelBuilder.name(this.user.getTranslation(Constants.TITLE + "entity-selector")); - PanelUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); + PanelUtils.fillBorder(panelBuilder, Material.BLUE_STAINED_GLASS_PANE); - this.populateElements(panelBuilder, this.filterElements); + this.populateElements(panelBuilder, this.filterElements); - panelBuilder.item(4, this.createButton()); + panelBuilder.item(4, this.createButton()); - panelBuilder.build(); - } + panelBuilder.build(); + } - /** - * This method is called when filter value is updated. - */ - @Override - protected void updateFilters() - { - if (this.searchString == null || this.searchString.isBlank()) - { - this.filterElements = this.elements; - } - else - { - this.filterElements = this.elements.stream(). - filter(element -> { - // If element name is set and name contains search field, then do not filter out. - return element.name().toLowerCase().contains(this.searchString.toLowerCase()); - }). - distinct(). - collect(Collectors.toList()); - } - } + /** + * This method is called when filter value is updated. + */ + @Override + protected void updateFilters() { + if (this.searchString == null || this.searchString.isBlank()) { + this.filterElements = this.elements; + } else { + this.filterElements = this.elements.stream().filter(element -> { + // If element name is set and name contains search field, then do not filter out. + return element.name().toLowerCase().contains(this.searchString.toLowerCase()); + }).distinct().collect(Collectors.toList()); + } + } - /** - * This method builds PanelItem for given entity. - * @param entity Entity which PanelItem must be created. - * @return new PanelItem for given Entity. - */ - @Override - protected PanelItem createElementButton(EntityType entity) - { - final String reference = Constants.BUTTON + "entity."; + /** + * This method builds PanelItem for given entity. + * @param entity Entity which PanelItem must be created. + * @return new PanelItem for given Entity. + */ + @Override + protected PanelItem createElementButton(EntityType entity) { + final String reference = Constants.BUTTON + "entity."; - List description = new ArrayList<>(); - description.add(this.user.getTranslation(reference + "description", - "[id]", entity.name())); - description.add(""); - description.add(this.user.getTranslation(Constants.TIPS + "click-to-choose")); - - return new PanelItemBuilder(). - name(this.user.getTranslation(reference + "name", "[entity]", - Utils.prettifyObject(entity, this.user))). - icon(this.asEggs ? PanelUtils.getEntityEgg(entity) : PanelUtils.getEntityHead(entity)). - description(description). - clickHandler((panel, user1, clickType, slot) -> { - this.consumer.accept(true, entity); - return true; - }). - build(); - } + List description = new ArrayList<>(); + description.add(this.user.getTranslation(reference + "description", "[id]", entity.name())); + description.add(""); + description.add(this.user.getTranslation(Constants.TIPS + "click-to-choose")); - /** - * This method creates PanelItem button of requested type. - * @return new PanelItem with requested functionality. - */ - private PanelItem createButton() - { - final String reference = Constants.BUTTON + "cancel."; + return new PanelItemBuilder() + .name(this.user.getTranslation(reference + "name", "[entity]", Utils.prettifyObject(entity, this.user))) + .icon(getIcon(entity)).description(description) + .clickHandler((panel, user1, clickType, slot) -> { + this.consumer.accept(true, entity); + return true; + }).build(); + } - final String name = this.user.getTranslation(reference + "name"); - final List description = new ArrayList<>(3); - description.add(this.user.getTranslation(reference + "description")); + /** + * Get an ItemStack icon for any entity type, or PAPER if it's not really known + * @param et entity type + * @return ItemStack + */ + public static ItemStack getIcon(EntityType et) { + // Check for Materials like boats that are named the same as their entitytype. + Material m = Material.getMaterial(et.getKey().getKey().toUpperCase(Locale.ENGLISH)); + if (m != null) { + return new ItemStack(m); + } + // Try to get the spawn egg for the given entity by using the naming convention. + String spawnEggName = et.name() + "_SPAWN_EGG"; + try { + Material spawnEgg = Material.valueOf(spawnEggName); + // If found, return an ItemStack of the spawn egg. + return new ItemStack(spawnEgg); + } catch (IllegalArgumentException ex) { + // No spawn egg material exists for this entity type. + } + // Fallback + return switch (et) { + case EYE_OF_ENDER -> new ItemStack(Material.ENDER_EYE); + case LEASH_KNOT -> new ItemStack(Material.LEAD); + case OMINOUS_ITEM_SPAWNER -> new ItemStack(Material.TRIAL_SPAWNER); + case PLAYER -> new ItemStack(Material.PLAYER_HEAD); + case SPAWNER_MINECART -> new ItemStack(Material.MINECART); + case TRADER_LLAMA -> new ItemStack(Material.LLAMA_SPAWN_EGG); + case WITHER_SKULL -> new ItemStack(Material.WITHER_SKELETON_SKULL); + default -> new ItemStack(Material.PAPER); - ItemStack icon = new ItemStack(Material.IRON_DOOR); - PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> - { - this.consumer.accept(false, null); - return true; - }; + }; + } - description.add(""); - description.add(this.user.getTranslation(Constants.TIPS + "click-to-cancel")); + /** + * This method creates PanelItem button of requested type. + * @return new PanelItem with requested functionality. + */ + private PanelItem createButton() { + final String reference = Constants.BUTTON + "cancel."; - return new PanelItemBuilder(). - icon(icon). - name(name). - description(description). - clickHandler(clickHandler). - build(); - } + final String name = this.user.getTranslation(reference + "name"); + final List description = new ArrayList<>(3); + description.add(this.user.getTranslation(reference + "description")); + + ItemStack icon = new ItemStack(Material.IRON_DOOR); + PanelItem.ClickHandler clickHandler = (panel, user1, clickType, slot) -> { + this.consumer.accept(false, null); + return true; + }; + + description.add(""); + description.add(this.user.getTranslation(Constants.TIPS + "click-to-cancel")); + + return new PanelItemBuilder().icon(icon).name(name).description(description).clickHandler(clickHandler).build(); + } -// --------------------------------------------------------------------- -// Section: Mode -// --------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Section: Mode + // --------------------------------------------------------------------- - public enum Mode - { - ALIVE, - ANY - } + public enum Mode { + ALIVE, ANY + } -// --------------------------------------------------------------------- -// Section: Variables -// --------------------------------------------------------------------- + // --------------------------------------------------------------------- + // Section: Variables + // --------------------------------------------------------------------- - /** - * List with elements that will be displayed in current GUI. - */ - private final List elements; + /** + * List with elements that will be displayed in current GUI. + */ + private final List elements; - /** - * Indicates if entities are displayed as eggs or heads. - */ - private final boolean asEggs; + /** + * This variable stores consumer. + */ + private final BiConsumer consumer; - /** - * This variable stores consumer. - */ - private final BiConsumer consumer; - - /** - * Stores filtered items. - */ - private List filterElements; + /** + * Stores filtered items. + */ + private List filterElements; }