STYGION Documentation Search the docs

Ranks, votes and the tab list

Promotions that happen on their own, vote rewards that wait for the player, and a tab list that says who is who.

Keystone 0.2.8 Updated 6 min read

This page is older than Keystone 0.2.8, released 18 October 2026. Something may have changed since.

On this page 3 parts
  1. Ranks earned by playing
  2. Votes
  3. The tab list

Ranks, votes and the tab list

Ranks earned by playing

#

progress.toml. promotions is the ladder: how long somebody has to have played, and what they get when they get there. Keystone checks every check-every and writes progress down every write-every, so a crash costs at most half a minute of somebody's evening.

  • count-idle-time decides whether standing in a corner counts. Off, and idle-after (default five minutes) is when somebody stops counting as playing.
  • announce says it out loud when somebody moves up. This is the whole point of a rank; a promotion nobody sees is a database row.

/playtime says how long somebody has played; /playtime <player> asks about somebody else, behind keystone.playtime.others.

Nobody has to run anything weekly. That is the feature.

Votes

#

votes.toml. Keystone listens for the vote itself — address and port (default 8192) are where the vote sites reach it, and sites is which ones you are listed on. /keystone votes keys prints what a site needs from you.

address is empty by default and nothing listens until you set it. That is deliberate: opening a port is a decision.

  • rewards is what a vote is worth. A reward waits for a player who was offline rather than evaporating, which is the thing most setups get wrong. A reward can be a crate key too: keystone crate give {player} 1.
  • streaks rewards voting several days running. A streak reward is paid once on its day, not once per vote that day.
  • party-goal, party-window and party-rewards are the whole-server version: reach so many votes inside a window and everybody gets something.
  • announce and announce-cooldown say it in chat without turning a busy evening into a wall.
  • time-zone decides when a day rolls over, which is what a streak counts.
  • services lists the site names a vote may carry, exactly as the log shows them (Ada voted on Czech-Craft.eu). A vote naming any other site is not counted — the name is whatever the sender writes. Empty takes every name, and the log says so at start.

Both of the protocols vote sites use are supported (NuVotifier v1 and v2), at once — so it works on all of them rather than half.

Which votes count (0.2.2). votes.count picks the rule:

  • every-reset — the default — counts every vote a site lets somebody make, held only to votes.site-cooldown (default 1h30m) per site and person. Lists that let people vote every two hours pay every two hours. A site already refuses a vote before its own reset, so this never pays more than the site allows. Set site-cooldown a little under the sites' own reset (at least 1m); votes.site-cooldowns gives a site its own interval, one site=duration each — minecraft-mp.com=23h.
  • once-a-day counts one vote per site per voting day, the way Keystone did before 0.2.2 and most Votifier plugins do — for a server that wants a day's rewards to be the same whichever lists its players use.

Either way there is a daily ceiling, votes.limit.per-day. At 0 — the default — it is worked out from the intervals: each site in services as many times as its interval fits in a day (with no names listed, each line of sites at site-cooldown, ten sites when there are none), so somebody who votes after every reset never meets it, while a sender inventing votes does. The whole port takes at most votes.limit.per-minute (30) a minute, counted per site, so one noisy sender does not shut out the honest ones. A vote counts as when it arrived here, never as the sender dated it, and one dated more than a day from this server's clock is refused. The original protocol is encrypted with a key every vote site holds, so its dates and site names are whatever the sender liked. votes.accept-v1 = false takes only signed v2 votes. A sender that trickles bytes is cut off after ten seconds, and no more than 32 connections are open at once. Streaks still count days.

A vote that does not count says so in game: too soon on that site (and when it will count again) or the day's ceiling — at once if the player is online, on their next join if not — beside the lines that already say a vote waits for time played or a Discord link. One such line per player per five minutes, so votes made up in somebody's name cannot fill their chat. A site's name is matched to services however it is spelt, so capitals and spaces do not get a vote past its interval. The editor's Votes screen shows the rules in force.

A vote pays a person, not a name. On a server in offline mode a name costs nothing, so a vote is always written down but pays only somebody who has played here for votes.pay.played (default 30 minutes) — a name nobody has joined as is never paid — and, with votes.pay.discord, whose account is linked to Discord. Linked accounts count as their Discord account: several names on one Discord share one site's interval, one voting day's limit.per-day and one streak reward a day. Waiting votes pay as soon as the conditions are met, and the player is told on joining what is missing.

Only the owner changes vote rewards. Rewards, streaks, party rewards and crate loot run as the console, so in game only the owner (a level-4 operator) may change them.

The tab list

#

tablist.toml — what the list shows and how often it is redrawn (three seconds by default). The header, the footer and the prefix and suffix on a name are built out of ranks, so somebody who is a supporter and a moderator reads as both.

Every rank's prefix (0.2.2). {prefix} is the prefix of the heaviest group somebody holds. {prefixes} is the prefix of every group they hold, heaviest first, a space between — [Staff] [VIP+]. A group that another of theirs inherits from is left out (VIP+ built on VIP shows only [VIP+]), and each prefix starts from a clean style. It works in the tab list (name, header and footer), in the chat format (chat.format) and in the join and leave lines (chat.presence); {prefix} stays for servers that want only the heaviest.

Ordering is honoured where the game has a notion of one: from Minecraft 1.21.2 the client sorts by a number the server sends, and that number is the rank's own weight. On older versions the only way is scoreboard teams, which take over name colours, nameplate visibility and friendly fire from whatever else is using them — so it is left alone there.

What the tab list does today, the server does on its own, and a vanilla client sees it. Columns, faces and badges in the mod's own type need the client half, and are not imitated here as "a list of names with brackets around them".

Did this page help?

Opens the feedback panel with this page attached. It lands in the same queue as everything else.