Skip to content

Creating Categories

Add a milestone track - pick a progress source, style its icons, and list the milestones.

A category is one file in milestones/. Add a file and you get a new track with its own selector icon in the menu. You need optimalmilestones.admin to reload.

Create plugins/OptimalMilestones/milestones/<id>.yml. The file name is the category id - it is what /milestones <category>, the admin commands and the placeholders use. Ids are lower-cased, so Mobs.yml becomes mobs.

Enabled: true
Display-Name: "Mobs"
Order: 3
Menu:
Slot: 4
Material: ZOMBIE_HEAD
Name: "&c&lMobs Milestone"
Lore:
- "&7Kill mobs to progress this track."
- ""
- "&4 - &cComplete: &a{complete}&8/&c{total}"
- ""
- "&e➥ Click to view!"
Progress:
Type: API
API: MOB_KILL
Milestone-Icons:
Locked: { ... }
Unclaimed: { ... }
Claimed: { ... }
Milestones:
"1":
Enabled: true
Required: 100
Lore:
- "{secondary} - &f3x Pearl Key"
Commands:
- "crates key give {player} pearl 3"

The easiest start is to copy blocks.yml, rename it and change what you need. Full field list: milestones reference.

One named source, +1 per matching event. No chance, amount, world, block or mob filters.

Progress:
Type: API
API: BLOCK_BREAK
Source +1 for every
BLOCK_BREAK Block a player breaks. Cancelled breaks (protected regions, etc.) do not count.
BLOCK_PLACE Block a player places. Cancelled places do not count.
MOB_KILL Non-player entity killed by a player. Player kills do not count.
PINNAPRISON PinnaPrison block mine event.
EDDUNGEONS EdDungeons sword swing event.
RIVALHARVESTERHOE RivalHarvesterHoes block break event.

Names are case-insensitive and - counts as _, so block-break works. An unknown name fails the load. The last three only count when their plugin is installed.

Several categories may share a source and each gets its own +1, so a Blocks track and a second Blocks track can both count block breaks independently. Disabled categories do not count anything.

API counters live in the plugin’s database, so /milestonesadmin progress can change them.

Progress:
Type: PLACEHOLDER
Placeholder: "%statistic_hours_played%"

The placeholder is resolved live for the player every time progress is needed. Any numeric placeholder from any expansion works. Everything from the first . on is dropped and every other non-digit is ignored, so 1,234.7 reads as 1234 and 58 hours as 58. A blank result reads 0.

PLACEHOLDER categories store no counter, so /milestonesadmin progress refuses them with CATEGORY-NOT-TRACKED. To change the number, change whatever feeds the placeholder. /milestonesadmin reset still works on them and clears their claims.

Milestone-Icons is required and needs all three states: Locked, Unclaimed and Claimed. Each state carries its own Primary and Secondary colors, which fill {primary} and {secondary} across the whole icon, including the milestone’s own reward lore. That is how one reward line recolors itself per state.

Milestone-Icons:
Unclaimed:
Material: YELLOW_STAINED_GLASS_PANE
Primary: "&e"
Secondary: "&6"
Name: "{primary}&lMilestone {secondary}&l{milestone}"
Lore:
- "&7You are able to claim this"
- "&7milestone."
- " "
- "{primary}Rewards:"
- "{reward-lore}"
- " "
- "{primary}&lUNCLAIMED"

There is no global icon block. Every category defines its own, so a Blocks track can show {progress}/{required} while a Playtime track shows {progress}h / {required}h.

The {reward-lore} line is replaced with the milestone’s own Lore list. The icon’s stack size is the milestone number (capped at 64).

Milestones holds entries keyed by the milestone number. Keys must be whole numbers, 1 or higher.

Milestones:
"1":
Enabled: true
Required: 1000
Lore:
- "{secondary} - &f3x Pearl Key"
Commands:
- "crates key give {player} pearl 3"
"2":
Enabled: true
Required: 2500
Lore:
- "{secondary} - &f3x Orbs Booster &7(1.25x, 10m)"
Commands:
- "booster give {player} orbs 1.25 10"

Required is a cumulative total: milestone 2 at 2500 means 2,500 overall, not 2,500 on top of milestone 1. Keep the values going up with the number, or the track will read strangely.

Every milestone needs at least one command. An empty Commands list fails the load.

/milestonesadmin reload

The category appears in the menu immediately. Test it with /milestonesadmin progress set <you> mobs 1000, then put yourself back with /milestonesadmin reset <you> mobs.

Two different slot settings are involved, and they live in different files:

Setting Where Controls
Menu.Slot the category file Where this category’s selector icon sits.
Milestone-Slots guis/milestones-menu.yml The paged grid every category shares. Its length is the page size.

Give each category its own Menu.Slot, inside the menu Size and outside the milestone grid. The category being viewed glows.

Order sorts the categories, lowest first. The enabled category with the lowest Order is the one /milestones opens by default. Two categories with the same Order are sorted by id.

  • Disable without deleting: Enabled: false on a category hides it from the menu, from /milestones <category> and from tab completion, and stops its progress being counted. Its stored data is kept.
  • Disable one milestone: Enabled: false on a milestone removes it from the track. The numbers around it don’t shift, so a gap is fine.
  • Roman numerals: {milestone} shows the number as a Roman numeral; use {number} for the plain number.
  • The menu opens on the page of the first unclaimed milestone, so long tracks land where the player actually is.
  • Errors fail loudly. A missing Menu, Progress, Milestones or Milestone-Icons section, a non-numeric milestone key or a milestone with no commands stops the load with the category id in the console. Check the console after every reload.