Files
photosync/build.gradle
T
2026-08-07 18:10:38 +00:00

208 lines
8.6 KiB
Groovy

plugins {
id 'java'
id 'fabric-loom' apply false
}
/**
* Compatibility buckets, not Minecraft versions.
*
* Every project under :platform is compiled against one representative version
* and declares -- in its own gradle.properties -- the full range of Minecraft
* versions that the resulting jar actually runs on. The grouping comes from
* measured API breakpoints, documented in docs/PORTING.md.
*/
ext.platformProjects = { subprojects.findAll { it.path.startsWith(':platform:') } }
ext.sharedProjects = { subprojects.findAll { it.path.startsWith(':shared:') } }
subprojects {
apply plugin: 'java'
group = rootProject.mod_group
version = rootProject.mod_version
repositories {
maven { name = 'Fabric'; url = 'https://maven.fabricmc.net/' }
mavenCentral()
}
dependencies {
compileOnly "org.projectlombok:lombok:${rootProject.lombok_version}"
annotationProcessor "org.projectlombok:lombok:${rootProject.lombok_version}"
testCompileOnly "org.projectlombok:lombok:${rootProject.lombok_version}"
testAnnotationProcessor "org.projectlombok:lombok:${rootProject.lombok_version}"
testImplementation platform("org.junit:junit-bom:${rootProject.junit_version}")
testImplementation 'org.junit.jupiter:junit-jupiter'
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.withType(JavaCompile).configureEach {
options.encoding = 'UTF-8'
}
tasks.withType(Test).configureEach {
useJUnitPlatform()
}
}
// ---------------------------------------------------------------------------
// Shared modules: zero Minecraft on the classpath.
//
// These compile to Java 17 bytecode because 1.20-1.20.4 run on a Java 17 JVM.
// That is a real constraint on the code, not just a flag: no virtual threads
// and no Java 21 pattern matching in shared code.
// ---------------------------------------------------------------------------
configure(sharedProjects()) {
// java-library so a module can re-export what its consumers legitimately
// need: :shared:ui hands RenderBridge types straight to platform code.
apply plugin: 'java-library'
java {
toolchain { languageVersion = JavaLanguageVersion.of(21) }
}
tasks.withType(JavaCompile).configureEach {
options.release = rootProject.shared_java as int
}
dependencies {
// Gson ships inside Minecraft's own dependency set on every supported
// version, so we compile against it but never bundle it. See
// docs/PORTING.md for the version range this has to stay within.
compileOnly "com.google.code.gson:gson:${rootProject.gson_api_version}"
compileOnly "org.slf4j:slf4j-api:${rootProject.slf4j_api_version}"
testImplementation "com.google.code.gson:gson:${rootProject.gson_api_version}"
testImplementation "org.slf4j:slf4j-api:${rootProject.slf4j_api_version}"
testRuntimeOnly "org.slf4j:slf4j-simple:${rootProject.slf4j_api_version}"
}
}
// ---------------------------------------------------------------------------
// Platform modules: the only code allowed to touch Minecraft types.
// ---------------------------------------------------------------------------
configure(platformProjects()) {
apply plugin: 'fabric-loom'
def mcVersion = project.property('minecraft_version')
def mcJava = project.property('mc_java') as int
def deobfuscated = project.property('deobfuscated').toBoolean()
// Minecraft 26.x ships already deobfuscated, so Loom has nothing to remap.
// It still insists on a mappings artifact carrying a 'named' namespace, so
// we hand it a header-only tiny-v2 file: three namespaces, zero rows, which
// Loom reads as "every name maps to itself".
//
// This is written during configuration rather than by a task because Loom
// resolves the mappings configuration while it configures the project --
// a task output would not exist yet. It is 47 bytes and deterministic.
def identityMappings = null
if (deobfuscated) {
identityMappings = layout.buildDirectory
.file("identity-mappings/identity-mappings-${mcVersion}.jar").get().asFile
if (!identityMappings.exists()) {
identityMappings.parentFile.mkdirs()
new java.util.zip.ZipOutputStream(identityMappings.newOutputStream()).withCloseable { zip ->
zip.putNextEntry(new java.util.zip.ZipEntry('mappings/mappings.tiny'))
zip.write("tiny\t2\t0\tofficial\tintermediary\tnamed\n".getBytes('UTF-8'))
zip.closeEntry()
}
}
}
java {
// javac can always read older bytecode, so one toolchain covers every
// bucket except 26.x, whose Minecraft classes are Java 25.
toolchain { languageVersion = JavaLanguageVersion.of(Math.max(mcJava, 21)) }
withSourcesJar()
}
// The compatibility layer. platform/common holds the adapter code that is
// textually identical on all nine buckets -- the Fabric entrypoint, the
// ClientBridge assembly, and the two seams (I18n, KeyboardHandler) that have
// not moved since 1.20. It is a source root rather than a project because it
// imports net.minecraft, so it has to be compiled once per bucket against
// that bucket's Minecraft; there is no single jar it could produce.
//
// Everything it calls that *does* differ lives in dev.photosync.platform.impl,
// which each bucket supplies from its own src/main/java under the same
// package. Common code names those classes directly and the bucket's source
// root satisfies them -- so the invariant half is written once, and the half
// that churns is a per-bucket file the compiler checks.
sourceSets.main.java.srcDir rootProject.file('platform/common/src/main/java')
sourceSets.main.resources.srcDir rootProject.file('platform/common/src/main/resources')
tasks.withType(JavaCompile).configureEach {
options.release = mcJava
}
dependencies {
minecraft "com.mojang:minecraft:${mcVersion}"
if (deobfuscated) {
mappings project.files(identityMappings)
} else {
mappings loom.officialMojangMappings()
}
modImplementation "net.fabricmc:fabric-loader:${project.property('loader_version')}"
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.property('fabric_api_version')}"
// Shared code is compiled once per bucket's bytecode target and folded
// into the platform jar below. No shading, no jar-in-jar: these are our
// own classes and they carry no third-party dependencies.
rootProject.sharedProjects().each { implementation it }
}
loom {
runs {
client {
client()
ideConfigGenerated = true
}
}
}
processResources {
def tokens = [
mod_id : rootProject.mod_id,
mod_name : rootProject.mod_name,
mod_version : rootProject.mod_version,
mod_description : rootProject.mod_description,
mod_license : rootProject.mod_license,
mod_sources : rootProject.mod_sources,
minecraft_range : project.property('minecraft_range'),
loader_version : project.property('loader_version'),
java_version : String.valueOf(mcJava),
// Mixin refuses to apply a class whose bytecode is newer than the
// declared level, and platform classes are compiled at the
// bucket's own level -- so this has to follow mc_java.
mixin_compat : "JAVA_${mcJava}",
]
inputs.properties(tokens)
filesMatching(['fabric.mod.json', '*.mixins.json']) { expand(tokens) }
}
jar {
rootProject.sharedProjects().each { from it.sourceSets.main.output }
manifest {
attributes(
'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version,
'Minecraft-Version': mcVersion,
'Minecraft-Range': project.property('minecraft_range')
)
}
}
// Give every bucket's artifact a distinguishable name.
base.archivesName = "${rootProject.mod_id}-${mcVersion}"
}
// Convenience: build every bucket's shippable jar in one go.
tasks.register('buildAllPlatforms') {
group = 'build'
description = 'Builds the remapped mod jar for every compatibility bucket.'
dependsOn platformProjects().collect { "${it.path}:build" }
}