Skip to content

Installation

  • Java 21+ - required. The plugin is compiled to Java 21 bytecode; on Java 17 or older it fails with UnsupportedClassVersionError. Check with java -version.
  • Paper / Folia (or a Paper fork). Spigot is not supported. api-version is 1.20.
  • Minecraft 1.20+, built against 1.21.11. The server must run Java 21.

Optional soft dependencies (hooked only if installed):

  • PlaceholderAPI - needed for the %optimalmilestones_...% placeholders, and required for any category using Progress.Type: PLACEHOLDER. Without it those categories always read 0.
  • PinnaPrison, EdDungeons, RivalHarvesterHoes - extra API progress sources. Each hook is pure reflection and registers only when its plugin is present.

Milestone rewards are console commands, so whatever plugin grants them needs to be installed - the plugin does not hook it directly.

  1. Confirm java -version reports 21 or higher.
  2. Stop the server.
  3. Drop OptimalMilestones.jar into plugins/.
  4. (Recommended) Add PlaceholderAPI.jar, plus any of the mining plugins above you want as progress sources.
  5. Start the server. The plugin generates its files and prints a startup banner with the category and milestone counts.
  6. Run /plugins - OptimalMilestones should be green.

XSeries downloads automatically on first startup via Paper’s library loader, so the first launch needs internet access and may take a few extra seconds. SQLite is not downloaded - the plugin uses the sqlite-jdbc driver Paper already bundles.

Each third-party hook that registers logs a line like Hooked PinnaPrison for milestone progress. If a category uses one of those sources and you don’t see its line, that plugin wasn’t loaded.

plugins/OptimalMilestones/
β”œβ”€ config.yml # save/notify intervals, progress bar, temporary icons, sounds
β”œβ”€ messages.yml # every message
β”œβ”€ guis/
β”‚ └─ milestones-menu.yml # the /milestones menu layout
β”œβ”€ 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)

Two example categories ship. They hand out crates, booster, cubes, tokens and dragoneggs commands - retarget those at your own plugins before going live. The playtime category reads %statistic_hours_played%, which needs PlaceholderAPI’s Statistic expansion installed (/papi ecloud download Statistic).

Progress and claims are stored in SQLite at data/data.db, one row per (player, category) holding the counter and the claimed-milestone list. There is no MySQL option.

Writes are buffered and flushed on Settings.Save-Interval (default 60 seconds), plus on quit and shutdown. A claim is flushed immediately, so a crash can never let a player claim the same milestone twice.

PLACEHOLDER categories store nothing but their claims - the progress number is read live from PlaceholderAPI each time.

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