Pretty groovy man

- Upgrade platform script plugin to pre-compiled groovy plugin
- It was getting really difficult to manage all the logic/plugins/types
  from the basic script, and implementing a real plugin gives us much
  better type safety and IDE access to upstream plugins
- Separate api/lib/backend/impl in platform projects
- Add platform module output to main runtime classpath so the fabric
  loader recognizes our additional modules
This commit is contained in:
Jozufozu 2024-04-26 17:04:00 -07:00
parent e1b0cebc2c
commit 9ae4065c1c
28 changed files with 281 additions and 126 deletions

View file

@ -1,3 +1,31 @@
plugins {
id 'groovy-gradle-plugin'
}
repositories {
gradlePluginPortal()
mavenCentral()
maven {
name = 'MinecraftForge'
url = 'https://maven.minecraftforge.net/'
}
maven {
name = 'Architectury'
url = 'https://maven.architectury.dev/'
}
maven { url = 'https://repo.spongepowered.org/repository/maven-public' }
maven { url = 'https://maven.parchmentmc.org' }
}
gradlePlugin {
plugins {
simplePlugin {
id = 'flywheel.platform'
implementationClass = 'com.jozufozu.gradle.PlatformPlugin'
}
}
}
dependencies {
implementation 'dev.architectury.loom:dev.architectury.loom.gradle.plugin:1.6-SNAPSHOT'
}

View file

@ -1,5 +1,3 @@
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.tasks.InputDirectory

View file

@ -0,0 +1,173 @@
package com.jozufozu.gradle
import groovy.transform.CompileStatic
import net.fabricmc.loom.api.LoomGradleExtensionAPI
import net.fabricmc.loom.task.RemapJarTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileCopyDetails
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.tasks.AbstractCopyTask
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.SourceTask
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.api.tasks.javadoc.Javadoc
import org.gradle.language.jvm.tasks.ProcessResources
// Couldn't get imports for loom to work in the simple .gradle file, so upgraded this to a real plugin.
@CompileStatic
class PlatformPlugin implements Plugin<Project> {
@Override
void apply(Project project) {
def commonProject = project.project(':common')
def commonSourceSets = commonProject.getExtensions().getByType(SourceSetContainer)
def sourceSets = project.getExtensions().getByType(SourceSetContainer)
def loom = project.getExtensions().getByType(LoomGradleExtensionAPI)
def publishing = project.getExtensions().getByType(PublishingExtension)
// Loom only populates mc stuff to the main source set,
// so grab that here and use it for the others.
// Note that the `+` operator does NOT perform a deep copy
// of a FileCollection, so this object is shared between
// the source sets and we should avoid mutating it.
SourceSet platformImpl = sourceSets.named('main').get()
FileCollection mcCompileClassPath = platformImpl.compileClasspath
SourceSet platformApi = sourceSets.create('api')
platformApi.compileClasspath = mcCompileClassPath
SourceSet platformLib = sourceSets.create('lib')
platformLib.compileClasspath = mcCompileClassPath + platformApi.output
SourceSet platformBackend = sourceSets.create('backend')
platformBackend.compileClasspath = mcCompileClassPath + platformApi.output + platformLib.output
// Assign here rather than concatenate to avoid modifying the mcCompileClassPath FileCollection
platformImpl.compileClasspath = mcCompileClassPath + platformApi.output + platformLib.output + platformBackend.output
// This isn't necessary for forge but fabric needs to recognize each classpath entry from ModSettings.
platformImpl.runtimeClasspath += platformApi.output + platformLib.output + platformBackend.output
// This is needed for both platforms.
def mainMod = loom.mods.maybeCreate('main')
mainMod.sourceSet(platformApi)
mainMod.sourceSet(platformLib)
mainMod.sourceSet(platformBackend)
mainMod.sourceSet(platformImpl)
def forApi = newConfiguration(project, 'forApi')
def forLib = newConfiguration(project, 'forLib')
def forBackend = newConfiguration(project, 'forBackend')
def forImpl = newConfiguration(project, 'forImpl')
extendsFrom(project, platformApi.compileOnlyConfigurationName, forApi)
extendsFrom(project, platformLib.compileOnlyConfigurationName, forApi, forLib)
extendsFrom(project, platformBackend.compileOnlyConfigurationName, forApi, forLib, forBackend)
extendsFrom(project, platformImpl.compileOnlyConfigurationName, forApi, forLib, forBackend, forImpl)
SourceSet commonApi = commonSourceSets.named('api').get()
SourceSet commonLib = commonSourceSets.named('lib').get()
SourceSet commonBackend = commonSourceSets.named('backend').get()
SourceSet commonImpl = commonSourceSets.named('main').get()
def commonSources = [commonApi, commonLib, commonBackend, commonImpl]
// Directly compile the platform sources with the common sources
includeFromCommon(project, platformApi, commonApi)
includeFromCommon(project, platformLib, commonLib)
includeFromCommon(project, platformBackend, commonBackend)
includeFromCommon(project, platformImpl, commonImpl)
def tasks = project.tasks
tasks.withType(JavaCompile).configureEach { JavaCompile compileJava ->
excludeDuplicatePackageInfos(compileJava)
}
def apiJar = tasks.register('apiJar', Jar) { Jar jar ->
jar.archiveClassifier.set('api-dev')
jar.from platformApi.output, platformLib.output
jar.destinationDirectory.set(project.layout.buildDirectory.dir('devlibs'))
excludeDuplicatePackageInfos(jar)
}
tasks.named('jar', Jar).configure { Jar jar ->
jar.archiveClassifier.set('dev')
jar.from platformApi.output, platformLib.output, platformBackend.output
excludeDuplicatePackageInfos(jar)
}
tasks.named('javadoc', Javadoc).configure { Javadoc javadoc ->
commonSources.forEach { javadoc.source it.allJava }
javadoc.source platformApi.allJava, platformLib.allJava, platformBackend.allJava
excludeDuplicatePackageInfos(javadoc)
}
tasks.named('sourcesJar', Jar).configure { Jar jar ->
commonSources.forEach { jar.from it.allJava }
jar.from platformApi.allJava, platformLib.allJava, platformBackend.allJava
excludeDuplicatePackageInfos(jar)
}
def remapApiJar = tasks.register('remapApiJar', RemapJarTask) { RemapJarTask remapJar ->
remapJar.dependsOn(apiJar)
remapJar.inputFile.set(apiJar.flatMap { it.archiveFile })
remapJar.archiveClassifier.set('api')
}
def remapJar = tasks.named('remapJar', RemapJarTask)
tasks.named('build').configure { Task build ->
build.dependsOn(remapApiJar)
}
}
// We have duplicate packages between the common and platform dependent subprojects.
// In theory the package-info.java files should be identical, so just take the first one we find.
static void excludeDuplicatePackageInfos(AbstractCopyTask copyTask) {
copyTask.filesMatching('**/package-info.java') { FileCopyDetails details ->
details.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
// The compile/javadoc tasks have a different base type that isn't so smart about exclusion handling.
static void excludeDuplicatePackageInfos(SourceTask sourceTask) {
sourceTask.exclude('**/package-info.java')
}
static Configuration newConfiguration(Project project, String name) {
return project.configurations.create(name) { Configuration it ->
it.canBeConsumed = true
it.canBeResolved = false
}
}
static void extendsFrom(Project project, String name, Configuration... configurations) {
project.configurations.named(name).configure {
it.extendsFrom(configurations)
}
}
static void includeFromCommon(Project project, SourceSet sourceSet, SourceSet commonSourceSet) {
project.tasks.named(sourceSet.compileJavaTaskName, JavaCompile).configure { JavaCompile compileJava ->
compileJava.source commonSourceSet.allJava
}
project.tasks.named(sourceSet.processResourcesTaskName, ProcessResources).configure { ProcessResources processResources ->
processResources.from commonSourceSet.resources
}
}
}

View file

@ -1,7 +1,3 @@
plugins {
id 'java'
}
boolean dev = System.getenv('RELEASE') == null || System.getenv('RELEASE').equalsIgnoreCase('false')
String buildNumber = System.getenv('BUILD_NUMBER')
@ -40,12 +36,7 @@ tasks.withType(JavaCompile).configureEach { JavaCompile javaCompile ->
javaCompile.options.compilerArgs = ['-Xdiags:verbose']
}
tasks.named('jar', Jar).configure { Jar jar ->
archiveClassifier = ''
addLicense(jar)
}
tasks.named('sourcesJar', Jar).configure { Jar jar ->
tasks.withType(Jar).configureEach { Jar jar ->
addLicense(jar)
}

View file

@ -1,89 +0,0 @@
plugins {
id 'flywheel.subproject'
}
evaluationDependsOn(':common')
loom {
runs {
client {
ideConfigGenerated true
// Turn on our own debug flags
property 'flw.dumpShaderSource', 'true'
property 'flw.debugMemorySafety', 'true'
// Turn on mixin debug flags
property 'mixin.debug.export', 'true'
property 'mixin.debug.verbose', 'true'
// 720p baby!
programArgs '--width', '1280', '--height', '720'
}
// We're a client mod, but we need to make sure we correctly render when playing on a server.
server {
ideConfigGenerated true
programArgs '--nogui'
}
}
}
dependencies {
compileOnly project(path: ':common', configuration: 'commonApi')
compileOnly project(path: ':common', configuration: 'commonLib')
compileOnly project(path: ':common', configuration: 'commonBackend')
compileOnly project(path: ':common', configuration: 'commonImpl')
}
SourceSet commonApiSource = project(':common').sourceSets.api
SourceSet commonLibSource = project(':common').sourceSets.lib
SourceSet commonBackendSource = project(':common').sourceSets.backend
SourceSet commonMainSource = project(':common').sourceSets.main
def commonSources = [commonApiSource, commonLibSource, commonBackendSource, commonMainSource]
tasks.named('processResources', ProcessResources).configure { ProcessResources processResources ->
// No resources in API
processResources.from commonLibSource.resources
processResources.from commonBackendSource.resources
processResources.from commonMainSource.resources
}
tasks.named('compileJava', JavaCompile).configure { JavaCompile compileJava ->
// TODO: Can we avoid this duplication? Would be nice to repackage the 4 common jars without having to re compile
commonSources.forEach { compileJava.source it.allJava }
excludeDuplicatePackageInfos(compileJava)
}
tasks.named('javadoc', Javadoc).configure { Javadoc javadoc ->
commonSources.forEach { javadoc.source it.allJava }
excludeDuplicatePackageInfos(javadoc)
}
tasks.named('jar', Jar).configure { Jar jar ->
excludeDuplicatePackageInfos(jar)
}
tasks.named('sourcesJar', Jar).configure { Jar jar ->
commonSources.forEach { jar.from it.allJava }
excludeDuplicatePackageInfos(jar)
}
// We have duplicate packages between the common and platform dependent subprojects.
// In theory the package-info.java files should be identical, so just take the first one we find.
static void excludeDuplicatePackageInfos(AbstractCopyTask copyTask) {
copyTask.filesMatching('**/package-info.java') {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
}
// The compile/javadoc tasks have a different base type that isn't so smart about exclusion handling.
static void excludeDuplicatePackageInfos(SourceTask sourceTask) {
// FIXME: actually scan the files and exclude the duplicates
// may be tough because the files have absolute paths
sourceTask.exclude('**/package-info.java')
}

View file

@ -1,11 +1,3 @@
plugins {
id 'idea'
id 'flywheel.java'
id 'maven-publish'
id 'dev.architectury.loom'
id 'flywheel.package-infos'
}
loom {
silentMojangMappingsLicense()
@ -49,7 +41,7 @@ dependencies {
api 'com.google.code.findbugs:jsr305:3.0.2'
}
processResources {
tasks.withType(ProcessResources).configureEach {
var replaceProperties = [
mod_id : mod_id,
mod_name : mod_name,

View file

@ -1,4 +1,10 @@
plugins {
id 'idea'
id 'java'
id 'maven-publish'
id 'dev.architectury.loom'
id 'flywheel.java'
id 'flywheel.package-infos'
id 'flywheel.subproject'
}

View file

@ -1,20 +1,50 @@
plugins {
id 'idea'
id 'java'
id 'maven-publish'
id 'dev.architectury.loom'
id 'flywheel.java'
id 'flywheel.package-infos'
id 'flywheel.subproject'
id 'flywheel.platform'
}
evaluationDependsOn(':common')
loom {
runs {
client {
ideConfigGenerated true
// Turn on our own debug flags
property 'flw.dumpShaderSource', 'true'
property 'flw.debugMemorySafety', 'true'
// Turn on mixin debug flags
property 'mixin.debug.export', 'true'
property 'mixin.debug.verbose', 'true'
// 720p baby!
programArgs '--width', '1280', '--height', '720'
}
// We're a client mod, but we need to make sure we correctly render when playing on a server.
server {
ideConfigGenerated true
programArgs '--nogui'
}
}
}
dependencies {
modImplementation "net.fabricmc:fabric-loader:${fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${fabric_api_version}"
modCompileOnly "maven.modrinth:sodium:${sodium_version}"
modCompileOnly "maven.modrinth:iris:${iris_version}"
}
publishing {
publications {
register('mavenJava', MavenPublication) {
from(components['java'])
artifactId = "flywheel-${project.name}-${artifact_minecraft_version}"
}
}
forApi project(path: ':common', configuration: 'commonApi')
forLib project(path: ':common', configuration: 'commonLib')
forBackend project(path: ':common', configuration: 'commonBackend')
forImpl project(path: ':common', configuration: 'commonImpl')
}

View file

@ -1,7 +1,16 @@
plugins {
id 'idea'
id 'java'
id 'maven-publish'
id 'dev.architectury.loom'
id 'flywheel.java'
id 'flywheel.package-infos'
id 'flywheel.subproject'
id 'flywheel.platform'
}
evaluationDependsOn(':common')
loom {
forge {
mixinConfig 'flywheel.backend.mixins.json'
@ -14,6 +23,27 @@ loom {
property 'forge.logging.markers', ''
property 'forge.logging.console.level', 'debug'
}
client {
ideConfigGenerated true
// Turn on our own debug flags
property 'flw.dumpShaderSource', 'true'
property 'flw.debugMemorySafety', 'true'
// Turn on mixin debug flags
property 'mixin.debug.export', 'true'
property 'mixin.debug.verbose', 'true'
// 720p baby!
programArgs '--width', '1280', '--height', '720'
}
// We're a client mod, but we need to make sure we correctly render when playing on a server.
server {
ideConfigGenerated true
programArgs '--nogui'
}
}
}
@ -22,13 +52,9 @@ dependencies {
modCompileOnly "maven.modrinth:embeddium:${embeddium_version}"
modCompileOnly "maven.modrinth:oculus:${oculus_version}"
}
publishing {
publications {
register('mavenJava', MavenPublication) {
from(components['java'])
artifactId = "flywheel-${project.name}-${artifact_minecraft_version}"
}
}
forApi project(path: ':common', configuration: 'commonApi')
forLib project(path: ':common', configuration: 'commonLib')
forBackend project(path: ':common', configuration: 'commonBackend')
forImpl project(path: ':common', configuration: 'commonImpl')
}