Repository: MC-Mapping-Reference
This project generates several useful artifacts from the official Minecraft mappings:
- Compact Markdown reference per mapping type and version (the
all-mappingsdocumentation). - V1 changelog: a file diff based on the generated
.mddocuments ("what changed?"). - V2 changelog: a core mapping comparator that reads the
.tinymapping files directly and detects real renames via a stable identity.
Goal: a coding agent (or human) that ports code to/between Minecraft versions should quickly learn which class names truly changed — without any obfuscation noise.
cache/mappings/<version>/ ──► takenaka (md generator) ──► all-mappings/<ns>/<version>/
(raw .tiny/.txt) (per-class .md + classes.md)
│
generate_changelog.py (V1, file diff)
│
changelog/<ns>/<version>.md
│
cache/mappings/<version>/*.client+server.tiny ──► generate_changelog_v2.py (V2)
│
changelog-v2/<ns>/<version>.md
There are three separate building blocks that work together but run independently.
Minecraft code is obfuscated (unreadable names such as a, ec, eza). Mappings are official or
community mappings that map these cryptic names back to readable ones. Different mod loaders use
different mapping systems:
| Mapping type | Internal namespace | Output folder | Used by |
|---|---|---|---|
| Mojang | mojang |
all-mappings/mojang/ |
Modern Mojang mappings (Vanilla, Paper ≥ 1.20.4) |
| Yarn | yarn |
all-mappings/yarn/ |
Fabric & Quilt (community) |
| Fabric | intermediary |
all-mappings/fabric/ |
Fabric runtime (internal intermediate name) |
| Forge | searge |
all-mappings/forge/ |
Forge/NeoForge (Searge names) |
| Obf | source |
all-mappings/obf/ |
Original obfuscation (reference only) |
Every mapping type has subdirectories per Minecraft version.
- 1.21 to 1.21.11: all mapping types available (16 versions).
- 26.1 to 26.2: Mojang and Obf only. There are no Yarn/Intermediary/Searge mappings for these versions — only
mojangis available.
When comparing two versions, the obfuscated source names change completely on every version jump
(overlap only ~60-99%). Comparing classes via the obfuscated names yields thousands of false "changes"
(noise). The mapped names (mojang/yarn/intermediary/searge), on the other hand, are ~98-99% stable —
this is the basis of identity in V2.
The generator comes from the takenaka project (ScreamingSandals). It loads the raw mappings plus the server/client JARs (for modifiers, superclasses/interfaces, generics), reconciles them, and writes one compact Markdown file per class.
cd takenaka
./gradlew :generator-md-cli:shadowJarThe finished JAR is then located at
generator/md-cli/build/libs/generator-md-cli-<version>-all.jar.
java -jar generator-md-cli-<version>-all.jar \
--client --server \
-n mojang -n yarn -n fabric -n forge -n obf \
-v 1.21.4 -v 1.21.11 -v 26.2 \
-o all-mappings \
-c cache/mappings-n(namespace): specify, or omit (then all); order matters.-v(version): required; specify multiple times, or omit to generate all versions again.-ccache directory (raw mapping data + JARs).- The cache needs
cache/mappings/<version>/with the downloaded mapping data.
all-mappings/<mapping>/<version>/...
classes.md # class overview (one line `- \`Class\`` per class)
<package-path>/<SimpleName>.md # one file per class
obf/<version>/<SimpleName>.md # Obf namespace: flat, without package path
Each class .md is a compact table:
# Player (1.21.4)
Class: `net.minecraft.world.entity.player.Player`
## Fields
| Type | Name |
|---|---|
| `Logger` | LOGGER |
## Methods
| Return | Method |
|---|---|
| `boolean` | blockActionRestricted(Level arg0, ...) |The obf documentation serves as reference only and is skipped by both changelog scripts
(all noise).
Staging folders (
md-test*,output-*) are intermediate development states and can be ignored.
Basis: the .md files produced by the Markdown generator.
Type of comparison: a pure file diff — which class names are not present in the previous version.
python3 generate_changelog.py <root> <changelog-dir>
# e.g.:
python3 generate_changelog.py . changelogroot= directory with the namespace subdirectories (theall-mappingsstructure).- generates
changelog/<mapping>/<version>.md, a file only for this single version (against its predecessor).
# Changes for 1.21.4
## New classes (250)
- `net/minecraft/client/ClientBootstrap`
...
## `net/minecraft/world/xxx/Foo` — Fields +1, -1, Methods +2
- Field + `SpriteSet` sprites
- Method - `getRenderType` ()Lgcr;Field identity = field name, method identity = name + parameter prefix. The Obf namespace is omitted.
- Counts every trivial rename as "removed + added" (only "new"/"removed", no rename relationship).
- At 1.21.2 this produces, for example, thousands of class entries, almost all of them pure obfuscation noise.
- No access to the real descriptors — method differences are partially invisible.
V2 is the current main building block and the most useful tool for coding agents. It reads the resolved
.tiny files directly (not the .md) and compares adjacent versions via the stable mapped identity.
python3 generate_changelog_v2.py <mappings-root> <changelog-v2-dir>
# e.g.:
python3 generate_changelog_v2.py cache/mappings changelog-v2mappings-root= directory withcache/mappings/<version>/*.client+server.tiny.- generates
changelog-v2/<mapping>/<version>.md(separate from the V1 directory, so V1 stays unchanged). - Runtime: ~2 minutes for all 16 versions × 4 mapping types.
Because the obfuscated names are unstable across version jumps, identity is based on the mapped
names (analogous to takariakka's AncestryTree / historyPage). Two (one from prev, one from
cur) count as the same logical element if their identity sets intersect:
| Element | Identity |
|---|---|
| Class | {(namespace, mappedName)} |
| Field | {(namespace, mappedName, normDesc)} |
| Method | {(namespace, mappedName, normDesc)} |
The descriptor must be normalized (normDesc): the obfuscated class references inside the descriptor
(e.g. Ldmm;) are replaced with their stable mapped name (e.g. Ljm; in the target namespace).
Without this normalization, members would produce countless false changes per version jump, because the
same method only fails to match because of its changed obfuscated descriptor ("rotate (Ldmm;)F"
vs. "rotate (Ljm;)F").
Furthermore, the union of all namespaces present in both versions (intermediary, yarn, searge,
mojang) is used as the identity search space (the more namespaces overlap, the more reliable the matching).
An element that matched and whose name differs in the target namespace between the previous and current version is a rename.
MAPPING_NS in the script defines which name is used for the output:
| Directory | Target namespace (display) |
|---|---|
mojang |
mojang |
yarn |
yarn |
fabric |
intermediary |
forge |
searge |
obf |
source (omitted, noise) |
# Changes for 1.21.2
## Renamed classes (28)
- **`world/entity/MobSpawnType`** → `world/entity/EntitySpawnReason`
- **`world/item/Tier`** → `world/item/ToolMaterial`
...
## `ElytraLayer` — Fields ~1
- Field ~ `texture` → `wingsTexture` `(Lnet/...;)`
## `Foo` — Methods ~2, +1, -1
- Method ~ `createParticle` → `spawnParticle` `(L...)V`
- Method + `register` `(Llq;)V`- Renamed classes: real
old → newpairs. - New / Removed classes: only the classes that actually appeared / disappeared.
- Members: renames as
~(old → new + descriptor), additions+, removals-. - Only sections with actual changes appear for each class.
26.x special case: here only
mojangexists as a namespace (no second stable namespace). Without a second stable identity, renames cannot be reliably assigned — they therefore appear consistently as removed + added (not assignable, unavoidable).
V1 (generate_changelog.py) |
V2 (generate_changelog_v2.py) |
|
|---|---|---|
| Input | generated .md files |
.tiny mapping files (direct) |
| Answers | only added / removed (no relationship) | identifies old → new pairs |
| Renames | ✗ (appear as removed + added) | ✓ (real pairs) |
| Noise tolerance | high (obf / many 1:1 renames) | low (noise-free) |
| Output folder | changelog/ |
changelog-v2/ |
| Recommended for coding agent | — | ✓ |
The biggest benefit of V2 is rename resolution. A coding agent that ports mod/plugin code to a new Minecraft version can then directly:
- Rewrite class name imports — e.g.
MobSpawnType→EntitySpawnReason, without wading through noise. - See only the real breakages — everything else is a 1:1 rename or a package move.
- Search purposefully — instead of a wall of ~5659 "changed" names, only see the handful of 28-58 real renames.
Thanks to the descriptor normalization, member renames now appear as real ~ pairs (old → new +
descriptor) rather than being misreported as +/-. Only for 26.x (only mojang namespace, no second
stable reference) the assignment is missing — there members still appear as +/-.
# 1) Build the mapping Markdown reference
cd takenaka && ./gradlew :generator-md-cli:shadowJar
java -jar generator/md-cli/build/libs/generator-md-cli-1.2.1-SNAPSHOT-all.jar \
--client --server -n mojang -n yarn -n fabric -n forge -n obf \
-v 1.21 -v 1.21.1 ... -v 26.2 -o all-mappings -c cache/mappings
cd ..
# 2) V1 (file diff) — only if still needed
python3 generate_changelog.py . changelog
# 3) V2 (real renames) — main script
python3 generate_changelog_v2.py cache/mappings changelog-v2MC-Mapping-Reference/
├── README.md # this file
├── generate_changelog.py # V1 script
├── generate_changelog_v2.py # V2 script (core)
├── takenaka/ # Kotlin project with the md generator (building block 1)
└── .gitignore
# Generated data (lives outside the repo in mappings-test/)
all-mappings/ # Markdown reference (generated docs)
├── mojang/ yarn/ fabric/ forge/ obf/ # per mapping type
└── mappings.md # overview of the mapping types
cache/mappings/<version>/ # raw input for both scripts (.client+server.tiny, JARs, ...)
changelog/ # V1 output (file diff)
changelog-v2/ # V2 output (real renames) —— main artifact
md-test*, output-* # obsolete staging folders (can be ignored)
Credits partially based on the work of zlataovce (GitHub profile):
- takenaka — Apache License 2.0; project by ScreamingSandals that provides the Markdown generation. The two changelog scripts build on top of it.