Skip to content

Version resolution

pack_format is a declaration of which asset layout a pack targets, not a version of the pack.mcmeta file. Turning it into Minecraft versions is what this library is for.

Declared vs effective

Overlays are how one pack supports several game versions: the root assets target one range, and each overlay directory swaps in replacements for another. So there are two honest answers, and both are exposed.

IdentificationResult.Identified identified = ...;

identified.declaredVersions();   // what the root "pack" section claims
identified.effectiveVersions();  // widened by every overlay range

For a pack declaring min_format 69.0 / max_format 88.0 with an overlay covering 55–63:

assertEquals("1.21.9 - 26.2", ((VersionResolution.Releases) identified.declaredVersions()).range().toString());
assertEquals("1.21.5 - 26.2", ((VersionResolution.Releases) identified.effectiveVersions()).range().toString());

Report only the declared range and you under-report every serious multi-version pack. Report only the effective range and you have silently merged ranges the author never claimed as one unit. Pick whichever suits the question you are answering.

The same distinction exists on the metadata itself as declaredRange() and effectiveRange(), in PackFormat terms rather than game versions.

The four resolutions

VersionResolution is sealed:

VersionTable table = VersionTable.bundled();

table.resolve(PackFormat.of(64));    // Releases        1.21.7 - 1.21.8
table.resolve(PackFormat.of(20));    // Snapshots       never shipped in a release
table.resolve(PackFormat.of(23));    // Unrecognised    no build ever used it
table.resolve(PackFormat.of(9999));  // NewerThanKnown  from the future
Case Meaning
Releases The format shipped in at least one release. Carries the release range
Snapshots The format existed only in snapshots
NewerThanKnown Beyond the table's ceiling. Carries the highest format the table knows
Unrecognised Within range but matching nothing — formats 10, 23 and 27 are real examples

NewerThanKnown is a useful answer, not an error: it tells you the pack is from a newer Minecraft than this build of the library knows about, which is different from the pack being broken.

Every case has describe() for a human-readable summary.

Format numbering

PackFormat(major, minor) models both eras. Minecraft switched to major.minor at 69.0 (1.21.9); before that a format was a bare integer. A bare 82 is PackFormat(82, 0), exactly as the game coerces it.

PackFormat.of(82);      // 82.0
PackFormat.of(69, 1);   // 69.1

toString() always renders major.minor. Legacy formats therefore print as 18.0 rather than 18 — uniform and unambiguous, at the cost of being slightly verbose for the pre-1.21.9 era.

The version table

The bundled table covers 485 Minecraft versions across 98 formats, snapshot-exact, and carries an asOf marker.

VersionTable table = VersionTable.bundled();

table.asOf();          // the newest version in the table
table.highestKnown();  // its pack format
table.lowestKnown();   // PackFormat.of(1)
table.versions();      // newest first

It is generated, not hand-maintained:

./gradlew updateVersionTable

That merges misode/mcmeta — machine-readable and updated every snapshot, covering 1.14 onwards — with a frozen hand-curated table for 1.6.1 – 1.13.2. It never runs during a normal build, so builds stay offline and reproducible.

Supply your own table with VersionTable.load(InputStream) if you need to run ahead of a release. Required fields are validated, so a malformed table fails loudly instead of silently resolving everything to format 0.0.