Skip to content

Commit 83b7c66

Browse files
authored
Merge pull request #2518 from BentoBoxWorld/2517_Admin_command_for_maximum_amount_of_homes
2 parents 69de5ea + f1219ec commit 83b7c66

File tree

10 files changed

+906
-11
lines changed

10 files changed

+906
-11
lines changed

pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@
8888
<!-- Do not change unless you want different name for local builds. -->
8989
<build.number>-LOCAL</build.number>
9090
<!-- This allows to change between versions. -->
91-
<build.version>2.5.4</build.version>
91+
<build.version>2.6.0</build.version>
9292
<sonar.organization>bentobox-world</sonar.organization>
9393
<sonar.host.url>https://sonarcloud.io</sonar.host.url>
9494
<server.jars>${project.basedir}/lib</server.jars>

src/main/java/world/bentobox/bentobox/api/commands/CompositeCommand.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -758,7 +758,7 @@ private List<String> getSubCommandLabels(@NonNull CommandSender sender, @NonNull
758758
* @param user - the User
759759
* @return result of help command or false if no help defined
760760
*/
761-
protected boolean showHelp(CompositeCommand command, User user) {
761+
public boolean showHelp(CompositeCommand command, User user) {
762762
return command.getSubCommand("help")
763763
.map(helpCommand -> helpCommand.execute(user, helpCommand.getLabel(), new ArrayList<>())).orElse(false);
764764
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
package world.bentobox.bentobox.api.commands.admin;
2+
3+
import java.util.ArrayList;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Optional;
8+
import java.util.UUID;
9+
10+
import com.google.common.primitives.Ints;
11+
12+
import world.bentobox.bentobox.api.commands.CompositeCommand;
13+
import world.bentobox.bentobox.api.commands.ConfirmableCommand;
14+
import world.bentobox.bentobox.api.localization.TextVariables;
15+
import world.bentobox.bentobox.api.user.User;
16+
import world.bentobox.bentobox.database.objects.Island;
17+
import world.bentobox.bentobox.util.Util;
18+
19+
/**
20+
* Sets the maximum number of homes allowed on this island.
21+
*
22+
* Commands:
23+
* <ul>
24+
* <li><b>/bsb maxhomes &lt;player&gt; &lt;number&gt;</b> - Sets the maximum number of homes for each island where the player is the owner. This could apply to multiple islands.</li>
25+
* <li><b>/bsb maxhomes &lt;player&gt; &lt;number&gt; [island name]</b> - Sets the maximum number of homes for a specific named island where the player is the owner.</li>
26+
* <li><b>/bsb maxhomes &lt;number&gt;</b> - Sets the maximum number of homes for the island you are standing on (in-game only).</li>
27+
* </ul>
28+
*
29+
* @author tastybento
30+
* @since 2.6.0
31+
*/
32+
33+
public class AdminMaxHomesCommand extends ConfirmableCommand {
34+
35+
Integer maxHomes;
36+
Map<String, Island> islands = new HashMap<>();
37+
38+
public AdminMaxHomesCommand(CompositeCommand parent) {
39+
super(parent, "setmaxhomes");
40+
}
41+
42+
@Override
43+
public void setup() {
44+
setPermission("mod.maxhomes");
45+
setOnlyPlayer(false);
46+
setParametersHelp("commands.admin.maxhomes.parameters");
47+
setDescription("commands.admin.maxhomes.description");
48+
}
49+
50+
@Override
51+
public boolean canExecute(User user, String label, List<String> args) {
52+
islands.clear();
53+
if (args.isEmpty()) {
54+
showHelp(this, user);
55+
return false;
56+
}
57+
// Check arguments
58+
if (args.size() == 1) {
59+
// Player must be in game
60+
if (!user.isPlayer()) {
61+
user.sendMessage("general.errors.use-in-game");
62+
return false;
63+
}
64+
// Check world
65+
if (user.getWorld() != getWorld()) {
66+
user.sendMessage("general.errors.wrong-world");
67+
return false;
68+
}
69+
// Arg must be an integer to return true, otherwise false
70+
maxHomes = Ints.tryParse(args.get(0));
71+
if (maxHomes == null || maxHomes < 1) {
72+
user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(0));
73+
return false;
74+
}
75+
// Get the island the user is standing on
76+
boolean onIsland = getIslands().getIslandAt(user.getLocation()).map(is -> {
77+
islands.put("", is);
78+
return true;
79+
}).orElse(false);
80+
if (!onIsland) {
81+
user.sendMessage("general.errors.not-on-island");
82+
return false;
83+
}
84+
return true;
85+
}
86+
// More than one argument
87+
// First arg must be a valid player name
88+
UUID targetUUID = getPlayers().getUUID(args.get(0));
89+
if (targetUUID == null) {
90+
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
91+
return false;
92+
}
93+
// Second arg must be the max homes number
94+
maxHomes = Ints.tryParse(args.get(1));
95+
if (maxHomes == null) {
96+
user.sendMessage("general.errors.must-be-positive-number", TextVariables.NUMBER, args.get(1));
97+
return false;
98+
}
99+
// Get islands
100+
islands = this.getNameIslandMap(User.getInstance(targetUUID));
101+
if (islands.isEmpty()) {
102+
user.sendMessage("general.errors.player-has-no-island");
103+
return false;
104+
}
105+
if (args.size() > 2) {
106+
// A specific island is mentioned. Parse which one it is and remove the others
107+
final String name = String.join(" ", args.subList(2, args.size())); // Join all the args from here with spaces
108+
109+
islands.keySet().removeIf(n -> !name.equalsIgnoreCase(n));
110+
111+
if (islands.isEmpty()) {
112+
// Failed name check - there are either
113+
user.sendMessage("commands.admin.maxhomes.errors.unknown-island", TextVariables.NAME, name);
114+
return false;
115+
}
116+
}
117+
118+
return true;
119+
}
120+
121+
@Override
122+
public boolean execute(User user, String label, List<String> args) {
123+
if (islands.isEmpty() || maxHomes < 1) {
124+
// Sanity check
125+
return false;
126+
}
127+
islands.forEach((name, island) -> {
128+
island.setMaxHomes(maxHomes);
129+
user.sendMessage("commands.admin.maxhomes.max-homes-set", TextVariables.NAME, name, TextVariables.NUMBER,
130+
String.valueOf(maxHomes));
131+
});
132+
return true;
133+
}
134+
135+
@Override
136+
public Optional<List<String>> tabComplete(User user, String alias, List<String> args) {
137+
String lastArg = !args.isEmpty() ? args.get(args.size()-1) : "";
138+
if (args.size() == 2) {
139+
// Suggest player names
140+
return Optional.of(Util.getOnlinePlayerList(user));
141+
}
142+
if (args.size() > 3) {
143+
return Optional.of(Util.tabLimit(new ArrayList<>(getNameIslandMap(user).keySet()), lastArg));
144+
}
145+
return Optional.of(List.of("1"));
146+
147+
}
148+
149+
Map<String, Island> getNameIslandMap(User user) {
150+
Map<String, Island> islandMap = new HashMap<>();
151+
int index = 0;
152+
for (Island island : getIslands().getIslands(getWorld(), user.getUniqueId())) {
153+
index++;
154+
if (island.getName() != null && !island.getName().isBlank()) {
155+
// Name has been set
156+
islandMap.put(island.getName(), island);
157+
} else {
158+
// Name has not been set
159+
String text = user.getTranslation("protection.flags.ENTER_EXIT_MESSAGES.island", TextVariables.NAME,
160+
user.getName(), TextVariables.DISPLAY_NAME, user.getDisplayName()) + " " + index;
161+
islandMap.put(text, island);
162+
}
163+
}
164+
165+
return islandMap;
166+
167+
}
168+
169+
}

src/main/java/world/bentobox/bentobox/api/commands/admin/DefaultAdminCommand.java

+2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,8 @@ public void setup() {
102102
new AdminDeleteHomesCommand(this);
103103
// Reset name
104104
new AdminResetNameCommand(this);
105+
// Max homes
106+
new AdminMaxHomesCommand(this);
105107
}
106108

107109
/**

src/main/java/world/bentobox/bentobox/listeners/JoinLeaveListener.java

+17-7
Original file line numberDiff line numberDiff line change
@@ -95,13 +95,7 @@ public void onPlayerJoin(final PlayerJoinEvent event) {
9595

9696
// Set island max members and homes based on permissions if this player is the
9797
// owner of an island
98-
plugin.getIWM().getOverWorlds().stream().map(w -> plugin.getIslands().getIsland(w, playerUUID))
99-
.filter(Objects::nonNull).filter(i -> playerUUID.equals(i.getOwner())).forEach(i -> {
100-
plugin.getIslands().getMaxMembers(i, RanksManager.MEMBER_RANK);
101-
plugin.getIslands().getMaxMembers(i, RanksManager.COOP_RANK);
102-
plugin.getIslands().getMaxMembers(i, RanksManager.TRUSTED_RANK);
103-
plugin.getIslands().getMaxHomes(i);
104-
});
98+
updateIslandMaxTeamAndHomeSize(user);
10599

106100
// Add a player to the bStats cache.
107101
plugin.getMetrics().ifPresent(bStats -> bStats.addPlayer(playerUUID));
@@ -125,6 +119,18 @@ public void onPlayerJoin(final PlayerJoinEvent event) {
125119
});
126120
}
127121

122+
private void updateIslandMaxTeamAndHomeSize(User user) {
123+
plugin.getIWM().getOverWorlds().stream()
124+
.flatMap(w -> plugin.getIslands().getIslands(w, user.getUniqueId()).stream()) // Flatten the List<Island> into a Stream<Island>
125+
.filter(Objects::nonNull).filter(i -> user.getUniqueId().equals(i.getOwner())).forEach(i -> {
126+
plugin.getIslands().getMaxMembers(i, RanksManager.MEMBER_RANK);
127+
plugin.getIslands().getMaxMembers(i, RanksManager.COOP_RANK);
128+
plugin.getIslands().getMaxMembers(i, RanksManager.TRUSTED_RANK);
129+
plugin.getIslands().getMaxHomes(i);
130+
});
131+
132+
}
133+
128134
private void firstTime(User user) {
129135
// Make sure the player is loaded into the cache or create the player if they
130136
// don't exist
@@ -206,6 +212,10 @@ private void clearPlayersInventory(@Nullable World world, @NonNull User user) {
206212
}
207213
}
208214

215+
/**
216+
* Update island range using player perms
217+
* @param user user
218+
*/
209219
private void updateIslandRange(User user) {
210220
plugin.getIslands().getIslands(user.getUniqueId()).stream()
211221
.filter(island -> island.getOwner() != null && island.getOwner().equals(user.getUniqueId()))

src/main/java/world/bentobox/bentobox/lists/GameModePlaceholder.java

+19
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,15 @@ public enum GameModePlaceholder {
157157
* @since 1.5.0
158158
*/
159159
ISLAND_VISITORS_COUNT("island_visitors_count", (addon, user, island) -> island == null ? "" : String.valueOf(island.getVisitors().size())),
160+
/**
161+
* Returns the amount of players that are at least MEMBER on the island the player is standing on.
162+
* @since 2.6.0
163+
*/
164+
ISLAND_MAX_HOMES("island_max_homes",
165+
(addon, user, island) -> island == null ? ""
166+
: String.valueOf(
167+
island.getMaxHomes() == null ? addon.getPlugin().getIWM().getMaxHomes(island.getWorld())
168+
: island.getMaxHomes())),
160169
/**
161170
* Returns the amount of players banned from the island.
162171
* @since 1.5.0
@@ -281,6 +290,16 @@ public enum GameModePlaceholder {
281290
*/
282291
VISITED_ISLAND_MEMBERS_COUNT("visited_island_members_count", (addon, user, island) ->
283292
getVisitedIsland(addon, user).map(value -> String.valueOf(value.getMemberSet().size())).orElse("")),
293+
/**
294+
* Returns the amount of players that are at least MEMBER on the island the player is standing on.
295+
* @since 2.6.0
296+
*/
297+
VISITED_ISLAND_MAX_HOMES("visited_island_max_homes",
298+
(addon, user,
299+
island) -> getVisitedIsland(addon, user).map(value -> String.valueOf(
300+
island.getMaxHomes() == null ? addon.getPlugin().getIWM().getMaxHomes(island.getWorld())
301+
: island.getMaxHomes()))
302+
.orElse("")),
284303
/**
285304
* Returns the amount of players that are TRUSTED on the island the player is standing on.
286305
* @since 1.5.2

src/main/java/world/bentobox/bentobox/util/IslandInfo.java

+3
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,9 @@ public boolean showInfo(User user) {
143143
// Show team members
144144
showMembers(user);
145145
}
146+
int maxHomes = island.getMaxHomes() == null ? plugin.getIWM().getMaxHomes(island.getWorld())
147+
: island.getMaxHomes();
148+
user.sendMessage("commands.admin.info.max-homes", TextVariables.NUMBER, String.valueOf(maxHomes));
146149
Vector location = island.getProtectionCenter().toVector();
147150
user.sendMessage("commands.admin.info.island-center", TextVariables.XYZ, Util.xyz(location));
148151
user.sendMessage("commands.admin.info.protection-range", RANGE, String.valueOf(island.getProtectionRange()));

src/main/resources/locales/en-US.yml

+8
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,13 @@ commands:
5959
admin:
6060
help:
6161
description: admin command
62+
maxhomes:
63+
description: change the number of homes allowed on this island or player's island
64+
parameters: <number / player> <number> <island name>
65+
max-homes-set: '&a [name] - Set island max homes to [number]'
66+
errors:
67+
unknown-island: &c Unknown island! [name]
68+
6269
resets:
6370
description: edit player reset values
6471
set:
@@ -213,6 +220,7 @@ commands:
213220
last-login-date-time-format: EEE MMM dd HH:mm:ss zzz yyyy
214221
deaths: 'Deaths: [number]'
215222
resets-left: 'Resets: [number] (Max: [total])'
223+
max-homes: 'Max homes: [number]'
216224
team-members-title: 'Team members:'
217225
team-owner-format: '&a [name] [rank]'
218226
team-member-format: '&b [name] [rank]'

src/test/java/world/bentobox/bentobox/api/commands/admin/AdminDeleteCommandTest.java

-2
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,6 @@ public class AdminDeleteCommandTest {
6868
@Mock
6969
private @Nullable Island island;
7070

71-
/**
72-
*/
7371
@Before
7472
public void setUp() throws Exception {
7573
PowerMockito.mockStatic(Bukkit.class, Mockito.RETURNS_MOCKS);

0 commit comments

Comments
 (0)