Mappings

class Mappings

Parses the runtime mappings bundle — tiny v2 (namespace ORDER read from the header, see Parser.parseTinyV2) or forge TSRG2 — into the named->runtime lookups mapClass / mapMethod / mapField, so name strings written in mojmap (REPL scripts that pass class/method names to Patches.onEnter / Patches.onExit, plus the mod's own reflective lookups — auth probe, command compat) can be translated to the runtime namespace on a non-mojmap production runtime.

Needed even though script bytecode is remapped: remap rewrites symbol references, NOT string constants. A patch name is a string, so it stays mojmap after remap and matches nothing on an intermediary runtime. Not closed in the remapper instead (rewriting string constants too, as Sinytra attempts): a remapper cannot tell a class name from data, and "minecraft:stone" is data.

Loaded once from the provisioned RemapBundle when the runtime isn't mojmap; a no-op (never loaded) on 26.1+ (unobfuscated), in dev and on NeoForge production, where names already match.

Constructors

Link copied to clipboard
private constructor()

Types

Link copied to clipboard
object Companion
Link copied to clipboard
private inner class Parser

Reads one mappings FILE into the enclosing table. Its own class because format knowledge — tiny v2's column math, TSRG2's indentation rules — is not what the lookup API below is about, and the two change for different reasons. inner, so the accumulating tables need no plumbing.

Properties

Link copied to clipboard
private val ambiguous: HashSet<String>

Runtime names claimed by more than one named method, which reverseMethod must refuse. Empty on intermediary/srg (unique by construction); populated on spigot, whose obf names repeat jar-wide. Only membership is kept — no caller reads what an ambiguous name could have been.

Link copied to clipboard
private val classI2N: HashMap<String, String>
Link copied to clipboard
private val classN2I: HashMap<String, String>
Link copied to clipboard
private var dropped: Int

Class rows either parser dropped for carrying too few columns. Reported once by load, which has the path.

Link copied to clipboard
private val fieldN2I: HashMap<String, String>
Link copied to clipboard
Link copied to clipboard

"runtimeMethod namedOwnerInternal desc" -> named method: the EXACT reverse, holding precisely the rows reverseMethod has to refuse. Owner alone would not identify them — proguard reuses one name for several signatures of a single class — so the descriptor is part of the key.

Link copied to clipboard

Functions

Link copied to clipboard
fun mapClass(namedFqn: String): String

named FQN (dot-separated) -> runtime (intermediary/srg) FQN, or the input unchanged if unmapped.

Link copied to clipboard
fun mapField(namedOwnerFqn: String, namedField: String): String

named field on a named owner FQN -> its runtime name, or the input unchanged if unmapped. Single-valued where mapMethod needs mapMethodAll beside it: overloads are what split one mojmap name across several runtime ones, and fields do not overload. namedOwnerFqn must DECLARE the field — no row exists under an inheritor and this does not climb, the same constraint Class.getDeclaredField puts on its caller.

Link copied to clipboard
fun mapMethod(namedOwnerFqn: String, namedMethod: String): String

named method on a named owner FQN -> a SINGLE runtime method name (the last-declared overload), or the input unchanged if unmapped. For reflective single-target callers (command compat, auth probes) that resolve the exact overload themselves by argument types. Patch weaving must use mapMethodAll instead, or it silently drops every overload but this one.

Link copied to clipboard
fun mapMethodAll(namedOwnerFqn: String, namedMethod: String): List<String>

named method on a named owner FQN -> EVERY runtime name it maps to. Overloads share one mojmap name but carry distinct runtime names, so weaving a name-only patch must target all of them — exactly as ByteBuddy named() already matches every overload on a mojmap runtime. Returns the input name alone when unmapped, so a dev / unmapped runtime still weaves by the mojmap name.

Link copied to clipboard
fun namedMethodOn(runtimeOwnerFqn: String, runtimeMethod: String, desc: String): String?

The exact counterpart of reverseMethod: runtimeMethod with descriptor desc on the RUNTIME owner runtimeOwnerFqn. Null when unmapped — including where the index was pruned away, which is exactly where reverseMethod answers on its own. Callers climb: an override's row lives under the class it inherited from.

Link copied to clipboard
fun reverseClass(runtimeFqn: String): String

runtime (intermediary/srg) FQN -> named FQN — reverse of mapClass, for demapping stack traces and exception messages back to the mojmap names the script was written in. Unmapped input passes through.

Link copied to clipboard
internal fun reverseClassInternal(runtimeInternal: String): String

reverseClass for a caller already holding the internal form — the table's own, so nothing converts.

Link copied to clipboard
fun reverseMethod(runtimeMethod: String): String

runtime method name -> named method name, owner-free — which is what lets a stack-trace frame demap without resolving its class. Unmapped names (constructors, library methods) pass through unchanged, and so do AMBIGUOUS ones: guessing one of them would be a lie in the one place that cannot check it.

Link copied to clipboard
private fun runtimeDesc(named: String): String

A NAMED method descriptor with its class references rewritten into the runtime namespace, so it can be compared against one read off live reflection. Unmapped names — JDK, library, mod types — pass through, which is correct: they are spelled the same in both namespaces.

Link copied to clipboard
fun runtimeNamesOn(runtimeOwnerFqn: String, mojmapMethod: String): List<String>

mapMethodAll against a RUNTIME owner, composed here so the internal name never tours through dotted form.