build: Bump to VanillaGradle 0.2 and Gradle 7 (#3381)

This is likely require a full re-import in most IDEs due to some
organizational changes.
This commit is contained in:
zml authored and GitHub committed 2021-04-25 18:57:04 -07:00
1 parent 10f6dafecb
commit 8521dfde65
31 files changed
+1073 -813

No files matched your search

@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Sponge (vanilla/client) *macOS " type="Application" factoryName="Application" singleton="false">
<envs>
<env name="MOD_CLASSES" value="$PROJECT_DIR$/vanilla/build/resources/main:$PROJECT_DIR$/vanilla/build/classes/java/main" />
<env name="target" value="client" />
</envs>
<option name="MAIN_CLASS_NAME" value="org.spongepowered.vanilla.applaunch.Main" />
<module name="Sponge.SpongeVanilla.applaunch" />
<option name="PROGRAM_PARAMETERS" value="--launchTarget sponge_client_dev --version 1.16.4 --accessToken 0 --assetIndex 1.16 --assetsDir $USER_HOME$/.gradle/caches/forge_gradle/assets" />
<option name="VM_PARAMETERS" value="-Dorg.lwjgl.system.SharedLibraryExtractDirectory=lwjgl_dll -Djava.library.path=$PROJECT_DIR$/vanilla/build/natives -XstartOnFirstThread -Xss1M -Xmx4G -Dmixin.debug.export=true -Dsponge.shouldFireAll=true" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/vanilla/run" />
<method v="2">
<option name="Make" enabled="true" />
<option name="Gradle.BeforeRunTask" enabled="false" tasks=":SpongeVanilla:prepareRunClient" externalProjectPath="$PROJECT_DIR$" />
</method>
</configuration>
</component>
-17
View File
@@ -1,17 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Sponge (vanilla/client)" type="Application" factoryName="Application" singleton="false">
<envs>
<env name="MOD_CLASSES" value="$PROJECT_DIR$/vanilla/build/resources/main:$PROJECT_DIR$/vanilla/build/classes/java/main" />
<env name="target" value="client" />
</envs>
<option name="MAIN_CLASS_NAME" value="org.spongepowered.vanilla.applaunch.Main" />
<module name="Sponge.SpongeVanilla.applaunch" />
<option name="PROGRAM_PARAMETERS" value="--launchTarget sponge_client_dev --version 1.16.4 --accessToken 0 --assetIndex 1.16 --assetsDir $USER_HOME$/.gradle/caches/forge_gradle/assets" />
<option name="VM_PARAMETERS" value="-Dorg.lwjgl.system.SharedLibraryExtractDirectory=lwjgl_dll -Djava.library.path=$PROJECT_DIR$/vanilla/build/natives -Xss1M -Xmx4G -Dmixin.debug.export=true -Dsponge.shouldFireAll=true" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/vanilla/run" />
<method v="2">
<option name="Make" enabled="true" />
<option name="Gradle.BeforeRunTask" enabled="false" tasks=":SpongeVanilla:prepareRunClient" externalProjectPath="$PROJECT_DIR$" />
</method>
</configuration>
</component>
-12
View File
@@ -1,12 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Sponge (vanilla/server)" type="Application" factoryName="Application">
<option name="MAIN_CLASS_NAME" value="org.spongepowered.vanilla.applaunch.Main" />
<module name="Sponge.SpongeVanilla.applaunch" />
<option name="PROGRAM_PARAMETERS" value="-launchTarget sponge_server_dev nogui" />
<option name="VM_PARAMETERS" value="-Dmixin.debug.export=true -Dsponge.shouldFireAll=true" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/vanilla/run" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
</component>
+22
View File
@@ -0,0 +1,22 @@
This file is part of ${name}, licensed under the MIT License (MIT).
Copyright (c) ${organization} <${url}>
Copyright (c) contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
+22 -18
View File
@@ -7,17 +7,17 @@ The SpongeAPI implementation targeting vanilla Minecraft and 3rd party platforms
* [Source]
* [Issues]
* [Documentation]
* [Discord]: [#sponge ]
* [Discord]: `#sponge`
## Latest Builds
### Sponge
**1.16.4**: ![Snapshots](https://img.shields.io/nexus/maven-snapshots/org.spongepowered/sponge?label=Sponge&server=https%3A%2F%2Frepo-new.spongepowered.org%2F)
**1.16.5**: ![Snapshots](https://img.shields.io/nexus/maven-snapshots/org.spongepowered/sponge?label=Sponge&server=https%3A%2F%2Frepo-new.spongepowered.org%2F)
### SpongeVanilla
**1.16.4**: ![Snapshots](https://img.shields.io/nexus/maven-releases/org.spongepowered/spongevanilla?label=SpongeVanilla&server=https%3A%2F%2Frepo-new.spongepowered.org%2F)
**1.16.5**: ![Snapshots](https://img.shields.io/nexus/maven-releases/org.spongepowered/spongevanilla?label=SpongeVanilla&server=https%3A%2F%2Frepo-new.spongepowered.org%2F)
## Prerequisites
@@ -32,32 +32,35 @@ The following steps will ensure your project is cloned properly.
## Setup
**Note**: Sponge uses [Gradle] as its build system. The repo includes the Gradle wrapper that will automatically download the correct Gradle
version. Local installations of Gradle may work but are untested. To execute the Gradle wrapper, run the `./gradlew` script on Unix systems or only
`gradlew` on Windows systems.
version. Local installations of Gradle may work (as long as they are using Gradle 6.8+) but are untested. To execute the Gradle wrapper, run the
`./gradlew` script on Unix systems or only `gradlew` on Windows systems.
Before you are able to build Sponge, you must first prepare the environment (some IDEs may do this for you).
- Run `./gradlew build --refresh-dependencies`
Even if this fails to compile Sponge, it will download all the dependencies so you can get started.
To have browsable sources for use in-IDE, run `./gradlew :decompile`. This command will need to be re-ran after any change to
Minecraft version or to `.accesswidener` files. If sources are not appearing properly, an IDE refresh should fix things.
### IDE Setup
__For [Eclipse]__
1. Run `./gradlew eclipse`
2. Import Sponge as an existing project (File > Import > General)
3. Select the root folder for Sponge and make sure `Search for nested projects` is enabled
4. Check Sponge when it finishes building and click **Finish**
1. Make sure the Buildship plugin is installed (available on the [Eclipse Marketplace])
2. Import the project as an *Existing Gradle Project* (via File > Import > Gradle)
While we do our best to support any IDE, most of our developers use IntelliJ, so issues may pop up with Eclipse from time to time.
We'll be happy to work to resolve those issues if reported via [our issues page][Issues] or fixed via PR.
__For [IntelliJ]__
1. Make sure you have the Gradle plugin enabled (File > Settings > Plugins).
2. Click File > New > Project from Existing Sources > Gradle and select the root folder for Sponge.
3. Make sure _Use default gradle wrapper_ is selected. Older/newer Gradle versions may work but we only test using the wrapper.
## Building
__Note:__ You must [Setup the environment](#setup) before you can build Sponge.
For both Eclipse and IntelliJ, a variety of run configurations will be generated which allow running the client and server in development. These run
configurations will be re-generated on each project import, so any desired modifications should be done on copies of the configurations.
In order to build Sponge you simply need to run the `gradlew` command. On Windows systems you should run `gradlew` instead of `./gradlew` to
invoke the Gradle wrapper. You can find the compiled JAR files in `./build/libs`.
While these run configurations have Java versions attached to them, be aware that IntelliJ ignores that information entirely, and Eclipse will
only be able to align those java versions with whatever JREs it is aware of.
## Building
In order to build Sponge you simply need to run the `gradlew build` command. On Windows systems you should run `gradlew build` instead
of `./gradlew build` to invoke the Gradle wrapper. You can find the compiled JAR files in `./build/libs` and `./vanilla/build/libs`.
## Updating your Clone
The following steps will update your clone with the official repo.
@@ -72,6 +75,7 @@ Are you a talented programmer looking to contribute some code? We'd love the hel
* Please follow the above guidelines for your pull request(s) to be accepted.
[Eclipse]: https://eclipse.org/
[Eclipse Marketplace]: http://marketplace.eclipse.org/content/buildship-gradle-integration
[Gradle]: https://gradle.org/
[Homepage]: https://spongepowered.org/
[IntelliJ]: http://www.jetbrains.com/idea/
+24
View File
@@ -0,0 +1,24 @@
plugins {
id "java-gradle-plugin"
id "org.spongepowered.gradle.sponge.dev" version "1.0.3"
}
repositories {
maven {
url = "https://repo.spongepowered.org/repository/maven-public"
name = "sponge"
}
}
dependencies {
implementation("com.google.code.gson:gson:2.8.6")
}
gradlePlugin {
plugins {
impl {
id = "implementation-structure"
implementationClass = "org.spongepowered.gradle.impl.SpongeImplementationPlugin"
}
}
}
+1
View File
@@ -0,0 +1 @@
rootProject.name = "build-logic"
@@ -0,0 +1,248 @@
/*
* This file is part of spongegradle-convention, licensed under the MIT License (MIT).
*
* Copyright (c) SpongePowered <https://www.spongepowered.org>
* Copyright (c) contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.spongepowered.gradle.impl;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.NamedDomainObjectProvider;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.component.ComponentIdentifier;
import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
import org.gradle.api.artifacts.result.ResolvedArtifactResult;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.provider.SetProperty;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.Optional;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
import java.io.BufferedWriter;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
public abstract class OutputDependenciesToJson extends DefaultTask {
// From http://stackoverflow.com/questions/9655181/convert-from-byte-array-to-hex-string-in-java
private static final char[] hexArray = "0123456789abcdef".toCharArray();
private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
/**
* A single dependency.
*/
static final class DependencyDescriptor implements Comparable<DependencyDescriptor> {
final String group;
final String module;
final String version;
final String md5;
DependencyDescriptor(final String group, final String module, final String version, final String md5) {
this.group = group;
this.module = module;
this.version = version;
this.md5 = md5;
}
@Override
public int compareTo(final DependencyDescriptor that) {
final int group = this.group.compareTo(that.group);
if (group != 0) {
return group;
}
final int module = this.module.compareTo(that.module);
if (module != 0) {
return module;
}
return this.version.compareTo(that.version);
}
@Override
public boolean equals(final Object other) {
if (this == other) {
return true;
}
if (other == null || this.getClass() != other.getClass()) {
return false;
}
final DependencyDescriptor that = (DependencyDescriptor) other;
return Objects.equals(this.group, that.group)
&& Objects.equals(this.module, that.module)
&& Objects.equals(this.version, that.version);
}
@Override
public int hashCode() {
return Objects.hash(this.group, this.module, this.version);
}
@Override
public String toString() {
return "DependencyDescriptor{" +
"group='" + this.group + '\'' +
", module='" + this.module + '\'' +
", version='" + this.version + '\'' +
", md5='" + this.md5 + '\'' +
'}';
}
}
/**
* A manifest containing a list of dependencies.
*
* <p>At runtime, transitive dependencies won't be traversed, so this needs to
* include direct + transitive depends.</p>
*/
static final class DependencyManifest {
final List<DependencyDescriptor> dependencies;
DependencyManifest(final List<DependencyDescriptor> dependencies) {
this.dependencies = dependencies;
}
}
/**
* Configuration to gather dependency artifacts from.
*/
@Input
public abstract Property<Configuration> getDependencies();
public final void dependencies(final NamedDomainObjectProvider<Configuration> config) {
this.getDependencies().set(config);
}
/**
* Excludes configuration, to remove certain entries from dependencies and
* transitive dependencies of {@link #getDependencies()}.
*/
@Input
@Optional
public abstract Property<Configuration> getExcludedDependencies();
public final void excludedDependencies(final NamedDomainObjectProvider<Configuration> config) {
this.getExcludedDependencies().set(config);
}
/**
* Classifiers to include in the dependency manifest. The empty string identifies no classifier.
*/
@Input
public abstract SetProperty<String> getAllowedClassifiers();
@OutputFile
public abstract RegularFileProperty getOutputFile();
public OutputDependenciesToJson() {
this.getAllowedClassifiers().add("");
}
@TaskAction
public void generateDependenciesJson() {
final Set<ModuleComponentIdentifier> excludedDeps = new HashSet<>();
if (this.getExcludedDependencies().isPresent()) {
for (final ResolvedArtifactResult result : this.getExcludedDependencies().get().getIncoming().getArtifacts()) {
if (result.getId().getComponentIdentifier() instanceof ModuleComponentIdentifier) {
excludedDeps.add((ModuleComponentIdentifier) result.getId().getComponentIdentifier());
}
}
}
final List<DependencyDescriptor> descriptors = this.getDependencies().get().getIncoming().getArtifacts().getArtifacts().stream()
.filter(dep -> {
final ComponentIdentifier ident = dep.getId().getComponentIdentifier();
return ident instanceof ModuleComponentIdentifier && !excludedDeps.contains(ident);
})
.distinct()
.map(dependency -> {
final ModuleComponentIdentifier id = (ModuleComponentIdentifier) dependency.getId().getComponentIdentifier();
// Get file input stream for reading the file content
final String md5hash;
try (final InputStream in = new FileInputStream(dependency.getFile())) {
final MessageDigest hasher = MessageDigest.getInstance("MD5");
final byte[] buf = new byte[4096];
int read;
while ((read = in.read(buf)) != -1) {
hasher.update(buf, 0, read);
}
md5hash = OutputDependenciesToJson.toHexString(hasher.digest());
} catch (final IOException | NoSuchAlgorithmException ex) {
throw new GradleException("Failed to create hash for " + dependency, ex);
}
// create descriptor
return new DependencyDescriptor(
id.getGroup(),
id.getModule(),
id.getVersion(),
md5hash
);
})
.sorted(Comparator.naturalOrder()) // sort dependencies for stable output
.collect(Collectors.toList());
final DependencyManifest manifest = new DependencyManifest(descriptors);
this.getLogger().info("Writing to {}", this.getOutputFile().get().getAsFile());
try (
final BufferedWriter writer = new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(this.getOutputFile().get().getAsFile()), StandardCharsets.UTF_8))
) {
OutputDependenciesToJson.GSON.toJson(manifest, writer);
} catch (final IOException ex) {
throw new GradleException("Failed to write dependencies manifest", ex);
}
}
public static String toHexString(final byte[] bytes) {
final char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
final int v = bytes[j] & 0xFF;
hexChars[j * 2] = OutputDependenciesToJson.hexArray[v >>> 4];
hexChars[j * 2 + 1] = OutputDependenciesToJson.hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
@@ -0,0 +1,73 @@
package org.spongepowered.gradle.impl;
import org.gradle.api.Project;
import org.gradle.api.logging.Logger;
import org.gradle.api.tasks.SourceSet;
import java.util.Objects;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
public abstract class SpongeImplementationExtension {
private final Logger logger;
@Inject
public SpongeImplementationExtension(final Logger logger) {
this.logger = logger;
}
public void applyNamedDependencyOnOutput(final Project originProject, final SourceSet sourceAdding, final SourceSet targetSource, final Project implProject, final String dependencyConfigName) {
implProject.getLogger().lifecycle(
"[{}] Adding {}({}) to {}({}).{}",
implProject.getName(),
originProject.getPath(),
sourceAdding.getName(),
implProject.getPath(),
targetSource.getName(),
dependencyConfigName
);
implProject.getDependencies().add(dependencyConfigName, sourceAdding.getOutput());
}
public String generateImplementationVersionString(final String apiVersion, final String minecraftVersion, final String implRecommendedVersion) {
return this.generateImplementationVersionString(apiVersion, minecraftVersion, implRecommendedVersion, null);
}
public String generateImplementationVersionString(final String apiVersion, final String minecraftVersion, final String implRecommendedVersion, final String addedVersionInfo) {
final String[] apiSplit = apiVersion.replace("-SNAPSHOT", "").split("\\.");
final String minor = apiSplit.length > 1 ? apiSplit[1] : apiSplit.length > 0 ? apiSplit[apiSplit.length - 1] : "-1";
final String apiReleaseVersion = apiSplit[0] + '.' + minor;
return Stream.of(minecraftVersion, addedVersionInfo, apiReleaseVersion + '.' + implRecommendedVersion)
.filter(Objects::nonNull)
.collect(Collectors.joining("-"));
}
public String generatePlatformBuildVersionString(final String apiVersion, final String minecraftVersion, final String implRecommendedVersion) {
return this.generatePlatformBuildVersionString(apiVersion, minecraftVersion, implRecommendedVersion, null);
}
public String generatePlatformBuildVersionString(final String apiVersion, final String minecraftVersion, final String implRecommendedVersion, final String addedVersionInfo) {
final boolean isRelease = !implRecommendedVersion.endsWith("-SNAPSHOT");
this.logger.lifecycle("Detected Implementation Version {} as {}", implRecommendedVersion, isRelease ? "Release" : "Snapshot");
final String[] apiSplit = apiVersion.replace("-SNAPSHOT", "").split("\\.");
final String minor = apiSplit.length > 1 ? apiSplit[1] : apiSplit.length > 0 ? apiSplit[apiSplit.length - 1] : "-1";
final String apiReleaseVersion = apiSplit[0] + '.' + minor;
final String rawBuildNumber = System.getenv("BUILD_NUMBER");
final int buildNumber = Integer.parseInt(rawBuildNumber == null ? "0" : rawBuildNumber);
final String implVersionAsReleaseCandidateOrRecommended;
if (isRelease) {
implVersionAsReleaseCandidateOrRecommended = apiReleaseVersion + '.' + implRecommendedVersion;
} else {
implVersionAsReleaseCandidateOrRecommended = apiReleaseVersion + '.' + implRecommendedVersion.replace("-SNAPSHOT", "") + "-RC" + buildNumber;
}
return Stream.of(minecraftVersion, addedVersionInfo, implVersionAsReleaseCandidateOrRecommended)
.filter(Objects::nonNull)
.collect(Collectors.joining("-"));
}
}
@@ -0,0 +1,15 @@
package org.spongepowered.gradle.impl;
import org.gradle.api.Plugin;
import org.gradle.api.Project;
/**
* Set up the appropriate variants of a project (accessors, main, mixins, launch, applaunch)
*/
public class SpongeImplementationPlugin implements Plugin<Project> {
@Override
public void apply(final Project target) {
target.getExtensions().create("spongeImpl", SpongeImplementationExtension.class, target.getLogger());
}
}
+66 -666
View File
@@ -1,17 +1,19 @@
import java.security.MessageDigest
import java.util.Locale
plugins {
id("org.spongepowered.gradle.vanilla")
`maven-publish`
`java-library`
eclipse
id("org.cadixdev.licenser") version "0.5.0"
id("com.github.johnrengelman.shadow") version "6.1.0"
id("org.spongepowered.gradle.vanilla")
id("org.cadixdev.licenser")
id("com.github.johnrengelman.shadow")
id("org.spongepowered.gradle.sponge.dev") apply false // for version json generation
id("implementation-structure")
id("org.jetbrains.gradle.plugin.idea-ext")
}
val apiProject = project.project("SpongeAPI")
val commonProject = project
val apiVersion: String by project
val minecraftVersion: String by project
val recommendedVersion: String by project
@@ -22,25 +24,13 @@ val pluginSpiVersion: String by project
val guavaVersion: String by project
val junitVersion: String by project
minecraft {
version(minecraftVersion)
injectRepositories().set(false)
project.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach {
accessWidener(it)
parent?.minecraft?.accessWidener(it)
}
}
val commonManifest = the<JavaPluginConvention>().manifest {
attributes(
"Specification-Title" to "Sponge",
"Specification-Vendor" to "SpongePowered",
"Specification-Version" to apiProject.version,
"Specification-Version" to apiVersion,
"Implementation-Title" to project.name,
"Implementation-Version" to generateImplementationVersionString(apiProject.version as String, minecraftVersion, recommendedVersion),
"Implementation-Version" to spongeImpl.generateImplementationVersionString(apiVersion, minecraftVersion, recommendedVersion),
"Implementation-Vendor" to "SpongePowered"
)
}
@@ -74,38 +64,34 @@ tasks {
useJUnitPlatform()
}
check {
dependsOn(gradle.includedBuild("SpongeAPI").task(":check"))
}
}
version = generateImplementationVersionString(apiProject.version as String, minecraftVersion, recommendedVersion)
version = spongeImpl.generateImplementationVersionString(apiVersion, minecraftVersion, recommendedVersion)
// Configurations
val minecraftConfig by configurations.named("minecraft")
val minecraftClasspathConfig by configurations.named("minecraftClasspath")
val applaunchConfig by configurations.register("applaunch")
val launchConfig by configurations.register("launch") {
extendsFrom(minecraftConfig)
extendsFrom(minecraftClasspathConfig)
extendsFrom(configurations.minecraft.get())
extendsFrom(applaunchConfig)
}
val accessorsConfig by configurations.register("accessors") {
extendsFrom(minecraftConfig)
extendsFrom(launchConfig)
extendsFrom(minecraftClasspathConfig)
}
val mixinsConfig by configurations.register("mixins") {
extendsFrom(applaunchConfig)
extendsFrom(launchConfig)
extendsFrom(minecraftConfig)
extendsFrom(minecraftClasspathConfig)
}
// create the sourcesets
val main by sourceSets
val applaunch by sourceSets.registering {
applyNamedDependencyOnOutput(originProject = project, sourceAdding = this, targetSource = main, implProject = project, dependencyConfigName = main.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, this, main, project, main.implementationConfigurationName)
project.dependencies {
mixinsConfig(this@registering.output)
}
@@ -114,7 +100,7 @@ val applaunch by sourceSets.registering {
}
}
val launch by sourceSets.registering {
applyNamedDependencyOnOutput(originProject = project, sourceAdding = applaunch.get(), targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, applaunch.get(), this, project, this.implementationConfigurationName)
project.dependencies {
mixinsConfig(this@registering.output)
}
@@ -128,17 +114,17 @@ val launch by sourceSets.registering {
}
val accessors by sourceSets.registering {
applyNamedDependencyOnOutput(originProject = project, sourceAdding = launch.get(), targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = project, sourceAdding = this, targetSource = main, implProject = project, dependencyConfigName = main.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, launch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, this, main, project, main.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(accessorsConfig)
}
}
val mixins by sourceSets.registering {
applyNamedDependencyOnOutput(originProject = project, sourceAdding = launch.get(), targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = project, sourceAdding = applaunch.get(), targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = project, sourceAdding = accessors.get(), targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = project, sourceAdding = main, targetSource = this, implProject = project, dependencyConfigName = this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, launch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, applaunch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, accessors.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, main, this, project, this.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(mixinsConfig)
}
@@ -146,7 +132,7 @@ val mixins by sourceSets.registering {
dependencies {
// api
api(project(":SpongeAPI"))
api("org.spongepowered:spongeapi:$apiVersion")
// Database stuffs... likely needs to be looked at
implementation("com.zaxxer:HikariCP:2.6.3")
@@ -164,7 +150,7 @@ dependencies {
implementation("net.kyori:adventure-serializer-configurate4")
// Launch Dependencies - Needed to bootstrap the engine(s)
launchConfig(project(":SpongeAPI"))
launchConfig("org.spongepowered:spongeapi:$apiVersion")
launchConfig("org.spongepowered:plugin-spi:$pluginSpiVersion")
launchConfig("org.spongepowered:mixin:$mixinVersion")
launchConfig("org.checkerframework:checker-qual:3.4.1")
@@ -198,45 +184,13 @@ dependencies {
applaunchConfig("org.apache.logging.log4j:log4j-core:2.11.2")
mixinsConfig(sourceSets.named("main").map { it.output })
add(mixins.get().implementationConfigurationName, project(":SpongeAPI"))
add(mixins.get().implementationConfigurationName, "org.spongepowered:spongeapi:$apiVersion")
// Tests
testImplementation("org.junit.jupiter:junit-jupiter-api:$junitVersion")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junitVersion")
}
fun debug(logger: Logger, messsage: String) {
println(message = messsage)
if (System.getProperty("sponge.gradleDebug", "false")!!.toBoolean()) {
logger.lifecycle(messsage)
}
}
fun applyNamedDependencyOnOutput(originProject: Project, sourceAdding: SourceSet, targetSource: SourceSet, implProject: Project, dependencyConfigName: String) {
debug(implProject.logger, "[${implProject.name}] Adding ${originProject.path}(${sourceAdding.name}) to ${implProject.path}(${targetSource.name}).$dependencyConfigName")
implProject.dependencies.add(dependencyConfigName, sourceAdding.output)
}
fun generateImplementationVersionString(apiVersion: String, minecraftVersion: String, implRecommendedVersion: String, addedVersionInfo: String? = null): String {
val apiSplit = apiVersion.replace("-SNAPSHOT", "").split(".")
val minor = if (apiSplit.size > 1) apiSplit[1] else (if (apiSplit.size > 0) apiSplit.last() else "-1")
val apiReleaseVersion = "${apiSplit[0]}.$minor"
return listOfNotNull(minecraftVersion, addedVersionInfo, "$apiReleaseVersion.$implRecommendedVersion").joinToString("-")
}
fun generatePlatformBuildVersionString(apiVersion: String, minecraftVersion: String, implRecommendedVersion: String, addedVersionInfo: String? = null): String {
val isRelease = !implRecommendedVersion.endsWith("-SNAPSHOT")
println("Detected Implementation Version $implRecommendedVersion as ${if (isRelease) "Release" else "Snapshot"}")
val apiSplit = apiVersion.replace("-SNAPSHOT", "").split(".")
val minor = if (apiSplit.size > 1) apiSplit[1] else (if (apiSplit.size > 0) apiSplit.last() else "-1")
val apiReleaseVersion = "${apiSplit[0]}.$minor"
val buildNumber = Integer.parseInt(System.getenv("BUILD_NUMBER") ?: "0")
val implVersionAsReleaseCandidateOrRecommended: String = if (isRelease) {
"$apiReleaseVersion.$implRecommendedVersion"
} else {
"$apiReleaseVersion.${implRecommendedVersion.replace("-SNAPSHOT", "")}-RC$buildNumber"
}
return listOfNotNull(minecraftVersion, addedVersionInfo, implVersionAsReleaseCandidateOrRecommended).joinToString("-")
}
val organization: String by project
val projectUrl: String by project
license {
@@ -245,14 +199,13 @@ license {
this["organization"] = organization
this["url"] = projectUrl
}
header = apiProject.file("HEADER.txt")
header = rootProject.file("HEADER.txt")
include("**/*.java")
newLine = false
}
allprojects {
configurations.configureEach {
resolutionStrategy.dependencySubstitution {
// https://github.com/zml2008/guice/tree/backport/5.0.1
@@ -262,19 +215,41 @@ allprojects {
}
}
apply(plugin = "org.jetbrains.gradle.plugin.idea-ext")
apply(plugin = "java-library")
apply(plugin = "maven-publish")
apply(plugin = "org.cadixdev.licenser")
base {
archivesBaseName = name.toLowerCase(Locale.ENGLISH)
}
tasks {
withType(JavaCompile::class).configureEach {
options.compilerArgs.addAll(listOf("-Xmaxerrs", "1000"))
options.encoding = "UTF-8"
if (JavaVersion.current().isJava10Compatible) {
options.release.set(8)
plugins.withId("org.spongepowered.gradle.vanilla") {
minecraft {
version(minecraftVersion)
injectRepositories(false)
project.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach {
accessWideners(it)
parent?.minecraft?.accessWideners(it)
}
}
}
idea {
if (project != null) {
(project as ExtensionAware).extensions["settings"].run {
(this as ExtensionAware).extensions.getByType(org.jetbrains.gradle.ext.ActionDelegationConfig::class).run {
delegateBuildRunToGradle = false
testRunner = org.jetbrains.gradle.ext.ActionDelegationConfig.TestRunner.PLATFORM
}
(this as ExtensionAware).extensions.getByType(org.jetbrains.gradle.ext.IdeaCompilerConfiguration::class).run {
addNotNullAssertions = false
useReleaseOption = JavaVersion.current().isJava10Compatible
parallelCompilation = true
}
}
}
}
@@ -283,6 +258,7 @@ allprojects {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
tasks.withType<AbstractArchiveTask> {
isPreserveFileTimestamps = false
isReproducibleFileOrder = true
@@ -290,8 +266,17 @@ allprojects {
val spongeSnapshotRepo: String? by project
val spongeReleaseRepo: String? by project
tasks {
val emptyAnnotationProcessors = objects.fileCollection()
withType(JavaCompile::class).configureEach {
options.compilerArgs.addAll(listOf("-Xmaxerrs", "1000"))
options.encoding = "UTF-8"
if (JavaVersion.current().isJava10Compatible) {
options.release.set(8)
}
options.annotationProcessorPath = emptyAnnotationProcessors
}
withType<PublishToMavenRepository>().configureEach {
withType(PublishToMavenRepository::class).configureEach {
onlyIf {
(repository == publishing.repositories["GitHubPackages"] &&
!(rootProject.version as String).endsWith("-SNAPSHOT")) ||
@@ -304,9 +289,6 @@ allprojects {
}
}
sourceSets.configureEach {
if (project.name == "SpongeAPI" && "main" == this.name) {
return@configureEach;
}
val sourceSet = this
val sourceJarName: String = if ("main".equals(this.name)) "sourceJar" else "${this.name}SourceJar"
tasks.register(sourceJarName, Jar::class.java) {
@@ -408,586 +390,4 @@ publishing {
}
}
}
}
data class ProjectDep(val group: String, val module: String, val version: String)
val testplugins: Project? = subprojects.find { "testplugins".equals(it.name) }
if (testplugins != null) {
project("testplugins") {
apply {
plugin("java-library")
plugin("idea")
plugin("eclipse")
plugin("org.cadixdev.licenser")
}
dependencies {
implementation(rootProject.project(":SpongeAPI"))
annotationProcessor(rootProject.project(":SpongeAPI"))
}
tasks.jar {
manifest {
attributes("Loader" to "java_plain")
}
}
license {
(this as ExtensionAware).extra.apply {
this["name"] = "Sponge"
this["organization"] = organization
this["url"] = projectUrl
}
header = apiProject.file("HEADER.txt")
include("**/*.java")
newLine = false
}
}
}
project("SpongeVanilla") {
val vanillaProject = this
apply {
plugin("org.spongepowered.gradle.vanilla")
plugin("java-library")
plugin("maven-publish")
plugin("org.cadixdev.licenser")
plugin("com.github.johnrengelman.shadow")
}
description = "The SpongeAPI implementation for Vanilla Minecraft"
version = generatePlatformBuildVersionString(apiProject.version as String, minecraftVersion, recommendedVersion)
println("SpongeVanilla Version $version")
val vanillaLibrariesConfig by configurations.register("libraries") {
}
val vanillaMinecraftConfig by configurations.named("minecraft")
val vanillaMinecraftClasspathConfig by configurations.named("minecraftClasspath")
val vanillaAppLaunchConfig by configurations.register("applaunch") {
extendsFrom(vanillaLibrariesConfig)
}
val vanillaInstallerConfig by configurations.register("installer") {
}
val vanillaInstaller by sourceSets.register("installer") {
}
val vanillaInstallerJava9 by sourceSets.register("installerJava9") {
this.java.setSrcDirs(setOf("src/installer/java9"))
compileClasspath += vanillaInstaller.compileClasspath
compileClasspath += vanillaInstaller.runtimeClasspath
tasks.named(compileJavaTaskName, JavaCompile::class) {
options.release.set(9)
if (JavaVersion.current() < JavaVersion.VERSION_11) {
javaCompiler.set(javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(11)) })
}
}
dependencies.add(implementationConfigurationName, objects.fileCollection().from(vanillaInstaller.output.classesDirs))
}
val vanillaMain by sourceSets.named("main") {
// implementation (compile) dependencies
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = accessors.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = launch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = applaunch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(vanillaLibrariesConfig)
}
}
val vanillaLaunch by sourceSets.register("launch") {
// implementation (compile) dependencies
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = launch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = applaunch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = main, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = this, targetSource = vanillaMain, implProject = vanillaProject, dependencyConfigName = vanillaMain.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig)
extendsFrom(vanillaMinecraftConfig)
extendsFrom(vanillaMinecraftClasspathConfig)
}
}
val vanillaMixins by sourceSets.register("mixins") {
// implementation (compile) dependencies
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = mixins.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = accessors.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = launch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = applaunch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = main, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaMain, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaLaunch, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
}
val vanillaAppLaunch by sourceSets.register("applaunch") {
// implementation (compile) dependencies
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = applaunch.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = launch.get(), targetSource = vanillaLaunch, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaInstaller, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.implementationConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = this, targetSource = vanillaLaunch, implProject = vanillaProject, dependencyConfigName = vanillaLaunch.implementationConfigurationName)
// runtime dependencies - literally add the rest of the project, because we want to launch the game
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaMixins, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaLaunch, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = mixins.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = main, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
applyNamedDependencyOnOutput(originProject = commonProject, sourceAdding = accessors.get(), targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
applyNamedDependencyOnOutput(originProject = vanillaProject, sourceAdding = vanillaMain, targetSource = this, implProject = vanillaProject, dependencyConfigName = this.runtimeOnlyConfigurationName)
}
val vanillaMixinsImplementation by configurations.named(vanillaMixins.implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig)
extendsFrom(vanillaMinecraftConfig)
extendsFrom(vanillaMinecraftClasspathConfig)
}
configurations.named(vanillaMixins.annotationProcessorConfigurationName)
configurations.named(vanillaInstaller.implementationConfigurationName) {
extendsFrom(vanillaInstallerConfig)
}
configurations.named(vanillaAppLaunch.implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig)
extendsFrom(launchConfig)
}
val vanillaAppLaunchRuntime by configurations.named(vanillaAppLaunch.runtimeOnlyConfigurationName)
minecraft {
version(minecraftVersion)
injectRepositories().set(false)
runs {
// Full development environment
sequenceOf(8, 11, 16).forEach {
server("runJava${it}Server") {
args("--nogui", "--launchTarget", "sponge_server_dev")
// ideaModule("${rootProject.name}.${project.name}.applaunch")
}
client("runJava${it}Client") {
args("--launchTarget", "sponge_client_dev")
// ideaModule("${rootProject.name}.${project.name}.applaunch")
}
tasks.named("runJava${it}Server", JavaExec::class).configure {
javaLauncher.set(javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(it)) })
}
tasks.named("runJava${it}Client", JavaExec::class).configure {
javaLauncher.set(javaToolchains.launcherFor { languageVersion.set(JavaLanguageVersion.of(it)) })
}
}
// Lightweight integration tests
server("integrationTestServer") {
args("--launchTarget", "sponge_server_it")
}
client("integrationTestClient") {
args("--launchTarget", "sponge_client_it")
}
configureEach {
workingDirectory().set(vanillaProject.file("run/"))
if (System.getProperty("idea.active")?.toBoolean() == true) {
// IntelliJ does not properly report its compatibility
jvmArgs("-Dterminal.ansi=true", "-Djansi.mode=force")
}
jvmArgs("-Dlog4j.configurationFile=log4j2_dev.xml")
allJvmArgumentProviders() += CommandLineArgumentProvider {
// Resolve the Mixin artifact for use as a reload agent
val mixinJar = vanillaAppLaunchConfig.resolvedConfiguration
.getFiles { it.name == "mixin" && it.group == "org.spongepowered" }
.firstOrNull()
val base = if (mixinJar != null) {
listOf("-javaagent:$mixinJar")
} else {
emptyList()
}
// Then add necessary module cracks
if (!this.name.contains("Java8")) {
base + listOf(
"--illegal-access=deny", // enable strict mode in prep for Java 16
"--add-exports=java.base/sun.security.util=ALL-UNNAMED", // ModLauncher
"--add-opens=java.base/java.util.jar=ALL-UNNAMED" // ModLauncher
)
} else {
base
}
}
mainClass().set("org.spongepowered.vanilla.applaunch.Main")
classpath().from(vanillaAppLaunch.runtimeClasspath, vanillaAppLaunch.output)
}
}
commonProject.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach {
accessWidener(it)
}
vanillaProject.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach { accessWidener(it) }
}
dependencies {
val jlineVersion: String by project
api(launch.map { it.output })
implementation(accessors.map { it.output })
implementation(project(commonProject.path))
vanillaMixinsImplementation(project(commonProject.path))
add(vanillaLaunch.implementationConfigurationName, project(":SpongeAPI"))
vanillaInstallerConfig("com.google.code.gson:gson:2.8.0")
vanillaInstallerConfig("org.spongepowered:configurate-hocon:4.0.0")
vanillaInstallerConfig("org.spongepowered:configurate-core:4.0.0")
vanillaInstallerConfig("net.sf.jopt-simple:jopt-simple:5.0.3")
vanillaInstallerConfig("org.tinylog:tinylog-api:2.2.1")
vanillaInstallerConfig("org.tinylog:tinylog-impl:2.2.1")
// Override ASM versions, and explicitly declare dependencies so ASM is excluded from the manifest.
val asmExclusions = sequenceOf("-commons", "-tree", "-analysis", "")
.map { "asm$it" }
.onEach {
vanillaInstallerConfig("org.ow2.asm:$it:$asmVersion")
}.toSet()
vanillaInstallerConfig("org.cadixdev:atlas:0.2.1") {
asmExclusions.forEach { exclude(group = "org.ow2.asm", module = it) } // Use our own ASM version
}
vanillaInstallerConfig("org.cadixdev:lorenz-asm:0.5.6") {
asmExclusions.forEach { exclude(group = "org.ow2.asm", module = it) } // Use our own ASM version
}
vanillaInstallerConfig("org.cadixdev:lorenz-io-proguard:0.5.6")
vanillaAppLaunchConfig(project(":SpongeAPI"))
vanillaAppLaunchConfig(platform("net.kyori:adventure-bom:4.7.0"))
vanillaAppLaunchConfig("net.kyori:adventure-serializer-configurate4")
vanillaAppLaunchConfig("org.spongepowered:mixin:$mixinVersion")
vanillaAppLaunchConfig("org.ow2.asm:asm-util:$asmVersion")
vanillaAppLaunchConfig("org.ow2.asm:asm-tree:$asmVersion")
vanillaAppLaunchConfig("com.google.guava:guava:$guavaVersion")
vanillaAppLaunchConfig("org.spongepowered:plugin-spi:$pluginSpiVersion")
vanillaAppLaunchConfig("javax.inject:javax.inject:1")
vanillaAppLaunchConfig("org.apache.logging.log4j:log4j-api:2.11.2")
vanillaAppLaunchConfig("org.apache.logging.log4j:log4j-core:2.11.2")
vanillaAppLaunchConfig("com.lmax:disruptor:3.4.2")
vanillaAppLaunchConfig("com.zaxxer:HikariCP:2.6.3")
vanillaAppLaunchConfig("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2")
vanillaAppLaunchConfig(platform("org.spongepowered:configurate-bom:4.0.0"))
vanillaAppLaunchConfig("org.spongepowered:configurate-core") {
exclude(group = "org.checkerframework", module = "checker-qual")
}
vanillaAppLaunchConfig("org.spongepowered:configurate-hocon") {
exclude(group = "org.spongepowered", module = "configurate-core")
exclude(group = "org.checkerframework", module = "checker-qual")
}
vanillaAppLaunchConfig("org.spongepowered:configurate-jackson") {
exclude(group = "org.spongepowered", module = "configurate-core")
exclude(group = "org.checkerframework", module = "checker-qual")
}
vanillaLibrariesConfig("net.minecrell:terminalconsoleappender:1.2.0")
vanillaLibrariesConfig("org.jline:jline-terminal:$jlineVersion")
vanillaLibrariesConfig("org.jline:jline-reader:$jlineVersion")
vanillaLibrariesConfig("org.jline:jline-terminal-jansi:$jlineVersion") {
exclude("org.fusesource.jansi") // Use our own JAnsi
}
// A newer version is required to make log4j happy
vanillaLibrariesConfig("org.fusesource.jansi:jansi:2.3.1")
// Launch Dependencies - Needed to bootstrap the engine(s)
// The ModLauncher compatibility launch layer
vanillaAppLaunchConfig("cpw.mods:modlauncher:$modlauncherVersion") {
exclude(group = "org.apache.logging.log4j")
}
vanillaAppLaunchConfig("org.ow2.asm:asm-commons:$asmVersion")
vanillaAppLaunchConfig("cpw.mods:grossjava9hacks:1.3.3") {
exclude(group = "org.apache.logging.log4j")
}
vanillaAppLaunchConfig("net.fabricmc:access-widener:1.0.2") {
exclude(group = "org.apache.logging.log4j")
}
testplugins?.apply {
vanillaAppLaunchRuntime(project(testplugins.path)) {
exclude(group = "org.spongepowered")
}
}
}
val vanillaManifest = the<JavaPluginConvention>().manifest {
attributes(
"Specification-Title" to "SpongeVanilla",
"Specification-Vendor" to "SpongePowered",
"Specification-Version" to apiProject.version,
"Implementation-Title" to project.name,
"Implementation-Version" to generatePlatformBuildVersionString(apiProject.version as String, minecraftVersion, recommendedVersion),
"Implementation-Vendor" to "SpongePowered"
)
}
tasks {
jar {
manifest.from(vanillaManifest)
}
val vanillaInstallerJar by registering(Jar::class) {
archiveClassifier.set("installer")
manifest{
from(vanillaManifest)
attributes(
"Premain-Class" to "org.spongepowered.vanilla.installer.Agent",
"Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Multi-Release" to true
)
}
from(vanillaInstaller.output)
into("META-INF/versions/9/") {
from(vanillaInstallerJava9.output)
}
}
val vanillaAppLaunchJar by registering(Jar::class) {
archiveClassifier.set("applaunch")
manifest.from(vanillaManifest)
from(vanillaAppLaunch.output)
}
val vanillaLaunchJar by registering(Jar::class) {
archiveClassifier.set("launch")
manifest.from(vanillaManifest)
from(vanillaLaunch.output)
}
val vanillaMixinsJar by registering(Jar::class) {
archiveClassifier.set("mixins")
manifest.from(vanillaManifest)
from(vanillaMixins.output)
}
val integrationTest by registering {
group = LifecycleBasePlugin.VERIFICATION_GROUP
dependsOn("integrationTestServer", "integrationTestClient")
}
val installerTemplateSource = vanillaProject.file("src/installer/templates")
val installerTemplateDest = vanillaProject.layout.buildDirectory.dir("generated/sources/installerTemplates")
val generateInstallerTemplates by registering(Copy::class) {
group = "sponge"
description = "Generate classes from templates for the SpongeVanilla installer"
val properties = mutableMapOf(
"minecraftVersion" to minecraftVersion
)
inputs.properties(properties)
// Copy template
from(installerTemplateSource)
into(installerTemplateDest)
expand(properties)
}
vanillaInstaller.java.srcDir(generateInstallerTemplates.map { it.outputs })
val installerResources = vanillaProject.layout.buildDirectory.dir("generated/resources/installer")
vanillaInstaller.resources.srcDir(installerResources)
val emitDependencies by registering(OutputDependenciesToJson::class) {
group = "sponge"
// everything in applaunch
configuration.set(vanillaAppLaunchConfig)
// except what we're providing through the installer
excludeConfiguration.set(vanillaInstallerConfig)
// for accesstransformers
allowedClassifiers.add("service")
outputFile.set(installerResources.map { it.file("libraries.json") })
}
named(vanillaInstaller.processResourcesTaskName).configure {
dependsOn(emitDependencies)
}
shadowJar {
mergeServiceFiles()
archiveClassifier.set("universal")
manifest {
attributes(mapOf(
"Access-Widener" to "common.accesswidener",
"Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain",
"Launch-Target" to "sponge_server_prod",
"Multi-Release" to true,
"Premain-Class" to "org.spongepowered.vanilla.installer.Agent",
"Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent"
))
from(vanillaManifest)
}
from(commonProject.tasks.jar)
from(commonProject.tasks.named("mixinsJar"))
from(commonProject.tasks.named("accessorsJar"))
from(commonProject.tasks.named("launchJar"))
from(commonProject.tasks.named("applaunchJar"))
from(jar)
from(vanillaInstallerJar)
from(vanillaAppLaunchJar)
from(vanillaLaunchJar)
from(vanillaMixinsJar)
from(vanillaInstallerConfig)
dependencies {
include(project(":"))
include(project(":SpongeAPI"))
}
// We cannot have modules in a shaded jar
exclude("META-INF/versions/*/module-info.class")
exclude("module-info.class")
}
assemble {
dependsOn(shadowJar)
}
}
license {
(this as ExtensionAware).extra.apply {
this["name"] = "Sponge"
this["organization"] = organization
this["url"] = projectUrl
}
header = apiProject.file("HEADER.txt")
include("**/*.java")
newLine = false
}
val shadowJar by tasks.existing
val vanillaInstallerJar by tasks.existing
val vanillaAppLaunchJar by tasks.existing
val vanillaLaunchJar by tasks.existing
val vanillaMixinsJar by tasks.existing
publishing {
publications {
register("sponge", MavenPublication::class) {
artifact(shadowJar.get())
artifact(vanillaInstallerJar.get())
artifact(vanillaAppLaunchJar.get())
artifact(vanillaLaunchJar.get())
artifact(vanillaMixinsJar.get())
artifact(tasks["applaunchSourceJar"])
artifact(tasks["launchSourceJar"])
artifact(tasks["mixinsSourceJar"])
pom {
artifactId = project.name.toLowerCase()
this.name.set(project.name)
this.description.set(project.description)
this.url.set(projectUrl)
licenses {
license {
this.name.set("MIT")
this.url.set("https://opensource.org/licenses/MIT")
}
}
scm {
connection.set("scm:git:git://github.com/SpongePowered/Sponge.git")
developerConnection.set("scm:git:ssh://github.com/SpongePowered/Sponge.git")
this.url.set(projectUrl)
}
}
}
}
}
}
abstract class OutputDependenciesToJson: DefaultTask() {
companion object {
val GSON: com.google.gson.Gson = com.google.gson.GsonBuilder().also {
it.setPrettyPrinting()
}.create()
}
/**
* A single dependency
*/
data class DependencyDescriptor(val group: String, val module: String, val version: String, val md5: String)
/**
* A manifest containing a list of dependencies.
*
* At runtime, transitive dependencies won't be traversed, so this needs to
* include direct + transitive depends.
*/
data class DependencyManifest(val dependencies: List<DependencyDescriptor>)
/**
* Configuration to gather depenency artifacts from
*/
@get:org.gradle.api.tasks.Input
abstract val configuration: Property<Configuration>
/**
* Excludes configuration, to remove certain entries from dependencies and transitive dependencies of [configuration]
*/
@get:org.gradle.api.tasks.Input
abstract val excludeConfiguration: Property<Configuration>
/**
* Classifiers to include in the dependency manifest. The empty string identifies no classifier.
*/
@get:org.gradle.api.tasks.Input
abstract val allowedClassifiers: SetProperty<String>
@get:org.gradle.api.tasks.OutputFile
abstract val outputFile: RegularFileProperty
init {
allowedClassifiers.add("")
}
@org.gradle.api.tasks.TaskAction
fun generateDependenciesJson() {
val foundConfig = if (this.excludeConfiguration.isPresent) {
val config = this.configuration.get().copyRecursive()
val excludes = this.excludeConfiguration.get()
excludes.allDependencies.forEach {
config.exclude(group = it.group, module = it.name)
}
config
} else {
this.configuration.get()
}
val manifest = foundConfig.resolvedConfiguration.firstLevelModuleDependencies.asSequence()
.flatMap { it.allModuleArtifacts.asSequence() }
// only jars with the allowed classifiers
.filter { it.extension == "jar" && allowedClassifiers.get().contains(it.classifier ?: "") }
.filter { it.moduleVersion.id.name != "SpongeAPI" }
.distinct()
.map { dependency ->
val ident = dependency.moduleVersion.id
val version = (dependency.id.componentIdentifier as? ModuleComponentIdentifier)?.version ?: ident.version
// Get file input stream for reading the file content
val md5hash = dependency.file.inputStream().use {
val hasher = MessageDigest.getInstance("MD5")
val buf = ByteArray(4096)
var read: Int = it.read(buf)
while (read != -1) {
hasher.update(buf, 0, read)
read = it.read(buf)
}
hasher.digest().joinToString("") { "%02x".format(it) }
}
// create descriptor
DependencyDescriptor(
group = ident.group,
module = ident.name,
version = version,
md5 = md5hash
)
}.toList().run {
DependencyManifest(this)
}
logger.info("Writing version manifest to ${outputFile.get().asFile}")
this.outputFile.get().asFile.bufferedWriter(Charsets.UTF_8).use {
GSON.toJson(manifest, it)
}
}
}
-15
View File
@@ -1,15 +0,0 @@
plugins {
`kotlin-dsl`
`java-library`
idea
}
repositories {
maven("https://repo.spongepowered.org/repository/maven-public/")
}
dependencies {
implementation("org.spongepowered:vanillagradle:0.1")
// implementation("org.spongepowered:mixingradle:0.7-SNAPSHOT")
implementation("com.google.code.gson:gson:2.8.6")
}
+2 -2
View File
@@ -18,5 +18,5 @@ junitVersion=5.7.0
jlineVersion=3.19.0
org.gradle.jvmargs=-Xss4m
org.gradle.vfs.watch=true
org.gradle.caching=true
org.gradle.parallel=true
org.gradle.caching=false
Binary file not shown.
+1 -1
View File
@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Vendored
+14 -17
View File
@@ -82,6 +82,7 @@ esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
@@ -129,6 +130,7 @@ fi
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
@@ -154,19 +156,19 @@ if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
i=`expr $i + 1`
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
@@ -175,14 +177,9 @@ save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=$(save "$@")
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"
Vendored
+7 -18
View File
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@@ -37,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -51,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -61,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
+1 -1
View File
@@ -1,3 +1,3 @@
#!/usr/bin/env sh
# -u = --no-search-upwards
./gradlew --daemon -u licenseFormat
./gradlew --daemon check
+59 -6
View File
@@ -1,18 +1,29 @@
rootProject.name = "Sponge"
import org.spongepowered.gradle.vanilla.repository.MinecraftRepositoryExtension
include("SpongeAPI")
include(":SpongeVanilla")
project(":SpongeVanilla").projectDir = file("vanilla")
pluginManagement {
repositories {
maven("https://repo.spongepowered.org/repository/maven-public/") {
name = "sponge"
}
}
plugins {
// Default plugin versions
id("org.spongepowered.gradle.vanilla") version "0.2-SNAPSHOT"
id("org.cadixdev.licenser") version "0.5.1"
id("com.github.johnrengelman.shadow") version "6.1.0"
id("org.spongepowered.gradle.sponge.dev") version "1.0.3"
id("implementation-structure")
id("org.jetbrains.gradle.plugin.idea-ext") version "1.0"
}
}
plugins {
id("org.spongepowered.gradle.vanilla")
}
dependencyResolutionManagement {
// repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) // TODO: Apply this once SpongeAPI is properly isolated
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
maven("https://repo.spongepowered.org/repository/maven-public/") {
name = "sponge"
@@ -20,6 +31,23 @@ dependencyResolutionManagement {
}
}
rootProject.name = "Sponge"
extensions.configure(MinecraftRepositoryExtension::class) {
injectRepositories(false)
}
// Set up project structure
includeBuild("build-logic")
includeBuild("SpongeAPI") {
dependencySubstitution {
substitute(module("org.spongepowered:spongeapi")).with(project(":"))
}
}
include(":SpongeVanilla")
project(":SpongeVanilla").projectDir = file("vanilla")
val testPlugins = file("testplugins.settings.gradle.kts")
if (testPlugins.exists()) {
apply(from = testPlugins)
@@ -44,4 +72,29 @@ val spongeForgeEnabledInCi: String = startParameter.projectProperties.getOrDefau
if (spongeForgeEnabledInCi.toBoolean()) {
include(":SpongeForge")
project(":SpongeForge").projectDir = file("forge")
}
}
// Include properties from API project (with api prefix)
val apiProps = file("SpongeAPI/gradle.properties")
if (apiProps.exists()) {
val props = java.util.Properties()
apiProps.bufferedReader(Charsets.UTF_8).use {
props.load(it)
}
val extraProperties = mutableMapOf<String, String>()
props.stringPropertyNames().forEach { key ->
val value = props.getProperty(key)
if (value != null) {
if (key.startsWith("api")) {
extraProperties[key] = value
} else {
extraProperties["api${key.capitalize()}"] = value
}
}
}
gradle.beforeProject {
val extraExt = project.extensions.extraProperties
extraProperties.forEach { (k, v) -> extraExt.set(k, v) }
}
}
@@ -58,8 +58,6 @@ import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Optional;
import javax.annotation.Nonnull;
public final class SpongeCommandContextBuilder extends CommandContextBuilder<CommandSourceStack>
implements org.spongepowered.api.command.parameter.CommandContext.Builder {
@@ -481,7 +479,7 @@ public final class SpongeCommandContextBuilder extends CommandContextBuilder<Com
}
@Override
public void rollback(@Nonnull final Transaction transaction) throws IllegalArgumentException {
public void rollback(final @NonNull Transaction transaction) throws IllegalArgumentException {
if (this.transaction != null && this.transaction.peek() == transaction) {
((SpongeCommandContextBuilderTransaction) transaction).rollback();
this.removeTransaction(transaction);
@@ -43,8 +43,9 @@ public final class RegisterBuilderEventImpl extends AbstractLifecycleEvent imple
}
@Override
@SuppressWarnings({ "unchecked", "rawtypes" })
public <T extends Builder<?, @NonNull ? super T>> void register(Class<T> builderClass, Supplier<? super T> supplier) throws DuplicateRegistrationException {
((SpongeBuilderProvider) Sponge.game().builderProvider()).register(builderClass, Objects.requireNonNull((Supplier < T >) supplier,
((SpongeBuilderProvider) Sponge.game().builderProvider()).register(builderClass, (Supplier) Objects.requireNonNull(supplier,
"supplier"));
}
@@ -324,7 +324,7 @@ public final class TrackingUtil {
// Now actually switch to the new phase
try (final PhaseContext<@NonNull ?> context = phaseContext) {
context.buildAndSwitch();
PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_TICK, () -> "Wrapping Random Block Tick: " + state.toString());
PhaseTracker.LOGGER.trace(TrackingUtil.BLOCK_TICK, "Wrapping Random Block Tick: {}", state);
state.randomTick(world, pos, random);
} catch (final Exception | NoClassDefFoundError e) {
PhasePrinter.printExceptionFromPhase(PhaseTracker.getInstance().stack, e, phaseContext);
@@ -25,6 +25,9 @@
package org.spongepowered.common.mixin.api.mcp.core;
import com.mojang.serialization.Lifecycle;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.resources.ResourceLocation;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.api.registry.RegistryEntry;
import org.spongepowered.asm.mixin.Mixin;
@@ -32,9 +35,6 @@ import org.spongepowered.common.bridge.core.WritableRegistryBridge;
import java.util.Objects;
import java.util.Optional;
import net.minecraft.core.Registry;
import net.minecraft.core.WritableRegistry;
import net.minecraft.resources.ResourceLocation;
@Mixin(WritableRegistry.class)
public abstract class WritableRegistryMixin_API<T> extends RegistryMixin_API<T> {
@@ -49,7 +49,12 @@ public abstract class WritableRegistryMixin_API<T> extends RegistryMixin_API<T>
Objects.requireNonNull(key, "key");
Objects.requireNonNull(value, "value");
return Optional.ofNullable(((WritableRegistryBridge<V>) this).bridge$register(net.minecraft.resources.ResourceKey.create((net.minecraft.resources.ResourceKey<? extends Registry<V>>) this
.shadow$key(), (ResourceLocation) (Object) key), value, Lifecycle.stable()));
return Optional.ofNullable(
((WritableRegistryBridge<V>) this).bridge$register(
(net.minecraft.resources.ResourceKey<V>) net.minecraft.resources.ResourceKey
.create((net.minecraft.resources.ResourceKey<? extends Registry<T>>) this.shadow$key(), (ResourceLocation) (Object) key),
value, Lifecycle.stable()
)
);
}
}
@@ -29,7 +29,6 @@ import net.minecraft.resources.ResourceLocation;
import org.spongepowered.api.ResourceKey;
import org.spongepowered.asm.mixin.Implements;
import org.spongepowered.asm.mixin.Interface;
import org.spongepowered.asm.mixin.Intrinsic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -38,7 +37,7 @@ import org.spongepowered.asm.mixin.Shadow;
@Interface(iface = Key.class, prefix = "adventure$"),
@Interface(iface = ResourceKey.class, prefix = "resourceKey$")
})
public abstract class ResourceLocationMixin_API implements Key, ResourceKey {
public abstract class ResourceLocationMixin_API {
// @formatter:off
@Shadow public abstract String shadow$getNamespace();
@@ -53,8 +52,7 @@ public abstract class ResourceLocationMixin_API implements Key, ResourceKey {
return this.shadow$getPath();
}
@Intrinsic
public int adventure$compareTo(Key o) {
return ResourceKey.super.compareTo(o);
return -o.compareTo((Key) this);
}
}
@@ -32,6 +32,7 @@ import net.minecraft.server.PlayerAdvancements;
import org.spongepowered.api.advancement.criteria.AdvancementCriterion;
import org.spongepowered.api.advancement.criteria.ScoreAdvancementCriterion;
import org.spongepowered.api.advancement.criteria.trigger.FilteredTrigger;
import org.spongepowered.api.advancement.criteria.trigger.FilteredTriggerConfiguration;
import org.spongepowered.api.entity.living.player.server.ServerPlayer;
import org.spongepowered.api.event.Cause;
import org.spongepowered.api.event.SpongeEventFactory;
@@ -43,8 +44,8 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.common.SpongeCommon;
import org.spongepowered.common.advancement.SpongeFilteredTrigger;
import org.spongepowered.common.advancement.SpongeCriterionTrigger;
import org.spongepowered.common.advancement.SpongeFilteredTrigger;
import org.spongepowered.common.bridge.advancements.CriterionBridge;
import org.spongepowered.common.bridge.server.PlayerAdvancementsBridge;
import org.spongepowered.common.event.tracking.PhaseTracker;
@@ -76,11 +77,11 @@ public abstract class CriterionTrigger_ListenerMixin {
}
// Sponge filters are always handled in the trigger method
if (!(this.trigger instanceof SpongeFilteredTrigger)) {
final FilteredTrigger filteredTrigger = (FilteredTrigger) this.trigger;
final FilteredTrigger<FilteredTriggerConfiguration> filteredTrigger = (FilteredTrigger) this.trigger;
if (filteredTrigger.type() instanceof SpongeCriterionTrigger) {
final Cause cause = PhaseTracker.getCauseStackManager().currentCause();
final ServerPlayer player = ((PlayerAdvancementsBridge) playerAdvancements).bridge$getPlayer();
final TypeToken typeToken = TypeToken.get(filteredTrigger.type().configurationType());
final TypeToken<FilteredTriggerConfiguration> typeToken = (TypeToken) TypeToken.get(filteredTrigger.type().configurationType());
final CriterionEvent.Trigger event = SpongeEventFactory.createCriterionEventTrigger(cause,
advancement, advancementCriterion, typeToken, player, filteredTrigger, true);
SpongeCommon.postEvent(event);
+19
View File
@@ -0,0 +1,19 @@
val apiVersion: String by project
val organization: String by project
val projectUrl: String by project
dependencies {
annotationProcessor(implementation("org.spongepowered:spongeapi:$apiVersion")!!)
}
license {
(this as ExtensionAware).extra.apply {
this["name"] = "Sponge"
this["organization"] = organization
this["url"] = projectUrl
}
header = rootProject.file("HEADER.txt")
include("**/*.java")
newLine = false
}
+473
View File
@@ -0,0 +1,473 @@
plugins {
id("org.spongepowered.gradle.vanilla")
id("com.github.johnrengelman.shadow")
id("implementation-structure")
}
val commonProject = parent!!
val apiVersion: String by project
val minecraftVersion: String by project
val recommendedVersion: String by project
val organization: String by project
val projectUrl: String by project
val testplugins: Project? = rootProject.subprojects.find { "testplugins".equals(it.name) }
description = "The SpongeAPI implementation for Vanilla Minecraft"
version = spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVersion, recommendedVersion)
// Vanilla extra configurations
val vanillaLibrariesConfig = configurations.register("libraries")
val vanillaAppLaunchConfig = configurations.register("applaunch") {
extendsFrom(vanillaLibrariesConfig.get())
extendsFrom(configurations.minecraft.get())
}
val vanillaInstallerConfig = configurations.register("installer")
// Common source sets and configurations
val launchConfig = commonProject.configurations.named("launch")
val accessors = commonProject.sourceSets.named("accessors")
val launch = commonProject.sourceSets.named("launch")
val applaunch = commonProject.sourceSets.named("applaunch")
val mixins = commonProject.sourceSets.named("mixins")
val main = commonProject.sourceSets.named("main")
// Vanilla source sets
val vanillaInstaller by sourceSets.register("installer")
val vanillaInstallerJava9 by sourceSets.register("installerJava9") {
this.java.setSrcDirs(setOf("src/installer/java9"))
compileClasspath += vanillaInstaller.compileClasspath
compileClasspath += vanillaInstaller.runtimeClasspath
tasks.named(compileJavaTaskName, JavaCompile::class) {
options.release.set(9)
if (JavaVersion.current() < JavaVersion.VERSION_11) {
javaCompiler.set(javaToolchains.compilerFor { languageVersion.set(JavaLanguageVersion.of(11)) })
}
}
dependencies.add(implementationConfigurationName, objects.fileCollection().from(vanillaInstaller.output.classesDirs))
}
val vanillaMain by sourceSets.named("main") {
// implementation (compile) dependencies
spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(vanillaLibrariesConfig.get())
}
}
val vanillaLaunch by sourceSets.register("launch") {
// implementation (compile) dependencies
spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaMain, project, vanillaMain.implementationConfigurationName)
configurations.named(implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig.get())
}
}
val vanillaMixins by sourceSets.register("mixins") {
// implementation (compile) dependencies
spongeImpl.applyNamedDependencyOnOutput(commonProject, mixins.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, vanillaMain, this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.implementationConfigurationName)
}
val vanillaAppLaunch by sourceSets.register("applaunch") {
// implementation (compile) dependencies
spongeImpl.applyNamedDependencyOnOutput(commonProject, applaunch.get(), this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, launch.get(), vanillaLaunch, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, vanillaInstaller, this, project, this.implementationConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, this, vanillaLaunch, project, vanillaLaunch.implementationConfigurationName)
// runtime dependencies - literally add the rest of the project, because we want to launch the game
spongeImpl.applyNamedDependencyOnOutput(project, vanillaMixins, this, project, this.runtimeOnlyConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, vanillaLaunch, this, project, this.runtimeOnlyConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, mixins.get(), this, project, this.runtimeOnlyConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, main.get(), this, project, this.runtimeOnlyConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(commonProject, accessors.get(), this, project, this.runtimeOnlyConfigurationName)
spongeImpl.applyNamedDependencyOnOutput(project, vanillaMain, this, project, this.runtimeOnlyConfigurationName)
}
val vanillaMixinsImplementation by configurations.named(vanillaMixins.implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig.get())
}
configurations.named(vanillaInstaller.implementationConfigurationName) {
extendsFrom(vanillaInstallerConfig.get())
}
configurations.named(vanillaAppLaunch.implementationConfigurationName) {
extendsFrom(vanillaAppLaunchConfig.get())
extendsFrom(launchConfig.get())
}
val vanillaAppLaunchRuntime by configurations.named(vanillaAppLaunch.runtimeOnlyConfigurationName)
minecraft {
runs {
// Full development environment
sequenceOf(8, 11, 16).forEach {
server("runJava${it}Server") {
args("--nogui", "--launchTarget", "sponge_server_dev")
targetVersion(it)
}
client("runJava${it}Client") {
args("--launchTarget", "sponge_client_dev")
targetVersion(it)
}
}
// Lightweight integration tests
server("integrationTestServer") {
args("--launchTarget", "sponge_server_it")
}
client("integrationTestClient") {
args("--launchTarget", "sponge_client_it")
}
configureEach {
workingDirectory(project.file("run/"))
if (org.spongepowered.gradle.vanilla.util.IdeConfigurer.isIdeaImport()) {
// IntelliJ does not properly report its compatibility
jvmArgs("-Dterminal.ansi=true", "-Djansi.mode=force")
} else if (org.spongepowered.gradle.vanilla.util.IdeConfigurer.isEclipseImport()) {
// Eclipse doesn't handle ansi, even if the "process escape sequences" option is enabled...
// jvmArgs("-Dspongevanilla.disableAnsi=true")
}
jvmArgs("-Dlog4j.configurationFile=log4j2_dev.xml")
allJvmArgumentProviders += CommandLineArgumentProvider {
// Resolve the Mixin artifact for use as a reload agent
val mixinJar = vanillaAppLaunchConfig.resolvedConfiguration
.getFiles { it.name == "mixin" && it.group == "org.spongepowered" }
.firstOrNull()
// The mixin agent initializes logging too early, which prevents jansi from properly stripping escape codes in Eclipse.
val base = if (!org.spongepowered.gradle.vanilla.util.IdeConfigurer.isEclipseImport() && mixinJar != null) {
listOf("-javaagent:$mixinJar")
} else {
emptyList()
}
// Then add necessary module cracks
if (!this.name.contains("Java8")) {
base + listOf(
"--illegal-access=deny", // enable strict mode in prep for Java 16
"--add-exports=java.base/sun.security.util=ALL-UNNAMED", // ModLauncher
"--add-opens=java.base/java.util.jar=ALL-UNNAMED" // ModLauncher
)
} else {
base
}
}
mainClass("org.spongepowered.vanilla.applaunch.Main")
classpath.setFrom(
vanillaAppLaunch.output,
vanillaAppLaunch.runtimeClasspath,
configurations.minecraft
)
ideaRunSourceSet.set(vanillaAppLaunch)
}
}
commonProject.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach {
accessWideners(it)
}
project.sourceSets["main"].resources
.filter { it.name.endsWith(".accesswidener") }
.files
.forEach { accessWideners(it) }
}
dependencies {
val asmVersion: String by project
val guavaVersion: String by project
val jlineVersion: String by project
val mixinVersion: String by project
val modlauncherVersion: String by project
val pluginSpiVersion: String by project
api(project(":", configuration = "launch"))
implementation(project(":", configuration = "accessors"))
implementation(project(commonProject.path))
vanillaMixinsImplementation(project(commonProject.path))
add(vanillaLaunch.implementationConfigurationName, "org.spongepowered:spongeapi:$apiVersion")
val installer = vanillaInstallerConfig.name
installer("com.google.code.gson:gson:2.8.0")
installer("org.spongepowered:configurate-hocon:4.0.0")
installer("org.spongepowered:configurate-core:4.0.0")
installer("net.sf.jopt-simple:jopt-simple:5.0.3")
installer("org.tinylog:tinylog-api:2.2.1")
installer("org.tinylog:tinylog-impl:2.2.1")
// Override ASM versions, and explicitly declare dependencies so ASM is excluded from the manifest.
val asmExclusions = sequenceOf("-commons", "-tree", "-analysis", "")
.map { "asm$it" }
.onEach {
installer("org.ow2.asm:$it:$asmVersion")
}.toSet()
installer("org.cadixdev:atlas:0.2.1") {
asmExclusions.forEach { exclude(group = "org.ow2.asm", module = it) } // Use our own ASM version
}
installer("org.cadixdev:lorenz-asm:0.5.6") {
asmExclusions.forEach { exclude(group = "org.ow2.asm", module = it) } // Use our own ASM version
}
installer("org.cadixdev:lorenz-io-proguard:0.5.6")
// Add the API as a runtime dependency, just so it gets shaded into the jar
add(vanillaInstaller.runtimeOnlyConfigurationName, "org.spongepowered:spongeapi:$apiVersion") {
isTransitive = false
}
val appLaunch = vanillaAppLaunchConfig.name
appLaunch("org.spongepowered:spongeapi:$apiVersion")
appLaunch(platform("net.kyori:adventure-bom:4.7.0"))
appLaunch("net.kyori:adventure-serializer-configurate4")
appLaunch("org.spongepowered:mixin:$mixinVersion")
appLaunch("org.ow2.asm:asm-util:$asmVersion")
appLaunch("org.ow2.asm:asm-tree:$asmVersion")
appLaunch("com.google.guava:guava:$guavaVersion")
appLaunch("org.spongepowered:plugin-spi:$pluginSpiVersion")
appLaunch("javax.inject:javax.inject:1")
appLaunch("org.apache.logging.log4j:log4j-api:2.11.2")
appLaunch("org.apache.logging.log4j:log4j-core:2.11.2")
appLaunch("com.lmax:disruptor:3.4.2")
appLaunch("com.zaxxer:HikariCP:2.6.3")
appLaunch("org.apache.logging.log4j:log4j-slf4j-impl:2.11.2")
appLaunch(platform("org.spongepowered:configurate-bom:4.0.0"))
appLaunch("org.spongepowered:configurate-core") {
exclude(group = "org.checkerframework", module = "checker-qual")
}
appLaunch("org.spongepowered:configurate-hocon") {
exclude(group = "org.spongepowered", module = "configurate-core")
exclude(group = "org.checkerframework", module = "checker-qual")
}
appLaunch("org.spongepowered:configurate-jackson") {
exclude(group = "org.spongepowered", module = "configurate-core")
exclude(group = "org.checkerframework", module = "checker-qual")
}
val libraries = vanillaLibrariesConfig.name
libraries("net.minecrell:terminalconsoleappender:1.2.0")
libraries("org.jline:jline-terminal:$jlineVersion")
libraries("org.jline:jline-reader:$jlineVersion")
libraries("org.jline:jline-terminal-jansi:$jlineVersion") {
exclude("org.fusesource.jansi") // Use our own JAnsi
}
// A newer version is required to make log4j happy
libraries("org.fusesource.jansi:jansi:2.3.1")
// Launch Dependencies - Needed to bootstrap the engine(s)
// The ModLauncher compatibility launch layer
appLaunch("cpw.mods:modlauncher:$modlauncherVersion") {
exclude(group = "org.apache.logging.log4j")
exclude(group = "net.sf.jopt-simple") // uses a newer version than MC
}
appLaunch("org.ow2.asm:asm-commons:$asmVersion")
appLaunch("cpw.mods:grossjava9hacks:1.3.3") {
exclude(group = "org.apache.logging.log4j")
}
appLaunch("net.fabricmc:access-widener:1.0.2") {
exclude(group = "org.apache.logging.log4j")
}
testplugins?.also {
vanillaAppLaunchRuntime(project(it.path)) {
exclude(group = "org.spongepowered")
}
}
}
val vanillaManifest = the<JavaPluginConvention>().manifest {
attributes(
"Specification-Title" to "SpongeVanilla",
"Specification-Vendor" to "SpongePowered",
"Specification-Version" to apiVersion,
"Implementation-Title" to project.name,
"Implementation-Version" to spongeImpl.generatePlatformBuildVersionString(apiVersion, minecraftVersion, recommendedVersion),
"Implementation-Vendor" to "SpongePowered"
)
}
tasks {
jar {
manifest.from(vanillaManifest)
}
val vanillaInstallerJar by registering(Jar::class) {
archiveClassifier.set("installer")
manifest{
from(vanillaManifest)
attributes(
"Premain-Class" to "org.spongepowered.vanilla.installer.Agent",
"Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Multi-Release" to true
)
}
from(vanillaInstaller.output)
into("META-INF/versions/9/") {
from(vanillaInstallerJava9.output)
}
}
val vanillaAppLaunchJar by registering(Jar::class) {
archiveClassifier.set("applaunch")
manifest.from(vanillaManifest)
from(vanillaAppLaunch.output)
}
val vanillaLaunchJar by registering(Jar::class) {
archiveClassifier.set("launch")
manifest.from(vanillaManifest)
from(vanillaLaunch.output)
}
val vanillaMixinsJar by registering(Jar::class) {
archiveClassifier.set("mixins")
manifest.from(vanillaManifest)
from(vanillaMixins.output)
}
val integrationTest by registering {
group = LifecycleBasePlugin.VERIFICATION_GROUP
dependsOn("integrationTestServer", "integrationTestClient")
}
val installerTemplateSource = project.file("src/installer/templates")
val installerTemplateDest = project.layout.buildDirectory.dir("generated/sources/installerTemplates")
val generateInstallerTemplates by registering(Copy::class) {
group = "sponge"
description = "Generate classes from templates for the SpongeVanilla installer"
val properties = mutableMapOf(
"minecraftVersion" to minecraftVersion
)
inputs.properties(properties)
// Copy template
from(installerTemplateSource)
into(installerTemplateDest)
expand(properties)
}
vanillaInstaller.java.srcDir(generateInstallerTemplates.map { it.outputs })
val installerResources = project.layout.buildDirectory.dir("generated/resources/installer")
vanillaInstaller.resources.srcDir(installerResources)
val downloadNotNeeded = configurations.register("downloadNotNeeded") {
extendsFrom(configurations.minecraft.get())
extendsFrom(vanillaInstallerConfig.get())
}
val emitDependencies by registering(org.spongepowered.gradle.impl.OutputDependenciesToJson::class) {
group = "sponge"
// everything in applaunch
this.dependencies(vanillaAppLaunchConfig)
// except what we're providing through the installer
this.excludedDependencies(downloadNotNeeded)
outputFile.set(installerResources.map { it.file("libraries.json") })
}
named(vanillaInstaller.processResourcesTaskName).configure {
dependsOn(emitDependencies)
}
shadowJar {
mergeServiceFiles()
configurations = listOf(project.configurations.getByName(vanillaInstaller.runtimeClasspathConfigurationName))
archiveClassifier.set("universal")
manifest {
attributes(mapOf(
"Access-Widener" to "common.accesswidener",
"Main-Class" to "org.spongepowered.vanilla.installer.InstallerMain",
"Launch-Target" to "sponge_server_prod",
"Multi-Release" to true,
"Premain-Class" to "org.spongepowered.vanilla.installer.Agent",
"Agent-Class" to "org.spongepowered.vanilla.installer.Agent",
"Launcher-Agent-Class" to "org.spongepowered.vanilla.installer.Agent"
))
from(vanillaManifest)
}
from(commonProject.sourceSets.main.map { it.output })
from(commonProject.sourceSets.named("mixins").map {it.output })
from(commonProject.sourceSets.named("accessors").map {it.output })
from(commonProject.sourceSets.named("launch").map {it.output })
from(commonProject.sourceSets.named("applaunch").map {it.output })
from(sourceSets.main.map {it.output })
from(vanillaInstaller.output)
from(vanillaInstallerJava9.output) {
into("META-INF/versions/9/")
}
from(vanillaAppLaunch.output)
from(vanillaLaunch.output)
from(vanillaMixins.output)
/*dependencies {
// include(project(":"))
include("org.spongepowered:spongeapi:$apiVersion")
} */
// We cannot have modules in a shaded jar
exclude("META-INF/versions/*/module-info.class")
exclude("module-info.class")
}
assemble {
dependsOn(shadowJar)
}
}
license {
(this as ExtensionAware).extra.apply {
this["name"] = "Sponge"
this["organization"] = organization
this["url"] = projectUrl
}
header = rootProject.file("HEADER.txt")
include("**/*.java")
newLine = false
}
val shadowJar by tasks.existing
val vanillaInstallerJar by tasks.existing
val vanillaAppLaunchJar by tasks.existing
val vanillaLaunchJar by tasks.existing
val vanillaMixinsJar by tasks.existing
publishing {
publications {
register("sponge", MavenPublication::class) {
artifact(shadowJar.get())
artifact(vanillaInstallerJar.get())
artifact(vanillaAppLaunchJar.get())
artifact(vanillaLaunchJar.get())
artifact(vanillaMixinsJar.get())
artifact(tasks["applaunchSourceJar"])
artifact(tasks["launchSourceJar"])
artifact(tasks["mixinsSourceJar"])
pom {
artifactId = project.name.toLowerCase()
this.name.set(project.name)
this.description.set(project.description)
this.url.set(projectUrl)
licenses {
license {
this.name.set("MIT")
this.url.set("https://opensource.org/licenses/MIT")
}
}
scm {
connection.set("scm:git:git://github.com/SpongePowered/Sponge.git")
developerConnection.set("scm:git:ssh://github.com/SpongePowered/Sponge.git")
this.url.set(projectUrl)
}
}
}
}
}
@@ -44,7 +44,7 @@ public final class MixinServiceVanillaModLauncher extends MixinServiceModLaunche
private static final class ContainerHandleVanillaModLauncher extends ContainerHandleModLauncher {
public ContainerHandleVanillaModLauncher(String name) {
public ContainerHandleVanillaModLauncher(final String name) {
super(name);
this.setAttribute(Constants.ManifestAttributes.MIXINCONNECTOR, "org.spongepowered.vanilla.applaunch.mixin.VanillaLaunchMixinConnector");
@@ -33,7 +33,6 @@ import java.lang.instrument.Instrumentation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
@@ -37,6 +37,7 @@ import org.spongepowered.plugin.PluginResource;
import org.spongepowered.vanilla.applaunch.plugin.VanillaPluginEngine;
import org.spongepowered.vanilla.launch.VanillaLaunch;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -96,7 +97,7 @@ public final class VanillaPluginManager implements SpongePluginManager {
}
@Override
public void addDummyPlugin(DummyPluginContainer plugin) {
public void addDummyPlugin(final DummyPluginContainer plugin) {
Objects.requireNonNull(plugin);
this.plugins.put(plugin.getMetadata().getId(), plugin);
@@ -110,8 +111,8 @@ public final class VanillaPluginManager implements SpongePluginManager {
final String loaderClass = languageService.getPluginLoader();
final PluginLoader<PluginResource, PluginContainer> pluginLoader;
try {
pluginLoader = (PluginLoader<PluginResource, PluginContainer>) Class.forName(loaderClass).newInstance();
} catch (final InstantiationException | IllegalAccessException | ClassNotFoundException e) {
pluginLoader = (PluginLoader<PluginResource, PluginContainer>) Class.forName(loaderClass).getConstructor().newInstance();
} catch (final InstantiationException | IllegalAccessException | ClassNotFoundException | NoSuchMethodException | InvocationTargetException e) {
throw new RuntimeException(e);
}
for (final PluginCandidate<PluginResource> candidate : candidates) {