Skip to main content

yog_cli/
mappings.rs

1//! `yog mappings` (`docs/design/nanites.md`, "Names"): a host's mapping
2//! table — Mojang's names → the host's run-time names — from Mojang's
3//! mappings and the loader's (Fabric's intermediary, Forge's SRG), fetched
4//! once into Yog's cache.
5
6mod fetch;
7mod proguard;
8mod runtime;
9#[cfg(test)]
10mod tests;
11
12use yog_event::nanite::{ClassMap, Mappings, MemberMap};
13use yog_ids::mapping_ns;
14
15/// Mojang's classes joined with `rt`: each class and member by Mojang's
16/// name, renamed as `rt` names it (`keep_classes`: Forge keeps Mojang's
17/// class names at run time, renaming members only).
18pub(crate) fn join(
19    mojang: &[proguard::Class],
20    rt: &runtime::Runtime,
21    runtime_ns: &str,
22    keep_classes: bool,
23) -> Mappings {
24    let obf_of = proguard::class_map(mojang);
25    let classes = mojang
26        .iter()
27        .map(|c| {
28            let renamed = rt.classes.get(&c.obf).filter(|_| !keep_classes);
29            let field = |(n, obf): &(proguard::Named, String)| MemberMap {
30                named: n.name.clone(),
31                desc: String::new(),
32                runtime: rt
33                    .fields
34                    .get(&(c.obf.clone(), obf.clone()))
35                    .cloned()
36                    .unwrap_or_else(|| n.name.clone()),
37            };
38            let method = |(n, obf): &(proguard::Named, String)| {
39                let obf_desc = proguard::remap_desc(&n.desc, &obf_of);
40                MemberMap {
41                    named: n.name.clone(),
42                    desc: n.desc.clone(),
43                    runtime: rt
44                        .methods
45                        .get(&(c.obf.clone(), obf.clone(), obf_desc))
46                        .cloned()
47                        .unwrap_or_else(|| n.name.clone()),
48                }
49            };
50            ClassMap {
51                named: c.named.clone(),
52                runtime: renamed.cloned().unwrap_or_else(|| c.named.clone()),
53                fields: c.fields.iter().map(field).collect(),
54                methods: c.methods.iter().map(method).collect(),
55            }
56        })
57        .collect();
58    let mut out = Mappings {
59        runtime: runtime_ns.to_owned(),
60        classes,
61    };
62    out.prune();
63    out
64}
65
66/// The table for Minecraft `mc` on a host running `runtime_ns` names.
67pub fn table(mc: &str, runtime_ns: &str) -> Result<Mappings, String> {
68    if runtime_ns == mapping_ns::MOJANG {
69        return Ok(Mappings {
70            runtime: runtime_ns.to_owned(),
71            classes: Vec::new(),
72        });
73    }
74    let mojang = proguard::parse(&fetch::mojang(mc)?);
75    match runtime_ns {
76        mapping_ns::INTERMEDIARY => {
77            let rt = runtime::tiny(&fetch::intermediary(mc)?)?;
78            Ok(join(&mojang, &rt, runtime_ns, false))
79        }
80        mapping_ns::SRG => Ok(join(
81            &mojang,
82            &runtime::tsrg(&fetch::srg(mc)?),
83            runtime_ns,
84            true,
85        )),
86        other => Err(format!(
87            "no run-time names `{other}`: {}, {} or {}",
88            mapping_ns::MOJANG,
89            mapping_ns::INTERMEDIARY,
90            mapping_ns::SRG
91        )),
92    }
93}