diff --git a/.gitignore b/.gitignore index 3eea975..738cfa4 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,7 @@ buildNumber.properties .classpath .project .settings/* + +# IntelliJ +.idea/ +*.iml diff --git a/pom.xml b/pom.xml index 60ba58d..51944cc 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,13 @@ io.minimum.minecraft SuperbVote - 0.5.5 + 0.6.1-CORP + + + UTF-8 + 21 + 21 + @@ -16,19 +22,10 @@ - - org.apache.maven.plugins - maven-compiler-plugin - 3.1 - - 1.8 - 1.8 - - org.apache.maven.plugins maven-shade-plugin - 2.3 + 3.6.0 @@ -40,6 +37,13 @@ io.minimum.minecraft.superbvote.slf4j + + + + maven + + + @@ -59,7 +63,7 @@ clip-repo - http://repo.extendedclip.com/content/repositories/placeholderapi/ + https://repo.extendedclip.com/content/repositories/placeholderapi/ bintray-nuvotifier-repo @@ -75,38 +79,48 @@ org.spigotmc spigot-api - 1.14-R0.1-SNAPSHOT + 1.19-R0.1-SNAPSHOT provided org.projectlombok lombok - 1.18.0 + 1.18.36 provided - com.github.NuVotifier.NuVotifier - nuvotifier-bukkit - v2.6.0 + com.github.NuVotifier + NuVotifier + 2.7.2 provided com.zaxxer HikariCP - 2.7.6 + 5.0.1 compile me.clip placeholderapi - 2.8.2 + 2.11.2 provided com.github.MilkBowl VaultAPI - 1.7 + 1.7.1 provided + + org.apache.commons + commons-lang3 + 3.12.0 + + + com.fasterxml.jackson.core + jackson-databind + 2.18.1 + - \ No newline at end of file + diff --git a/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java b/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java index 047df05..22b86ec 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java +++ b/src/main/java/io/minimum/minecraft/superbvote/SuperbVote.java @@ -75,8 +75,7 @@ public void onEnable() { } getCommand("superbvote").setExecutor(new SuperbVoteCommand()); - getCommand("vote").setExecutor(configuration.getVoteCommand()); - getCommand("votestreak").setExecutor(configuration.getVoteStreakCommand()); + registerCommands(); getServer().getPluginManager().registerEvents(new SuperbVoteListener(), this); getServer().getPluginManager().registerEvents(new TopPlayerSignListener(), this); @@ -124,8 +123,7 @@ public void reloadPlugin() { scoreboardHandler.reload(); voteServiceCooldown = new VoteServiceCooldown(getConfig().getInt("votes.cooldown-per-service", 3600)); getServer().getScheduler().runTaskAsynchronously(this, getScoreboardHandler()::doPopulate); - getCommand("vote").setExecutor(configuration.getVoteCommand()); - getCommand("votestreak").setExecutor(configuration.getVoteStreakCommand()); + registerCommands(); if (voteReminderTask != null) { voteReminderTask.cancel(); @@ -141,4 +139,13 @@ public void reloadPlugin() { public ClassLoader _exposeClassLoader() { return getClassLoader(); } + + private void registerCommands() { + if (configuration.getVoteCommand() != null) { + getCommand("vote").setExecutor(configuration.getVoteCommand()); + } + if (configuration.getVoteStreakCommand() != null) { + getCommand("votestreak").setExecutor(configuration.getVoteStreakCommand()); + } + } } diff --git a/src/main/java/io/minimum/minecraft/superbvote/configuration/SuperbVoteConfiguration.java b/src/main/java/io/minimum/minecraft/superbvote/configuration/SuperbVoteConfiguration.java index 8923d03..6c7b0aa 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/configuration/SuperbVoteConfiguration.java +++ b/src/main/java/io/minimum/minecraft/superbvote/configuration/SuperbVoteConfiguration.java @@ -202,6 +202,11 @@ public VoteStorage initializeVoteStorage() throws IOException { file = "votes.json"; SuperbVote.getPlugin().getLogger().info("No file found in configuration, using 'votes.json'."); } + if (configuration.getBoolean("votes.one-vote-per-day")) { + SuperbVote.getPlugin().getLogger() + .warning("votes.one-vote-per-day=true is not fully supported with JSON storage! " + + "Use mysql instead if you need this feature to work properly."); + } return new JsonVoteStorage(new File(SuperbVote.getPlugin().getDataFolder(), file)); case "mysql": String host = configuration.getString("storage.mysql.host", "localhost"); diff --git a/src/main/java/io/minimum/minecraft/superbvote/storage/JsonVoteStorage.java b/src/main/java/io/minimum/minecraft/superbvote/storage/JsonVoteStorage.java index cc28dcf..115577b 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/storage/JsonVoteStorage.java +++ b/src/main/java/io/minimum/minecraft/superbvote/storage/JsonVoteStorage.java @@ -90,7 +90,7 @@ private VotingFile migrateOldVersion(Map votes) throws IOExceptio } @Override - public void addVote(Vote vote) { + public void addVote(Vote vote, PlayerVotes playerVotes) { Preconditions.checkNotNull(vote, "vote"); rwl.writeLock().lock(); try { @@ -143,8 +143,10 @@ public PlayerVotes getVotes(UUID player) { rwl.readLock().lock(); try { PlayerRecord pr = voteCounts.get(player); - return new PlayerVotes(player, pr != null ? pr.lastKnownUsername : null, pr == null ? 0 : pr.votes, - PlayerVotes.Type.CURRENT); + if (pr == null) { + return new PlayerVotes(player, null, 0, Collections.emptyMap(), PlayerVotes.Type.CURRENT); + } + return new PlayerVotes(player, pr.lastKnownUsername, pr.votes, Collections.emptyMap(), PlayerVotes.Type.CURRENT); } finally { rwl.readLock().unlock(); } @@ -160,7 +162,9 @@ public List getTopVoters(int amount, int page) { .sorted(Collections.reverseOrder(Comparator.comparing(Map.Entry::getValue))) .skip(skip) .limit(amount) - .map(e -> new PlayerVotes(e.getKey(), e.getValue().lastKnownUsername, e.getValue().votes, PlayerVotes.Type.CURRENT)) + .map(e -> new PlayerVotes(e.getKey(), e.getValue().lastKnownUsername, e.getValue().votes, + Collections.emptyMap(), + PlayerVotes.Type.CURRENT)) .collect(Collectors.toList()); } finally { rwl.readLock().unlock(); diff --git a/src/main/java/io/minimum/minecraft/superbvote/storage/MysqlVoteStorage.java b/src/main/java/io/minimum/minecraft/superbvote/storage/MysqlVoteStorage.java index ad5c569..0eee25b 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/storage/MysqlVoteStorage.java +++ b/src/main/java/io/minimum/minecraft/superbvote/storage/MysqlVoteStorage.java @@ -29,7 +29,8 @@ public class MysqlVoteStorage implements ExtendedVoteStorage { private static final int TABLE_VERSION_2 = 2; private static final int TABLE_VERSION_3 = 3; private static final int TABLE_VERSION_4 = 4; - private static final int TABLE_VERSION_CURRENT = TABLE_VERSION_4; + private static final int TABLE_VERSION_5 = 5; + private static final int TABLE_VERSION_CURRENT = TABLE_VERSION_5; private final HikariPool dbPool; private final String tableName, streaksTableName; @@ -47,7 +48,7 @@ public void initialize() { try (ResultSet t = connection.getMetaData().getTables(null, null, tableName, null)) { if (!t.next()) { try (Statement statement = connection.createStatement()) { - statement.executeUpdate("CREATE TABLE " + tableName + " (uuid VARCHAR(36) PRIMARY KEY NOT NULL, last_name VARCHAR(16), votes INT NOT NULL, last_vote TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP)"); + statement.executeUpdate("CREATE TABLE " + tableName + " (uuid VARCHAR(36) PRIMARY KEY NOT NULL, last_name VARCHAR(16), votes INT NOT NULL, last_vote TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, last_votes VARCHAR(256))"); // This may speed up leaderboards statement.executeUpdate("CREATE INDEX uuid_votes_idx ON " + tableName + " (uuid, votes)"); } @@ -74,6 +75,12 @@ public void initialize() { statement.executeUpdate("ALTER TABLE " + tableName + " MODIFY votes int(11) NOT NULL DEFAULT 0"); } } + if (ver < TABLE_VERSION_5) { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate("ALTER TABLE " + tableName + " ADD COLUMN last_votes VARCHAR(256)"); + } + isUpdated = true; + } } } } @@ -106,28 +113,34 @@ public void initialize() { } @Override - public void addVote(Vote vote) { + public void addVote(Vote vote, PlayerVotes playerVotes) { if (readOnly) return; Preconditions.checkNotNull(vote, "vote"); try (Connection connection = dbPool.getConnection()) { + Timestamp voteReceivedTimestamp = new Timestamp(vote.getReceived() + .getTime()); if (vote.getName() != null) { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, last_name, votes, last_vote) VALUES (?, ?, 1, ?)" + - " ON DUPLICATE KEY UPDATE votes = votes + 1, last_name = ?, last_vote = ?")) { + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, last_name, votes, last_vote, last_votes) VALUES (?, ?, 1, ?, ?)" + + " ON DUPLICATE KEY UPDATE votes = votes + 1, last_name = ?, last_vote = ?, last_votes = ?")) { statement.setString(1, vote.getUuid().toString()); statement.setString(2, vote.getName()); - statement.setTimestamp(3, new Timestamp(vote.getReceived().getTime())); - statement.setString(4, vote.getName()); - statement.setTimestamp(5, new Timestamp(vote.getReceived().getTime())); + statement.setTimestamp(3, voteReceivedTimestamp); + statement.setString(4, playerVotes.getSerializedLastVotes()); + statement.setString(5, vote.getName()); + statement.setTimestamp(6, voteReceivedTimestamp); + statement.setString(7, playerVotes.getSerializedLastVotes()); statement.executeUpdate(); } } else { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, last_name, votes, last_vote) VALUES (?, NULL, 1, ?)" + - " ON DUPLICATE KEY UPDATE votes = votes + 1, last_vote = ?")) { + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, last_name, votes, last_vote, last_votes) VALUES (?, NULL, 1, ?, ?)" + + " ON DUPLICATE KEY UPDATE votes = votes + 1, last_vote = ?, last_votes = ?")) { statement.setString(1, vote.getUuid().toString()); - statement.setTimestamp(2, new Timestamp(vote.getReceived().getTime())); - statement.setTimestamp(3, new Timestamp(vote.getReceived().getTime())); + statement.setTimestamp(2, voteReceivedTimestamp); + statement.setString(3, playerVotes.getSerializedLastVotes()); + statement.setTimestamp(4, voteReceivedTimestamp); + statement.setString(5, playerVotes.getSerializedLastVotes()); statement.executeUpdate(); } } @@ -184,7 +197,7 @@ public void setVotes(UUID player, int votes, long ts) { Preconditions.checkNotNull(player, "player"); try (Connection connection = dbPool.getConnection()) { - try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, votes, last_vote) VALUES (?, ?, ?)" + + try (PreparedStatement statement = connection.prepareStatement("INSERT INTO " + tableName + " (uuid, votes, last_vote, last_votes) VALUES (?, ?, ?, NULL)" + " ON DUPLICATE KEY UPDATE votes = ?, last_vote = ?")) { statement.setString(1, player.toString()); statement.setInt(2, votes); @@ -216,19 +229,23 @@ public void clearVotes() { public PlayerVotes getVotes(UUID player) { Preconditions.checkNotNull(player, "player"); try (Connection connection = dbPool.getConnection()) { - try (PreparedStatement statement = connection.prepareStatement("SELECT last_name, votes FROM " + tableName + " WHERE uuid = ?")) { + try (PreparedStatement statement = connection.prepareStatement("SELECT last_name, votes, last_votes FROM " + tableName + " WHERE uuid = ?")) { statement.setString(1, player.toString()); try (ResultSet resultSet = statement.executeQuery()) { if (resultSet.next()) { - return new PlayerVotes(player, resultSet.getString(1), resultSet.getInt(2), PlayerVotes.Type.CURRENT); + return new PlayerVotes(player, + resultSet.getString(1), + resultSet.getInt(2), + PlayerVotes.deserializeLastVotes(resultSet.getString(3)), + PlayerVotes.Type.CURRENT); } else { - return new PlayerVotes(player, null, 0, PlayerVotes.Type.CURRENT); + return new PlayerVotes(player, null, 0, Collections.emptyMap(), PlayerVotes.Type.CURRENT); } } } } catch (SQLException e) { SuperbVote.getPlugin().getLogger().log(Level.SEVERE, "Unable to get votes for " + player.toString(), e); - return new PlayerVotes(player, null, 0, PlayerVotes.Type.CURRENT); + return new PlayerVotes(player, null, 0, Collections.emptyMap(), PlayerVotes.Type.CURRENT); } } @@ -236,14 +253,17 @@ public PlayerVotes getVotes(UUID player) { public List getTopVoters(int amount, int page) { int offset = page * amount; try (Connection connection = dbPool.getConnection()) { - try (PreparedStatement statement = connection.prepareStatement("SELECT uuid, last_name, votes FROM " + tableName + " WHERE votes > 0 ORDER BY votes DESC " + + try (PreparedStatement statement = connection.prepareStatement("SELECT uuid, last_name, votes, last_votes FROM " + tableName + " WHERE votes > 0 ORDER BY votes DESC " + "LIMIT " + amount + " OFFSET " + offset)) { try (ResultSet resultSet = statement.executeQuery()) { List records = new ArrayList<>(); while (resultSet.next()) { UUID uuid = UUID.fromString(resultSet.getString(1)); String name = resultSet.getString(2); - records.add(new PlayerVotes(uuid, name, resultSet.getInt(3), PlayerVotes.Type.CURRENT)); + records.add(new PlayerVotes(uuid, name, + resultSet.getInt(3), + PlayerVotes.deserializeLastVotes(resultSet.getString(4)), + PlayerVotes.Type.CURRENT)); } return records; } @@ -293,7 +313,7 @@ public List getAllPlayersWithNoVotesToday(List onlinePlayers) List votes = new ArrayList<>(); try (Connection connection = dbPool.getConnection()) { String valueStatement = Joiner.on(", ").join(Collections.nCopies(onlinePlayers.size(), "?")); - try (PreparedStatement statement = connection.prepareStatement("SELECT uuid, last_name, votes, (DATE(last_vote) = CURRENT_DATE()) AS has_voted_today FROM " + tableName + " WHERE uuid IN (" + valueStatement + ")")) { + try (PreparedStatement statement = connection.prepareStatement("SELECT uuid, last_name, votes, last_votes, (DATE(last_vote) = CURRENT_DATE()) AS has_voted_today FROM " + tableName + " WHERE uuid IN (" + valueStatement + ")")) { for (int i = 0; i < onlinePlayers.size(); i++) { statement.setString(i + 1, onlinePlayers.get(i).toString()); } @@ -302,12 +322,13 @@ public List getAllPlayersWithNoVotesToday(List onlinePlayers) while (resultSet.next()) { UUID uuid = UUID.fromString(resultSet.getString(1)); found.add(uuid); - if (resultSet.getBoolean(4)) { + if (resultSet.getBoolean(5)) { continue; // already voted today } PlayerVotes pv = new PlayerVotes(UUID.fromString(resultSet.getString(1)), resultSet.getString(2), resultSet.getInt(3), + PlayerVotes.deserializeLastVotes(resultSet.getString(4)), PlayerVotes.Type.CURRENT); votes.add(pv); } @@ -317,7 +338,7 @@ public List getAllPlayersWithNoVotesToday(List onlinePlayers) List missing = new ArrayList<>(onlinePlayers); missing.removeAll(found); for (UUID uuid : missing) { - votes.add(new PlayerVotes(uuid, null, 0, PlayerVotes.Type.CURRENT)); + votes.add(new PlayerVotes(uuid, null, 0, Collections.emptyMap(), PlayerVotes.Type.CURRENT)); } } return votes; diff --git a/src/main/java/io/minimum/minecraft/superbvote/storage/VoteStorage.java b/src/main/java/io/minimum/minecraft/superbvote/storage/VoteStorage.java index f27a35d..52f3bd9 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/storage/VoteStorage.java +++ b/src/main/java/io/minimum/minecraft/superbvote/storage/VoteStorage.java @@ -8,7 +8,7 @@ import java.util.UUID; public interface VoteStorage { - void addVote(Vote vote); + void addVote(Vote vote, PlayerVotes playerVotes); default void setVotes(UUID player, int votes) { setVotes(player, votes, System.currentTimeMillis()); diff --git a/src/main/java/io/minimum/minecraft/superbvote/util/PlayerVotes.java b/src/main/java/io/minimum/minecraft/superbvote/util/PlayerVotes.java index de23b97..5d3315a 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/util/PlayerVotes.java +++ b/src/main/java/io/minimum/minecraft/superbvote/util/PlayerVotes.java @@ -1,17 +1,37 @@ package io.minimum.minecraft.superbvote.util; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import io.minimum.minecraft.superbvote.SuperbVote; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.stream.Collectors; import lombok.Value; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.time.DateUtils; import org.bukkit.Bukkit; -import java.util.UUID; - @Value public class PlayerVotes { + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private final UUID uuid; private final String associatedUsername; private final int votes; + private final Map lastVotes; private final Type type; + public PlayerVotes(UUID uuid, String associatedUsername, int votes, Map lastVotes, Type type) { + this.uuid = uuid; + this.associatedUsername = associatedUsername; + this.votes = votes; + this.lastVotes = new HashMap<>(lastVotes); + this.type = type; + } + public String getAssociatedUsername() { if (associatedUsername == null) { return Bukkit.getOfflinePlayer(uuid).getName(); @@ -21,6 +41,55 @@ public String getAssociatedUsername() { public enum Type { CURRENT, - FUTURE + FUTURE; + + } + public boolean hasVoteOnSameDay(String serviceName, Date voteDate) { + Date lastVoteDate = lastVotes.get(serviceName); + if (lastVoteDate == null) { + return false; + } + if (lastVoteDate.equals(voteDate)) { + // the new vote is just about being processed right now + return false; + } + return DateUtils.isSameDay(lastVoteDate, voteDate); + } + + public void updateLastVotes(String serviceName, Date voteReceived) { + lastVotes.put(serviceName, voteReceived); + } + + public String getSerializedLastVotes() { + try { + Map preprocessed = new HashMap<>(); + for (Map.Entry entry : lastVotes.entrySet()) { + long dateSeconds = entry.getValue().getTime() / 1000; + preprocessed.put(entry.getKey(), new Date(dateSeconds)); + } + return OBJECT_MAPPER.writeValueAsString(preprocessed); + } catch (JsonProcessingException e) { + SuperbVote.getPlugin() + .getLogger() + .severe("Could not serialize last votes to JSON: " + lastVotes + "\n" + e.getMessage()); + return ""; + } + } + + public static Map deserializeLastVotes(String lastVotesString) { + if (StringUtils.isBlank(lastVotesString)) { + return new HashMap<>(); + } + try { + Map lastVotes = OBJECT_MAPPER.readValue(lastVotesString, new TypeReference<>() {}); + return lastVotes.entrySet() + .stream() + .collect(Collectors.toMap(Map.Entry::getKey, e -> new Date(e.getValue() * 1000))); + } catch (JsonProcessingException e) { + SuperbVote.getPlugin() + .getLogger() + .severe("Could not deserialize last votes from JSON: " + lastVotesString + "\n" + e.getMessage()); + return new HashMap<>(); + } } } diff --git a/src/main/java/io/minimum/minecraft/superbvote/util/SpigotUpdater.java b/src/main/java/io/minimum/minecraft/superbvote/util/SpigotUpdater.java index e8a89c1..7ecd387 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/util/SpigotUpdater.java +++ b/src/main/java/io/minimum/minecraft/superbvote/util/SpigotUpdater.java @@ -1,7 +1,7 @@ package io.minimum.minecraft.superbvote.util; import com.google.common.io.ByteStreams; -import io.minimum.minecraft.superbvote.SuperbVote;; +import io.minimum.minecraft.superbvote.SuperbVote; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.event.EventHandler; @@ -39,7 +39,7 @@ private static String getLatestVersion() throws IOException { @Override public void run() { String myVersion = SuperbVote.getPlugin().getDescription().getVersion(); - if (myVersion.endsWith("-SNAPSHOT")) { + if (myVersion.endsWith("-SNAPSHOT") || myVersion.endsWith("-CORP")) { // Nothing to do. return; } diff --git a/src/main/java/io/minimum/minecraft/superbvote/votes/SuperbVoteListener.java b/src/main/java/io/minimum/minecraft/superbvote/votes/SuperbVoteListener.java index 6799e13..5b407eb 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/votes/SuperbVoteListener.java +++ b/src/main/java/io/minimum/minecraft/superbvote/votes/SuperbVoteListener.java @@ -10,6 +10,9 @@ import io.minimum.minecraft.superbvote.util.BrokenNag; import io.minimum.minecraft.superbvote.util.PlayerVotes; import io.minimum.minecraft.superbvote.votes.rewards.VoteReward; +import java.util.HashMap; +import java.util.Map; +import org.apache.commons.lang3.time.DateUtils; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; import org.bukkit.entity.Player; @@ -39,13 +42,15 @@ public void onVote(final VotifierEvent event) { worldName = op.getPlayer().getWorld().getName(); } - VoteStorage voteStorage = SuperbVote.getPlugin().getVoteStorage(); - VoteStreak voteStreak = voteStorage.getVoteStreakIfSupported(op.getUniqueId(), false); - PlayerVotes pvCurrent = voteStorage.getVotes(op.getUniqueId()); - PlayerVotes pv = new PlayerVotes(op.getUniqueId(), op.getName(), pvCurrent.getVotes() + 1, PlayerVotes.Type.FUTURE); Vote vote = new Vote(op.getName(), op.getUniqueId(), event.getVote().getServiceName(), event.getVote().getAddress().equals(SuperbVoteCommand.FAKE_HOST_NAME_FOR_VOTE), worldName, new Date()); + VoteStorage voteStorage = SuperbVote.getPlugin().getVoteStorage(); + PlayerVotes pvCurrent = voteStorage.getVotes(op.getUniqueId()); + PlayerVotes pv = new PlayerVotes(op.getUniqueId(), op.getName(), pvCurrent.getVotes() + 1, + pvCurrent.getLastVotes(), PlayerVotes.Type.FUTURE); + + VoteStreak voteStreak = voteStorage.getVoteStreakIfSupported(op.getUniqueId(), false); if (!vote.isFakeVote()) { if (SuperbVote.getPlugin().getConfiguration().getStreaksConfiguration().isSharedCooldownPerService()) { if (voteStreak == null) { @@ -88,9 +93,20 @@ private void processVote(PlayerVotes pv, VoteStreak voteStreak, Vote vote, boole throw new RuntimeException("No vote rewards found for '" + vote + "'"); } + if (SuperbVote.getPlugin().getConfig().getBoolean("votes.one-vote-per-day") + && pv.hasVoteOnSameDay(vote.getServiceName(), vote.getReceived())) { + + SuperbVote.getPlugin() + .getLogger() + .log(Level.INFO, "Discarding vote: " + vote.getName() + + " already received a vote the same day at " + pv.getLastVotes().get(vote.getServiceName()) + + " for service:" + vote.getServiceName()); + return; + } + pv.updateLastVotes(vote.getServiceName(), vote.getReceived()); if (queue) { if (!SuperbVote.getPlugin().getConfiguration().shouldQueueVotes()) { - SuperbVote.getPlugin().getLogger().log(Level.WARNING, "Ignoring vote from " + vote.getName() + " (service: " + + SuperbVote.getPlugin().getLogger().log(Level.WARNING, "Ignoring vote from " + vote.getName() + " (service:" + vote.getServiceName() + ") because they aren't online."); return; } @@ -102,7 +118,7 @@ private void processVote(PlayerVotes pv, VoteStreak voteStreak, Vote vote, boole SuperbVote.getPlugin().getQueuedVotes().addVote(vote); } else { if (!vote.isFakeVote() || SuperbVote.getPlugin().getConfig().getBoolean("votes.process-fake-votes")) { - SuperbVote.getPlugin().getVoteStorage().addVote(vote); + SuperbVote.getPlugin().getVoteStorage().addVote(vote, pv); } if (!wasQueued) { @@ -141,7 +157,9 @@ public void onPlayerJoin(PlayerJoinEvent event) { if (!votes.isEmpty()) { for (Vote vote : votes) { processVote(pv, voteStreak, vote, false, false, true); - pv = new PlayerVotes(pv.getUuid(), event.getPlayer().getName(),pv.getVotes() + 1, PlayerVotes.Type.CURRENT); + pv = new PlayerVotes(pv.getUuid(), event.getPlayer().getName(),pv.getVotes() + 1, + pv.getLastVotes(), PlayerVotes.Type.CURRENT); + pv.updateLastVotes(vote.getServiceName(), vote.getReceived()); } afterVoteProcessing(); } diff --git a/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/RewardMatchers.java b/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/RewardMatchers.java index ef0e9d3..4f52fdd 100644 --- a/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/RewardMatchers.java +++ b/src/main/java/io/minimum/minecraft/superbvote/votes/rewards/matchers/RewardMatchers.java @@ -5,7 +5,7 @@ import com.google.common.collect.ImmutableSet; import io.minimum.minecraft.superbvote.SuperbVote; import net.milkbowl.vault.permission.Permission; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; import org.bukkit.plugin.RegisteredServiceProvider; diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 53d9838..a4cb1e3 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,6 +26,9 @@ votes: # Whether or not to treat fake votes as real votes process-fake-votes: true + # Whether to allow only one vote per day for each player + one-vote-per-day: false + # Streaks configuration # Important: Streaks does not support JSON storage streaks: diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index c0cbbd1..083c3f7 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -4,16 +4,11 @@ author: tuxed version: ${project.version} depend: [Votifier] softdepend: [Vault, PlaceholderAPI] -api-version: "1.13" +api-version: "1.19" commands: superbvote: description: SuperbVote main command. aliases: [sv] - vote: - description: SuperbVote vote command. - votestreak: - description: SuperbVote vote streak command. - aliases: [vstreak] permissions: superbvote.notify: default: true