Skip to content

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).

  • 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.
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.
  • 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

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 with all. Works on offline players who have joined before. Refused when the player has that cosmetic listed on the market (all skips listed ones).
  • /cosmeticsadmin remove <player> <cosmetic|all> - take a cosmetic away, or every cosmetic with all. 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 own Voucher block or the global one).
  • /cosmeticsadmin maxlistings <player> <amount|reset> - override a player’s market listing limit. 0 means unlimited, reset (or default) goes back to Market.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.

  • optimalcosmetics.use - /cosmetics and /cosmetics market (default: everyone)
  • optimalcosmetics.admin - every /cosmeticsadmin command 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.

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.

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).

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).

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.