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.
This page is older than Keystone 0.2.8, released 18 October 2026. Something may have changed since.
On this page 3 parts
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-timedecides whether standing in a corner counts. Off, andidle-after(default five minutes) is when somebody stops counting as playing.announcesays 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.
rewardsis 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.streaksrewards voting several days running. A streak reward is paid once on its day, not once per vote that day.party-goal,party-windowandparty-rewardsare the whole-server version: reach so many votes inside a window and everybody gets something.announceandannounce-cooldownsay it in chat without turning a busy evening into a wall.time-zonedecides when a day rolls over, which is what a streak counts.serviceslists 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 tovotes.site-cooldown(default1h30m) 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. Setsite-cooldowna little under the sites' own reset (at least1m);votes.site-cooldownsgives a site its own interval, onesite=durationeach —minecraft-mp.com=23h.once-a-daycounts 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.