mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2025-01-21 07:32:32 +01:00
Rewrite of cooldowns to use island ID instead of player ID
Adds cooldown to island leave command. Tries to mitigate cooldown bypassing by players who change island owner or use subowner or members to issue invites instead of owner. Now the cooldown is based on the island ID itself. Original API's are kept for compatibility with addons that use cooldowns. Relates to https://github.com/BentoBoxWorld/BentoBox/issues/727
This commit is contained in:
parent
d57a9aa6d8
commit
7b2e8a657e
@ -107,7 +107,7 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
/**
|
||||
* Cool down tracker
|
||||
*/
|
||||
private Map<UUID, Map<UUID, Long>> cooldowns = new HashMap<>();
|
||||
private Map<String, Map<String, Long>> cooldowns = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Top level command
|
||||
@ -670,32 +670,76 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
|
||||
/**
|
||||
* Set a cool down - can be set by other commands on this one
|
||||
* @param uniqueId - the caller
|
||||
* @param uniqueId - the unique ID that is having the cooldown
|
||||
* @param targetUUID - the target (if any)
|
||||
* @param timeInSeconds - time in seconds to cool down
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public void setCooldown(UUID uniqueId, UUID targetUUID, int timeInSeconds) {
|
||||
public void setCooldown(String uniqueId, String targetUUID, int timeInSeconds) {
|
||||
cooldowns.putIfAbsent(uniqueId, new HashMap<>());
|
||||
cooldowns.get(uniqueId).put(targetUUID, System.currentTimeMillis() + timeInSeconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cool down is in progress
|
||||
* Set a cool down - can be set by other commands on this one
|
||||
* @param uniqueId - the UUID that is having the cooldown
|
||||
* @param targetUUID - the target UUID (if any)
|
||||
* @param timeInSeconds - time in seconds to cool down
|
||||
*/
|
||||
public void setCooldown(UUID uniqueId, UUID targetUUID, int timeInSeconds) {
|
||||
cooldowns.putIfAbsent(uniqueId.toString(), new HashMap<>());
|
||||
cooldowns.get(uniqueId.toString()).put(targetUUID == null ? null : targetUUID.toString(), System.currentTimeMillis() + timeInSeconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a cool down for a user - can be set by other commands on this one
|
||||
* @param uniqueId - the UUID that is having the cooldown
|
||||
* @param timeInSeconds - time in seconds to cool down
|
||||
* @since 1.5.0
|
||||
*/
|
||||
public void setCooldown(UUID uniqueId, int timeInSeconds) {
|
||||
setCooldown(uniqueId, null, timeInSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cool down is in progress for user
|
||||
* @param user - the caller of the command
|
||||
* @param targetUUID - the target (if any)
|
||||
* @return true if cool down in place, false if not
|
||||
*/
|
||||
protected boolean checkCooldown(User user, UUID targetUUID) {
|
||||
if (!cooldowns.containsKey(user.getUniqueId()) || user.isOp() || user.hasPermission(getPermissionPrefix() + "mod.bypasscooldowns")) {
|
||||
return checkCooldown(user, user.getUniqueId().toString(), targetUUID == null ? null : targetUUID.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cool down is in progress for user
|
||||
* @param user - the user to check
|
||||
* @return true if cool down in place, false if not
|
||||
* @since 1.5.0
|
||||
*/
|
||||
protected boolean checkCooldown(User user) {
|
||||
return checkCooldown(user, user.getUniqueId().toString(), null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cool down is in progress
|
||||
* @param user - the caller of the command
|
||||
* @param uniqueId - the id that needs to be checked
|
||||
* @param targetUUID - the target (if any)
|
||||
* @return true if cool down in place, false if not
|
||||
* @since 1.5.0
|
||||
*/
|
||||
protected boolean checkCooldown(User user, String uniqueId, String targetUUID) {
|
||||
if (!cooldowns.containsKey(uniqueId) || user.isOp() || user.hasPermission(getPermissionPrefix() + "mod.bypasscooldowns")) {
|
||||
return false;
|
||||
}
|
||||
cooldowns.putIfAbsent(user.getUniqueId(), new HashMap<>());
|
||||
if (cooldowns.get(user.getUniqueId()).getOrDefault(targetUUID, 0L) - System.currentTimeMillis() <= 0) {
|
||||
cooldowns.putIfAbsent(uniqueId, new HashMap<>());
|
||||
if (cooldowns.get(uniqueId).getOrDefault(targetUUID, 0L) - System.currentTimeMillis() <= 0) {
|
||||
// Cool down is done
|
||||
cooldowns.get(user.getUniqueId()).remove(targetUUID);
|
||||
cooldowns.get(uniqueId).remove(targetUUID);
|
||||
return false;
|
||||
}
|
||||
int timeToGo = (int) ((cooldowns.get(user.getUniqueId()).getOrDefault(targetUUID, 0L) - System.currentTimeMillis()) / 1000);
|
||||
int timeToGo = (int) ((cooldowns.get(uniqueId).getOrDefault(targetUUID, 0L) - System.currentTimeMillis()) / 1000);
|
||||
user.sendMessage("general.errors.you-must-wait", TextVariables.NUMBER, String.valueOf(timeToGo));
|
||||
return true;
|
||||
}
|
||||
|
@ -46,7 +46,8 @@ public class IslandBanCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Check rank to use command
|
||||
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
Island island = getIslands().getIsland(getWorld(), user);
|
||||
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
user.sendMessage("general.errors.no-permission");
|
||||
return false;
|
||||
}
|
||||
@ -69,7 +70,7 @@ public class IslandBanCommand extends CompositeCommand {
|
||||
user.sendMessage("commands.island.ban.player-already-banned");
|
||||
return false;
|
||||
}
|
||||
if (getSettings().getBanCooldown() > 0 && checkCooldown(user, targetUUID)) {
|
||||
if (getSettings().getBanCooldown() > 0 && checkCooldown(user, island.getUniqueId(), targetUUID.toString())) {
|
||||
return false;
|
||||
}
|
||||
User target = User.getInstance(targetUUID);
|
||||
|
@ -86,7 +86,7 @@ public class IslandCreateCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
if (getSettings().isResetCooldownOnCreate()) {
|
||||
getParent().getSubCommand("reset").ifPresent(resetCommand -> resetCommand.setCooldown(user.getUniqueId(), null, getSettings().getResetCooldown()));
|
||||
getParent().getSubCommand("reset").ifPresent(resetCommand -> resetCommand.setCooldown(user.getUniqueId(), getSettings().getResetCooldown()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ public class IslandResetCommand extends ConfirmableCommand {
|
||||
@Override
|
||||
public boolean canExecute(User user, String label, List<String> args) {
|
||||
// Check cooldown
|
||||
if (getSettings().getResetCooldown() > 0 && checkCooldown(user, null)) {
|
||||
if (getSettings().getResetCooldown() > 0 && checkCooldown(user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -128,7 +128,7 @@ public class IslandResetCommand extends ConfirmableCommand {
|
||||
user.sendMessage("commands.island.create.unable-create-island");
|
||||
return false;
|
||||
}
|
||||
setCooldown(user.getUniqueId(), null, getSettings().getResetCooldown());
|
||||
setCooldown(user.getUniqueId(), getSettings().getResetCooldown());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ public class IslandUnbanCommand extends CompositeCommand {
|
||||
// Set cooldown
|
||||
if (getSettings().getBanCooldown() > 0 && getParent() != null) {
|
||||
getParent().getSubCommand("ban").ifPresent(subCommand ->
|
||||
subCommand.setCooldown(issuer.getUniqueId(), target.getUniqueId(), getSettings().getBanCooldown() * 60));
|
||||
subCommand.setCooldown(island.getUniqueId(), target.getUniqueId().toString(), getSettings().getBanCooldown() * 60));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -48,7 +48,8 @@ public class IslandTeamCoopCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Check rank to use command
|
||||
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
Island island = getIslands().getIsland(getWorld(), user);
|
||||
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
user.sendMessage("general.errors.no-permission");
|
||||
return false;
|
||||
}
|
||||
@ -59,7 +60,7 @@ public class IslandTeamCoopCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Check cooldown
|
||||
if (getSettings().getCoopCooldown() > 0 && checkCooldown(user, targetUUID)) {
|
||||
if (getSettings().getCoopCooldown() > 0 && checkCooldown(user, island.getUniqueId(), targetUUID.toString())) {
|
||||
return false;
|
||||
}
|
||||
// Player cannot coop themselves
|
||||
|
@ -77,7 +77,7 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Check cool down
|
||||
if (getSettings().getInviteCooldown() > 0 && checkCooldown(user, invitedPlayerUUID)) {
|
||||
if (getSettings().getInviteCooldown() > 0 && checkCooldown(user, getIslands().getIsland(getWorld(), user).getUniqueId(), invitedPlayerUUID.toString())) {
|
||||
return false;
|
||||
}
|
||||
// Player cannot invite someone already on a team
|
||||
|
@ -105,7 +105,10 @@ public class IslandTeamKickCommand extends ConfirmableCommand {
|
||||
// Add cooldown for this player and target
|
||||
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {
|
||||
// Get the invite class from the parent
|
||||
getParent().getSubCommand("invite").ifPresent(c -> c.setCooldown(user.getUniqueId(), targetUUID, getSettings().getInviteCooldown() * 60));
|
||||
getParent().getSubCommand("invite").ifPresent(c -> c.setCooldown(
|
||||
oldIsland.getUniqueId(),
|
||||
targetUUID.toString(),
|
||||
getSettings().getInviteCooldown() * 60));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,6 +62,11 @@ public class IslandTeamLeaveCommand extends ConfirmableCommand {
|
||||
if (getSettings().isUseEconomy() && getIWM().isOnLeaveResetMoney(getWorld())) {
|
||||
getPlugin().getVault().ifPresent(vault -> vault.withdraw(user, vault.getBalance(user)));
|
||||
}
|
||||
// Add cooldown for this player and target
|
||||
if (getSettings().getInviteCooldown() > 0 && getParent() != null) {
|
||||
// Get the invite class from the parent
|
||||
getParent().getSubCommand("invite").ifPresent(c -> c.setCooldown(island.getUniqueId(), user.getUniqueId().toString(), getSettings().getInviteCooldown() * 60));
|
||||
}
|
||||
user.sendMessage("general.success");
|
||||
// Fire event
|
||||
IslandBaseEvent e = TeamEvent.builder()
|
||||
|
@ -44,7 +44,8 @@ public class IslandTeamTrustCommand extends CompositeCommand {
|
||||
return false;
|
||||
}
|
||||
// Check rank to use command
|
||||
if (getIslands().getIsland(getWorld(), user).getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
Island island = getIslands().getIsland(getWorld(), user);
|
||||
if (island.getRank(user) < getPlugin().getSettings().getRankCommand(getUsage())) {
|
||||
user.sendMessage("general.errors.no-permission");
|
||||
return false;
|
||||
}
|
||||
@ -54,7 +55,7 @@ public class IslandTeamTrustCommand extends CompositeCommand {
|
||||
user.sendMessage("general.errors.unknown-player", TextVariables.NAME, args.get(0));
|
||||
return false;
|
||||
}
|
||||
return (getSettings().getTrustCooldown() <= 0 || !checkCooldown(user, targetUUID)) && trustCmd(user, targetUUID);
|
||||
return (getSettings().getTrustCooldown() <= 0 || !checkCooldown(user, island.getUniqueId(), targetUUID.toString())) && trustCmd(user, targetUUID);
|
||||
}
|
||||
|
||||
private boolean trustCmd(User user, UUID targetUUID) {
|
||||
|
@ -86,7 +86,7 @@ public class IslandTeamUncoopCommand extends CompositeCommand {
|
||||
// Set cooldown
|
||||
if (getSettings().getCoopCooldown() > 0 && getParent() != null) {
|
||||
getParent().getSubCommand("coop").ifPresent(subCommand ->
|
||||
subCommand.setCooldown(user.getUniqueId(), targetUUID, getSettings().getCoopCooldown() * 60));
|
||||
subCommand.setCooldown(island.getUniqueId(), targetUUID.toString(), getSettings().getCoopCooldown() * 60));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -86,7 +86,7 @@ public class IslandTeamUntrustCommand extends CompositeCommand {
|
||||
// Set cooldown
|
||||
if (getSettings().getTrustCooldown() > 0 && getParent() != null) {
|
||||
getParent().getSubCommand("trust").ifPresent(subCommand ->
|
||||
subCommand.setCooldown(user.getUniqueId(), targetUUID, getSettings().getTrustCooldown() * 60));
|
||||
subCommand.setCooldown(island.getUniqueId(), targetUUID.toString(), getSettings().getTrustCooldown() * 60));
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
|
@ -33,6 +33,7 @@ import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
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.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
@ -140,6 +141,11 @@ public class IslandTeamKickCommandTest {
|
||||
when(server.getPluginManager()).thenReturn(pim);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
|
||||
// Island
|
||||
Island island = mock(Island.class);
|
||||
when(island.getUniqueId()).thenReturn("uniqueid");
|
||||
when(im.getIsland(Mockito.any(), Mockito.any(UUID.class))).thenReturn(island);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -296,6 +302,6 @@ public class IslandTeamKickCommandTest {
|
||||
// 10 minutes = 600 seconds
|
||||
when(s.getInviteCooldown()).thenReturn(10);
|
||||
testExecuteNoConfirmation();
|
||||
Mockito.verify(subCommand).setCooldown(uuid, notUUID, 600);
|
||||
Mockito.verify(subCommand).setCooldown("uniqueid", notUUID.toString(), 600);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
@ -19,6 +20,7 @@ import org.bukkit.scheduler.BukkitScheduler;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.powermock.api.mockito.PowerMockito;
|
||||
import org.powermock.core.classloader.annotations.PrepareForTest;
|
||||
@ -29,6 +31,7 @@ import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.database.objects.Island;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
import world.bentobox.bentobox.managers.IslandsManager;
|
||||
@ -49,6 +52,8 @@ public class IslandTeamLeaveCommandTest {
|
||||
private IslandsManager im;
|
||||
private IslandWorldManager iwm;
|
||||
private Player player;
|
||||
@Mock
|
||||
private CompositeCommand subCommand;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -81,6 +86,8 @@ public class IslandTeamLeaveCommandTest {
|
||||
// Parent command has no aliases
|
||||
ic = mock(CompositeCommand.class);
|
||||
when(ic.getSubCommandAliases()).thenReturn(new HashMap<>());
|
||||
Optional<CompositeCommand> optionalCommand = Optional.of(subCommand);
|
||||
when(ic.getSubCommand(Mockito.anyString())).thenReturn(optionalCommand);
|
||||
|
||||
// Player has island to begin with
|
||||
im = mock(IslandsManager.class);
|
||||
@ -107,6 +114,11 @@ public class IslandTeamLeaveCommandTest {
|
||||
PluginManager pim = mock(PluginManager.class);
|
||||
when(server.getPluginManager()).thenReturn(pim);
|
||||
when(Bukkit.getServer()).thenReturn(server);
|
||||
|
||||
// Island
|
||||
Island island = mock(Island.class);
|
||||
when(island.getUniqueId()).thenReturn("uniqueid");
|
||||
when(im.getIsland(Mockito.any(), Mockito.any(User.class))).thenReturn(island);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -194,4 +206,15 @@ public class IslandTeamLeaveCommandTest {
|
||||
Mockito.verify(enderChest).clear();
|
||||
Mockito.verify(inv).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link IslandTeamLeaveCommand#execute(User, String, java.util.List)}
|
||||
*/
|
||||
@Test
|
||||
public void testCooldown() {
|
||||
// 10 minutes = 600 seconds
|
||||
when(s.getInviteCooldown()).thenReturn(10);
|
||||
testExecuteNoConfirmation();
|
||||
Mockito.verify(subCommand).setCooldown("uniqueid", uuid.toString(), 600);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user