Compare commits
2 commits
8ce3afa7d6
...
e7bde3bab1
Author | SHA1 | Date | |
---|---|---|---|
TheKodeToad | e7bde3bab1 | ||
moehreag | 087234d3f9 |
9
.editorconfig
Normal file
9
.editorconfig
Normal file
|
@ -0,0 +1,9 @@
|
|||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = true
|
||||
indent_style = tab
|
|
@ -1,18 +1,19 @@
|
|||
package org.ecorous.esnesnon.nonsense_remapper;
|
||||
|
||||
import java.io.IOError;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.Mapper;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.ParameterClassRemapper;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.MappingData;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.Member;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.Parchment;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.parser.ProguardParser;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.provider.MojmapProvider;
|
||||
|
@ -20,24 +21,23 @@ import org.ecorous.esnesnon.nonsense_remapper.provider.ParchmentProvider;
|
|||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.ClassVisitor;
|
||||
import org.objectweb.asm.ClassWriter;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.objectweb.asm.commons.ClassRemapper;
|
||||
|
||||
public class NonsenseRemapper {
|
||||
|
||||
public static void run(String minecraftVersion, Path inputJar, Path outputJar, boolean skipMetaInf, boolean renameParameters) throws IOException, InterruptedException {
|
||||
MappingData data = ProguardParser.read(MojmapProvider.get(minecraftVersion).orElseThrow()).reverse();
|
||||
Mapper mapper = new Mapper(data);
|
||||
|
||||
MappingData data = ProguardParser.read(MojmapProvider.get(minecraftVersion, outputJar.resolveSibling("client-" + minecraftVersion + ".txt")).orElseThrow()).reverse();
|
||||
|
||||
Parchment paramMappings = null;
|
||||
if (renameParameters) {
|
||||
paramMappings = ParchmentProvider.getParchment(minecraftVersion, outputJar.getParent());
|
||||
}
|
||||
|
||||
remap(mapper, inputJar, outputJar, skipMetaInf, paramMappings);
|
||||
remap(data, inputJar, outputJar, skipMetaInf, paramMappings);
|
||||
}
|
||||
|
||||
public static void remap(Mapper mapper, Path inputJar, Path outputJar, boolean skipMetaInf, Parchment paramMappings) throws IOException, InterruptedException {
|
||||
public static void remap(MappingData data, Path inputJar, Path outputJar, boolean skipMetaInf, Parchment paramMappings) throws IOException, InterruptedException {
|
||||
Files.deleteIfExists(outputJar);
|
||||
|
||||
System.out.println("Remapping...");
|
||||
|
@ -49,12 +49,35 @@ public class NonsenseRemapper {
|
|||
FileSystem outFs = FileSystems.newFileSystem(outputJar, Map.of("create", "true"))) {
|
||||
List<Callable<Void>> tasks = new ArrayList<>();
|
||||
|
||||
Map<String, List<String>> lazyParents = new ConcurrentHashMap<>();
|
||||
Mapper mapper = new Mapper(data, className -> lazyParents.computeIfAbsent(className, ignored -> {
|
||||
try {
|
||||
Path path = inFs.getPath("/" + className + ".class");
|
||||
if (!Files.isRegularFile(path))
|
||||
return List.of();
|
||||
|
||||
byte[] bytes = Files.readAllBytes(path);
|
||||
ClassReader reader = new ClassReader(bytes);
|
||||
List<String> superTypes = new ArrayList<>();
|
||||
reader.accept(new ClassVisitor(Opcodes.ASM9) {
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
superTypes.add(superName);
|
||||
superTypes.addAll(Arrays.asList(interfaces));
|
||||
}
|
||||
}, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
|
||||
return superTypes;
|
||||
} catch (IOException error) {
|
||||
throw new Error(error); // not our problem :^) for now
|
||||
}
|
||||
}));
|
||||
|
||||
Files.walkFileTree(inFs.getPath("/"), new SimpleFileVisitor<>() {
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path path, BasicFileAttributes basicFileAttributes) {
|
||||
if (skipMetaInf && path.startsWith("/META-INF")) {
|
||||
if (skipMetaInf && path.startsWith("/META-INF"))
|
||||
return FileVisitResult.SKIP_SUBTREE;
|
||||
}
|
||||
|
||||
tasks.add(() -> {
|
||||
try {
|
||||
|
|
|
@ -4,26 +4,60 @@ import org.ecorous.esnesnon.nonsense_remapper.api.data.MappingData;
|
|||
import org.ecorous.esnesnon.nonsense_remapper.api.data.Member;
|
||||
import org.objectweb.asm.commons.Remapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class Mapper extends Remapper {
|
||||
|
||||
private final MappingData data;
|
||||
private final MappingData data;
|
||||
private final Function<String, List<String>> parentProvider;
|
||||
|
||||
public Mapper(MappingData data) {
|
||||
this.data = data;
|
||||
}
|
||||
public Mapper(MappingData data, Function<String, List<String>> parentProvider) {
|
||||
this.data = data;
|
||||
this.parentProvider = parentProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String map(String internalName) {
|
||||
return data.classes().getOrDefault(internalName, internalName);
|
||||
}
|
||||
@Override
|
||||
public String map(String internalName) {
|
||||
return data.classes().getOrDefault(internalName, internalName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String descriptor) {
|
||||
return data.methods().getOrDefault(new Member(owner, name, descriptor), name);
|
||||
}
|
||||
@Override
|
||||
public String mapMethodName(String owner, String name, String descriptor) {
|
||||
String result = map(0, data.methods(), owner, name, descriptor);
|
||||
if (result != null)
|
||||
return result;
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String descriptor) {
|
||||
return data.fields().getOrDefault(new Member(owner, name, descriptor), name);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String mapFieldName(String owner, String name, String descriptor) {
|
||||
String result = map(0, data.fields(), owner, name, descriptor);
|
||||
if (result != null)
|
||||
return result;
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
private String map(int depth, Map<Member, String> map, String owner, String name, String descriptor) {
|
||||
if (owner.startsWith("["))
|
||||
return null;
|
||||
|
||||
String result = map.get(new Member(owner, name, descriptor));
|
||||
if (result != null)
|
||||
return result;
|
||||
|
||||
if (depth >= 64)
|
||||
return null;
|
||||
|
||||
for (String parent : parentProvider.apply(owner)) {
|
||||
result = map(depth + 1, map, parent, name, descriptor);
|
||||
if (result != null)
|
||||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,97 +1,97 @@
|
|||
package org.ecorous.esnesnon.nonsense_remapper.parser;
|
||||
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.Member;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.MappingData;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.api.data.Member;
|
||||
|
||||
public class ProguardParser {
|
||||
|
||||
public static MappingData read(String mappings) {
|
||||
String[] lines = mappings.split("\n");
|
||||
public static MappingData read(String mappings) {
|
||||
String[] lines = mappings.split("\n");
|
||||
|
||||
MappingData data = new MappingData();
|
||||
String currentClass = null;
|
||||
for (String line : lines) {
|
||||
if (line.contains("#")) {
|
||||
line = line.substring(0, line.indexOf('#'));
|
||||
}
|
||||
MappingData data = new MappingData();
|
||||
String currentClass = null;
|
||||
for (String line : lines) {
|
||||
if (line.contains("#")) {
|
||||
line = line.substring(0, line.indexOf('#'));
|
||||
}
|
||||
|
||||
line = line.trim();
|
||||
line = line.trim();
|
||||
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int arrowIndex = line.indexOf("->");
|
||||
if (arrowIndex == -1) {
|
||||
throw new IllegalStateException("Missing arrow in mapping");
|
||||
}
|
||||
int arrowIndex = line.indexOf("->");
|
||||
if (arrowIndex == -1) {
|
||||
throw new IllegalStateException("Missing arrow in mapping");
|
||||
}
|
||||
|
||||
String obf = line.substring(0, arrowIndex).trim();
|
||||
String deobf = line.substring(arrowIndex + 2).trim();
|
||||
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) {
|
||||
throw new IllegalStateException("Member mapping specified before a class");
|
||||
}
|
||||
if (line.endsWith(":")) {
|
||||
deobf = deobf.substring(0, deobf.length() - 1);
|
||||
currentClass = obf.replace('.', '/');
|
||||
data.classes().put(currentClass, deobf.replace('.', '/'));
|
||||
} else {
|
||||
if (currentClass == null) {
|
||||
throw new IllegalStateException("Member mapping specified before a class");
|
||||
}
|
||||
|
||||
int spaceIndex = obf.indexOf(' ');
|
||||
if (spaceIndex == -1) {
|
||||
throw new IllegalStateException("Missing member signature");
|
||||
}
|
||||
int spaceIndex = obf.indexOf(' ');
|
||||
if (spaceIndex == -1) {
|
||||
throw new IllegalStateException("Missing member signature");
|
||||
}
|
||||
|
||||
String type = obf.substring(0, spaceIndex);
|
||||
String signature = obf.substring(spaceIndex + 1);
|
||||
String type = obf.substring(0, spaceIndex);
|
||||
String signature = obf.substring(spaceIndex + 1);
|
||||
|
||||
int colonIndex = type.lastIndexOf(':');
|
||||
if (colonIndex != -1)
|
||||
type = type.substring(colonIndex + 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));
|
||||
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;
|
||||
}
|
||||
data.methods().put(new Member(currentClass, name, descriptor.toString()), deobf);
|
||||
} else
|
||||
data.fields().put(new Member(currentClass, signature, convertType(type)), deobf);
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
private static String convertType(String type) {
|
||||
int dimensions = 0;
|
||||
while (type.endsWith("[]")) {
|
||||
type = type.substring(0, type.length() - 2);
|
||||
++dimensions;
|
||||
}
|
||||
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('.', '/') + ';';
|
||||
};
|
||||
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;
|
||||
}
|
||||
return "[".repeat(dimensions) + result;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,24 @@ import com.google.gson.*;
|
|||
import org.ecorous.esnesnon.nonsense_remapper.Constants;
|
||||
import org.ecorous.esnesnon.nonsense_remapper.HttpHelper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
|
||||
public class MojmapProvider {
|
||||
|
||||
public static Optional<String> get(String gameVersion) {
|
||||
return HttpHelper.getJson(Constants.VERSION_MANIFEST).map(manifest -> {
|
||||
public static Optional<String> get(String gameVersion, Path cacheFile) {
|
||||
if (Files.exists(cacheFile)){
|
||||
try {
|
||||
return Optional.of(Files.readString(cacheFile, StandardCharsets.UTF_8));
|
||||
} catch (IOException e) {
|
||||
// TODO
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return HttpHelper.getJson(Constants.VERSION_MANIFEST).flatMap(manifest -> {
|
||||
String versionName;
|
||||
if (gameVersion.startsWith("latest-")) {
|
||||
versionName = manifest.get("latest").getAsJsonObject().get(gameVersion.split("-")[1]).getAsString();
|
||||
|
@ -27,10 +39,18 @@ public class MojmapProvider {
|
|||
String mappingsUrl = versionManifest
|
||||
.get("downloads").getAsJsonObject().get("client_mappings").getAsJsonObject().get("url").getAsString();
|
||||
|
||||
return HttpHelper.getString(mappingsUrl).orElseThrow();
|
||||
return HttpHelper.getString(mappingsUrl).map(s -> {
|
||||
try {
|
||||
Files.writeString(cacheFile, s);
|
||||
} catch (IOException e) {
|
||||
// TODO
|
||||
e.printStackTrace();
|
||||
}
|
||||
return s;
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return Optional.empty();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue