3 releases, newest first.
templates: entry of guis/rankup-list.yml can now set material and glow, and they
are actually applied: both fields used to parse fine and do nothing, because SnLib's stack
overlay crosses only display-name and lore onto a plugin-supplied stack. One line now
dresses every tile of a state instead of repeating the field on every rank.rankup-button in guis/rankup-menu.yml (menu.mode: single).basehead-<base64> works on a template exactly like it does on a rank.menu-item.states.<state> beats the template,
the template beats the rank's base menu-item. A file that declares neither field behaves
exactly as before, so nothing existing changes look.CFC00 is replaced by the fleet accent ₢f2 across both language files (prefix and the snlib.help header / entry / footer).₢f2&lRank Menu and ₢f2&lRank Ladder, item names use the accent, lore uses &8 separators, &7 body text and &f values, and the page buttons read ₢f2Previous Page / ₢f2Next Page. The single-menu rankup button now uses the same semantic &a&lCLICK TO RANK UP the paginated ladder already used.rankup.yml moved off the ad-hoc yellow/lime palette onto accent headers plus semantic colour codes.config.yml band banners no longer carry numbers. They read 1 MODEL, 3 LIMITS, 4 INTEGRATIONS, which looked like a section was missing - the plugin simply has no band-2 (features) keys.top moved from the LIMITS band to FEEDBACK, where the standard places leaderboards, and the redundant double banners were collapsed into one per band.No Java changed. Because SnLib never overwrites a value that already exists on disk, the new colours apply to fresh installs; an existing server keeps whatever is in its own lang/, guis/ and rankup.yml files. To adopt them, delete those files (or the individual values) and let SnLib re-seed them on the next boot.
Rank ladder for Paper 1.20.x and 1.21.x. Every rank lives in one file, a rank is priced in whatever currency your server already runs, and the menu players open is a YAML file you lay out yourself.
Each rank is one entry in rankup.yml with an order and a display prefix. Orders do not need to be contiguous, so 10, 20, 30 leaves room to insert a rank later without renumbering anything. The lowest order is the starting rank: everyone begins there, and since nobody ever reaches it, its requirements are never charged and its rewards never fire.
requirements and rewards describe reaching a rank, not leaving it. A rankup checks and charges the price of the rank the player is going to, and fires that rank's rewards.
hours is always available and needs no setup: it is the player's playtime, and it is checked, never charged.
Every other price is a currency you declare in config.yml, and two types ship:
vault reads and charges the Vault economy, so any economy plugin works.placeholder reads a balance from any PlaceholderAPI placeholder and charges by running a console command: check, consume, and optionally deposit so refunds are possible. {amount} and %player% are substituted in both commands. That covers tokens, gems, points and anything else a plugin exposes as a placeholder.Requirements are checked and charged in the order you wrote them, and if a later charge is refused everything already taken is handed back. A currency whose backing plugin is not installed is skipped at load with a warning and every requirement naming it is dropped, which makes that rank cheaper rather than unreachable.
Any SnLib action tag works: [broadcast], [message], [console], [title], [actionbar], [sound] and the [chance=50] guard. A line with no tag runs as a console command. %player% and PlaceholderAPI resolve per line.
Two of them, and menu.mode in config.yml decides which one /rankup opens.
single shows one dynamic button for the next rank, styled by that rank's own menu-item, with the live leaderboard beside it. paginated lays the whole ladder out one slot per rank, opens on the page holding your next rank, and renders each tile in one of four states: claimed, ready, next, locked. Exactly one tile is ever ready or next.
Both are ordinary guis/*.yml files: a title, rows, a character grid for the layout and items you can move, restyle or delete. Rank lore takes hex colors, MiniMessage, PlaceholderAPI tokens, and the plugin's own {req_hours}, {req_<currency>}, {missing_hours}, {missing_<currency>} and {current_hours}, so a tile can show both the price and what the player still lacks without PlaceholderAPI installed.
A snapshot of the highest ranked players, rebuilt on the database thread every top.refresh-seconds and exposed as %snrankup_top_name_<N>% and %snrankup_top_value_<N>%. Those two answer even when there is no requesting player, so holograms, signs and Discord bridges get a real value instead of an empty string.
/rankup opens the menu. Its aliases are ru and rank, and they are re-read on reload.
Admin side: /rankup force <player> advances one rank and fires that rank's rewards, /rankup set <player> <rank> writes a rank with no charge and no rewards, /rankup reset <player> puts a player back on the starting rank, and /rankup bypass [player] toggles ignoring rank requirements for you or for someone else. /rankup reload, /rankup help and /rankup debug come with the framework. Every argument tab-completes.
Optional. %snrankup_prefix%, %snrankup_num%, %snrankup_next_prefix% and %snrankup_next_num% resolve anywhere, alongside the two leaderboard placeholders. The shipped menus use them, so on a server without PlaceholderAPI those lines render blank while everything else keeps working.
SQLite by default, with nothing to configure. MySQL by setting database.type and filling the connection block. Every read and write happens off the server thread.