From deaee2ad65113fded4403c680463afeda450f8b6 Mon Sep 17 00:00:00 2001 From: shedaniel Date: Thu, 4 Apr 2024 23:19:37 +0900 Subject: [PATCH] Workaround inner classes decompilation on Forge --- .../sources/ForgeSourcesRemapper.java | 27 ++++++++++--- .../task/GenerateForgePatchedSourcesTask.java | 2 +- .../loom/task/GenerateSourcesTask.java | 38 ++++++++++++++++++- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java index 9f276f36..a7dc502a 100644 --- a/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java +++ b/src/main/java/net/fabricmc/loom/configuration/sources/ForgeSourcesRemapper.java @@ -38,6 +38,7 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import dev.architectury.loom.util.MappingOption; @@ -45,6 +46,7 @@ import org.apache.commons.io.output.NullOutputStream; import org.cadixdev.lorenz.MappingSet; import org.cadixdev.mercury.Mercury; import org.cadixdev.mercury.remapper.MercuryRemapper; +import org.jetbrains.annotations.Nullable; import org.gradle.api.Project; import net.fabricmc.loom.LoomGradleExtension; @@ -84,17 +86,27 @@ public class ForgeSourcesRemapper { if (!Files.exists(sourcesJar)) { try (var serviceManager = new ScopedSharedServiceManager()) { - addForgeSources(project, serviceManager, sourcesJar); + addForgeSources(project, serviceManager, minecraftJar, sourcesJar); } } } - public static void addForgeSources(Project project, SharedServiceManager serviceManager, Path sourcesJar) throws IOException { - try (FileSystemUtil.Delegate delegate = FileSystemUtil.getJarFileSystem(sourcesJar, true)) { + public static void addForgeSources(Project project, SharedServiceManager serviceManager, @Nullable Path inputJar, Path sourcesJar) throws IOException { + try (FileSystemUtil.Delegate inputFs = inputJar == null ? null : FileSystemUtil.getJarFileSystem(inputJar, true); + FileSystemUtil.Delegate outputFs = FileSystemUtil.getJarFileSystem(sourcesJar, true)) { ThreadingUtils.TaskCompleter taskCompleter = ThreadingUtils.taskCompleter(); - provideForgeSources(project, serviceManager, (path, bytes) -> { - Path fsPath = delegate.get().getPath(path); + provideForgeSources(project, serviceManager, path -> { + Path inputPath = inputFs == null ? null : inputFs.get().getPath(path.replace(".java", ".class")); + + if (inputPath != null && Files.notExists(inputPath)) { + project.getLogger().info("Discarding forge source file {} as it does not exist in the input jar", path); + return false; + } + + return !path.contains("$"); + }, (path, bytes) -> { + Path fsPath = outputFs.get().getPath(path); if (fsPath.getParent() != null) { try { @@ -105,6 +117,7 @@ public class ForgeSourcesRemapper { } taskCompleter.add(() -> { + project.getLogger().info("Added forge source file {}", path); Files.write(fsPath, bytes, StandardOpenOption.CREATE); }); }); @@ -113,17 +126,19 @@ public class ForgeSourcesRemapper { } } - public static void provideForgeSources(Project project, SharedServiceManager serviceManager, BiConsumer consumer) throws IOException { + public static void provideForgeSources(Project project, SharedServiceManager serviceManager, Predicate classFilter, BiConsumer consumer) throws IOException { LoomGradleExtension extension = LoomGradleExtension.get(project); String sourceDependency = extension.getForgeUserdevProvider().getConfig().sources(); List forgeInstallerSources = new ArrayList<>(); for (File file : DependencyDownloader.download(project, sourceDependency)) { forgeInstallerSources.add(file.toPath()); + project.getLogger().info("Found forge source jar: {}", file); } project.getLogger().lifecycle(":found {} forge source jars", forgeInstallerSources.size()); Map forgeSources = extractSources(forgeInstallerSources); + forgeSources.keySet().removeIf(classFilter.negate()); project.getLogger().lifecycle(":extracted {} forge source classes", forgeSources.size()); remapSources(project, serviceManager, forgeSources); forgeSources.forEach(consumer); diff --git a/src/main/java/net/fabricmc/loom/task/GenerateForgePatchedSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateForgePatchedSourcesTask.java index 8bec39fe..ed5cf8c6 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateForgePatchedSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateForgePatchedSourcesTask.java @@ -111,7 +111,7 @@ public abstract class GenerateForgePatchedSourcesTask extends AbstractLoomTask { // Step 3: remap remap(patched, serviceManager); // Step 4: add Forge's own sources - ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, getOutputJar().get().getAsFile().toPath()); + ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, null, getOutputJar().get().getAsFile().toPath()); } } diff --git a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java index 42be11ea..d61fea61 100644 --- a/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java +++ b/src/main/java/net/fabricmc/loom/task/GenerateSourcesTask.java @@ -42,6 +42,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; @@ -49,6 +50,7 @@ import java.util.Objects; import java.util.StringJoiner; import java.util.UUID; import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.inject.Inject; @@ -255,6 +257,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { try (var timer = new Timer("Decompile")) { outputLineNumbers = runDecompileJob(inputJar, workToDoJob.output(), existing); + removeForgeInnerClassSources(workToDoJob.output()); outputLineNumbers = filterForgeLineNumbers(outputLineNumbers); } @@ -316,6 +319,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { try (var timer = new Timer("Decompile")) { lineNumbers = runDecompileJob(inputJar, sourcesJar, null); + removeForgeInnerClassSources(sourcesJar); lineNumbers = filterForgeLineNumbers(lineNumbers); } @@ -393,7 +397,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { // Inject Forge's own sources if (getExtension().isForgeLike()) { try (var serviceManager = new ScopedSharedServiceManager()) { - ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, outputJar); + ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, inputJar, outputJar); } } @@ -416,7 +420,7 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { // Inject Forge's own sources if (getExtension().isForgeLike()) { try (var serviceManager = new ScopedSharedServiceManager()) { - ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, outputJar); + ForgeSourcesRemapper.addForgeSources(getProject(), serviceManager, inputJar, outputJar); } } @@ -448,6 +452,36 @@ public abstract class GenerateSourcesTask extends AbstractLoomTask { } } + /** + * Some inner classes orders are messed up with forge recompilation, I don't know if that is why the decompiler + * would occasionally split out extra inner classes (where with normal fabric setups it doesn't happen), + * but this is a workaround for that. + */ + private void removeForgeInnerClassSources(Path sourcesJar) throws IOException { + if (!getExtension().isForgeLike()) return; + + try (FileSystemUtil.Delegate outputFs = FileSystemUtil.getJarFileSystem(sourcesJar, false); + Stream walk = Files.walk(outputFs.getRoot())) { + Iterator iterator = walk.iterator(); + + while (iterator.hasNext()) { + final Path fsPath = iterator.next(); + + if (fsPath.startsWith("/META-INF/")) { + continue; + } + + if (!Files.isRegularFile(fsPath)) { + continue; + } + + if (fsPath.toString().substring(outputFs.getRoot().toString().length()).indexOf('$') != -1) { + Files.delete(fsPath); + } + } + } + } + // Re-run the named minecraft provider to give us a fresh jar to decompile. // This prevents re-applying line maps on an existing jar. private MinecraftJar rebuildInputJar() {