Skip to content

Commit 7002c31

Browse files
Technici4nshartte
andauthored
Support for 26.1 / unobfuscated Minecraft (#298)
Co-authored-by: Sebastian Hartte <[email protected]>
1 parent 1c72eb0 commit 7002c31

File tree

23 files changed

+167
-109
lines changed

23 files changed

+167
-109
lines changed

src/generated/java/net/neoforged/moddevgradle/internal/generated/MinecraftVersionList.java

Lines changed: 17 additions & 17 deletions
Large diffs are not rendered by default.

src/main/java/net/neoforged/moddevgradle/internal/ArtifactNamingStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ static ArtifactNamingStrategy createVanilla(String version) {
1212
};
1313
}
1414

15+
static ArtifactNamingStrategy createVanillaPatched(String loaderVersion) {
16+
return artifact -> "minecraft-patched-%s%s.jar".formatted(loaderVersion, artifact.defaultSuffix);
17+
}
18+
1519
static ArtifactNamingStrategy createNeoForge(VersionCapabilitiesInternal versionCapabilities, String loader, String version) {
1620
return (artifact) -> {
1721
if (artifact != WorkflowArtifact.CLIENT_RESOURCES || versionCapabilities.modLocatorRework()) {

src/main/java/net/neoforged/moddevgradle/internal/ModDevArtifactsWorkflow.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,13 @@ public static ModDevArtifactsWorkflow create(Project project,
123123
task.getToolsJavaExecutable().set(javaToolchainService
124124
.launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.of(versionCapabilities.javaVersion())))
125125
.map(javaLauncher -> javaLauncher.getExecutablePath().getAsFile().getAbsolutePath()));
126+
// NFRT itself needs to run with a newer version of the JDK to be able to compile with -release 25, for example
127+
// It can however not run with Java 25 and compile Java 8 code while maintaining the same lambda naming.
128+
if (versionCapabilities.javaVersion() > 21) {
129+
task.getJavaExecutable().set(javaToolchainService
130+
.launcherFor(spec -> spec.getLanguageVersion().set(JavaLanguageVersion.of(versionCapabilities.javaVersion())))
131+
.map(javaLauncher -> javaLauncher.getExecutablePath().getAsFile().getAbsolutePath()));
132+
}
126133

127134
task.getAccessTransformers().from(accessTransformers);
128135
// If AT validation is enabled, add the user-supplied AT paths as files to be validated,
@@ -142,14 +149,17 @@ public static ModDevArtifactsWorkflow create(Project project,
142149

143150
Function<WorkflowArtifact, Provider<RegularFile>> artifactPathStrategy = artifact -> artifactsBuildDir.map(dir -> dir.file(artifactNamingStrategy.getFilename(artifact)));
144151

152+
task.getIncludeNeoForgeInGameJar().set(versionCapabilities.needsNeoForgeInMinecraftJar());
145153
task.getGameJarArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.COMPILED));
146-
task.getResourcesArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.CLIENT_RESOURCES));
147154
if (disableRecompilation) {
148155
task.getDisableRecompilation().set(true);
149156
} else {
150157
task.getGameJarWithSourcesArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.COMPILED_WITH_SOURCES));
151158
task.getGameSourcesArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.SOURCES));
152159
}
160+
if (versionCapabilities.needsNeoForgeInMinecraftJar()) {
161+
task.getResourcesArtifact().set(artifactPathStrategy.apply(WorkflowArtifact.CLIENT_RESOURCES));
162+
}
153163

154164
task.getNeoForgeArtifact().set(moddingDependencies.neoForgeDependencyNotation());
155165
task.getNeoFormArtifact().set(moddingDependencies.neoFormDependencyNotation());
@@ -188,7 +198,11 @@ public static ModDevArtifactsWorkflow create(Project project,
188198
config.setCanBeConsumed(false);
189199

190200
config.getDependencies().addLater(minecraftClassesDependency);
191-
config.getDependencies().addLater(createArtifacts.map(task -> project.files(task.getResourcesArtifact())).map(dependencyFactory::create));
201+
if (versionCapabilities.needsNeoForgeInMinecraftJar()) {
202+
config.getDependencies().addLater(createArtifacts.map(task -> project.files(task.getResourcesArtifact())).map(dependencyFactory::create));
203+
} else if (moddingDependencies.neoForgeDependency() != null) {
204+
config.getDependencies().add(moddingDependencies.neoForgeDependency());
205+
}
192206
// Technically, the Minecraft dependencies do not strictly need to be on the classpath because they are pulled from the legacy class path.
193207
// However, we do it anyway because this matches production environments, and allows launch proxies such as DevLogin to use Minecraft's libraries.
194208
config.getDependencies().add(moddingDependencies.gameLibrariesDependency());
@@ -202,6 +216,9 @@ public static ModDevArtifactsWorkflow create(Project project,
202216
config.setCanBeConsumed(false);
203217
config.getDependencies().addLater(minecraftClassesDependency);
204218
config.getDependencies().add(moddingDependencies.gameLibrariesDependency());
219+
if (!versionCapabilities.needsNeoForgeInMinecraftJar() && moddingDependencies.neoForgeDependency() != null) {
220+
config.getDependencies().add(moddingDependencies.neoForgeDependency());
221+
}
205222
});
206223

207224
// For IDEs that support it, link the source/binary artifacts if we use separated ones

src/main/java/net/neoforged/moddevgradle/internal/ModDevPlugin.java

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,19 +73,21 @@ public void enable(
7373
var versionCapabilities = neoForgeVersion != null ? VersionCapabilitiesInternal.ofNeoForgeVersion(neoForgeVersion)
7474
: VersionCapabilitiesInternal.ofNeoFormVersion(neoFormVersion);
7575

76+
var configurations = project.getConfigurations();
77+
78+
var dependencies = neoForge != null ? ModdingDependencies.create(neoForge, neoForgeNotation, neoForm, neoFormNotation, versionCapabilities)
79+
: ModdingDependencies.createVanillaOnly(neoForm, neoFormNotation);
80+
7681
ArtifactNamingStrategy artifactNamingStrategy;
7782
// It's helpful to be able to differentiate the Vanilla jar and the NeoForge jar in classic multiloader setups.
78-
if (neoForge != null) {
83+
if (neoForge == null) {
84+
artifactNamingStrategy = ArtifactNamingStrategy.createVanilla(neoFormVersion);
85+
} else if (versionCapabilities.needsNeoForgeInMinecraftJar()) {
7986
artifactNamingStrategy = ArtifactNamingStrategy.createNeoForge(versionCapabilities, "neoforge", neoForgeVersion);
8087
} else {
81-
artifactNamingStrategy = ArtifactNamingStrategy.createVanilla(neoFormVersion);
88+
artifactNamingStrategy = ArtifactNamingStrategy.createVanillaPatched(neoForgeVersion);
8289
}
8390

84-
var configurations = project.getConfigurations();
85-
86-
var dependencies = neoForge != null ? ModdingDependencies.create(neoForge, neoForgeNotation, neoForm, neoFormNotation, versionCapabilities)
87-
: ModdingDependencies.createVanillaOnly(neoForm, neoFormNotation);
88-
8991
var artifacts = ModDevArtifactsWorkflow.create(
9092
project,
9193
settings.getEnabledSourceSets(),

src/main/java/net/neoforged/moddevgradle/internal/ModDevRunWorkflow.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,9 @@ private ModDevRunWorkflow(Project project,
104104
spec.setCanBeConsumed(false);
105105

106106
spec.getDependencies().add(gameLibrariesDependency);
107-
addClientResources(project, spec, artifactsWorkflow.createArtifacts());
107+
if (artifactsWorkflow.versionCapabilities().needsNeoForgeInMinecraftJar()) {
108+
addClientResources(project, spec, artifactsWorkflow.createArtifacts());
109+
}
108110
if (!versionCapabilities.modLocatorRework()) {
109111
// Forge expects to find the Forge and client-extra jar on the legacy classpath
110112
// Newer FML versions also search for it on the java.class.path.
@@ -221,7 +223,9 @@ public void configureTesting(Provider<ModModel> testedMod, Provider<Set<ModModel
221223
},
222224
legacyClassPath -> {
223225
legacyClassPath.getDependencies().add(gameLibrariesDependency);
224-
addClientResources(project, legacyClassPath, artifactsWorkflow.createArtifacts());
226+
if (artifactsWorkflow.versionCapabilities().needsNeoForgeInMinecraftJar()) {
227+
addClientResources(project, legacyClassPath, artifactsWorkflow.createArtifacts());
228+
}
225229
},
226230
artifactsWorkflow.downloadAssets().flatMap(DownloadAssets::getAssetPropertiesFile),
227231
artifactsWorkflow.versionCapabilities());

src/main/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilitiesInternal.java

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,32 @@
1010
/**
1111
* Models the changing capabilities of the modding platform and Vanilla, which we tie to the Minecraft version.
1212
*
13-
* @param minecraftVersion The Minecraft version.
14-
* @param javaVersion Which Java version Vanilla uses to compile and run.
15-
* @param splitDataRuns Whether Vanilla has separate main classes for generating client and server data.
16-
* @param testFixtures If the NeoForge version for this Minecraft version supports test fixtures.
13+
* @param minecraftVersion The Minecraft version.
14+
* @param javaVersion Which Java version Vanilla uses to compile and run.
15+
* @param splitDataRuns Whether Vanilla has separate main classes for generating client and server data.
16+
* @param testFixtures If the NeoForge version for this Minecraft version supports test fixtures.
17+
* @param needsNeoForgeInMinecraftJar The FML version shipped by NeoForge in this Minecraft version requires NeoForge
18+
* classes to be merged into the Minecraft jar to work.
1719
*/
1820
public record VersionCapabilitiesInternal(String minecraftVersion, int javaVersion, boolean splitDataRuns,
19-
boolean testFixtures, boolean modLocatorRework, boolean legacyClasspath) implements VersionCapabilities, Serializable {
21+
boolean testFixtures, boolean modLocatorRework, boolean legacyClasspath, boolean needsNeoForgeInMinecraftJar) implements VersionCapabilities, Serializable {
2022

2123
private static final Logger LOG = Logging.getLogger(VersionCapabilitiesInternal.class);
2224

23-
private static final VersionCapabilitiesInternal LATEST = ofVersionIndex(0);
24-
2525
private static final Pattern NEOFORGE_PATTERN = Pattern.compile("^(\\d+\\.\\d+)\\.\\d+(|-.*)$");
2626
// Strips NeoForm timestamp suffixes OR dynamic version markers
2727
private static final Pattern NEOFORM_PATTERN = Pattern.compile("^(.*)-(?:\\+|\\d{8}\\.\\d{6})$");
2828

29+
private static final int MC_1_21_11_INDEX = getReferenceVersionIndex("1.21.11");
2930
private static final int MC_1_21_9_INDEX = getReferenceVersionIndex("1.21.9");
3031
private static final int MC_24W45A_INDEX = getReferenceVersionIndex("24w45a");
3132
private static final int MC_1_20_5_INDEX = getReferenceVersionIndex("1.20.5");
3233
private static final int MC_24W14A_INDEX = getReferenceVersionIndex("24w14a");
3334
private static final int MC_1_20_4_INDEX = getReferenceVersionIndex("1.20.4");
3435
private static final int MC_1_18_PRE2_INDEX = getReferenceVersionIndex("1.18-pre2");
3536
private static final int MC_21W19A_INDEX = getReferenceVersionIndex("21w19a");
37+
38+
private static final VersionCapabilitiesInternal LATEST = ofVersionIndex(0);
3639
public static VersionCapabilitiesInternal latest() {
3740
return LATEST;
3841
}
@@ -58,12 +61,15 @@ public static VersionCapabilitiesInternal ofVersionIndex(int versionIndex, Strin
5861
var testFixtures = hasTestFixtures(versionIndex);
5962
var modLocatorRework = hasModLocatorRework(versionIndex);
6063
var legacyClasspath = hasLegacyClasspath(versionIndex);
64+
var needsNeoForgeInMinecraftJar = needsNeoForgeInMinecraftJar(versionIndex);
6165

62-
return new VersionCapabilitiesInternal(minecraftVersion, javaVersion, splitData, testFixtures, modLocatorRework, legacyClasspath);
66+
return new VersionCapabilitiesInternal(minecraftVersion, javaVersion, splitData, testFixtures, modLocatorRework, legacyClasspath, needsNeoForgeInMinecraftJar);
6367
}
6468

6569
static int getJavaVersion(int versionIndex) {
66-
if (versionIndex <= MC_24W14A_INDEX) {
70+
if (versionIndex < MC_1_21_11_INDEX) {
71+
return 25;
72+
} else if (versionIndex <= MC_24W14A_INDEX) {
6773
return 21;
6874
} else if (versionIndex <= MC_1_18_PRE2_INDEX) {
6975
return 17;
@@ -90,6 +96,10 @@ static boolean hasLegacyClasspath(int versionIndex) {
9096
return versionIndex > MC_1_21_9_INDEX;
9197
}
9298

99+
static boolean needsNeoForgeInMinecraftJar(int versionIndex) {
100+
return versionIndex >= MC_1_21_11_INDEX;
101+
}
102+
93103
static int indexOfNeoForgeVersion(String version) {
94104
// NeoForge omits the "1." at the start of the Minecraft version and just adds an incrementing last digit
95105
var matcher = NEOFORGE_PATTERN.matcher(version);
@@ -175,6 +185,7 @@ public VersionCapabilitiesInternal withMinecraftVersion(String minecraftVersion)
175185
splitDataRuns,
176186
testFixtures,
177187
modLocatorRework,
178-
legacyClasspath);
188+
legacyClasspath,
189+
needsNeoForgeInMinecraftJar);
179190
}
180191
}

src/main/java/net/neoforged/nfrtgradle/CreateMinecraftArtifacts.java

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import net.neoforged.problems.FileProblemReporter;
1212
import net.neoforged.problems.Problem;
1313
import org.gradle.api.GradleException;
14+
import org.gradle.api.InvalidUserCodeException;
1415
import org.gradle.api.file.ConfigurableFileCollection;
1516
import org.gradle.api.file.RegularFileProperty;
1617
import org.gradle.api.problems.Problems;
@@ -43,6 +44,8 @@ public CreateMinecraftArtifacts() {
4344
getDisableRecompilation().convention(false);
4445
getValidateAccessTransformers().convention(false);
4546
getParchmentEnabled().convention(false);
47+
getIncludeNeoForgeInGameJar().convention(true);
48+
getIncludeResourcesInGameJar().convention(false);
4649
}
4750

4851
/**
@@ -231,11 +234,35 @@ public RegularFileProperty getSourcesArtifact() {
231234
return getGameSourcesArtifact();
232235
}
233236

237+
/**
238+
* Controls whether NeoForge classes and resources are included in {@link #getGameJarArtifact()}, if
239+
* {@link #getNeoForgeArtifact()} is configured. Note that this option is mutually exclusive with {@link #getIncludeResourcesInGameJar()}.
240+
* <p>
241+
* Defaults to true.
242+
*/
243+
@Input
244+
@ApiStatus.Experimental
245+
public abstract Property<Boolean> getIncludeNeoForgeInGameJar();
246+
247+
/**
248+
* Controls whether the Minecraft resources (data, assets, etc.) are included in {@link #getGameJarArtifact()}
249+
* and similar artifacts.
250+
* <p>
251+
* Defaults to false.
252+
*/
253+
@Input
254+
@ApiStatus.Experimental
255+
public abstract Property<Boolean> getIncludeResourcesInGameJar();
256+
234257
@Inject
235258
protected abstract Problems getProblems();
236259

237260
@TaskAction
238261
public void createArtifacts() {
262+
if (getIncludeNeoForgeInGameJar().get() && getIncludeResourcesInGameJar().get()) {
263+
throw new InvalidUserCodeException("Cannot enable both includeNeoForgeInGameJar and includeResourcesInGameJar, since Minecraft and NeoForge resources clash.");
264+
}
265+
239266
var args = new ArrayList<String>();
240267
args.add("run");
241268

@@ -319,9 +346,10 @@ public void createArtifacts() {
319346
requestedResults.add(new RequestedResult("clientResources", getResourcesArtifact().get().getAsFile()));
320347
}
321348

349+
boolean includeNeoForgeInGameJar = getIncludeNeoForgeInGameJar().get();
322350
if (getDisableRecompilation().get()) {
323351
if (getGameJarArtifact().isPresent()) {
324-
if (getNeoForgeArtifact().isPresent()) {
352+
if (getNeoForgeArtifact().isPresent() && includeNeoForgeInGameJar) {
325353
requestedResults.add(new RequestedResult("gameJarNoRecompWithNeoForge", getGameJarArtifact().get().getAsFile()));
326354
} else {
327355
requestedResults.add(new RequestedResult("gameJarNoRecomp", getGameJarArtifact().get().getAsFile()));
@@ -333,7 +361,7 @@ public void createArtifacts() {
333361
if (getGameJarWithSourcesArtifact().isPresent()) {
334362
throw new IllegalArgumentException("Cannot request game jar with sources if recompilation is disabled.");
335363
}
336-
} else if (getNeoForgeArtifact().isPresent()) {
364+
} else if (getNeoForgeArtifact().isPresent() && includeNeoForgeInGameJar) {
337365
if (getGameJarArtifact().isPresent()) {
338366
requestedResults.add(new RequestedResult("gameJarWithNeoForge", getGameJarArtifact().get().getAsFile()));
339367
}

src/main/java/net/neoforged/nfrtgradle/NeoFormRuntimeTask.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ public abstract class NeoFormRuntimeTask extends DefaultTask {
7373
*/
7474
@Input
7575
@ApiStatus.Internal
76-
protected abstract Property<String> getJavaExecutable();
76+
public abstract Property<String> getJavaExecutable();
7777

7878
@Inject
7979
@ApiStatus.Internal

src/test/java/net/neoforged/moddevgradle/internal/ModDevPluginTest.java

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void testModdingCannotBeEnabledTwice() {
4848
@Test
4949
void testEnableForTestSourceSetOnly() {
5050
extension.enable(settings -> {
51-
settings.setVersion("100.3.0"); // Needs to be at least 20.5 to use paths for newer FML
51+
settings.setVersion("21.11.0"); // Needs to be at least 20.5 to use paths for newer FML
5252
settings.setEnabledSourceSets(Set.of(testSourceSet));
5353
});
5454

@@ -57,25 +57,25 @@ void testEnableForTestSourceSetOnly() {
5757
assertThatDependencies(mainSourceSet.getRuntimeClasspathConfigurationName()).isEmpty();
5858

5959
// While the test classpath should have modding dependencies
60-
assertContainsModdingCompileDependencies("100.3.0", testSourceSet.getCompileClasspathConfigurationName());
61-
assertContainsModdingRuntimeDependencies("100.3.0", testSourceSet.getRuntimeClasspathConfigurationName());
60+
assertContainsModdingCompileDependencies("21.11.0", testSourceSet.getCompileClasspathConfigurationName());
61+
assertContainsModdingRuntimeDependencies("21.11.0", testSourceSet.getRuntimeClasspathConfigurationName());
6262
}
6363

6464
@Test
6565
void testAddModdingDependenciesTo() {
66-
extension.setVersion("100.3.0"); // Needs to be at least 20.5 to use paths for newer FML
66+
extension.setVersion("21.11.0"); // Needs to be at least 20.5 to use paths for newer FML
6767

6868
// Initially, only the main source set should have the dependencies
69-
assertContainsModdingCompileDependencies("100.3.0", mainSourceSet.getCompileClasspathConfigurationName());
70-
assertContainsModdingRuntimeDependencies("100.3.0", mainSourceSet.getRuntimeClasspathConfigurationName());
69+
assertContainsModdingCompileDependencies("21.11.0", mainSourceSet.getCompileClasspathConfigurationName());
70+
assertContainsModdingRuntimeDependencies("21.11.0", mainSourceSet.getRuntimeClasspathConfigurationName());
7171
assertThatDependencies(testSourceSet.getCompileClasspathConfigurationName()).isEmpty();
7272
assertThatDependencies(testSourceSet.getRuntimeClasspathConfigurationName()).isEmpty();
7373

7474
// Now add it to the test source set too
7575
extension.addModdingDependenciesTo(testSourceSet);
7676

77-
assertContainsModdingCompileDependencies("100.3.0", testSourceSet.getCompileClasspathConfigurationName());
78-
assertContainsModdingRuntimeDependencies("100.3.0", testSourceSet.getRuntimeClasspathConfigurationName());
77+
assertContainsModdingCompileDependencies("21.11.0", testSourceSet.getCompileClasspathConfigurationName());
78+
assertContainsModdingRuntimeDependencies("21.11.0", testSourceSet.getRuntimeClasspathConfigurationName());
7979
}
8080

8181
@Test

src/test/java/net/neoforged/moddevgradle/internal/utils/VersionCapabilitiesInternalTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@ public class VersionCapabilitiesInternalTest {
1616
"24w45a,21",
1717
"24w44a,21",
1818
"1.21.3-pre1,21",
19-
"25w01a,21",
19+
"25w46a,21",
2020
"23w07a,17",
2121
"1.20,17",
2222
"1.20-pre1,17",
2323
"1.21,21",
2424
"1.21-pre1-20240529.150918,21",
2525
"1.21-pre1,21",
26-
"1.22,21",
27-
"1.22-pre1,21",
26+
"1.21.11,21",
27+
"26.1-snapshot-1,25",
2828
"1.0,8",
2929
"1.14.2 Pre-Release 2,8",
3030
"21w19a,16",

0 commit comments

Comments
 (0)