diff --git a/resources/config.yml b/resources/config.yml
index bf9dd77..f8abd1c 100644
--- a/resources/config.yml
+++ b/resources/config.yml
@@ -26,11 +26,18 @@ MaxSize: 6
# AllowedGameModes: [ "SURVIVAL", "ADVENTURE" ]
AllowedGameModes: [ "SURVIVAL" ]
-# Defines how long a player have to wait till he can reopen his backpack.
-# Time is in seconds. Values < 1 disable the cooldown.
-CommandCooldown: -1
-# If enabled whe cooldown will be synced between servers (BungeeCord network). It will also prevent players from leaving and joining to bypass the cooldown.
-SyncCooldown: false
+Cooldown:
+ # Defines how long a player have to wait till he can reopen his backpack.
+ # Time is in seconds. Values < 1 disable the cooldown.
+ Command: -1
+ # If enabled whe cooldown will be synced between servers (BungeeCord network). It will also allow to keep cooldown through server restarts.
+ # You should only use it with long lasting cooldowns.
+ Sync: false
+ AddOnJoin: true
+ # You can turn this on when using sync to reduce the memory consumption a little bit
+ ClearOnLeave: false
+ # Removes old cooldowns from the cache to free memory. Time in seconds.
+ CleanupInterval: 600
# Controls for the auto pickup on full inventory function
FullInventory:
diff --git a/resources/lang/en.yml b/resources/lang/en.yml
index 2de96a1..eb31c11 100644
--- a/resources/lang/en.yml
+++ b/resources/lang/en.yml
@@ -11,8 +11,8 @@ Language:
InvalidBackpack: "Invalid backpack."
NotAllowedInBackpack: "&c{ItemName} is not allowed in the backpack."
Open:
- #Parameter: {TimeLeft} time in seconds till he can reopen his backpack
- Cooldown: "&2Please wait {TimeLeft} seconds till you reopen your backpack."
+ #Parameter: {TimeLeft} time in seconds till he can reopen his backpack, {TimeSpanLeft}
+ Cooldown: "&2Please wait {TimeSpanLeft} seconds till you reopen your backpack."
#Parameter: {CurrentGameMode}, {AllowedGameModes}
WrongGameMode: "You are not allowed to open your backpack in your current game-mode."
Clean:
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Backpack.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Backpack.java
index 9f0c36d..6acff16 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Backpack.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Backpack.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2016, 2017 GeorgH93
+ * Copyright (C) 2016-2018 GeorgH93
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Command/OpenCommand.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Command/OpenCommand.java
index c36bbb3..6926d1b 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Command/OpenCommand.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Command/OpenCommand.java
@@ -18,6 +18,7 @@
package at.pcgamingfreaks.Minepacks.Bukkit.Command;
import at.pcgamingfreaks.Bukkit.Message.Message;
+import at.pcgamingfreaks.Calendar.TimeSpan;
import at.pcgamingfreaks.Command.HelpData;
import at.pcgamingfreaks.Minepacks.Bukkit.API.MinepacksCommand;
import at.pcgamingfreaks.Minepacks.Bukkit.Minepacks;
@@ -35,8 +36,6 @@ public class OpenCommand extends MinepacksCommand
{
private final Message messageCooldown, messageWrongGameMode;
private final String allowedGameModes, descriptionOpenOthers, helpParam;
- private final long cooldown;
- private final boolean syncCooldown;
private final Minepacks plugin;
public OpenCommand(Minepacks plugin)
@@ -44,14 +43,11 @@ public OpenCommand(Minepacks plugin)
super(plugin, "open", plugin.getLanguage().getTranslated("Commands.Description.Backpack"), "backpack.use", true, plugin.getLanguage().getCommandAliases("Open"));
this.plugin = plugin;
- messageCooldown = plugin.getLanguage().getMessage("Ingame.Open.Cooldown").replaceAll("\\{TimeLeft}", "%1\\$.1f");
- messageWrongGameMode = plugin.getLanguage().getMessage("Ingame.Open.WrongGameMode").replaceAll("\\{CurrentGameMode}", "%1\\$s").replaceAll("\\{AllowedGameModes}", "%1\\$s");
+ messageCooldown = plugin.getLanguage().getMessage("Ingame.Open.Cooldown").replaceAll("\\{TimeLeft}", "%1\\$.1f").replaceAll("\\{TimeSpanLeft}", "%2\\$s");
+ messageWrongGameMode = plugin.getLanguage().getMessage("Ingame.Open.WrongGameMode").replaceAll("\\{CurrentGameMode}", "%1\\$s").replaceAll("\\{AllowedGameModes}", "%1\\$s");
descriptionOpenOthers = plugin.getLanguage().getTranslated("Commands.Description.OpenOthers");
helpParam = "<" + plugin.getLanguage().get("Commands.PlayerNameVariable") + ">";
- cooldown = plugin.getConfiguration().getCommandCooldown();
- syncCooldown = plugin.getConfiguration().isCommandCooldownSyncEnabled();
-
StringBuilder allowedGameModesBuilder = new StringBuilder();
for(GameMode gameMode : plugin.getConfiguration().getAllowedGameModes())
{
@@ -72,24 +68,16 @@ public void execute(@NotNull CommandSender sender, @NotNull String main, @NotNul
{
if(getMinepacksPlugin().isPlayerGameModeAllowed(player))
{
- if(cooldown > 0 && !player.hasPermission("backpack.noCooldown"))
+ if(plugin.getCooldownManager() != null && !player.hasPermission("backpack.noCooldown"))
{
- if(plugin.cooldowns.containsKey(player.getUniqueId()))
+ long cd = plugin.getCooldownManager().getRemainingCooldown(player);
+ if(cd > 0)
{
- long cd = plugin.cooldowns.get(player.getUniqueId());
- if(cd < System.currentTimeMillis())
- {
- cd = cd - System.currentTimeMillis();
- messageCooldown.send(sender, cd / 1000f);
- return;
- }
+ TimeSpan ts = new TimeSpan(cd, true);
+ messageCooldown.send(sender, cd / 1000f, ts.toString());
+ return;
}
- final long cooldownTime = System.currentTimeMillis() + cooldown;
- if(syncCooldown)
- {
- plugin.getDatabase().syncCooldown(player, cooldownTime);
- }
- plugin.cooldowns.put(player.getUniqueId(), cooldownTime);
+ plugin.getCooldownManager().setCooldown(player);
}
plugin.openBackpack(player, player, true);
}
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/CooldownManager.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/CooldownManager.java
new file mode 100644
index 0000000..d2881d5
--- /dev/null
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/CooldownManager.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 GeorgH93
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package at.pcgamingfreaks.Minepacks.Bukkit;
+
+import at.pcgamingfreaks.Minepacks.Bukkit.API.Callback;
+
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.EventPriority;
+import org.bukkit.event.HandlerList;
+import org.bukkit.event.Listener;
+import org.bukkit.event.player.PlayerJoinEvent;
+import org.bukkit.event.player.PlayerQuitEvent;
+import org.bukkit.scheduler.BukkitRunnable;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+public class CooldownManager extends BukkitRunnable implements Listener
+{
+ private final Minepacks plugin;
+ private final Map cooldowns = new HashMap<>();
+ private final long cooldown;
+ private final boolean syncCooldown, addOnJoin, clearOnLeave;
+
+ public CooldownManager(Minepacks plugin)
+ {
+ this.plugin = plugin;
+
+ cooldown = plugin.getConfiguration().getCommandCooldown();
+ syncCooldown = plugin.getConfiguration().isCommandCooldownSyncEnabled();
+ addOnJoin = plugin.getConfiguration().isCommandCooldownAddOnJoinEnabled();
+ clearOnLeave = plugin.getConfiguration().isCommandCooldownClearOnLeaveEnabled();
+ plugin.getServer().getPluginManager().registerEvents(this, plugin);
+
+ runTaskTimer(plugin, plugin.getConfiguration().getCommandCooldownCleanupInterval(), plugin.getConfiguration().getCommandCooldownCleanupInterval());
+ }
+
+ public void close()
+ {
+ cancel();
+ HandlerList.unregisterAll(this);
+ }
+
+ public void setCooldown(Player player)
+ {
+ final long cooldownTime = System.currentTimeMillis() + cooldown;
+ if(syncCooldown)
+ {
+ plugin.getDatabase().syncCooldown(player, cooldownTime);
+ }
+ cooldowns.put(player.getUniqueId(), cooldownTime);
+ }
+
+ @SuppressWarnings("unused")
+ public boolean isInCooldown(Player player)
+ {
+ return cooldowns.getOrDefault(player.getUniqueId(), 0L) > System.currentTimeMillis();
+ }
+
+ public long getRemainingCooldown(Player player)
+ {
+ long cd = cooldowns.getOrDefault(player.getUniqueId(), 0L);
+ if(cd > System.currentTimeMillis())
+ {
+ return cd - System.currentTimeMillis();
+ }
+ return 0;
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerJoinEvent(PlayerJoinEvent event)
+ {
+ if(syncCooldown)
+ {
+ final UUID uuid = event.getPlayer().getUniqueId();
+ cooldowns.put(uuid, System.currentTimeMillis() + cooldown); // Temporary cooldown till the data is loaded from the database
+ plugin.getDatabase().getCooldown(event.getPlayer(), new Callback() {
+ @Override
+ public void onResult(Long dbCooldownTime)
+ {
+ if(dbCooldownTime > System.currentTimeMillis())
+ {
+ cooldowns.put(uuid, dbCooldownTime);
+ }
+ }
+
+ @Override
+ public void onFail() {}
+ });
+ }
+ else if(addOnJoin)
+ {
+ setCooldown(event.getPlayer());
+ }
+ }
+
+ @EventHandler(priority = EventPriority.MONITOR)
+ public void onPlayerLeaveEvent(PlayerQuitEvent event)
+ {
+ if(clearOnLeave) cooldowns.remove(event.getPlayer().getUniqueId());
+ }
+
+ @Override
+ public void run()
+ {
+ cooldowns.entrySet().removeIf(entry -> entry.getValue() < System.currentTimeMillis());
+ }
+}
\ No newline at end of file
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Config.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Config.java
index efd0630..c16cd47 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Config.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Config.java
@@ -198,12 +198,27 @@ public boolean isBungeeCordModeEnabled()
public long getCommandCooldown()
{
- return getConfig().getInt("CommandCooldown", -1) * 1000L;
+ return getConfig().getInt("Cooldown.Command", -1) * 1000L;
}
public boolean isCommandCooldownSyncEnabled()
{
- return getConfig().getBoolean("SyncCooldown", false);
+ return getConfig().getBoolean("Cooldown.Sync", false);
+ }
+
+ public boolean isCommandCooldownClearOnLeaveEnabled()
+ {
+ return getConfig().getBoolean("Cooldown.ClearOnLeave", false);
+ }
+
+ public boolean isCommandCooldownAddOnJoinEnabled()
+ {
+ return getConfig().getBoolean("Cooldown.AddOnJoin", true);
+ }
+
+ public long getCommandCooldownCleanupInterval()
+ {
+ return getConfig().getInt("Cooldown.CleanupInterval", 600) * 20L;
}
public Collection getAllowedGameModes()
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Database.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Database.java
index 83f3b25..f370a5a 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Database.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Database.java
@@ -222,7 +222,9 @@ public void updatePlayerAndLoadBackpack(Player player)
public abstract void saveBackpack(Backpack backpack);
- public abstract void syncCooldown(Player player, long time);
+ public void syncCooldown(Player player, long time) {}
+
+ public void getCooldown(final Player player, final Callback callback) {}
protected abstract void loadBackpack(final OfflinePlayer player, final Callback callback);
}
\ No newline at end of file
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Files.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Files.java
index 5b30870..3c530b0 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Files.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Files.java
@@ -143,12 +143,6 @@ public void saveBackpack(Backpack backpack)
}
}
- @Override
- public void syncCooldown(Player player, long time)
- {
- // There is no reason for cooldown syncing in file mode
- }
-
@Override
protected void loadBackpack(final OfflinePlayer player, final Callback callback)
{
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Helper/OldFileUpdater.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Helper/OldFileUpdater.java
index 712ed4f..73d5800 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Helper/OldFileUpdater.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/Helper/OldFileUpdater.java
@@ -41,8 +41,8 @@ public static void updateConfig(YAML oldYAML, YAML newYAML)
}
switch(key)
{
- case "CommandCooldown": oldKey = "command_cooldown"; break;
- case "SyncCooldown": oldKey = "sync_cooldown"; break;
+ case "Cooldown.Command": oldKey = "command_cooldown"; break;
+ case "Cooldown.Sync": oldKey = "sync_cooldown"; break;
case "DropOnDeath": oldKey = "drop_on_death"; break;
case "MaxSize": oldKey = "max_size"; break;
case "AllowedGameModes": oldKey = "allowed_game_modes"; break;
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/SQL.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/SQL.java
index 141ae18..31ea80f 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/SQL.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Database/SQL.java
@@ -40,7 +40,7 @@
import java.util.*;
public abstract class SQL extends Database
-{ //TODO load cooldown
+{
private HikariDataSource dataSource;
protected String tablePlayers, tableBackpacks, tableCooldowns; // Table Names
@@ -212,6 +212,7 @@ protected final void buildQuerys()
queryGetPlayerID = "SELECT {FieldPlayerID} FROM {TablePlayers} WHERE {FieldUUID}=?;";
queryGetBP += "{FieldUUID}=?;";
querySyncCooldown = "INSERT INTO {TableCooldowns} ({FieldCDPlayer},{FieldCDTime}) SELECT {FieldPlayerID},? FROM {TablePlayers} WHERE {FieldUUID}=?;";
+ queryGetCooldown = "SELECT * FROM {TableCooldowns} WHERE {FieldCDPlayer} IN (SELECT {FieldPlayerID} FROM {TablePlayers} WHERE {FieldUUID}=?);";
}
else
{
@@ -219,6 +220,7 @@ protected final void buildQuerys()
queryGetPlayerID = "SELECT {FieldPlayerID} FROM {TablePlayers} WHERE {FieldName}=?;";
queryGetBP += "{FieldName}=?;";
querySyncCooldown = "INSERT INTO {TableCooldowns} ({FieldCDPlayer},{FieldCDTime}) SELECT {FieldPlayerID},? FROM {TablePlayers} WHERE {FieldName}=?;";
+ queryGetCooldown = "SELECT * FROM {TableCooldowns} WHERE {FieldCDPlayer} IN (SELECT {FieldPlayerID} FROM {TablePlayers} WHERE {FieldName}=?);";
}
queryInsertBp = "REPLACE INTO {TableBackpacks} ({FieldBPOwner},{FieldBPITS},{FieldBPVersion}) VALUES (?,?,?);";
queryUpdateBp = "UPDATE {TableBackpacks} SET {FieldBPITS}=?,{FieldBPVersion}=?,{FieldBPLastUpdate}={NOW} WHERE {FieldBPOwner}=?;";
@@ -251,6 +253,7 @@ protected void setTableAndFieldNames()
queryDeleteOldBackpacks = replacePlaceholders(queryDeleteOldBackpacks.replaceAll("\\{VarMaxAge}", maxAge + ""));
queryGetUnsetOrInvalidUUIDs = replacePlaceholders(queryGetUnsetOrInvalidUUIDs);
querySyncCooldown = replacePlaceholders(querySyncCooldown);
+ queryGetCooldown = replacePlaceholders(queryGetCooldown);
queryDeleteOldCooldowns = replacePlaceholders(queryDeleteOldCooldowns);
}
@@ -320,7 +323,7 @@ public void saveBackpack(final Backpack backpack)
{
if(rs.next())
{
- final int newID = rs.getInt(1);
+ final int newID = rs.getInt(fieldPlayerID);
DBTools.runStatement(connection, queryInsertBp, newID, data, usedSerializer);
plugin.getServer().getScheduler().runTask(plugin, () -> backpack.setOwnerID(newID));
}
@@ -374,9 +377,9 @@ protected void loadBackpack(final OfflinePlayer player, final Callback
{
if(rs.next())
{
- bpID = rs.getInt(1);
- version = rs.getInt(3);
- data = rs.getBytes(2);
+ bpID = rs.getInt(fieldBpOwner);
+ version = rs.getInt(fieldBpVersion);
+ data = rs.getBytes(fieldBpIts);
}
else
{
@@ -410,4 +413,25 @@ public void syncCooldown(Player player, long cooldownTime)
{
runStatementAsync(querySyncCooldown, new Timestamp(cooldownTime), getPlayerNameOrUUID(player));
}
+
+ @Override
+ public void getCooldown(final Player player, final Callback callback)
+ {
+ plugin.getServer().getScheduler().runTaskAsynchronously(plugin, () -> {
+ try(Connection conn = getConnection(); PreparedStatement ps = conn.prepareStatement(queryGetCooldown))
+ {
+ ps.setString(1, getPlayerNameOrUUID(player));
+ try(ResultSet rs = ps.executeQuery())
+ {
+ final long time = (rs.next()) ? rs.getLong(fieldCdTime) : 0;
+ plugin.getServer().getScheduler().runTask(plugin, () -> callback.onResult(time));
+ }
+ }
+ catch(SQLException e)
+ {
+ e.printStackTrace();
+ plugin.getServer().getScheduler().runTask(plugin, () -> callback.onResult(0L));
+ }
+ });
+ }
}
\ No newline at end of file
diff --git a/src/at/pcgamingfreaks/Minepacks/Bukkit/Minepacks.java b/src/at/pcgamingfreaks/Minepacks/Bukkit/Minepacks.java
index b8aa15a..42da5b4 100644
--- a/src/at/pcgamingfreaks/Minepacks/Bukkit/Minepacks.java
+++ b/src/at/pcgamingfreaks/Minepacks/Bukkit/Minepacks.java
@@ -55,9 +55,6 @@
import java.io.File;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
public class Minepacks extends JavaPlugin implements MinepacksPlugin
{
@@ -69,8 +66,6 @@ public class Minepacks extends JavaPlugin implements MinepacksPlugin
private Language lang;
private Database database;
- public final Map cooldowns = new HashMap<>();
-
public String backpackTitleOther = "%s Backpack", backpackTitle = "Backpack";
public Message messageNoPermission, messageInvalidBackpack, messageWorldDisabled, messageNotFromConsole;
@@ -80,6 +75,7 @@ public class Minepacks extends JavaPlugin implements MinepacksPlugin
private ItemsCollector collector;
private CommandManager commandManager;
private Collection gameModes;
+ private CooldownManager cooldownManager = null;
public static Minepacks getInstance()
{
@@ -194,6 +190,7 @@ private void load()
}
gameModes = config.getAllowedGameModes();
+ if(config.getCommandCooldown() > 0) cooldownManager = new CooldownManager(this);
}
private void unload()
@@ -204,7 +201,8 @@ private void unload()
HandlerList.unregisterAll(this); // Stop the listeners
getServer().getScheduler().cancelTasks(this); // Kill all running task
database.close(); // Close the DB connection, we won't need them any longer
- cooldowns.clear();
+ if(cooldownManager != null) cooldownManager.close();
+ cooldownManager = null;
}
public void reload()
@@ -328,4 +326,9 @@ public boolean isPlayerGameModeAllowed(Player player)
{
return gameModes.contains(player.getGameMode()) || player.hasPermission("backpack.ignoreGameMode");
}
+
+ public @Nullable CooldownManager getCooldownManager()
+ {
+ return cooldownManager;
+ }
}
\ No newline at end of file