diff --git a/src/main/java/world/bentobox/limits/commands/LimitPanel.java b/src/main/java/world/bentobox/limits/commands/LimitPanel.java index 5a41764..aaf3ce3 100644 --- a/src/main/java/world/bentobox/limits/commands/LimitPanel.java +++ b/src/main/java/world/bentobox/limits/commands/LimitPanel.java @@ -1,29 +1,15 @@ package world.bentobox.limits.commands; -import java.util.HashMap; import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; import java.util.UUID; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.entity.EntityType; -import com.google.common.collect.ImmutableMap; -import java.util.ArrayList; -import java.util.List; - -import world.bentobox.bentobox.api.localization.TextVariables; -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.objects.Island; -import world.bentobox.bentobox.util.Util; import world.bentobox.limits.Limits; -import world.bentobox.limits.Settings; -import world.bentobox.limits.Settings.EntityGroup; import world.bentobox.limits.objects.IslandBlockCount; /** @@ -34,39 +20,6 @@ import world.bentobox.limits.objects.IslandBlockCount; public class LimitPanel { private final Limits addon; - // This maps the entity types to the icon that should be shown in the panel - // If the icon is null, then the entity type is not covered by the addon - private static final Map E2M = ImmutableMap.builder() - .put(EntityType.MUSHROOM_COW, Material.MOOSHROOM_SPAWN_EGG) - .put(EntityType.SNOWMAN, Material.SNOW_BLOCK) - .put(EntityType.IRON_GOLEM, Material.IRON_BLOCK) - .put(EntityType.ILLUSIONER, Material.VILLAGER_SPAWN_EGG) - .put(EntityType.WITHER, Material.WITHER_SKELETON_SKULL) - .put(EntityType.BOAT, Material.OAK_BOAT) - .put(EntityType.ARMOR_STAND, Material.ARMOR_STAND) - .put(EntityType.ITEM_FRAME, Material.ITEM_FRAME) - .put(EntityType.PAINTING, Material.PAINTING) - // Minecarts - .put(EntityType.MINECART_TNT, Material.TNT_MINECART) - .put(EntityType.MINECART_CHEST, Material.CHEST_MINECART) - .put(EntityType.MINECART_COMMAND, Material.COMMAND_BLOCK_MINECART) - .put(EntityType.MINECART_FURNACE, Material.FURNACE_MINECART) - .put(EntityType.MINECART_HOPPER, Material.HOPPER_MINECART) - .put(EntityType.MINECART_MOB_SPAWNER, Material.MINECART) - .build(); - // This is a map of blocks to Material - private static final Map B2M; - static { - ImmutableMap.Builder builder = ImmutableMap.builder() - .put(Material.POTATOES, Material.POTATO) - .put(Material.CARROTS, Material.CARROT) - .put(Material.BEETROOTS, Material.BEETROOT) - .put(Material.REDSTONE_WIRE, Material.REDSTONE); - // Block to Material icons - Optional.ofNullable(Material.getMaterial("SWEET_BERRY_BUSH")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("SWEET_BERRIES")))); - Optional.ofNullable(Material.getMaterial("BAMBOO_SAPLING")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("BAMBOO")))); - B2M = builder.build(); - } /** * @param addon - limit addon @@ -76,7 +29,6 @@ public class LimitPanel { } public void showLimits(World world, User user, UUID target) { - PanelBuilder pb = new PanelBuilder().name(user.getTranslation(world, "limits.panel-title")).user(user); // Get the island for the target Island island = addon.getIslands().getIsland(world, target); if (island == null) { @@ -87,142 +39,23 @@ public class LimitPanel { } return; } + // Get the limits for this island IslandBlockCount ibc = addon.getBlockLimitListener().getIsland(island.getUniqueId()); Map matLimits = addon.getBlockLimitListener().getMaterialLimits(world, island.getUniqueId()); if (matLimits.isEmpty() && addon.getSettings().getLimits().isEmpty()) { user.sendMessage("island.limits.no-limits"); return; } - // Material limits - for (Entry en : matLimits.entrySet()) { - PanelItemBuilder pib = new PanelItemBuilder(); - pib.name(Util.prettifyText(en.getKey().toString())); - // Adjust icon - pib.icon(B2M.getOrDefault(en.getKey(), en.getKey())); - int count = ibc == null ? 0 : ibc.getBlockCount().getOrDefault(en.getKey(), 0); - String color = count >= en.getValue() ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); - pib.description(color - + user.getTranslation("island.limits.block-limit-syntax", - TextVariables.NUMBER, String.valueOf(count), - "[limit]", String.valueOf(en.getValue()))); - pb.item(pib.build()); - } - // Entity limits - Map map = new HashMap<>(addon.getSettings().getLimits()); - // Merge in any permission-based limits - if (ibc != null) ibc.getEntityLimits().forEach(map::put); - map.forEach((k,v) -> { - PanelItemBuilder pib = new PanelItemBuilder(); - pib.name(Util.prettifyText(k.toString())); - Material m; - try { - if (E2M.containsKey(k)) { - m = E2M.get(k); - } else if (k.isAlive()) { - m = Material.valueOf(k.toString() + "_SPAWN_EGG"); - } else { - // Regular material - m = Material.valueOf(k.toString()); - } - } catch (Exception e) { - m = Material.BARRIER; - } - pib.icon(m); - long count = getCount(island, k); - String color = count >= v ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); - pib.description(color - + user.getTranslation("island.limits.block-limit-syntax", - TextVariables.NUMBER, String.valueOf(count), - "[limit]", String.valueOf(v))); - pb.item(pib.build()); - }); - - // Entity group limits - List groupmap = addon.getSettings().getGroupLimitDefinitions(); - // Merge in any permission-based limits -// if (ibc != null) ibc.getEntityLimits().forEach(map::put); - groupmap.forEach(v -> { - PanelItemBuilder pib = new PanelItemBuilder(); - EntityType k = v.getTypes().iterator().next(); - pib.name(v.getName()); - String description = ""; - description += "(" + prettyNames(v) + ")\n"; - Material m; - try { - if (E2M.containsKey(k)) { - m = E2M.get(k); - } else if (k.isAlive()) { - m = Material.valueOf(k.toString() + "_SPAWN_EGG"); - } else { - // Regular material - m = Material.valueOf(k.toString()); - } - } catch (Exception e) { - m = Material.BARRIER; - } - pib.icon(m); - long count = getCount(island, v); - String color = count >= v.getLimit() ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); - description += color - + user.getTranslation("island.limits.block-limit-syntax", - TextVariables.NUMBER, String.valueOf(count), - "[limit]", String.valueOf(v.getLimit())); - pib.description(description); - pb.item(pib.build()); - }); - pb.build(); + new TabbedPanelBuilder() + .user(user) + .world(world) + .tab(0, new LimitTab(addon, ibc, matLimits, island, world, user, LimitTab.SORT_BY.A2Z)) + .tab(1, new LimitTab(addon, ibc, matLimits, island, world, user, LimitTab.SORT_BY.Z2A)) + .startingSlot(0) + .size(54) + .build().openPanel(); + } - long getCount(Island island, EntityType ent) { - long count = island.getWorld().getEntities().stream() - .filter(e -> e.getType().equals(ent)) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - // Nether - if (addon.getPlugin().getIWM().isNetherIslands(island.getWorld()) && addon.getPlugin().getIWM().getNetherWorld(island.getWorld()) != null) { - count += addon.getPlugin().getIWM().getNetherWorld(island.getWorld()).getEntities().stream() - .filter(e -> e.getType().equals(ent)) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - } - // End - if (addon.getPlugin().getIWM().isEndIslands(island.getWorld()) && addon.getPlugin().getIWM().getEndWorld(island.getWorld()) != null) { - count += addon.getPlugin().getIWM().getEndWorld(island.getWorld()).getEntities().stream() - .filter(e -> e.getType().equals(ent)) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - } - return count; - } - - long getCount(Island island, EntityGroup group) { - long count = island.getWorld().getEntities().stream() - .filter(e -> group.contains(e.getType())) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - // Nether - if (addon.getPlugin().getIWM().isNetherIslands(island.getWorld()) && addon.getPlugin().getIWM().getNetherWorld(island.getWorld()) != null) { - count += addon.getPlugin().getIWM().getNetherWorld(island.getWorld()).getEntities().stream() - .filter(e -> group.contains(e.getType())) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - } - // End - if (addon.getPlugin().getIWM().isEndIslands(island.getWorld()) && addon.getPlugin().getIWM().getEndWorld(island.getWorld()) != null) { - count += addon.getPlugin().getIWM().getEndWorld(island.getWorld()).getEntities().stream() - .filter(e -> group.contains(e.getType())) - .filter(e -> island.inIslandSpace(e.getLocation())).count(); - } - return count; - } - - private String prettyNames(EntityGroup v) { - StringBuilder sb = new StringBuilder(); - List l = new ArrayList<>(v.getTypes()); - for(int i = 0; i < l.size(); i++) - { - sb.append(Util.prettifyText(l.get(i).toString())); - if (i + 1 < l.size()) - sb.append(", "); - if((i+1) % 5 == 0) - sb.append("\n"); - } - return sb.toString(); - } } diff --git a/src/main/java/world/bentobox/limits/commands/LimitTab.java b/src/main/java/world/bentobox/limits/commands/LimitTab.java new file mode 100644 index 0000000..634ac1c --- /dev/null +++ b/src/main/java/world/bentobox/limits/commands/LimitTab.java @@ -0,0 +1,260 @@ +package world.bentobox.limits.commands; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; + +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.entity.EntityType; +import org.eclipse.jdt.annotation.Nullable; + +import com.google.common.collect.ImmutableMap; + +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.panels.PanelItem; +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.limits.Limits; +import world.bentobox.limits.Settings; +import world.bentobox.limits.Settings.EntityGroup; +import world.bentobox.limits.objects.IslandBlockCount; + +/** + * @author tastybento + * + */ +public class LimitTab implements Tab { + + enum SORT_BY { + A2Z, + Z2A + } + // This maps the entity types to the icon that should be shown in the panel + // If the icon is null, then the entity type is not covered by the addon + private static final Map E2M = ImmutableMap.builder() + .put(EntityType.MUSHROOM_COW, Material.MOOSHROOM_SPAWN_EGG) + .put(EntityType.SNOWMAN, Material.SNOW_BLOCK) + .put(EntityType.IRON_GOLEM, Material.IRON_BLOCK) + .put(EntityType.ILLUSIONER, Material.VILLAGER_SPAWN_EGG) + .put(EntityType.WITHER, Material.WITHER_SKELETON_SKULL) + .put(EntityType.BOAT, Material.OAK_BOAT) + .put(EntityType.ARMOR_STAND, Material.ARMOR_STAND) + .put(EntityType.ITEM_FRAME, Material.ITEM_FRAME) + .put(EntityType.PAINTING, Material.PAINTING) + // Minecarts + .put(EntityType.MINECART_TNT, Material.TNT_MINECART) + .put(EntityType.MINECART_CHEST, Material.CHEST_MINECART) + .put(EntityType.MINECART_COMMAND, Material.COMMAND_BLOCK_MINECART) + .put(EntityType.MINECART_FURNACE, Material.FURNACE_MINECART) + .put(EntityType.MINECART_HOPPER, Material.HOPPER_MINECART) + .put(EntityType.MINECART_MOB_SPAWNER, Material.MINECART) + .build(); + // This is a map of blocks to Material + private static final Map B2M; + static { + ImmutableMap.Builder builder = ImmutableMap.builder() + .put(Material.POTATOES, Material.POTATO) + .put(Material.CARROTS, Material.CARROT) + .put(Material.BEETROOTS, Material.BEETROOT) + .put(Material.REDSTONE_WIRE, Material.REDSTONE); + // Block to Material icons + Optional.ofNullable(Material.getMaterial("SWEET_BERRY_BUSH")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("SWEET_BERRIES")))); + Optional.ofNullable(Material.getMaterial("BAMBOO_SAPLING")).ifPresent(material -> builder.put(material, Objects.requireNonNull(Material.getMaterial("BAMBOO")))); + B2M = builder.build(); + } + + private final World world; + private final User user; + private final Limits addon; + private final List<@Nullable PanelItem> result; + private final SORT_BY sortBy; + + public LimitTab(Limits addon, IslandBlockCount ibc, Map matLimits, Island island, World world, User user, SORT_BY sortBy) { + this.addon = addon; + this.world = world; + this.user = user; + this.sortBy = sortBy; + result = new ArrayList<>(); + addMaterialIcons(ibc, matLimits); + addEntityLimits(ibc, island); + addEntityGroupLimits(island); + // Sort + switch (sortBy) { + default: + Collections.sort(result, (o1, o2) -> o1.getName().compareTo(o2.getName())); + break; + case Z2A: + Collections.sort(result, (o1, o2) -> o2.getName().compareTo(o1.getName())); + break; + } + + } + + private void addEntityGroupLimits(Island island) { + // Entity group limits + List groupmap = addon.getSettings().getGroupLimitDefinitions(); + // Merge in any permission-based limits + // if (ibc != null) ibc.getEntityLimits().forEach(map::put); + groupmap.forEach(v -> { + PanelItemBuilder pib = new PanelItemBuilder(); + EntityType k = v.getTypes().iterator().next(); + pib.name(v.getName()); + String description = ""; + description += "(" + prettyNames(v) + ")\n"; + Material m; + try { + if (E2M.containsKey(k)) { + m = E2M.get(k); + } else if (k.isAlive()) { + m = Material.valueOf(k.toString() + "_SPAWN_EGG"); + } else { + // Regular material + m = Material.valueOf(k.toString()); + } + } catch (Exception e) { + m = Material.BARRIER; + } + pib.icon(m); + long count = getCount(island, v); + String color = count >= v.getLimit() ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); + description += color + + user.getTranslation("island.limits.block-limit-syntax", + TextVariables.NUMBER, String.valueOf(count), + "[limit]", String.valueOf(v.getLimit())); + pib.description(description); + result.add(pib.build()); + }); + } + + private void addEntityLimits(IslandBlockCount ibc, Island island) { + // Entity limits + Map map = new HashMap<>(addon.getSettings().getLimits()); + // Merge in any permission-based limits + if (ibc != null) ibc.getEntityLimits().forEach(map::put); + map.forEach((k,v) -> { + PanelItemBuilder pib = new PanelItemBuilder(); + pib.name(Util.prettifyText(k.toString())); + Material m; + try { + if (E2M.containsKey(k)) { + m = E2M.get(k); + } else if (k.isAlive()) { + m = Material.valueOf(k.toString() + "_SPAWN_EGG"); + } else { + // Regular material + m = Material.valueOf(k.toString()); + } + } catch (Exception e) { + m = Material.BARRIER; + } + pib.icon(m); + long count = getCount(island, k); + String color = count >= v ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); + pib.description(color + + user.getTranslation("island.limits.block-limit-syntax", + TextVariables.NUMBER, String.valueOf(count), + "[limit]", String.valueOf(v))); + result.add(pib.build()); + }); + + } + + private void addMaterialIcons(IslandBlockCount ibc, Map matLimits) { + // Material limits + for (Entry en : matLimits.entrySet()) { + PanelItemBuilder pib = new PanelItemBuilder(); + pib.name(Util.prettifyText(en.getKey().toString())); + // Adjust icon + pib.icon(B2M.getOrDefault(en.getKey(), en.getKey())); + + int count = ibc == null ? 0 : ibc.getBlockCount().getOrDefault(en.getKey(), 0); + String color = count >= en.getValue() ? user.getTranslation("island.limits.max-color") : user.getTranslation("island.limits.regular-color"); + pib.description(color + + user.getTranslation("island.limits.block-limit-syntax", + TextVariables.NUMBER, String.valueOf(count), + "[limit]", String.valueOf(en.getValue()))); + result.add(pib.build()); + } + } + + @Override + public PanelItem getIcon() { + return new PanelItemBuilder().icon(Material.MAGENTA_GLAZED_TERRACOTTA).name(this.getName()).build(); + } + + @Override + public String getName() { + return user.getTranslation(world, "limits.panel-title") + " " + sortBy.name(); + } + + @Override + public List<@Nullable PanelItem> getPanelItems() { + return result; + } + + @Override + public String getPermission() { + return ""; + } + + private String prettyNames(EntityGroup v) { + StringBuilder sb = new StringBuilder(); + List l = new ArrayList<>(v.getTypes()); + for(int i = 0; i < l.size(); i++) + { + sb.append(Util.prettifyText(l.get(i).toString())); + if (i + 1 < l.size()) + sb.append(", "); + if((i+1) % 5 == 0) + sb.append("\n"); + } + return sb.toString(); + } + + long getCount(Island island, EntityType ent) { + long count = island.getWorld().getEntities().stream() + .filter(e -> e.getType().equals(ent)) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + // Nether + if (addon.getPlugin().getIWM().isNetherIslands(island.getWorld()) && addon.getPlugin().getIWM().getNetherWorld(island.getWorld()) != null) { + count += addon.getPlugin().getIWM().getNetherWorld(island.getWorld()).getEntities().stream() + .filter(e -> e.getType().equals(ent)) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + } + // End + if (addon.getPlugin().getIWM().isEndIslands(island.getWorld()) && addon.getPlugin().getIWM().getEndWorld(island.getWorld()) != null) { + count += addon.getPlugin().getIWM().getEndWorld(island.getWorld()).getEntities().stream() + .filter(e -> e.getType().equals(ent)) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + } + return count; + } + + long getCount(Island island, EntityGroup group) { + long count = island.getWorld().getEntities().stream() + .filter(e -> group.contains(e.getType())) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + // Nether + if (addon.getPlugin().getIWM().isNetherIslands(island.getWorld()) && addon.getPlugin().getIWM().getNetherWorld(island.getWorld()) != null) { + count += addon.getPlugin().getIWM().getNetherWorld(island.getWorld()).getEntities().stream() + .filter(e -> group.contains(e.getType())) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + } + // End + if (addon.getPlugin().getIWM().isEndIslands(island.getWorld()) && addon.getPlugin().getIWM().getEndWorld(island.getWorld()) != null) { + count += addon.getPlugin().getIWM().getEndWorld(island.getWorld()).getEntities().stream() + .filter(e -> group.contains(e.getType())) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + } + return count; + } +} diff --git a/src/test/java/world/bentobox/limits/commands/LimitPanelTest.java b/src/test/java/world/bentobox/limits/commands/LimitTabTest.java similarity index 86% rename from src/test/java/world/bentobox/limits/commands/LimitPanelTest.java rename to src/test/java/world/bentobox/limits/commands/LimitTabTest.java index 9fced6d..05023f4 100644 --- a/src/test/java/world/bentobox/limits/commands/LimitPanelTest.java +++ b/src/test/java/world/bentobox/limits/commands/LimitTabTest.java @@ -27,15 +27,17 @@ import world.bentobox.bentobox.BentoBox; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandWorldManager; import world.bentobox.limits.Limits; +import world.bentobox.limits.Settings; +import world.bentobox.limits.objects.IslandBlockCount; @RunWith(PowerMockRunner.class) @PrepareForTest( Bukkit.class ) -public class LimitPanelTest { +public class LimitTabTest { @Mock private Limits addon; - - private LimitPanel lp; + + private LimitTab lp; @Mock private Island island; @@ -47,8 +49,10 @@ public class LimitPanelTest { private World end; @Mock private BentoBox plugin; -@Mock + @Mock private IslandWorldManager iwm; + @Mock + private Settings settings; @Before public void setUp() throws Exception { @@ -56,19 +60,21 @@ public class LimitPanelTest { when(island.getWorld()).thenReturn(world); // Addon when(addon.getPlugin()).thenReturn(plugin); + when(addon.getSettings()).thenReturn(settings); + when(settings.getLimits()).thenReturn(Collections.emptyMap()); when(plugin.getIWM()).thenReturn(iwm); when(iwm.isNetherIslands(any())).thenReturn(true); when(iwm.isEndIslands(any())).thenReturn(true); when(iwm.getNetherWorld(eq(world))).thenReturn(nether); when(iwm.getEndWorld(eq(world))).thenReturn(end); - // Worlds + // Worlds Entity entity = mock(Entity.class); when(entity.getType()).thenReturn(EntityType.BAT); when(entity.getLocation()).thenReturn(mock(Location.class)); when(world.getEntities()).thenReturn(Collections.singletonList(entity)); when(nether.getEntities()).thenReturn(Collections.singletonList(entity)); when(end.getEntities()).thenReturn(Collections.singletonList(entity)); - lp = new LimitPanel(addon); + lp = new LimitTab(addon, new IslandBlockCount(), Collections.emptyMap(), island, world, null, LimitTab.SORT_BY.A2Z); } @After @@ -95,7 +101,7 @@ public class LimitPanelTest { ent = EntityType.BAT; assertEquals(1L, lp.getCount(island, ent)); } - + @Test public void testGetCountNotInIslandSpace() { EntityType ent = EntityType.BAT;