Skip to content

Commit ac2c6fe

Browse files
committed
Expose version, minecraft version and version capabilities on the extension
1 parent afe9bbe commit ac2c6fe

File tree

6 files changed

+219
-67
lines changed

6 files changed

+219
-67
lines changed

src/main/java/net/neoforged/moddevgradle/dsl/ModDevExtension.java

+27-2
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,8 @@
33
import net.neoforged.moddevgradle.internal.Branding;
44
import net.neoforged.moddevgradle.internal.IdeIntegration;
55
import net.neoforged.moddevgradle.internal.ModDevArtifactsWorkflow;
6-
import net.neoforged.moddevgradle.internal.utils.ExtensionUtils;
6+
import net.neoforged.moddevgradle.internal.utils.VersionCapabilities;
77
import org.gradle.api.Action;
8-
import org.gradle.api.GradleException;
98
import org.gradle.api.NamedDomainObjectContainer;
109
import org.gradle.api.Project;
1110
import org.gradle.api.Task;
@@ -14,6 +13,7 @@
1413
import org.gradle.api.provider.Property;
1514
import org.gradle.api.tasks.SourceSet;
1615
import org.gradle.api.tasks.TaskProvider;
16+
import org.jetbrains.annotations.Nullable;
1717

1818
import javax.inject.Inject;
1919
import java.io.File;
@@ -158,4 +158,29 @@ public void ideSyncTask(Task task) {
158158
public void addModdingDependenciesTo(SourceSet sourceSet) {
159159
ModDevArtifactsWorkflow.get(project).addToSourceSet(sourceSet);
160160
}
161+
162+
/**
163+
* After enabling modding, you can retrieve the version of the modding platform you picked using this getter.
164+
* I.e. the NeoForge or Forge version. If you chose to enable vanilla-only mode, this getter returns null.
165+
*/
166+
@Nullable
167+
public String getVersion() {
168+
var dependencies = ModDevArtifactsWorkflow.get(project).dependencies();
169+
return dependencies.neoForgeDependency() != null ? dependencies.neoForgeDependency().getVersion() : null;
170+
}
171+
172+
/**
173+
* After enabling modding, you can retrieve the effective Minecraft version using this getter.
174+
*/
175+
@Nullable
176+
public String getMinecraftVersion() {
177+
return ModDevArtifactsWorkflow.get(project).versionCapabilities().minecraftVersion();
178+
}
179+
180+
/**
181+
* After enabling modding, you can retrieve the capabilities of the version you picked using this getter.
182+
*/
183+
public VersionCapabilities getVersionCapabilities() {
184+
return ModDevArtifactsWorkflow.get(project).versionCapabilities();
185+
}
161186
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package net.neoforged.moddevgradle.dsl;
2+
3+
/**
4+
* Describes the capabilities of the currently chosen version of Minecraft.
5+
*/
6+
public interface VersionCapabilities {
7+
/**
8+
* The Java version used by this version of Minecraft.
9+
*/
10+
int javaVersion();
11+
12+
/**
13+
* Whether this version of Minecraft uses separate data-generation runs for client and server data.
14+
*/
15+
boolean splitDataRuns();
16+
17+
/**
18+
* Whether the NeoForge version for this version of Minecraft supports mod-loading in unit tests.
19+
*/
20+
boolean testFixtures();
21+
}

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,12 @@ public record ModDevArtifactsWorkflow(
5050
Provider<Directory> modDevBuildDir,
5151
Provider<Directory> artifactsBuildDir
5252
) {
53-
5453
private static final String EXTENSION_NAME = "__internal_modDevArtifactsWorkflow";
5554

5655
public static ModDevArtifactsWorkflow get(Project project) {
5756
var result = ExtensionUtils.findExtension(project, EXTENSION_NAME, ModDevArtifactsWorkflow.class);
5857
if (result == null) {
59-
throw new IllegalStateException("Mod development has not been enabled yet for project " + project);
58+
throw new InvalidUserCodeException("Mod development has not been enabled yet for project " + project);
6059
}
6160
return result;
6261
}

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

+50-16
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,21 @@
99

1010
/**
1111
* Models the changing capabilities of the modding platform and Vanilla, which we tie to the Minecraft version.
12-
* @param javaVersion Which Java version Vanilla uses to compile and run.
13-
* @param splitDataRuns Whether Vanilla has separate main classes for generating client and server data.
14-
* @param testFixtures If the NeoForge version for this Minecraft version supports test fixtures.
12+
*
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.
1517
*/
16-
public record VersionCapabilities(int javaVersion, boolean splitDataRuns, boolean testFixtures) implements Serializable {
18+
public record VersionCapabilities(String minecraftVersion, int javaVersion, boolean splitDataRuns,
19+
boolean testFixtures) implements net.neoforged.moddevgradle.dsl.VersionCapabilities, Serializable {
1720
private static final Logger LOG = LoggerFactory.getLogger(VersionCapabilities.class);
1821

19-
private static final VersionCapabilities LATEST = new VersionCapabilities(21, true, true);
22+
private static final VersionCapabilities LATEST = new VersionCapabilities(MinecraftVersionList.VERSIONS.get(0), 21, true, true);
2023

2124
private static final Pattern NEOFORGE_PATTERN = Pattern.compile("^(\\d+\\.\\d+)\\.\\d+(|-.*)$");
25+
// Strips NeoForm timestamp suffixes OR dynamic version markers
26+
private static final Pattern NEOFORM_PATTERN = Pattern.compile("^(.*)-(?:\\+|\\d{8}\\.\\d{6})$");
2227

2328
private static final int MC_24W45A_INDEX = getReferenceVersionIndex("24w45a");
2429
private static final int MC_24W14A_INDEX = getReferenceVersionIndex("24w14a");
@@ -34,18 +39,23 @@ public static VersionCapabilities ofMinecraftVersion(String minecraftVersion) {
3439
var versionIndex = MinecraftVersionList.VERSIONS.indexOf(minecraftVersion);
3540
if (versionIndex == -1) {
3641
LOG.info("Minecraft Version {} is unknown. Assuming latest capabilities.", versionIndex);
37-
return LATEST;
42+
return LATEST.withMinecraftVersion(minecraftVersion);
3843
}
3944

4045
return ofVersionIndex(versionIndex);
4146
}
4247

4348
public static VersionCapabilities ofVersionIndex(int versionIndex) {
49+
var minecraftVersion = MinecraftVersionList.VERSIONS.get(versionIndex);
50+
return ofVersionIndex(versionIndex, minecraftVersion);
51+
}
52+
53+
public static VersionCapabilities ofVersionIndex(int versionIndex, String minecraftVersion) {
4454
var javaVersion = getJavaVersion(versionIndex);
4555
var splitData = hasSplitDataEntrypoints(versionIndex);
4656
var testFixtures = hasTestFixtures(versionIndex);
4757

48-
return new VersionCapabilities(javaVersion, splitData, testFixtures);
58+
return new VersionCapabilities(minecraftVersion, javaVersion, splitData, testFixtures);
4959
}
5060

5161
static int getJavaVersion(int versionIndex) {
@@ -86,23 +96,38 @@ static int indexOfNeoForgeVersion(String version) {
8696
public static VersionCapabilities ofNeoForgeVersion(String version) {
8797
var index = indexOfNeoForgeVersion(version);
8898
if (index == -1) {
89-
LOG.warn("Failed to parse MC version from NeoForge version {}. Using capabilities of latest known Minecraft version.", version);
90-
return LATEST;
99+
var capabilities = LATEST;
100+
var m = NEOFORGE_PATTERN.matcher(version);
101+
if (m.matches()) {
102+
var minecraftVersion = "1." + m.group(1);
103+
if (minecraftVersion.endsWith(".0")) {
104+
minecraftVersion = minecraftVersion.substring(0, minecraftVersion.length() - 2);
105+
}
106+
capabilities = capabilities.withMinecraftVersion(minecraftVersion);
107+
}
108+
109+
LOG.warn("Failed to parse MC version from NeoForge version {}. Using capabilities of latest known Minecraft version with Minecraft version {}.", version, capabilities.minecraftVersion());
110+
return capabilities;
91111
}
92112

93113
return ofVersionIndex(index);
94114
}
95115

96-
static int indexOfNeoFormVersion(String version) {
116+
public static VersionCapabilities ofNeoFormVersion(String version) {
97117
// Examples: 1.21-<timestamp>
98-
return MinecraftVersionList.indexOfByPrefix(version, "-");
99-
}
118+
var index = MinecraftVersionList.indexOfByPrefix(version, "-");
100119

101-
public static VersionCapabilities ofNeoFormVersion(String version) {
102-
var index = indexOfNeoFormVersion(version);
103120
if (index == -1) {
104-
LOG.warn("Failed to parse MC version from NeoForm version {}. Using capabilities of latest known Minecraft version.", version);
105-
return LATEST;
121+
var capabilities = LATEST;
122+
var m = NEOFORM_PATTERN.matcher(version);
123+
if (m.matches()) {
124+
capabilities = capabilities.withMinecraftVersion(m.group(1));
125+
} else {
126+
capabilities = capabilities.withMinecraftVersion(version);
127+
}
128+
129+
LOG.warn("Failed to parse MC version from NeoForm version {}. Using capabilities of latest known Minecraft version with Minecraft version {}.", version, capabilities.minecraftVersion());
130+
return capabilities;
106131
}
107132

108133
return ofVersionIndex(index);
@@ -130,4 +155,13 @@ private static int getReferenceVersionIndex(String v) {
130155
}
131156
return idx;
132157
}
158+
159+
public VersionCapabilities withMinecraftVersion(String minecraftVersion) {
160+
return new VersionCapabilities(
161+
minecraftVersion,
162+
javaVersion,
163+
splitDataRuns,
164+
testFixtures
165+
);
166+
}
133167
}

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

+105-28
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,20 @@
33
import net.neoforged.moddevgradle.AbstractProjectBuilderTest;
44
import net.neoforged.moddevgradle.dsl.NeoForgeExtension;
55
import net.neoforged.moddevgradle.internal.utils.ExtensionUtils;
6+
import net.neoforged.moddevgradle.internal.utils.VersionCapabilities;
67
import org.gradle.api.InvalidUserCodeException;
7-
import org.gradle.api.Project;
88
import org.gradle.api.Task;
99
import org.gradle.api.plugins.JavaPluginExtension;
1010
import org.gradle.api.tasks.SourceSet;
1111
import org.gradle.jvm.toolchain.JavaLanguageVersion;
1212
import org.gradle.testfixtures.ProjectBuilder;
13+
import org.junit.jupiter.api.Nested;
1314
import org.junit.jupiter.api.Test;
1415

1516
import java.util.Set;
1617

1718
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.junit.jupiter.api.Assertions.assertEquals;
1820
import static org.junit.jupiter.api.Assertions.assertThrows;
1921

2022
public class ModDevPluginTest extends AbstractProjectBuilderTest {
@@ -39,32 +41,15 @@ public ModDevPluginTest() {
3941

4042
@Test
4143
void testModdingCannotBeEnabledTwice() {
42-
extension.setVersion("1.2.3");
43-
var e = assertThrows(InvalidUserCodeException.class, () -> extension.setVersion("1.2.3"));
44+
extension.setVersion("2.3.0");
45+
var e = assertThrows(InvalidUserCodeException.class, () -> extension.setVersion("2.3.0"));
4446
assertThat(e).hasMessage("You cannot enable modding in the same project twice.");
4547
}
4648

47-
@Test
48-
void testEnableVanillaOnlyMode() {
49-
extension.setNeoFormVersion("1.2.3");
50-
51-
assertThatDependencies(mainSourceSet.getCompileClasspathConfigurationName())
52-
.containsOnly(
53-
"build/moddev/artifacts/vanilla-1.2.3.jar",
54-
"net.neoforged:neoform:1.2.3[net.neoforged:neoform-dependencies]"
55-
);
56-
assertThatDependencies(mainSourceSet.getRuntimeClasspathConfigurationName())
57-
.containsOnly(
58-
"build/moddev/artifacts/vanilla-1.2.3.jar",
59-
"build/moddev/artifacts/vanilla-1.2.3-client-extra-aka-minecraft-resources.jar",
60-
"net.neoforged:neoform:1.2.3[net.neoforged:neoform-dependencies]"
61-
);
62-
}
63-
6449
@Test
6550
void testEnableForTestSourceSetOnly() {
6651
extension.enable(settings -> {
67-
settings.setVersion("1.2.3");
52+
settings.setVersion("2.3.0");
6853
settings.setEnabledSourceSets(Set.of(testSourceSet));
6954
});
7055

@@ -73,25 +58,117 @@ void testEnableForTestSourceSetOnly() {
7358
assertThatDependencies(mainSourceSet.getRuntimeClasspathConfigurationName()).isEmpty();
7459

7560
// While the test classpath should have modding dependencies
76-
assertContainsModdingCompileDependencies("1.2.3", testSourceSet.getCompileClasspathConfigurationName());
77-
assertContainsModdingRuntimeDependencies("1.2.3", testSourceSet.getRuntimeClasspathConfigurationName());
61+
assertContainsModdingCompileDependencies("2.3.0", testSourceSet.getCompileClasspathConfigurationName());
62+
assertContainsModdingRuntimeDependencies("2.3.0", testSourceSet.getRuntimeClasspathConfigurationName());
7863
}
7964

8065
@Test
8166
void testAddModdingDependenciesTo() {
82-
extension.setVersion("1.2.3");
67+
extension.setVersion("2.3.0");
8368

8469
// Initially, only the main source set should have the dependencies
85-
assertContainsModdingCompileDependencies("1.2.3", mainSourceSet.getCompileClasspathConfigurationName());
86-
assertContainsModdingRuntimeDependencies("1.2.3", mainSourceSet.getRuntimeClasspathConfigurationName());
70+
assertContainsModdingCompileDependencies("2.3.0", mainSourceSet.getCompileClasspathConfigurationName());
71+
assertContainsModdingRuntimeDependencies("2.3.0", mainSourceSet.getRuntimeClasspathConfigurationName());
8772
assertThatDependencies(testSourceSet.getCompileClasspathConfigurationName()).isEmpty();
8873
assertThatDependencies(testSourceSet.getRuntimeClasspathConfigurationName()).isEmpty();
8974

9075
// Now add it to the test source set too
9176
extension.addModdingDependenciesTo(testSourceSet);
9277

93-
assertContainsModdingCompileDependencies("1.2.3", testSourceSet.getCompileClasspathConfigurationName());
94-
assertContainsModdingRuntimeDependencies("1.2.3", testSourceSet.getRuntimeClasspathConfigurationName());
78+
assertContainsModdingCompileDependencies("2.3.0", testSourceSet.getCompileClasspathConfigurationName());
79+
assertContainsModdingRuntimeDependencies("2.3.0", testSourceSet.getRuntimeClasspathConfigurationName());
80+
}
81+
82+
@Test
83+
void testGetVersion() {
84+
extension.setVersion("2.3.0");
85+
assertEquals("2.3.0", extension.getVersion());
86+
}
87+
88+
@Test
89+
void testGetVersionCapabilities() {
90+
extension.setVersion("2.3.0");
91+
assertEquals(VersionCapabilities.ofMinecraftVersion("1.2.3"), extension.getVersionCapabilities());
92+
assertEquals("1.2.3", extension.getVersionCapabilities().minecraftVersion());
93+
}
94+
95+
@Test
96+
void testGetMinecraftVersion() {
97+
extension.setVersion("2.3.0-suffixstuff");
98+
assertEquals("1.2.3", extension.getMinecraftVersion());
99+
}
100+
101+
@Nested
102+
class VanillaOnlyMode {
103+
final static String VERSION = "1.21.4-20240101.235959";
104+
105+
@Test
106+
void testEnable() {
107+
extension.setNeoFormVersion(VERSION);
108+
109+
assertThatDependencies(mainSourceSet.getCompileClasspathConfigurationName())
110+
.containsOnly(
111+
"build/moddev/artifacts/vanilla-" + VERSION + ".jar",
112+
"net.neoforged:neoform:" + VERSION + "[net.neoforged:neoform-dependencies]"
113+
);
114+
assertThatDependencies(mainSourceSet.getRuntimeClasspathConfigurationName())
115+
.containsOnly(
116+
"build/moddev/artifacts/vanilla-" + VERSION + ".jar",
117+
"build/moddev/artifacts/vanilla-" + VERSION + "-client-extra-aka-minecraft-resources.jar",
118+
"net.neoforged:neoform:" + VERSION + "[net.neoforged:neoform-dependencies]"
119+
);
120+
}
121+
122+
@Test
123+
void testGetVersion() {
124+
extension.setNeoFormVersion(VERSION);
125+
assertEquals(VersionCapabilities.ofNeoFormVersion(VERSION), extension.getVersionCapabilities());
126+
}
127+
128+
@Test
129+
void testGetMinecraftVersion() {
130+
extension.setNeoFormVersion(VERSION);
131+
assertEquals("1.21.4", extension.getMinecraftVersion());
132+
}
133+
134+
@Test
135+
void testGetVersionCapabilities() {
136+
extension.setNeoFormVersion(VERSION);
137+
assertEquals(VersionCapabilities.ofNeoFormVersion(VERSION), extension.getVersionCapabilities());
138+
}
139+
140+
@Test
141+
void testGetVersionCapabilitiesForUnknownVersion() {
142+
extension.setNeoFormVersion("1.99.1-20990101.235959");
143+
// Should use latest features, but with the specified Minecraft version
144+
assertEquals(
145+
VersionCapabilities.latest().withMinecraftVersion("1.99.1"),
146+
extension.getVersionCapabilities()
147+
);
148+
}
149+
}
150+
151+
@Nested
152+
class CannotCallWhenModdingIsNotEnabled {
153+
static String expectedMessage = "Mod development has not been enabled yet for project root project 'test'";
154+
155+
@Test
156+
void testGettingMinecraftVersionThrows() {
157+
var e = assertThrows(InvalidUserCodeException.class, extension::getVersionCapabilities);
158+
assertThat(e).hasMessage(expectedMessage);
159+
}
160+
161+
@Test
162+
void testGettingVersionCapabilitiesThrows() {
163+
var e = assertThrows(InvalidUserCodeException.class, extension::getVersion);
164+
assertThat(e).hasMessage(expectedMessage);
165+
}
166+
167+
@Test
168+
void testAddModdingDependenciesToThrows() {
169+
var e = assertThrows(InvalidUserCodeException.class, () -> extension.addModdingDependenciesTo(mainSourceSet));
170+
assertThat(e).hasMessage(expectedMessage);
171+
}
95172
}
96173

97174
private void assertContainsModdingCompileDependencies(String version, String configurationName) {

0 commit comments

Comments
 (0)