Skip to content

Commit 62ccaa9

Browse files
committed
Preliminary support for multiple MC deps
- The primary limitation is that run configurations cannot be generated for source sets with more than one Minecraft dependency
1 parent 2dea382 commit 62ccaa9

14 files changed

+783
-266
lines changed

src/main/groovy/net/minecraftforge/gradle/ForgeGradleExtensionImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import org.gradle.api.plugins.PluginAware;
99

1010
record ForgeGradleExtensionImpl() implements ForgeGradleExtension {
11-
static <T extends ExtensionAware & PluginAware> void register(T target) {
11+
static void register(ExtensionAware target) {
1212
target.getExtensions().add(
1313
ForgeGradleExtension.class,
1414
ForgeGradleExtension.NAME,

src/main/groovy/net/minecraftforge/gradle/ForgeGradlePlugin.groovy

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ import javax.inject.Inject
3535
*/
3636
@CompileStatic
3737
@PackageScope([PackageScopeTarget.CLASS, PackageScopeTarget.FIELDS])
38-
class ForgeGradlePlugin<T extends ExtensionAware & PluginAware> implements Plugin<T> {
38+
class ForgeGradlePlugin implements Plugin<ExtensionAware> {
3939
/** The global logger for ForgeGradle, mostly used within {@link ForgeGradleProblems}. */
4040
static final Logger LOGGER = Logging.getLogger("ForgeGradle")
4141

@@ -62,7 +62,7 @@ class ForgeGradlePlugin<T extends ExtensionAware & PluginAware> implements Plugi
6262
* @param target The target to apply the plugin to
6363
*/
6464
@Override
65-
void apply(T target) {
65+
void apply(ExtensionAware target) {
6666
this.globalCaches = this.objects.directoryProperty().convention(
6767
this.objects.directoryProperty().fileValue(this.getGradleUserHomeDir(target)).dir(Constants.CACHES_LOCATION).map(this.enhancedProblems.ensureDirectory())
6868
)
@@ -98,7 +98,7 @@ class ForgeGradlePlugin<T extends ExtensionAware & PluginAware> implements Plugi
9898
}
9999

100100
@CompileDynamic
101-
private File getGradleUserHomeDir(T target) {
101+
private File getGradleUserHomeDir(ExtensionAware target) {
102102
try {
103103
target.gradle.startParameter.gradleUserHomeDir
104104
} catch (Throwable e) {

src/main/groovy/net/minecraftforge/gradle/ForgeGradleProblems.java

Lines changed: 10 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
import org.gradle.api.Transformer;
99
import org.gradle.api.artifacts.Dependency;
1010
import org.gradle.api.artifacts.ExternalModuleDependency;
11-
import org.gradle.api.artifacts.FileCollectionDependency;
1211
import org.gradle.api.file.Directory;
1312
import org.gradle.api.problems.Problem;
1413
import org.gradle.api.problems.ProblemGroup;
@@ -175,7 +174,7 @@ RuntimeException invalidMinecraftDependencyType(Dependency dependency) {
175174
This means that it cannot be substituted with file or project dependencies.
176175
Expected: (implementation of) %s, Actual: '%s
177176
Dependency: '%s'"""
178-
.formatted(ExternalModuleDependency.class.getName(), dependency.getClass().getName(), depToString(dependency)))
177+
.formatted(ExternalModuleDependency.class.getName(), dependency.getClass().getName(), Util.toString(dependency)))
179178
.severity(Severity.ERROR)
180179
.stackLocation()
181180
.solution("Declare a module dependency instead.")
@@ -199,49 +198,24 @@ void reportMissingMetadata(Throwable throwable) {
199198
);
200199
}
201200

202-
RuntimeException multipleMinecraftDependencies(Dependency current, Dependency replacement) {
203-
return this.getReporter().throwing(new IllegalArgumentException("Cannot have more than one Minecraft dependency"), id("multiple-minecraft-dependencies", "Multiple Minecraft dependencies declared"), spec -> spec
204-
.details("""
205-
Attempted to use multiple Minecraft dependencies. Only one can be declared
206-
Current: %s, Replacement: '%s'"""
207-
.formatted(depToString(current), depToString(replacement)))
208-
.severity(Severity.ERROR)
209-
.stackLocation()
210-
.solution("Declare only one Minecraft dependency using `minecraft.dep(...)`.")
211-
.solution(HELP_MESSAGE)
212-
);
213-
}
214-
215201
RuntimeException changingMinecraftDependency(Dependency dependency) {
216202
return this.getReporter().throwing(new IllegalArgumentException("Minecraft dependency cannot be changing"), id("changing-minecraft-dependency", "Minecraft dependency marked as changing"), spec -> spec
217203
.details("""
218204
Attempted to use a Minecraft dependency that was marked as changing.
219205
This is currently unsupported.
220206
Dependency: %s"""
221-
.formatted(depToString(dependency)))
207+
.formatted(Util.toString(dependency)))
222208
.severity(Severity.ERROR)
223209
.solution("Do not mark the Minecraft dependency as changing.")
224210
.solution(HELP_MESSAGE)
225211
);
226212
}
227-
228-
private static String depToString(Dependency dependency) {
229-
var group = dependency.getGroup();
230-
var version = dependency.getVersion();
231-
var reason = dependency.getReason();
232-
return "(%s) %s%s%s%s%s".formatted(
233-
dependency.getClass().getName(),
234-
group != null ? group + ':' : "",
235-
dependency.getName(),
236-
version != null ? ':' + version : "",
237-
reason != null ? " (" + reason + ')' : "",
238-
dependency instanceof FileCollectionDependency files ? " [%s]".formatted(String.join(", ", files.getFiles().getFiles().stream().map(File::getAbsolutePath).map(CharSequence.class::cast)::iterator)) : ""
239-
);
240-
}
241213
//endregion
242214

243215
//region Minecraft Maven
244216
void reportMcMavenNotDeclared() {
217+
if (!properties.test("net.minecraftforge.gradle.warnings.missingRepository.mcmaven")) return;
218+
245219
this.getReporter().report(id("minecraft-maven-not-declared", "Minecraft Maven not declared"), spec -> spec
246220
.details("""
247221
ForgeGradle was configured to sync the Minecraft Maven, but it was not declared as a repository!
@@ -253,6 +227,8 @@ void reportMcMavenNotDeclared() {
253227
}
254228

255229
void reportMcLibsMavenNotDeclared() {
230+
if (!properties.test("net.minecraftforge.gradle.warnings.missingRepository.mclibs")) return;
231+
256232
this.getReporter().report(id("minecraft-libs-maven-not-declared", "Minecraft Libraries maven not declared"), spec -> spec
257233
.details("""
258234
ForgeGradle was configured to sync the Minecraft Maven, but the Minecraft Libraries maven was not declared!
@@ -265,6 +241,8 @@ void reportMcLibsMavenNotDeclared() {
265241
}
266242

267243
void reportForgeMavenNotDeclared() {
244+
if (!properties.test("net.minecraftforge.gradle.warnings.missingRepository.forge")) return;
245+
268246
this.getReporter().report(id("forge-maven-not-declared", "Forge maven not declared"), spec -> spec
269247
.details("""
270248
ForgeGradle was configured to sync the Minecraft Maven, but the Forge maven was not declared!
@@ -275,26 +253,14 @@ void reportForgeMavenNotDeclared() {
275253
.solution(HELP_MESSAGE)
276254
);
277255
}
278-
279-
void reportMcMavenNotFound(Throwable e) {
280-
this.getReporter().report(id("minecraft-maven-not-found", "Minecraft Maven not found"), spec -> spec
281-
.details("""
282-
Attempted to sync the Minecraft Maven, but the Minecraft Mavenizer tool was not found!""")
283-
.withException(e)
284-
.severity(Severity.ERROR)
285-
.solution("Ensure that the Forge Maven (`fg.forgeMaven`) exists in your project/settings repositories.")
286-
.solution("If you are using a custom tool, ensure that you added your repository and it is up and running.")
287-
.solution(HELP_MESSAGE)
288-
);
289-
}
290256
//endregion
291257

292258
//region Deobfuscation
293259
RuntimeException invalidDeobfDependencyType(Dependency dependency) {
294-
return this.getReporter().throwing(new IllegalArgumentException("Non-module dependencies are not currently supported"), id("unsupported-dependency-type", "Non-module dependency used as Minecraft/deobf dependency"), spec -> spec
260+
return this.getReporter().throwing(new IllegalArgumentException("Non-module deobf dependencies are not supported"), id("unsupported-dependency-type", "Non-module dependency used as Minecraft/deobf dependency"), spec -> spec
295261
.details("""
296262
Attempted to use a non-module dependency as a deobf dependency, which is currently unsupported.
297-
Support for file dependencies will come at a later time. Project dependencies are not supported.
263+
Support for file dependencies may come at a later time. Project dependencies will not be supported.
298264
Expected: (implementation of) %s, Actual: '%s
299265
Dependency: '%s'"""
300266
.formatted(ExternalModuleDependency.class.getName(), dependency.getClass().getName(), dependency.toString()))
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradle;
6+
7+
import org.gradle.api.Task;
8+
import org.gradle.api.file.DirectoryProperty;
9+
import org.gradle.api.provider.Provider;
10+
11+
import java.io.File;
12+
13+
interface ForgeGradleTask extends Task {
14+
private ForgeGradlePlugin getPlugin() {
15+
return this.getProject().getPlugins().getPlugin(ForgeGradlePlugin.class);
16+
}
17+
18+
default Provider<File> getTool(Tools tool) {
19+
return this.getPlugin().getTool(tool);
20+
}
21+
22+
default DirectoryProperty getGlobalCaches() {
23+
return this.getPlugin().getGlobalCaches();
24+
}
25+
}
Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
/*
2+
* Copyright (c) Forge Development LLC and contributors
3+
* SPDX-License-Identifier: LGPL-2.1-only
4+
*/
5+
package net.minecraftforge.gradle;
6+
7+
import groovy.lang.Closure;
8+
import groovy.lang.DelegatesTo;
9+
import groovy.transform.Generated;
10+
import groovy.transform.NamedParam;
11+
import groovy.transform.NamedParams;
12+
import groovy.transform.NamedVariant;
13+
import groovy.transform.stc.ClosureParams;
14+
import groovy.transform.stc.SimpleType;
15+
import net.minecraftforge.accesstransformers.gradle.AccessTransformersContainer;
16+
import org.gradle.api.Action;
17+
import org.gradle.api.artifacts.ExternalModuleDependency;
18+
import org.gradle.api.file.RegularFile;
19+
import org.gradle.api.provider.Provider;
20+
import org.jetbrains.annotations.Contract;
21+
import org.jetbrains.annotations.Nullable;
22+
23+
import java.io.File;
24+
import java.util.Map;
25+
26+
public sealed interface MinecraftDependency extends ExternalModuleDependency permits MinecraftDependencyInternal {
27+
@Nullable MinecraftExtension.Mappings getMappings();
28+
29+
/**
30+
* Sets the mappings to use for the Minecraft Maven.
31+
* <p>This method includes a generated named variant that can make declaration in your buildscript easier.</p>
32+
* <pre><code>
33+
* minecraft {
34+
* mappings channel: 'official', version: '1.21.5'
35+
* }
36+
* </code></pre>
37+
*
38+
* @param channel The mappings channel
39+
* @param version The mappings version
40+
* @throws IllegalArgumentException If any parameter is {@code null}
41+
* @apiNote Mappings should only be declared once. A warning will be reported on re-declaration.
42+
* @see <a href="https://docs.groovy-lang.org/latest/html/api/groovy/transform/NamedVariant.html">NamedVariant</a>
43+
*/
44+
@NamedVariant
45+
void mappings(String channel, String version);
46+
47+
/// Sets the mappings to use for the Minecraft Maven.
48+
///
49+
/// This method is generated by Groovy in the implementing class, but has been included here for convenience and IDE
50+
/// support.
51+
///
52+
/// @param namedArgs The named arguments
53+
/// @throws IllegalArgumentException If any parameter is `null`
54+
/// @apiNote Mappings should only be declared once. A warning will be reported on re-declaration.
55+
/// @see #mappings(String, String)
56+
@Contract // empty contract so IDEs don't think this method always fails
57+
@Generated
58+
@SuppressWarnings("rawtypes")
59+
default void mappings(
60+
@NamedParams({
61+
@NamedParam(
62+
type = String.class,
63+
value = "channel",
64+
required = true
65+
),
66+
@NamedParam(
67+
type = String.class,
68+
value = "version",
69+
required = true
70+
)
71+
}) Map namedArgs
72+
) {
73+
throw new IllegalStateException("Groovy did not generate MinecraftExtension.mappings(Map)");
74+
}
75+
76+
/// Sets the AccessTransformer configuration to use.
77+
///
78+
/// @param configFile The configuration file to use
79+
void setAccessTransformer(RegularFile configFile);
80+
81+
/// Sets the AccessTransformer configuration to use.
82+
///
83+
/// @param configFile The configuration file to use
84+
void setAccessTransformer(File configFile);
85+
86+
/// Sets the AccessTransformer configuration to use.
87+
///
88+
/// The given object is resolved using [org.gradle.api.Project#file(Object)].
89+
///
90+
/// @param configFile The configuration file to use
91+
void setAccessTransformer(Object configFile);
92+
93+
/// Sets the AccessTransformer configuration to use.
94+
///
95+
/// If the given provider does not provide a [file][File] or [regular file][RegularFile], the result will be
96+
/// resolved using [org.gradle.api.Project#file(Object)], similarly to [#setAccessTransformer(Object)].
97+
///
98+
/// @param configFile The configuration file to use
99+
void setAccessTransformer(Provider<?> configFile);
100+
101+
/// Configures the AccessTransformer options for this project.
102+
///
103+
/// @param options The options to apply
104+
default void accessTransformer(Action<? super AccessTransformersContainer.Options> options) {
105+
this.accessTransformer(Closures.action(this, options));
106+
}
107+
108+
/// Configures the AccessTransformer options for this project.
109+
///
110+
/// @param options The options to apply
111+
@SuppressWarnings("rawtypes") // public-facing closure
112+
void accessTransformer(
113+
@DelegatesTo(value = AccessTransformersContainer.Options.class, strategy = Closure.DELEGATE_FIRST)
114+
@ClosureParams(value = SimpleType.class, options = "net.minecraftforge.accesstransformers.gradle.AccessTransformersContainer.Options")
115+
Closure options
116+
);
117+
118+
119+
/* DEPENDENCY OVERRIDES */
120+
121+
@Override
122+
default boolean isChanging() {
123+
return false;
124+
}
125+
126+
@Override
127+
default MinecraftDependency setChanging(boolean changing) {
128+
return this;
129+
}
130+
131+
@Override
132+
MinecraftDependency copy();
133+
}

0 commit comments

Comments
 (0)