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.
1. Create the file
Section titled “1. Create the file”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: trueDisplay-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.
2. Pick the progress type
Section titled “2. Pick the progress type”API - the plugin counts
Section titled “API - the plugin counts”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.
PLACEHOLDER - another plugin counts
Section titled “PLACEHOLDER - another plugin counts”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.
3. Style the milestone icons
Section titled “3. Style the milestone icons”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).
4. List the milestones
Section titled “4. List the milestones”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.
5. Reload
Section titled “5. Reload”/milestonesadmin reloadThe category appears in the menu immediately. Test it with
/milestonesadmin progress set <you> mobs 1000, then put yourself back with
/milestonesadmin reset <you> mobs.
Menu slots
Section titled “Menu slots”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: falseon 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: falseon 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,MilestonesorMilestone-Iconssection, 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.
