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:
+ *
+ * - /bsb maxhomes <player> <number> - Sets the maximum number of homes for each island where the player is the owner. This could apply to multiple islands.
+ * - /bsb maxhomes <player> <number> [island name] - Sets the maximum number of homes for a specific named island where the player is the owner.
+ * - /bsb maxhomes <number> - Sets the maximum number of homes for the island you are standing on (in-game only).
+ *
+ *
+ * @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]'