From abd88c08263acc0f367ab0c3ad3e90090cd0effc Mon Sep 17 00:00:00 2001 From: tastybento Date: Sat, 6 Jul 2019 23:08:16 -0700 Subject: [PATCH] Adds a cooldown API for flags. (#821) * Adds a cooldown API for flags. https://github.com/BentoBoxWorld/BentoBox/issues/754 Added 60 second cooldown to PVP flags * Added cooldowns to database. This way, if a cooldown is a long one it will be remembered even if the server restarts. * Update src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer3.java --- .../bentobox/bentobox/api/flags/Flag.java | 26 +++++++++ .../clicklisteners/IslandToggleClick.java | 8 +++ .../bentobox/database/objects/Island.java | 47 +++++++++++++++ .../objects/adapters/FlagSerializer3.java | 57 +++++++++++++++++++ .../world/bentobox/bentobox/lists/Flags.java | 6 +- src/main/resources/locales/en-US.yml | 1 + .../mariadb/MariaDBDatabaseHandlerTest.java | 7 ++- .../mysql/MySQLDatabaseHandlerTest.java | 7 ++- 8 files changed, 150 insertions(+), 9 deletions(-) create mode 100644 src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer3.java diff --git a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java index 90daf5e68..33c1fb05d 100644 --- a/src/main/java/world/bentobox/bentobox/api/flags/Flag.java +++ b/src/main/java/world/bentobox/bentobox/api/flags/Flag.java @@ -77,6 +77,7 @@ public class Flag implements Comparable { private final boolean subPanel; private Set gameModes = new HashSet<>(); private final Addon addon; + private final int cooldown; private Flag(Builder builder) { this.id = builder.id; @@ -90,6 +91,7 @@ public class Flag implements Comparable { if (builder.gameModeAddon != null) { this.gameModes.add(builder.gameModeAddon); } + this.cooldown = builder.cooldown; this.addon = builder.addon; } @@ -105,6 +107,13 @@ public class Flag implements Comparable { return Optional.ofNullable(listener); } + /** + * @return the cooldown + */ + public int getCooldown() { + return cooldown; + } + /** * Check if a setting is set in this world * @param world - world @@ -322,6 +331,9 @@ public class Flag implements Comparable { : user.getTranslation("protection.panel.flag-item.setting-disabled"); pib.description(user.getTranslation("protection.panel.flag-item.setting-layout", TextVariables.DESCRIPTION, user.getTranslation(getDescriptionReference()) , "[setting]", islandSetting)); + if (this.cooldown > 0 && island.isCooldown(this)) { + pib.description(user.getTranslation("protection.panel.flag-item.setting-cooldown")); + } } return pib; } @@ -384,6 +396,9 @@ public class Flag implements Comparable { private GameModeAddon gameModeAddon; private Addon addon; + // Cooldown + private int cooldown; + /** * Builder for making flags * @param id - a unique id that MUST be the same as the enum of the flag @@ -476,6 +491,17 @@ public class Flag implements Comparable { return this; } + /** + * Set a cooldown for {@link Type#SETTING} flag. Only applicable for settings. + * @param cooldown in seconds + * @return Builder + * @since 1.6.0 + */ + public Builder cooldown(int cooldown) { + this.cooldown = cooldown; + return this; + } + /** * Build the flag * @return Flag diff --git a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java index a1327ace0..7b09fc2a3 100644 --- a/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java +++ b/src/main/java/world/bentobox/bentobox/api/flags/clicklisteners/IslandToggleClick.java @@ -61,9 +61,17 @@ public class IslandToggleClick implements ClickHandler { // Save changes plugin.getIWM().getAddon(user.getWorld()).ifPresent(GameModeAddon::saveWorldSettings); } else { + // Check cooldown + if (!user.isOp() && island.isCooldown(flag)) { + user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_BEACON_DEACTIVATE, 1F, 1F); + user.notify("protection.panel.flag-item.setting-cooldown"); + return; + } // Toggle flag island.toggleFlag(flag); user.getPlayer().playSound(user.getLocation(), Sound.BLOCK_STONE_BUTTON_CLICK_ON, 1F, 1F); + // Set cooldown + island.setCooldown(flag); } // Apply change to panel panel.getInventory().setItem(slot, flag.toPanelItem(plugin, user, invisible).getItem()); diff --git a/src/main/java/world/bentobox/bentobox/database/objects/Island.java b/src/main/java/world/bentobox/bentobox/database/objects/Island.java index e8b4a7cb4..6511b95b4 100644 --- a/src/main/java/world/bentobox/bentobox/database/objects/Island.java +++ b/src/main/java/world/bentobox/bentobox/database/objects/Island.java @@ -35,6 +35,7 @@ import world.bentobox.bentobox.api.logs.LogEntry; import world.bentobox.bentobox.api.user.User; import world.bentobox.bentobox.database.objects.adapters.Adapter; import world.bentobox.bentobox.database.objects.adapters.FlagSerializer; +import world.bentobox.bentobox.database.objects.adapters.FlagSerializer3; import world.bentobox.bentobox.database.objects.adapters.LogEntryListAdapter; import world.bentobox.bentobox.lists.Flags; import world.bentobox.bentobox.managers.IslandWorldManager; @@ -146,6 +147,13 @@ public class Island implements DataObject { @Expose private boolean doNotLoad; + /** + * Used to store flag cooldowns for this island + */ + @Adapter(FlagSerializer3.class) + @Expose + private Map cooldowns = new HashMap<>(); + public Island() {} public Island(@NonNull Location location, UUID owner, int protectionRange) { @@ -1049,6 +1057,43 @@ public class Island implements DataObject { !getCenter().toVector().toLocation(iwm.getEndWorld(getWorld())).getBlock().getType().equals(Material.AIR); } + + /** + * Checks if a flag is on cooldown. Only stored in memory so a server restart will reset the cooldown. + * @param flag - flag + * @return true if on cooldown, false if not + * @since 1.6.0 + */ + public boolean isCooldown(Flag flag) { + if (cooldowns.containsKey(flag) && cooldowns.get(flag) > System.currentTimeMillis()) { + return true; + } + cooldowns.remove(flag); + return false; + } + + /** + * Sets a cooldown for this flag on this island. + * @param flag - Flag to cooldown + */ + public void setCooldown(Flag flag) { + cooldowns.put(flag, flag.getCooldown() * 1000 + System.currentTimeMillis()); + } + + /** + * @return the cooldowns + */ + public Map getCooldowns() { + return cooldowns; + } + + /** + * @param cooldowns the cooldowns to set + */ + public void setCooldowns(Map cooldowns) { + this.cooldowns = cooldowns; + } + /* (non-Javadoc) * @see java.lang.Object#toString() */ @@ -1061,4 +1106,6 @@ public class Island implements DataObject { + ", purgeProtected=" + purgeProtected + ", flags=" + flags + ", history=" + history + ", levelHandicap=" + levelHandicap + ", spawnPoint=" + spawnPoint + ", doNotLoad=" + doNotLoad + "]"; } + + } diff --git a/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer3.java b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer3.java new file mode 100644 index 000000000..7ef181eeb --- /dev/null +++ b/src/main/java/world/bentobox/bentobox/database/objects/adapters/FlagSerializer3.java @@ -0,0 +1,57 @@ +package world.bentobox.bentobox.database.objects.adapters; + +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.bukkit.configuration.MemorySection; + +import world.bentobox.bentobox.BentoBox; +import world.bentobox.bentobox.api.flags.Flag; + +/** + * Serializes the {@link world.bentobox.bentobox.database.objects.Island#getFlags() getFlags()} and + * {@link world.bentobox.bentobox.database.objects.Island#setFlags(Map)} () setFlags()} + * in {@link world.bentobox.bentobox.database.objects.Island} + * @author tastybento + * @since 1.6.0 + */ +public class FlagSerializer3 implements AdapterInterface, Map> { + + @SuppressWarnings("unchecked") + @Override + public Map deserialize(Object object) { + Map result = new HashMap<>(); + if (object == null) { + return result; + } + // For YAML + if (object instanceof MemorySection) { + MemorySection section = (MemorySection) object; + for (String key : section.getKeys(false)) { + BentoBox.getInstance().getFlagsManager().getFlag(key).ifPresent(flag -> result.put(flag, section.getLong(key))); + } + } else { + for (Entry en : ((Map)object).entrySet()) { + BentoBox.getInstance().getFlagsManager().getFlag(en.getKey()).ifPresent(flag -> result.put(flag, en.getValue())); + } + } + return result; + } + + @SuppressWarnings("unchecked") + @Override + public Map serialize(Object object) { + Map result = new HashMap<>(); + if (object == null) { + return result; + } + Map flags = (Map)object; + for (Entry en: flags.entrySet()) { + if (en != null && en.getKey() != null) { + result.put(en.getKey().getID(), en.getValue()); + } + } + return result; + } +} diff --git a/src/main/java/world/bentobox/bentobox/lists/Flags.java b/src/main/java/world/bentobox/bentobox/lists/Flags.java index bbac6d0aa..516308986 100644 --- a/src/main/java/world/bentobox/bentobox/lists/Flags.java +++ b/src/main/java/world/bentobox/bentobox/lists/Flags.java @@ -256,11 +256,11 @@ public final class Flags { */ // PVP public static final Flag PVP_OVERWORLD = new Flag.Builder("PVP_OVERWORLD", Material.ARROW).type(Type.SETTING) - .defaultRank(DISABLED).listener(new PVPListener()).build(); + .defaultRank(DISABLED).listener(new PVPListener()).cooldown(60).build(); public static final Flag PVP_NETHER = new Flag.Builder("PVP_NETHER", Material.IRON_AXE).type(Type.SETTING) - .defaultRank(DISABLED).build(); + .defaultRank(DISABLED).cooldown(60).build(); public static final Flag PVP_END = new Flag.Builder("PVP_END", Material.END_CRYSTAL).type(Type.SETTING) - .defaultRank(DISABLED).build(); + .defaultRank(DISABLED).cooldown(60).build(); // Fire /** diff --git a/src/main/resources/locales/en-US.yml b/src/main/resources/locales/en-US.yml index a3f9e5a57..9bd1ae3b4 100644 --- a/src/main/resources/locales/en-US.yml +++ b/src/main/resources/locales/en-US.yml @@ -1053,6 +1053,7 @@ protection: blocked-rank: "&3- &c" minimal-rank: "&3- &2" menu-layout: "&a[description]" + setting-cooldown: "&cSetting is on cooldown" setting-layout: | &a[description] diff --git a/src/test/java/world/bentobox/bentobox/database/mariadb/MariaDBDatabaseHandlerTest.java b/src/test/java/world/bentobox/bentobox/database/mariadb/MariaDBDatabaseHandlerTest.java index c89672c56..3ef7365a8 100644 --- a/src/test/java/world/bentobox/bentobox/database/mariadb/MariaDBDatabaseHandlerTest.java +++ b/src/test/java/world/bentobox/bentobox/database/mariadb/MariaDBDatabaseHandlerTest.java @@ -22,7 +22,6 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.PluginManager; import org.bukkit.scheduler.BukkitScheduler; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -60,7 +59,8 @@ public class MariaDBDatabaseHandlerTest { " \"history\": [],\n" + " \"levelHandicap\": 0,\n" + " \"spawnPoint\": {},\n" + - " \"doNotLoad\": false\n" + + " \"doNotLoad\": false,\n" + + " \"cooldowns\": {}\n" + "}"; private MariaDBDatabaseHandler handler; private Island instance; @@ -279,7 +279,8 @@ public class MariaDBDatabaseHandlerTest { " \"history\": [],\n" + " \"levelHandicap\": 0,\n" + " \"spawnPoint\": {},\n" + - " \"doNotLoad\": false\n" + + " \"doNotLoad\": false,\n" + + " \"cooldowns\": {}\n" + "}"); } diff --git a/src/test/java/world/bentobox/bentobox/database/mysql/MySQLDatabaseHandlerTest.java b/src/test/java/world/bentobox/bentobox/database/mysql/MySQLDatabaseHandlerTest.java index a88155e2b..867627b15 100644 --- a/src/test/java/world/bentobox/bentobox/database/mysql/MySQLDatabaseHandlerTest.java +++ b/src/test/java/world/bentobox/bentobox/database/mysql/MySQLDatabaseHandlerTest.java @@ -22,7 +22,6 @@ import org.bukkit.Bukkit; import org.bukkit.plugin.PluginManager; import org.bukkit.scheduler.BukkitScheduler; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -59,7 +58,8 @@ public class MySQLDatabaseHandlerTest { " \"history\": [],\n" + " \"levelHandicap\": 0,\n" + " \"spawnPoint\": {},\n" + - " \"doNotLoad\": false\n" + + " \"doNotLoad\": false,\n" + + " \"cooldowns\": {}\n" + "}"; private MySQLDatabaseHandler handler; private Island instance; @@ -278,7 +278,8 @@ public class MySQLDatabaseHandlerTest { " \"history\": [],\n" + " \"levelHandicap\": 0,\n" + " \"spawnPoint\": {},\n" + - " \"doNotLoad\": false\n" + + " \"doNotLoad\": false,\n" + + " \"cooldowns\": {}\n" + "}"); }