Get mapping reversal working
This commit is contained in:
parent
29abf83418
commit
361b9d62f3
|
@ -14,7 +14,13 @@ public class MojMapPatcher {
|
||||||
}
|
}
|
||||||
MojmapProvider.get(version).map(ProguardParser::read).ifPresent(s -> {
|
MojmapProvider.get(version).map(ProguardParser::read).ifPresent(s -> {
|
||||||
//s.getClassFields().keySet().forEach(System.out::println);
|
//s.getClassFields().keySet().forEach(System.out::println);
|
||||||
s.classFields().get("net.minecraft.client.Minecraft").forEach((s1, s2) -> System.out.println(s1 + " -> " + s2));
|
String mcObf = s.classes().get("net/minecraft/client/Minecraft");
|
||||||
|
s = s.reverse();
|
||||||
|
s.fields()
|
||||||
|
.entrySet()
|
||||||
|
.stream()
|
||||||
|
.filter(entry -> entry.getKey().owner().equals(mcObf))
|
||||||
|
.forEach(entry -> System.out.println(entry.getKey() + " -> " + entry.getValue()));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
package io.github.moehreag.mojmap_patcher.api;
|
package io.github.moehreag.mojmap_patcher.api;
|
||||||
|
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.MappingData;
|
import io.github.moehreag.mojmap_patcher.api.data.MappingData;
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.Field;
|
import io.github.moehreag.mojmap_patcher.api.data.Member;
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.Method;
|
|
||||||
import org.objectweb.asm.commons.Remapper;
|
import org.objectweb.asm.commons.Remapper;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -17,54 +16,18 @@ public class Mapper extends Remapper {
|
||||||
throw new UnsupportedOperationException("TODO");
|
throw new UnsupportedOperationException("TODO");
|
||||||
}
|
}
|
||||||
|
|
||||||
public String mapClass(String name) {
|
|
||||||
return data.classes().getOrDefault(name, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Method> mapMethodInternal(String owner, String name, String descriptor) {
|
|
||||||
for (Map.Entry<Method, Method> entry : data.classMethods().getOrDefault(owner, Collections.emptyMap()).entrySet()) {
|
|
||||||
Method from = entry.getKey();
|
|
||||||
Method to = entry.getValue();
|
|
||||||
|
|
||||||
if (from.name().equals(name) && from.descriptor().equals(descriptor)) {
|
|
||||||
return Optional.of(to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Method mapMethod(String owner, String name, String descriptor) {
|
|
||||||
return mapMethodInternal(owner, name, descriptor).orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Optional<Field> mapFieldInternal(String owner, String name, String descriptor) {
|
|
||||||
for (Map.Entry<Field, Field> entry : data.classFields().getOrDefault(owner, Collections.emptyMap()).entrySet()) {
|
|
||||||
Field from = entry.getKey();
|
|
||||||
Field to = entry.getValue();
|
|
||||||
|
|
||||||
if (from.name().equals(name) && from.descriptor().equals(descriptor)) {
|
|
||||||
return Optional.of(to);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return Optional.empty();
|
|
||||||
}
|
|
||||||
|
|
||||||
public Field mapField(String owner, String name, String descriptor) {
|
|
||||||
return mapFieldInternal(owner, name, descriptor).orElse(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String map(String internalName) {
|
public String map(String internalName) {
|
||||||
return mapClass(internalName);
|
return data.classes().get(internalName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String mapMethodName(String owner, String name, String descriptor) {
|
public String mapMethodName(String owner, String name, String descriptor) {
|
||||||
return mapMethodInternal(owner, name, descriptor).map(Method::name).orElse(name);
|
return data.methods().get(new Member(owner, name, descriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String mapFieldName(String owner, String name, String descriptor) {
|
public String mapFieldName(String owner, String name, String descriptor) {
|
||||||
return mapFieldInternal(owner, name, descriptor).map(Field::name).orElse(name);
|
return data.fields().get(new Member(owner, name, descriptor));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
package io.github.moehreag.mojmap_patcher.api.data;
|
|
||||||
|
|
||||||
public record Field(String name, String descriptor) {
|
|
||||||
}
|
|
|
@ -1,17 +1,66 @@
|
||||||
package io.github.moehreag.mojmap_patcher.api.data;
|
package io.github.moehreag.mojmap_patcher.api.data;
|
||||||
|
|
||||||
|
import org.objectweb.asm.Type;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
public record MappingData(
|
public record MappingData(Map<String, String> classes, Map<Member, String> methods, Map<Member, String> fields) {
|
||||||
// IntelliJank, stop putting 8 spaces >:(
|
|
||||||
Map<String, String> classes,
|
|
||||||
Map<String, Map<Method, Method>> classMethods,
|
|
||||||
Map<String, Map<Field, Field>> classFields
|
|
||||||
) {
|
|
||||||
|
|
||||||
public MappingData() {
|
public MappingData() {
|
||||||
this(new HashMap<>(), new HashMap<>(), new HashMap<>());
|
this(new HashMap<>(), new HashMap<>(), new HashMap<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public MappingData reverse() {
|
||||||
|
Map<String, String> classesReversed = new HashMap<>();
|
||||||
|
Map<Member, String> methodsReversed = new HashMap<>();
|
||||||
|
Map<Member, String> fieldsReversed = new HashMap<>();
|
||||||
|
|
||||||
|
for (Map.Entry<String, String> clazz : classes.entrySet())
|
||||||
|
classesReversed.put(clazz.getValue(), clazz.getValue());
|
||||||
|
|
||||||
|
for (Map.Entry<Member, String> method : methods.entrySet()) {
|
||||||
|
methodsReversed.put(
|
||||||
|
new Member(
|
||||||
|
classes.getOrDefault(method.getKey().owner(), method.getKey().owner()),
|
||||||
|
method.getValue(),
|
||||||
|
remapType(Type.getType(method.getKey().descriptor())).getDescriptor()
|
||||||
|
),
|
||||||
|
method.getKey().name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Member, String> field : fields.entrySet()) {
|
||||||
|
fieldsReversed.put(
|
||||||
|
new Member(
|
||||||
|
classes.getOrDefault(field.getKey().owner(), field.getKey().owner()),
|
||||||
|
field.getValue(),
|
||||||
|
remapType(Type.getType(field.getKey().descriptor())).getDescriptor()
|
||||||
|
),
|
||||||
|
field.getKey().name()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new MappingData(classesReversed, methodsReversed, fieldsReversed);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Type remapType(Type type) {
|
||||||
|
switch (type.getSort()) {
|
||||||
|
case Type.OBJECT:
|
||||||
|
return Type.getObjectType(classes.getOrDefault(type.getInternalName(), type.getInternalName()));
|
||||||
|
case Type.ARRAY:
|
||||||
|
return Type.getObjectType(
|
||||||
|
"[".repeat(type.getDimensions()) + remapType(type.getElementType()).getDescriptor()
|
||||||
|
);
|
||||||
|
case Type.METHOD:
|
||||||
|
return Type.getMethodType(
|
||||||
|
remapType(type.getReturnType()),
|
||||||
|
Arrays.stream(type.getArgumentTypes()).map(this::remapType).toArray(Type[]::new)
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package io.github.moehreag.mojmap_patcher.api.data;
|
||||||
|
|
||||||
|
public record Member(String owner, String name, String descriptor) {
|
||||||
|
}
|
|
@ -1,4 +0,0 @@
|
||||||
package io.github.moehreag.mojmap_patcher.api.data;
|
|
||||||
|
|
||||||
public record Method(int startLine, int endLine, String returnType, String name, String descriptor) {
|
|
||||||
}
|
|
|
@ -1,11 +1,14 @@
|
||||||
package io.github.moehreag.mojmap_patcher.parser;
|
package io.github.moehreag.mojmap_patcher.parser;
|
||||||
|
|
||||||
import io.github.moehreag.mojmap_patcher.Constants;
|
import io.github.moehreag.mojmap_patcher.Constants;
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.Field;
|
import io.github.moehreag.mojmap_patcher.api.data.Member;
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.MappingData;
|
import io.github.moehreag.mojmap_patcher.api.data.MappingData;
|
||||||
import io.github.moehreag.mojmap_patcher.api.data.Method;
|
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.StreamSupport;
|
||||||
|
|
||||||
public class ProguardParser {
|
public class ProguardParser {
|
||||||
|
|
||||||
|
@ -15,32 +18,87 @@ public class ProguardParser {
|
||||||
MappingData data = new MappingData();
|
MappingData data = new MappingData();
|
||||||
String currentClass = null;
|
String currentClass = null;
|
||||||
for (String line : lines) {
|
for (String line : lines) {
|
||||||
if (line.startsWith("#")) { // Filter out comments
|
if (line.contains("#")) {
|
||||||
|
line = line.substring(0, line.indexOf('#'));
|
||||||
|
}
|
||||||
|
|
||||||
|
line = line.trim();
|
||||||
|
|
||||||
|
if (line.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String[] mapping = line.split("->");
|
int arrowIndex = line.indexOf("->");
|
||||||
String deobf = mapping[0].trim();
|
if (arrowIndex == -1) {
|
||||||
String obf = mapping[1].trim();
|
throw new IllegalStateException("Missing arrow in mapping");
|
||||||
if (line.startsWith(" ")) { // It's a field/method mapping
|
}
|
||||||
|
|
||||||
|
String obf = line.substring(0, arrowIndex).trim();
|
||||||
|
String deobf = line.substring(arrowIndex + 2).trim();
|
||||||
|
|
||||||
|
if (line.endsWith(":")) {
|
||||||
|
deobf = deobf.substring(0, deobf.length() - 1);
|
||||||
|
currentClass = obf.replace('.', '/');
|
||||||
|
data.classes().put(currentClass, deobf.replace('.', '/'));
|
||||||
|
} else {
|
||||||
if (currentClass == null) {
|
if (currentClass == null) {
|
||||||
throw new IllegalStateException("Field/Method mapping outside a class");
|
throw new IllegalStateException("Member mapping specified before a class");
|
||||||
}
|
}
|
||||||
if (Constants.METHOD_PATTERN.matcher(deobf).matches()) {
|
|
||||||
String[] method = deobf.split(":");
|
int spaceIndex = obf.indexOf(' ');
|
||||||
String[] descriptor = method[2].split(" ");
|
if (spaceIndex == -1) {
|
||||||
int bracket = descriptor[1].indexOf("(");
|
throw new IllegalStateException("Missing member signature");
|
||||||
data.classMethods().computeIfAbsent(currentClass, s -> new HashMap<>()).put(new Method(Integer.parseInt(method[0]), Integer.parseInt(method[1]), obf, descriptor[1].substring(0, bracket), descriptor[1].substring(bracket + 1)),
|
|
||||||
new Method(Integer.parseInt(method[0]), Integer.parseInt(method[1]), descriptor[0], descriptor[1].substring(0, bracket), descriptor[1].substring(bracket + 1)));
|
|
||||||
} else {
|
|
||||||
String[] field = deobf.split(" ");
|
|
||||||
data.classFields().computeIfAbsent(currentClass, s -> new HashMap<>()).put(new Field(field[1], obf), new Field(field[1], field[0]));
|
|
||||||
}
|
}
|
||||||
} else { // It's a class mapping
|
|
||||||
currentClass = deobf;
|
String type = obf.substring(0, spaceIndex);
|
||||||
data.classes().put(obf, deobf);
|
String signature = obf.substring(spaceIndex + 1);
|
||||||
|
|
||||||
|
int colonIndex = type.lastIndexOf(':');
|
||||||
|
if (colonIndex != -1)
|
||||||
|
type = type.substring(colonIndex + 1);
|
||||||
|
|
||||||
|
if (signature.contains("(") && signature.endsWith(")")) {
|
||||||
|
// method
|
||||||
|
String name = signature.substring(0, signature.indexOf('('));
|
||||||
|
String args = signature.substring(signature.indexOf('(') + 1, signature.length() - 1);
|
||||||
|
StringBuilder descriptor = new StringBuilder();
|
||||||
|
descriptor.append('(');
|
||||||
|
if (!args.isEmpty()) {
|
||||||
|
for (String arg : args.split(",")) {
|
||||||
|
descriptor.append(convertType(arg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
descriptor.append(')');
|
||||||
|
descriptor.append(convertType(type));
|
||||||
|
|
||||||
|
data.methods().put(new Member(currentClass, name, descriptor.toString()), deobf);
|
||||||
|
} else
|
||||||
|
data.fields().put(new Member(currentClass, signature, convertType(type)), deobf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String convertType(String type) {
|
||||||
|
int dimensions = 0;
|
||||||
|
while (type.endsWith("[]")) {
|
||||||
|
type = type.substring(0, type.length() - 2);
|
||||||
|
++dimensions;
|
||||||
|
}
|
||||||
|
|
||||||
|
String result = switch (type) {
|
||||||
|
case "void" -> "V";
|
||||||
|
case "boolean" -> "Z";
|
||||||
|
case "byte" -> "B";
|
||||||
|
case "short" -> "S";
|
||||||
|
case "int" -> "I";
|
||||||
|
case "long" -> "J";
|
||||||
|
case "float" -> "F";
|
||||||
|
case "double" -> "D";
|
||||||
|
case "char" -> "C";
|
||||||
|
default -> 'L' + type.replace('.', '/') + ';';
|
||||||
|
};
|
||||||
|
|
||||||
|
return "[".repeat(dimensions) + result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue