v4.17 · Paper 1.20–1.21.x

Guide & Tutorials

Everything to install, configure, translate, and connect CelestialCosmetics to the rest of your server — written straight from the plugin's own source, not a stale changelog.

Start Here

Getting Started

What the plugin needs, and how to get it running for the first time.

Requirements

RequirementNeeded for
Paper 1.20.1 – 1.21.xServer software. Forks built on Paper's API work too.
Java 17+Runtime.
required PlaceholderAPIEvery placeholder (%celestial_*%) and the economy balance placeholder in commands mode.
required LuckPermsRank-based defaults, rank-restricted backgrounds, and the layered rank prefix builder.
optional VaultCharging the server's main economy (economy-mode: vault).
optional EdDungeonsCharging a custom currency for the Auction House and paid crates (economy-mode: eddungeons).
optional ItemsAdder / Oraxen / NexoCustom icons and fonts — GUI items already support custom model data and player-head textures either way.
optional PacketEventsGlow outlines that keep their color alongside TAB.
optional FancyHologramsFloating labels above physical crate blocks.

Installation

  1. Drop the jar into plugins/, alongside PlaceholderAPI and LuckPerms.
  2. Start the server once. It generates config.yml, messages.yml, crates.yml and every file under cosmetics/ with sane, ready-to-use defaults.
  3. Edit whichever files you need — see the breakdown below.
  4. Apply changes with /cosmetics reload — no restart needed for config edits.

File layout

plugins/CelestialCosmetics/
├── config.yml         # menus, economy, storage, categories on/off
├── messages.yml        # every player-facing string, 100% translatable
├── crates.yml          # crate definitions and reward tables
└── cosmetics/
    ├── tags.yml
    ├── rebirth.yml
    ├── customstat1.yml, customstat2.yml, customstat3.yml
    ├── namecolors.yml
    ├── chatcolors.yml
    ├── rankcolors.yml
    ├── rank-backgrounds.yml
    ├── emojis.yml
    ├── glows.yml
    ├── joinmessages.yml, leavemessages.yml
    ├── chatemojis.yml
    └── sets.yml
💡
plugin.getConfig() internally merges ALL of these files into one view, so config.yml, messages.yml and every file under cosmetics/ are all readable and reloadable together — you never have to worry about which physical file a setting lives in.
Start Here

The Vault Model

The one concept that explains why trading, the Auction House and rank defaults all behave the way they do.

A cosmetic isn't a permission flag — it's a quantity stored per player, per cosmetic. A player can own 0, 1, or many copies of the same tag, name color, glow, etc. This is what makes physical trading and reselling possible without ever duplicating anything.

There are two completely separate ways to have access to a cosmetic, and only one of them can be turned into a physical item:

Access typeCan equip?Can withdraw / sell?
Owned copies (quantity > 0 in the vault)
Rank / permission / Set access (no real copies owned)❌ — prevents infinite duplication from a rank

If a player's last owned copy is withdrawn or sold while a cosmetic is equipped, it's automatically unequipped — unless their rank or an active Set still grants access, in which case nothing visibly changes for them.

Whole categories can be switched off in config.yml under categories-enabled: a disabled category disappears from every menu (including the admin wizard), its placeholder returns empty, and it can't be equipped, searched, traded, sold, or won from a crate.

Start Here

Cosmetic Categories

15 independent types, each with its own file under cosmetics/ and its own PlaceholderAPI placeholder.

Tag
tags.yml
Rebirth Color
rebirth.yml
Custom Stat 1 / 2 / 3
customstat1/2/3.yml
Name Color
namecolors.yml
Rank Effect
rankcolors.yml
Rank Background
rank-backgrounds.yml
Chat Color
chatcolors.yml
Emojis
emojis.yml
Glow
glows.yml
Join Message
joinmessages.yml
Leave Message
leavemessages.yml
Chat Emoji
chatemojis.yml
Sets
sets.yml

Custom Stat 1/2/3 work exactly like Rebirth Color but point at any placeholder you choose (customstat1-source-placeholder in config.yml) — a second or third progression system rendered the same way, from any plugin.

Sets bundle any combination of the other 14 into one equip: picking a Set applies every component at once (tag + name color + chat color + …), and unequipping it cleanly reverses only the pieces the Set itself applied.

Example entry, from tags.yml:

tags:
  dragon:
    display: "&#fc6c00Dragon"
    value: "&#fc0000&l[&#fc6c00&lDRAGON&#fc0000&l]"
    icon: DRAGON_HEAD
    permission: celestial.cosmetics.tag.dragon

Configuration

Configuration Files

config.yml at a glance — the sections you'll actually touch.

SectionControls
storageSQLite (default, single server) or MySQL (syncs the vault, Auction House, crate stock, pity and daily claims across a whole network).
categories-enabledOne on/off switch per category.
economyeconomy-mode: vault, eddungeons, or commands — see Economy Integration.
auctionMin/max price, tax percentage, the Auction House button and its confirm menu.
admin-menuThe /cosmetics admin menu — one creation button per type, plus Reload.
crates-menu, crate-hologramsThe crates list button/title, and floating labels for physical crate blocks (needs FancyHolograms).
search-menuThe vault-wide search button.
menuMain menu title/size, filler item, navigation buttons, one entry per category (slot/material/name/icon), the actions menu (Equip/Withdraw/Auction), and the shared confirm/preview buttons used by both crates and the Auction House.
rank-defaultsCosmetics auto-applied per LuckPerms primary group when nothing is equipped. Empty by default.

Every menu item — button or category — accepts the same fields: enabled, slot, material, custom-model-data, name, lore, and texture (a base64 player-head skin, for ItemsAdder/Oraxen/Nexo icons). Set slot: -1 or enabled: false to hide something entirely.

Configuration

Translating the Plugin

Every single player-facing string — menu titles, button names, lore, crate text, command responses — is config-driven. Nothing is hardcoded in a way that can't be overridden.

The two files that matter

messages.yml holds every sentence: base messages, trade/Auction House text, crate text, cosmetic descriptions, command responses (cli.*), and the admin creation wizard's prompts (wizard.*).

config.yml holds every menu title and button name — category names, the Auction House/Crates/Search buttons, admin buttons, and navigation (Back/Previous/Next/Unequip).

Type labels: one key, everywhere

A category's display name — "Chat Color", "Rank Effect", etc. — shows up in a lot of places beyond its own menu button: crate reward lore, trade item lore, the Auction House, the actions menu, the admin wizard, and cosmetic descriptions. Rather than hunting all of those down, messages.yml has one dedicated map:

messages:
  type-labels:
    tag: Tags
    chatcolor: Couleur du Chat
    rankcolor: Effet de Grade
    # ...one line per category

Change a type's name here once, and it updates everywhere that type is mentioned — keep it in sync with the matching menu.categories.<type>.name in config.yml so the category button and everything else agree.

💡
Every string keeps its &/&#RRGGBB color codes and {placeholder} tokens exactly where they are — translate the words around them, never the codes themselves.

What stays untranslated by default

The actual cosmetic content — names like "Dragon" or "Dubstep Wobble" inside cosmetics/*.yml — is separate from the UI chrome above, and isn't touched by a UI translation pass unless you edit those files too.

Configuration

GUI Customization

Every menu is rebuilt from config.yml on open — nothing requires recompiling.

Content slots — where cosmetics are placed in a category submenu — default to the classic centered rectangle, but can be listed explicitly for a compact layout:

menu:
  # content-slots: [10,11,12,13,14,15,16, 19,20,21,22,23,24,25]

Set menu.filler.enabled: false to remove the background filler entirely — useful on packs where a custom ItemsAdder/Oraxen/Nexo texture already draws one.


Features

Crates

Weighted reward tables, opened with a key or paid currency.

  • Weighted rewards — each reward in crates.yml has a weight; odds are shown live in the preview menu.
  • Stock-limited rewards — cap how many times a reward can ever be won (globally, or per-server without MySQL). Hitting 1 triggers a server-wide broadcast and a permanent "Winners" list in the reward's lore.
  • Pity / guarantee/cosmetics crate pity <player> <crate> [reset] checks or resets a player's counter toward a guaranteed pull.
  • Daily keys/cosmetics daily shows cooldowns for any crate flagged as a daily reward.
  • Physical crate blocks — link any world block to a crate with /cosmetics crate setblock; left/right-click previews or opens it, with a roulette-style opening animation. Add FancyHolograms for a floating label above it.
  • Timed events/cosmetics crate enable <crate> 7d12h30m (or always) opens a crate for a duration; disable closes it early.
💡
Opening a crate with /cosmetics crate open <crate> automatically uses a key if the player has one, otherwise it charges the configured price.
Features

Trading & Auction House

Withdraw → trade → claim

Withdrawing an owned cosmetic (Shift-Click in the vault, or the Withdraw button in the actions menu) takes one real copy out as a physical, stackable item that carries the cosmetic's identity. Any player can then claim it — right-click works no matter how you do it: holding the item and clicking air or a block, or right-clicking it while it's still sitting on the ground, before even picking it up. Claiming always adds a copy, even on top of ones you already own.

Auction House

A real player marketplace: list an owned cosmetic (Right-Click in the vault, the Auction button in the actions menu, or /cosmetics sell <type> <id> [price]), buyers pay through a confirm menu, and the sale is atomic — a listing can't be bought twice. auction.tax-percent takes a cut on every sale; min-price/max-price bound what can be listed.

Features

Admin Tools

Everything an admin needs without ever hand-editing YAML.

/cosmetics admin opens a menu with one "+ New …" button per category. Clicking one starts a guided chat wizard — id, display name, value, icon, and any type-specific fields (a rebirth prefix/text/suffix, a Set's component list, and so on) — and writes the finished cosmetic straight into the right file.

/cosmetics set <player> <type> <id> force-equips any cosmetic on any player, even one they don't own — useful for events, giveaways, or support tickets. It's gated behind celestial.cosmetics.admin and bypasses ownership checks entirely.

/cosmetics give <player> <type> <id> [amount] adds real, ownable copies to a player's vault (so they can be withdrawn/sold), rather than just equipping one.


Reference

Commands

Base command /cosmetics (aliases: /cosmetic, /ccos).

CommandDescription
/cosmeticsOpen the main vault menu.
/cosmetics ah / auctionOpen the Auction House.
/cosmetics sell <type> <id> [price]List an owned cosmetic. Omit the price to be prompted in chat.
/cosmetics cratesOpen the crates menu.
/cosmetics search [query]Search your whole vault by name or id.
/cosmetics dailyShow cooldowns for daily-reward crates.
Admin — require celestial.cosmetics.admin
/cosmetics adminOpen the cosmetic-creation menu.
/cosmetics reloadReload every configuration file.
/cosmetics give <player> <type> <id> [amount]Add real vault copies.
/cosmetics set <player> <type> <id>Force-equip, ownership-independent.
/cosmetics clear <player> <type>Unequip a category for a player.
/cosmetics extract <player> <type> <id>Trigger a withdraw on someone's behalf.
/cosmetics crate open <crate>Open a crate (key first, then currency).
/cosmetics crate givekey <player> <crate> [n]Give crate keys.
/cosmetics crate enable <crate> <7d12h30m|always>Open a crate for a duration.
/cosmetics crate disable <crate>Close a crate early.
/cosmetics crate setblock <crate> [world x y z]Link a world block to a crate.
/cosmetics crate removeblockUnlink the next block you click.
/cosmetics crate blocksList every linked crate block.
/cosmetics crate pity <player> <crate> [reset]Check or reset a pity counter.
Reference

Permissions

NodeDefaultGrants
celestial.cosmetics.usetrue (everyone)Using /cosmetics and its player subcommands.
celestial.cosmetics.adminopEvery admin subcommand: admin, reload, give, set, clear, extract, and all crate management subcommands.
celestial.cosmetics.<type>.<id>Per-cosmetic access node, e.g. celestial.cosmetics.tag.dragon — set per-entry as permission: in its file.
Reference

Placeholders

Expansion identifier: celestial — register with PlaceholderAPI as usual.

PlaceholderReturns
%celestial_tag%Equipped tag, or empty.
%celestial_emoji%A leading space + the equipped emoji, or empty.
%celestial_namecolor%Name color code, or namecolor-default.
%celestial_namecolor_legacy%Same, snapped to the nearest of the 16 legacy colors — use this (not the hex version) for a nametag plugin's overhead-nametag field, which can't render arbitrary RGB.
%celestial_rankcolor%Equipped Rank Effect code.
%celestial_rankbg%Equipped Rank Background glyph.
%celestial_chatcolor%Chat color code, or chatcolor-default.
%celestial_rank% / %celestial_rank_tab%The full assembled rank image (effect + background + text) for chat, or for TAB (uses image offsets).
%celestial_rankname%Plain rank name, no color.
%celestial_rebirth%Fully styled Rebirth display (empty if the category is disabled).
%celestial_customstat1/2/3%Same idea as Rebirth, pointed at whatever placeholder you configured for that slot.
%celestial_glow%Equipped Glow color name.
%celestial_set%Active Set's display name.
%celestial_keys_<crateId>%How many keys for that crate the player is holding.

Connecting Other Plugins

Economy Integration

Shared by the Auction House and paid crates. If the chosen mode isn't available at startup, purchases are disabled and a clear warning is printed — nothing is ever given away for free by mistake.

ModeBehavior
vaultHooks any Vault-compatible plugin (EssentialsX, CMI, …). Charges the server's main balance — the currency field is ignored in this mode.
eddungeonsHooks the EdDungeons Currency API directly, for a custom currency (credits, gems, whatever you've configured there). currency selects which one.
commandsFully manual — set balance-placeholder plus commands.give/commands.take to match any economy plugin, including PlayerPoints, RivalCredits, or a custom one.
economy:
  economy-mode: eddungeons
  currency: credits
  currency-display: Credits
Connecting Other Plugins

Third-Party Integrations

ItemsAdder / Oraxen / Nexo icons

Every configurable icon supports custom-model-data for a resource-pack model, or a texture field (a base64 player-head skin) for a fully custom head texture — no Java, no recompiling.

Glows through TAB (PacketEvents)

Vanilla glow color is carried by scoreboard teams, which TAB also manages — without PacketEvents installed, TAB can silently reset a player's glow color. With it, CelestialCosmetics rewrites the outgoing team packets directly so the color sticks.

FancyHolograms

Purely optional: install it and floating labels appear automatically above every linked crate block, styled from crate-holograms.lines-normal/lines-limited in config.yml. No FancyHolograms, no label — the block still works.

Worked example: wiring into AlonsoChat's chat format

A real recipe for embedding CelestialCosmetics placeholders into another plugin's chat formatter. AlonsoChat parses its own &#RRGGBB hex codes through a special placeholder — %alonsochat_restorehex_<placeholder>% — that re-applies its hex parser on top of ANY other PlaceholderAPI placeholder's output. Since every CelestialCosmetics color placeholder already emits &#RRGGBB-style codes, wrapping them is enough to make them render:

# AlonsoChat formats.yml — one rank's Parts, in order
Parts:
  rebirth:
    Text: "%alonsochat_restorehex_celestial_rebirth%"
  rank:
    Text: "%notranks_prefix_default% %vault_prefix%"
  player:
    Text: " %alonsochat_restorehex_celestial_namecolor%%player_name%"
  suffix:
    Text: " %alonsochat_restorehex_celestial_tag%"
  message:
    Text: "%alonsochat_restorehex_celestial_chatcolor%{MESSAGE}"

The same trick applies to any chat plugin that lets PlaceholderAPI output pass through unmodified — the order of the Parts keys is what controls left-to-right placement, so a Rebirth prefix in front of the rank is just a matter of listing it first.

⚠️
Most chat plugins strip unrecognized hex codes by default. If a CelestialCosmetics color isn't showing up in chat, check whether the receiving plugin needs its own "allow hex" toggle enabled first.
Connecting Other Plugins

Troubleshooting & FAQ

Purchases are disabled / "economy unavailable"

The configured economy-mode couldn't be hooked at startup — most often Vault or EdDungeons isn't installed, or loaded after CelestialCosmetics. Check the console on startup for the exact warning, then /cosmetics reload once it's fixed.

A menu button's text won't change no matter what I put in config.yml

Double-check the exact path the button lives under — some buttons are shared across two menus (the crate open-confirm and the Auction House purchase-confirm use the same menu.confirm-buttons entries, for instance), so one edit affects both. If a field genuinely has no effect, make sure you're on the latest build; a couple of button paths were fixed in 4.17.13+.

A rank isn't picking up its background/effect

%celestial_rank%/rankbg read from rank-color.ranks.<LuckPerms primary group> — if a group isn't mapped there, the player falls back to their plain rank name with no styling.

Glow color resets randomly

That's almost always TAB fighting over the scoreboard team packets. Install PacketEvents so CelestialCosmetics can rewrite the team packet after TAB sends its own.

Where do I report a bug or request a feature?

Through the BuiltByBit resource page, or open an issue on the GitHub repo.