plugins { id "java" // Plugin to put dependencies inside our final jar id "com.github.johnrengelman.shadow" version '7.1.2' apply false // Plugin to create merged jars id "io.github.pacifistmc.forgix" version "1.2.6" // Manifold preprocessor id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha" // Architectury is used here only as a replacement for forge's own loom id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false } /** * Creates the list of preprocessors to use. * * @param mcVers array of all MC versions * @param mcIndex array index of the currently active MC version */ def writeBuildGradlePredefine(List mcVers, int mcIndex) { // Build the list of preprocessors to use StringBuilder sb = new StringBuilder(); sb.append("# DON'T TOUCH THIS FILE, This is handled by the build script\n"); for (int i = 0; i < mcVers.size(); i++) { String verStr = mcVers[i].replace(".", "_"); sb.append("MC_" + verStr + "=" + i.toString() + "\n"); if (mcIndex == i) sb.append("MC_VER=" + i.toString() + "\n"); } // Check if this is a development build if (mod_version.toLowerCase().contains("dev")) { // WARNING: only use this for logging, we don't want to have confusion // when a method doesn't work correctly in the release build. sb.append("DEV_BUILD=\n"); } new File(projectDir, "build.properties").text = sb.toString() } // Transfers the values set in settings.gradle to the rest of the project project.gradle.ext.getProperties().each { prop -> rootProject.ext.set(prop.key, prop.value) // println "Added prop [key:" + prop.key + ", value:" + prop.value + "]" } // Sets up manifold stuff writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex) // Sets up the version string (the name we use for our jar) rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm") // Forgix settings (used for merging jars) forgix { group = "com.seibel.distanthorizons" mergedJarName = "DistantHorizons-${rootProject.versionStr}.jar" if (findProject(":forge")) forge { jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar" } if (findProject(":neoforge")) custom { projectName = "neoforge" jarLocation = "build/libs/DistantHorizons-neoforge-${rootProject.versionStr}.jar" } if (findProject(":fabric")) fabric { jarLocation = "build/libs/DistantHorizons-fabric-${rootProject.versionStr}.jar" } if (findProject(":quilt")) quilt { jarLocation = "build/libs/DistantHorizons-quilt-${rootProject.versionStr}.jar" } removeDuplicate "com.seibel.distanthorizons" } subprojects { p -> // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")" // Useful later on so we dont have duplicated code def isMinecraftSubProject = p != project(":core") && p != project(":api") // Apply plugins apply plugin: "java" apply plugin: "com.github.johnrengelman.shadow" if (isMinecraftSubProject) apply plugin: "systems.manifold.manifold-gradle-plugin" // Apply forge's loom if ( (findProject(":forge") && p == project(":forge")) || (findProject(":neoforge") && p == project(":neoforge")) ) apply plugin: "dev.architectury.loom" // Set the manifold version (may not be required tough) manifold { manifoldVersion = rootProject.manifold_version } // set up custom configurations (configurations are a way to handle dependencies) configurations { // extends the shadowJar configuration shadowMe // have implemented dependencies automatically embedded in the final jar implementation.extendsFrom(shadowMe) // Configuration fpr core & api coreProjects shadowMe.extendsFrom(coreProjects) // FIXME this additional configuration is necessary because forge // needs forgeRuntimeLibrary, although adding it to shadowMe // causes runtime issues where the libraries aren't properly added forgeShadowMe // this should match shadowMe pretty closely implementation.extendsFrom(forgeShadowMe) shadowMe.extendsFrom(forgeShadowMe) forgeRuntimeLibrary.extendsFrom(forgeShadowMe) if (isMinecraftSubProject && p != project(":common")) { // Shadow common common shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this. compileClasspath.extendsFrom common runtimeClasspath.extendsFrom common if (findProject(":forge")) developmentForge.extendsFrom common if (findProject(":neoforge")) developmentNeoForge.extendsFrom common compileClasspath.extendsFrom coreProjects runtimeClasspath.extendsFrom coreProjects if (findProject(":forge")) developmentForge.extendsFrom coreProjects if (findProject(":neoforge")) developmentNeoForge.extendsFrom coreProjects if (findProject(":fabricLike") && p != project(":fabricLike")) { // Shadow fabricLike fabricLike shadowFabricLike compileClasspath.extendsFrom fabricLike runtimeClasspath.extendsFrom fabricLike } } } dependencies { //=====================// // shared dependencies // //=====================// // Manifold if (isMinecraftSubProject) { annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}") } // Log4j // TODO: Change to shadowMe later to work in the standalone jar // We cannot do this now as it would break Quilt implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}") implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}") // JOML if (project.hasProperty("embed_joml") && embed_joml == "true") forgeShadowMe("org.joml:joml:${rootProject.joml_version}") else implementation("org.joml:joml:${rootProject.joml_version}") // JUnit tests implementation("org.junit.jupiter:junit-jupiter:5.8.2") implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2") implementation("junit:junit:4.13") // FastUtil // Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12 // We cannot relocate this library since we call some MC classes that reference it implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}") // Compression forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4 forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA // Sqlite Database forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}") // NightConfig (includes Toml & Json) forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}") forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}") // SVG (not needed atm) // forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}") // Netty // Breaks 1.16.5 //forgeShadowMe("io.netty:netty-all:${rootProject.netty_version}") // Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") { exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it } //==========================// // conditional dependencies // //==========================// // Add core if (isMinecraftSubProject) { coreProjects(project(":core")) { // Remove Junit test libraries exclude group: "org.junit.jupiter", module: "junit-jupiter" exclude group: "org.junit.jupiter", module: "junit-jupiter-engine" exclude group: "junit", module: "junit" // Removed dependencies transitive false } } // Add the api if (p != project(":api")) { coreProjects(project(":api")) { // Remove Junit test libraries exclude group: "org.junit.jupiter", module: "junit-jupiter" exclude group: "org.junit.jupiter", module: "junit-jupiter-engine" exclude group: "junit", module: "junit" // Removed dependencies transitive false } } // Add common if (isMinecraftSubProject && p != project(":common")) { // Common common(project(":common")) { transitive false } shadowCommon(project(":common")) { transitive false } // FabricLike if (findProject(":fabricLike") && p != project(":fabricLike")) { fabricLike(project(path: ":fabricLike")) { transitive false } shadowFabricLike(project(path: ":fabricLike")) { transitive false } } } } shadowJar { configurations = [project.configurations.shadowMe] if (isMinecraftSubProject && p != project(":common")) { configurations.push(project.configurations.shadowCommon) // Shadow the common subproject relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location if (findProject(":fabricLike") && p != project(":fabricLike")) { configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location } } def librariesLocation = "distanthorizons.libraries" // LWJGL // Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt" // Compression (LZ4) relocate "net.jpountz", "${librariesLocation}.jpountz" // Sqlite Database //At the moment, there is a bug in this library which doesnt allow it to be relocated // relocate "org.sqlite", "${librariesLocation}.sqlite" // JOML if (project.hasProperty("embed_joml") && embed_joml == "true") relocate "org.joml", "${librariesLocation}.joml" // NightConfig (includes Toml & Json) relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig" // SVG (not needed atm) // relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg" // Netty relocate "io.netty", "${librariesLocation}.netty" mergeServiceFiles() } // Using jar.finalizedBy(shadowJar) causes issues so we do this scuffed bypass jar.dependsOn(shadowJar) // Put stuff from gradle.properties into the mod info processResources { def resourceTargets = [ // Location of where to inject the properties // Holds info like git commit // TODO: For some reason this script doesnt work with the core project "build_info.json", // Properties for each of the loaders "fabric.mod.json", "quilt.mod.json", "META-INF/mods.toml", // The mixins for each of the loaders "DistantHorizons."+ p.name +".fabricLike.mixins.json" ] def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder // Fix forge version numbering system as it is weird // For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"] def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)") // println compatible_forgemc_versions // Quilt's custom contributors system // This has to be like // "Person": "Developer", "Another person": "Developer" def quilt_contributors = [] def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",") for (dev in mod_author_list) { quilt_contributors.push("\"${dev.strip()}\": \"Developer\"") } quilt_contributors.reverse() //println quilt_contributors.join(", ") // TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated // println p.tasks.findByName('shadowJar') // These "hasProperty"'s are so that they can be passed through the cli (ie in the CI) try { if (infoGitCommit == "null") infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim() if (infoGitBranch == "null") infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim() } catch (Exception e) { infoGitCommit = infoGitBranch = "Git not found" println "Git or Git project not found" } // The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties def replaceProperties = [ version : mod_version, mod_name : mod_readable_name, group : maven_group, authors : mod_authors, description : mod_description, homepage : mod_homepage, source : mod_source, issues : mod_issues, discord : mod_discord, minecraft_version : minecraft_version, compatible_minecraft_versions: compatible_minecraft_versions, compatible_forgemc_versions : compatible_forgemc_versions, java_version : java_version, quilt_contributors : "{"+quilt_contributors.join(", ")+"}", info_git_commit : infoGitBranch, info_git_branch : infoGitCommit, info_build_source : infoBuildSource, fabric_incompatibility_list : fabric_incompatibility_list, fabric_recommend_list : fabric_recommend_list, ] // replace any properties in the sub-projects with the values defined here inputs.properties replaceProperties replaceProperties.put "project", project filesMatching(resourceTargets) { expand replaceProperties } intoTargets.each { target -> if (file(target).exists()) { copy { from(sourceSets.main.resources) { include resourceTargets expand replaceProperties } into target } } } // ==================== Delete un-needed files ==================== exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later // exclude "*.distanthorizons.accesswidener" //// include "${accessWidenerVersion}.distanthorizons.accesswidener" // Jank solution to remove all unused accesswideners // The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it exclude { file -> if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") { return true } return false } } // Adds the standalone jar's entrypoint jar { from "LICENSE.txt" manifest { attributes 'Implementation-Title': rootProject.mod_name, 'Implementation-Version': rootProject.mod_version, 'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line } } // this can be un-commented if we ever wanted to make DH modular (AKA use a module-info.java file) again /* // Tells gradle where to look for other modules // Why isn't the classpath added to the modules path by default? if (p == project(":core")) { compileJava { inputs.property('moduleName', 'dhApi') doFirst { options.compilerArgs = [ '--module-path', classpath.asPath ] classpath = files() } } } */ } allprojects { p -> // Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")" // Useful later on so we dont have duplicated code def isMinecraftSubProject = p != project(":core") && p != project(":api") apply plugin: "java" apply plugin: "maven-publish" archivesBaseName = rootProject.mod_name version = project.name + "-" + rootProject.versionStr group = rootProject.maven_group // this is the text that appears at the top of the overview (home) page // and is used when bookmarking a page javadoc.title = rootProject.mod_name + "-" + project.name // Some annotations arent "technically" part of the official java standard, // so we define it ourself here javadoc { configure( options ) { tags( 'todo:X"', 'apiNote:a:API Note:', 'implSpec:a:Implementation Requirements:', 'implNote:a:Implementation Note:' ) } } repositories { // The central repo mavenCentral() // Used for Google's Collect library maven { url "https://repo.enonic.com/public/" } // For parchment mappings maven { url "https://maven.parchmentmc.org" } // For Architectury API maven { url "https://maven.architectury.dev" } // For Git repositories maven { url "https://jitpack.io" } // For Manifold Preprocessor maven { url "https://oss.sonatype.org/content/repositories/snapshots/" } // Required for importing Modrinth mods maven { name = "Modrinth" url = "https://api.modrinth.com/maven" content { includeGroup "maven.modrinth" } } // Required for importing CursedForge mods maven { url "https://www.cursemaven.com" content { includeGroup "curse.maven" } } // Required for ModMenu maven { url "https://maven.terraformersmc.com/" } // Required for Mixins & VanillaGradle maven { url "https://repo.spongepowered.org/maven/" } // Required for Canvas (mod) maven { url "https://maven.vram.io/" } // These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource 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" } } // TODO: If neoforged is ever needed, should we use that, or call it a forge mod? } // Adds some dependencies that are in vanilla but not in core if (p == project(":core")) { OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem; // Set the OS lwjgl is using to the current os project.ext.lwjglNatives = "natives-" + os.toFamilyName() dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core // Imports most of lwjgl's libraries (well, only the ones that we need) implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions // REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use implementation "org.lwjgl:lwjgl" implementation "org.lwjgl:lwjgl-assimp" implementation "org.lwjgl:lwjgl-glfw" implementation "org.lwjgl:lwjgl-openal" implementation "org.lwjgl:lwjgl-opengl" implementation "org.lwjgl:lwjgl-stb" implementation "org.lwjgl:lwjgl-tinyfd" runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives" runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives" implementation "org.joml:joml:${rootProject.joml_version}" // Some other dependencies implementation("org.jetbrains:annotations:16.0.2") implementation("com.google.code.findbugs:jsr305:3.0.2") implementation("com.google.common:google-collect:0.5") implementation("com.google.guava:guava:31.1-jre") } } task copyCommonLoaderResources(type: Copy) { from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") into(file(p.file("build/resources/main"))) rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener" // Move the fabricLike mixin to its different places for each subproject if (findProject(":fabricLike")) { from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json") into(file(p.file("build/resources/main"))) rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json" } } task copyCoreResources(type: Copy) { from fileTree(project(":core").file("src/main/resources")) into p.file("build/resources/main") } tasks.withType(JavaCompile) { if (isMinecraftSubProject) { options.release = rootProject.java_version as Integer options.compilerArgs += ["-Xplugin:Manifold"] } else { options.release = 8; // Core & Api should use Java 8 no matter what //options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled } options.encoding = "UTF-8" } java { withSourcesJar() } } // Delete the merged folder when running clean task cleanMergedJars() { def mergedFolder = file("Merged") if (mergedFolder.exists()) { delete(mergedFolder) } } // add cleanMergedJars to the end of the "clean" task tasks["clean"].finalizedBy(cleanMergedJars)