diff --git a/pom.xml b/pom.xml
index 839051c..ca6490a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
fr.votenetwork
votenetwork-parent
- 1.0.0
+ 1.0.1
pom
diff --git a/spigot/pom.xml b/spigot/pom.xml
index 0a84672..f7e5135 100644
--- a/spigot/pom.xml
+++ b/spigot/pom.xml
@@ -7,7 +7,7 @@
fr.votenetwork
votenetwork-parent
- 1.0.0
+ 1.0.1
votenetwork-spigot
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/VoteConfig.java b/spigot/src/main/java/fr/votenetwork/spigot/VoteConfig.java
index 0914bd1..39e1d83 100644
--- a/spigot/src/main/java/fr/votenetwork/spigot/VoteConfig.java
+++ b/spigot/src/main/java/fr/votenetwork/spigot/VoteConfig.java
@@ -1,9 +1,14 @@
package fr.votenetwork.spigot;
+import fr.votenetwork.spigot.gui.VoteSite;
import org.bukkit.ChatColor;
+import org.bukkit.Material;
import org.bukkit.configuration.file.FileConfiguration;
+import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
+import java.util.Map;
import java.util.stream.Collectors;
public class VoteConfig {
@@ -141,6 +146,57 @@ public class VoteConfig {
"&cVous n'avez pas la permission d'utiliser cette commande."));
}
+ public String getGuiTitle() {
+ return colorize(cfg().getString("gui.title", "&8VoteNetwork"));
+ }
+
+ public String getGuiProgressItemMaterial() {
+ return cfg().getString("gui.progress-item.material", "NETHER_STAR");
+ }
+
+ public String getGuiProgressItemName() {
+ return colorize(cfg().getString("gui.progress-item.name", "&b&lVoteParty"));
+ }
+
+ public List getGuiProgressItemLore() {
+ return colorizeList(cfg().getStringList("gui.progress-item.lore"));
+ }
+
+ public String getGuiClickMessage() {
+ return colorize(cfg().getString("gui.click-message", "&a[Vote] Clique sur le lien pour voter :"));
+ }
+
+ /**
+ * Parses gui.vote-sites (a YAML list of maps: name/material/url/lore) into VoteSite
+ * objects, one item per configured vote site.
+ */
+ public List getVoteSites() {
+ List sites = new ArrayList<>();
+ for (Map, ?> raw : cfg().getMapList("gui.vote-sites")) {
+ String name = raw.containsKey("name") ? String.valueOf(raw.get("name")) : "&aVoter";
+ String materialName = raw.containsKey("material") ? String.valueOf(raw.get("material")) : "PAPER";
+ String url = raw.containsKey("url") ? String.valueOf(raw.get("url")) : "";
+
+ List lore = new ArrayList<>();
+ Object loreObj = raw.get("lore");
+ if (loreObj instanceof List> loreList) {
+ for (Object line : loreList) {
+ lore.add(String.valueOf(line));
+ }
+ }
+
+ Material material;
+ try {
+ material = Material.valueOf(materialName.toUpperCase(Locale.ROOT));
+ } catch (IllegalArgumentException e) {
+ material = Material.PAPER;
+ }
+
+ sites.add(new VoteSite(colorize(name), material, url, colorizeList(lore)));
+ }
+ return sites;
+ }
+
private String colorize(String input) {
return input == null ? "" : ChatColor.translateAlternateColorCodes('&', input);
}
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java b/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java
index f24e99b..1b76606 100644
--- a/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java
+++ b/spigot/src/main/java/fr/votenetwork/spigot/VoteNetworkSpigot.java
@@ -5,6 +5,8 @@ import fr.votenetwork.spigot.api.VoteNetworkAPIHolder;
import fr.votenetwork.spigot.api.VoteNetworkAPIImpl;
import fr.votenetwork.spigot.command.ClaimCommand;
import fr.votenetwork.spigot.command.VoteAdminCommand;
+import fr.votenetwork.spigot.command.VoteGuiCommand;
+import fr.votenetwork.spigot.gui.VotePartyGuiListener;
import fr.votenetwork.spigot.listener.VoteMessageListener;
import fr.votenetwork.spigot.placeholder.VoteNetworkPlaceholders;
import fr.votenetwork.spigot.storage.MySqlPendingVoteStore;
@@ -55,6 +57,8 @@ public class VoteNetworkSpigot extends JavaPlugin {
getCommand("claim").setExecutor(new ClaimCommand(this, voteConfig, pendingVoteStore, voteParty, maintenanceState));
getCommand("vote").setExecutor(new VoteAdminCommand(this, voteConfig, pendingVoteStore, maintenanceState));
+ getCommand("votegui").setExecutor(new VoteGuiCommand(voteConfig, voteParty));
+ getServer().getPluginManager().registerEvents(new VotePartyGuiListener(voteConfig), this);
VoteNetworkAPI api = new VoteNetworkAPIImpl(this, voteConfig, pendingVoteStore, voteParty, maintenanceState);
VoteNetworkAPIHolder.set(api);
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/command/VoteGuiCommand.java b/spigot/src/main/java/fr/votenetwork/spigot/command/VoteGuiCommand.java
new file mode 100644
index 0000000..854c796
--- /dev/null
+++ b/spigot/src/main/java/fr/votenetwork/spigot/command/VoteGuiCommand.java
@@ -0,0 +1,31 @@
+package fr.votenetwork.spigot.command;
+
+import fr.votenetwork.spigot.VoteConfig;
+import fr.votenetwork.spigot.gui.VotePartyGui;
+import fr.votenetwork.spigot.voteparty.VoteParty;
+import org.bukkit.ChatColor;
+import org.bukkit.command.Command;
+import org.bukkit.command.CommandExecutor;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+
+public class VoteGuiCommand implements CommandExecutor {
+
+ private final VoteConfig config;
+ private final VoteParty voteParty;
+
+ public VoteGuiCommand(VoteConfig config, VoteParty voteParty) {
+ this.config = config;
+ this.voteParty = voteParty;
+ }
+
+ @Override
+ public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
+ if (!(sender instanceof Player player)) {
+ sender.sendMessage(ChatColor.RED + "Commande reservee aux joueurs.");
+ return true;
+ }
+ VotePartyGui.open(player, config, voteParty);
+ return true;
+ }
+}
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGui.java b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGui.java
new file mode 100644
index 0000000..680de71
--- /dev/null
+++ b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGui.java
@@ -0,0 +1,72 @@
+package fr.votenetwork.spigot.gui;
+
+import fr.votenetwork.spigot.VoteConfig;
+import fr.votenetwork.spigot.voteparty.VoteParty;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+
+import java.util.List;
+
+/**
+ * Builds and opens the VoteParty progress GUI: a progress item (slot 4) plus one item per
+ * configured vote site (starting at slot 9), each opening its URL when clicked.
+ */
+public final class VotePartyGui {
+
+ public static final int PROGRESS_SLOT = 4;
+ public static final int SITES_START_SLOT = 9;
+
+ private VotePartyGui() {
+ }
+
+ public static void open(Player player, VoteConfig config, VoteParty voteParty) {
+ List sites = config.getVoteSites();
+ int size = ((SITES_START_SLOT + sites.size() + 8) / 9) * 9;
+ size = Math.max(size, 18);
+
+ VotePartyGuiHolder holder = new VotePartyGuiHolder();
+ Inventory inventory = Bukkit.createInventory(holder, size, config.getGuiTitle());
+ holder.setInventory(inventory);
+
+ int required = config.getVotePartyVotesRequired();
+ int current = Math.min(voteParty.getCurrentVotes(), required);
+
+ ItemStack progressItem = new ItemStack(materialOrFallback(config.getGuiProgressItemMaterial()));
+ ItemMeta progressMeta = progressItem.getItemMeta();
+ if (progressMeta != null) {
+ progressMeta.setDisplayName(config.getGuiProgressItemName());
+ progressMeta.setLore(config.getGuiProgressItemLore().stream()
+ .map(line -> line.replace("%current%", String.valueOf(current))
+ .replace("%required%", String.valueOf(required)))
+ .toList());
+ progressItem.setItemMeta(progressMeta);
+ }
+ inventory.setItem(PROGRESS_SLOT, progressItem);
+
+ int slot = SITES_START_SLOT;
+ for (VoteSite site : sites) {
+ ItemStack item = new ItemStack(site.getMaterial());
+ ItemMeta meta = item.getItemMeta();
+ if (meta != null) {
+ meta.setDisplayName(site.getName());
+ meta.setLore(site.getLore());
+ item.setItemMeta(meta);
+ }
+ inventory.setItem(slot, item);
+ slot++;
+ }
+
+ player.openInventory(inventory);
+ }
+
+ private static org.bukkit.Material materialOrFallback(String name) {
+ try {
+ return org.bukkit.Material.valueOf(name.toUpperCase(java.util.Locale.ROOT));
+ } catch (IllegalArgumentException e) {
+ return org.bukkit.Material.NETHER_STAR;
+ }
+ }
+}
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiHolder.java b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiHolder.java
new file mode 100644
index 0000000..3109961
--- /dev/null
+++ b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiHolder.java
@@ -0,0 +1,23 @@
+package fr.votenetwork.spigot.gui;
+
+import org.bukkit.inventory.Inventory;
+import org.bukkit.inventory.InventoryHolder;
+
+/**
+ * Marker holder used to recognize our own GUI inventory in InventoryClickEvent, so the
+ * listener never touches clicks happening in unrelated inventories (chests, other plugins'
+ * GUIs, etc.).
+ */
+public class VotePartyGuiHolder implements InventoryHolder {
+
+ private Inventory inventory;
+
+ @Override
+ public Inventory getInventory() {
+ return inventory;
+ }
+
+ public void setInventory(Inventory inventory) {
+ this.inventory = inventory;
+ }
+}
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiListener.java b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiListener.java
new file mode 100644
index 0000000..c7d5bef
--- /dev/null
+++ b/spigot/src/main/java/fr/votenetwork/spigot/gui/VotePartyGuiListener.java
@@ -0,0 +1,53 @@
+package fr.votenetwork.spigot.gui;
+
+import fr.votenetwork.spigot.VoteConfig;
+import net.md_5.bungee.api.chat.ClickEvent;
+import net.md_5.bungee.api.chat.TextComponent;
+import org.bukkit.entity.Player;
+import org.bukkit.event.EventHandler;
+import org.bukkit.event.Listener;
+import org.bukkit.event.inventory.InventoryClickEvent;
+
+import java.util.List;
+
+/**
+ * Bukkit cannot open a browser directly from an inventory click, so a click on a vote-site
+ * item closes the GUI and sends a clickable chat message (ClickEvent OPEN_URL) instead.
+ */
+public class VotePartyGuiListener implements Listener {
+
+ private final VoteConfig config;
+
+ public VotePartyGuiListener(VoteConfig config) {
+ this.config = config;
+ }
+
+ @EventHandler
+ public void onInventoryClick(InventoryClickEvent event) {
+ if (!(event.getInventory().getHolder() instanceof VotePartyGuiHolder)) {
+ return;
+ }
+ event.setCancelled(true);
+
+ int slot = event.getRawSlot();
+ if (slot < VotePartyGui.SITES_START_SLOT || !(event.getWhoClicked() instanceof Player player)) {
+ return;
+ }
+
+ List sites = config.getVoteSites();
+ int index = slot - VotePartyGui.SITES_START_SLOT;
+ if (index < 0 || index >= sites.size()) {
+ return;
+ }
+
+ VoteSite site = sites.get(index);
+ if (site.getUrl() == null || site.getUrl().isEmpty()) {
+ return;
+ }
+
+ player.closeInventory();
+ TextComponent message = new TextComponent(config.getGuiClickMessage() + " " + site.getUrl());
+ message.setClickEvent(new ClickEvent(ClickEvent.Action.OPEN_URL, site.getUrl()));
+ player.spigot().sendMessage(message);
+ }
+}
diff --git a/spigot/src/main/java/fr/votenetwork/spigot/gui/VoteSite.java b/spigot/src/main/java/fr/votenetwork/spigot/gui/VoteSite.java
new file mode 100644
index 0000000..d1fa954
--- /dev/null
+++ b/spigot/src/main/java/fr/votenetwork/spigot/gui/VoteSite.java
@@ -0,0 +1,40 @@
+package fr.votenetwork.spigot.gui;
+
+import org.bukkit.Material;
+
+import java.util.List;
+
+/**
+ * A single vote-site entry configured in config.yml (gui.vote-sites): the display item and
+ * the URL opened (via a clickable chat message) when the player clicks it in the GUI.
+ */
+public class VoteSite {
+
+ private final String name;
+ private final Material material;
+ private final String url;
+ private final List lore;
+
+ public VoteSite(String name, Material material, String url, List lore) {
+ this.name = name;
+ this.material = material;
+ this.url = url;
+ this.lore = lore;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public Material getMaterial() {
+ return material;
+ }
+
+ public String getUrl() {
+ return url;
+ }
+
+ public List getLore() {
+ return lore;
+ }
+}
diff --git a/spigot/src/main/resources/config.yml b/spigot/src/main/resources/config.yml
index c600160..38ee5d1 100644
--- a/spigot/src/main/resources/config.yml
+++ b/spigot/src/main/resources/config.yml
@@ -47,6 +47,30 @@ voteparty:
progress-message: "&b[Vote] &f%current%&7/&f%required% &fvotes avant le prochain VoteParty !"
triggered-message: "&a[Vote] &fVoteParty declenche ! Profitez des recompenses !"
+# GUI /votegui : affiche la progression du VoteParty et des items cliquables vers les sites
+# de vote (ouvre le lien via un message chat cliquable, Bukkit ne peut pas ouvrir un navigateur
+# directement depuis un clic d'inventaire).
+gui:
+ title: "&8VoteNetwork"
+ progress-item:
+ material: NETHER_STAR
+ name: "&b&lVoteParty"
+ lore:
+ - "&7Progression actuelle :"
+ - "&f%current%&7/&f%required% &7votes"
+ click-message: "&a[Vote] Clique sur le lien pour voter :"
+ vote-sites:
+ - name: "&aVoter sur le site 1"
+ material: PAPER
+ url: "https://example.com/vote/site1"
+ lore:
+ - "&7Clique pour voter !"
+ - name: "&aVoter sur le site 2"
+ material: BOOK
+ url: "https://example.com/vote/site2"
+ lore:
+ - "&7Clique pour voter !"
+
messages:
direct-vote: "&a[Vote] &fMerci pour ton vote !"
claim-success: "&a[Vote] &fVous avez recupere &e%amount% &fvote(s) en attente !"
diff --git a/spigot/src/main/resources/plugin.yml b/spigot/src/main/resources/plugin.yml
index 9031b9a..aaa65ab 100644
--- a/spigot/src/main/resources/plugin.yml
+++ b/spigot/src/main/resources/plugin.yml
@@ -14,6 +14,9 @@ commands:
description: Administration du systeme de vote (maintenance, test du stockage).
usage: /vote
permission: votenetwork.admin
+ votegui:
+ description: Ouvre le GUI de progression du VoteParty avec les liens de vote.
+ usage: /votegui
permissions:
votenetwork.admin:
diff --git a/velocity/pom.xml b/velocity/pom.xml
index 0c50857..c858217 100644
--- a/velocity/pom.xml
+++ b/velocity/pom.xml
@@ -7,7 +7,7 @@
fr.votenetwork
votenetwork-parent
- 1.0.0
+ 1.0.1
votenetwork-velocity
diff --git a/velocity/src/main/java/fr/votenetwork/velocity/VoteNetworkVelocity.java b/velocity/src/main/java/fr/votenetwork/velocity/VoteNetworkVelocity.java
index d507155..a2dc281 100644
--- a/velocity/src/main/java/fr/votenetwork/velocity/VoteNetworkVelocity.java
+++ b/velocity/src/main/java/fr/votenetwork/velocity/VoteNetworkVelocity.java
@@ -14,7 +14,7 @@ import java.nio.file.Path;
@Plugin(
id = "votenetwork",
name = "VoteNetwork",
- version = "1.0.0",
+ version = "1.0.1",
description = "Systeme de vote reseau Velocity <-> Spigot",
authors = {"Sar_Tron"}
)