Skip to content

Commit 177bf3e

Browse files
committed
Support dynamically selecting MC Versions in vanilla mode.
1 parent 0e4a841 commit 177bf3e

5 files changed

Lines changed: 171 additions & 1 deletion

File tree

utils/src/main/java/net/neoforged/gradle/util/UrlConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ private UrlConstants() {
1212
public static final String MOJANG_MANIFEST = "https://piston-meta.mojang.com/mc/game/version_manifest.json";
1313
public static final String NEO_FORGE_MAVEN = "https://maven.neoforged.net/releases/";
1414
public static final String MOJANG_MAVEN = "https://libraries.minecraft.net/";
15+
public static final String MINECRAFT_METADATA = "https://maven.neoforged.net/mojang-meta";
1516
}
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
package net.neoforged.gradle.vanilla
2+
3+
import net.neoforged.trainingwheels.gradle.functional.BuilderBasedTestSpecification
4+
import org.gradle.testkit.runner.TaskOutcome
5+
6+
class VersionRangeTests extends BuilderBasedTestSpecification {
7+
8+
@Override
9+
protected void configurePluginUnderTest() {
10+
pluginUnderTest = "net.neoforged.gradle.vanilla";
11+
injectIntoAllProject = true;
12+
}
13+
14+
def "the vanilla runtime supports finding an mc version from a range"() {
15+
given:
16+
def project = create("vanilla_loads_from_a_range", {
17+
it.build("""
18+
java {
19+
toolchain {
20+
languageVersion = JavaLanguageVersion.of(21)
21+
}
22+
}
23+
24+
dependencies {
25+
implementation ('net.minecraft:client') {
26+
version {
27+
strictly '[1.21.6,1.21.7)'
28+
}
29+
}
30+
}
31+
""")
32+
33+
it.withToolchains()
34+
it.withGlobalCacheDirectory(tempDir)
35+
})
36+
37+
when:
38+
def initialRun = project.run {
39+
it.tasks('build')
40+
it.stacktrace()
41+
}
42+
43+
then:
44+
initialRun.task(":build").outcome == TaskOutcome.SUCCESS
45+
}
46+
47+
def "the_vanilla_runtime_supports_loading_a_range_with_a_preferred_option_chosen"() {
48+
given:
49+
def project = create("vanilla_supports_ats_from_file", {
50+
it.build("""
51+
java {
52+
toolchain {
53+
languageVersion = JavaLanguageVersion.of(21)
54+
}
55+
}
56+
57+
dependencies {
58+
implementation ('net.minecraft:client') {
59+
version {
60+
strictly '[1.21.6,1.21.7)'
61+
prefer '1.21.6'
62+
}
63+
}
64+
}
65+
""")
66+
67+
it.withToolchains()
68+
it.withGlobalCacheDirectory(tempDir)
69+
})
70+
71+
when:
72+
def initialRun = project.run {
73+
it.tasks('build')
74+
it.stacktrace()
75+
}
76+
77+
then:
78+
initialRun.task(":build").outcome == TaskOutcome.SUCCESS
79+
initialRun.task(":cacheVersionManifest1.21.6").outcome == TaskOutcome.SUCCESS
80+
}
81+
}

vanilla/src/main/java/net/neoforged/gradle/vanilla/VanillaProjectPlugin.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,14 @@ public void apply(Project project) {
2323
e.setUrl(UrlConstants.NEO_FORGE_MAVEN);
2424
e.metadataSources(MavenArtifactRepository.MetadataSources::mavenPom);
2525
});
26+
27+
//Add Known repos, -> We need this to resolve the minecraft dependencies to properly get the correct version.
28+
project.getRepositories().maven(e -> {
29+
e.setUrl(UrlConstants.MINECRAFT_METADATA);
30+
e.metadataSources(MavenArtifactRepository.MetadataSources::mavenPom);
31+
e.mavenContent(content -> {
32+
content.includeModule("net.neoforged", "minecraft-dependencies");
33+
});
34+
});
2635
}
2736
}

vanilla/src/main/java/net/neoforged/gradle/vanilla/dependency/VanillaDependencyManager.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import net.neoforged.gradle.dsl.common.extensions.dependency.replacement.ReplacementResult;
88
import net.neoforged.gradle.vanilla.runtime.VanillaRuntimeDefinition;
99
import net.neoforged.gradle.vanilla.runtime.extensions.VanillaRuntimeExtension;
10+
import net.neoforged.gradle.vanilla.util.MinecraftDependencyUtil;
1011
import org.gradle.api.Action;
1112
import org.gradle.api.Project;
1213
import org.gradle.api.artifacts.Dependency;
@@ -95,7 +96,10 @@ private static VanillaRuntimeDefinition buildVanillaRuntimeDefinition(Project pr
9596
final VanillaRuntimeExtension runtimeExtension = project.getExtensions().getByType(VanillaRuntimeExtension.class);
9697

9798
return runtimeExtension.maybeCreateFor(dependency, builder -> {
98-
final String version = dependency.getVersion() == null ? runtimeExtension.getVersion().get() : dependency.getVersion();
99+
String version = MinecraftDependencyUtil.resolveMinecraftDependenciesVersion(project, dependency);
100+
if (version == null) {
101+
version = runtimeExtension.getVersion().get();
102+
}
99103

100104
builder.withMinecraftArtifact(StringCapitalizationUtils.deCapitalize(dependency.getName()));
101105
builder.withDistributionType(DistributionType.valueOf(dependency.getName().toUpperCase(Locale.ROOT)));
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
package net.neoforged.gradle.vanilla.util;
2+
3+
import net.neoforged.gradle.common.util.ConfigurationUtils;
4+
import org.gradle.api.Project;
5+
import org.gradle.api.artifacts.*;
6+
import org.gradle.api.attributes.Attribute;
7+
import org.jetbrains.annotations.Nullable;
8+
9+
import java.util.concurrent.atomic.AtomicBoolean;
10+
11+
@SuppressWarnings("ConstantValue")
12+
public class MinecraftDependencyUtil
13+
{
14+
15+
@Nullable
16+
public static String resolveMinecraftDependenciesVersion(final Project project, final ExternalModuleDependency dependency)
17+
{
18+
final Dependency minecraftDependenciesDependency = project.getDependencies().create("net.neoforged:minecraft-dependencies" + (
19+
dependency.getVersion() != null ? ":" + dependency.getVersion() : ""
20+
));
21+
22+
AtomicBoolean configured = new AtomicBoolean(dependency.getVersion() != null);
23+
if (minecraftDependenciesDependency instanceof ExternalModuleDependency emd)
24+
{
25+
emd.version(version -> {
26+
final VersionConstraint versionConstraint = dependency.getVersionConstraint();
27+
28+
if (versionConstraint.getPreferredVersion() != null && !versionConstraint.getPreferredVersion().isEmpty())
29+
{
30+
version.prefer(versionConstraint.getPreferredVersion());
31+
configured.set(true);
32+
}
33+
34+
if (versionConstraint.getRejectedVersions() != null && !versionConstraint.getRejectedVersions().isEmpty())
35+
{
36+
version.reject(versionConstraint.getRejectedVersions().toArray(new String[0]));
37+
configured.set(true);
38+
}
39+
40+
if (versionConstraint.getRequiredVersion() != null && !versionConstraint.getRequiredVersion().isEmpty())
41+
{
42+
version.require(versionConstraint.getRequiredVersion());
43+
configured.set(true);
44+
}
45+
46+
if (versionConstraint.getStrictVersion() != null && !versionConstraint.getStrictVersion().isEmpty())
47+
{
48+
version.strictly(versionConstraint.getStrictVersion());
49+
configured.set(true);
50+
}
51+
52+
if (versionConstraint.getBranch() != null && !versionConstraint.getBranch().isEmpty())
53+
{
54+
version.setBranch(versionConstraint.getBranch());
55+
configured.set(true);
56+
}
57+
});
58+
}
59+
60+
if (!configured.get())
61+
{
62+
return null;
63+
}
64+
65+
final Configuration dependenciesLookup =
66+
ConfigurationUtils.temporaryUnhandledConfiguration(project.getConfigurations(), "ResolveRequestedMinecraftVersion", minecraftDependenciesDependency);
67+
68+
dependenciesLookup.attributes(attributes -> {
69+
attributes.attribute(Attribute.of("net.neoforged.distribution", String.class), "client"); //The distribution does not matter here.
70+
attributes.attribute(Attribute.of("net.neoforged.operatingsystem", String.class), "linux"); //Again the OS does not matter, we only need the resolved version, and it will always exist for all of them
71+
});
72+
73+
return dependenciesLookup.getResolvedConfiguration().getFirstLevelModuleDependencies().iterator().next().getModuleVersion();
74+
}
75+
}

0 commit comments

Comments
 (0)