Skip to content

Installation

Install OptimalCosmetics and OptimalLibrary on your Paper or Folia server.

  • OptimalLibrary - required. It is a separate free plugin that every Optimal plugin runs on (text and MiniMessage, menus, storage, economy hooks, the packet holograms). OptimalCosmetics will not load without it.
  • Paper or Folia (or a Paper fork) on 1.21.11, 26.1.1, 26.1.2, 26.2 or 26.3. Spigot is not supported.
  • Java 21 for 1.21.11, Java 25 for the 26.x versions. Check with java -version.

Soft dependencies, hooked only when installed:

  • PlaceholderAPI - strongly recommended. The cosmetic placeholders are how your chat, tab and nametag plugins show tags, name paints, chat colors, rank colors, glow colors and tab icons. It also resolves %...% from other plugins in messages, menu items and case holograms. Without it only join/leave messages, the glow outline and Paint-Chat-Message still work.
  • Vault (with an economy plugin), PlayerPoints or RivalCredits - the currency for the market (Settings.Economy) and for each case (Settings.Currency in the case file). Without the configured provider, market buying and selling and opening that case are refused with a “currency unavailable” message.

Holograms above case blocks are built in. No hologram plugin is needed.

  1. Confirm java -version reports the right version for your server (21 or 25).
  2. Stop the server.
  3. Drop OptimalLibrary.jar and OptimalCosmetics.jar into plugins/.
  4. (Recommended) Add PlaceholderAPI.jar and your economy plugin.
  5. Start the server. OptimalCosmetics generates its files and prints a startup banner with the number of loaded cosmetics.
  6. Run /plugins - both OptimalLibrary and OptimalCosmetics should be green.

OptimalLibrary downloads sqlite-jdbc, mysql-connector-j, HikariCP and XSeries through Paper’s library loader on first startup, so the first launch needs internet access and may take a few extra seconds.

plugins/OptimalCosmetics/
├─ config.yml # settings, economy, MySQL, market, voucher, types, sorts, rarities, lore, sounds
├─ messages.yml # every message, plus the type labels
├─ locations.yml # placed case blocks (written by the plugin)
├─ cosmetics/ # one file per type, each holding many cosmetics
│ ├─ chat-colors.yml
│ ├─ tags.yml
│ ├─ name-paints.yml
│ ├─ rank-colors.yml
│ ├─ glow.yml
│ ├─ tab-icons.yml
│ ├─ join-messages.yml
│ └─ leave-messages.yml
├─ cases/
│ └─ secret.yml # example case, the file name is the case id
├─ guis/
│ ├─ cosmetics-menu.yml # the /cosmetics menu
│ ├─ equip-menu.yml # equip / unequip / sell one cosmetic
│ ├─ cosmetics-market.yml # the market
│ ├─ market-confirm.yml # market purchase confirmation
│ └─ case-confirm.yml # case opening confirmation
└─ data/
└─ data.db # SQLite data (only with Database: "SQLite")

A few example cosmetics ship in each type file and one example case (secret) ships in cases/. Before going live, check the example case’s Currency and Price, and edit or replace the example cosmetics.

How missing files come back:

  • cosmetics/ and cases/ are only extracted when the folder does not exist. A type file you delete stays deleted (that type then has no cosmetics). Delete the whole folder to get the defaults back.
  • Files missing from guis/ are re-extracted on every load and reload.
  • Keys missing from messages.yml are written back with their defaults.
  • config.yml is created once and never merged. A setting you delete falls back to its built-in default, but the list and lore sections must stay (see config.yml).

Everything players own is stored in SQLite at data/data.db by default: equipped cosmetics, owned cosmetics, market listings, listing-limit overrides, pending market payouts and refunds, the purchase journal, case rotations and limited-edition winners.

Set Settings.Database: "MySQL" and fill in the MySQL section to share that data across a network, so ownership and equips follow a player between servers. The market is built for this: a listing can only be bought, removed or expired once, even when several servers share the database. Switching database needs a full restart; /cosmeticsadmin reload does not reconnect.

When data is written:

  • Ownership grants and removals are written immediately.
  • Equipping or unequipping saves the player straight away. Any unsaved profile is also flushed every Settings.Save-Interval seconds, on quit and on shutdown.
  • A player’s profile is loaded while they log in. If it cannot be loaded, the login is refused with PROFILE-LOAD-FAILED instead of letting them in with empty cosmetics.

Placed cases are stored in locations.yml, not in the database. Each server keeps its own.

Continue to Creating Cosmetics, or read the Information overview first.