Repository navigation
🥇 Ranking System
CraftEngine BitmapImage spritesheet (3×12 grid). Each rank within a prestige is 25% harder to reach than the previous one, but the growth rate is nerfed per prestige to keep Gold accessible. Players start unranked and must earn 10,000 XP to achieve their first rank.
Prestige nerf coefficients (applied to the growth rate, not to XP earnings):
- Bronze: ×1.0 → all 12 ranks use the full ×1.25 multiplier
- Silver: ×0.8 → effective multiplier = 1 + 0.25 × 0.8 = ×1.20
- Gold: ×0.5 → effective multiplier = 1 + 0.25 × 0.5 = ×1.125
This means each prestige curves more gently than the last, so Gold Ruby III requires ~14K games instead of ~80K.
Spritesheet Grid (3 rows × 12 columns)
Each row is a prestige; each column is a rank within that prestige:
| Row | Prestige | Cols 0–2 | Cols 3–5 | Cols 6–8 | Cols 9–11 |
|---|---|---|---|---|---|
| 0 | Bronze | Emerald I–III | Amethyst I–III | Diamond I–III | Ruby I–III |
| 1 | Silver | Emerald I–III | Amethyst I–III | Diamond I–III | Ruby I–III |
| 2 | Gold | Emerald I–III | Amethyst I–III | Diamond I–III | Ruby I–III |
Rank index = row × 12 + col (0–35).
-
rankIndex / 12→ prestige index (0=Bronze, 1=Silver, 2=Gold) -
rankIndex % 12→ position within prestige -
(rankIndex % 12) / 3→ gem index (0=Emerald, 1=Amethyst, 2=Diamond, 3=Ruby) -
(rankIndex % 12) % 3→ gem level (0→I, 1→II, 2→III), displayed as +1
Unranked State: A player with totalXP < 10,000 has rankIndex = -1. No rank image is shown — instead, a progress bar toward the first rank is displayed.
Formula: Each prestige has its own effective multiplier: effMultiplier = 1 + (RANK_MULTIPLIER - 1) × PRESTIGE_NERF[prestige]
| Prestige | Nerf | effMultiplier | Formula within prestige |
|---|---|---|---|
| Bronze (ranks 0–11) | ×1.0 | ×1.25 | threshold(n) = 10_000 × 1.25ⁿ |
| Silver (ranks 12–23) | ×0.8 | ×1.20 | threshold(12+k) = threshold(11) × 1.20^(k+1) |
| Gold (ranks 24–35) | ×0.5 | ×1.125 | threshold(24+k) = threshold(23) × 1.125^(k+1) |
Thresholds are cumulative — totalXP must reach or exceed a threshold to attain that rank.
Full Table:
| # | Prestige | Gem | Lvl | Eff. mult. | Cumul. XP | XP → next | ~2v2 games |
|---|---|---|---|---|---|---|---|
| -1 | (unranked) | — | — | — | 0 | 10,000 | 0 |
| 0 | Bronze | Emerald | I | ×1.250 | 10,000 | 2,500 | 32 |
| 1 | Bronze | Emerald | II | ×1.250 | 12,500 | 3,125 | 40 |
| 2 | Bronze | Emerald | III | ×1.250 | 15,625 | 3,906 | 50 |
| 3 | Bronze | Amethyst | I | ×1.250 | 19,531 | 4,883 | 63 |
| 4 | Bronze | Amethyst | II | ×1.250 | 24,414 | 6,103 | 79 |
| 5 | Bronze | Amethyst | III | ×1.250 | 30,518 | 7,630 | 99 |
| 6 | Bronze | Diamond | I | ×1.250 | 38,148 | 9,537 | 123 |
| 7 | Bronze | Diamond | II | ×1.250 | 47,685 | 11,921 | 154 |
| 8 | Bronze | Diamond | III | ×1.250 | 59,606 | 14,902 | 193 |
| 9 | Bronze | Ruby | I | ×1.250 | 74,508 | 18,627 | 241 |
| 10 | Bronze | Ruby | II | ×1.250 | 93,135 | 23,284 | 302 |
| 11 | Bronze | Ruby | III | ×1.250 | 116,419 | 23,284 | 377 |
| 12 | Silver | Emerald | I | ×1.200 | 139,703 | 23,284 | 453 |
| 13 | Silver | Emerald | II | ×1.200 | 167,644 | 27,941 | 544 |
| 14 | Silver | Emerald | III | ×1.200 | 201,173 | 33,529 | 653 |
| 15 | Silver | Amethyst | I | ×1.200 | 241,408 | 40,235 | 783 |
| 16 | Silver | Amethyst | II | ×1.200 | 289,690 | 48,282 | 940 |
| 17 | Silver | Amethyst | III | ×1.200 | 347,628 | 57,938 | 1,128 |
| 18 | Silver | Diamond | I | ×1.200 | 417,154 | 69,526 | 1,354 |
| 19 | Silver | Diamond | II | ×1.200 | 500,585 | 83,431 | 1,625 |
| 20 | Silver | Diamond | III | ×1.200 | 600,702 | 100,117 | 1,950 |
| 21 | Silver | Ruby | I | ×1.200 | 720,842 | 120,140 | 2,340 |
| 22 | Silver | Ruby | II | ×1.200 | 865,010 | 144,168 | 2,808 |
| 23 | Silver | Ruby | III | ×1.200 | 1,038,012 | 129,752 | 3,370 |
| 24 | Gold | Emerald | I | ×1.125 | 1,167,764 | 145,970 | 3,791 |
| 25 | Gold | Emerald | II | ×1.125 | 1,313,734 | 164,217 | 4,265 |
| 26 | Gold | Emerald | III | ×1.125 | 1,477,951 | 184,744 | 4,798 |
| 27 | Gold | Amethyst | I | ×1.125 | 1,662,695 | 207,837 | 5,398 |
| 28 | Gold | Amethyst | II | ×1.125 | 1,870,532 | 233,816 | 6,073 |
| 29 | Gold | Amethyst | III | ×1.125 | 2,104,348 | 263,044 | 6,832 |
| 30 | Gold | Diamond | I | ×1.125 | 2,367,392 | 295,924 | 7,686 |
| 31 | Gold | Diamond | II | ×1.125 | 2,663,316 | 332,914 | 8,647 |
| 32 | Gold | Diamond | III | ×1.125 | 2,996,230 | 374,529 | 9,728 |
| 33 | Gold | Ruby | I | ×1.125 | 3,370,759 | 421,345 | 10,944 |
| 34 | Gold | Ruby | II | ×1.125 | 3,792,104 | 474,013 | 12,312 |
| 35 | Gold | Ruby | III | ×1.125 | 4,266,117 | — | 13,851 |
When a player crosses a prestige boundary (rank 11→12 Bronze→Silver, or rank 23→24 Silver→Gold), fire a distinct celebration event:
- Custom title/subtitle (e.g.
"§6✧ Prestige Argent ✧") - Unique sound different from normal rank-up
- Broadcast a server message:
"{player} §7a atteint le prestige §e{name}§7!"
Detect in PlayerLevelManager.addXP(): if getRankIndexAfter() / 12 > getRankIndexBefore() / 12, trigger prestige celebration instead of normal rank-up sound.
Base XP Values (per event):
| Event | Base XP | Notes |
|---|---|---|
| Kill | +15 | Awarded to killer |
| Assist | +8 | Awarded per assister (≥25% of killer's damage to victim) |
| Bed destroy | +30 | Awarded to the destroyer player |
| Win | +200 | Awarded to every player on the winning team |
| Loss | 0 | No XP for losing |
| Death | 0 | No XP penalty on death |
Game Mode Coefficients — each game awards baseXP × coefficient:
| Teams | 1v1 | 2v2 | 3v3 | 4v4 |
|---|---|---|---|---|
| 2 | 1.00 | 1.15 | 1.25 | 1.35 |
| 3 | 1.05 | 1.20 | 1.30 | 1.40 |
| 4 | 1.10 | 1.25 | 1.35 | 1.45 |
-
destroyedBedsstat never incremented —Game.onBedDestroyed()must callstat.setCurrentDestroyedBeds(...)on the destroyer -
Remove legacy methods:
recalculateLevelFromStats(UUID),calculateTotalXP(PlayerStatistic),calculateLevel(int)— XP is awarded per-action, not derived -
totalXPtype: int → long everywhere —PlayerLevel.totalXP,addXP()param,PlayerLevelManager.addXP()param. Gold Ruby III requires ~4.2M;intmax is 2.1B but future-proofing matters -
current_xpcolumn orphaned — Hibernate never drops columns; migration script must explicitlyDROP COLUMN IF EXISTS current_xp -
Existing
totalXPdoesn't map cleanly — old rates (win=100, death=-10) vs new (win=200, death=0). Recompute from lifetime stats via migration query -
Hologram leaderboard references removed methods —
PlayerLevel.getTierIcon(lvl)/tierColorMiniMessage(lvl)gone. Use rank MiniMessage tag from spritesheet -
Scoreboard uses removed methods —
getCurrentXP()→getProgressInRank(),getXPForNextLevel()→getXPToNextRank() -
Prestige crossover celebration — when
rankIndexAfter / 12 > rankIndexBefore / 12, fire distinct title/subtitle, unique sound, broadcast message -
Legacy game mode coefficient default — since legacy mode has no
GameRoomConfig,Game.javamust declareprivate double coefficient = 1.0;so it always defaults to 1.0 without a setter call