Skip to content

Instantly share code, notes, and snippets.

@tildejustin
Last active November 6, 2023 00:49
Show Gist options
  • Save tildejustin/1f6d4c2a9977978fca1d2df616f76859 to your computer and use it in GitHub Desktop.
Save tildejustin/1f6d4c2a9977978fca1d2df616f76859 to your computer and use it in GitHub Desktop.
import os
import time
from typing import TextIO
class Element:
containing_class: str
signature: str
official_name: str
intermediary_name: str
def __init__(self, definition: list[str]):
self.containing_class = definition[1]
self.signature = definition[2]
self.official_name = definition[3]
self.intermediary_name = definition[4]
def __str__(self) -> str:
return f"{self.intermediary_name}, {self.official_name}: {self.signature} in {self.containing_class}"
def find_element(signature: str, official_name: str, candidates: list[Element]) -> Element:
results = list(filter(lambda x: x.signature == signature and x.official_name == official_name, candidates))
if len(results) != 1:
print(signature, official_name, [str(element) for element in candidates])
raise AssertionError()
return results[0]
def rename_class(clas: str) -> str:
candidate = classes.get(clas)
if candidate is None:
return clas
return candidate
# some documentation on signatures
# https://jenkins.liteloader.com/view/Other/job/Mixin/javadoc/index.html?org/spongepowered/asm/mixin/injection/InjectionPoint.Selector.html
def remap_signature(signature: str) -> str:
is_method = signature[0] == "("
method_part = []
field_part = signature
if is_method:
sections = signature[1:].split(")")
# method_part = sections[0].split(";")
started = False
method_part = list()
name = list()
for c in sections[0]:
if c == "L" and not started:
started = True
name.append(c)
elif c == ";" and started:
started = False
method_part.append("".join(name))
name = list()
elif started:
name.append(c)
else:
method_part.append(c)
field_part = sections[1]
for i, method_name in enumerate(method_part):
if method_name != "" and method_name[0] == "L":
method_part[i] = "L" + rename_class(method_name[1:]) + ";"
if ";" in field_part:
field_part = "L" + rename_class(field_part[1:-1]) + ";"
result = ""
if is_method:
result += "(" + "".join(method_part) + ")"
return result + field_part
def remap_file(file: TextIO) -> str:
output = ""
# fifo queue for inner classes
current_class: list[str] = list()
indent = 0
for line in file:
current_line = line.strip().split(" ")
# go back to outer class after finishing inner class
if indent >= 1 and current_line[0] != "ARG" and indent != len(line) - len(line.lstrip("\t")):
indent = len(line) - len(line.lstrip("\t"))
while len(current_class) > indent:
current_class.pop()
match (current_line[0]):
case "CLASS":
indent += 1
current_class.append(current_line[1])
# already mapped
if len(current_line) == 2:
output += line
continue
parts = line.split(" ")
parts[1] = classes.get(parts[1])
output += " ".join(parts)
case "METHOD" | "FIELD":
if current_line[1] == "<init>":
parts = line.split(" ")
parts[2] = remap_signature(parts[2])
output += " ".join(parts)
continue
if len(current_line) == 3:
output += line
continue
element = find_element(
current_line[3],
current_line[1],
methods_by_class[current_class[indent - 1]] if current_line[0] == "METHOD" else
fields_by_class[current_class[indent - 1]]
)
parts = line.split(" ")
parts[1] = element.intermediary_name
parts[3] = remap_signature(element.signature)
output += " ".join(parts) + "\n"
# args and comments
case _:
output += line
return output
classes: dict[str, str] = dict()
methods: set[Element] = set()
fields: set[Element] = set()
with open("intermediary.tiny") as intermediary:
for line in intermediary.readlines():
parts = line.strip().split("\t")
match (parts[0]):
case "CLASS":
classes[parts[1]] = parts[2]
case "METHOD":
methods.add(Element(parts))
case "FIELD":
fields.add(Element(parts))
methods_by_class: dict[str, list[Element]] = {clazz: [] for clazz in classes}
fields_by_class: dict[str, list[Element]] = {clazz: [] for clazz in classes}
for method in methods:
methods_by_class[method.containing_class].append(method)
for field in fields:
fields_by_class[field.containing_class].append(field)
def main():
start = time.perf_counter()
for subdir, dirs, files in os.walk("mappings"):
for file in files:
# if "net\\minecraft\\advancement" not in subdir:
# continue
with open(subdir + "\\" + file, "r") as input:
dir = f"remapped{subdir.replace("mappings", "")}\\"
try:
os.makedirs(dir)
except FileExistsError:
pass
with open(dir + file, "w") as output:
try:
output.write(remap_file(input))
except AssertionError:
print(file)
exit()
end = time.perf_counter()
print(end - start)
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment