Installation
Install OptimalMilestones and OptimalLibrary on your Paper or Folia server.
Requirements
Section titled “Requirements”- OptimalLibrary - required. It is a separate free plugin that provides the shared runtime (text and MiniMessage, menus, storage, PlaceholderAPI support). OptimalMilestones will not enable without it. Keep both plugins up to date together.
- Paper or Folia (or a Paper fork). Spigot is not supported. Supported server versions: 1.21.11, 26.1.1, 26.1.2, 26.2 and 26.3.
- Java 21 for 1.21.11, Java 25 for the 26.x servers. Check with
java -version.
Optional soft dependencies (used only when installed):
- PlaceholderAPI - needed for the
%optimalmilestones_...%placeholders, and required for any category usingProgress.Type: PLACEHOLDER. Without it those categories always read0and never unlock. - PinnaPrison, EdDungeons, RivalHarvesterHoes - extra
APIprogress sources (PINNAPRISON,EDDUNGEONS,RIVALHARVESTERHOE). Each hook registers only when its plugin is installed, and logsHooked <plugin>.on startup.
Milestone rewards are console commands, so whatever plugin hands out the reward (crates, boosters, economy) needs to be installed too. OptimalMilestones does not hook it directly.
- Check
java -versionmatches your server version (21 for 1.21.11, 25 for 26.x). - Stop the server.
- Drop
OptimalLibrary.jarandOptimalMilestones.jarintoplugins/. - (Recommended) Add
PlaceholderAPI.jar, plus any of the plugins above you want as progress sources. - Start the server. The plugin generates its files and prints a startup banner with the number of categories and milestones loaded.
- Run
/plugins-OptimalLibraryandOptimalMilestonesshould both be green.
On the first start OptimalLibrary downloads its libraries (the SQLite and MySQL drivers, HikariCP and XSeries) through Paper’s library loader, so the server needs internet access and the first launch takes a few extra seconds.
Generated files
Section titled “Generated files”plugins/OptimalMilestones/├─ config.yml # save/notify intervals, progress bar, sounds├─ messages.yml # every message├─ guis/│ └─ milestones-menu.yml # the /milestones menu layout and temporary icons├─ milestones/ # one file per category, id = file name│ ├─ blocks.yml # API category, BLOCK_BREAK source, 24 milestones│ └─ playtime.yml # PLACEHOLDER category, %statistic_hours_played%, 12 milestones└─ data/ └─ data.db # SQLite player data (do not edit by hand)The milestones/ folder is only filled with the two examples when it does not exist yet. Delete or
rename the examples freely, they will not come back unless you delete the whole folder.
The example rewards use crates, booster, cubes, dragoneggs, dragonbox, tokens, credits
and lootbox commands. Point them at your own plugins before going live. The playtime category
reads %statistic_hours_played%, which needs PlaceholderAPI’s Statistic expansion
(/papi ecloud download Statistic).
Storage
Section titled “Storage”Progress and claims are stored in SQLite at data/data.db, in a player_milestones table with
one row per player and category (the counter plus the list of claimed milestone numbers). There is no
MySQL option for this plugin.
- A player’s data is loaded while they log in. If it cannot be loaded, the login is refused with the
PROFILE-LOAD-FAILEDmessage, so nobody plays with an empty profile that would overwrite their real one. - Changes are kept in memory and saved every
Settings.Save-Intervalseconds (default60), on quit and on server shutdown. - A claim is saved immediately, so a crash can never let a player claim the same milestone twice.
PLACEHOLDERcategories store only their claims. The progress number is read live from PlaceholderAPI.
Continue to Creating Categories, or read the Information overview first.
