From 25298dc9507fea83d42644bbfa0fd290cfee7acc Mon Sep 17 00:00:00 2001 From: Jason Penilla <11360596+jpenilla@users.noreply.github.com> Date: Mon, 30 Sep 2024 18:34:12 -0700 Subject: [PATCH] WIP: Use ModDevGradle instead of archloom for common and NeoForge --- build.gradle | 56 +++----- buildSrc/build.gradle.kts | 11 ++ buildSrc/src/main/java/Aw2AtTask.java | 129 ++++++++++++++++++ buildSrc/src/main/java/CopyTask.java | 44 ++++++ fabric/build.gradle | 29 +++- neoforge/build.gradle | 58 ++++++-- neoforge/gradle.properties | 1 - settings.gradle | 3 +- .../LevelChunkSectionMixin.java | 4 +- .../fast_palette/PalettedContainerMixin.java | 10 +- src/main/resources/moonrise.accesswidener | 13 +- 11 files changed, 300 insertions(+), 58 deletions(-) create mode 100644 buildSrc/build.gradle.kts create mode 100644 buildSrc/src/main/java/Aw2AtTask.java create mode 100644 buildSrc/src/main/java/CopyTask.java delete mode 100644 neoforge/gradle.properties diff --git a/build.gradle b/build.gradle index 20539956..d3959ecd 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,8 @@ import me.modmuss50.mpp.ReleaseType plugins { - id("xyz.jpenilla.quiet-architectury-loom") + id("java-library") + id("net.neoforged.moddev") id("me.modmuss50.mod-publish-plugin") version "0.7.2" apply false } @@ -18,23 +19,38 @@ def getGitCommit = { -> return stdout.toString().trim() } +Aw2AtTask.configureDefault( + getProject(), + layout.projectDirectory.file("src/main/resources/moonrise.accesswidener").getAsFile(), + sourceSets.main +) + +neoForge { + neoFormVersion = "1.21.1-20240808.144430" + validateAccessTransformers = true +} + +tasks.named("createMinecraftArtifacts") { + dependsOn("copyAt") +} dependencies { - modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + // todo: check versions + compileOnly "net.fabricmc:sponge-mixin:0.13.4+mixin.0.8.5" + compileOnly "io.github.llamalad7:mixinextras-common:0.4.1" api("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") api("org.yaml:snakeyaml:${rootProject.snakeyaml_version}") - modImplementation "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}" + // todo: does cloth publish a platform-agnostic jar in mojang mappings? + compileOnly "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}" } -File awFile = file("src/main/resources/moonrise.accesswidener") - allprojects { group = rootProject.maven_group version = rootProject.mod_version + "+" + getGitCommit() - plugins.apply("xyz.jpenilla.quiet-architectury-loom") + plugins.apply("java-library") java { withSourcesJar() @@ -60,11 +76,6 @@ allprojects { maven { url "https://maven.terraformersmc.com/releases/" } } - dependencies { - minecraft "com.mojang:minecraft:${project.minecraft_version}" - mappings loom.officialMojangMappings() - } - // make build reproducible tasks.withType(AbstractArchiveTask).configureEach { preserveFileTimestamps = false @@ -80,31 +91,12 @@ allprojects { rename { "${it}_${rootProject.base.archivesName.get()}"} } } - - loom { - accessWidenerPath = awFile - mixin { - useLegacyMixinAp = false - } - } } subprojects { - loom.mods { - main { - sourceSet("main") - sourceSet("main", project.rootProject) - } - } - loom.runs.all { - ideConfigGenerated true - // property "mixin.debug", "true" - } - plugins.apply("me.modmuss50.mod-publish-plugin") publishMods { - file = remapJar.archiveFile if (project.version.contains("-beta.")) { type = ReleaseType.BETA } else { @@ -127,7 +119,3 @@ subprojects { } } } - -loom.runs.all { - ideConfigGenerated false -} diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts new file mode 100644 index 00000000..81dbb2bb --- /dev/null +++ b/buildSrc/build.gradle.kts @@ -0,0 +1,11 @@ +repositories { + gradlePluginPortal() + mavenCentral() + maven("https://maven.fabricmc.net/") + maven("https://maven.architectury.dev/") +} + +dependencies { + implementation("net.fabricmc:access-widener:2.1.0") + implementation("dev.architectury:at:1.0.1") +} diff --git a/buildSrc/src/main/java/Aw2AtTask.java b/buildSrc/src/main/java/Aw2AtTask.java new file mode 100644 index 00000000..c881ff85 --- /dev/null +++ b/buildSrc/src/main/java/Aw2AtTask.java @@ -0,0 +1,129 @@ +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 java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import javax.inject.Inject; +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.Project; +import org.gradle.api.file.ProjectLayout; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.tasks.CacheableTask; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputFile; +import org.gradle.api.tasks.PathSensitive; +import org.gradle.api.tasks.PathSensitivity; +import org.gradle.api.tasks.SourceSet; +import org.gradle.api.tasks.TaskAction; +import org.gradle.api.tasks.TaskProvider; + +@CacheableTask +public abstract class Aw2AtTask extends DefaultTask { + + @InputFile + @PathSensitive(PathSensitivity.NONE) + public abstract RegularFileProperty getInputFile(); + + @OutputFile + public abstract RegularFileProperty getOutputFile(); + + @Inject + public abstract ProjectLayout getLayout(); + + public static TaskProvider configureDefault( + final Project project, + final File awFile, + final SourceSet sourceSet + ) { + final TaskProvider aw2at = project.getTasks().register("aw2at", Aw2AtTask.class, task -> { + task.getOutputFile().set(project.getLayout().getBuildDirectory().file("aw2at/files/accesstransformer.cfg")); + task.getInputFile().set(awFile); + }); + + final TaskProvider copyTask = project.getTasks().register("copyAt", CopyTask.class, copy -> { + copy.getInputFile().set(aw2at.flatMap(Aw2AtTask::getOutputFile)); + copy.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir("aw2at/dir")); + copy.getDestination().set("META-INF/accesstransformer.cfg"); + }); + + sourceSet.resources(resources -> { + resources.srcDir(copyTask.flatMap(CopyTask::getOutputDirectory)); + }); + + return aw2at; + } + + @TaskAction + public void run() { + try (final BufferedReader reader = Files.newBufferedReader(this.getInputFile().get().getAsFile().toPath())) { + final AccessTransformSet accessTransformSet = toAccessTransformSet(reader); + Files.deleteIfExists(this.getOutputFile().get().getAsFile().toPath()); + Files.createDirectories(this.getOutputFile().get().getAsFile().toPath().getParent()); + AccessTransformFormats.FML.write(this.getOutputFile().get().getAsFile().toPath(), accessTransformSet); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } + + // Below methods are heavily based on architectury-loom Aw2At class (MIT licensed) + /* + MIT License + + Copyright (c) 2016 FabricMC + + 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. + */ + + public static AccessTransformSet toAccessTransformSet(final BufferedReader reader) throws IOException { + AccessTransformSet atSet = AccessTransformSet.create(); + + new AccessWidenerReader(new AccessWidenerVisitor() { + @Override + public void visitClass(final String name, final AccessWidenerReader.AccessType access, final boolean transitive) { + atSet.getOrCreateClass(name).merge(toAt(access)); + } + + @Override + public void visitMethod(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) { + atSet.getOrCreateClass(owner).mergeMethod(MethodSignature.of(name, descriptor), toAt(access)); + } + + @Override + public void visitField(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) { + atSet.getOrCreateClass(owner).mergeField(name, toAt(access)); + } + }).read(reader); + + return atSet; + } + + public static AccessTransform toAt(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/buildSrc/src/main/java/CopyTask.java b/buildSrc/src/main/java/CopyTask.java new file mode 100644 index 00000000..b727a66d --- /dev/null +++ b/buildSrc/src/main/java/CopyTask.java @@ -0,0 +1,44 @@ +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Comparator; +import java.util.stream.Stream; +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.file.RegularFileProperty; +import org.gradle.api.provider.Property; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputFile; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; + +public abstract class CopyTask extends DefaultTask { + + @InputFile + public abstract RegularFileProperty getInputFile(); + + @Input + public abstract Property getDestination(); + + @OutputDirectory + public abstract DirectoryProperty getOutputDirectory(); + + @TaskAction + public void run() { + final Path outputDirPath = this.getOutputDirectory().get().getAsFile().toPath(); + try { + try (final Stream walk = Files.walk(outputDirPath)) { + for (final Path path : walk.sorted(Comparator.reverseOrder()).toList()) { + Files.delete(path); + } + } + + final Path destFile = outputDirPath.resolve(this.getDestination().get()); + Files.createDirectories(destFile.getParent()); + + Files.copy(this.getInputFile().get().getAsFile().toPath(), destFile); + } catch (final IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/fabric/build.gradle b/fabric/build.gradle index dd01e80d..a7c28d48 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id("xyz.jpenilla.quiet-architectury-loom") + id("quiet-fabric-loom") id 'maven-publish' id 'com.gradleup.shadow' } @@ -13,10 +13,15 @@ configurations.implementation { } dependencies { - add('shadow', project([path: ":", configuration: "namedElements"])) - runtimeOnly(project(":").sourceSets.main.output) + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings loom.officialMojangMappings() modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + // todo: runs are broken (cannot find aw file) + //add('shadow', project([path: ":", configuration: "namedElements"])) + //runtimeOnly(project(":").sourceSets.main.output) + libs(project(":")) + libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}") @@ -46,6 +51,7 @@ shadowJar { } publishMods { + file = remapJar.archiveFile modLoaders = ["fabric"] modrinth { @@ -64,6 +70,23 @@ publishMods { } } +loom { + accessWidenerPath.set(getRootProject().file("src/main/resources/moonrise.accesswidener")) + mixin { + useLegacyMixinAp = false + } + runs.all { + ideConfigGenerated true + // property "mixin.debug", "true" + } + mods { + main { + sourceSet("main") + sourceSet("main", project.rootProject) + } + } +} + // Setup a run with lithium for compatibility testing sourceSets.create("lithium") configurations.create("lithium") diff --git a/neoforge/build.gradle b/neoforge/build.gradle index 045db590..84600585 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -1,7 +1,8 @@ -import net.fabricmc.loom.util.aw2at.Aw2At +import net.neoforged.moddevgradle.internal.RunGameTask +import java.nio.file.Files plugins { - id("xyz.jpenilla.quiet-architectury-loom") + id("net.neoforged.moddev") id 'maven-publish' id 'com.gradleup.shadow' } @@ -13,20 +14,54 @@ repositories { } } +Aw2AtTask.configureDefault( + getProject(), + rootProject.layout.projectDirectory.file("src/main/resources/moonrise.accesswidener").getAsFile(), + sourceSets.main +) + +neoForge { + version = rootProject.neoforge_version + validateAccessTransformers = true + runs { + client { + client() + mods.set([]) // Work around classpath issues by using the production jar for dev runs + } + server { + server() + mods.set([]) // Work around classpath issues by using the production jar for dev runs + } + } +} + +tasks.named("createMinecraftArtifacts") { + dependsOn("copyAt") +} + configurations.implementation { extendsFrom(configurations.shadow) } dependencies { - add('shadow', project([path: ":", configuration: "namedElements"])) - neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}" + add('shadow', project(":")) shadow("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") shadow("org.yaml:snakeyaml:${rootProject.snakeyaml_version}") - forgeExtra("org.yaml:snakeyaml:${rootProject.snakeyaml_version}") - modImplementation "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}" - include "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}" + implementation "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}" + jarJar "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}" +} + +// Work around classpath issues by using the production jar for dev runs +tasks.withType(RunGameTask).configureEach { + dependsOn(tasks.shadowJar) + doFirst { + def jar = file("run/mods/main.jar") + jar.parentFile.mkdirs() + jar.delete() + Files.copy(tasks.shadowJar.archiveFile.get().asFile.toPath(), jar.toPath()) + } } processResources { @@ -37,17 +72,20 @@ processResources { } } +jar { + archiveClassifier = "" +} + shadowJar { - archiveClassifier = "dev-all" + archiveClassifier = "" destinationDirectory = layout.buildDirectory.dir("libs") configurations = [project.configurations.shadow] relocate 'ca.spottedleaf.concurrentutil', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.concurrentutil' relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml' } -Aw2At.setup(getProject(), tasks.remapJar) - publishMods { + file = shadowJar.archiveFile modLoaders = ["neoforge"] modrinth { diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties deleted file mode 100644 index 7da18ea6..00000000 --- a/neoforge/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -loom.platform=neoforge diff --git a/settings.gradle b/settings.gradle index 54a1f22a..c90ba0f7 100644 --- a/settings.gradle +++ b/settings.gradle @@ -24,7 +24,8 @@ pluginManagement { plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" - id("xyz.jpenilla.quiet-architectury-loom") version "1.7.295" apply false + id("quiet-fabric-loom") version "1.7.296" apply false + id("net.neoforged.moddev") version "1.0.20" apply false id 'com.gradleup.shadow' version '8.3.0' apply false } diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java index 990bd8f5..12311505 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/block_counting/LevelChunkSectionMixin.java @@ -154,9 +154,9 @@ public void recalcBlockCounts() { if (this.maybeHas((final BlockState state) -> !state.isAir())) { final PalettedContainer.Data data = this.states.data; - final Palette palette = data.palette; + final Palette palette = data.palette(); final int paletteSize = palette.getSize(); - final BitStorage storage = data.storage; + final BitStorage storage = data.storage(); final Int2ObjectOpenHashMap counts; if (paletteSize == 1) { diff --git a/src/main/java/ca/spottedleaf/moonrise/mixin/fast_palette/PalettedContainerMixin.java b/src/main/java/ca/spottedleaf/moonrise/mixin/fast_palette/PalettedContainerMixin.java index 7a11507d..21cbf07c 100644 --- a/src/main/java/ca/spottedleaf/moonrise/mixin/fast_palette/PalettedContainerMixin.java +++ b/src/main/java/ca/spottedleaf/moonrise/mixin/fast_palette/PalettedContainerMixin.java @@ -24,7 +24,7 @@ abstract class PalettedContainerMixin implements PaletteResize, PalettedCo private void updateData(final PalettedContainer.Data data) { if (data != null) { ((FastPaletteData)(Object)data).moonrise$setPalette( - ((FastPalette)data.palette).moonrise$getRawPalette((FastPaletteData)(Object)data) + ((FastPalette)data.palette()).moonrise$getRawPalette((FastPaletteData)(Object)data) ); } } @@ -102,7 +102,7 @@ private void readHook(final CallbackInfo ci) { @Unique private T readPaletteSlow(final PalettedContainer.Data data, final int paletteIdx) { - return data.palette.valueFor(paletteIdx); + return data.palette().valueFor(paletteIdx); } @Unique @@ -125,9 +125,9 @@ private T readPalette(final PalettedContainer.Data data, final int paletteIdx */ @Overwrite public T getAndSet(final int index, final T value) { - final int paletteIdx = this.data.palette.idFor(value); + final int paletteIdx = this.data.palette().idFor(value); final PalettedContainer.Data data = this.data; - final int prev = data.storage.getAndSet(index, paletteIdx); + final int prev = data.storage().getAndSet(index, paletteIdx); return this.readPalette(data, prev); } @@ -138,6 +138,6 @@ public T getAndSet(final int index, final T value) { @Overwrite public T get(final int index) { final PalettedContainer.Data data = this.data; - return this.readPalette(data, data.storage.get(index)); + return this.readPalette(data, data.storage().get(index)); } } diff --git a/src/main/resources/moonrise.accesswidener b/src/main/resources/moonrise.accesswidener index 747efb38..acc3cda4 100644 --- a/src/main/resources/moonrise.accesswidener +++ b/src/main/resources/moonrise.accesswidener @@ -17,8 +17,11 @@ accessible field net/minecraft/world/level/chunk/PalettedContainer data Lnet/min # PalettedContainer.Data accessible class net/minecraft/world/level/chunk/PalettedContainer$Data -accessible field net/minecraft/world/level/chunk/PalettedContainer$Data storage Lnet/minecraft/util/BitStorage; -accessible field net/minecraft/world/level/chunk/PalettedContainer$Data palette Lnet/minecraft/world/level/chunk/Palette; +# MDG requires we AT the constructor if we AT the class +accessible method net/minecraft/world/level/chunk/PalettedContainer$Data (Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Lnet/minecraft/world/level/chunk/Palette;)V +# For some reason these won't apply with MDG "field does not exist" +#accessible field net/minecraft/world/level/chunk/PalettedContainer$Data storage Lnet/minecraft/util/BitStorage; +#accessible field net/minecraft/world/level/chunk/PalettedContainer$Data palette Lnet/minecraft/world/level/chunk/Palette; # PaletteResize @@ -145,6 +148,12 @@ accessible method net/minecraft/world/level/material/Fluid isEmpty ()Z accessible method net/minecraft/world/level/material/Fluid createLegacyBlock (Lnet/minecraft/world/level/material/FluidState;)Lnet/minecraft/world/level/block/state/BlockState; accessible method net/minecraft/world/level/material/Fluid isRandomlyTicking ()Z +# We need to manually copy these down for MDG +accessible method net/minecraft/world/level/material/EmptyFluid isEmpty ()Z +accessible method net/minecraft/world/level/material/EmptyFluid createLegacyBlock (Lnet/minecraft/world/level/material/FluidState;)Lnet/minecraft/world/level/block/state/BlockState; +accessible method net/minecraft/world/level/material/LavaFluid createLegacyBlock (Lnet/minecraft/world/level/material/FluidState;)Lnet/minecraft/world/level/block/state/BlockState; +accessible method net/minecraft/world/level/material/LavaFluid isRandomlyTicking ()Z + # VisibilitySet accessible field net/minecraft/client/renderer/chunk/VisibilitySet FACINGS I