diff --git a/build.gradle b/build.gradle index 4c7f9cb..8d62838 100644 --- a/build.gradle +++ b/build.gradle @@ -189,6 +189,16 @@ idea { programParameters = "run --dist joined --neoform net.neoforged:neoform:1.21-20240613.152323@zip --write-result=gameJar:build/minecraft.jar --write-result=clientResources:build/client-extra.jar --write-result=gameSources:build/minecraft-sources.jar" moduleRef(project, sourceSets.main) } + "Run Neoform 26.1 (joined) - common/client split"(Application) { + mainClass = mainClassName + programParameters = "run --dist joined --neoform net.neoforged:neoform:26.1-1@zip --write-result=gameCommonSources:build/common-sources.jar --write-result=gameClientSources:build/client-sources.jar --write-result=gameCommonJar:build/common.jar --write-result=gameClientJar:build/client.jar --write-result=gameCommonJarWithSources:build/common-with-sources.jar --write-result=gameClientJarWithSources:build/client-with-sources.jar --write-result=gameCommonJarNoRecomp:build/common-norecomp.jar --write-result=gameClientJarNoRecomp:build/client-norecomp.jar" + moduleRef(project, sourceSets.main) + } + "Run Neoforge 26.1 (joined) - common/client split"(Application) { + mainClass = mainClassName + programParameters = "run --dist joined --neoforge net.neoforged:neoforge:26.1.2.29-beta:userdev --write-result=gameCommonSources:build/common-sources.jar --write-result=gameClientSources:build/client-sources.jar --write-result=gameCommonJarNoRecomp:build/common-norecomp.jar --write-result=gameClientJarNoRecomp:build/client-norecomp.jar --write-result=gameCommonJarNoRecompWithNeoForge:build/common-norecomp-neoforge.jar --write-result=gameClientJarNoRecompWithNeoForge:build/client-norecomp-neoforge.jar --write-result=gameCommonJarWithNeoForge:build/common-recomp-neoforge.jar --write-result=gameClientJarWithNeoForge:build/client-recomp-neoforge.jar --write-result=gameCommonSourcesWithNeoForge:build/common-sources-neoforge.jar --write-result=gameClientSourcesWithNeoForge:build/client-sources-neoforge.jar --write-result=gameCommonJarWithSourcesAndNeoForge:build/common-recomp-sources-neoforge.jar --write-result=gameClientJarWithSourcesAndNeoForge:build/client-recomp-sources-neoforge.jar" + moduleRef(project, sourceSets.main) + } "Run Neoforge 1.20.6 (joined) + Parchment"(Application) { mainClass = mainClassName programParameters = "run --dist joined --neoforge net.neoforged:neoforge:20.6.72-beta:userdev --add-repository=https://maven.parchmentmc.org --parchment-data=org.parchmentmc.data:parchment-1.20.6:2024.05.01:checked@zip --write-result=gameJar:build/minecraft.jar --write-result=clientResources:build/client-extra.jar --write-result=gameSources:build/minecraft-sources.jar" diff --git a/src/main/java/net/neoforged/neoform/runtime/actions/SpiltDistAction.java b/src/main/java/net/neoforged/neoform/runtime/actions/SpiltDistAction.java new file mode 100644 index 0000000..a6a88bc --- /dev/null +++ b/src/main/java/net/neoforged/neoform/runtime/actions/SpiltDistAction.java @@ -0,0 +1,60 @@ +package net.neoforged.neoform.runtime.actions; + +import net.neoforged.neoform.runtime.engine.ProcessingEnvironment; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.util.jar.Attributes; +import java.util.jar.JarFile; +import java.util.zip.ZipInputStream; +import java.util.zip.ZipOutputStream; + +public class SpiltDistAction extends BuiltInAction { + @Override + public void run(ProcessingEnvironment environment) throws IOException, InterruptedException { + var inputPath = environment.getRequiredInputPath("input"); + var commonPath = environment.getOutputPath("common"); + var clientPath = environment.getOutputPath("client"); + try (var inputJar = new JarFile(inputPath.toFile()); + var input = new ZipInputStream(new BufferedInputStream(Files.newInputStream(inputPath))); + var commonTarget = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(commonPath))); + var clientTarget = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(clientPath))) + ) { + var manifest = inputJar.getManifest(); + var distName = new Attributes.Name("Minecraft-Dist"); + for (var entry = input.getNextEntry(); entry != null; entry = input.getNextEntry()) { + if (entry.isDirectory()) { + continue; + } + + var name = entry.getName(); + Attributes fileEntry = null; + if (name.endsWith(".class")) { + fileEntry = manifest.getEntries().get(name); + } else if (name.endsWith(".java")) { + fileEntry = manifest.getEntries().get(name.replace(".java", ".class")); + } + String dist = null; + + if (fileEntry != null) { + dist = fileEntry.getValue(distName); + } else if (name.startsWith("net/neoforged/neoforge/client")) { + dist = "client"; + } + + if ("client".equals(dist)) { + clientTarget.putNextEntry(entry); + input.transferTo(clientTarget); + clientTarget.closeEntry(); + } else { + commonTarget.putNextEntry(entry); + input.transferTo(commonTarget); + commonTarget.closeEntry(); + } + } + } + } + +} diff --git a/src/main/java/net/neoforged/neoform/runtime/cli/ResultIds.java b/src/main/java/net/neoforged/neoform/runtime/cli/ResultIds.java index 1424c86..d449bbf 100644 --- a/src/main/java/net/neoforged/neoform/runtime/cli/ResultIds.java +++ b/src/main/java/net/neoforged/neoform/runtime/cli/ResultIds.java @@ -8,26 +8,86 @@ public final class ResultIds { * The recompilable Minecraft source code as a source zip. */ public static final String GAME_SOURCES = "gameSources"; + + /** + * The recompilable Minecraft common source code as a source zip. + */ + public static final String GAME_COMMON_SOURCES = "gameCommonSources"; + + /** + * The Minecraft client only source code as a source zip. + */ + public static final String GAME_CLIENT_SOURCES = "gameClientSources"; + /** * The recompiled Minecraft source code as a jar file. */ public static final String GAME_JAR = "gameJar"; + + /** + * The recompiled Minecraft common source code as a jar file. + */ + public static final String GAME_COMMON_JAR = "gameCommonJar"; + + /** + * The recompiled Minecraft client source code as a jar file. + */ + public static final String GAME_CLIENT_JAR = "gameClientJar"; + /** * The recompiled Minecraft source code as a jar file, with sources merge into it to allow source browsing * in IntelliJ (which doesn't support attaching sources to a file dependency in Gradle). */ public static final String GAME_JAR_WITH_SOURCES = "gameJarWithSources"; + /** + * The recompiled Minecraft common source code as a jar file, with sources merge into it to allow source browsing + * in IntelliJ (which doesn't support attaching sources to a file dependency in Gradle). + */ + public static final String GAME_COMMON_JAR_WITH_SOURCES = "gameCommonJarWithSources"; + + /** + * The recompiled Minecraft client source code as a jar file, with sources merge into it to allow source browsing + * in IntelliJ (which doesn't support attaching sources to a file dependency in Gradle). + */ + public static final String GAME_CLIENT_JAR_WITH_SOURCES = "gameClientJarWithSources"; + /** * Same as {@link #GAME_SOURCES}, but NeoForge sources are merged into the source zip file. * Should be considered deprecated as NeoForge should be added separately to the classpath. */ public static final String GAME_SOURCES_WITH_NEOFORGE = "gameSourcesWithNeoForge"; + + /** + * Same as {@link #GAME_COMMON_SOURCES}, but NeoForge sources are merged into the source zip file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_COMMON_SOURCES_WITH_NEOFORGE = "gameCommonSourcesWithNeoForge"; + + /** + * Same as {@link #GAME_CLIENT_SOURCES}, but NeoForge sources are merged into the source zip file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_CLIENT_SOURCES_WITH_NEOFORGE = "gameClientSourcesWithNeoForge"; + /** * Same as {@link #GAME_JAR}, but .class files from the NeoForge universal jar are merged into the jar file. * Should be considered deprecated as NeoForge should be added separately to the classpath. */ public static final String GAME_JAR_WITH_NEOFORGE = "gameJarWithNeoForge"; + + /** + * Same as {@link #GAME_COMMON_JAR}, but .class files from the NeoForge universal jar are merged into the jar file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_COMMON_JAR_WITH_NEOFORGE = "gameCommonJarWithNeoForge"; + + /** + * Same as {@link #GAME_CLIENT_JAR}, but .class files from the NeoForge universal jar are merged into the jar file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_CLIENT_JAR_WITH_NEOFORGE = "gameClientJarWithNeoForge"; + /** * Same as {@link #GAME_JAR_WITH_SOURCES}, but both the NeoForge sources and universal jar are merged into the * jar file. @@ -35,18 +95,59 @@ public final class ResultIds { */ public static final String GAME_JAR_WITH_SOURCES_AND_NEOFORGE = "gameJarWithSourcesAndNeoForge"; + /** + * Same as {@link #GAME_COMMON_JAR_WITH_SOURCES}, but both the NeoForge sources and universal jar are merged into + * the jar file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_COMMON_JAR_WITH_SOURCES_AND_NEOFORGE = "gameCommonJarWithSourcesAndNeoForge"; + + /** + * Same as {@link #GAME_CLIENT_JAR_WITH_SOURCES}, but both the NeoForge sources and universal jar are merged into + * the jar file. + * Should be considered deprecated as NeoForge should be added separately to the classpath. + */ + public static final String GAME_CLIENT_JAR_WITH_SOURCES_AND_NEOFORGE = "gameClientJarWithSourcesAndNeoForge"; + /** * Similar to {@link #GAME_JAR} as it contains the compiled game classes, but they were not created * using the NeoForm decompile+recompile workflow. Rather they use original artifacts with binary patches * applied (for NeoForge) or just remapped (for NeoForm only mode). */ public static final String GAME_JAR_NO_RECOMP = "gameJarNoRecomp"; + + /** + * Similar to {@link #GAME_COMMON_JAR} as it contains the compiled game classes, but they were not created + * using the NeoForm decompile+recompile workflow. Rather they use original artifacts with binary patches + * applied (for NeoForge) or just remapped (for NeoForm only mode). + */ + public static final String GAME_COMMON_JAR_NO_RECOMP = "gameCommonJarNoRecomp"; + + /** + * Similar to {@link #GAME_CLIENT_JAR} as it contains the compiled game classes, but they were not created + * using the NeoForm decompile+recompile workflow. Rather they use original artifacts with binary patches + * applied (for NeoForge) or just remapped (for NeoForm only mode). + */ + public static final String GAME_CLIENT_JAR_NO_RECOMP = "gameClientJarNoRecomp"; + /** * Same as {@link #GAME_JAR_NO_RECOMP}, but with NeoForge merged into the artifact. It is the same relationship * as between {@link #GAME_JAR} and {@link #GAME_JAR_WITH_NEOFORGE}. */ public static final String GAME_JAR_NO_RECOMP_WITH_NEOFORGE = "gameJarNoRecompWithNeoForge"; + /** + * Same as {@link #GAME_COMMON_JAR_NO_RECOMP}, but with NeoForge merged into the artifact. It is the same + * relationship as between {@link #GAME_COMMON_JAR} and {@link #GAME_COMMON_JAR_WITH_NEOFORGE}. + */ + public static final String GAME_COMMON_JAR_NO_RECOMP_WITH_NEOFORGE = "gameCommonJarNoRecompWithNeoForge"; + + /** + * Same as {@link #GAME_CLIENT_JAR_NO_RECOMP}, but with NeoForge merged into the artifact. It is the same + * relationship as between {@link #GAME_CLIENT_JAR} and {@link #GAME_CLIENT_JAR_WITH_NEOFORGE}. + */ + public static final String GAME_CLIENT_JAR_NO_RECOMP_WITH_NEOFORGE = "gameClientJarNoRecompWithNeoForge"; + /** * The Jar file of the Vanilla artifact (client, server or joined) after it has been deobfuscated. * In legacy Forge processes, the mapping from intermediary to named should have been applied as well. diff --git a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java index 89c32d4..dee4a7f 100644 --- a/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java +++ b/src/main/java/net/neoforged/neoform/runtime/cli/RunNeoFormCommand.java @@ -10,6 +10,7 @@ import net.neoforged.neoform.runtime.actions.MergeWithSourcesAction; import net.neoforged.neoform.runtime.actions.PatchActionFactory; import net.neoforged.neoform.runtime.actions.RecompileSourcesAction; +import net.neoforged.neoform.runtime.actions.SpiltDistAction; import net.neoforged.neoform.runtime.actions.StripManifestDigestContentFilter; import net.neoforged.neoform.runtime.artifacts.ClasspathItem; import net.neoforged.neoform.runtime.config.neoforge.BinpatcherConfig; @@ -281,6 +282,24 @@ private static void applyNeoForgeProcessTransforms(NeoFormEngine engine, JarFile var sourcesAndCompiledWithNeoForgeOutput = createSourcesAndCompiledWithNeoForge(graph, compiledWithNeoForgeOutput, sourcesWithNeoForgeOutput); + engine.addSplitStep("splitSourcesWithNeoForge", NodeOutputType.ZIP, + sourcesWithNeoForgeOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_SOURCES_WITH_NEOFORGE, ResultIds.GAME_CLIENT_SOURCES_WITH_NEOFORGE, + "Source ZIP containing NeoForge and Minecraft common sources", "Source ZIP containing NeoForge and Minecraft client only sources" + ); + + engine.addSplitStep("splitCompiledWithNeoForge", NodeOutputType.JAR, + compiledWithNeoForgeOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR_WITH_NEOFORGE, ResultIds.GAME_CLIENT_JAR_WITH_NEOFORGE, + "JAR containing NeoForge classes, resources and Minecraft common classes", "JAR containing NeoForge classes, resources and Minecraft client only classes" + ); + + engine.addSplitStep("splitSourcesAndCompiledWithNeo", NodeOutputType.JAR, + sourcesAndCompiledWithNeoForgeOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR_WITH_SOURCES_AND_NEOFORGE, ResultIds.GAME_CLIENT_JAR_WITH_SOURCES_AND_NEOFORGE, + "Common sources and compiled classes of Neoforge and Minecraft", "Client only sources and compiled classes of Neoforge and Minecraft" + ); + graph.setResult(ResultIds.GAME_SOURCES_WITH_NEOFORGE, sourcesWithNeoForgeOutput); graph.setResult(ResultIds.GAME_JAR_WITH_NEOFORGE, compiledWithNeoForgeOutput); graph.setResult(ResultIds.GAME_JAR_WITH_SOURCES_AND_NEOFORGE, sourcesAndCompiledWithNeoForgeOutput); @@ -322,6 +341,14 @@ private static void applyNeoForgeBinaryPatchProcessTransforms(NeoFormEngine engi graph.setResult(ResultIds.GAME_JAR_NO_RECOMP, binaryPatchOutput); graph.setResult(ResultIds.GAME_JAR_NO_RECOMP_WITH_NEOFORGE, binaryWithNeoForgeOutput); } + + var noRecompWithNeoForgeOutput = graph.getResult(ResultIds.GAME_JAR_NO_RECOMP_WITH_NEOFORGE); + engine.addSplitStep("splitNoRecompWithNeoForge", NodeOutputType.JAR, + noRecompWithNeoForgeOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR_NO_RECOMP_WITH_NEOFORGE, ResultIds.GAME_CLIENT_JAR_NO_RECOMP_WITH_NEOFORGE, + "JAR containing NeoForge and non-recompiled Minecraft common classes", + "JAR containing NeoForge and non-recompiled Minecraft client only classes" + ); } /** diff --git a/src/main/java/net/neoforged/neoform/runtime/engine/NeoFormEngine.java b/src/main/java/net/neoforged/neoform/runtime/engine/NeoFormEngine.java index e0732c4..dfa1a77 100644 --- a/src/main/java/net/neoforged/neoform/runtime/engine/NeoFormEngine.java +++ b/src/main/java/net/neoforged/neoform/runtime/engine/NeoFormEngine.java @@ -16,6 +16,7 @@ import net.neoforged.neoform.runtime.actions.RemapSrgClassesAction; import net.neoforged.neoform.runtime.actions.RemapSrgSourcesAction; import net.neoforged.neoform.runtime.actions.SplitResourcesFromClassesAction; +import net.neoforged.neoform.runtime.actions.SpiltDistAction; import net.neoforged.neoform.runtime.artifacts.ArtifactManager; import net.neoforged.neoform.runtime.cache.CacheKeyBuilder; import net.neoforged.neoform.runtime.cache.CacheManager; @@ -28,6 +29,7 @@ import net.neoforged.neoform.runtime.config.neoform.NeoFormStep; import net.neoforged.neoform.runtime.graph.ExecutionGraph; import net.neoforged.neoform.runtime.graph.ExecutionNode; +import net.neoforged.neoform.runtime.graph.ExecutionNodeAction; import net.neoforged.neoform.runtime.graph.ExecutionNodeBuilder; import net.neoforged.neoform.runtime.graph.NodeExecutionException; import net.neoforged.neoform.runtime.graph.NodeOutput; @@ -192,10 +194,31 @@ public void loadNeoFormProcess(NeoFormDistConfig distConfig) { var sourcesOutput = graph.getRequiredOutput("patch", "output"); + addSplitStep("splitSources", NodeOutputType.ZIP, + sourcesOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_SOURCES, ResultIds.GAME_CLIENT_SOURCES, + "Split common dist sources", + "Spilt client dist only sources" + ); + var compiledOutput = addRecompileStep(distConfig, sourcesOutput); + addSplitStep("splitCompiled", NodeOutputType.JAR, + compiledOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR, ResultIds.GAME_CLIENT_JAR, + "Split common dist compiled classes", + "Spilt client dist only compiled classes" + ); + var sourcesAndCompiledOutput = addMergeWithSourcesStep(compiledOutput, sourcesOutput); + addSplitStep("splitSourcesAndCompiled", NodeOutputType.JAR, + sourcesAndCompiledOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR_WITH_SOURCES, ResultIds.GAME_CLIENT_JAR_WITH_SOURCES, + "Split common dist sources and compiled", + "Spilt client dist only sources and compiled" + ); + // Register the sources and the compiled binary as results // Vanilla deobfuscated is equivalent to the input to the decompiler at this point of setting up the process. // While the input to the decompiler might be adjusted later, that will not change this result retroactively. @@ -268,6 +291,14 @@ public void loadNeoFormProcess(NeoFormDistConfig distConfig) { // Without the presence of further patching or renaming, the game jar without recompilation is the deobfuscated vanilla jar graph.setResultFromCurrentInput(ResultIds.GAME_JAR_NO_RECOMP, decompileInput); } + + var noRecompOutput = graph.getResult(ResultIds.GAME_JAR_NO_RECOMP); + addSplitStep("splitNoRecomp", NodeOutputType.JAR, + noRecompOutput, new SpiltDistAction(), + ResultIds.GAME_COMMON_JAR_NO_RECOMP, ResultIds.GAME_CLIENT_JAR_NO_RECOMP, + "Split common dist no-recomp jar", + "Split client only no-recomp jar" + ); } private NodeOutput addRecompileStep(NeoFormDistConfig distConfig, NodeOutput sourcesOutput) { @@ -294,6 +325,22 @@ private NodeOutput addRecompileStep(NeoFormDistConfig distConfig, NodeOutput sou return compiledOutput; } + public void addSplitStep( + String nodeName,NodeOutputType outputType, + NodeOutput nodeInput, ExecutionNodeAction action, + String commonResultId, String clientResultId, + String commonDesc, String clientDesc + ) { + var builder = graph.nodeBuilder(nodeName); + builder.input("input", nodeInput.asInput()); + var common = builder.output("common", outputType, commonDesc); + var client = builder.output("client", outputType, clientDesc); + builder.action(action); + graph.setResult(commonResultId, common); + graph.setResult(clientResultId, client); + builder.build(); + } + private NodeOutput addMergeWithSourcesStep(NodeOutput compiledOutput, NodeOutput sourcesOutput) { var builder = graph.nodeBuilder("mergeWithSources"); builder.input("classes", compiledOutput.asInput());