actions/setup-java installe le JDK mais pas Maven. Ca marche sur les runners GitHub-hostes (Maven deja present dans l'image), mais pas sur ce runner self-hoste (act) qui utilise une image minimale. Bascule sur l'image Docker officielle maven:3.9-eclipse-temurin-17, qui a Maven + JDK 17 preinstalles, peu importe le runner sous-jacent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
VoteNetwork
Par Sar_Tron, sous licence MIT.
Systeme de vote reseau en deux modules, pour une architecture proxy Velocity + serveurs Spigot/Paper (modes A, B, C, ...).
velocity/— module proxy. Recoitvotenetwork vote <pseudo>(console uniquement) et route le vote en direct ou le met en attente.spigot/— module serveur. Recoit le signal en direct via Plugin Messaging, gere/claim, le VoteParty local et le mode maintenance.
Compatible Java 17, compile contre l'API Spigot 1.18.2 (additive, donc compatible en avant vers 1.19 → 1.21.x et versions futures).
Sommaire
- Installation
- Build depuis les sources
- Configuration
- Stockage : MySQL ou YAML
- Fonctionnement du vote
- Commandes & permissions
- VoteParty
- API publique (scoreboard / GUI)
- Structure de la base de données
Installation
velocity/target/VoteNetwork-Velocity.jar→plugins/du proxy Velocity.spigot/target/VoteNetwork-Spigot.jar→plugins/de chaque serveur Spigot/Paper (A, B, C, ...).- Démarrer une fois pour générer les fichiers de config, puis les éditer :
- Proxy :
plugins/votenetwork/config.properties - Serveur :
plugins/votenetwork/config.yml
- Proxy :
- Redémarrer.
⚠️ Même base de données partout.
mysql.host/mysql.port/mysql.database/mysql.user/mysql.passworddoivent être identiques dansconfig.properties(Velocity) et dans chaqueconfig.yml(tous les serveurs Spigot : A, B, C...). C'est cette base commune qui permet à un joueur de voter hors ligne, puis de récupérer ses votes avec/claimsur n'importe lequel de vos serveurs. Des bases différentes =/claimne retrouvera jamais les votes stockés par Velocity. Voir aussi Stockage : MySQL ou YAML.
Build depuis les sources
mvn clean package
Jars produits dans velocity/target/ et spigot/target/.
Publier une release (Gitea)
GITEA_TOKEN=xxxx ./scripts/release.sh 1.0.1 "Description de la release"
Build les 2 jars, les zip dans dist/VoteNetwork.zip, crée le tag/release sur Gitea et y attache le zip. Nécessite un token Gitea (Paramètres → Applications → Générer un nouveau jeton, scope repo), passé uniquement en variable d'environnement — jamais commité.
Configuration
Chaque composant a son propre fichier, tous deux dans un dossier votenetwork :
| Composant | Fichier | Dossier |
|---|---|---|
| Velocity | config.properties |
plugins/votenetwork/ (racine du proxy) |
| Spigot | config.yml |
plugins/votenetwork/ (sur chaque serveur) |
Le config.yml Spigot regroupe tout ce qui est personnalisable :
storage:
type: mysql # mysql ou yaml
mysql:
host: 127.0.0.1
port: 3306
database: votenetwork
user: root
password: changeme
pool-size: 5
rewards:
vote-commands: # executees pour CHAQUE vote (direct ou via /claim, une fois par vote)
- "goldencrates give %player% vote_key 1"
broadcast: # message annonce a tout le serveur a chaque vote / claim
enabled: false
message: "&a[Vote] &e%player% &fvient de voter, merci a lui !"
voteparty:
votes-requis: 100 # déclenche le VoteParty à ce cumul (par serveur)
commands: # executees UNE fois quand le VoteParty se déclenche
- "goldencrates broadcast_give vote_key 1"
broadcast:
enabled: true
progress-message: "&b[Vote] &f%current%&7/&f%required% &fvotes avant le prochain VoteParty !"
triggered-message: "&a[Vote] &fVoteParty declenche ! Profitez des recompenses !"
messages:
direct-vote: "&a[Vote] &fMerci pour ton vote !"
claim-success: "&a[Vote] &fVous avez recupere &e%amount% &fvote(s) en attente !"
claim-empty: "&c[Vote] &fVous n'avez aucun vote en attente."
maintenance: "&c[Vote] &fLe systeme de vote est actuellement en maintenance."
maintenance-enabled: "&c[Vote] &fMode maintenance active."
maintenance-disabled: "&a[Vote] &fMode maintenance desactive."
no-permission: "&cVous n'avez pas la permission d'utiliser cette commande."
%player%dansrewards.vote-commandsest remplacé par le pseudo du joueur.%current%/%required%dans les messages de progression VoteParty.%amount%dans le message de succès/claimet dansrewards.broadcast.message.- Codes couleur
&supportés partout. rewards.broadcast(désactivé par défaut) : annonce publique à chaque vote direct ou à chaque/claim(avec le nombre de votes récupérés).
Stockage : MySQL ou YAML
Chaque composant choisit son stockage via storage.type, mais ce choix doit être le même partout (Velocity + tous les serveurs Spigot), avec les mêmes identifiants de connexion :
mysql(recommandé, seul mode fiable pour un vrai réseau) : Velocity et tous les serveurs Spigot pointent sur la même base (mêmehost/database/user/password). La tablenb_votes_attenteest créée automatiquement au démarrage si absente. Un vote stocké par Velocity (joueur hors ligne) est donc visible par/claimsur n'importe quel serveur.yaml: fichier localpending-votes.ymldans le dossier de chaque plugin (un par proxy, un par serveur). Pas synchronisé automatiquement entre eux. Si Velocity est enyamlet qu'un serveur Spigot vote pour lui-même enmysql(ou l'inverse),/claimne trouvera jamais les votes stockés côté proxy. N'utilisez ce mode qu'en solo/test, ou si tous les dossiers de plugins partagent le même disque (montage réseau, symlink) — sinon utilisezmysqlpartout.
Testez la connexion/l'accès au stockage configuré côté Spigot avec :
/vote testdb
Portée des votes en attente : partagée (global) ou par serveur (per-server)
En mode mysql uniquement, pending-votes.scope (dans config.properties côté Velocity) contrôle si le compteur de votes en attente est partagé entre tous les serveurs ou indépendant par serveur :
-
global(par défaut) : un seul compteur par joueur. Un/claimsur n'importe quel serveur le remet à 0 partout à la fois. -
per-server: chaque serveur listé dansdirect-vote.serversa son propre compteur. Un vote hors ligne incrémente le compteur de chaque serveur de la liste. Un/claimsur le serveur 1 ne remet à 0 que le serveur 1 — le joueur garde ses votes en attente sur le serveur 2 et peut les réclamer séparément là-bas.Exemple : le joueur vote 2 fois hors ligne → 2 votes en attente sur chaque serveur.
/claimsur le serveur 1 → 2 récompenses, serveur 1 repasse à 0, serveur 2 reste à 2. S'il revote une fois → serveur 1 = 1, serveur 2 = 3.
Pour activer per-server, il faut les deux :
pending-votes.scope=per-server+direct-vote.serversrempli dansconfig.properties(Velocity).storage.pending-votes-scope: per-server+server-name: "gen1"(nom exact tiré dedirect-vote.servers) dans leconfig.ymlde chaque serveur Spigot concerné.
Si ces réglages ne correspondent pas entre le proxy et un serveur (scope différent, ou server-name absent/mal orthographié), ce serveur ne retrouvera jamais les votes stockés par Velocity.
Fonctionnement du vote
- Un site de vote appelle la console du proxy :
votenetwork vote <pseudo>. - Joueur connecté ET sur un serveur listé dans
direct-vote.servers: le proxy envoie un paquet sur le canalvotenetwork:vote. Le serveur Spigot donne la récompense immédiatement et incrémente son VoteParty local de +1. Rien n'est écrit en base. - Joueur déconnecté, OU connecté mais sur un serveur absent de
direct-vote.servers(ex: un lobby sans le plugin) : le proxy résout son UUID (API Mojang, avec repli si indisponible) et incrémente son compteur de votes en attente (MySQL ou YAML selon la config), de façon asynchrone. - Le joueur tape
/claimsur un serveur Spigot : lecture asynchrone du compteur en attente, distribution des récompenses × N, VoteParty local +N, remise à 0. /vote stopbloque/claim(mode maintenance, message personnalisable) ;/vote startle réactive.
Important
:
direct-vote.servers(dansconfig.propertiescôté Velocity) doit lister les noms exacts des serveurs (tels que dansvelocity.toml) oùVoteNetwork-Spigot.jarest installé. Un joueur sur un serveur absent de cette liste (lobby, hub...) est traité comme "hors ligne" pour le vote — sinon le paquet direct part dans le vide (aucun plugin pour l'écouter) et le vote est perdu silencieusement.
Commandes & permissions
| Commande | Où | Qui | Description |
|---|---|---|---|
votenetwork vote <pseudo> |
Velocity | Console uniquement | Enregistre un vote pour le joueur |
/claim |
Spigot | Joueurs | Récupère les votes en attente |
/vote stop|start |
Spigot | votenetwork.admin (op par défaut) |
Bascule le mode maintenance |
/vote testdb |
Spigot | votenetwork.admin (op par défaut) |
Teste le stockage configuré (MySQL ou YAML) |
VoteParty
- Compteur indépendant par serveur, toujours persistant localement dans
plugins/votenetwork/voteparty.yml(indépendant destorage.type, qui ne concerne que les votes en attente), survit aux redémarrages. voteparty.votes-requisdéfinit le seuil de déclenchement.voteparty.commandss'exécutent une fois le seuil atteint, puis le compteur repart à 0 (avec report de l'excédent si plusieurs votes arrivent d'un coup, ex. via/claimde N votes).- Messages de progression et de déclenchement personnalisables (
voteparty.broadcast).
API publique (scoreboard / GUI)
Un autre plugin sur le même serveur Spigot peut lire l'état du vote via fr.votenetwork.spigot.api.VoteNetworkAPI :
VoteNetworkAPI api = VoteNetworkAPI.get();
// ou : Bukkit.getServicesManager().getRegistration(VoteNetworkAPI.class).getProvider();
int current = api.getVotePartyCurrentVotes();
int required = api.getVotePartyRequiredVotes();
boolean maintenance = api.isMaintenanceEnabled();
api.getPendingVotes(player.getUniqueId(), pending -> {
// callback rappelé sur le thread principal — safe pour un scoreboard/GUI
scoreboardLine.setText("Votes en attente: " + 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 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éées automatiquement si absentes (mode mysql), les deux tables coexistent toujours — seule celle correspondant à pending-votes.scope est utilisée :
-- scope = global (par defaut)
CREATE TABLE IF NOT EXISTS nb_votes_attente (
player_uuid VARCHAR(36) NOT NULL PRIMARY KEY,
player_name VARCHAR(16) NOT NULL,
nombre_votes INT DEFAULT 0
);
-- scope = per-server
CREATE TABLE IF NOT EXISTS nb_votes_attente_serveur (
player_uuid VARCHAR(36) NOT NULL,
server_name VARCHAR(64) NOT NULL,
player_name VARCHAR(16) NOT NULL,
nombre_votes INT DEFAULT 0,
PRIMARY KEY (player_uuid, server_name)
);
Notes techniques
- HikariCP + MySQL Connector/J sont shadés et relocalisés dans les deux jars (rien à installer manuellement sur le serveur). Le driver JDBC est chargé explicitement par son nom de classe relocalisé pour rester fiable après le shading.
- Toutes les requêtes SQL et I/O fichier sont asynchrones — aucun accès réseau ou disque ne bloque le thread principal du serveur ni celui du proxy.
- Si la connexion MySQL échoue au démarrage, le plugin reste actif (pas de crash) : corrigez
config.yml/config.propertiespuis utilisez/vote testdb, ou redémarrez. - Mise à jour de config : à chaque démarrage, les nouvelles options apportées par une mise à jour du plugin (absentes de votre
config.yml/config.propertiesexistant) sont ajoutées automatiquement, sans jamais toucher aux valeurs que vous avez déjà personnalisées. Côté Spigot, la réécriture duconfig.ymlfait perdre les commentaires (limitation de l'API Bukkit) ; côté Velocity, les nouvelles clés sont simplement ajoutées en bas duconfig.properties, les commentaires existants sont préservés.