diff --git a/pom.xml b/pom.xml index 5f5b6f725..e49d241f5 100644 --- a/pom.xml +++ b/pom.xml @@ -88,7 +88,7 @@ -LOCAL - 2.5.4 + 2.6.0 bentobox-world https://sonarcloud.io ${project.basedir}/lib diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminMaxHomesCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminMaxHomesCommand.java new file mode 100644 index 000000000..52a568f48 --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/AdminMaxHomesCommand.java @@ -0,0 +1,169 @@ +package world.bentobox.bentobox.api.commands.admin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import com.google.common.primitives.Ints; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.commands.CompositeCommand; +import world.bentobox.bentobox.api.commands.ConfirmableCommand; +import world.bentobox.bentobox.api.localization.TextVariables; +import world.bentobox.bentobox.api.user.User; +import world.bentobox.bentobox.database.objects.Island; +import world.bentobox.bentobox.util.Util; + +/** + * Sets the maximum number of homes allowed on this island. + * + * Commands: + * + * + * @author tastybento + */ + +public class AdminMaxHomesCommand extends ConfirmableCommand { + + private Integer maxHomes; + private Map islands = new HashMap<>(); + + public AdminMaxHomesCommand(CompositeCommand parent) { + super(parent, "setmaxhomes"); + } + + @Override + public void setup() { + setPermission("mod.maxhomes"); + setOnlyPlayer(false); + setParametersHelp("commands.admin.maxhomes.parameters"); + setDescription("commands.admin.maxhomes.description"); + } + + @Override + public boolean canExecute(User user, String label, List args) { + islands.clear(); + if (args.isEmpty()) { + showHelp(this, user); + return false; + } + // Check arguments + if (args.size() == 1) { + // Player must be in game + if (!user.isPlayer()) { + user.sendMessage("general.errors.use-in-game"); + return false; + } + // Check world + if (user.getWorld() != getWorld()) { + user.sendMessage("general.errors.wrong-world"); + return false; + } + // Arg must be an integer to return true, otherwise false + maxHomes = Ints.tryParse(args.get(0)); + if (maxHomes == null || maxHomes < 1) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(0)); + return false; + } + // Get the island the user is standing on + boolean onIsland = getIslands().getIslandAt(user.getLocation()).map(is -> { + islands.put("", is); + return true; + }).orElse(false); + if (!onIsland) { + user.sendMessage("general.errors.not-on-island"); + return false; + } + return true; + } + // More than one argument + // First arg must be a valid player name + UUID targetUUID = getPlayers().getUUID(args.get(0)); + if (targetUUID == null) { + user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0)); + return false; + } + // Second arg must be the max homes number + maxHomes = Ints.tryParse(args.get(1)); + if (maxHomes == null) { + user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1)); + return false; + } + // Get islands + islands = this.getNameIslandMap(User.getInstance(targetUUID)); + if (islands.isEmpty()) { + user.sendMessage("general.errors.player-has-no-island"); + return false; + } + if (args.size() > 2) { + // A specific island is mentioned. Parse which one it is and remove the others + final String name = String.join(" ", args.subList(2, args.size())); // Join all the args from here with spaces + + islands.keySet().removeIf(n -> !name.equalsIgnoreCase(n)); + + if (islands.isEmpty()) { + // Failed name check - there are either + user.sendMessage("commands.admin.maxhomes.errors.unknown-island", TextVariables.NAME, name); + return false; + } + } + + return true; + } + + @Override + public boolean execute(User user, String label, List args) { + if (islands.isEmpty() || maxHomes < 1) { + // Sanity check + return false; + } + islands.forEach((name, island) -> { + island.setMaxHomes(maxHomes); + user.sendMessage("commands.admin.maxhomes.max-homes-set", TextVariables.NAME, name, TextVariables.NUMBER, + String.valueOf(maxHomes)); + }); + return true; + } + + @Override + public Optional> tabComplete(User user, String alias, List args) { + String lastArg = !args.isEmpty() ? args.get(args.size()-1) : ""; + if (args.size() == 2) { + // Suggest player names + return Optional.of(Util.getOnlinePlayerList(user)); + } + if (args.size() > 3) { + return Optional.of(Util.tabLimit(new ArrayList<>(getNameIslandMap(user).keySet()), lastArg)); + } + return Optional.of(List.of("1")); + + } + + private Map getNameIslandMap(User user) { + Map islandMap = new HashMap<>(); + int index = 0; + for (Island island : getIslands().getIslands(getWorld(), user.getUniqueId())) { + index++; + if (island.getName() != null && !island.getName().isBlank()) { + // Name has been set + islandMap.put(island.getName(), island); + } else { + // Name has not been set + String text = user.getTranslation("protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME, + user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName()) + " " + index; + islandMap.put(text, island); + } + } + + return islandMap; + + } + +} diff --git a/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java b/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java index be27bf080..00ad796f8 100644 --- a/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java +++ b/src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java @@ -102,6 +102,8 @@ public abstract class DefaultAdminCommand extends CompositeCommand { new AdminDeleteHomesCommand(this); // Reset name new AdminResetNameCommand(this); + // Max homes + new AdminMaxHomesCommand(this); } /** diff --git a/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java b/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java index 11c750889..eac3174e4 100644 --- a/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java +++ b/src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java @@ -95,13 +95,7 @@ public class JoinLeaveListener implements Listener { // Set island max members and homes based on permissions if this player is the // owner of an island - plugin.getIWM().getOverWorlds().stream().map(w -> plugin.getIslands().getIsland(w, playerUUID)) - .filter(Objects::nonNull).filter(i -> playerUUID.equals(i.getOwner())).forEach(i -> { - plugin.getIslands().getMaxMembers(i, RanksManager.MEMBER_RANK); - plugin.getIslands().getMaxMembers(i, RanksManager.COOP_RANK); - plugin.getIslands().getMaxMembers(i, RanksManager.TRUSTED_RANK); - plugin.getIslands().getMaxHomes(i); - }); + updateIslandMaxTeamAndHomeSize(user); // Add a player to the bStats cache. plugin.getMetrics().ifPresent(bStats -> bStats.addPlayer(playerUUID)); @@ -125,6 +119,18 @@ public class JoinLeaveListener implements Listener { }); } + private void updateIslandMaxTeamAndHomeSize(User user) { + plugin.getIWM().getOverWorlds().stream() + .flatMap(w -> plugin.getIslands().getIslands(w, user.getUniqueId()).stream()) // Flatten the List into a Stream + .filter(Objects::nonNull).filter(i -> user.getUniqueId().equals(i.getOwner())).forEach(i -> { + plugin.getIslands().getMaxMembers(i, RanksManager.MEMBER_RANK); + plugin.getIslands().getMaxMembers(i, RanksManager.COOP_RANK); + plugin.getIslands().getMaxMembers(i, RanksManager.TRUSTED_RANK); + plugin.getIslands().getMaxHomes(i); + }); + + } + private void firstTime(User user) { // Make sure the player is loaded into the cache or create the player if they // don't exist @@ -206,6 +212,10 @@ public class JoinLeaveListener implements Listener { } } + /** + * Update island range using player perms + * @param user user + */ private void updateIslandRange(User user) { plugin.getIslands().getIslands(user.getUniqueId()).stream() .filter(island -> island.getOwner() != null && island.getOwner().equals(user.getUniqueId())) diff --git a/src/main/java/world/bentobox/bentobox/util/IslandInfo.java b/src/main/java/world/bentobox/bentobox/util/IslandInfo.java index 9604aa33f..f7a0eecc7 100644 --- a/src/main/java/world/bentobox/bentobox/util/IslandInfo.java +++ b/src/main/java/world/bentobox/bentobox/util/IslandInfo.java @@ -143,6 +143,7 @@ public class IslandInfo { // Show team members showMembers(user); } + user.sendMessage("commands.admin.info.max-homes", TextVariables.NUMBER, String.valueOf(island.getMaxHomes())); Vector location = island.getProtectionCenter().toVector(); user.sendMessage("commands.admin.info.island-center", TextVariables.XYZ, Util.xyz(location)); user.sendMessage("commands.admin.info.protection-range", RANGE, String.valueOf(island.getProtectionRange())); diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index 1cbaf9f40..bd5529aee 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -59,6 +59,13 @@ commands: admin: help: description: admin command + maxhomes: + description: change the number of homes allowed on this island or player's island + parameters: + max-homes-set: '&a [name] - Set island max homes to [number]' + errors: + unknown-island: &c Unknown island! [name] + resets: description: edit player reset values set: @@ -213,6 +220,7 @@ commands: last-login-date-time-format: EEE MMM dd HH:mm:ss zzz yyyy deaths: 'Deaths: [number]' resets-left: 'Resets: [number] (Max: [total])' + max-homes: 'Max homes: [number]' team-members-title: 'Team members:' team-owner-format: '&a [name] [rank]' team-member-format: '&b [name] [rank]'