From 74b2914529409234ba78ddca12cf0d8e6cb9823e Mon Sep 17 00:00:00 2001 From: SarTron-NorthBlue Date: Sun, 12 Jul 2026 14:26:44 +0400 Subject: [PATCH] Ajoute un expansion PlaceholderAPI (%votenetwork_...%) Le scoreboard du joueur affichait %current%/%required% en clair car seule une API Java existait, pas de placeholders texte. Enregistre automatiquement si PlaceholderAPI est present (softdepend) : voteparty_current, voteparty_required, voteparty_remaining, maintenance, pending (rafraichi en arriere-plan, async). Co-Authored-By: Claude Sonnet 5 --- README.md | 14 +++ spigot/pom.xml | 10 ++ .../votenetwork/spigot/VoteNetworkSpigot.java | 7 ++ .../placeholder/VoteNetworkPlaceholders.java | 102 ++++++++++++++++++ spigot/src/main/resources/plugin.yml | 1 + 5 files changed, 134 insertions(+) create mode 100644 spigot/src/main/java/fr/votenetwork/spigot/placeholder/VoteNetworkPlaceholders.java diff --git a/README.md b/README.md index c34d614..3c56788 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,20 @@ api.getPendingVotes(player.getUniqueId(), pending -> { - `getVotePartyCurrentVotes()` / `getVotePartyRequiredVotes()` : lecture directe en mémoire, thread principal uniquement. - `getPendingVotes(...)` : lecture asynchrone du stockage configuré (MySQL ou YAML), ne consomme pas les votes contrairement à `/claim`. +### Placeholders PlaceholderAPI (scoreboard/GUI sans coder de plugin) + +Si [PlaceholderAPI](https://www.spigotmc.org/resources/placeholderapi.6245/) est installé, VoteNetwork enregistre automatiquement ses propres placeholders (aucune config nécessaire) : + +| Placeholder | Valeur | +|---|---| +| `%votenetwork_voteparty_current%` | Votes cumulés sur ce serveur pour le VoteParty | +| `%votenetwork_voteparty_required%` | Objectif VoteParty (`voteparty.votes-requis`) | +| `%votenetwork_voteparty_remaining%` | Votes restants avant déclenchement | +| `%votenetwork_maintenance%` | `true`/`false` | +| `%votenetwork_pending%` | Votes en attente du joueur (rafraîchi en arrière-plan, pas de lag) | + +Utilisez ces placeholders directement dans la config de votre plugin de scoreboard/tab/GUI habituel (FeatherBoard, TAB, DeluxeMenus, ...) — **pas** `%current%`/`%required%` bruts, qui n'existent pas côté PlaceholderAPI et doivent être définis dans la config du plugin de scoreboard lui-même. + ## Structure de la base de données Créée automatiquement si absente (mode `mysql`) : diff --git a/spigot/pom.xml b/spigot/pom.xml index 77f5ba0..062042d 100644 --- a/spigot/pom.xml +++ b/spigot/pom.xml @@ -36,6 +36,12 @@ mysql-connector-j ${mysql.version} + + me.clip + placeholderapi + 2.11.6 + provided + @@ -47,6 +53,10 @@ sonatype https://oss.sonatype.org/content/groups/public/ + + placeholderapi + https://repo.extendedclip.com/content/repositories/placeholderapi/ + diff --git a/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java b/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java index f8315d7..f24e99b 100644 --- a/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java +++ b/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java @@ -6,10 +6,12 @@ import fr.votenetwork.spigot.api.VoteNetworkAPIImpl; import fr.votenetwork.spigot.command.ClaimCommand; import fr.votenetwork.spigot.command.VoteAdminCommand; import fr.votenetwork.spigot.listener.VoteMessageListener; +import fr.votenetwork.spigot.placeholder.VoteNetworkPlaceholders; import fr.votenetwork.spigot.storage.MySqlPendingVoteStore; import fr.votenetwork.spigot.storage.PendingVoteStore; import fr.votenetwork.spigot.storage.YamlPendingVoteStore; import fr.votenetwork.spigot.voteparty.VoteParty; +import org.bukkit.Bukkit; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.ServicePriority; import org.bukkit.plugin.java.JavaPlugin; @@ -58,6 +60,11 @@ public class VoteNetworkSpigot extends JavaPlugin { VoteNetworkAPIHolder.set(api); getServer().getServicesManager().register(VoteNetworkAPI.class, api, this, ServicePriority.Normal); + if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { + new VoteNetworkPlaceholders(this, voteConfig, pendingVoteStore, voteParty, maintenanceState).register(); + getLogger().info("Placeholders PlaceholderAPI enregistres (%votenetwork_...%)."); + } + getLogger().info("VoteNetwork (Spigot) demarre."); } diff --git a/spigot/src/main/java/fr/votenetwork/spigot/placeholder/VoteNetworkPlaceholders.java b/spigot/src/main/java/fr/votenetwork/spigot/placeholder/VoteNetworkPlaceholders.java new file mode 100644 index 0000000..08f8cea --- /dev/null +++ b/spigot/src/main/java/fr/votenetwork/spigot/placeholder/VoteNetworkPlaceholders.java @@ -0,0 +1,102 @@ +package fr.votenetwork.spigot.placeholder; + +import fr.votenetwork.spigot.MaintenanceState; +import fr.votenetwork.spigot.VoteConfig; +import fr.votenetwork.spigot.VoteNetworkSpigot; +import fr.votenetwork.spigot.storage.PendingVoteStore; +import fr.votenetwork.spigot.voteparty.VoteParty; +import me.clip.placeholderapi.expansion.PlaceholderExpansion; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * Placeholders PlaceholderAPI : + * %votenetwork_voteparty_current% + * %votenetwork_voteparty_required% + * %votenetwork_voteparty_remaining% + * %votenetwork_maintenance% -> "true"/"false" + * %votenetwork_pending% -> votes en attente du joueur (rafraichi en arriere-plan) + * + * Utilisables dans n'importe quel plugin de scoreboard/GUI qui supporte PlaceholderAPI + * (%votenetwork_...%, pas %current%/%required% bruts : ces derniers doivent etre configures + * comme placeholders dans le plugin de scoreboard lui-meme). + */ +public class VoteNetworkPlaceholders extends PlaceholderExpansion { + + private final VoteNetworkSpigot plugin; + private final VoteConfig config; + private final PendingVoteStore pendingVoteStore; + private final VoteParty voteParty; + private final MaintenanceState maintenanceState; + + private final Map pendingVotesCache = new ConcurrentHashMap<>(); + + public VoteNetworkPlaceholders(VoteNetworkSpigot plugin, VoteConfig config, PendingVoteStore pendingVoteStore, + VoteParty voteParty, MaintenanceState maintenanceState) { + this.plugin = plugin; + this.config = config; + this.pendingVoteStore = pendingVoteStore; + this.voteParty = voteParty; + this.maintenanceState = maintenanceState; + } + + @Override + public @NotNull String getIdentifier() { + return "votenetwork"; + } + + @Override + public @NotNull String getAuthor() { + return "VoteNetwork"; + } + + @Override + public @NotNull String getVersion() { + return plugin.getDescription().getVersion(); + } + + @Override + public boolean persist() { + return true; + } + + @Override + public String onRequest(OfflinePlayer player, @NotNull String params) { + switch (params.toLowerCase()) { + case "voteparty_current": + return String.valueOf(voteParty.getCurrentVotes()); + case "voteparty_required": + return String.valueOf(config.getVotePartyVotesRequired()); + case "voteparty_remaining": + return String.valueOf(Math.max(0, config.getVotePartyVotesRequired() - voteParty.getCurrentVotes())); + case "maintenance": + return String.valueOf(maintenanceState.isStopped()); + case "pending": + if (player == null) { + return "0"; + } + return String.valueOf(getPendingVotesCached(player)); + default: + return null; + } + } + + private int getPendingVotesCached(OfflinePlayer player) { + String key = player.getUniqueId().toString(); + Integer cached = pendingVotesCache.get(key); + + Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> + pendingVoteStore.peek( + player.getUniqueId(), + votes -> pendingVotesCache.put(key, votes), + exception -> { /* on garde la derniere valeur en cache en cas d'erreur */ } + ) + ); + + return cached != null ? cached : 0; + } +} diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml index a741b0a..644ad54 100644 --- a/spigot/src/main/resources/plugin.yml +++ b/spigot/src/main/resources/plugin.yml @@ -4,6 +4,7 @@ version: ${project.version} api-version: 1.18 author: VoteNetwork description: Reception des votes reseau (direct ou en attente) avec VoteParty local. +softdepend: [PlaceholderAPI] commands: claim: