From 77841ba38440983fff57eecbf79873c7f8437c6b Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 22:29:14 +0800 Subject: [PATCH 1/6] spilt dist --- .../internal/LegacyForgeModDevPlugin.java | 3 +- .../neoforged/moddevgradle/dsl/ModModel.java | 8 ++ .../dsl/ModdingVersionSettings.java | 18 ++- .../internal/EclipseIntegration.java | 8 +- .../internal/IntelliJIntegration.java | 12 +- .../internal/ModDevArtifactsWorkflow.java | 70 +++++++++-- .../moddevgradle/internal/ModDevPlugin.java | 3 +- .../internal/ModDevRunWorkflow.java | 12 +- .../moddevgradle/internal/RunUtils.java | 23 +++- .../internal/VsCodeIntegration.java | 3 +- .../internal/WorkflowArtifact.java | 4 + .../neoforged/nfrtgradle/SplitMergedJar.java | 116 ++++++++++++++++++ testproject/settings.gradle | 1 + testproject/split/build.gradle | 26 ++++ .../client/java/split/client/ClientMain.java | 17 +++ .../split/src/main/java/split/SplitMain.java | 10 ++ .../resources/META-INF/neoforge.mods.toml | 96 +++++++++++++++ 17 files changed, 399 insertions(+), 31 deletions(-) create mode 100644 src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java create mode 100644 testproject/split/build.gradle create mode 100644 testproject/split/src/client/java/split/client/ClientMain.java create mode 100644 testproject/split/src/main/java/split/SplitMain.java create mode 100644 testproject/split/src/main/resources/META-INF/neoforge.mods.toml diff --git a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java index a3f7ef17..64e1c129 100644 --- a/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java +++ b/src/legacy/java/net/neoforged/moddevgradle/legacyforge/internal/LegacyForgeModDevPlugin.java @@ -154,7 +154,8 @@ public void enable(Project project, LegacyForgeModdingSettings settings, LegacyF configurations.getByName(DataFileCollections.CONFIGURATION_ACCESS_TRANSFORMERS), configurations.getByName(DataFileCollections.CONFIGURATION_INTERFACE_INJECTION_DATA), versionCapabilities, - settings.isDisableRecompilation()); + settings.isDisableRecompilation(), + false); var runs = ModDevRunWorkflow.create( project, diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/ModModel.java b/src/main/java/net/neoforged/moddevgradle/dsl/ModModel.java index bc259127..7ef1e12d 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/ModModel.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/ModModel.java @@ -15,6 +15,8 @@ public ModModel() { // TODO: We could potentially do a bit of name validation getModSourceSets().convention(List.of()); getModSourceSets().finalizeValueOnRead(); + getModClientSourceSets().convention(List.of()); + getModClientSourceSets().finalizeValueOnRead(); } @Override @@ -23,7 +25,13 @@ public ModModel() { // Do not name getSourceSets or it will conflict with project.sourceSets in scripts. public abstract ListProperty getModSourceSets(); + public abstract ListProperty getModClientSourceSets(); + public void sourceSet(SourceSet sourceSet) { getModSourceSets().add(sourceSet); } + + public void clientSourceSet(SourceSet sourceSet) { + getModClientSourceSets().add(sourceSet); + } } diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java b/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java index d6a1da9b..05f4d15a 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java @@ -1,13 +1,14 @@ package net.neoforged.moddevgradle.dsl; -import java.util.HashSet; -import java.util.Set; -import javax.inject.Inject; import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; import org.gradle.api.Project; import org.gradle.api.tasks.SourceSet; import org.jetbrains.annotations.Nullable; +import javax.inject.Inject; +import java.util.HashSet; +import java.util.Set; + public abstract class ModdingVersionSettings { @Nullable private String version; @@ -15,6 +16,8 @@ public abstract class ModdingVersionSettings { @Nullable private String neoFormVersion; + private boolean splitDist = false; + private Set enabledSourceSets = new HashSet<>(); private boolean disableRecompilation = "true".equals(System.getenv("CI")); @@ -77,4 +80,13 @@ public boolean isDisableRecompilation() { public void setDisableRecompilation(boolean disableRecompilation) { this.disableRecompilation = disableRecompilation; } + + public boolean isSplitDist() { + return splitDist; + } + + public void setSplitDist(boolean enable) { + this.splitDist = enable; + } + } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java index 40e97557..fd7e7ced 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java @@ -154,7 +154,8 @@ private void addEclipseLaunchConfiguration(Project project, } // This is the actual main launch configuration that launches the game - var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null); + boolean isClient = run.getType().get().startsWith("client"); + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, isClient); var config = JavaApplicationLaunchConfig.builder(eclipseProjectName) .vmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())), @@ -168,12 +169,13 @@ private void addEclipseLaunchConfiguration(Project project, protected static ModFoldersProvider getModFoldersProvider(Project project, Provider> modsProvider, - @Nullable Provider testedMod) { + @Nullable Provider testedMod, + boolean isClient) { var folders = RunUtils.buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { output.from(RunUtils.findSourceSetProject(project, sourceSet).getProjectDir().toPath() .resolve("bin") .resolve(sourceSet.getName())); - }); + }, isClient); var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); modFoldersProvider.getModFolders().set(folders); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java index 50f08e80..583ebf0b 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java @@ -122,7 +122,7 @@ public void configureTesting(Provider> loadedMods, var intellijVmArgsFile = runArgsDir.map(dir -> dir.file("intellijVmArgs.txt")); var outputDirectory = IntelliJOutputDirectoryValueSource.getIntellijOutputDirectory(project); - var ideSpecificVmArgs = RunUtils.escapeJvmArg(getModFoldersProvider(project, outputDirectory, loadedMods, testedMod).getArgument()); + var ideSpecificVmArgs = RunUtils.escapeJvmArg(getModFoldersProvider(project, outputDirectory, loadedMods, testedMod, true).getArgument()); try { var vmArgsFilePath = intellijVmArgsFile.get().getAsFile().toPath(); Files.createDirectories(vmArgsFilePath.getParent()); @@ -185,7 +185,8 @@ private static void addIntelliJRunConfiguration(Project project, } appRun.setModuleName(getIntellijModuleName(project, sourceSet)); appRun.setWorkingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()); - var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null); + boolean isClient = run.getType().get().startsWith("client"); + var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null, isClient); appRun.setEnvs(RunUtils.replaceModClassesEnv(run, modFoldersProvider)); appRun.setJvmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())) @@ -232,15 +233,16 @@ public boolean shouldUseCombinedSourcesAndClassesArtifact() { private static ModFoldersProvider getModFoldersProvider(Project project, @Nullable Function outputDirectory, Provider> modsProvider, - @Nullable Provider testedMod) { + @Nullable Provider testedMod, + boolean isClient) { Provider> folders; if (outputDirectory != null) { folders = RunUtils.buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { var sourceSetDir = outputDirectory.apply(RunUtils.findSourceSetProject(project, sourceSet)).toPath().resolve(getIdeaOutName(sourceSet)); output.from(sourceSetDir.resolve("classes"), sourceSetDir.resolve("resources")); - }); + }, isClient); } else { - folders = RunUtils.getModFoldersForGradle(project, modsProvider, testedMod); + folders = RunUtils.getModFoldersForGradle(project, modsProvider, testedMod, isClient); } var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java index 40b1723d..cdc0843c 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java @@ -11,6 +11,7 @@ import net.neoforged.moddevgradle.internal.utils.VersionCapabilitiesInternal; import net.neoforged.nfrtgradle.CreateMinecraftArtifacts; import net.neoforged.nfrtgradle.DownloadAssets; +import net.neoforged.nfrtgradle.SplitMergedJar; import org.gradle.api.GradleException; import org.gradle.api.InvalidUserCodeException; import org.gradle.api.Named; @@ -28,6 +29,7 @@ import org.gradle.api.plugins.JavaPluginExtension; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.SourceSetContainer; import org.gradle.api.tasks.TaskProvider; import org.gradle.jvm.toolchain.JavaLanguageVersion; import org.gradle.jvm.toolchain.JavaToolchainService; @@ -47,6 +49,7 @@ public record ModDevArtifactsWorkflow( TaskProvider downloadAssets, Configuration runtimeDependencies, Configuration compileDependencies, + Configuration clientExtraCompileDependencies, Provider modDevBuildDir, Provider artifactsBuildDir) { @@ -68,7 +71,8 @@ public static ModDevArtifactsWorkflow create(Project project, Configuration accessTransformers, Configuration interfaceInjectionData, VersionCapabilitiesInternal versionCapabilities, - boolean disableRecompilation) { + boolean disableRecompilation, + boolean splitDist) { if (project.getExtensions().findByName(EXTENSION_NAME) != null) { throw new InvalidUserCodeException("You cannot enable modding in the same project twice."); } @@ -115,6 +119,8 @@ public static ModDevArtifactsWorkflow create(Project project, spec.getDependencies().addLater(parchment.getParchmentArtifact().map(dependencyFactory::create)); }); + Function> artifactPathStrategy = artifact -> artifactsBuildDir.map(dir -> dir.file(artifactNamingStrategy.getFilename(artifact))); + // it has to contain client-extra to be loaded by FML, and it must be added to the legacy CP var createArtifacts = tasks.register("createMinecraftArtifacts", CreateMinecraftArtifacts.class, task -> { task.setGroup(branding.internalTaskGroup()); @@ -151,8 +157,6 @@ public static ModDevArtifactsWorkflow create(Project project, task.getParchmentEnabled().set(parchment.getEnabled()); task.getParchmentConflictResolutionPrefix().set(parchment.getConflictResolutionPrefix()); - Function> artifactPathStrategy = artifact -> artifactsBuildDir.map(dir -> dir.file(artifactNamingStrategy.getFilename(artifact))); - task.getIncludeNeoForgeInGameJar().set(versionCapabilities.needsNeoForgeInMinecraftJar()); task.getGameJarArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.COMPILED)); if (disableRecompilation) { @@ -185,6 +189,27 @@ public static ModDevArtifactsWorkflow create(Project project, task.getNeoFormArtifact().set(moddingDependencies.neoFormDependencyNotation()); }); + var splitMergedJar = tasks.register("splitMergedJar", SplitMergedJar.class, task -> { + if (!splitDist){ + throw new IllegalStateException("Can't request split dist result when splitDist is disabled!"); + } + task.getClientResourcesJar().set(createArtifacts.flatMap(CreateMinecraftArtifacts::getResourcesArtifact)); + task.getClientJar().set(artifactPathStrategy.apply(WorkflowArtifact.CLIENT)); + task.getCommonJar().set(artifactPathStrategy.apply(WorkflowArtifact.COMMON)); + if (!disableRecompilation) { + task.getMergedJar().set(createArtifacts.flatMap(CreateMinecraftArtifacts::getGameJarWithSourcesArtifact)); + task.getClientSourcesJar().set(artifactPathStrategy.apply(WorkflowArtifact.CLIENT_SOURCES)); + task.getCommonSourcesJar().set(artifactPathStrategy.apply(WorkflowArtifact.COMMON_SOURCES)); + } else { + task.getMergedJar().set(createArtifacts.flatMap(CreateMinecraftArtifacts::getGameJarArtifact)); + } + + }); + + if(splitDist){ + ideIntegration.runTaskOnProjectSync(splitMergedJar); + } + // For IntelliJ, we attach a combined sources+classes artifact which enables an "Attach Sources..." link for IJ users // Otherwise, attaching sources is a pain for IJ users. Provider minecraftClassesDependency; @@ -218,13 +243,26 @@ public static ModDevArtifactsWorkflow create(Project project, config.setDescription("The compile-time dependencies to develop a mod, including Minecraft and modding platform classes."); config.setCanBeResolved(false); config.setCanBeConsumed(false); - config.getDependencies().addLater(minecraftClassesDependency); + if (!splitDist){ + config.getDependencies().addLater(minecraftClassesDependency); + } else { + config.getDependencies().addLater(splitMergedJar.map(task -> project.files(task.getCommonJar())).map(dependencyFactory::create)); + } config.getDependencies().add(moddingDependencies.gameLibrariesDependency()); if (!versionCapabilities.needsNeoForgeInMinecraftJar() && moddingDependencies.neoForgeDependency() != null) { config.getDependencies().add(moddingDependencies.neoForgeDependency()); } }); + var clientExtraCompileDependencies = configurations.create("modDevClientCompileDependencies", config -> { + config.setDescription("The extra client compile-time dependencies to develop a mod, including Minecraft and modding platform classes."); + config.setCanBeResolved(false); + config.setCanBeConsumed(false); + if (splitDist){ + config.getDependencies().addLater(splitMergedJar.map(task -> project.files(task.getClientJar())).map(dependencyFactory::create)); + } + }); + // For IDEs that support it, link the source/binary artifacts if we use separated ones if (!disableRecompilation && !ideIntegration.shouldUseCombinedSourcesAndClassesArtifact()) { ideIntegration.attachSources( @@ -242,13 +280,22 @@ public static ModDevArtifactsWorkflow create(Project project, downloadAssets, runtimeDependencies, compileDependencies, + clientExtraCompileDependencies, modDevBuildDir, artifactsBuildDir); project.getExtensions().add(ModDevArtifactsWorkflow.class, EXTENSION_NAME, result); for (var sourceSets : enabledSourceSets) { - result.addToSourceSet(sourceSets); + result.addToSourceSet(sourceSets, !splitDist); + } + + if (splitDist){ + SourceSetContainer sourceSets = ExtensionUtils.getSourceSets(project); + var main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); + SourceSet client = sourceSets.create("client"); + client.setCompileClasspath(client.getCompileClasspath().plus(main.getOutput())); + result.addToSourceSet(client,true); } return result; @@ -351,14 +398,23 @@ private static List configureArtifactManifestConfigurations( * Adds the compile-time and runtime-dependencies needed to compile mod code to the source-set of the given name. */ public void addToSourceSet(SourceSet sourceSet) { + addToSourceSet(sourceSet, true); + } + + public void addToSourceSet(SourceSet sourceSet, boolean includeClient) { var configurations = project.getConfigurations(); var sourceSets = ExtensionUtils.getSourceSets(project); if (!sourceSets.contains(sourceSet)) { throw new GradleException("Cannot add to the source set in another project: " + sourceSet); } - configurations.getByName(sourceSet.getRuntimeClasspathConfigurationName()).extendsFrom(runtimeDependencies); - configurations.getByName(sourceSet.getCompileClasspathConfigurationName()).extendsFrom(compileDependencies); + Configuration runtime = configurations.getByName(sourceSet.getRuntimeClasspathConfigurationName()); + runtime.extendsFrom(runtimeDependencies); + Configuration compile = configurations.getByName(sourceSet.getCompileClasspathConfigurationName()); + compile.extendsFrom(compileDependencies); + if (includeClient) { + compile.extendsFrom(clientExtraCompileDependencies); + } } public Provider requestAdditionalMinecraftArtifact(String id, String filename) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java index 97f0e7f5..2646c33a 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java @@ -98,7 +98,8 @@ public void enable( configurations.getByName(DataFileCollections.CONFIGURATION_ACCESS_TRANSFORMERS), configurations.getByName(DataFileCollections.CONFIGURATION_INTERFACE_INJECTION_DATA), versionCapabilities, - settings.isDisableRecompilation()); + settings.isDisableRecompilation(), + settings.isSplitDist()); ModDevRunWorkflow.create( project, diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java index d6be0f49..eefd82e5 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java @@ -272,7 +272,8 @@ public static void setupRuns( if (!versionCapabilities.modLocatorRework()) { // TODO: do this properly now that we have a flag in the version capabilities // This will explicitly be replaced in RunUtils to make this work for IDEs - run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null).getClassesArgument()); + boolean isClient = run.getType().get().startsWith("client"); + run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient).getClassesArgument()); } var prepareRunTask = setupRunInGradle( project, @@ -405,7 +406,8 @@ private static TaskProvider setupRunInGradle( task.getVmArgsFile().set(prepareRunTask.get().getVmArgsFile().map(d -> d.getAsFile().getAbsolutePath())); task.getProgramArgsFile().set(prepareRunTask.get().getProgramArgsFile().map(d -> d.getAsFile().getAbsolutePath())); task.getEnvironment().set(run.getEnvironment()); - task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null)); + boolean isClient = run.getType().get().startsWith("client"); + task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient)); }); createLaunchScriptsTask.configure(task -> task.dependsOn(launchScriptTask)); @@ -428,8 +430,8 @@ private static TaskProvider setupRunInGradle( // Of course we need the arg files to be up-to-date ;) task.dependsOn(prepareRunTask); task.dependsOn(run.getTasksBefore()); - - task.getJvmArgumentProviders().add(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null)); + boolean isClient = run.getType().get().startsWith("client"); + task.getJvmArgumentProviders().add(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient)); }); return prepareRunTask; @@ -524,7 +526,7 @@ static void setupTestTask(Project project, task.systemProperty("fml.junit.argsfile", programArgsFile.get().getAsFile().getAbsolutePath()); task.jvmArgs(RunUtils.getArgFileParameter(vmArgsFile.get())); - var modFoldersProvider = RunUtils.getGradleModFoldersProvider(project, loadedMods, testedMod); + var modFoldersProvider = RunUtils.getGradleModFoldersProvider(project, loadedMods, testedMod, true); task.getJvmArgumentProviders().add(modFoldersProvider); }); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index c913ce82..d3ca0aa1 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -171,9 +171,9 @@ public static String getArgFileParameter(RegularFile argFile) { return "@" + argFile.getAsFile().getAbsolutePath(); } - public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod) { + public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod, boolean isClient) { var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); - modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod)); + modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod, isClient)); return modFoldersProvider; } @@ -215,16 +215,18 @@ public static Map replaceModClassesEnv(RunModel model, ModFolder public static Provider> getModFoldersForGradle(Project project, Provider> modsProvider, - @Nullable Provider testedMod) { + @Nullable Provider testedMod, + boolean isClient) { return buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { output.from(sourceSet.getOutput()); - }); + }, isClient); } public static Provider> buildModFolders(Project project, Provider> modsProvider, @Nullable Provider testedModProvider, - BiConsumer outputFolderResolver) { + BiConsumer outputFolderResolver, + boolean isClient) { // Convert it to optional to ensure zip will be called even if no mod under test is present. if (testedModProvider == null) { testedModProvider = project.provider(() -> null); @@ -253,6 +255,17 @@ public static Provider> buildModFolders(Project project, outputFolderResolver.accept(sourceSet, modFolder.getFolders()); } + if (isClient){ + var clientSourceSets = mod.getModClientSourceSets().get(); + for (int i = 0; i < clientSourceSets.size(); ++i) { + var sourceSet = clientSourceSets.get(i); + if (clientSourceSets.subList(0, i).contains(sourceSet)) { + throw new InvalidUserCodeException("Duplicate source set '%s' in mod '%s'".formatted(sourceSet.getName(), mod.getName())); + } + outputFolderResolver.accept(sourceSet, modFolder.getFolders()); + } + } + // Add the test source set to the mod under test and if unit tests are enabled if (testedMod.isPresent() && testedMod.get() == mod) { var testSourceSet = ExtensionUtils.getSourceSets(project).findByName(SourceSet.TEST_SOURCE_SET_NAME); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java index 342f042b..0ea06fc9 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java @@ -67,7 +67,8 @@ private void addVscodeLaunchConfiguration(Project project, eclipseModel.autoBuildTasks(run.getTasksBefore().toArray()); } - var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null); + boolean isClient = run.getType().get().startsWith("client"); + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, isClient); launchWriter.createGroup("Mod Development - " + project.getName(), WritingMode.REMOVE_EXISTING) .createLaunchConfiguration() .withName(runIdeName) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/WorkflowArtifact.java b/src/main/java/net/neoforged/moddevgradle/internal/WorkflowArtifact.java index 2d16251d..89496478 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/WorkflowArtifact.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/WorkflowArtifact.java @@ -6,6 +6,10 @@ public enum WorkflowArtifact { COMPILED(""), COMPILED_WITH_SOURCES("-merged"), + COMMON("-common"), + COMMON_SOURCES("-common-sources"), + CLIENT("-client"), + CLIENT_SOURCES("-client-sources"), SOURCES("-sources"), CLIENT_RESOURCES("-client-extra-aka-minecraft-resources"); diff --git a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java new file mode 100644 index 00000000..d7672341 --- /dev/null +++ b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java @@ -0,0 +1,116 @@ +package net.neoforged.nfrtgradle; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.jetbrains.annotations.Nullable; + +import javax.inject.Inject; +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 abstract class SplitMergedJar extends DefaultTask { + @Inject + public SplitMergedJar() {} + + @InputFile + public abstract RegularFileProperty getClientResourcesJar(); + + @InputFile + public abstract RegularFileProperty getMergedJar(); + + @OutputFile + public abstract RegularFileProperty getCommonJar(); + + @OutputFile + @Optional + public abstract RegularFileProperty getCommonSourcesJar(); + + @OutputFile + public abstract RegularFileProperty getClientJar(); + + @OutputFile + @Optional + public abstract RegularFileProperty getClientSourcesJar(); + + @TaskAction + public void splitMergedJar() throws IOException { + try ( + var clientResources = new JarFile(getClientResourcesJar().get().getAsFile()); + var merged = new ZipInputStream(new BufferedInputStream(Files.newInputStream(getMergedJar().get().getAsFile().toPath()))); + var common = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getCommonJar().get().getAsFile().toPath()))); + var client = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientJar().get().getAsFile().toPath()))) + ) { + + var manifest = clientResources.getManifest(); + + if (getCommonSourcesJar().isPresent() && getClientSourcesJar().isPresent()) { + try ( + var commonSources = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getCommonSourcesJar().get().getAsFile().toPath()))); + var clientSources = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientSourcesJar().get().getAsFile().toPath()))) + ) { + spiltHelper(manifest, merged, common, client, commonSources, clientSources); + } + } else { + spiltHelper(manifest, merged, common, client, null, null); + } + + + } + + } + + private static void spiltHelper( + java.util.jar.Manifest manifest, + ZipInputStream merged, ZipOutputStream common, ZipOutputStream client, + @Nullable ZipOutputStream commonSources, @Nullable ZipOutputStream clientSources + ) throws IOException { + var sourceDistName = new Attributes.Name("Minecraft-Dist"); + for (var entry = merged.getNextEntry(); entry != null; entry = merged.getNextEntry()) { + if (entry.isDirectory()) { + continue; + } + + var name = entry.getName(); + ZipOutputStream commonTarget = common; + ZipOutputStream clientTarget = client; + 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")); + if (commonSources != null && clientSources != null) { + commonTarget = commonSources; + clientTarget = clientSources; + } + } + String dist = null; + + if (fileEntry != null) { + dist = fileEntry.getValue(sourceDistName); + } else if (name.startsWith("net/neoforged/neoforge/client")) { + dist = "client"; + } + + if ("client".equals(dist)) { + clientTarget.putNextEntry(entry); + merged.transferTo(clientTarget); + clientTarget.closeEntry(); + } else { + commonTarget.putNextEntry(entry); + merged.transferTo(commonTarget); + commonTarget.closeEntry(); + } + } + } + +} diff --git a/testproject/settings.gradle b/testproject/settings.gradle index 952a551e..56ce33d8 100644 --- a/testproject/settings.gradle +++ b/testproject/settings.gradle @@ -21,5 +21,6 @@ include 'subproject' include 'common' include 'jijtest' include 'coremod' +include 'split' enableFeaturePreview "STABLE_CONFIGURATION_CACHE" diff --git a/testproject/split/build.gradle b/testproject/split/build.gradle new file mode 100644 index 00000000..94b509f3 --- /dev/null +++ b/testproject/split/build.gradle @@ -0,0 +1,26 @@ +plugins { + id 'net.neoforged.moddev' + id 'maven-publish' +} + +neoForge { + enable { + version = project.neoforge_version + splitDist = true + } + runs { + "client" { + client() + } + + "server" { + server() + } + } + mods { + splittest { + sourceSet sourceSets.main + clientSourceSet sourceSets.client + } + } +} \ No newline at end of file diff --git a/testproject/split/src/client/java/split/client/ClientMain.java b/testproject/split/src/client/java/split/client/ClientMain.java new file mode 100644 index 00000000..97344fa2 --- /dev/null +++ b/testproject/split/src/client/java/split/client/ClientMain.java @@ -0,0 +1,17 @@ +package split.client; + +import net.minecraft.client.Minecraft; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.fml.common.Mod; +import split.SplitMain; + +@Mod(value = "splittest", dist = Dist.CLIENT) +public class ClientMain { + + public ClientMain() { + Minecraft instance = Minecraft.getInstance(); + System.out.println("from client"); + System.out.println(SplitMain.class); + } + +} diff --git a/testproject/split/src/main/java/split/SplitMain.java b/testproject/split/src/main/java/split/SplitMain.java new file mode 100644 index 00000000..fe8c40d3 --- /dev/null +++ b/testproject/split/src/main/java/split/SplitMain.java @@ -0,0 +1,10 @@ +package split; + +import net.neoforged.fml.common.Mod; + +@Mod("splittest") +public class SplitMain { + public SplitMain() { + + } +} diff --git a/testproject/split/src/main/resources/META-INF/neoforge.mods.toml b/testproject/split/src/main/resources/META-INF/neoforge.mods.toml new file mode 100644 index 00000000..a65ab0dc --- /dev/null +++ b/testproject/split/src/main/resources/META-INF/neoforge.mods.toml @@ -0,0 +1,96 @@ +# This is an example neoforge.mods.toml file. It contains the data relating to the loading mods. +# There are several mandatory fields (#mandatory), and many more that are optional (#optional). +# The overall format is standard TOML format, v0.5.0. +# Note that there are a couple of TOML lists in this file. +# Find more information on toml format here: https://github.com/toml-lang/toml + +# The license for you mod. This is mandatory metadata and allows for easier comprehension of your redistributive properties. +# Review your options at https://choosealicense.com/. All rights reserved is the default copyright stance, and is thus the default here. +license="CC0" + +# A URL to refer people to when problems occur with this mod +#issueTrackerURL="https://change.me.to.your.issue.tracker.example.invalid/" #optional + + +# A list of mods - how many allowed here is determined by the individual mod loader +[[mods]] #mandatory + +# The modid of the mod +modId="splittest" #mandatory + +# The version number of the mod +version="0.0.0" + +# A display name for the mod +displayName="Test Split Project" #mandatory + +# A URL to query for updates for this mod. See the JSON update specification https://docs.neoforged.net/docs/misc/updatechecker/ +#updateJSONURL="https://change.me.example.invalid/updates.json" #optional + +# A URL for the "homepage" for this mod, displayed in the mod UI +#displayURL="https://change.me.to.your.mods.homepage.example.invalid/" #optional + +# A file name (in the root of the mod JAR) containing a logo for display +#logoFile="examplemod.png" #optional + +# A text field displayed in the mod UI +#credits="" #optional + +# A text field displayed in the mod UI +#authors="${mod_authors}" #optional + +# Display Test controls the display for your mod in the server connection screen +# MATCH_VERSION means that your mod will cause a red X if the versions on client and server differ. This is the default behaviour and should be what you choose if you have server and client elements to your mod. +# IGNORE_SERVER_VERSION means that your mod will not cause a red X if it's present on the server but not on the client. This is what you should use if you're a server only mod. +# IGNORE_ALL_VERSION means that your mod will not cause a red X if it's present on the client or the server. This is a special case and should only be used if your mod has no server component. +# NONE means that no display test is set on your mod. You need to do this yourself, see IExtensionPoint.DisplayTest for more information. You can define any scheme you wish with this value. +# IMPORTANT NOTE: this is NOT an instruction as to which environments (CLIENT or DEDICATED SERVER) your mod loads on. Your mod should load (and maybe do nothing!) whereever it finds itself. +#displayTest="MATCH_VERSION" # MATCH_VERSION is the default if nothing is specified (#optional) + +# The description text for the mod (multi line!) (#mandatory) +description='''A test project.''' + +# The [[mixins]] block allows you to declare your mixin config to FML so that it gets loaded. +#[[mixins]] +#config="${mod_id}.mixins.json" + +# The [[accessTransformers]] block allows you to declare where your AT file is. +# If this block is omitted, a fallback attempt will be made to load an AT from META-INF/accesstransformer.cfg +#[[accessTransformers]] +#file="META-INF/accesstransformer.cfg" + +# The coremods config file path is not configurable and is always loaded from META-INF/coremods.json + +# A dependency - use the . to indicate dependency for a specific modid. Dependencies are optional. +[[dependencies.splittest]] #optional +# the modid of the dependency +modId="neoforge" #mandatory +# The type of the dependency. Can be one of "required", "optional", "incompatible" or "discouraged" (case insensitive). +# 'required' requires the mod to exist, 'optional' does not +# 'incompatible' will prevent the game from loading when the mod exists, and 'discouraged' will show a warning +type="required" #mandatory +# Optional field describing why the dependency is required or why it is incompatible +# reason="..." +# The version range of the dependency +versionRange="[21.10.0-beta,)" #mandatory +# An ordering relationship for the dependency. +# BEFORE - This mod is loaded BEFORE the dependency +# AFTER - This mod is loaded AFTER the dependency +ordering="NONE" +# Side this dependency is applied on - BOTH, CLIENT, or SERVER +side="BOTH" + +# Here's another dependency +[[dependencies.splittest]] +modId="minecraft" +type="required" +# This version range declares a minimum of the current minecraft version up to but not including the next major version +versionRange="[1.21.10]" +ordering="NONE" +side="BOTH" + +# Features are specific properties of the game environment, that you may want to declare you require. This example declares +# that your mod requires GL version 3.2 or higher. Other features will be added. They are side aware so declaring this won't +# stop your mod loading on the server for example. +#[features.${mod_id}] +#openGLVersion="[3.2,)" From 356029c9dc2b7ac7cafc3c7e5a1ea6f223eee634 Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 22:38:01 +0800 Subject: [PATCH 2/6] spotless apply --- .../dsl/ModdingVersionSettings.java | 8 ++--- .../internal/ModDevArtifactsWorkflow.java | 12 ++++---- .../moddevgradle/internal/RunUtils.java | 2 +- .../neoforged/nfrtgradle/SplitMergedJar.java | 29 +++++++------------ 4 files changed, 21 insertions(+), 30 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java b/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java index 05f4d15a..dc1a80e8 100644 --- a/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java +++ b/src/main/java/net/neoforged/moddevgradle/dsl/ModdingVersionSettings.java @@ -1,14 +1,13 @@ package net.neoforged.moddevgradle.dsl; +import java.util.HashSet; +import java.util.Set; +import javax.inject.Inject; import net.neoforged.moddevgradle.internal.utils.ExtensionUtils; import org.gradle.api.Project; import org.gradle.api.tasks.SourceSet; import org.jetbrains.annotations.Nullable; -import javax.inject.Inject; -import java.util.HashSet; -import java.util.Set; - public abstract class ModdingVersionSettings { @Nullable private String version; @@ -88,5 +87,4 @@ public boolean isSplitDist() { public void setSplitDist(boolean enable) { this.splitDist = enable; } - } diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java index cdc0843c..b382561c 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java @@ -190,7 +190,7 @@ public static ModDevArtifactsWorkflow create(Project project, }); var splitMergedJar = tasks.register("splitMergedJar", SplitMergedJar.class, task -> { - if (!splitDist){ + if (!splitDist) { throw new IllegalStateException("Can't request split dist result when splitDist is disabled!"); } task.getClientResourcesJar().set(createArtifacts.flatMap(CreateMinecraftArtifacts::getResourcesArtifact)); @@ -206,7 +206,7 @@ public static ModDevArtifactsWorkflow create(Project project, }); - if(splitDist){ + if (splitDist) { ideIntegration.runTaskOnProjectSync(splitMergedJar); } @@ -243,7 +243,7 @@ public static ModDevArtifactsWorkflow create(Project project, config.setDescription("The compile-time dependencies to develop a mod, including Minecraft and modding platform classes."); config.setCanBeResolved(false); config.setCanBeConsumed(false); - if (!splitDist){ + if (!splitDist) { config.getDependencies().addLater(minecraftClassesDependency); } else { config.getDependencies().addLater(splitMergedJar.map(task -> project.files(task.getCommonJar())).map(dependencyFactory::create)); @@ -258,7 +258,7 @@ public static ModDevArtifactsWorkflow create(Project project, config.setDescription("The extra client compile-time dependencies to develop a mod, including Minecraft and modding platform classes."); config.setCanBeResolved(false); config.setCanBeConsumed(false); - if (splitDist){ + if (splitDist) { config.getDependencies().addLater(splitMergedJar.map(task -> project.files(task.getClientJar())).map(dependencyFactory::create)); } }); @@ -290,12 +290,12 @@ public static ModDevArtifactsWorkflow create(Project project, result.addToSourceSet(sourceSets, !splitDist); } - if (splitDist){ + if (splitDist) { SourceSetContainer sourceSets = ExtensionUtils.getSourceSets(project); var main = sourceSets.getByName(SourceSet.MAIN_SOURCE_SET_NAME); SourceSet client = sourceSets.create("client"); client.setCompileClasspath(client.getCompileClasspath().plus(main.getOutput())); - result.addToSourceSet(client,true); + result.addToSourceSet(client, true); } return result; diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index d3ca0aa1..0d1cc36a 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -255,7 +255,7 @@ public static Provider> buildModFolders(Project project, outputFolderResolver.accept(sourceSet, modFolder.getFolders()); } - if (isClient){ + if (isClient) { var clientSourceSets = mod.getModClientSourceSets().get(); for (int i = 0; i < clientSourceSets.size(); ++i) { var sourceSet = clientSourceSets.get(i); diff --git a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java index d7672341..e51c87e4 100644 --- a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java +++ b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java @@ -1,14 +1,5 @@ package net.neoforged.nfrtgradle; -import org.gradle.api.DefaultTask; -import org.gradle.api.file.RegularFileProperty; -import org.gradle.api.tasks.InputFile; -import org.gradle.api.tasks.Optional; -import org.gradle.api.tasks.OutputFile; -import org.gradle.api.tasks.TaskAction; -import org.jetbrains.annotations.Nullable; - -import javax.inject.Inject; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.IOException; @@ -17,6 +8,14 @@ import java.util.jar.JarFile; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; +import javax.inject.Inject; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.Optional; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; +import org.jetbrains.annotations.Nullable; public abstract class SplitMergedJar extends DefaultTask { @Inject @@ -48,32 +47,27 @@ public void splitMergedJar() throws IOException { var clientResources = new JarFile(getClientResourcesJar().get().getAsFile()); var merged = new ZipInputStream(new BufferedInputStream(Files.newInputStream(getMergedJar().get().getAsFile().toPath()))); var common = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getCommonJar().get().getAsFile().toPath()))); - var client = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientJar().get().getAsFile().toPath()))) - ) { + var client = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientJar().get().getAsFile().toPath())))) { var manifest = clientResources.getManifest(); if (getCommonSourcesJar().isPresent() && getClientSourcesJar().isPresent()) { try ( var commonSources = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getCommonSourcesJar().get().getAsFile().toPath()))); - var clientSources = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientSourcesJar().get().getAsFile().toPath()))) - ) { + var clientSources = new ZipOutputStream(new BufferedOutputStream(Files.newOutputStream(getClientSourcesJar().get().getAsFile().toPath())))) { spiltHelper(manifest, merged, common, client, commonSources, clientSources); } } else { spiltHelper(manifest, merged, common, client, null, null); } - } - } private static void spiltHelper( java.util.jar.Manifest manifest, ZipInputStream merged, ZipOutputStream common, ZipOutputStream client, - @Nullable ZipOutputStream commonSources, @Nullable ZipOutputStream clientSources - ) throws IOException { + @Nullable ZipOutputStream commonSources, @Nullable ZipOutputStream clientSources) throws IOException { var sourceDistName = new Attributes.Name("Minecraft-Dist"); for (var entry = merged.getNextEntry(); entry != null; entry = merged.getNextEntry()) { if (entry.isDirectory()) { @@ -112,5 +106,4 @@ private static void spiltHelper( } } } - } From 000df9403d2f4e13fc6b489980eab28ca3514ca2 Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 23:25:18 +0800 Subject: [PATCH 3/6] fix test --- .../moddevgradle/internal/ModDevArtifactsWorkflow.java | 3 --- .../net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java | 3 +-- src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java | 3 +++ 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java index b382561c..a8465d84 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java @@ -190,9 +190,6 @@ public static ModDevArtifactsWorkflow create(Project project, }); var splitMergedJar = tasks.register("splitMergedJar", SplitMergedJar.class, task -> { - if (!splitDist) { - throw new IllegalStateException("Can't request split dist result when splitDist is disabled!"); - } task.getClientResourcesJar().set(createArtifacts.flatMap(CreateMinecraftArtifacts::getResourcesArtifact)); task.getClientJar().set(artifactPathStrategy.apply(WorkflowArtifact.CLIENT)); task.getCommonJar().set(artifactPathStrategy.apply(WorkflowArtifact.COMMON)); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java index eefd82e5..3257029d 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java @@ -272,8 +272,7 @@ public static void setupRuns( if (!versionCapabilities.modLocatorRework()) { // TODO: do this properly now that we have a flag in the version capabilities // This will explicitly be replaced in RunUtils to make this work for IDEs - boolean isClient = run.getType().get().startsWith("client"); - run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient).getClassesArgument()); + run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, true).getClassesArgument()); } var prepareRunTask = setupRunInGradle( project, diff --git a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java index e51c87e4..3b557e2e 100644 --- a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java +++ b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java @@ -43,6 +43,9 @@ public SplitMergedJar() {} @TaskAction public void splitMergedJar() throws IOException { + if (!getClientSourcesJar().isPresent()) { + throw new IllegalStateException("Can't request split dist result when splitDist is disabled!"); + } try ( var clientResources = new JarFile(getClientResourcesJar().get().getAsFile()); var merged = new ZipInputStream(new BufferedInputStream(Files.newInputStream(getMergedJar().get().getAsFile().toPath()))); From 9c97353627beb7c4642ffc00dae3dd9ff84f813f Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 23:44:50 +0800 Subject: [PATCH 4/6] Pass run type instead of isClient --- .../moddevgradle/internal/EclipseIntegration.java | 7 +++---- .../moddevgradle/internal/IntelliJIntegration.java | 11 +++++------ .../moddevgradle/internal/ModDevRunWorkflow.java | 10 ++++------ .../net/neoforged/moddevgradle/internal/RunUtils.java | 11 ++++++----- .../moddevgradle/internal/VsCodeIntegration.java | 3 +-- 5 files changed, 19 insertions(+), 23 deletions(-) diff --git a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java index fd7e7ced..32cef5e0 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/EclipseIntegration.java @@ -154,8 +154,7 @@ private void addEclipseLaunchConfiguration(Project project, } // This is the actual main launch configuration that launches the game - boolean isClient = run.getType().get().startsWith("client"); - var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, isClient); + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, run.getType()); var config = JavaApplicationLaunchConfig.builder(eclipseProjectName) .vmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())), @@ -170,12 +169,12 @@ private void addEclipseLaunchConfiguration(Project project, protected static ModFoldersProvider getModFoldersProvider(Project project, Provider> modsProvider, @Nullable Provider testedMod, - boolean isClient) { + Provider runType) { var folders = RunUtils.buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { output.from(RunUtils.findSourceSetProject(project, sourceSet).getProjectDir().toPath() .resolve("bin") .resolve(sourceSet.getName())); - }, isClient); + }, runType); var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); modFoldersProvider.getModFolders().set(folders); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java index 583ebf0b..d1a4dcb7 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/IntelliJIntegration.java @@ -122,7 +122,7 @@ public void configureTesting(Provider> loadedMods, var intellijVmArgsFile = runArgsDir.map(dir -> dir.file("intellijVmArgs.txt")); var outputDirectory = IntelliJOutputDirectoryValueSource.getIntellijOutputDirectory(project); - var ideSpecificVmArgs = RunUtils.escapeJvmArg(getModFoldersProvider(project, outputDirectory, loadedMods, testedMod, true).getArgument()); + var ideSpecificVmArgs = RunUtils.escapeJvmArg(getModFoldersProvider(project, outputDirectory, loadedMods, testedMod, project.provider(() -> "client")).getArgument()); try { var vmArgsFilePath = intellijVmArgsFile.get().getAsFile().toPath(); Files.createDirectories(vmArgsFilePath.getParent()); @@ -185,8 +185,7 @@ private static void addIntelliJRunConfiguration(Project project, } appRun.setModuleName(getIntellijModuleName(project, sourceSet)); appRun.setWorkingDirectory(run.getGameDirectory().get().getAsFile().getAbsolutePath()); - boolean isClient = run.getType().get().startsWith("client"); - var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null, isClient); + var modFoldersProvider = getModFoldersProvider(project, outputDirectory, run.getLoadedMods(), null, run.getType()); appRun.setEnvs(RunUtils.replaceModClassesEnv(run, modFoldersProvider)); appRun.setJvmArgs( RunUtils.escapeJvmArg(RunUtils.getArgFileParameter(prepareTask.getVmArgsFile().get())) @@ -234,15 +233,15 @@ private static ModFoldersProvider getModFoldersProvider(Project project, @Nullable Function outputDirectory, Provider> modsProvider, @Nullable Provider testedMod, - boolean isClient) { + Provider runType) { Provider> folders; if (outputDirectory != null) { folders = RunUtils.buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { var sourceSetDir = outputDirectory.apply(RunUtils.findSourceSetProject(project, sourceSet)).toPath().resolve(getIdeaOutName(sourceSet)); output.from(sourceSetDir.resolve("classes"), sourceSetDir.resolve("resources")); - }, isClient); + }, runType); } else { - folders = RunUtils.getModFoldersForGradle(project, modsProvider, testedMod, isClient); + folders = RunUtils.getModFoldersForGradle(project, modsProvider, testedMod, runType); } var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java index 3257029d..db574df6 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java @@ -272,7 +272,7 @@ public static void setupRuns( if (!versionCapabilities.modLocatorRework()) { // TODO: do this properly now that we have a flag in the version capabilities // This will explicitly be replaced in RunUtils to make this work for IDEs - run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, true).getClassesArgument()); + run.getEnvironment().put("MOD_CLASSES", RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, run.getType()).getClassesArgument()); } var prepareRunTask = setupRunInGradle( project, @@ -405,8 +405,7 @@ private static TaskProvider setupRunInGradle( task.getVmArgsFile().set(prepareRunTask.get().getVmArgsFile().map(d -> d.getAsFile().getAbsolutePath())); task.getProgramArgsFile().set(prepareRunTask.get().getProgramArgsFile().map(d -> d.getAsFile().getAbsolutePath())); task.getEnvironment().set(run.getEnvironment()); - boolean isClient = run.getType().get().startsWith("client"); - task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient)); + task.getModFolders().set(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, run.getType())); }); createLaunchScriptsTask.configure(task -> task.dependsOn(launchScriptTask)); @@ -429,8 +428,7 @@ private static TaskProvider setupRunInGradle( // Of course we need the arg files to be up-to-date ;) task.dependsOn(prepareRunTask); task.dependsOn(run.getTasksBefore()); - boolean isClient = run.getType().get().startsWith("client"); - task.getJvmArgumentProviders().add(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, isClient)); + task.getJvmArgumentProviders().add(RunUtils.getGradleModFoldersProvider(project, run.getLoadedMods(), null, run.getType())); }); return prepareRunTask; @@ -525,7 +523,7 @@ static void setupTestTask(Project project, task.systemProperty("fml.junit.argsfile", programArgsFile.get().getAsFile().getAbsolutePath()); task.jvmArgs(RunUtils.getArgFileParameter(vmArgsFile.get())); - var modFoldersProvider = RunUtils.getGradleModFoldersProvider(project, loadedMods, testedMod, true); + var modFoldersProvider = RunUtils.getGradleModFoldersProvider(project, loadedMods, testedMod, project.provider(() -> "client")); task.getJvmArgumentProviders().add(modFoldersProvider); }); diff --git a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java index 0d1cc36a..c0bbedbc 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/RunUtils.java @@ -171,9 +171,9 @@ public static String getArgFileParameter(RegularFile argFile) { return "@" + argFile.getAsFile().getAbsolutePath(); } - public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod, boolean isClient) { + public static ModFoldersProvider getGradleModFoldersProvider(Project project, Provider> modsProvider, Provider testedMod, Provider runType) { var modFoldersProvider = project.getObjects().newInstance(ModFoldersProvider.class); - modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod, isClient)); + modFoldersProvider.getModFolders().set(getModFoldersForGradle(project, modsProvider, testedMod, runType)); return modFoldersProvider; } @@ -216,17 +216,17 @@ public static Map replaceModClassesEnv(RunModel model, ModFolder public static Provider> getModFoldersForGradle(Project project, Provider> modsProvider, @Nullable Provider testedMod, - boolean isClient) { + Provider runType) { return buildModFolders(project, modsProvider, testedMod, (sourceSet, output) -> { output.from(sourceSet.getOutput()); - }, isClient); + }, runType); } public static Provider> buildModFolders(Project project, Provider> modsProvider, @Nullable Provider testedModProvider, BiConsumer outputFolderResolver, - boolean isClient) { + Provider runType) { // Convert it to optional to ensure zip will be called even if no mod under test is present. if (testedModProvider == null) { testedModProvider = project.provider(() -> null); @@ -255,6 +255,7 @@ public static Provider> buildModFolders(Project project, outputFolderResolver.accept(sourceSet, modFolder.getFolders()); } + boolean isClient = runType.get().startsWith("client"); if (isClient) { var clientSourceSets = mod.getModClientSourceSets().get(); for (int i = 0; i < clientSourceSets.size(); ++i) { diff --git a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java index 0ea06fc9..67d8c1d9 100644 --- a/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java +++ b/src/main/java/net/neoforged/moddevgradle/internal/VsCodeIntegration.java @@ -67,8 +67,7 @@ private void addVscodeLaunchConfiguration(Project project, eclipseModel.autoBuildTasks(run.getTasksBefore().toArray()); } - boolean isClient = run.getType().get().startsWith("client"); - var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, isClient); + var modFoldersProvider = getModFoldersProvider(project, run.getLoadedMods(), null, run.getType()); launchWriter.createGroup("Mod Development - " + project.getName(), WritingMode.REMOVE_EXISTING) .createLaunchConfiguration() .withName(runIdeName) From d58ddcd63e9df87657ac032a9981c96f1b4150db Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 23:49:40 +0800 Subject: [PATCH 5/6] fix incorrect reference --- src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java index 3b557e2e..12d54181 100644 --- a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java +++ b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java @@ -43,7 +43,7 @@ public SplitMergedJar() {} @TaskAction public void splitMergedJar() throws IOException { - if (!getClientSourcesJar().isPresent()) { + if (!getClientResourcesJar().isPresent()) { throw new IllegalStateException("Can't request split dist result when splitDist is disabled!"); } try ( From 4dc16d39d2bece920dd5a213e867eab33e122b8a Mon Sep 17 00:00:00 2001 From: vfyjxf <2331007009@qq.com> Date: Sun, 5 Apr 2026 23:51:53 +0800 Subject: [PATCH 6/6] fix import --- src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java index 12d54181..deefec3c 100644 --- a/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java +++ b/src/main/java/net/neoforged/nfrtgradle/SplitMergedJar.java @@ -6,6 +6,7 @@ import java.nio.file.Files; import java.util.jar.Attributes; import java.util.jar.JarFile; +import java.util.jar.Manifest; import java.util.zip.ZipInputStream; import java.util.zip.ZipOutputStream; import javax.inject.Inject; @@ -68,7 +69,7 @@ public void splitMergedJar() throws IOException { } private static void spiltHelper( - java.util.jar.Manifest manifest, + Manifest manifest, ZipInputStream merged, ZipOutputStream common, ZipOutputStream client, @Nullable ZipOutputStream commonSources, @Nullable ZipOutputStream clientSources) throws IOException { var sourceDistName = new Attributes.Name("Minecraft-Dist");