diff --git a/README.md b/README.md index aee1605..0fd6eec 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,8 @@ When the shop and/or vote plugins are installed on your Azuriom website, the int * `%azlink_vote_sites_[id]_url%`: URL of vote site with given ID * `%azlink_vote_top_[position]_name%`: name of player at given position in vote ranking * `%azlink_vote_top_[position]_votes%`: vote count of player at given position in ranking +* `%azlink_vote_goal_progress%`: number of votes currently counted toward the monthly vote goal +* `%azlink_vote_goal_target%`: total number of votes required to reach the monthly vote goal ### Shop Placeholders * `%azlink_shop_goal_progress%`: current progress of the shop goal this month diff --git a/bukkit/src/main/java/com/azuriom/azlink/bukkit/placeholders/VotePlaceholderProvider.java b/bukkit/src/main/java/com/azuriom/azlink/bukkit/placeholders/VotePlaceholderProvider.java index c17bbc3..03fad83 100644 --- a/bukkit/src/main/java/com/azuriom/azlink/bukkit/placeholders/VotePlaceholderProvider.java +++ b/bukkit/src/main/java/com/azuriom/azlink/bukkit/placeholders/VotePlaceholderProvider.java @@ -13,15 +13,16 @@ import java.time.Duration; import java.time.Instant; -import java.time.temporal.ChronoUnit; import java.util.*; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; public class VotePlaceholderProvider implements PlaceholderProvider, Runnable, Listener { - private final Map voteSites = new HashMap<>(); - private final Map users = new HashMap<>(); + private final Map voteSites = new ConcurrentHashMap<>(); + private final Map users = new ConcurrentHashMap<>(); private final List topVotes = new ArrayList<>(); + private volatile VoteGoal goal; private volatile boolean pendingRefresh = true; private volatile Instant lastUpdate = Instant.MIN; @@ -64,7 +65,9 @@ public List availablePlaceholders() { "%azlink_vote_sites_[id]_name%", "%azlink_vote_sites_[id]_url%", "%azlink_vote_top_[position]_name%", - "%azlink_vote_top_[position]_votes%" + "%azlink_vote_top_[position]_votes%", + "%azlink_vote_goal_target%", + "%azlink_vote_goal_progress%" ); } @@ -94,6 +97,8 @@ public String evaluatePlaceholder(String[] parts, OfflinePlayer player) { return topPlaceholder(parts); case "sites": return sitePlaceholder(parts); + case "goal": + return goalPlaceholder(parts[1]); default: return null; } @@ -134,6 +139,19 @@ private String userCanPlaceholder(String[] parts, OfflinePlayer player) throws N return null; } + private String goalPlaceholder(String action) { + VoteGoal goal = this.goal; + + switch (action) { + case "target": + return goal != null ? Integer.toString(goal.target) : "0"; + case "progress": + return goal != null ? Integer.toString(goal.progress) : "0"; + default: + return null; + } + } + private String sitePlaceholder(String[] parts) throws NumberFormatException { if (parts[1].equals("count")) { return Integer.toString(voteSites.size()); @@ -229,6 +247,7 @@ private void refreshData() { this.voteSites.clear(); this.users.clear(); this.topVotes.clear(); + this.goal = response.goal; for (VoteSite site : response.sites) { this.voteSites.put(site.id, site); @@ -246,7 +265,9 @@ private void refreshData() { } private VoteUser getUserFromPlayer(OfflinePlayer player) { - return this.users.get(player.getName().toLowerCase(Locale.ROOT)); + String name = player.getName(); + + return name != null ? this.users.get(name.toLowerCase(Locale.ROOT)) : null; } private String formatDuration(Duration duration) { @@ -260,6 +281,12 @@ public static class VoteResponse { public List users = new ArrayList<>(); @SerializedName("top_votes") public List topVotes = new ArrayList<>(); + public VoteGoal goal; + } + + public static class VoteGoal { + public int target; + public int progress; } public static class VoteUser {