diff --git a/build-logic/build.gradle b/build-logic/build.gradle index 5cabd817724..1539cbfb1a6 100644 --- a/build-logic/build.gradle +++ b/build-logic/build.gradle @@ -13,6 +13,11 @@ indra { dependencies { api(apiLibs.gson) implementation("gradle.plugin.org.jetbrains.gradle.plugin.idea-ext:gradle-idea-ext:${apiLibs.versions.ideaExt.get()}") + implementation(libs.at) + implementation(libs.accessWidener) + + // arch-loom is used by SpongeNeo but must be declared here to avoid a classloader conflict with its transitive dependencies + api("dev.architectury:architectury-loom:1.6.411") } indraSpotlessLicenser { diff --git a/build-logic/settings.gradle b/build-logic/settings.gradle index 9e7a64e236c..3e53ae9cde4 100644 --- a/build-logic/settings.gradle +++ b/build-logic/settings.gradle @@ -9,7 +9,14 @@ pluginManagement { dependencyResolutionManagement { repositoriesMode = RepositoriesMode.FAIL_ON_PROJECT_REPOS - repositories { pluginManagement.repositories.each { add(it) } } + repositories { + pluginManagement.repositories.each { add(it) } + maven { + url = "https://maven.architectury.dev/" + name = "architectury" + } + } + versionCatalogs { libs { from files("../gradle/libs.versions.toml") diff --git a/build-logic/src/main/java/org/spongepowered/gradle/impl/ConvertAWToAT.java b/build-logic/src/main/java/org/spongepowered/gradle/impl/ConvertAWToAT.java new file mode 100644 index 00000000000..d3f1e05193d --- /dev/null +++ b/build-logic/src/main/java/org/spongepowered/gradle/impl/ConvertAWToAT.java @@ -0,0 +1,109 @@ +/* + * This file is part of Sponge, licensed under the MIT License (MIT). + * + * Copyright (c) SpongePowered + * 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 dev.architectury.at.AccessChange; +import dev.architectury.at.AccessTransform; +import dev.architectury.at.AccessTransformSet; +import dev.architectury.at.ModifierChange; +import dev.architectury.at.io.AccessTransformFormats; +import net.fabricmc.accesswidener.AccessWidenerReader; +import net.fabricmc.accesswidener.AccessWidenerVisitor; +import org.cadixdev.bombe.type.signature.MethodSignature; +import org.gradle.api.DefaultTask; +import org.gradle.api.GradleException; +import org.gradle.api.file.ConfigurableFileCollection; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.InputFiles; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.TaskAction; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Set; + +public abstract class ConvertAWToAT extends DefaultTask { + + @InputFiles + public abstract ConfigurableFileCollection getAccessWideners(); + + public void accessWideners(Object... paths) { + this.getAccessWideners().from(paths); + } + + @OutputFile + public abstract RegularFileProperty getAccessTransformer(); + + @TaskAction + public void convert() { + final Set awFiles = this.getAccessWideners().getFiles(); + final File atFile = this.getAccessTransformer().get().getAsFile(); + + final AccessTransformSet at = AccessTransformSet.create(); + + for (final File awFile : awFiles) { + try (final BufferedReader reader = Files.newBufferedReader(awFile.toPath())) { + ConvertAWToAT.convert(reader, at); + } catch (final IOException e) { + throw new GradleException("Failed to read access widener: " + awFile, e); + } + } + + try (final BufferedWriter writer = Files.newBufferedWriter(atFile.toPath())) { + AccessTransformFormats.FML.write(writer, at); + } catch (IOException e) { + throw new GradleException("Failed to write access transformer: " + atFile, e); + } + } + + public static void convert(final BufferedReader reader, final AccessTransformSet at) throws IOException { + new AccessWidenerReader(new AccessWidenerVisitor() { + @Override + public void visitClass(final String name, final AccessWidenerReader.AccessType access, final boolean transitive) { + at.getOrCreateClass(name).merge(ConvertAWToAT.convertEntry(access)); + } + + @Override + public void visitMethod(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) { + at.getOrCreateClass(owner).mergeMethod(MethodSignature.of(name, descriptor), ConvertAWToAT.convertEntry(access)); + } + + @Override + public void visitField(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) { + at.getOrCreateClass(owner).mergeField(name, ConvertAWToAT.convertEntry(access)); + } + }).read(reader); + } + + public static AccessTransform convertEntry(final AccessWidenerReader.AccessType access) { + return switch (access) { + case ACCESSIBLE -> AccessTransform.of(AccessChange.PUBLIC); + case EXTENDABLE, MUTABLE -> AccessTransform.of(AccessChange.PUBLIC, ModifierChange.REMOVE); + }; + } +} diff --git a/build.gradle.kts b/build.gradle.kts index 936320ff20b..85ce26ad312 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -176,6 +176,10 @@ dependencies { } } +minecraft { + accessWideners(main.resources.filter { it.name.endsWith(".accesswidener") }) +} + allprojects { configurations.configureEach { resolutionStrategy.dependencySubstitution { @@ -199,13 +203,6 @@ allprojects { minecraft { version(minecraftVersion) injectRepositories(false) - project.sourceSets["main"].resources - .filter { it.name.endsWith(".accesswidener") } - .files - .forEach { - accessWideners(it) - parent?.minecraft?.accessWideners(it) - } } dependencies { diff --git a/forge/build.gradle.kts b/forge/build.gradle.kts index 99f42629fcd..3394d182ff7 100644 --- a/forge/build.gradle.kts +++ b/forge/build.gradle.kts @@ -1,5 +1,6 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar import net.minecraftforge.gradle.userdev.UserDevExtension +import org.spongepowered.gradle.impl.ConvertAWToAT buildscript { repositories { @@ -201,11 +202,17 @@ dependencies { runtimeOnly(project(bootstrapDevProject.path)) } +val convertAWToAT = tasks.register("convertAWToAT", ConvertAWToAT::class) { + accessWideners(main.get().resources.filter { it.name.endsWith(".accesswidener") }) + accessWideners(forgeMain.resources.filter { it.name.endsWith(".accesswidener") }) + accessTransformer.set(project.layout.buildDirectory.file("generated/resources/at.cfg")) +} + val mixinConfigs: MutableSet = spongeImpl.mixinConfigurations extensions.configure(UserDevExtension::class) { mappings("official", "1.21.3") - // accessWidenerPath.set(file("../src/main/resources/common.accesswidener")) TODO + accessTransformers.from(convertAWToAT.flatMap { it.accessTransformer }) reobf = false @@ -213,8 +220,7 @@ extensions.configure(UserDevExtension::class) { configureEach { ideaModule("Sponge.SpongeForge.main") - property("forge.logging.markers", "REGISTRIES") - property("forge.logging.console.level", "debug") + // property("forge.logging.console.level", "debug") // jvmArgs("-Dbsl.debug=true") // Uncomment to debug bootstrap classpath diff --git a/generator/build.gradle.kts b/generator/build.gradle.kts index 6481b69c15c..da7ca6bedc2 100644 --- a/generator/build.gradle.kts +++ b/generator/build.gradle.kts @@ -5,12 +5,7 @@ plugins { description = "Code generator for automatically producing API catalog classes based off of Vanilla MC data" minecraft { - rootProject.sourceSets["main"].resources - .filter { it.name.endsWith(".accesswidener") } - .files - .forEach { - accessWideners(it) - } + accessWideners(rootProject.sourceSets["main"].resources.filter { it.name.endsWith(".accesswidener") }) } configurations.configureEach { diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index cbc47e0b08d..d2eca4aaf9b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -68,6 +68,7 @@ terminalConsoleAppender = { module = "net.minecrell:terminalconsoleappender", ve # buildtime-only vineflower = { module = "org.vineflower:vineflower", version.ref = "vineflower" } +at = { module = "dev.architectury:at", version = "1.0.1" } [plugins] blossom = { id = "net.kyori.blossom", version = "2.1.0" } diff --git a/neoforge/build.gradle.kts b/neoforge/build.gradle.kts index 9cd699e0d03..96e95d67d69 100644 --- a/neoforge/build.gradle.kts +++ b/neoforge/build.gradle.kts @@ -14,7 +14,7 @@ plugins { alias(libs.plugins.shadow) id("implementation-structure") alias(libs.plugins.blossom) - id("dev.architectury.loom") version "1.6.411" + id("dev.architectury.loom") } val commonProject = parent!! diff --git a/vanilla/build.gradle.kts b/vanilla/build.gradle.kts index 00ac01e6f6c..90595bb3a29 100644 --- a/vanilla/build.gradle.kts +++ b/vanilla/build.gradle.kts @@ -126,15 +126,8 @@ val superclassConfigs = spongeImpl.getNamedConfigurations("superClassChanges") val mixinConfigs = spongeImpl.mixinConfigurations minecraft { - main.get().resources - .filter { it.name.endsWith(".accesswidener") } - .files - .forEach { accessWideners(it) } - - vanillaMain.resources - .filter { it.name.endsWith(".accesswidener") } - .files - .forEach { accessWideners(it) } + accessWideners(main.get().resources.filter { it.name.endsWith(".accesswidener") }) + accessWideners(vanillaMain.resources.filter { it.name.endsWith(".accesswidener") }) } configurations.configureEach {