Description
๐ณ๏ธ HyVote
A powerful Hytale plugin that rewards players for voting on server lists using both Votifier V1 and V2 protocols.
If you need any help, join our discord! https://discord.gg/fWgDuCThj2
โจ Features
- ๐ Reward Commands - Execute any server commands when players vote
- ๐ข Broadcast Messages - Announce votes to all online players with multiple messages
- ๐จ Color Support - Full color formatting with TaleMessage tags (
<green>,<gold>,<aqua>, etc.) - ๐ Vote Notifications - Send in-game UI notifications to voters
- ๐ Custom Sounds - Play sounds when players receive vote rewards
- ๐ Vote Menu -
/votecommand opens a GUI with clickable vote site links and top voters - ๐ Vote Leaderboards -
/votetopshows monthly and all-time top voters - โฐ Vote Reminders - Remind players who haven't voted in a while
- ๐พ Vote Database - JSON database tracks votes, monthly statistics, and pending rewards
- ๐ Dual Protocol Support - Both Votifier V1 (RSA) and V2 (HMAC-SHA256) on the same port
- ๐ก Vote Forwarding - Forward votes to other servers in your network
- ๐ฏ Event System -
VoteReceivedEventfor other plugins to integrate - ๐ Fully Translatable - All messages configurable via JSON configs
- ๐ง Debug Mode - Detailed logging for troubleshooting
๐ฎ Commands
- /vote - Opens the vote menu with vote sites and top voters
- /votetop - Shows top voters this month with your rank
- /votetop all - Shows top voters of all time with your rank
- /votetop previous - Shows top voters from the previous month
- /hyvote - Shows HyVote admin commands
- /hyvote test <player> - Send a test vote for a player (permission:
hytalist.hyvote.admin) - /hyvote reload - Reload all configuration files (permission:
hytalist.hyvote.admin) - /testvote <player> - Alias for testing if not taken by another plugin (permission:
hytalist.hyvote.admin)
๐จ Color Formatting
All messages support color tags: <green>, <gold>, <aqua>, <red>, <yellow>, <gray>, <white>, etc.
Example: <green>%player%</green> <gray>voted on</gray> <gold>%service%</gold>
See all options at TaleMessage CurseForge Page
๐ config.json
Main configuration for the Votifier server and global vote broadcast.

{
"Port": 8192,
"Token": "auto-generated-secure-token",
"DisableV1Protocol": false,
"BroadcastMessage": true,
"BroadcastWhenOffline": true,
"BroadcastMessages": [
"<green>%player%</green> <gray>has voted on</gray> <aqua>%service%</aqua><gray>!</gray>",
"<gold>Vote with <aqua>/vote</aqua> and check your stats with <aqua>/votetop</aqua></gold>"
],
"DebugMode": false,
"CheckForUpdates": true,
"CustomTokens": {
"ExampleServerListName": "random-generated-token"
}
}
- Port - Votifier server port (default: 8192)
- Host - Bind address (default: "0.0.0.0"). Not shown in config by default โ only add this if you need to bind to a specific interface.
- Token - Auto-generated V2 authentication token (used as default for all services)
- DisableV1Protocol - Disable V1 (RSA) protocol (default: false)
- BroadcastMessage - Enable global vote broadcast to all players (default: true)
- BroadcastWhenOffline - Broadcast votes even when the voter is offline (default: true)
- BroadcastMessages - Messages broadcast to all players on every vote
- DebugMode - Verbose logging (default: false)
- CheckForUpdates - Check for updates on startup (default: true)
- CustomTokens - Per-service V2 tokens for vote sites that generate their own token (see below)
Note: RSA keys for V1 protocol are auto-generated in rsa/public.key and rsa/private.key.
Custom Tokens (Per-Service)
Some server lists generate their own V2 token instead of letting you provide one. Use CustomTokens to set a different token for each service. The service name matching is case-insensitive.
"CustomTokens": {
"ExampleServerListName": "paste-token-from-that-site-here",
"AnotherList.net": "another-custom-token"
}
When a vote arrives, HyVote checks the service name against CustomTokens first. If a match is found, that token is used for HMAC verification. Otherwise, the default Token is used. Remove the example entry if you don't need it.
๐ rewards.json
Reward configuration with two systems: Rewards (independent rolls) and RandomReward (weighted pick, one result). Set "Enabled": false to disable all rewards (useful for hub servers that only broadcast votes).
{
"Enabled": true,
"Rewards": [
{
"WaitForPlayer": true,
"Commands": [
"give %player% Rock_Gem_Diamond --quantity 1",
"give %player% Rock_Gem_Emerald --quantity 5"
]
},
{
"Chance": 50.0,
"WaitForPlayer": true,
"Commands": [
"give %player% Ingredient_Bar_Silver --quantity 5"
]
},
{
"Permission": "vip.example",
"Commands": [
"money give %player% 5000"
]
}
],
"RandomReward": {
"Enabled": false,
"Tiers": []
}
}
Rewards
Each group rolls independently with its own chance. All commands within a group share the same chance and permission check -- either the whole group triggers or it doesn't.
- Chance - Chance for this group to trigger, 0-100 (default: 100)
- WaitForPlayer - Queue commands and player messages until player comes online (default: false). Recommended for
givecommands. Pending rewards expire after 3 days. - Permission - Required permission; group is skipped if player is offline or lacks permission (optional)
- Commands - List of commands to execute (array of strings)
- BroadcastMessages - Messages broadcast to all online players when this group triggers (optional). Sent immediately, even if the voter is offline.
- PlayerMessages - Messages sent directly to the voter when this group triggers (optional). If the voter is offline and
WaitForPlayeris true, messages are queued and delivered when the player joins. - Services - Limit this reward to specific vote services (optional, array of strings). If omitted or empty, the reward applies to all services. Matching is case-insensitive.
Service-Specific Rewards Example
Give different rewards depending on which vote site the player used:
"Rewards": [
{
"Commands": ["give %player% Rock_Gem_Diamond --quantity 1"],
"Services": ["Hytalist.com"]
},
{
"Commands": ["give %player% Rock_Gem_Emerald --quantity 1"],
"Services": ["AnotherVoteSite.net", "ThirdSite.org"]
},
{
"Commands": ["give %player% Coin --quantity 100"]
}
]
In this example:
- Voting on Hytalist.com gives a diamond
- Voting on AnotherVoteSite.net or ThirdSite.org gives an emerald
- The last reward (100 coins) has no Services filter, so it applies to all vote sites
RandomReward
A weighted tier system where exactly one tier is picked per vote (or nothing). Useful for crate/loot table style rewards. All tier chances are summed -- if the total is less than 100, the remainder is the chance of getting nothing.
Example with tiers summing to 30 (70% chance of getting nothing):
"RandomReward": {
"Enabled": true,
"Tiers": [
{
"Chance": 20.0,
"WaitForPlayer": true,
"Commands": ["give %player% Rare_Crate --quantity 1"],
"PlayerMessages": ["<aqua>You received a <white>Rare</white> crate!</aqua>"]
},
{
"Chance": 10.0,
"WaitForPlayer": true,
"Commands": ["give %player% Legendary_Crate --quantity 1"],
"PlayerMessages": ["<gold>You received a <white>Legendary</white> crate!</gold>"],
"BroadcastMessages": ["<gold>%player%</gold> <gray>found a</gray> <gold>Legendary</gold> <gray>crate!</gray>"]
}
]
}
Each tier supports the same options as reward groups: Chance (weight), WaitForPlayer, Permission, Commands, BroadcastMessages, PlayerMessages, Services.
Tiers with a Permission requirement are excluded from the roll for players who lack the permission -- the remaining tiers are rolled among as if the restricted tier didn't exist.
๐ท๏ธ Placeholders
Use these in commands and messages (both %placeholder% and {placeholder} formats supported):
- %player% - Username of the player who voted
- %service% - Name of the voting service
- %address% - IP address of the voter
- %timestamp% - Unix timestamp of the vote
๐ notification.json
Configure notifications sent to players when they vote. Supports multiple notification types.

{
"Title": {
"Enabled": false,
"Title": "<green>Reward Received!</green>",
"Subtitle": "<gray>Thanks for voting on</gray> <aqua>%service%</aqua><gray>!</gray>",
"DurationSeconds": 3,
"FadeInSeconds": 0.5,
"FadeOutSeconds": 0.5
},
"Notification": {
"Enabled": true,
"Title": "<green>Reward Received!</green>",
"Description": "<gray>Thanks for your vote on</gray> <aqua>%service%</aqua><gray>!</gray>",
"IconItem": "Rock_Gem_Diamond"
},
"Chat": {
"Enabled": false,
"Messages": [
"<green>Reward Received!</green>",
"<gray>Thanks for your vote on</gray> <aqua>%service%</aqua><gray>!</gray>"
]
},
"Sound": {
"Enabled": true,
"Name": "SFX_Player_Pickup_Item"
}
}
Title Options (Big text on screen)
- Enabled - Show title on screen (true/false, default: false)
- Title - Main title text, supports colors & placeholders (string)
- Subtitle - Subtitle text below the title (string)
- DurationSeconds - How long the title stays on screen (integer)
- FadeInSeconds - Fade in duration (float)
- FadeOutSeconds - Fade out duration (float)
Notification Options (Small popup)
- Enabled - Show notification popup (true/false, default: true)
- Title - Notification title, supports colors & placeholders (string)
- Description - Notification description, supports colors & placeholders (string)
- IconItem - Item icon to display (string)
Chat Options
- Enabled - Send messages to voter's chat (true/false, default: false)
- Messages - Array of messages to send, supports colors & placeholders (array of strings)
Sound Options
- Enabled - Play sound on vote (true/false, default: true)
- Name - Sound event name, e.g.
SFX_Player_Pickup_Item(string)
๐ voteCommand.json
Configure the /vote command and vote site links. You can toggle UI, Chat or both.


{
"Enabled": true,
"VoteLinks": {
"Hytalist.com": "https://hytalist.com/test-server?nick=%player%",
"AnotherServerList": "https://example.com"
},
"UI": {
"Enabled": true,
"Title": "Vote for the Server",
"VoteLinkTitle": "Vote Link (Copy and open in Browser)",
"VoteLinkDescription": "Click a site above to see the vote link"
},
"Chat": {
"Enabled": true,
"Header": "<gray>========== <green>Vote Links</green> ==========</gray>",
"Format": "<yellow>#[</yellow><aqua>%iterator%</aqua><yellow>]</yellow> <white><click:%siteUrl%>%siteUrl%</click></white>",
"Footer": "<gray>===================================</gray>"
}
}

Options
- Enabled - Enable/disable the /vote command entirely (true/false)
- VoteLinks - Map of site names to vote URLs (object)
UI Options
- Enabled - Show the vote GUI (true/false)
- Title - Title displayed at the top of the GUI (string)
- VoteLinkTitle - Label above the URL text field (string)
- VoteLinkDescription - Placeholder text in URL field before selection (string)
Chat Options
- Enabled - Send vote links to chat (true/false)
- Header - Message shown before the links, supports colors (string)
- Format - Format for each link with placeholders:
%iterator%(number starting from 1),%siteUrl%,%siteName%(string) - Footer - Message shown after the links, supports colors (string)
The %player% placeholder in URLs will be replaced with the player's username (both %player% and {player} formats work).
๐ voteTopCommand.json
Configure the /votetop command leaderboards. You can toggle UI, Chat or both (UI enabled by default).

{
"Enabled": true,
"UI": {
"Enabled": true,
"Limit": 25,
"Title": "Top Voters",
"MonthlyTitle": "This Month",
"PreviousMonthTitle": "Previous Month",
"AllTimeTitle": "All Time",
"YourRankLabel": "Your Rank",
"NoVotesYet": "No votes recorded yet",
"NoRankYet": "Vote to get ranked!",
"PlayerDescription": "%votesThisMonth% this month / %votes% total"
},
"Chat": {
"Enabled": false,
"Limit": 10,
"Header": "<gray>=========</gray> <green>Top Voters</green> <gray>(%period%)</gray> <gray>=========</gray>",
"Format": "<yellow>#%rank%</yellow> <aqua>%player%</aqua> <gray>(votes: %votes%)</gray>",
"Footer": "<gray>-----------------------------------------</gray>",
"YourRankFormat": "<gray>Your rank:</gray> <aqua>#%rank%</aqua> <gray>(votes: %votes%)</gray>",
"NoVotesYet": "<gray>No votes recorded yet.</gray>",
"NoRankYet": "<gray>Your rank:</gray> <dark_gray>No votes yet</dark_gray>"
}
}
Options
- Enabled - Enable/disable the /votetop command entirely (true/false)
UI Options
- Enabled - Show the vote top GUI with 3 tabs: This Month, Previous Month, All Time (true/false, default: true)
- Limit - Maximum number of top voters to display (integer, default: 25)
- Title - Title displayed at the top of the GUI (string)
- MonthlyTitle - Label for the current month tab (string)
- PreviousMonthTitle - Label for the previous month tab (string)
- AllTimeTitle - Label for the all-time tab (string)
- YourRankLabel - Label above the player's rank (string)
- NoVotesYet - Message when no votes recorded (string)
- NoRankYet - Message when player has no rank (string)
- PlayerDescription - Description shown below each player name with placeholders:
%votesThisMonth%,%votes%(string)
Chat Options
- Enabled - Send leaderboard to chat (true/false, default: false)
- Limit - Maximum number of top voters to display (integer, default: 10)
- Header - Header message with
%period%placeholder for "January 2025" or "All Time" (string) - Format - Format for each voter entry with placeholders:
%rank%,%player%,%votes%(string) - Footer - Footer message (string)
- YourRankFormat - Format for showing player's own rank (string)
- NoVotesYet - Message when no votes recorded (string)
- NoRankYet - Message when player has no rank (string)
โฐ reminder.json
Configure vote reminders for players who haven't voted recently.


{
"Enabled": true,
"AfterHours": 24,
"DelayInSeconds": 60,
"CheckIntervalSeconds": 60,
"Title": {
"Enabled": true,
"Title": "Vote Reminder",
"Subtitle": "Use /vote to support the server!",
"DurationSeconds": 3,
"FadeInSeconds": 0.5,
"FadeOutSeconds": 0.5
},
"Notification": {
"Enabled": false,
"Title": "<gold>Vote Reminder</gold>",
"Description": "<gray>You haven't voted in a while!</gray> <aqua>Use /vote</aqua>",
"IconItem": "Rock_Gem_Diamond"
},
"Chat": {
"Enabled": false,
"Messages": [
"<gold>You haven't voted in a while!</gold>",
"<gray>Support the server by voting:</gray> <aqua>/vote</aqua>"
]
},
"Sound": {
"Enabled": true,
"Name": "SFX_UI_Quest_Objective_Complete"
}
}
Options
- Enabled - Enable/disable vote reminders (true/false)
- AfterHours - Remind players who haven't voted in X hours (integer, default: 24)
- DelayInSeconds - Wait X seconds after player joins before checking (integer, default: 60)
- CheckIntervalSeconds - How often to check for reminders (integer, default: 60)
Title Options (Big text on screen)
- Enabled - Show title on screen (true/false, default: true)
- Title - Main title text (string)
- Subtitle - Subtitle text below the title (string)
- DurationSeconds - How long the title stays on screen (integer)
- FadeInSeconds - Fade in duration (float)
- FadeOutSeconds - Fade out duration (float)
Notification Options (Small popup)
- Enabled - Show notification popup (true/false, default: false)
- Title - Notification title, supports colors (string)
- Description - Notification description, supports colors (string)
- IconItem - Item icon to display (string)
Chat Options
- Enabled - Send reminder messages to chat (true/false, default: false)
- Messages - Array of messages to send (array of strings)
Sound Options
- Enabled - Play sound with reminder (true/false, default: true)
- Name - Sound event name (string)
๐ก forwarding.json
Forward votes to other servers in your network. Useful for BungeeCord/Velocity-style setups where you want votes received on a proxy to be forwarded to backend servers, or vice versa.
{
"Enabled": false,
"Targets": [
{
"Host": "127.0.0.1",
"Port": 8192,
"Token": "target-server-token"
},
{
"Host": "192.168.1.100",
"Port": 8192,
"Token": "another-server-token"
}
]
}
Options
- Enabled - Enable/disable vote forwarding (true/false, default: false)
- Targets - Array of target servers to forward votes to
Target Options
- Host - IP address or hostname of the target server (string)
- Port - Votifier port of the target server (integer, default: 8192)
- Token - Votifier V2 token of the target server (string)
How It Works
- When HyVote receives a vote, it processes it locally (rewards, broadcasts, etc.)
- If forwarding is enabled, it sends the vote to all configured targets
- Forwarding uses Votifier V2 protocol with HMAC-SHA256 authentication
- Each target server receives the vote as if it came directly from the vote site
- Forwarding happens asynchronously and won't slow down local vote processing
Example Use Cases
- Proxy โ Backend: Receive votes on your proxy server and forward to game servers
- Hub โ Game Servers: Forward votes from a hub server to multiple game mode servers
- Redundancy: Forward votes to a backup server for logging/statistics
Note: The target server must have HyVote (or another Votifier V2 compatible plugin) running. Make sure the token matches the target server's config.
๐ Vote Statistics
HyVote automatically tracks vote statistics in the database/ folder:
- votes.json - Stores total vote count per player (all-time)
- votes-YYYY-MM.json - Monthly vote files (e.g.,
votes-2025-01.json) - pending_rewards.json - Queued rewards for offline players (auto-cleaned after 3 days)
This data powers:
/votetopcommand showing monthly leaderboards/votetop allcommand showing all-time leaderboards- Top 3 voters displayed in the
/voteUI menu - Player rank shown at the bottom of leaderboards
Old monthly files are kept for historical records and can be safely deleted if not needed.
๐ Setting Up Vote Sites
For Votifier V2 (Recommended)
- Get your token from
config.json(auto-generated on first run) - Configure your server list with:
- IP/Host: Your server IP
- Port: 8192 (or your configured port)
- Token: Copy from config.json
- Protocol: Votifier V2
For Votifier V1 (Legacy)
Get your public key from
rsa/public.key(auto-generated on first run)Configure your server list with:
- IP/Host: Your server IP
- Port: 8192 (same port as V2)
- Public Key: Copy content from public.key
- Protocol: Votifier V1
Test the setup by enabling
DebugModeand voting
๐ง Troubleshooting
Votes not being received
- โ
Enable
DebugModein config.json - โ Check firewall - ensure Votifier port is open
- โ Verify token matches between config and vote site
- โ
Check server logs for
HyVotemessages
Common Issues
- "Invalid signature" (V2) - Token mismatch. If the vote site generates its own token, add it to
CustomTokensin config.json - "Failed to decrypt" (V1) - Public key mismatch, copy full content from rsa/public.key
- "No response" - Check firewall/port configuration
๐จโ๐ป For Developers
Full API documentation is available at github.com/hytalist/hyvote-api. The API allows you to retrieve player votes, monthly statistics, rankings, and more.
Installation
Add the HyVote API to your project:
Gradle (Kotlin DSL)
repositories {
maven { url = uri("https://jitpack.io") }
}
dependencies {
compileOnly("com.github.hytalist:hyvote-api:1.6.0")
}
Gradle (Groovy)
repositories {
maven { url 'https://jitpack.io' }
}
dependencies {
compileOnly 'com.github.hytalist:hyvote-api:1.6.0'
}
Maven
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>com.github.hytalist</groupId>
<artifactId>hyvote-api</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
VoteReceivedEvent
Listen to vote events from other plugins:
Java
import com.hytalist.hyvote.event.VoteReceivedEvent;
import com.hytalist.hyvote.model.Vote;
@Override
public void setup() {
eventRegistry.registerGlobal(VoteReceivedEvent.class, event -> {
Vote vote = event.getVote();
String player = vote.getUsername();
String service = vote.getServiceName();
// Cancel default rewards
event.setCancelled(true);
// Handle with custom logic
});
}
Kotlin
import com.hytalist.hyvote.event.VoteReceivedEvent
override fun setup() {
eventRegistry.registerGlobal(VoteReceivedEvent::class.java) { event ->
val vote = event.vote
val player = vote.username
val service = vote.serviceName
// Cancel default rewards
event.setCancelled(true)
// Handle with custom logic
}
}
๐ Credits
- Protocol based on NuVotifier specification
- Color formatting powered by TaleMessage
Made with โค๏ธ for the Hytale community


