Skip to content

🥇 Ranking System

Walid Korchi edited this page Jun 13, 2026 · 1 revision

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.

Rank Structure

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.

XP Thresholds

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

Prestige crossover celebration

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.

XP Earning

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

Edge Cases

  1. destroyedBeds stat never incremented — Game.onBedDestroyed() must call stat.setCurrentDestroyedBeds(...) on the destroyer
  2. Remove legacy methods: recalculateLevelFromStats(UUID), calculateTotalXP(PlayerStatistic), calculateLevel(int) — XP is awarded per-action, not derived
  3. totalXP type: int → long everywhere — PlayerLevel.totalXP, addXP() param, PlayerLevelManager.addXP() param. Gold Ruby III requires ~4.2M; int max is 2.1B but future-proofing matters
  4. current_xp column orphaned — Hibernate never drops columns; migration script must explicitly DROP COLUMN IF EXISTS current_xp
  5. Existing totalXP doesn't map cleanly — old rates (win=100, death=-10) vs new (win=200, death=0). Recompute from lifetime stats via migration query
  6. Hologram leaderboard references removed methods — PlayerLevel.getTierIcon(lvl) / tierColorMiniMessage(lvl) gone. Use rank MiniMessage tag from spritesheet
  7. Scoreboard uses removed methods — getCurrentXP() → getProgressInRank(), getXPForNextLevel() → getXPToNextRank()
  8. Prestige crossover celebration — when rankIndexAfter / 12 > rankIndexBefore / 12, fire distinct title/subtitle, unique sound, broadcast message
  9. Legacy game mode coefficient default — since legacy mode has no GameRoomConfig, Game.java must declare private double coefficient = 1.0; so it always defaults to 1.0 without a setter call

Clone this wiki locally