Information
OptimalCosmetics features, cosmetic types, commands, permissions, placeholders, tokens and formatting in one reference.
BattleStudio plugin
OptimalCosmetics
Eight types of equippable cosmetics, a player-to-player escrow market and placeable cases with daily rotations and limited-edition wins.
- Requires
- Paper / FoliaMC 1.21.11+Java 21+OptimalLibraryPlaceholderAPI
OptimalCosmetics gives players a menu of collectable cosmetics - chat colors, tags, name paints, rank colors, glow, tab icons, join messages and leave messages - plus a player-to-player market and cases you place in the world that players pay to open. Players own cosmetics and equip one per type. There are no per-cosmetic permissions: a player either owns a cosmetic or does not.
The plugin does not format chat or nametags itself. It exposes every equipped cosmetic through
PlaceholderAPI, and your chat, tab or nametag plugin renders them. The things it does handle
directly are join and leave messages (it replaces the vanilla join/quit message), glow (it turns on
the entity glow outline) and, optionally, chat colors (see Paint-Chat-Message).
How it works
Section titled “How it works”- Cosmetics are config. Each type is one file in
cosmetics/, and every top-level key in that file is one cosmetic. - Ownership is stored per player in SQLite or MySQL, keyed by type and id. Players get cosmetics
from an admin
give, a redeemed voucher, a market purchase or a case win. - Equipping happens in
/cosmetics: click an owned cosmetic, then equip or unequip it in the equip menu. Equipping a second cosmetic of the same type replaces the first. - The market holds listings in escrow: listing a cosmetic takes it out of the seller’s collection until it sells, is removed, or expires.
- Cases are blocks placed with
/cosmeticsadmin place. Clicking one shows today’s rotation of cosmetics; opening it charges the case price, plays an animation above the block and unlocks one random cosmetic from the rotation.
Cosmetic types
Section titled “Cosmetic types”| Type | File | What it does |
|---|---|---|
| Chat Color | chat-colors.yml |
Colors the player’s chat message, through placeholders or directly with Paint-Chat-Message. |
| Tag | tags.yml |
A label exposed as %optimalcosmetics_tag% for your chat or nametag plugin. |
| Name Paint | name-paints.yml |
The player’s name painted with a color or gradient, as %optimalcosmetics_namepaint%. |
| Rank Color | rank-colors.yml |
Repaints the player’s rank (read from Rank-Placeholder, for example the LuckPerms prefix), as %optimalcosmetics_rankcolor%. |
| Glow | glow.yml |
Turns on the glow outline and exposes a color that cycles every 2 seconds. |
| Tab Icon | tab-icons.yml |
A symbol exposed as %optimalcosmetics_tabicon% for your tab plugin. |
| Join Message | join-messages.yml |
Replaces the player’s vanilla join message. |
| Leave Message | leave-messages.yml |
Replaces the player’s vanilla quit message. |
Features
Section titled “Features”- Eight cosmetic types, one equipped per type, any number of cosmetics per type
- Paginated cosmetics menu with a type filter, an “Owned” filter and three sort modes
- Fully dynamic rarities: add, rename or remove them, config order is the rank
- Player-to-player market with escrow, listing fee, sale tax, price bounds, listing limits, expiry, search and an optional purchase confirmation
- Market purchases are journaled in the database, so a crash mid-purchase is recovered on the next start, and they stay safe across several servers sharing one MySQL database
- Cases: a placed block with a daily rotation, a spin animation, limited-edition cosmetics with a fixed number of winners and a built-in packet hologram (no hologram plugin needed)
- Vouchers: redeemable items that unlock one cosmetic
- Economy through Vault, PlayerPoints or RivalCredits, each with its own currency format
- Every menu is a config file with action-driven buttons
- PlaceholderAPI output in MiniMessage or legacy form, to match your chat plugin
- SQLite or MySQL storage, Folia-ready
Commands
Section titled “Commands”Player - /cosmetics (alias /cosmetic):
/cosmetics- open the cosmetics menu ·optimalcosmetics.use/cosmetics market- open the market ·optimalcosmetics.use
Admin - /cosmeticsadmin (alias /cosmeticadmin) · all optimalcosmetics.admin:
/cosmeticsadmin give <player> <cosmetic|all>- unlock a cosmetic, or every cosmetic withall. Works on offline players who have joined before. Refused when the player has that cosmetic listed on the market (allskips listed ones)./cosmeticsadmin remove <player> <cosmetic|all>- take a cosmetic away, or every cosmetic withall. An online player also has it unequipped. Works on offline players./cosmeticsadmin givevoucher <player> <cosmetic> [amount]- give redeemable vouchers. Online players only. Needs a voucher template (the cosmetic’s ownVoucherblock or the global one)./cosmeticsadmin maxlistings <player> <amount|reset>- override a player’s market listing limit.0means unlimited,reset(ordefault) goes back toMarket.Max-Listings. Works offline./cosmeticsadmin place <case>- get the placeable item for a case. Players only./cosmeticsadmin reload- reload every config, menu, cosmetic, case and message file.
Running /cosmeticsadmin with no or wrong arguments shows the help panel (COSMETICS-ADMIN-HELP).
<cosmetic> is the cosmetic’s id (its key in the type file), matched case-insensitively. When two
types share an id, prefix the type: CHAT_COLOR:Lime or chat-colors:Lime.
Removing a case block: sneak and left-click it while holding optimalcosmetics.admin. The block
is removed and its case item goes back into your inventory.
Permissions
Section titled “Permissions”optimalcosmetics.use-/cosmeticsand/cosmetics market(default: everyone)optimalcosmetics.admin- every/cosmeticsadmincommand and removing placed case blocks (default: op)
Cosmetics have no permission nodes. Opening a case, using the market and redeeming vouchers need no extra permission.
Placeholders
Section titled “Placeholders”Requires PlaceholderAPI. The identifier is optimalcosmetics. Text placeholders return
MiniMessage or legacy § codes depending on Settings.Placeholder-Format; match it to what your
chat or nametag plugin expects. Every placeholder returns an empty string while the player’s profile
is not loaded.
Equipped cosmetics:
| Placeholder | Returns |
|---|---|
%optimalcosmetics_tag% |
The equipped tag’s Value, or empty. |
%optimalcosmetics_chatcolor% |
The part of the chat color Value before {context}. Put it in front of the message. |
%optimalcosmetics_chatcolor_suffix% |
The part after {context} (the closing tags). Put it after the message. |
%optimalcosmetics_namepaint% |
The player’s name painted with the equipped name paint, or the plain name when none is equipped. |
%optimalcosmetics_namepaint_suffix% |
Always empty. Kept for formats that expect a suffix. |
%optimalcosmetics_rankcolor% |
The player’s rank from Settings.Rank-Placeholder, stripped of its own colors and repainted. Returns the rank unchanged when no rank color is equipped, and empty when Rank-Placeholder is blank. |
%optimalcosmetics_rankcolor_prefix% |
The part of the rank color Value before {context}, for wrapping a rank placeholder yourself. |
%optimalcosmetics_rankcolor_suffix% |
The part after {context}. |
%optimalcosmetics_glow% |
The current glow color, cycling through the glow’s colors every 2 seconds (<red> in MiniMessage mode, a § code in legacy mode). Empty without a glow. |
%optimalcosmetics_tabicon% |
The equipped tab icon with a leading space, or empty. |
Totals:
| Placeholder | Returns |
|---|---|
%optimalcosmetics_count% |
Number of enabled cosmetics across every type. |
%optimalcosmetics_owned% |
Number of cosmetics the player owns. |
Per type - <type> is one of chatcolor, tag, namepaint, rankcolor, glow, tabicon,
joinmessage, leavemessage:
| Placeholder | Returns |
|---|---|
%optimalcosmetics_<type>_id% |
The equipped cosmetic’s id, or empty. |
%optimalcosmetics_<type>_name% |
The equipped cosmetic’s Name, formatted. |
%optimalcosmetics_<type>_value% |
The equipped cosmetic’s Value, formatted. |
%optimalcosmetics_<type>_count% |
Number of enabled cosmetics of that type. |
%optimalcosmetics_<type>_owned% |
How many of that type the player owns. |
Tokens
Section titled “Tokens”These are the plugin’s own {...} tokens. Where each one resolves is listed on the config pages.
| Token | Value | Used in |
|---|---|---|
{context} |
The text a cosmetic paints (chat message, name or rank). | Chat color, name paint and rank color Value. |
{player} |
The player’s name. | Join and leave message Value, messages, menu actions. |
{primary}, {secondary} |
The rarity’s colors from Rarity-Colors. |
Cosmetic Name/Lore/Value, lore addons, market lore, vouchers, case lore. |
{type} |
The cosmetic’s type label from Cosmetic-Format.Type-Labels. |
Lore addons, market lore, vouchers, case lore. |
{rarity} |
The cosmetic’s Rarity. |
Lore addons, market lore, vouchers, case lore. |
{count} |
Enabled cosmetics of that type (in case holograms: cosmetics in the rotation). | Lore addons, market lore, vouchers, holograms. |
{cosmetic}, {cosmetic-type} |
The cosmetic’s Name and type label. |
Messages, vouchers, case lore. |
{price}, {seller}, {expires} |
Listing price (currency formatted), seller name, time left. | Market lore, market messages. |
{category}, {sort}, {sort-market} |
The current filter and sort. | Filter and sort buttons. |
{page}, {pages}, {results} |
Current page, page count, number of entries. | Paged menus (cosmetics menu, market). |
Vouchers
Section titled “Vouchers”A voucher is an item that unlocks one cosmetic when the player right-clicks it. Admins give them
with /cosmeticsadmin givevoucher, and a case gives one instead when the player wins a cosmetic
they already own (or have listed). Redeeming is refused while the player owns the cosmetic or has it
listed on the market. The voucher’s look comes from the cosmetic’s own Voucher block, or from the
global Voucher template in config.yml. A voucher
whose cosmetic was deleted from the config stops working (VOUCHER-INVALID).
Formatting
Section titled “Formatting”Every text field supports legacy & codes, &#RRGGBB hex, MiniMessage (<gradient:a,b,c>,
<rainbow>, <bold>, <#RRGGBB>, …) and, with PlaceholderAPI installed, %...% in messages, menu
items and case holograms. <gradient> accepts comma-separated hex stops. Messages and join/leave
message values support [center]...[/center] to center a line in chat.
Reference
Section titled “Reference”- Install: Installation
- Guides: Creating Cosmetics · Creating Cases · The Market
- Config files: config.yml · cosmetics · cases · menus · messages.yml
