import zipfile, json, re, os, sys, glob, subprocess, collections
VERSIONS = ["1.20.1", "1.21.1"]
ids = collections.defaultdict(set) for v in VERSIONS:
z = zipfile.ZipFile(os.path.expanduser(f"~/.gradle/caches/fabric-loom/{v}/minecraft-client.jar"))
names = z.namelist()
lang = json.loads(z.read("assets/minecraft/lang/en_us.json"))
named_items = {k.split(".")[2] for k in lang if re.fullmatch(r"item\.minecraft\.[a-z0-9_]+", k)}
named_blocks = {k.split(".")[2] for k in lang if re.fullmatch(r"block\.minecraft\.[a-z0-9_]+", k)}
textured = {m[1] for n in names if (m := re.fullmatch(r"assets/minecraft/textures/item/([a-z0-9_]+)\.png", n))}
for n in names:
if re.fullmatch(r"assets/minecraft/models/item/[a-z0-9_]+\.json", n):
for o in json.loads(z.read(n)).get("overrides", []):
textured.discard(o.get("model", "").split("/")[-1])
for n in names:
m = re.fullmatch(r"assets/minecraft/models/item/([a-z0-9_]+)\.json", n)
if m and (m[1] in named_items or m[1] in named_blocks or m[1] in textured):
ids[("item", m[1])].add(v)
m = re.fullmatch(r"assets/minecraft/blockstates/([a-z0-9_]+)\.json", n)
if m:
ids[("block", m[1])].add(v)
m = re.fullmatch(r"data/minecraft/recipes?/([a-z0-9_/]+)\.json", n)
if m:
ids[("recipe", m[1])].add(v)
m = re.fullmatch(r"data/minecraft/loot_tables?/([a-z0-9_/]+)\.json", n)
if m:
ids[("loot_table", m[1])].add(v)
for k in lang:
m = re.fullmatch(r"entity\.minecraft\.([a-z0-9_]+)", k)
if m:
ids[("entity", m[1])].add(v)
mappings = glob.glob(os.path.expanduser(f"~/.gradle/caches/fabric-loom/{v}/*/mappings.tiny"))
registry_class = None
for mapping in mappings:
with open(mapping) as f:
for line in f:
columns = line.rstrip("\n").split("\t")
if len(columns) >= 4 and columns[0] == "c" and columns[-1] == "net/minecraft/potion/Potions":
registry_class = columns[1]
break
if registry_class:
break
if registry_class is None:
raise RuntimeError(f"no Yarn mapping for Minecraft {v}'s potion registry")
bytecode = subprocess.run(
["javap", "-classpath", os.path.expanduser(f"~/.gradle/caches/fabric-loom/{v}/minecraft-client.jar"), "-c", "-p", registry_class],
check=True,
capture_output=True,
text=True,
).stdout
for potion in re.findall(r"// String ([a-z0-9_]+)\s*$", bytecode, re.MULTILINE):
ids[("potion", potion)].add(v)
out = ["# Vanilla ids per Minecraft version: <kind> <path> <versions>; generated from the client jars.",
"# versions: " + " ".join(VERSIONS)]
for (kind, path), vs in sorted(ids.items()):
tag = "*" if len(vs) == len(VERSIONS) else ",".join(sorted(vs))
out.append(f"{kind} {path} {tag}")
open(sys.argv[1], "w").write("\n".join(out) + "\n")
c = collections.Counter(k for k, _ in ids)
print(c, "partial:", sum(1 for vs in ids.values() if len(vs) < len(VERSIONS)))