diff options
author | shedaniel <daniel@shedaniel.me> | 2021-08-30 14:10:32 +0800 |
---|---|---|
committer | shedaniel <daniel@shedaniel.me> | 2021-08-30 14:10:32 +0800 |
commit | 9366d42baa22b53b16ad8b21b843576ec8c964c7 (patch) | |
tree | a83f8a0b0b4f1b78fc5d293aeccac27dfc9f4c19 /src/main/java/net/fabricmc/loom/util/srg | |
parent | d819b1cc47b26572ab6af85258e54d5737bead69 (diff) | |
download | architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.tar.gz architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.tar.bz2 architectury-loom-9366d42baa22b53b16ad8b21b843576ec8c964c7.zip |
Start work on porting 0.7.4 over
Signed-off-by: shedaniel <daniel@shedaniel.me>
Diffstat (limited to 'src/main/java/net/fabricmc/loom/util/srg')
4 files changed, 333 insertions, 48 deletions
diff --git a/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java b/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java index 1949c55d..edc7e263 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java +++ b/src/main/java/net/fabricmc/loom/util/srg/InnerClassRemapper.java @@ -27,11 +27,14 @@ package net.fabricmc.loom.util.srg; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashSet; import java.util.Iterator; -import java.util.Map; +import java.util.Set; import java.util.function.BiConsumer; import java.util.stream.Collectors; +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; import dev.architectury.tinyremapper.IMappingProvider; import net.fabricmc.loom.util.FileSystemUtil; @@ -40,22 +43,16 @@ import net.fabricmc.mapping.tree.ClassDef; import net.fabricmc.mapping.tree.TinyTree; public class InnerClassRemapper { - public static IMappingProvider of(Path fromJar, TinyTree mappingsWithSrg, String from, String to) throws IOException { + public static IMappingProvider of(Set<String> fromClassNames, TinyTree mappingsWithSrg, String from, String to) throws IOException { return sink -> { - remapInnerClass(fromJar, mappingsWithSrg, from, to, sink::acceptClass); + remapInnerClass(fromClassNames, mappingsWithSrg, from, to, sink::acceptClass); }; } - private static void remapInnerClass(Path fromJar, TinyTree mappingsWithSrg, String from, String to, BiConsumer<String, String> action) { - try (FileSystemDelegate system = FileSystemUtil.getJarFileSystem(fromJar, false)) { - Map<String, String> availableClasses = mappingsWithSrg.getClasses().stream() - .collect(Collectors.groupingBy(classDef -> classDef.getName(from), - Collectors.<ClassDef, String>reducing( - null, - classDef -> classDef.getName(to), - (first, last) -> last - )) - ); + public static Set<String> readClassNames(Path jar) { + Set<String> set = new HashSet<>(); + + try (FileSystemDelegate system = FileSystemUtil.getJarFileSystem(jar, false)) { Iterator<Path> iterator = Files.walk(system.get().getPath("/")).iterator(); while (iterator.hasNext()) { @@ -65,21 +62,42 @@ public class InnerClassRemapper { if (!Files.isDirectory(path) && name.contains("$") && name.endsWith(".class")) { String className = name.substring(0, name.length() - 6); + set.add(className); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } - if (!availableClasses.containsKey(className)) { - String parentName = className.substring(0, className.indexOf('$')); - String childName = className.substring(className.indexOf('$') + 1); - String remappedParentName = availableClasses.getOrDefault(parentName, parentName); - String remappedName = remappedParentName + "$" + childName; + return set; + } + + private static void remapInnerClass(Set<String> classNames, TinyTree mappingsWithSrg, String from, String to, BiConsumer<String, String> action) { + BiMap<String, String> availableClasses = HashBiMap.create(mappingsWithSrg.getClasses().stream() + .collect(Collectors.groupingBy(classDef -> classDef.getName(from), + Collectors.<ClassDef, String>reducing( + null, + classDef -> classDef.getName(to), + (first, last) -> last + )) + )); + + for (String className : classNames) { + if (!availableClasses.containsKey(className)) { + String parentName = className.substring(0, className.indexOf('$')); + String childName = className.substring(className.indexOf('$') + 1); + String remappedParentName = availableClasses.getOrDefault(parentName, parentName); + String remappedName = remappedParentName + "$" + childName; - if (!className.equals(remappedName)) { - action.accept(className, remappedName); - } + if (!className.equals(remappedName)) { + if (availableClasses.containsValue(remappedName)) { + // https://github.com/MinecraftForge/MinecraftForge/blob/b027a92dd287d6810a9fdae4d4b1e1432d7dc9cc/patches/minecraft/net/minecraft/Util.java.patch#L8 + action.accept(className, remappedName + "_UNBREAK"); + } else { + action.accept(className, remappedName); } } } - } catch (IOException e) { - throw new RuntimeException(e); } } } diff --git a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java index 8d5e7738..327825d3 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java +++ b/src/main/java/net/fabricmc/loom/util/srg/SpecialSourceExecutor.java @@ -39,6 +39,7 @@ import org.apache.commons.io.output.NullOutputStream; import org.gradle.api.Project; import org.gradle.api.file.FileCollection; import org.gradle.api.logging.LogLevel; +import org.gradle.api.logging.configuration.ShowStacktrace; import org.zeroturnaround.zip.ZipUtil; import net.fabricmc.loom.LoomGradleExtension; @@ -87,8 +88,10 @@ public class SpecialSourceExecutor { spec.setMain("net.md_5.specialsource.SpecialSource"); // if running with INFO or DEBUG logging - if (project.getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { + if (project.getGradle().getStartParameter().getShowStacktrace() != ShowStacktrace.INTERNAL_EXCEPTIONS + || project.getGradle().getStartParameter().getLogLevel().compareTo(LogLevel.LIFECYCLE) < 0) { spec.setStandardOutput(System.out); + spec.setErrorOutput(System.err); } else { spec.setStandardOutput(NullOutputStream.NULL_OUTPUT_STREAM); spec.setErrorOutput(NullOutputStream.NULL_OUTPUT_STREAM); diff --git a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java b/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java index 39a2b57c..e2cf730f 100644 --- a/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java +++ b/src/main/java/net/fabricmc/loom/util/srg/SrgMerger.java @@ -27,15 +27,20 @@ package net.fabricmc.loom.util.srg; import java.io.BufferedReader; import java.io.IOException; import java.io.StringReader; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.function.Consumer; import java.util.function.Supplier; +import com.google.common.base.MoreObjects; import dev.architectury.mappingslayers.api.mutable.MutableClassDef; +import dev.architectury.mappingslayers.api.mutable.MutableDescriptored; import dev.architectury.mappingslayers.api.mutable.MutableFieldDef; import dev.architectury.mappingslayers.api.mutable.MutableMethodDef; import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; @@ -56,6 +61,7 @@ import net.fabricmc.mapping.tree.FieldDef; import net.fabricmc.mapping.tree.MethodDef; import net.fabricmc.mapping.tree.TinyMappingFactory; import net.fabricmc.mapping.tree.TinyTree; +import net.fabricmc.mappingio.format.TsrgReader; import net.fabricmc.stitch.commands.tinyv2.TinyClass; import net.fabricmc.stitch.commands.tinyv2.TinyField; import net.fabricmc.stitch.commands.tinyv2.TinyFile; @@ -80,8 +86,9 @@ public final class SrgMerger { * @throws MappingException if the input tiny tree's default namespace is not 'official' * or if an element mentioned in the SRG file does not have tiny mappings */ - public static void mergeSrg(Path srg, Path tiny, Path out, boolean lenient) throws IOException, MappingException { - MappingSet arr = readSrg(srg); + public static void mergeSrg(Supplier<Path> mojmap, Path srg, Path tiny, Path out, boolean lenient) throws IOException, MappingException { + Map<String, List<MutableDescriptored>> addRegardlessSrgs = new HashMap<>(); + MappingSet arr = readSrg(srg, mojmap, addRegardlessSrgs); TinyTree foss; try (BufferedReader reader = Files.newBufferedReader(tiny)) { @@ -100,19 +107,19 @@ public final class SrgMerger { List<TinyClass> classes = new ArrayList<>(); for (TopLevelClassMapping klass : arr.getTopLevelClassMappings()) { - classToTiny(foss, namespaces, klass, classes::add, lenient); + classToTiny(addRegardlessSrgs, foss, namespaces, klass, classes::add, lenient); } TinyFile file = new TinyFile(header, classes); TinyV2Writer.write(file, out); } - private static MappingSet readSrg(Path srg) throws IOException { + private static MappingSet readSrg(Path srg, Supplier<Path> mojmap, Map<String, List<MutableDescriptored>> addRegardlessSrgs) throws IOException { try (BufferedReader reader = Files.newBufferedReader(srg)) { String content = IOUtils.toString(reader); if (content.startsWith("tsrg2")) { - return readTsrg2(content); + return readTsrg2(content, mojmap, addRegardlessSrgs); } else { try (TSrgReader srgReader = new TSrgReader(new StringReader(content))) { return srgReader.read(); @@ -121,31 +128,45 @@ public final class SrgMerger { } } - private static MappingSet readTsrg2(String content) { - MappingSet set = MappingSet.create(); - MutableTinyTree tree = MappingsUtils.deserializeFromTsrg2(content); - int obfIndex = tree.getMetadata().index("obf"); - int srgIndex = tree.getMetadata().index("srg"); + private static MappingSet readTsrg2(String content, Supplier<Path> mojmap, Map<String, List<MutableDescriptored>> addRegardlessSrgs) throws IOException { + MappingSet set; - for (MutableClassDef classDef : tree.getClassesMutable()) { - ClassMapping<?, ?> classMapping = set.getOrCreateClassMapping(classDef.getName(obfIndex)); - classMapping.setDeobfuscatedName(classDef.getName(srgIndex)); + try (Tsrg2Utils.MappingsIO2LorenzWriter lorenzWriter = new Tsrg2Utils.MappingsIO2LorenzWriter(0, false)) { + TsrgReader.read(new StringReader(content), lorenzWriter); + set = lorenzWriter.read(); + MutableTinyTree mojmapTree = readTsrg2ToTinyTree(mojmap.get()); - for (MutableFieldDef fieldDef : classDef.getFieldsMutable()) { - FieldMapping fieldMapping = classMapping.getOrCreateFieldMapping(fieldDef.getName(obfIndex)); - fieldMapping.setDeobfuscatedName(fieldDef.getName(srgIndex)); - } + for (MutableClassDef classDef : mojmapTree.getClassesMutable()) { + for (MutableMethodDef methodDef : classDef.getMethodsMutable()) { + String name = methodDef.getName(0); + + if (name.indexOf('<') != 0 && name.equals(methodDef.getName(1))) { + addRegardlessSrgs.computeIfAbsent(classDef.getName(0), $ -> new ArrayList<>()).add(methodDef); + } + } - for (MutableMethodDef methodDef : classDef.getMethodsMutable()) { - MethodMapping methodMapping = classMapping.getOrCreateMethodMapping(methodDef.getName(obfIndex), methodDef.getDescriptor(obfIndex)); - methodMapping.setDeobfuscatedName(methodDef.getName(srgIndex)); + for (MutableFieldDef fieldDef : classDef.getFieldsMutable()) { + if (fieldDef.getName(0).equals(fieldDef.getName(1))) { + addRegardlessSrgs.computeIfAbsent(classDef.getName(0), $ -> new ArrayList<>()).add(fieldDef); + } + } } } return set; } - private static void classToTiny(TinyTree foss, List<String> namespaces, ClassMapping<?, ?> klass, Consumer<TinyClass> classConsumer, boolean lenient) { + private static MutableTinyTree readTsrg2ToTinyTree(Path path) throws IOException { + MutableTinyTree tree; + + try (BufferedReader reader = Files.newBufferedReader(path, StandardCharsets.UTF_8)) { + tree = MappingsUtils.deserializeFromTsrg2(IOUtils.toString(reader)); + } + + return tree; + } + + private static void classToTiny(Map<String, List<MutableDescriptored>> addRegardlessSrgs, TinyTree foss, List<String> namespaces, ClassMapping<?, ?> klass, Consumer<TinyClass> classConsumer, boolean lenient) { String obf = klass.getFullObfuscatedName(); String srg = klass.getFullDeobfuscatedName(); ClassDef classDef = foss.getDefaultNamespaceClassMap().get(obf); @@ -170,9 +191,17 @@ public final class SrgMerger { MethodDef def = CollectionUtil.find( classDef.getMethods(), m -> m.getName("official").equals(method.getObfuscatedName()) && m.getDescriptor("official").equals(method.getObfuscatedDescriptor()) - ).orElse(nullOrThrow(lenient, () -> new MappingException("Missing method: " + method.getFullObfuscatedName() + " (srg: " + method.getFullDeobfuscatedName() + ")"))); + ).orElse(null); - if (def == null) continue; + if (def == null) { + if (tryMatchRegardlessSrgs(addRegardlessSrgs, namespaces, obf, methods, method)) continue; + + if (!lenient) { + throw new MappingException("Missing method: " + method.getFullObfuscatedName() + " (srg: " + method.getFullDeobfuscatedName() + ")"); + } + + continue; + } List<String> methodNames = CollectionUtil.map( namespaces, @@ -207,8 +236,34 @@ public final class SrgMerger { classConsumer.accept(tinyClass); for (InnerClassMapping innerKlass : klass.getInnerClassMappings()) { - classToTiny(foss, namespaces, innerKlass, classConsumer, lenient); + classToTiny(addRegardlessSrgs, foss, namespaces, innerKlass, classConsumer, lenient); + } + } + + private static boolean tryMatchRegardlessSrgs(Map<String, List<MutableDescriptored>> addRegardlessSrgs, List<String> namespaces, String obf, + List<TinyMethod> methods, MethodMapping method) { + List<MutableDescriptored> mutableDescriptoredList = addRegardlessSrgs.get(obf); + + if (!method.getDeobfuscatedName().equals(method.getObfuscatedName())) { + for (MutableDescriptored descriptored : MoreObjects.firstNonNull(mutableDescriptoredList, Collections.<MutableDescriptored>emptyList())) { + if (descriptored.isMethod() && descriptored.getName(0).equals(method.getObfuscatedName()) && descriptored.getDescriptor(0).equals(method.getObfuscatedDescriptor())) { + List<String> methodNames = CollectionUtil.map( + namespaces, + namespace -> "srg".equals(namespace) ? method.getDeobfuscatedName() : method.getObfuscatedName() + ); + + methods.add(new TinyMethod( + method.getObfuscatedDescriptor(), methodNames, + /* parameters */ Collections.emptyList(), + /* locals */ Collections.emptyList(), + /* comments */ Collections.emptyList() + )); + return true; + } + } } + + return false; } @Nullable diff --git a/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java b/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java new file mode 100644 index 00000000..e6ddf578 --- /dev/null +++ b/src/main/java/net/fabricmc/loom/util/srg/Tsrg2Utils.java @@ -0,0 +1,209 @@ +package net.fabricmc.loom.util.srg; + +import java.io.IOException; +import java.io.Reader; +import java.io.UncheckedIOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; + +import dev.architectury.mappingslayers.api.mutable.MutableClassDef; +import dev.architectury.mappingslayers.api.mutable.MutableFieldDef; +import dev.architectury.mappingslayers.api.mutable.MutableMethodDef; +import dev.architectury.mappingslayers.api.mutable.MutableParameterDef; +import dev.architectury.mappingslayers.api.mutable.MutableTinyMetadata; +import dev.architectury.mappingslayers.api.mutable.MutableTinyTree; +import dev.architectury.mappingslayers.api.utils.MappingsUtils; +import org.cadixdev.lorenz.MappingSet; +import org.cadixdev.lorenz.io.srg.tsrg.TSrgWriter; +import org.cadixdev.lorenz.model.ClassMapping; +import org.cadixdev.lorenz.model.MethodMapping; + +import net.fabricmc.mappingio.MappingVisitor; +import net.fabricmc.mappingio.MappingWriter; +import net.fabricmc.mappingio.adapter.ForwardingMappingVisitor; +import net.fabricmc.mappingio.format.TsrgReader; +import net.fabricmc.mappingio.tree.MappingTree; +import net.fabricmc.mappingio.tree.MemoryMappingTree; + +public class Tsrg2Utils { + public static void convert(Reader reader, Writer writer) throws IOException { + writeTsrg(visitor -> { + try { + TsrgReader.read(reader, visitor); + } catch (IOException e) { + throw new UncheckedIOException(e); + } + }, "srg", false, writer); + } + + public static void writeTsrg(Consumer<MappingVisitor> visitorConsumer, String dstNamespace, boolean applyParameterMappings, Writer writer) + throws IOException { + MappingSet set; + + try (MappingsIO2LorenzWriter lorenzWriter = new MappingsIO2LorenzWriter(dstNamespace, applyParameterMappings)) { + visitorConsumer.accept(lorenzWriter); + set = lorenzWriter.read(); + } + + try (TSrgWriter w = new TSrgWriter(writer)) { + w.write(set); + } + } + + public static void writeTsrg2(Consumer<MappingVisitor> visitorConsumer, Writer writer) + throws IOException { + MutableTinyTree tree; + + try (MappingsIO2MappingsUtils w = new MappingsIO2MappingsUtils()) { + visitorConsumer.accept(w); + tree = w.read(); + } + + writer.write(MappingsUtils.serializeToTsrg2(tree)); + } + + // TODO Move this elsewhere + public abstract static class MappingsIO2Others extends ForwardingMappingVisitor implements MappingWriter { + public MappingsIO2Others() { + super(new MemoryMappingTree()); + } + + public MappingTree tree() { + return (MappingTree) next; + } + + @Override + public void close() throws IOException { + MappingTree tree = tree(); + List<String> names = new ArrayList<>(); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + names.add(aClass.getSrcName()); + } + + for (String name : names) { + tree.removeClass(name); + } + } + } + + public static class MappingsIO2LorenzWriter extends MappingsIO2Others { + private final Object dstNamespaceUnresolved; + private int dstNamespace; + private boolean applyParameterMappings; + + public MappingsIO2LorenzWriter(int dstNamespace, boolean applyParameterMappings) { + this.dstNamespaceUnresolved = dstNamespace; + this.applyParameterMappings = applyParameterMappings; + } + + public MappingsIO2LorenzWriter(String dstNamespace, boolean applyParameterMappings) { + this.dstNamespaceUnresolved = dstNamespace; + this.applyParameterMappings = applyParameterMappings; + } + + @Override + public void visitNamespaces(String srcNamespace, List<String> dstNamespaces) throws IOException { + super.visitNamespaces(srcNamespace, dstNamespaces); + this.dstNamespace = dstNamespaceUnresolved instanceof Integer ? (Integer) dstNamespaceUnresolved : dstNamespaces.indexOf((String) dstNamespaceUnresolved); + } + + public MappingSet read() throws IOException { + return this.read(MappingSet.create()); + } + + public MappingSet read(final MappingSet mappings) throws IOException { + MappingTree tree = tree(); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + ClassMapping<?, ?> lClass = mappings.getOrCreateClassMapping(aClass.getSrcName()) + .setDeobfuscatedName(aClass.getDstName(dstNamespace)); + + for (MappingTree.FieldMapping aField : aClass.getFields()) { + String srcDesc = aField.getSrcDesc(); + + if (srcDesc == null || srcDesc.isEmpty()) { + lClass.getOrCreateFieldMapping(aField.getSrcName()) + .setDeobfuscatedName(aField.getDstName(dstNamespace)); + } else { + lClass.getOrCreateFieldMapping(aField.getSrcName(), srcDesc) + .setDeobfuscatedName(aField.getDstName(dstNamespace)); + } + } + + for (MappingTree.MethodMapping aMethod : aClass.getMethods()) { + MethodMapping lMethod = lClass.getOrCreateMethodMapping(aMethod.getSrcName(), aMethod.getSrcDesc()) + .setDeobfuscatedName(aMethod.getDstName(dstNamespace)); + + if (applyParameterMappings) { + for (MappingTree.MethodArgMapping aArg : aMethod.getArgs()) { + lMethod.getOrCreateParameterMapping(aArg.getLvIndex()) + .setDeobfuscatedName(aArg.getDstName(dstNamespace)); + } + } + } + } + + return mappings; + } + } + + public static class MappingsIO2MappingsUtils extends MappingsIO2Others { + public MutableTinyTree read() { + MappingTree tree = tree(); + int dstNamesSize = tree.getDstNamespaces().size(); + List<String> namespaces = new ArrayList<>(); + namespaces.add(tree.getSrcNamespace()); + namespaces.addAll(tree.getDstNamespaces()); + Map<String, String> properties = new HashMap<>(); + + for (Map.Entry<String, String> entry : tree.getMetadata()) { + properties.put(entry.getKey(), entry.getValue()); + } + + MutableTinyTree out = MappingsUtils.create(MutableTinyMetadata.create(2, 0, namespaces, properties)); + + for (MappingTree.ClassMapping aClass : tree.getClasses()) { + MutableClassDef classDef = out.getOrCreateClass(aClass.getSrcName()); + classDef.setComment(aClass.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + classDef.setName(i + 1, aClass.getDstName(i)); + } + + for (MappingTree.MethodMapping aMethod : aClass.getMethods()) { + MutableMethodDef methodDef = classDef.getOrCreateMethod(aMethod.getSrcName(), aMethod.getSrcDesc()); + methodDef.setComment(aMethod.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + methodDef.setName(i + 1, aMethod.getDstName(i)); + } + + for (MappingTree.MethodArgMapping aMethodArg : aMethod.getArgs()) { + MutableParameterDef parameterDef = methodDef.getOrCreateParameter(aMethodArg.getLvIndex(), aMethodArg.getSrcName()); + parameterDef.setComment(aMethodArg.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + parameterDef.setName(i + 1, aMethodArg.getDstName(i)); + } + } + } + + for (MappingTree.FieldMapping aField : aClass.getFields()) { + MutableFieldDef fieldDef = classDef.getOrCreateField(aField.getSrcName(), aField.getSrcDesc()); + fieldDef.setComment(aField.getComment()); + + for (int i = 0; i < dstNamesSize; i++) { + fieldDef.setName(i + 1, aField.getDstName(i)); + } + } + } + + return out; + } + } +} |