mirror of
https://github.com/BentoBoxWorld/BentoBox.git
synced 2024-12-28 03:57:39 +01:00
Added generic cooldown methods to CompositeCommand
This API enables any command to have a cool down and to have that cool down called by another command. For example, the Kick command sets the cool down on the Invite command. It is possible for commands to set cool downs on themselves too. Currently, cool downs are not stored persistently in the database so they disappear if the server is reloaded. This should be okay for now.
This commit is contained in:
parent
2cc6d36997
commit
783caf985f
@ -96,8 +96,16 @@ public abstract class CompositeCommand extends Command implements PluginIdentifi
|
||||
*/
|
||||
private String topLabel = "";
|
||||
|
||||
/**
|
||||
* Confirmation tracker
|
||||
*/
|
||||
private static Map<User, Confirmer> toBeConfirmed = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Cool down tracker
|
||||
*/
|
||||
private Map<UUID, Map<UUID, Long>> cooldowns = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Top level command
|
||||
* @param addon - addon creating the command
|
||||
@ -658,4 +666,36 @@ 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 targetUUID - the target (if any)
|
||||
* @param timeInSeconds - time in seconds to cool down
|
||||
*/
|
||||
public void setCooldown(UUID uniqueId, UUID targetUUID, int timeInSeconds) {
|
||||
cooldowns.putIfAbsent(uniqueId, new HashMap<>());
|
||||
cooldowns.get(uniqueId).put(targetUUID, System.currentTimeMillis() + timeInSeconds * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cool down has expired or not
|
||||
* @param user - the caller of the command
|
||||
* @param targetUUID - the target (if any)
|
||||
* @return true if cool down does not exist, false if it is still active
|
||||
*/
|
||||
protected boolean checkCooldown(User user, UUID targetUUID) {
|
||||
if (!cooldowns.containsKey(user.getUniqueId()) || user.isOp() || user.hasPermission(getPermissionPrefix() + ".mod.bypasscooldowns")) {
|
||||
return true;
|
||||
}
|
||||
cooldowns.putIfAbsent(user.getUniqueId(), new HashMap<>());
|
||||
if (cooldowns.get(user.getUniqueId()).getOrDefault(targetUUID, 0L) - System.currentTimeMillis() <= 0) {
|
||||
// Cool down is done
|
||||
cooldowns.get(user.getUniqueId()).remove(targetUUID);
|
||||
return true;
|
||||
}
|
||||
int timeToGo = (int) ((cooldowns.get(user.getUniqueId()).getOrDefault(targetUUID, 0L) - System.currentTimeMillis()) / 1000);
|
||||
user.sendMessage("general.errors.you-must-wait", TextVariables.NUMBER, String.valueOf(timeToGo));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -74,11 +74,8 @@ public class IslandTeamInviteCommand extends CompositeCommand {
|
||||
user.sendMessage("commands.island.team.invite.errors.cannot-invite-self");
|
||||
return false;
|
||||
}
|
||||
// Check if this player can be invited to this island, or
|
||||
// whether they are still on cooldown
|
||||
long time = getPlayers().getInviteCoolDownTime(invitedPlayerUUID, getIslands().getIslandLocation(getWorld(), playerUUID));
|
||||
if (time > 0 && !user.isOp()) {
|
||||
user.sendMessage("commands.island.team.invite.errors.cooldown", TextVariables.NUMBER, String.valueOf(time));
|
||||
// Check cool down
|
||||
if (getSettings().getInviteWait() > 0 && !checkCooldown(user, invitedPlayerUUID)) {
|
||||
return false;
|
||||
}
|
||||
// Player cannot invite someone already on a team
|
||||
|
@ -53,7 +53,7 @@ public class IslandTeamKickCommand extends CompositeCommand {
|
||||
kick(user, targetUUID);
|
||||
return true;
|
||||
} else {
|
||||
this.askConfirmation(user, () -> kick(user, targetUUID));
|
||||
askConfirmation(user, () -> kick(user, targetUUID));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -72,7 +72,15 @@ public class IslandTeamKickCommand extends CompositeCommand {
|
||||
// TODO: needs Vault
|
||||
}
|
||||
user.sendMessage("general.success");
|
||||
|
||||
// Add cooldown for this player and target
|
||||
if (getSettings().getInviteWait() > 0) {
|
||||
// Get the invite class from the parent
|
||||
if (getParent() != null) {
|
||||
getParent().getSubCommand("invite").ifPresent(c -> c.setCooldown(user.getUniqueId(), targetUUID, getSettings().getInviteWait() * 60));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -261,4 +261,5 @@ public interface WorldSettings {
|
||||
* @return max number of deaths for this world
|
||||
*/
|
||||
int getDeathsMax();
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,5 @@
|
||||
package world.bentobox.bentobox.database.objects;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -35,8 +33,6 @@ public class Players implements DataObject {
|
||||
private String locale = "";
|
||||
@Expose
|
||||
private Map<String, Integer> deaths = new HashMap<>();
|
||||
@Expose
|
||||
private Map<Location, Long> kickedList = new HashMap<>();
|
||||
|
||||
/**
|
||||
* This is required for database storage
|
||||
@ -53,7 +49,6 @@ public class Players implements DataObject {
|
||||
this.uniqueId = uniqueId.toString();
|
||||
homeLocations = new HashMap<>();
|
||||
locale = "";
|
||||
kickedList = new HashMap<>();
|
||||
// Try to get player's name
|
||||
this.playerName = Bukkit.getOfflinePlayer(uniqueId).getName();
|
||||
if (this.playerName == null) {
|
||||
@ -100,20 +95,6 @@ public class Players implements DataObject {
|
||||
return homeLocations;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the kickedList
|
||||
*/
|
||||
public Map<Location, Long> getKickedList() {
|
||||
return kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param kickedList the kickedList to set
|
||||
*/
|
||||
public void setKickedList(Map<Location, Long> kickedList) {
|
||||
this.kickedList = kickedList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param homeLocations the homeLocations to set
|
||||
*/
|
||||
@ -248,47 +229,6 @@ public class Players implements DataObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can invite or still waiting for cool down to end
|
||||
*
|
||||
* @param location - the location
|
||||
* to check
|
||||
* @return number of mins/hours left until cool down ends
|
||||
*/
|
||||
public long getInviteCoolDownTime(Location location) {
|
||||
// Check the hashmap
|
||||
if (location != null && kickedList.containsKey(location)) {
|
||||
// The location is in the list
|
||||
// Check the date/time
|
||||
Date kickedDate = new Date(kickedList.get(location));
|
||||
Calendar coolDownTime = Calendar.getInstance();
|
||||
coolDownTime.setTime(kickedDate);
|
||||
coolDownTime.add(Calendar.MINUTE, getPlugin().getSettings().getInviteWait());
|
||||
// Add the invite cooldown period
|
||||
Calendar timeNow = Calendar.getInstance();
|
||||
if (coolDownTime.before(timeNow)) {
|
||||
// The time has expired
|
||||
kickedList.remove(location);
|
||||
return 0;
|
||||
} else {
|
||||
// Still not there yet
|
||||
// Time in minutes
|
||||
return (long) Math.ceil((coolDownTime.getTimeInMillis() - timeNow.getTimeInMillis()) / (1000 * 60D));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the invite cooldown timer for location. Location should be the center of an island.
|
||||
* @param location - the location
|
||||
*/
|
||||
public void startInviteCoolDownTimer(Location location) {
|
||||
if (location != null) {
|
||||
kickedList.put(location, System.currentTimeMillis());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueId() {
|
||||
return uniqueId;
|
||||
|
@ -673,4 +673,5 @@ public class IslandWorldManager {
|
||||
public int getDeathsMax(World world) {
|
||||
return worldSettings.get(Util.getWorld(world)).getDeathsMax();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -315,32 +315,6 @@ public class PlayersManager {
|
||||
playerCache.get(playerUUID).setResets(world, resets);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns how long the player must wait before they can be invited to an
|
||||
* island with the location
|
||||
*
|
||||
* @param playerUUID - the player's UUID
|
||||
* @param location - the location
|
||||
* @return time to wait in minutes/hours
|
||||
*/
|
||||
public long getInviteCoolDownTime(UUID playerUUID, Location location) {
|
||||
addPlayer(playerUUID);
|
||||
return playerCache.get(playerUUID).getInviteCoolDownTime(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the timer for the player for this location before which they can
|
||||
* be invited
|
||||
* Called when they are kicked from an island or leave.
|
||||
*
|
||||
* @param playerUUID - the player's UUID
|
||||
* @param location - the location
|
||||
*/
|
||||
public void startInviteCoolDownTimer(UUID playerUUID, Location location) {
|
||||
addPlayer(playerUUID);
|
||||
playerCache.get(playerUUID).startInviteCoolDownTimer(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the locale for this player. If missing, will return nothing
|
||||
* @param playerUUID - the player's UUID
|
||||
|
@ -27,7 +27,6 @@ import org.powermock.reflect.Whitebox;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.commands.island.team.IslandTeamInviteCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
@ -49,6 +48,7 @@ public class IslandTeamInviteCommandTest {
|
||||
private IslandsManager im;
|
||||
private PlayersManager pm;
|
||||
private UUID notUUID;
|
||||
private Settings s;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -64,7 +64,7 @@ public class IslandTeamInviteCommandTest {
|
||||
when(plugin.getCommandsManager()).thenReturn(cm);
|
||||
|
||||
// Settings
|
||||
Settings s = mock(Settings.class);
|
||||
s = mock(Settings.class);
|
||||
when(s.getResetWait()).thenReturn(0L);
|
||||
|
||||
when(plugin.getSettings()).thenReturn(s);
|
||||
@ -211,4 +211,16 @@ public class IslandTeamInviteCommandTest {
|
||||
Mockito.verify(user).sendMessage(Mockito.eq("commands.island.team.invite.errors.already-on-team"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link IslandTeamInviteCommand#execute(world.bentobox.bentobox.api.user.User, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteCoolDownActive() {
|
||||
// 10 minutes = 600 seconds
|
||||
when(s.getInviteWait()).thenReturn(10);
|
||||
IslandTeamInviteCommand itl = new IslandTeamInviteCommand(ic);
|
||||
String[] name = {"tastybento"};
|
||||
itl.execute(user, itl.getLabel(), Arrays.asList(name));
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -32,7 +33,6 @@ import org.powermock.reflect.Whitebox;
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.api.commands.CompositeCommand;
|
||||
import world.bentobox.bentobox.api.commands.island.team.IslandTeamKickCommand;
|
||||
import world.bentobox.bentobox.api.user.User;
|
||||
import world.bentobox.bentobox.managers.CommandsManager;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
@ -57,6 +57,7 @@ public class IslandTeamKickCommandTest {
|
||||
private UUID notUUID;
|
||||
private IslandWorldManager iwm;
|
||||
private Player player;
|
||||
private CompositeCommand subCommand;
|
||||
|
||||
/**
|
||||
* @throws java.lang.Exception
|
||||
@ -95,6 +96,9 @@ public class IslandTeamKickCommandTest {
|
||||
// Parent command has no aliases
|
||||
ic = mock(CompositeCommand.class);
|
||||
when(ic.getSubCommandAliases()).thenReturn(new HashMap<>());
|
||||
subCommand = mock(CompositeCommand.class);
|
||||
Optional<CompositeCommand> optionalCommand = Optional.of(subCommand);
|
||||
when(ic.getSubCommand(Mockito.anyString())).thenReturn(optionalCommand);
|
||||
|
||||
// Player has island to begin with
|
||||
im = mock(IslandsManager.class);
|
||||
@ -266,4 +270,15 @@ public class IslandTeamKickCommandTest {
|
||||
Mockito.verify(enderChest).clear();
|
||||
Mockito.verify(inv).clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link IslandTeamKickCommand#execute(world.bentobox.bentobox.api.user.User, java.util.List)}.
|
||||
*/
|
||||
@Test
|
||||
public void testCooldown() {
|
||||
// 10 minutes = 600 seconds
|
||||
when(s.getInviteWait()).thenReturn(10);
|
||||
testExecuteNoConfirmation();
|
||||
Mockito.verify(subCommand).setCooldown(uuid, notUUID, 600);
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +121,6 @@ public class MySQLDatabaseHandlerTest {
|
||||
players.setHomeLocation(location, 2);
|
||||
Map<Location, Long> map = new HashMap<>();
|
||||
map.put(location, 324L);
|
||||
players.setKickedList(map);
|
||||
players.setLocale("sdfsd");
|
||||
players.setPlayerName("name");
|
||||
players.setPlayerUUID(UUID.randomUUID());
|
||||
|
@ -24,7 +24,6 @@ import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.powermock.reflect.Whitebox;
|
||||
|
||||
import world.bentobox.bentobox.BentoBox;
|
||||
import world.bentobox.bentobox.Settings;
|
||||
import world.bentobox.bentobox.managers.IslandWorldManager;
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@ -100,21 +99,4 @@ public class PlayersTest {
|
||||
assertTrue(p.getDeaths(world) == 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInviteCoolDownTime() throws InterruptedException {
|
||||
Settings settings = mock(Settings.class);
|
||||
when(settings.getInviteWait()).thenReturn(1);
|
||||
when(plugin.getSettings()).thenReturn(settings);
|
||||
Players p = new Players(plugin, UUID.randomUUID());
|
||||
// Check a null location
|
||||
assertTrue(p.getInviteCoolDownTime(null) == 0);
|
||||
// Real location
|
||||
Location l = mock(Location.class);
|
||||
// Should be no cooldown
|
||||
assertTrue(p.getInviteCoolDownTime(l) == 0);
|
||||
// Start the timer
|
||||
p.startInviteCoolDownTimer(l);
|
||||
// More than 0 cooldown
|
||||
assertTrue(p.getInviteCoolDownTime(l) > 0);
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user