This commit is contained in:
Ran-Mewo
2026-03-29 19:29:01 +11:00
parent 5f228f0567
commit 215e1d46d0
27 changed files with 657 additions and 1163 deletions
+24
View File
@@ -0,0 +1,24 @@
plugins {
id 'groovy-gradle-plugin'
}
repositories {
gradlePluginPortal()
mavenCentral()
maven { url = 'https://maven.wagyourtail.xyz/releases' }
maven { url = 'https://maven.outlands.top/releases' }
maven { url = 'https://maven.wagyourtail.xyz/snapshots' }
maven { url = 'https://maven.architectury.dev/' }
maven { url = 'https://maven.fabricmc.net/' }
maven { url = 'https://maven.neoforged.net/releases/' }
maven { url = 'https://maven.minecraftforge.net/' }
maven { url = 'https://repo.spongepowered.org/repository/maven-public/' }
maven { url = 'https://oss.sonatype.org/content/repositories/snapshots/' }
}
dependencies {
implementation 'com.gradleup.shadow:shadow-gradle-plugin:9.0.0'
implementation 'xyz.wagyourtail.unimined:xyz.wagyourtail.unimined.gradle.plugin:1.4.16-kappa'
implementation 'xyz.wagyourtail:manifold-gradle:1.0.0-SNAPSHOT'
implementation 'xyz.wagyourtail.jvmdowngrader:xyz.wagyourtail.jvmdowngrader.gradle.plugin:1.3.4'
}
+450
View File
@@ -0,0 +1,450 @@
import com.github.jengelman.gradle.plugins.shadow.transformers.ResourceTransformer
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
import org.apache.tools.zip.ZipEntry
import org.apache.tools.zip.ZipOutputStream
import javax.annotation.Nonnull
import java.util.function.Function
import java.util.function.Predicate
// Convention plugin for all MC-facing subprojects (common + loaders).
// Common uses this directly; loaders use it via unimined-fabric/forge/neoforge.
// IMPORTANT: unimined MUST be applied before shadow/jvmdowngrader
// so its afterEvaluate runs first and can modify configs.
plugins {
id 'java'
id 'maven-publish'
id 'xyz.wagyourtail.unimined'
id 'com.gradleup.shadow'
id 'xyz.wagyourtail.manifold'
id 'xyz.wagyourtail.jvmdowngrader'
}
def isNotCommonProject = project.name != "common"
// ==================== Version Properties ====================
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
manifold {
version = rootProject.manifold_version
}
// ==================== Repositories ====================
repositories {
maven { url "https://libraries.minecraft.net/" }
mavenCentral()
maven { url "https://repo.enonic.com/public/" }
maven { url "https://maven.parchmentmc.org" }
maven { url "https://maven.architectury.dev" }
maven { url "https://jitpack.io" }
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
maven {
name = "Modrinth"
url = "https://api.modrinth.com/maven"
content { includeGroup "maven.modrinth" }
}
maven {
url "https://www.cursemaven.com"
content { includeGroup "curse.maven" }
}
maven { url "https://repo.spongepowered.org/maven/" }
maven { url "https://maven.terraformersmc.com/" }
maven { url "https://maven.neoforged.net/releases/" }
flatDir {
dirs "${rootDir}/mods/fabric"
content { includeGroup "fabric-mod" }
}
flatDir {
dirs "${rootDir}/mods/quilt"
content { includeGroup "quilt-mod" }
}
flatDir {
dirs "${rootDir}/mods/forge"
content { includeGroup "forge-mod" }
}
}
// ==================== Java Config ====================
tasks.withType(JavaCompile).configureEach {
options.release = rootProject.java_version as Integer
options.encoding = "UTF-8"
}
java {
sourceCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
targetCompatibility = JavaVersion.toVersion(gradle.ext.java_version as Integer)
withSourcesJar()
}
// ==================== Loader-Only Config ====================
if (isNotCommonProject) {
base { archivesName = rootProject.mod_name }
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
version = project.name + "-" + rootProject.versionStr
group = rootProject.maven_group
javadoc.title = rootProject.mod_name + "-" + project.name
javadoc {
configure(options) {
tags(
'todo:X"',
'apiNote:a:API Note:',
'implSpec:a:Implementation Requirements:',
'implNote:a:Implementation Note:'
)
}
}
tasks.withType(GenerateModuleMetadata).configureEach {
enabled = false
}
tasks.withType(Test).configureEach {
enabled = false
}
compileTestJava.enabled = false
tasks.withType(Sign).configureEach {
enabled = false
}
jar {
from "LICENSE.txt"
manifest {
attributes(
'Implementation-Title': rootProject.mod_name,
'Implementation-Version': rootProject.mod_version,
'Multi-Release': true,
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain',
)
}
}
}
// ==================== Unimined Minecraft Config ====================
unimined.minecraft(sourceSets.main, true) {
version gradle.ext.minecraft_version
mappings {
mojmap()
devNamespace "mojmap"
}
}
if (isNotCommonProject) {
// Mixin remapping and common project wiring
unimined.minecraft(sourceSets.main, true) {
mods.modImplementation {
mixinRemap {
reset()
enableBaseMixin()
enableMixinExtra()
}
}
}
dependencies {
implementation(project(":common"))
}
processResources {
from project(":common").sourceSets.main.resources
}
tasks.withType(JavaCompile).configureEach {
source(project(":common").sourceSets.main.allSource)
}
} else {
// Common: fabric for compilation + access widener, no jar remapping or runs
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project.file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
defaultRemapJar = false
runs.off = true
}
}
// ==================== Configurations ====================
evaluationDependsOn(":core")
configurations {
shadowMe
coreProjects
shadowMe.extendsFrom(coreProjects)
implementation.extendsFrom(shadowMe)
common
implementation.extendsFrom(common)
}
// ==================== Dependencies ====================
// Copy core's compileOnly deps so MC-provided deps are visible without redeclaring them.
project(":core").configurations.compileOnly.allDependencies.each { dep ->
if (!(dep instanceof ProjectDependency))
dependencies.add("compileOnly", dep)
}
dependencies {
// Manifold preprocessor & strings
annotationProcessor(manifold.module("preprocessor"))
annotationProcessor(manifold.module("strings"))
// NightConfig: implementation in core (bundled) but Unimined strips it from compile classpath
compileOnly("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
// Core & API projects — bundled into shadow jar
coreProjects(project(":core"))
coreProjects(project(":api"))
// JOML: shadow for old MC versions that don't bundle it (core has it compileOnly already)
if (project.hasProperty("embed_joml") && embed_joml == "true")
shadowMe("org.joml:joml:${rootProject.joml_version}")
// Common project dependency
if (isNotCommonProject)
common(project(":common")) { transitive false }
}
// ==================== NativeTransformer ====================
class NativeTransformer implements ResourceTransformer {
private Predicate<String> fileMatcher
private Function<String, String> filePathMapper
private final HashMap<String, String> replacements = new HashMap()
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
private nativeRelocator
public File rootDir
void matchFiles(Predicate<String> matcher) {
fileMatcher = matcher
}
void mapPaths(Function<String, String> mapper) {
filePathMapper = mapper
}
void relocateNative(String target, String replacement) {
if (replacement.length() > target.length()) {
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
}
replacements.put(target, replacement)
}
@Override
boolean canTransformResource(@Nonnull FileTreeElement element) {
return fileMatcher != null && fileMatcher.test(element.relativePath.pathString)
}
@Override
void transform(@Nonnull TransformerContext context) {
byte[] content = context.inputStream.readAllBytes()
if (nativeRelocator == null) {
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
}
try {
String path = filePathMapper != null
? filePathMapper.apply(context.path)
: context.path
content = nativeRelocator.processBinary(path, content, replacements)
rewrittenFiles.put(path, content)
}
catch (Throwable e) {
throw new GradleException("Failed to relocate", e)
}
}
@Override
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
@Override
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
os.putNextEntry(new ZipEntry(rewrittenFile.key))
os.write(rewrittenFile.value)
}
}
}
// ==================== Shadow JAR (loaders only) ====================
if (isNotCommonProject) {
shadowJar {
configurations = [project.configurations.shadowMe]
relocate "com.seibel.distanthorizons.common", "loaderCommon.${project.name}.com.seibel.distanthorizons.common"
def librariesLocation = "DistantHorizons.libraries"
// LZ4
relocate "net.jpountz", "${librariesLocation}.jpountz"
// SLF4J
relocate "org.slf4j", "${librariesLocation}.slf4j"
// SQLite
relocate "org.sqlite", "dh_sqlite", { exclude "org/sqlite/native/**" }
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.startsWith("org/sqlite") }
mapPaths { it.replace("org/sqlite", "dh_sqlite") }
relocateNative "org/sqlite", "dh_sqlite"
relocateNative "org_sqlite", "dh_1sqlite"
}
// ZStd
relocate "com.github.luben", "dhcomgithubluben"
relocate "libzstd-jni", "libzstd-jni_dh"
relocate "zstd-jni", "zstd-jni_dh"
transform(NativeTransformer) {
rootDir = project.rootDir
matchFiles { it.contains("libzstd-jni") && !it.contains("aix/ppc64") }
mapPaths { it.replace("libzstd-jni", "libzstd-jni_dh") }
relocateNative "com/github/luben", "dhcomgithubluben"
relocateNative "com_github_luben", "dhcomgithubluben"
}
// JOML (conditional)
if (project.hasProperty("embed_joml") && embed_joml == "true")
relocate "org.joml", "${librariesLocation}.joml"
// NightConfig
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
mergeServiceFiles()
}
afterEvaluate {
tasks.named("remapJar").configure {
dependsOn(shadowJar)
inputFile.set(shadowJar.archiveFile)
}
// Make run tasks use the shadow jar so relocated deps (NightConfig, etc.) work in dev.
// Without this, NeoForge's bundled NightConfig 3.8.x conflicts with DH's 3.6.6.
tasks.withType(JavaExec).configureEach { runTask ->
dependsOn(shadowJar)
classpath = files(shadowJar.archiveFile) + classpath.filter { file ->
!file.path.contains(project.buildDir.path) &&
!file.path.contains("core${File.separator}build") &&
!file.path.contains("api${File.separator}build") &&
!file.path.contains("common${File.separator}build")
}
}
}
}
// ==================== Process Resources (loaders only) ====================
if (isNotCommonProject) {
processResources {
def resourceTargets = [
"build_info.json",
"fabric.mod.json",
"quilt.mod.json",
"META-INF/mods.toml",
"META-INF/neoforge.mods.toml",
]
def compatible_forgemc_versions = "${rootProject.compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
// Quilt contributors
def quilt_contributors = []
def mod_author_list = rootProject.mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
for (dev in mod_author_list) {
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
}
quilt_contributors.reverse()
try {
if (rootProject.infoGitCommit == "null")
rootProject.ext.infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
if (rootProject.infoGitBranch == "null")
rootProject.ext.infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
} catch (Exception e) {
rootProject.ext.infoGitCommit = "Git not found"
rootProject.ext.infoGitBranch = "Git not found"
}
def replaceProperties = [
version : rootProject.mod_version,
mod_name : rootProject.mod_readable_name,
group : rootProject.maven_group,
authors : rootProject.mod_authors,
description : rootProject.mod_description,
homepage : rootProject.mod_homepage,
source : rootProject.mod_source,
issues : rootProject.mod_issues,
discord : rootProject.mod_discord,
minecraft_version : rootProject.minecraft_version,
compatible_minecraft_versions: rootProject.compatible_minecraft_versions,
compatible_forgemc_versions : compatible_forgemc_versions,
java_version : rootProject.java_version,
quilt_contributors : "{" + quilt_contributors.join(", ") + "}",
info_git_commit : rootProject.infoGitBranch,
info_git_branch : rootProject.infoGitCommit,
info_build_source : rootProject.infoBuildSource,
fabric_incompatibility_list : rootProject.fabric_incompatibility_list,
fabric_recommend_list : rootProject.fabric_recommend_list,
neoforge_version_range : rootProject.neoforge_version_range,
]
inputs.properties replaceProperties
replaceProperties.put "project", project
filesMatching(resourceTargets) {
expand replaceProperties
}
// Remove unused access wideners
exclude { file ->
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener") {
return true
}
return false
}
}
// ==================== Resource Copy Tasks ====================
task copyCommonLoaderResources(type: Copy) {
from project(":common").file("src/main/resources/${rootProject.accessWidenerVersion}.distanthorizons.accesswidener")
into(file(project.file("build/resources/main")))
rename "${rootProject.accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
}
task copyCoreResources(type: Copy) {
from fileTree(project(":core").file("src/main/resources"))
into project.file("build/resources/main")
}
// ==================== JVMDowngrader ====================
jvmdg.downgradeTo = JavaVersion.toVersion(rootProject.java_version)
downgradeJar.archiveClassifier.set(null)
shadeDowngradedApi.archiveClassifier.set(null)
}
+44
View File
@@ -0,0 +1,44 @@
plugins {
id 'java'
}
// Transfer version properties from settings.gradle to project
project.gradle.ext.getProperties().each { prop ->
rootProject.ext.set(prop.key, prop.value)
}
// Version string for archives
rootProject.ext.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version
rootProject.allprojects {
version = (it == rootProject ? "" : it.name + "-") + rootProject.versionStr
group = rootProject.maven_group
}
// Create build.properties with preprocessor definitions
def writePreprocessorDefinitions() {
StringBuilder sb = new StringBuilder()
sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n")
gradle.ext.mcVers.eachWithIndex { ver, idx ->
sb.append("MC_${ver.replace('.', '_')}=${idx}\n")
if (gradle.ext.mcIndex == idx)
sb.append("MC_VER=${idx}\n")
}
if (rootProject.mod_version.toLowerCase().contains("dev")) {
sb.append("DEV_BUILD=\n")
}
new File(rootDir, "build.properties").text = sb.toString()
}
writePreprocessorDefinitions()
// Wire JVMDowngrader to process remapped jars
gradle.projectsEvaluated {
rootProject.subprojects.each {
if (it.tasks.findByName('remapJar') == null) return
it.tasks.downgradeJar.inputFile = it.tasks.remapJar.archiveFile
it.tasks.jar.finalizedBy(it.tasks.remapJar)
it.tasks.remapJar.finalizedBy(it.tasks.shadeDowngradedApi)
}
}
@@ -0,0 +1,13 @@
plugins {
id 'dh-loader'
}
unimined.minecraft {
fabric {
loader gradle.ext.fabric_loader_version
accessWidener project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -0,0 +1,17 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
forge {
loader gradle.ext.forge_version
useToolchains = false
mixinConfig("DistantHorizons.forge.mixins.json")
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null
@@ -0,0 +1,16 @@
plugins {
id 'dh-loader'
}
def awFile = project(":common").file("src/main/resources/${gradle.ext.accessWidenerVersion}.distanthorizons.accesswidener")
unimined.minecraft {
neoForged {
loader gradle.ext.neoforge_version
useToolchains = false
accessTransformer aw2at(awFile)
}
}
runClient.javaLauncher = null
runServer.javaLauncher = null