diff --git a/src/main/java/world/bentobox/limits/Settings.java b/src/main/java/world/bentobox/limits/Settings.java index 7a7a98b..a93c99b 100644 --- a/src/main/java/world/bentobox/limits/Settings.java +++ b/src/main/java/world/bentobox/limits/Settings.java @@ -1,10 +1,16 @@ package world.bentobox.limits; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.EnumMap; +import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.entity.EntityType; @@ -12,6 +18,7 @@ import org.bukkit.entity.EntityType; public class Settings { private final Map limits = new EnumMap<>(EntityType.class); + private final Map> groupLimits = new EnumMap<>(EntityType.class); private final List gameModes; private static final List DISALLOWED = Arrays.asList( EntityType.PRIMED_TNT, @@ -61,6 +68,38 @@ public class Settings { } addon.log("Entity limits:"); limits.entrySet().stream().map(e -> "Limit " + e.getKey().toString() + " to " + e.getValue()).forEach(addon::log); + + //group limits + el = addon.getConfig().getConfigurationSection("entitygrouplimits"); + if (el != null) { + for (String name : el.getKeys(false)) { + int limit = el.getInt(name + ".limit"); + Set entities = el.getStringList(name + ".entities").stream().map(s -> { + EntityType type = getType(s); + if (type != null) { + if (DISALLOWED.contains(type)) { + addon.logError("Entity type: " + s + " is not supported - skipping..."); + } else { + return type; + } + } else { + addon.logError("Unknown entity type: " + s + " - skipping..."); + } + return null; + }).filter(e -> e != null).collect(Collectors.toCollection(LinkedHashSet::new)); + if (entities.isEmpty()) + continue; + EntityGroup group = new EntityGroup(name, entities, limit); + entities.forEach(e -> { + List groups = groupLimits.getOrDefault(e, new ArrayList()); + groups.add(group); + groupLimits.put(e, groups); + }); + } + } + + addon.log("Entity group limits:"); + getGroupLimitDefinitions().stream().map(e -> "Limit " + e.getName() + " (" + e.getTypes().stream().map(x -> x.name()).collect(Collectors.joining(", ")) + ") to " + e.getLimit()).forEach(addon::log); } private EntityType getType(String key) { @@ -74,6 +113,20 @@ public class Settings { return Collections.unmodifiableMap(limits); } + /** + * @return the group limits + */ + public Map> getGroupLimits() { + return groupLimits; + } + + /** + * @return the group limit definitions + */ + public List getGroupLimitDefinitions() { + return groupLimits.values().stream().flatMap(e -> e.stream()).distinct().collect(Collectors.toList()); + } + /** * @return the gameModes */ @@ -81,4 +134,60 @@ public class Settings { return gameModes; } + public static class EntityGroup { + private final String name; + private final Set types; + private final int limit; + + public EntityGroup(String name, Set types, int limit) { + this.name = name; + this.types = types; + this.limit = limit; + } + + public boolean contains(EntityType type) { + return types.contains(type); + } + + public String getName() { + return name; + } + + public Set getTypes() { + return types; + } + + public int getLimit() { + return limit; + } + + @Override + public int hashCode() + { + int hash = 7; + hash = 83 * hash + Objects.hashCode(this.name); + return hash; + } + + @Override + public boolean equals(Object obj) + { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final EntityGroup other = (EntityGroup) obj; + if (!Objects.equals(this.name, other.name)) + return false; + return true; + } + + @Override + public String toString() + { + return "EntityGroup{" + "name=" + name + ", types=" + types + ", limit=" + limit + '}'; + } + } } diff --git a/src/main/java/world/bentobox/limits/commands/LimitPanel.java b/src/main/java/world/bentobox/limits/commands/LimitPanel.java index 88b2420..5a41764 100644 --- a/src/main/java/world/bentobox/limits/commands/LimitPanel.java +++ b/src/main/java/world/bentobox/limits/commands/LimitPanel.java @@ -12,6 +12,8 @@ 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; @@ -20,6 +22,8 @@ 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; /** @@ -133,6 +137,40 @@ public class LimitPanel { "[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(); } @@ -154,4 +192,37 @@ public class LimitPanel { } 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/listeners/EntityLimitListener.java b/src/main/java/world/bentobox/limits/listeners/EntityLimitListener.java index 5d5cf5a..2d99b6a 100644 --- a/src/main/java/world/bentobox/limits/listeners/EntityLimitListener.java +++ b/src/main/java/world/bentobox/limits/listeners/EntityLimitListener.java @@ -1,10 +1,17 @@ package world.bentobox.limits.listeners; +import java.util.AbstractMap; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Objects; +import java.util.stream.Collectors; import org.bukkit.Location; import org.bukkit.World; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -19,6 +26,8 @@ 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; public class EntityLimitListener implements Listener { private static final String MOD_BYPASS = "mod.bypass"; @@ -54,14 +63,21 @@ public class EntityLimitListener implements Listener { return; } // Check if the player is at the limit - if (!bypass && atLimit(island, e.getVehicle())) { + AtLimitResult res; + if (!bypass && (res = atLimit(island, e.getVehicle())).hit()) { e.setCancelled(true); for (Entity ent : e.getVehicle().getLocation().getWorld().getNearbyEntities(e.getVehicle().getLocation(), 5, 5, 5)) { if (ent instanceof Player) { ((Player) ent).updateInventory(); - User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", - Util.prettifyText(e.getVehicle().getType().toString()) - , TextVariables.NUMBER, String.valueOf(addon.getSettings().getLimits().get(e.getVehicle().getType()))); + if (res.getTypelimit() != null) { + User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", + Util.prettifyText(e.getVehicle().getType().toString()), + TextVariables.NUMBER, String.valueOf(res.getTypelimit().getValue())); + } else { + User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", + res.getGrouplimit().getKey().getName() + " (" + res.getGrouplimit().getKey().getTypes().stream().map(x -> Util.prettifyText(x.toString())).collect(Collectors.joining(", ")) + ")", + TextVariables.NUMBER, String.valueOf(res.getGrouplimit().getValue())); + } } } } @@ -122,13 +138,19 @@ public class EntityLimitListener implements Listener { addon.getIslands().getIslandAt(e.getEntity().getLocation()).ifPresent(island -> { boolean bypass = Objects.requireNonNull(player).isOp() || player.hasPermission(addon.getPlugin().getIWM().getPermissionPrefix(e.getEntity().getWorld()) + MOD_BYPASS); // Check if entity can be hung - if (!bypass && !island.isSpawn() && atLimit(island, e.getEntity())) { + AtLimitResult res; + if (!bypass && !island.isSpawn() && (res = atLimit(island, e.getEntity())).hit()) { // Not allowed e.setCancelled(true); - User.getInstance(player).notify("block-limits.hit-limit", "[material]", - Util.prettifyText(e.getEntity().getType().toString()), - TextVariables.NUMBER, String.valueOf(addon.getSettings().getLimits().getOrDefault(e.getEntity().getType(), -1))); - + if (res.getTypelimit() != null) { + User.getInstance(player).notify("block-limits.hit-limit", "[material]", + Util.prettifyText(e.getEntity().getType().toString()), + TextVariables.NUMBER, String.valueOf(res.getTypelimit().getValue())); + } else { + User.getInstance(player).notify("block-limits.hit-limit", "[material]", + res.getGrouplimit().getKey().getName() + " (" + res.getGrouplimit().getKey().getTypes().stream().map(x -> Util.prettifyText(x.toString())).collect(Collectors.joining(", ")) + ")", + TextVariables.NUMBER, String.valueOf(res.getGrouplimit().getValue())); + } } }); } @@ -136,7 +158,8 @@ public class EntityLimitListener implements Listener { private void checkLimit(CreatureSpawnEvent e, boolean bypass) { addon.getIslands().getIslandAt(e.getLocation()).ifPresent(island -> { // Check if creature is allowed to spawn or not - if (!bypass && !island.isSpawn() && atLimit(island, e.getEntity())) { + AtLimitResult res; + if (!bypass && !island.isSpawn() && (res = atLimit(island, e.getEntity())).hit()) { // Not allowed e.setCancelled(true); // If the reason is anything but because of a spawner then tell players within range @@ -145,9 +168,15 @@ public class EntityLimitListener implements Listener { if (w == null) return; for (Entity ent : w.getNearbyEntities(e.getLocation(), 5, 5, 5)) { if (ent instanceof Player) { - User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", - Util.prettifyText(e.getEntityType().toString()), - TextVariables.NUMBER, String.valueOf(addon.getSettings().getLimits().get(e.getEntityType()))); + if (res.getTypelimit() != null) { + User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", + Util.prettifyText(e.getEntityType().toString()), + TextVariables.NUMBER, String.valueOf(res.getTypelimit().getValue())); + } else { + User.getInstance(ent).notify("entity-limits.hit-limit", "[entity]", + res.getGrouplimit().getKey().getName() + " (" + res.getGrouplimit().getKey().getTypes().stream().map(x -> Util.prettifyText(x.toString())).collect(Collectors.joining(", ")) + ")", + TextVariables.NUMBER, String.valueOf(res.getGrouplimit().getValue())); + } } } } @@ -163,21 +192,78 @@ public class EntityLimitListener implements Listener { * @param ent - the entity * @return true if at the limit, false if not */ - private boolean atLimit(Island island, Entity ent) { + private AtLimitResult atLimit(Island island, Entity ent) { // Check island settings first int limitAmount = -1; + Map groupsLimits = new HashMap<>(); if (addon.getBlockLimitListener().getIsland(island.getUniqueId()) != null) { limitAmount = addon.getBlockLimitListener().getIsland(island.getUniqueId()).getEntityLimit(ent.getType()); + List groupdefs = addon.getSettings().getGroupLimits().getOrDefault(ent.getType(), new ArrayList()); + groupdefs.forEach(def -> { + int limit = addon.getBlockLimitListener().getIsland(island.getUniqueId()).getEntityGroupLimit(def.getName()); + if (limit >= 0) + groupsLimits.put(def, limit); + }); } // If no island settings then try global settings if (limitAmount < 0 && addon.getSettings().getLimits().containsKey(ent.getType())) { limitAmount = addon.getSettings().getLimits().get(ent.getType()); } - if (limitAmount < 0) return false; + if (addon.getSettings().getGroupLimits().containsKey(ent.getType())) { + addon.getSettings().getGroupLimits().getOrDefault(ent.getType(), new ArrayList<>()).stream() + .filter(group -> !groupsLimits.containsKey(group) || groupsLimits.get(group) > group.getLimit()) + .forEach(group -> groupsLimits.put(group, group.getLimit())); + } + if (limitAmount < 0 && groupsLimits.isEmpty()) return new AtLimitResult(); + // We have to count the entities - return ent.getWorld().getEntities().stream() - .filter(e -> e.getType().equals(ent.getType())) - .filter(e -> island.inIslandSpace(e.getLocation())).count() >= limitAmount; + if (limitAmount >= 0) + { + int count = (int) ent.getWorld().getEntities().stream() + .filter(e -> e.getType().equals(ent.getType())) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + if (count >= limitAmount) + return new AtLimitResult(ent.getType(), limitAmount); + } + + // Now do the group limits + for (Map.Entry group : groupsLimits.entrySet()) { //do not use lambda + if (group.getValue() < 0) + continue; + int count = (int) ent.getWorld().getEntities().stream() + .filter(e -> group.getKey().contains(e.getType())) + .filter(e -> island.inIslandSpace(e.getLocation())).count(); + if (count >= group.getValue()) + return new AtLimitResult(group.getKey(), group.getValue()); + } + return new AtLimitResult(); + } + + private class AtLimitResult { + private Map.Entry typelimit; + private Map.Entry grouplimit; + + public AtLimitResult() {} + + public AtLimitResult(EntityType type, int limit) { + typelimit = new AbstractMap.SimpleEntry<>(type, limit); + } + + public AtLimitResult(EntityGroup type, int limit) { + grouplimit = new AbstractMap.SimpleEntry<>(type, limit); + } + + public boolean hit() { + return typelimit != null || grouplimit != null; + } + + public Map.Entry getTypelimit() { + return typelimit; + } + + public Map.Entry getGrouplimit() { + return grouplimit; + } } } diff --git a/src/main/java/world/bentobox/limits/listeners/JoinListener.java b/src/main/java/world/bentobox/limits/listeners/JoinListener.java index 1e66fb5..e3cddef 100644 --- a/src/main/java/world/bentobox/limits/listeners/JoinListener.java +++ b/src/main/java/world/bentobox/limits/listeners/JoinListener.java @@ -23,6 +23,7 @@ import world.bentobox.bentobox.api.events.island.IslandEvent.Reason; import world.bentobox.bentobox.api.events.team.TeamEvent.TeamSetownerEvent; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.limits.Limits; +import world.bentobox.limits.Settings.EntityGroup; import world.bentobox.limits.events.LimitsJoinPermCheckEvent; import world.bentobox.limits.objects.IslandBlockCount; @@ -56,6 +57,7 @@ public class JoinListener implements Listener { if (ibc != null) { // Clear permission limits ibc.getEntityLimits().clear(); + ibc.getEntityGroupLimits().clear(); ibc.getBlockLimits().clear(); } for (PermissionAttachmentInfo perms : player.getEffectivePermissions()) { @@ -68,7 +70,7 @@ public class JoinListener implements Listener { // Check formatting String[] split = perms.getPermission().split("\\."); if (split.length != 5) { - logError(player.getName(), perms.getPermission(), "format must be '" + permissionPrefix + "MATERIAL.NUMBER' or '" + permissionPrefix + "ENTITY-TYPE.NUMBER'"); + logError(player.getName(), perms.getPermission(), "format must be '" + permissionPrefix + "MATERIAL.NUMBER', '" + permissionPrefix + "ENTITY-TYPE.NUMBER', or '" + permissionPrefix + "ENTITY-GROUP.NUMBER'"); return; } // Check value @@ -79,16 +81,20 @@ public class JoinListener implements Listener { // Entities & materials EntityType et = Arrays.stream(EntityType.values()).filter(t -> t.name().equalsIgnoreCase(split[3])).findFirst().orElse(null); Material m = Arrays.stream(Material.values()).filter(t -> t.name().equalsIgnoreCase(split[3])).findFirst().orElse(null); + EntityGroup entgroup = addon.getSettings().getGroupLimitDefinitions().stream().filter(t -> t.getName().equalsIgnoreCase(split[3])).findFirst().orElse(null); - if (et == null && m == null) { - logError(player.getName(), perms.getPermission(), split[3].toUpperCase(Locale.ENGLISH) + " is not a valid material or entity type."); + if (entgroup == null && et == null && m == null) { + logError(player.getName(), perms.getPermission(), split[3].toUpperCase(Locale.ENGLISH) + " is not a valid material or entity type/group."); break; } // Make an ibc if required if (ibc == null) { ibc = new IslandBlockCount(islandId, gameMode); } - if (et != null && m == null) { + if (entgroup != null) { + // Entity group limit + ibc.setEntityGroupLimit(entgroup.getName(), Math.max(ibc.getEntityGroupLimit(entgroup.getName()), Integer.valueOf(split[4]))); + } else if (et != null && m == null) { // Entity limit ibc.setEntityLimit(et, Math.max(ibc.getEntityLimit(et), Integer.valueOf(split[4]))); } else if (m != null && et == null) { diff --git a/src/main/java/world/bentobox/limits/objects/IslandBlockCount.java b/src/main/java/world/bentobox/limits/objects/IslandBlockCount.java index b30f260..485b21e 100644 --- a/src/main/java/world/bentobox/limits/objects/IslandBlockCount.java +++ b/src/main/java/world/bentobox/limits/objects/IslandBlockCount.java @@ -1,6 +1,7 @@ package world.bentobox.limits.objects; import java.util.EnumMap; +import java.util.HashMap; import java.util.Map; import org.bukkit.Material; @@ -34,6 +35,8 @@ public class IslandBlockCount implements DataObject { private Map blockLimits = new EnumMap<>(Material.class); @Expose private Map entityLimits = new EnumMap<>(EntityType.class); + @Expose + private Map entityGroupLimits = new HashMap<>(); // Required for YAML database public IslandBlockCount() {} @@ -202,5 +205,43 @@ public class IslandBlockCount implements DataObject { public void clearEntityLimits() { entityLimits.clear(); } + + /** + * @return the entityGroupLimits + */ + public Map getEntityGroupLimits() { + return entityGroupLimits; + } + /** + * @param entityGroupLimits the entityGroupLimits to set + */ + public void setEntityGroupLimits(Map entityGroupLimits) { + this.entityGroupLimits = entityGroupLimits; + } + + /** + * Set an island-specific entity group limit + * @param name - entity group + * @param limit - limit + */ + public void setEntityGroupLimit(String name, int limit) { + entityGroupLimits.put(name, limit); + } + + /** + * Get the limit for an entity group + * @param name - entity group + * @return limit or -1 for unlimited + */ + public int getEntityGroupLimit(String name) { + return entityGroupLimits.getOrDefault(name, -1); + } + + /** + * Clear all island-specific entity group limits + */ + public void clearEntityGroupLimits() { + entityGroupLimits.clear(); + } } diff --git a/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java b/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java index 8648d54..702c8c1 100644 --- a/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java +++ b/src/test/java/bentobox/addon/limits/listeners/JoinListenerTest.java @@ -1,5 +1,7 @@ package bentobox.addon.limits.listeners; +import java.util.ArrayList; +import java.util.Arrays; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -39,6 +41,7 @@ import world.bentobox.bentobox.api.events.team.TeamEvent.TeamSetownerEvent; import world.bentobox.bentobox.database.objects.Island; import world.bentobox.bentobox.managers.IslandsManager; import world.bentobox.limits.Limits; +import world.bentobox.limits.Settings; import world.bentobox.limits.listeners.BlockLimitsListener; import world.bentobox.limits.listeners.JoinListener; import world.bentobox.limits.objects.IslandBlockCount; @@ -54,6 +57,8 @@ public class JoinListenerTest { @Mock private Limits addon; @Mock + private Settings settings; + @Mock private GameModeAddon bskyblock; @Mock private Player player; @@ -79,6 +84,9 @@ public class JoinListenerTest { when(addon.getGameModes()).thenReturn(Collections.singletonList(bskyblock)); when(addon.getGameModeName(any())).thenReturn("bskyblock"); when(addon.getGameModePermPrefix(any())).thenReturn("bskyblock."); + when(addon.getSettings()).thenReturn(settings); + // Settings + when(settings.getGroupLimitDefinitions()).thenReturn(new ArrayList(Arrays.asList(new Settings.EntityGroup("friendly", new HashSet<>(), -1)))); // Island Manager when(im.hasIsland(any(), any(UUID.class))).thenReturn(true); when(island.getUniqueId()).thenReturn("unique_id"); @@ -248,7 +256,7 @@ public class JoinListenerTest { when(player.getEffectivePermissions()).thenReturn(perms); PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome"); jl.onPlayerJoin(e); - verify(addon).logError("Player tastybento has permission: 'bskyblock.island.limit.my.perm.for.game' but format must be 'bskyblock.island.limit.MATERIAL.NUMBER' or 'bskyblock.island.limit.ENTITY-TYPE.NUMBER' Ignoring..."); + verify(addon).logError("Player tastybento has permission: 'bskyblock.island.limit.my.perm.for.game' but format must be 'bskyblock.island.limit.MATERIAL.NUMBER', 'bskyblock.island.limit.ENTITY-TYPE.NUMBER', or 'bskyblock.island.limit.ENTITY-GROUP.NUMBER' Ignoring..."); } /** @@ -264,7 +272,7 @@ public class JoinListenerTest { when(player.getEffectivePermissions()).thenReturn(perms); PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome"); jl.onPlayerJoin(e); - verify(addon).logError("Player tastybento has permission: 'bskyblock.island.limit.mumbo.34' but MUMBO is not a valid material or entity type. Ignoring..."); + verify(addon).logError("Player tastybento has permission: 'bskyblock.island.limit.mumbo.34' but MUMBO is not a valid material or entity type/group. Ignoring..."); } /** @@ -332,6 +340,23 @@ public class JoinListenerTest { verify(addon, never()).logError(anyString()); verify(ibc).setEntityLimit(eq(EntityType.BAT), eq(24)); } + + /** + * Test method for {@link world.bentobox.limits.listeners.JoinListener#onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent)}. + */ + @Test + public void testOnPlayerJoinWithPermLimitsSuccessEntityGroup() { + Set perms = new HashSet<>(); + PermissionAttachmentInfo permAtt = mock(PermissionAttachmentInfo.class); + when(permAtt.getPermission()).thenReturn("bskyblock.island.limit.friendly.24"); + when(permAtt.getValue()).thenReturn(true); + perms.add(permAtt); + when(player.getEffectivePermissions()).thenReturn(perms); + PlayerJoinEvent e = new PlayerJoinEvent(player, "welcome"); + jl.onPlayerJoin(e); + verify(addon, never()).logError(anyString()); + verify(ibc).setEntityGroupLimit(eq("friendly"), eq(24)); + } /** * Test method for {@link world.bentobox.limits.listeners.JoinListener#onPlayerJoin(org.bukkit.event.player.PlayerJoinEvent)}.