Guides & reference
Explore the complete guides and reference material below for RankForge.
๐ Full Configuration Examples
Survival Server (5 Ranks)
Click to expand
# ranks.yml
default-rank: Guest
ranks:
Guest:
display-name: "&7[Guest]"
next-rank: "Member"
slot: 10
material: GRAY_WOOL
lore:
- "&7Welcome to the server!"
chat-prefix: "&7[G]"
permissions: []
commands: []
required-money: 0
required-xp-level: 0
required-playtime: 0
required-mob-kills: 0
required-block-breaks: 0
required-items: {}
Member:
display-name: "&a[Member]"
next-rank: "Veteran"
slot: 13
material: GREEN_WOOL
lore:
- "&7A trusted member."
- ""
- "&eRequires:"
- " &7$500 | 5 XP | 1 hour"
chat-prefix: "&a[M]"
permissions:
- "essentials.sethome.multiple.2"
commands:
- "lp user %player% group set member"
- "eco take %player% 500"
required-money: 500
required-xp-level: 5
required-playtime: 60
required-mob-kills: 0
required-block-breaks: 0
required-items: {}
Veteran:
display-name: "&2[Veteran]"
next-rank: "Elite"
slot: 16
material: EMERALD
lore:
- "&7A seasoned player."
chat-prefix: "&2[V]"
permissions:
- "essentials.sethome.multiple.4"
commands:
- "lp user %player% group set veteran"
- "eco take %player% 10000"
- "give %player% GOLDEN_APPLE 3"
required-money: 10000
required-xp-level: 30
required-playtime: 600
required-mob-kills: 200
required-block-breaks: 10000
required-items:
DIAMOND: 5
Elite:
display-name: "&b[Elite]"
next-rank: "Legend"
slot: 22
material: DIAMOND
lore:
- "&7Among the best."
chat-prefix: "&b[E]"
permissions:
- "essentials.sethome.multiple.6"
commands:
- "lp user %player% group set elite"
- "eco take %player% 50000"
required-money: 50000
required-xp-level: 60
required-playtime: 3000
required-mob-kills: 1000
required-block-breaks: 100000
required-items:
DIAMOND: 32
NETHERITE_INGOT: 2
Legend:
display-name: "&6&l[Legend]"
next-rank: ""
slot: 31
material: NETHER_STAR
lore:
- "&6The highest rank."
- "&7Only the truly dedicated reach this."
chat-prefix: "&6&l[L]"
permissions:
- "essentials.sethome.multiple.10"
commands:
- "lp user %player% group set legend"
- "eco take %player% 200000"
- "broadcast &6โฆ %player% &rhas become a LEGEND! &6โฆ"
required-money: 200000
required-xp-level: 100
required-playtime: 10000
required-mob-kills: 5000
required-block-breaks: 500000
required-items:
NETHERITE_INGOT: 10
DRAGON_EGG: 1
required-quests:
- "ender_dragon"
Prison Server (AโZ)
Click to expand
# ranks.yml
default-rank: A
ranks:
A:
display-name: "&7[A]"
next-rank: "B"
slot: 0
material: GRAY_WOOL
lore: ["&7Mine the A mine."]
chat-prefix: "&7[A]"
permissions: ["mines.a"]
commands: []
required-money: 0
required-xp-level: 0
required-playtime: 0
required-mob-kills: 0
required-block-breaks: 0
required-items: {}
B:
display-name: "&f[B]"
next-rank: "C"
slot: 1
material: WHITE_WOOL
lore: ["&7Mine the B mine."]
chat-prefix: "&f[B]"
permissions: ["mines.b"]
commands:
- "lp user %player% group set B"
- "eco take %player% 5000"
required-money: 5000
required-xp-level: 0
required-playtime: 0
required-mob-kills: 0
required-block-breaks: 500
required-items: {}
# ... repeat the pattern through Z ...
Z:
display-name: "&6&l[Z] FREE"
next-rank: ""
slot: 25
material: GOLD_BLOCK
lore:
- "&6You've earned your freedom!"
chat-prefix: "&6[FREE]"
permissions: ["mines.free", "prison.free"]
commands:
- "lp user %player% group set free"
- "eco take %player% 10000000"
- "broadcast &6%player% has earned their FREEDOM from prison!"
required-money: 10000000
required-xp-level: 0
required-playtime: 0
required-mob-kills: 0
required-block-breaks: 1000000
required-items: {}
๐ก Best Practices
Rank ID Naming
- Use
PascalCaseorUPPERCASE:Guest,Member,VeteranorRANK_A,RANK_B - Avoid spaces and special characters
- Keep IDs short โ they appear in logs, commands, and API calls
Requirement Scaling
- Scale requirements exponentially, not linearly. Each rank should be noticeably harder than the last
- Combine multiple requirement types to prevent any single grind path from being exploitable (e.g., money + playtime together prevent AFK farming)
- Use
required-block-breakson survival/skyblock servers; userequired-mob-killson combat servers
LuckPerms Groups
- Create a matching LuckPerms group for every rank before configuring RankForge
- Use
commandsentries to calllp user %player% group set <group>โ this is permanent, unlike thepermissionsfield which is session-based
YAML Editing Safety
- Always run
/rank reloadafter editingranks.yml, never/reload - Use a YAML validator before applying changes on a live server
- Take a backup of
ranks.ymlbefore major restructuring
MySQL on Networks
- Use MySQL if you run more than one server (BungeeCord/Velocity) and want shared rank data
- Ensure the MySQL user has only
SELECT,INSERT,UPDATE,DELETEon therankforgedatabase (noDROPorCREATE)
โ Frequently Asked Questions
Why isn't my rank saving between restarts?
If using YAML storage, ensure the server is shutting down gracefully (not SIGKILL). RankForge performs a synchronous flush on onDisable(). If the server is killed abruptly, the last sync interval's changes may be lost. Use MySQL for stronger durability guarantees.
The money requirement isn't being checked.
Vault must be installed and an economy plugin must be registered with it. Check the startup log:
[RankForge] [SoftDep] Vault=โ ...
If Vault shows โ, install Vault. If Vault shows โ but economy is still not working, check whether your economy plugin registers with Vault on startup.
Permissions aren't being applied on login.
The permissions field grants session-based permissions. With LuckPerms, these are applied as transient nodes when the player joins. Check:
- LuckPerms shows
โin the startup log - The permission node in
permissionsis correctly spelled - There are no LuckPerms policy restrictions blocking transient nodes
For permanent permissions, use commands with lp user %player% permission set <node> true.
Players can't rank up even though they meet all requirements.
Run /rank requirements as the player to see which requirements are unmet. Also check:
- The
next-rankfield on their current rank is set correctly - The player's rank ID exists in
ranks.yml debug: trueinconfig.ymlfor detailed logs
%rankforge_*% placeholders show as literal text.
PlaceholderAPI must be installed. Check the startup log for PlaceholderAPI=โ. If PAPI is installed but placeholders still don't resolve, run /papi reload and verify the plugin that uses them supports PAPI (check its documentation).
My rank GUI is blank / shows wrong items.
Each rank's icon is determined by its material field. If an invalid material name is used, the item defaults to GRAY_WOOL. The slot field must be unique per rank (0โ53). Run /rank editor drag to visually verify and correct slot assignments.
Block breaks aren't being counted.
RankForge's BlockBreakTracker uses a BlockBreakEvent listener. Ensure no other plugin is cancelling this event before RankForge processes it. In debug: true mode, block break events are logged for each player.
Can I have the same player on multiple rank systems?
RankForge uses a single linear rank chain. If you need separate progression paths (e.g., survival and donor), create distinct rank IDs and manage them via separate commands entries and LuckPerms groups. Multi-track support is not built in but can be simulated via the API.
๐ Troubleshooting
Enable Debug Mode
# config.yml
debug: true
Reload with /rank reload. Debug mode prints detailed logs for:
- Requirement checks per player
- Block-break counter updates
- Cache hits/misses
- Storage read/write operations
- Performance mode transitions
Common Errors
| Error Message | Cause | Fix |
|---|---|---|
[SoftDep] Vault=โ | Vault not installed | Install Vault |
[DB] Defaulting to fallback local storage | MySQL connection failed | Check config.yml credentials; verify MySQL is running |
[RankYaml] Failed to save ranks.yml | File permissions issue | Check the server process has write access to plugins/RankForge/ |
Unknown subcommand | Typo in command | Run /rank help to see all valid subcommands |
Rank 'X' does not exist | Rank ID not found in ranks.yml | Check spelling; run /rank reload after adding the rank |
[Requirements] Unknown statistic | Invalid required-statistic-id | Check the Bukkit Statistic enum name (must be uppercase, untyped) |
[AntiAbuse] Macro-like click detected | Player clicking GUI too fast | Normal if player has no macro; report if persistent on legitimate players |
Checking the Startup Log
A healthy startup looks like:
[RankForge] [SoftDep] Vault=โ LuckPerms=โ PlaceholderAPI=โ Floodgate=โ
[RankForge] [Lang] Dynamically indexed 4 language profiles: [en, es, fil, id]
[RankForge] [REST] API server listening on port 4567 โ (if enabled)
[RankForge] RankForge v3.8 successfully loaded! (5 ranks compiled)
If the rank count shows (0 ranks compiled), ranks.yml failed to parse. Check for YAML syntax errors (indentation, missing colons, tab characters).
Checking Player Data
Use /rank debug (run as the player) or the Player List GUI (/rank playerlist) to inspect a player's current rank, XP, and cached data.
๐ค Contributing
Contributions are welcome! Please follow these steps:
- Fork the repository on GitHub
- Branch from
main:git checkout -b feature/my-feature - Code your changes following the existing style (Java 21, no wildcard imports, Javadoc on all public API methods)
- Test on a local Paper 1.21.4 server
- Commit with a clear message:
git commit -m "feat: add custom statistic requirement support" - Open a Pull Request targeting
main
Bug Reports
Use GitHub Issues. Include:
- Server software and exact version (e.g.,
Paper 1.21.4 #123) - Java version (
java -version) - Full error from
logs/latest.log - Your
config.ymlandranks.yml(remove credentials) - Steps to reproduce
๐ฌ Support
| Channel | Link |
|---|---|
| ๐ Bug Reports | GitHub Issues |
| ๐ก Feature Requests | GitHub Discussions |
| ๐ Source Code | github.com/JoshuaOP/RankForge |
Before opening an issue, enable debug: true, reproduce the problem, and include the relevant log section. Issues without reproduction steps may be closed without resolution.
๐ License
MIT License
Copyright (c) 2024 JoshuaOP
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
See LICENSE for the full text.
๐ Credits
| Name / Project | Role |
|---|---|
| JoshuaOP | Author & lead developer |
| Vault (MilkBowl) | Economy abstraction API |
| LuckPerms (Luck) | Permission management API |
| PlaceholderAPI (extended_clip) | Placeholder framework |
| HikariCP (brettwooldridge) | High-performance JDBC connection pooling |
| bStats (Bastian) | Anonymous plugin analytics |
| Paper Team | High-performance Bukkit fork |
| Community | Bug reports, translations, feature suggestions |
Behind the Scenes: Automatic Schema Handling
No manual configuration changes are ever required for playtime tracking. The playtime key in ranks.yml stays the same whether you use whole minutes or the new duration-string format:
- RankForge automatically keeps the YAML playerdata schema up to date, adding
playtime: 0to any record that doesn't already have it. - For MySQL, a
playtime_minutescolumn is added automatically viaALTER TABLEon startup if it doesn't exist. - Any player without existing wall-clock playtime data starts at
0real minutes and accumulates from that point onward.
Note: Legacy tick-based statistics are never used to back-fill wall-clock playtime. Servers that want to credit players for time already played can use an admin command or manually edit playerdata.yml. This is intentional โ converting approximate tick counts would propagate their inaccuracy.
Tips and Best Practices
- Start low. Begin with shorter playtime requirements (30โ60 minutes) and increase them based on your player feedback.
- Combine with other requirements. Playtime alone doesn't show engagement. Pair it with
block-breaksormob-killsfor a richer progression curve. - AFK players. Playtime counts even while AFK. If you want to exclude AFK time, use a compatible AFK plugin that removes players from the server (which stops the timer), or use an activity-based requirement like
block-breaksas the primary gate. - Test before going live. Use
/rank set <yourself> <rank>and/rank progressto verify requirements display correctly. - Reload safely. Always use
/rank reloadโ never/reload. A server reload can corrupt the tracker's session state.
Troubleshooting Playtime
| Symptom | Cause | Fix |
|---|---|---|
| Playtime shows 0 for an existing player | Normal for a record with no prior wall-clock data โ accumulation begins fresh | No action needed; time will accumulate naturally |
| Playtime not advancing | PlaytimeTracker not initialized | Check console for errors on startup; use /rank version to verify plugin loaded |
| Playtime resets on relog | Data not saving before quit | Check storage errors in console; ensure playerdata.yml is writable |
| Requirement shows wrong time | Stale cache | Run /rank reload to flush the cache |
| MySQL column missing | Very old database, migration failed | Check console for [DB] Column migration check failed warnings |
โ Frequently Asked Questions
General
Q: Does RankForge work without Vault, LuckPerms, or PlaceholderAPI? A: Yes. All three are optional. Without Vault, money requirements are skipped. Without LuckPerms, a Bukkit PermissionAttachment is used as fallback. Without PlaceholderAPI, the %rankforge_*% placeholders are simply unavailable.
Q: Can I have unlimited ranks? A: Yes. RankForge loads every rank defined in ranks.yml with no hardcoded limit.
Q: Does RankForge support Bedrock players (Geyser/Floodgate)? A: Yes. All storage and checks use UUID, not player name. The Bedrock prefix (. by default) is stripped from display names automatically.
Q: Will /reload (vanilla server reload) break the plugin? A: It can. Always use /rank reload instead. The vanilla reload can corrupt in-memory state and discard unsaved playtime data.
Playtime
Q: How is playtime measured? A: Using System.currentTimeMillis() โ real wall-clock time measured in milliseconds and stored as whole minutes. This is completely independent of server TPS.
Q: Does playtime count while the player is AFK? A: Yes, by default. The timer runs from join to quit regardless of activity. If you need AFK detection, use an external AFK plugin that disconnects inactive players, or gate progression on activity-based requirements like block-breaks.
Q: Why does a player show 0 playtime even though they've played before? A: This happens if a player's record predates wall-clock tracking being enabled on your server. The vanilla PLAY_ONE_MINUTE statistic (tick-based) is intentionally not used to back-fill this value, since it can be skewed by lag. Playtime accumulates accurately from that point onward.
Q: What happens to playtime if the server crashes? A: Playtime is periodically flushed to storage (every sync.interval-ticks, default 10 seconds). On a crash, up to 10 seconds of playtime may be lost. Clean shutdowns always flush everything before stopping.
Q: Can I manually set a player's playtime? A: Currently, this must be done by editing playerdata.yml while the server is stopped (or via a MySQL UPDATE). A /rank playtime set admin command may be added in a future version.
Q: My playtime requirement shows "0min" in /rank progress even though I've been online for an hour. A: This can happen if the tracker didn't initialize on join (e.g., the plugin reloaded while you were online). Rejoin the server โ the tracker will re-register your session start. If the issue persists, check console for errors.
Q: Does playtime in ranks.yml still work without changes? A: Yes. The configuration key is identical. No migration of ranks.yml is required โ only the underlying implementation changed.
Storage
Q: Which storage backend should I use? A: YAML is suitable for single servers. MySQL is recommended for networks, bungeecord/velocity proxies, or servers with more than a few hundred players. MySQL is also required if you want to query player data from external tools (dashboards, Discord bots, etc.).
Q: My MySQL connection fails. Will the server error out? A: No. RankForge automatically falls back to YAML storage when MySQL is unavailable, logs a single info-level message, and continues loading normally.
Q: How do I migrate from YAML to MySQL? A: Start the server with MySQL configured. RankForge will create the tables. Then manually export data from playerdata.yml and insert it into rf_players. A built-in migration tool may be added in a future version.
๐ง Troubleshooting
Plugin fails to load
- Check Java version:
java -versionmust be 21 or higher. - Confirm you are running Spigot or Paper 1.17+.
- Review the console for
[SEVERE]messages from RankForge on startup.
Ranks not loading
- Ensure
ranks.ymlis valid YAML. Use yaml-online-parser.appspot.com to validate. - Verify the
default-rankvalue matches an actual rank key. - Run
/rank reloadafter editing the file.
/rank up does nothing
- Run
/rank progressโ this shows which requirements are unmet. - Confirm the current rank has a
next-rankset. - Ensure you are not at the final rank (empty
next-rank).
Playtime not advancing
- Check startup log โ PlaytimeTracker registers on load. If there are errors, address them.
- Relog: the join event re-registers your session start.
- Check if
/rank requirementsshows a playtime line. If absent, the rank hasplaytime: 0(no requirement).
Playtime not saving after restart
- Check write permissions on
plugins/RankForge/data/playerdata.yml. - Confirm no
[YamlStorage] Failed to saveerrors appear in console. - For MySQL: check for
[DB] MySQL save failedwarnings.
GUI not opening
- Ensure no other plugin is cancelling inventory open events.
- Check for
GuiClickShieldManagerwarnings in console. - Confirm the player has
rankforge.rank.usepermission.
LuckPerms permissions not applying
- LuckPerms must load before RankForge. Add
depend: [LuckPerms]to LuckPerms's plugin.yml or ensure load order. - Verify the permission nodes in
ranks.ymlare valid (no spaces, valid format). - Use
/rank set <player> <rank>to force a re-apply after fixing configuration.
MySQL tables not created
- Verify credentials in
config.ymlare correct. - Ensure the database user has
CREATE TABLE,ALTER, andINSERTprivileges. - Check console for
[DB] Failed to create MySQL tableswith the specific SQL error.
๐ ๏ธ Setup & Configuration Guide
This guide walks through every step of installing and configuring RankForge from scratch.
๐ฅ Installation Guide
Step 1 โ Download RankForge
Download the latest RankForge-*.jar from the SpigotMC resource page.
Step 2 โ Install the plugin
Drop the JAR into your server's plugins/ folder:
server/
โโโ plugins/
โโโ RankForge-3.8.jar
Step 3 โ Install optional dependencies
Install any of the following soft dependencies for additional features:
| Plugin | Purpose |
|---|---|
| Vault | Money requirements and economy balance tracking |
| LuckPerms | Automatic permission group management on rankup |
| PlaceholderAPI | %rankforge_*% placeholders in other plugins |
| Floodgate / Geyser | Bedrock crossplay player name handling |
| MySQL | (Configure in config.yml) Persistent relational storage for networks |
None are required โ RankForge works out of the box with no dependencies.
Step 4 โ Start the server
Start your server once. RankForge auto-generates all configuration files:
plugins/RankForge/
โโโ config.yml
โโโ ranks.yml
โโโ gui.yml
โโโ lang/
โโโ en.yml
โโโ es.yml
โโโ fil.yml
โโโ id.yml
Step 5 โ Configure the plugin
Edit the generated files (see the Configuration Guide below).
Step 6 โ Reload or restart
Apply your changes without a full restart:
/rank reload
Never use the vanilla /reload command. It can corrupt in-memory player data and break the playtime tracker. Always use /rank reload.
โ๏ธ Configuration Guide
config.yml
The master settings file. Key sections:
| Section | Key | Description |
|---|---|---|
language | default | Default language code (en, es, fil, id) |
language | per-player | Allow players to pick their own language |
announcements | rankup.broadcast | Broadcast message to all players on rankup |
announcements | rankup.title | Full-screen title shown to the ranking-up player |
cosmetic | bossbar.enabled | Boss bar on rankup and progress checks |
cosmetic | tablist.enabled | Show rank prefix in the player list |
cosmetic | particles.enabled | Particle trail around the player on rankup |
storage | type | yaml (default) or mysql |
storage | mysql.* | Host, port, database, username, password, pool-size |
performance | modes.*-tps-threshold | TPS thresholds for HIGH / MEDIUM / LOW cosmetic modes |
crossplay | bedrock-prefix | Floodgate prefix to strip from Bedrock player names |
rest-api | enabled | Enable the optional embedded HTTP API |
debug | (boolean) | Enable verbose debug logging |
ranks.yml
Defines every rank. Each top-level key under ranks: is a rank ID.
default-rank: Guest # Rank assigned to new / unknown players
ranks:
RankId:
display-name: "&aDisplay Name"
next-rank: "NextRankId" # Empty string = final rank
slot: 11 # GUI inventory slot (0โ53)
material: GREEN_WOOL # Bukkit Material name
lore:
- "&7Description line"
chat-prefix: "&a[Tag]"
permissions:
- "some.permission.node"
commands:
- "lp user %player% group set rankid"
requirements:
money: 1000
xp-level: 10
playtime: 1hr # Human-readable duration format (see Requirements Guide)
mob-kills: 50
block-breaks: 500
permission: "some.required.node"
statistic-id: "FISH_CAUGHT"
statistic-value: 10
quests:
- "quest_id"
worlds:
- "world"
items:
DIAMOND: 5
Language files (lang/en.yml, lang/fil.yml, lang/id.yml, lang/es.yml)
Located in plugins/RankForge/lang/. Each file contains:
prefix:โ the[RankForge]prefix shown before messagesmessages:โ every translatable message string
To add a language, copy en.yml to a new file (e.g., de.yml), translate the messages block, and run /rank reload. Players switch languages with /rank lang set de.
gui.yml
Controls all GUI titles, border materials, slot positions, icons, and themes. Every GUI in RankForge is configurable here without touching any Java code. Apply changes with /rank reload.
YAML storage
Default. Player data is stored in plugins/RankForge/data/playerdata.yml and synced every sync.interval-ticks (default: 200 ticks = 10 seconds). A final flush always runs on clean shutdown.
MySQL storage
storage:
type: mysql
mysql:
host: "localhost"
port: 3306
database: "rankforge"
username: "rankforge_user"
password: "your_password"
pool-size: 10
Tables are created automatically. HikariCP handles connection pooling. If the connection fails at startup, RankForge falls back to YAML automatically.
๐ Rank Creation Guide
Creating a rank
Add a new key under ranks: in ranks.yml:
ranks:
Builder:
display-name: "&e[Builder]"
next-rank: "Veteran"
slot: 13
material: BRICKS
lore:
- "&7A creative builder."
chat-prefix: "&e[Builder]"
Reload with /rank reload. You can also create ranks in-game with /rank create <id>.
Linking rank chains
Each rank points to the next via next-rank. Leave it empty for the final rank:
Guest โ Member โ Veteran โ Elite โ (empty, final rank)
Configuring rewards
ranks:
Member:
permissions:
- "essentials.sethome.multiple.2" # Applied when player holds this rank
commands:
- "lp user %player% group set member" # Runs on rankup
- "eco take %player% 1000"
Configuring permissions
permissions:โ nodes granted while the player holds this rank (managed by LuckPerms or Bukkit attachment)commands:โ console commands executed at the moment of rankup (%player%is replaced with the player's name)
Configuring requirements
See the Requirements Guide below for all supported types and the new playtime format.
๐ Requirements Guide
All requirements are defined inside a requirements: block within each rank entry.
| Key | Type | Description |
|---|---|---|
money | Double | Vault balance required. 0 = no requirement. |
xp-level | Integer | Vanilla Minecraft XP level. |
permission | String | A single permission node the player must have. |
playtime | String | Real wall-clock playtime (see format below). |
mob-kills | Integer | Total mob kills via MOB_KILLS statistic. |
block-breaks | Integer | Block breaks tracked by RankForge's counter. |
statistic-id | String | Any untyped Bukkit Statistic enum name. |
statistic-value | Integer | Required value for statistic-id. |
quests | List\<String\> | Quest IDs checked as rankforge.quest.completed.<id>. |
worlds | List\<String\> | Player must be in one of these world names. |
items | Map | MATERIAL_NAME: amount pairs. Items must be in inventory. |
Playtime Requirement Format
The playtime key uses a single human-readable string. This is the recommended format.
Supported units:
| Unit | Meaning |
|---|---|
d | Days (1d = 1440 minutes) |
hr | Hours (1hr = 60 minutes) |
m | Minutes |
s | Seconds (truncated to whole minutes; < 60s = 0) |
Units are case-insensitive (D, HR, M, S all work). Extra whitespace is ignored. Any combination of units is accepted.
Examples:
requirements:
playtime: 30m # 30 minutes
requirements:
playtime: 2hr # 2 hours (120 minutes)
requirements:
playtime: 7d # 7 days (10,080 minutes)
requirements:
playtime: 1d 12hr # 1 day and 12 hours (2,160 minutes)
requirements:
playtime: 5d 5hr 5m 5s # 5 days, 5 hours, 5 minutes (seconds truncated)
requirements:
playtime: 45s # 45 seconds โ 0 whole minutes (no requirement in effect)
Backward compatibility:
Existing configurations using playtime continue to work without any changes:
requirements:
playtime: 60 # Still fully supported โ equals "1hr"
The loader checks for playtime first; if absent, it falls back to playtime. No edits to existing ranks.yml files are required.
Full example rank using the duration format:
ranks:
Veteran:
display-name: "&2[Veteran]"
next-rank: "Elite"
slot: 15
material: EMERALD
chat-prefix: "&2[Veteran]"
commands:
- "lp user %player% group set veteran"
requirements:
money: 10000
xp-level: 30
playtime: 10hr
mob-kills: 100
block-breaks: 5000
items:
DIAMOND: 10
โจ๏ธ Commands Guide
Player Commands
| Command | Permission | Description |
|---|---|---|
/rank | rankforge.rank.use | Open the animated rank tree GUI |
/rank up | rankforge.rank.up | Attempt to rank up to the next rank |
/rank progress | rankforge.rank.progress | Show a progress bar and requirement breakdown |
/rank next | rankforge.rank.next | Show your next rank's display name |
/rank current | rankforge.rank.current | Show your current rank |
/rank requirements | rankforge.rank.requirements | List unmet requirements for the next rank |
/rank history | rankforge.rank.history | View your last 10 rank changes |
/rank xp | rankforge.rank.use | View your custom RankForge XP |
/rank lang set <lang> | rankforge.rank.lang | Set your preferred language |
/rank lang list | rankforge.rank.lang | List all available languages |
/rank lang reset | rankforge.rank.lang | Reset to the server default language |
/rank version | rankforge.rank.system.version | Show plugin and system information |
/rank help | (none) | Show the help screen |
Admin Commands
| Command | Permission | Description |
|---|---|---|
/rank editor | rankforge.rank.editor | Open the admin rank editor GUI |
/rank editor <rankId> | rankforge.rank.editor | Open the editor for a specific rank |
/rank editor drag | rankforge.rank.editor.drag | Open the drag-and-drop slot editor |
/rank create <id> | rankforge.rank.create | Create a new rank with a specific ID |
/rank delete <id> | rankforge.rank.delete | Delete a rank (prompts for confirmation) |
/rank set <player> <rank> | rankforge.rank.set | Set a player's rank (online or offline) |
/rank force <player> <rank> | rankforge.rank.force | Force-set a rank bypassing all checks |
/rank bypassreq <player> <requirement> | rankforge.rank.bypassreq | Waive a single requirement for a player |
/rank reset <player> | rankforge.rank.reset | Reset a player to the default rank |
/rank reload | rankforge.rank.reload | Hot-reload all configuration files |
/rank playerlist | rankforge.rank.playerlist | Browse all player rank data in a GUI |
/rank xp set <player> <amount> | rankforge.rank.xp.set | Set a player's custom XP |
/rank xp add <player> <amount> | rankforge.rank.xp.add | Add custom XP to a player |
/rank security | rankforge.rank.security | View the admin rollback audit log |
/rank history <player> | rankforge.rank.admin | View another player's rank history |
๐ Permissions Guide
Player Permissions
| Permission | Default | Description |
|---|---|---|
rankforge.use.* | true | Grants all player permissions (wildcard) |
rankforge.use | true | Open the rank GUI (/rank) |
rankforge.use.up | true | Rank up (/rank up) |
rankforge.use.current | true | View current rank (/rank current) |
rankforge.use.next | true | View next rank info (/rank next) |
rankforge.use.progress | true | View rank progress bar (/rank progress) |
rankforge.use.requirements | true | View rank requirements (/rank requirements) |
rankforge.use.history | true | View rank history (/rank history) |
rankforge.use.help | true | View command help (/rank help) |
rankforge.use.lang | true | Change language (/rank lang) |
rankforge.use.version | true | View plugin version info (/rank version) |
rankforge.use.xp | true | View personal XP info (/rank xp) |
Administrator Permissions
| Permission | Default | Description |
|---|---|---|
rankforge.admin.* | op | Grants all admin permissions (wildcard) |
rankforge.admin.reload | op | Full plugin reload (/rank reload) |
rankforge.admin.editor | op | Open the admin rank editor (/rank editor) |
rankforge.admin.playerlist | op | View and edit all player data (/rank playerlist) |
rankforge.admin.create | op | Create a new rank (/rank create) |
rankforge.admin.delete | op | Delete a rank (/rank delete) |
rankforge.admin.set | op | Set a player's rank (/rank set) |
rankforge.admin.force | op | Force-set a rank bypassing requirements (/rank force) |
rankforge.admin.reset | op | Reset a player's rank (/rank reset) |
rankforge.admin.bypassreq | op | Instantly complete a requirement for a player (/rank bypassreq) |
rankforge.admin.stats | op | View system statistics (/rank stats) |
rankforge.admin.debug | op | View rank debug info (/rank debug) |
rankforge.admin.security | op | View anti-bypass status (/rank security) |
rankforge.admin.sound | op | Manage sound settings (/rank sound) |
rankforge.admin.xp | op | Set or add XP for other players |
Wildcard Permissions
| Permission | Default | Description |
|---|---|---|
rankforge.* | op | Grants all RankForge permissions |
rankforge.use.* | true | Grants all player command permissions |
rankforge.admin.* | op | Grants all administrator command permissions |
Quest Permission
| Permission | Description |
|---|---|
rankforge.quest.completed.<id> | Marks a quest as complete for requirement checks |
๐ PlaceholderAPI Guide
With PlaceholderAPI installed, all %rankforge_*% placeholders are available in any PAPI-compatible plugin (scoreboards, chat formatters, holograms, tab lists, etc.).
| Placeholder | Example Output | Description |
|---|---|---|
%rankforge_rank% | Veteran | Current rank ID |
%rankforge_rank_name% | &2[Veteran] | Current rank display name |
%rankforge_rank_display% | &2[Veteran] | Alias for rank_name |
%rankforge_rank_prefix% | &2[Veteran] | Current rank's chat-prefix |
%rankforge_rank_position% | 3 | Position in the rank chain (1-based) |
%rankforge_is_max_rank% | false | true if player is at the final rank |
%rankforge_next_rank% | Elite | Next rank ID, or MAX |
%rankforge_next_cost% | $100,000 | Next rank's money requirement |
%rankforge_cost% | $10,000 | Current rank's money requirement |
%rankforge_progress% | 62.5 | Overall requirement progress (decimal) |
%rankforge_progress_percent% | 62.5% | Same with % appended |
%rankforge_progress_bar% | โโโโโโโโโโ | Visual ASCII progress bar |
%rankforge_required_progress% | $100,000 Lv75 | All requirements for the next rank |
%rankforge_remaining_progress% | $37,500 Lv12 | What remains unmet |
%rankforge_money% | $62,500 | Player's current Vault balance |
%rankforge_has_money% | false | true if player can afford the next rank |
%rankforge_missing_money% | $37,500 | Money still needed |
%rankforge_requirements_status% | ยงcโ Requirements Unmet | Met / unmet status label |
%rankforge_requirements_detail% | (multiline) | Full requirement breakdown |
%rankforge_xp_level% | 30 | Player's current Minecraft XP level |
%rankforge_xp_progress% | 100% | Fraction to next XP level |
%rankforge_player% | Steve | Player's display name (Bedrock-safe) |
%rankforge_uuid% | xxxxxxxx-... | Player's UUID |
%rankforge_lang% | en | Player's active language code |
%rankforge_version% | 3.8 | Plugin version |
โ FAQ / Troubleshooting
Rank not updating after /rank up Run /rank progress to see which requirements are unmet. Confirm next-rank is set correctly on the current rank.
PlaceholderAPI not working Ensure PlaceholderAPI is installed and loaded before RankForge. Run /papi list to confirm rankforge is registered. Use /rank reload after installing PAPI.
Vault not detected Vault must be installed and an economy provider (e.g., EssentialsX) must also be present. Check startup log for [SoftDep] Vault=โ.
LuckPerms integration not applying permissions LuckPerms must load before RankForge. Verify with /rank version that the plugin loaded successfully. Check that permission nodes in ranks.yml have no spaces or typos.
MySQL connection problems Verify credentials in config.yml. Ensure the database user has CREATE, ALTER, and INSERT privileges. Check console for [DB] Failed to create MySQL tables and the specific SQL error. RankForge automatically falls back to YAML if MySQL is unreachable.
Playtime requirement not progressing Check that PlaytimeTracker initialized on startup (look for errors in the console). Relog โ the PlayerJoinEvent re-registers your session start. Confirm the rank's playtime value is greater than zero. Use /rank requirements to see the playtime line.
Old playtime config stopped working It has not stopped working. The key is fully supported. Add playtime: 1hr to new ranks going forward; existing playtime entries require no changes.
Invalid playtime format error Ensure the value uses only the supported units (d, hr, m, s) with whole numbers and no special characters. Valid: 1d 12hr 30m. Invalid: 1.5d, 2hours, 90.
Configuration mistakes Use a YAML validator (e.g., yaml-online-parser.appspot.com) to check ranks.yml for syntax errors. All invalid ranks are logged and skipped โ look for [YamlLoader] Skipped rank warnings in the console.
๐ก Best Practices
Organizing rank chains
- Keep rank IDs simple and consistent (
Guest,Member,Veteran) โ they are stored in player data. - Always set
next-rankfor every non-final rank to avoid silent dead-ends. - Use the
slotfield to arrange ranks visually in the GUI from left to right.
Optimizing performance
- Use YAML storage for single servers; MySQL for networks with many concurrent players.
- Keep
sync.interval-ticksat200(10 seconds) or higher to reduce disk I/O. - Disable cosmetics you don't use (
particles,bossbar) to reduce per-player overhead on busy servers. - The TPS-aware performance system automatically suppresses heavy effects when the server is under load.
Creating balanced progression
- Start playtime requirements low (30mโ1hr for the first rank) and increase gradually.
- Combine
playtimewith activity-based requirements (block-breaks,mob-kills) so idle AFK players don't auto-rank. - Test all requirements on yourself with
/rank set <yourself> <rank>and/rank progressbefore opening to players.
Maintaining configuration files
- Always use
/rank reloadโ never/reload. - Back up
ranks.ymlandplayerdata.yml(or your MySQL database) before making major changes. - When renaming a rank ID, update
default-rankand allnext-rankreferences, then use/rank reload. Players with the old ID are automatically repaired todefault-rank. - Use the in-game admin editor (
/rank editor) for safe edits that automatically validate and save the file.
Made with โค๏ธ by JoshuaOP
โญ If RankForge helps your server, please star the repository โ it helps others find the project!