diff --git a/build.gradle b/build.gradle index df7c0ba84..7a8162a82 100644 --- a/build.gradle +++ b/build.gradle @@ -1,684 +1,8 @@ -import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer -import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext -import org.apache.tools.zip.ZipEntry - -import javax.annotation.Nonnull -import org.apache.tools.zip.ZipOutputStream - -import java.util.function.Function -import java.util.function.Predicate - - plugins { - id "java" - - // Plugin to put dependencies inside our final jar - id "com.github.johnrengelman.shadow" version '8.1.1' apply false - - // Plugin to create merged jars - id "io.github.pacifistmc.forgix" version "1.3.4" - - // 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.13-SNAPSHOT" apply false + id 'root' + id 'io.github.pacifistmc.forgix' version '2.+' } - -/** - * 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") - -class NativeTransformer implements Transformer { - private Predicate fileMatcher - private Function filePathMapper - - private final HashMap replacements = new HashMap() - private final HashMap rewrittenFiles = new HashMap() - private var nativeRelocator - - public File rootDir - - void matchFiles(Predicate matcher) { - fileMatcher = matcher - } - - void mapPaths(Function 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.test(element.name) - } - - @Override - void transform(@Nonnull TransformerContext context) { - byte[] content = context.is.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 rewrittenFile : rewrittenFiles.entrySet()) { - os.putNextEntry(new ZipEntry(rewrittenFile.key)) - os.write(rewrittenFile.value) - } - } -} - -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 - } - } - - - dependencies { - //=====================// - // shared dependencies // - //=====================// - - // Manifold - if (isMinecraftSubProject) { - annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}") - } - - // Log4j - if (p == project(":core")) - { - // the standalone core jar needs logging shaded otherwise it won't run - forgeShadowMe("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}") - forgeShadowMe("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}") - } - else - { - // When running in MC, MC already includes logging - 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}") - - forgeShadowMe("com.github.luben:zstd-jni:${rootProject.zstd_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 - implementation("io.netty:netty-buffer:${rootProject.netty_version}") - - - - //==========================// - // 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 } - } - } - - - 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 - } - def librariesLocation = "DistantHorizons.libraries" - - // Compression (LZ4) - relocate "net.jpountz", "${librariesLocation}.jpountz" - - // Logging - relocate "org.slf4j", "${librariesLocation}.slf4j" - - // Sqlite Database - // librariesLocation isn't used because it's too long for replacing paths in native libraries - // Allowing strings larger than the original string would require shifting the entire binary's contents - 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 - // librariesLocation isn't used because it's too long for replacing paths in native libraries - // Allowing strings larger than the original string would require shifting the entire binary's contents - 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 - if (project.hasProperty("embed_joml") && embed_joml == "true") - relocate "org.joml", "${librariesLocation}.joml" - - // NightConfig (includes Toml & Json) - relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig" - - // Netty - // Don't relocate, it causes problems with using MC's FriendlyByteBufs -// 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 - // Note: these resources are only included in the mod jars, the core and API jars don't include these files - processResources { - def resourceTargets = [ // Location of where to inject the properties - // Holds info like git commit - "build_info.json", - - // Properties for each of the loaders - "fabric.mod.json", - "quilt.mod.json", - "META-INF/mods.toml", - "META-INF/neoforge.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(", ") - - - // 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, - - neoforge_version_range : neoforge_version_range, - ] - - // 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 ==================== - // Jank solution to remove all unused accesswideners - // (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, - 'Multi-Release': true, // needed for logging in the standalone core jar - '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" - - // Sets the name of the jar, the version will contain the name of the project if it isn't the root project - archivesBaseName = rootProject.mod_name - version = (project == rootProject ? "" : 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 { - // Mojang overrides (added to fix downloading the wrong LWJGL libs on M1 Mac's and potentially other arm64 based machines) - maven { url "https://libraries.minecraft.net/" } - - // The central repo - mavenCentral() - - // Used for Google's Collect library - maven { url "https://repo.enonic.com/public/" } - - // For parchment mappings - // versions can be found here: https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/ - 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" - } - } - - // VanillaGradle and Mixins in common - maven { url "https://repo.spongepowered.org/maven/" } - - // Canvas mod - maven { url "https://maven.vram.io/" } - // ModMenu mod - maven { url "https://maven.terraformersmc.com/" } - - // neoforge - maven { url "https://maven.neoforged.net/releases/" } - - // 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" - } - } - } - - // 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 them as we arent importing Minecraft in the core - - // Imports most of lwjgl's libraries - implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") - - // REMEMBER: Don't shadow stuff here, these are just the libs that are included in Minecraft so that the core can use them - implementation "org.lwjgl:lwjgl" - implementation "org.lwjgl:lwjgl-assimp" - implementation "org.lwjgl:lwjgl-glfw" - // OpenGL is removed since DH now handles rendering in the "Common" project - // so we can use OpenGL for old MC versions and Blaze3D (IE Vulkan) for newer ones -// 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" - } - - 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 - } else { - options.release = 8; // Core & Api should use Java 8 no matter what - } - options.encoding = "UTF-8" - } - - java { - withSourcesJar() - } +forgix { + autoRun = true } diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle new file mode 100644 index 000000000..3253068ae --- /dev/null +++ b/buildSrc/build.gradle @@ -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' +} diff --git a/buildSrc/src/main/groovy/dh-loader.gradle b/buildSrc/src/main/groovy/dh-loader.gradle new file mode 100644 index 000000000..433f033ab --- /dev/null +++ b/buildSrc/src/main/groovy/dh-loader.gradle @@ -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 fileMatcher + private Function filePathMapper + + private final HashMap replacements = new HashMap() + private final HashMap rewrittenFiles = new HashMap() + private nativeRelocator + + public File rootDir + + void matchFiles(Predicate matcher) { + fileMatcher = matcher + } + + void mapPaths(Function 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 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) +} diff --git a/buildSrc/src/main/groovy/root.gradle b/buildSrc/src/main/groovy/root.gradle new file mode 100644 index 000000000..6fd5802c4 --- /dev/null +++ b/buildSrc/src/main/groovy/root.gradle @@ -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) + } +} \ No newline at end of file diff --git a/buildSrc/src/main/groovy/unimined-fabric.gradle b/buildSrc/src/main/groovy/unimined-fabric.gradle new file mode 100644 index 000000000..9e3de7851 --- /dev/null +++ b/buildSrc/src/main/groovy/unimined-fabric.gradle @@ -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 diff --git a/buildSrc/src/main/groovy/unimined-forge.gradle b/buildSrc/src/main/groovy/unimined-forge.gradle new file mode 100644 index 000000000..587553a8f --- /dev/null +++ b/buildSrc/src/main/groovy/unimined-forge.gradle @@ -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 diff --git a/buildSrc/src/main/groovy/unimined-neoforge.gradle b/buildSrc/src/main/groovy/unimined-neoforge.gradle new file mode 100644 index 000000000..a97de717a --- /dev/null +++ b/buildSrc/src/main/groovy/unimined-neoforge.gradle @@ -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 diff --git a/common/build.gradle b/common/build.gradle index 40870f24e..018764b41 100644 --- a/common/build.gradle +++ b/common/build.gradle @@ -1,41 +1,3 @@ - -// temporary fix for broken spongepowered version -buildscript { - configurations.configureEach { - resolutionStrategy { - force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82' - // newer versions can be found by going to the link: - // https://repo.spongepowered.org/#browse/browse:maven-public:org%2Fspongepowered%2Fvanillagradle%2F0.2.1-SNAPSHOT - } - } -} - plugins { - id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT" + id 'dh-loader' } - -minecraft { - accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")) - version(rootProject.minecraft_version) -} - -dependencies { - // So mixins can be written in common - compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5' -} - - -publishing { - publications { - mavenCommon(MavenPublication) { - artifactId = rootProject.mod_readable_name - from components.java - } - } - - // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. - repositories { - // Add repositories to publish to here. - } -} - diff --git a/coreSubProjects b/coreSubProjects index 2b8cddd42..ecb3dce96 160000 --- a/coreSubProjects +++ b/coreSubProjects @@ -1 +1 @@ -Subproject commit 2b8cddd424cb26040de8c85bb9cdaf7c06bc67f1 +Subproject commit ecb3dce963dce25a80c5be4d76ec22f7a49de67c diff --git a/fabric/build.gradle b/fabric/build.gradle index 0609d4659..5951c2005 100644 --- a/fabric/build.gradle +++ b/fabric/build.gradle @@ -1,110 +1,24 @@ plugins { - id "fabric-loom" version "1.10-SNAPSHOT" -} - -loom { - accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") - - // "runs" isn't required, but when we do need it then it can be useful - runs { - client { - client() - setConfigName("Fabric Client") - ideConfigGenerated(true) // When true a run configuration file will be generated for IDE's. By default only set to true for the root project. - runDir("../run/client") - vmArgs( - // https://github.com/FabricMC/fabric-loom/issues/915#issuecomment-1609154390 - "-Dminecraft.api.auth.host=https://nope.invalid", - "-Dminecraft.api.account.host=https://nope.invalid", - "-Dminecraft.api.session.host=https://nope.invalid", - "-Dminecraft.api.services.host=https://nope.invalid", - // https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels - "-Dio.netty.leakDetection.level=advanced", - "-XX:+UseZGC", - "-XX:+ZGenerational" - ) - programArgs( - "--username", "Dev", - // "--renderDebugLabels" is a Mojang command to show render names in RenderDoc - "--renderDebugLabels", - // "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1 - "--tracy") - } - server { - server() - setConfigName("Fabric Server") - ideConfigGenerated(true) - runDir("../run/server") - vmArgs("-Dio.netty.leakDetection.level=advanced") - } - } -} - -remapJar { - inputFile = shadowJar.archiveFile - dependsOn shadowJar + id 'unimined-fabric' } -configurations { - // The addModJar basically embeds the mod to the built jar - addModJar - include.extendsFrom addModJar - modImplementation.extendsFrom addModJar -} - - +// ==================== Dependencies ==================== def addMod(path, enabled) { if (enabled == "2") dependencies { modImplementation(path) } else if (enabled == "1") - dependencies { modCompileOnly(path) } + dependencies { compileOnly(path) } } dependencies { - minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - mappings loom.layered() { - // Mojmap mappings - officialMojangMappings() - // Parchment mappings (it adds parameter mappings & javadoc) - parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip") - } // Fabric loader modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}" - -// annotationProcessor "javax.annotation:javax.annotation-api:1.3.2" -// implementation("javax.annotation:javax.annotation-api:1.3.2") -// runtimeOnly "javax.annotation:javax.annotation-api:1.3.2" -// compileOnly "javax.annotation:javax.annotation-api:1.3.2" -// modImplementation "javax.annotation:javax.annotation-api:1.3.2" - - // Fabric API - addModJar(fabricApi.module("fabric-api-base", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-lifecycle-events-v1", rootProject.fabric_api_version)) - if (buildVersionBefore(minecraft_version, "1.21.9")) - { - addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) - } - else // > 1.21.9 - { - addModJar(fabricApi.module("fabric-resource-loader-v0", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-resource-loader-v1", rootProject.fabric_api_version)) - } - addModJar(fabricApi.module("fabric-events-interaction-v0", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-rendering-v1", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-networking-api-v1", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-entity-events-v1", rootProject.fabric_api_version)) - if (buildVersionBefore(minecraft_version, "1.19.2")) - addModJar(fabricApi.module("fabric-command-api-v1", rootProject.fabric_api_version)) - else - addModJar(fabricApi.module("fabric-command-api-v2", rootProject.fabric_api_version)) - - // used by mod menu in MC 1.20.6+ - addModJar(fabricApi.module("fabric-screen-api-v1", rootProject.fabric_api_version)) - addModJar(fabricApi.module("fabric-key-binding-api-v1", rootProject.fabric_api_version)) - + // Fabric API (bundled as jar-in-jar so users don't need to install it separately) + modImplementation "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" + include "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}" // Mod Menu addMod("com.terraformersmc:modmenu:${rootProject.modmenu_version}", rootProject.enable_mod_menu) @@ -117,11 +31,7 @@ dependencies { // Sodium addMod("maven.modrinth:sodium:${rootProject.sodium_version}", rootProject.enable_sodium) - if (rootProject.enable_sodium == "2") { - implementation "org.joml:joml:1.10.2" - modImplementation(fabricApi.module("fabric-rendering-data-attachment-v1", rootProject.fabric_api_version)) - modImplementation(fabricApi.module("fabric-rendering-fluids-v1", rootProject.fabric_api_version)) - } + if (rootProject.enable_sodium == "2") implementation "org.joml:joml:1.10.2" // Lithium addMod("maven.modrinth:lithium:${rootProject.lithium_version}", rootProject.enable_lithium) @@ -133,65 +43,32 @@ dependencies { addMod("com.github.quiqueck:BCLib:${rootProject.bclib_version}", rootProject.enable_bclib) // Canvas - addMod("io.vram:canvas-fabric-${project.canvas_version}", rootProject.enable_canvas) + addMod("io.vram:canvas-fabric-${rootProject.canvas_version}", rootProject.enable_canvas) // Immersive Portals if (rootProject.enable_immersive_portals == "1") { - modCompileOnly("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}") + modCompileOnly("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${rootProject.immersive_portals_version}") } else if (rootProject.enable_immersive_portals == "2") { - modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${project.immersive_portals_version}") { + modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:imm_ptl_core:${rootProject.immersive_portals_version}") { exclude(group: "net.fabricmc.fabric-api") transitive(false) } - modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:q_misc_util:${project.immersive_portals_version}") { + modImplementation("com.github.iPortalTeam.ImmersivePortalsMod:q_misc_util:${rootProject.immersive_portals_version}") { exclude(group: "net.fabricmc.fabric-api") transitive(false) } - modImplementation ("com.github.iPortalTeam.ImmersivePortalsMod:build:${project.immersive_portals_version}") { + modImplementation("com.github.iPortalTeam.ImmersivePortalsMod:build:${rootProject.immersive_portals_version}") { exclude(group: "net.fabricmc.fabric-api") transitive(false) } - modImplementation("net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}") api("com.github.LlamaLad7:MixinExtras:0.2.0-beta.4") annotationProcessor("com.github.LlamaLad7:MixinExtras:0.2.0-beta.4") } } -private static boolean buildVersionBefore(String minecraft_version, String compareVersion) -{ - int sortValue = sortSemanticVersionOldestToNewest(minecraft_version, compareVersion); - return sortValue == -1; -} -/** - * input format: "major.minor.patch" - * needed so we can sort versions with different length strings - * IE: 1.21.1 should come before 1.21.10 - */ -private static int sortSemanticVersionOldestToNewest(String version1, String version2) -{ - String[] parts1 = version1.split("\\."); - String[] parts2 = version2.split("\\."); - - int major1 = Integer.parseInt(parts1[0]); - int major2 = Integer.parseInt(parts2[0]); - if (major1 != major2) - { - return Integer.compare(major1, major2); - } - - int minor1 = Integer.parseInt(parts1[1]); - int minor2 = Integer.parseInt(parts2[1]); - if (minor1 != minor2) - { - return Integer.compare(minor1, minor2); - } - - int patch1 = Integer.parseInt(parts1[2]); - int patch2 = Integer.parseInt(parts2[2]); - return Integer.compare(patch1, patch2); -} +// ==================== Tasks ==================== task deleteResources(type: Delete) { delete file("build/resources/main") @@ -202,14 +79,12 @@ processResources { dependsOn(copyCommonLoaderResources) } -runClient { +tasks.named('runClient') { dependsOn(copyCoreResources) dependsOn(copyCommonLoaderResources) -// jvmArgs([ "-XX:-OmitStackTraceInFastThrow", minecraftMemoryJavaArg ]) finalizedBy(deleteResources) } - sourcesJar { def commonSources = project(":common").sourcesJar dependsOn commonSources diff --git a/forge/build.gradle b/forge/build.gradle index e9fc94579..b28418f08 100644 --- a/forge/build.gradle +++ b/forge/build.gradle @@ -1,107 +1,38 @@ plugins { - // Note: This is only needed for multi-loader projects - // The main architectury loom version is set at the start of the root build.gradle - id "architectury-plugin" version "3.4-SNAPSHOT" + id 'unimined-forge' } -sourceCompatibility = targetCompatibility = JavaVersion.VERSION_21 -architectury { - platformSetupLoomIde() - forge() -} - -//loom { -// forge { -// convertAccessWideners.set(true) -// extraAccessWideners.add("lod.accesswidener") -// mixinConfigs("DistantHorizons.mixins.json") -// } -//} - -loom { - silentMojangMappingsLicense() // Shut the licencing warning - accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") - - forge { - convertAccessWideners = true - extraAccessWideners.add loom.accessWidenerPath.get().asFile.name - - mixinConfigs = [ - "DistantHorizons.forge.mixins.json" - ] - } - - // "runs" isn't required, but when we do need it then it can be useful - runs { - client { - client() - setConfigName("Forge Client") - ideConfigGenerated(false) // When true a run configuration file will be generated for IDE's. By default only set to true for the root project. - runDir("../run/client") - vmArgs( - // https://github.com/FabricMC/fabric-loom/issues/915#issuecomment-1609154390 - "-Dminecraft.api.auth.host=https://nope.invalid", - "-Dminecraft.api.account.host=https://nope.invalid", - "-Dminecraft.api.session.host=https://nope.invalid", - "-Dminecraft.api.services.host=https://nope.invalid", - // https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels - "-Dio.netty.leakDetection.level=advanced" - ) - programArgs("--username", "Dev") - } - server { - server() - setConfigName("Forge Server") - ideConfigGenerated(false) - runDir("../run/server") - vmArgs("-Dio.netty.leakDetection.level=advanced") - } - } -} - -remapJar { - inputFile = shadowJar.archiveFile - dependsOn shadowJar -} +// ==================== Mod Dependency Helper ==================== def addMod(path, enabled) { if (enabled == "2") - dependencies { implementation(path) } + dependencies { modImplementation(path) } else if (enabled == "1") - dependencies { modCompileOnly(path) } + dependencies { compileOnly(path) } } + +// ==================== Dependencies ==================== + dependencies { - minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - mappings loom.layered() { - // Mojmap mappings - officialMojangMappings() - // Parchment mappings (it adds parameter mappings & javadoc) - parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip") - } - - // Forge - forge "net.minecraftforge:forge:${rootProject.minecraft_version}-${rootProject.forge_version}" - + // TerraForged addMod("curse.maven:TerraForged-363820:${rootProject.terraforged_version}", rootProject.enable_terraforged) + // TerraFirmaCraft addMod("curse.maven:TerraFirmaCraft-302973:4616004", rootProject.enable_terrafirmacraft) - - if ( // Only run on MC 1.20.6 or later - // FIXME: Add an environment variable for the Major, Minor, and Patch version number of Minecraft - minecraft_version.split("\\.")[1].toInteger() >= 20 && - ( - minecraft_version.split("\\.").length > 1 && // Incase there isn't a minor version - minecraft_version.split("\\.")[2].toInteger() >= 6 - ) - ) { - // (potential) hack fix, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+ - implementation('net.sf.jopt-simple:jopt-simple:5.0.4') //{ version { strictly '5.0.4' } } + // TODO: Check if this is still needed and if so ensure this code works for MC 26.1+ + // (potential) hack fix for MC 1.20.6 and later, force jopt-simple to be exactly 5.0.4 because Mojang ships that version, but some transitive dependencies request 6.0+ + def mcParts = rootProject.minecraft_version.split("\\.") + if (mcParts[1].toInteger() >= 20 && (mcParts.length > 2 && mcParts[2].toInteger() >= 6)) { + implementation('net.sf.jopt-simple:jopt-simple:5.0.4') } } + +// ==================== Tasks ==================== + task deleteResources(type: Delete) { delete file("build/resources/main") } @@ -119,4 +50,3 @@ tasks.named('runClient') { dependsOn(tasks.named('copyAllResources')) finalizedBy(deleteResources) } - diff --git a/forge/gradle.properties b/forge/gradle.properties deleted file mode 100644 index 32f842a63..000000000 --- a/forge/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -loom.platform=forge \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index ba7b2f522..12e455bf9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -34,11 +34,6 @@ fastutil_version=8.2.1 log4j_version=2.23.1 joml_version=1.10.2 -# Architectury config -# this is necessary for MC 1.21.3 because including Sodium and Iris throws "Mod was built with a newer version of Loom (1.8.9), you are using Loom (1.7.415)" -loom.ignoreDependencyLoomVersionValidation=true - - # These are here so they can be changed with cmd arguments # If they are null, they would be automatically set # (This is mainly used for the CI) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793a..c61a118f7 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.1-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/neoforge/build.gradle b/neoforge/build.gradle index f23c2c45b..9809b552b 100644 --- a/neoforge/build.gradle +++ b/neoforge/build.gradle @@ -1,110 +1,43 @@ plugins { - // Note: This is only needed for multi-loader projects - // The main architectury loom version is set at the start of the root build.gradle - id "architectury-plugin" version "3.4-SNAPSHOT" -} - -sourceCompatibility = targetCompatibility = JavaVersion.VERSION_17 - -architectury { - platformSetupLoomIde() - neoForge() -} - -loom { - silentMojangMappingsLicense() // Shut the licencing warning - accessWidenerPath = project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener") - - neoForge { - // Access wideners are defined in the `remapJar.atAccessWideners` - - // Mixins are defined in the `mods.toml` - } - mixin { - // Mixins are defined in the `mods.toml` - } - - // "runs" isn't required, but when we do need it then it can be useful - runs { - client { - client() - setConfigName("NeoForge Client") - ideConfigGenerated(false) // When true a run configuration file will be generated for IDE's. By default only set to true for the root project. - runDir("../run/client") - vmArgs( - "-Dio.netty.leakDetection.level=advanced", - "-XX:+UseZGC") // https://netty.io/wiki/reference-counted-objects.html#leak-detection-levels - programArgs( - "--username", "Dev", - // "--renderDebugLabels" is a Mojang command to show render names in RenderDoc - "--renderDebugLabels", - // "--tracy" is a Mojang command to allow individual frames to be debugged using Tracy https://github.com/wolfpld/tracy/releases/tag/v0.13.1 - "--tracy") - } - server { - server() - setConfigName("NeoForge Server") - ideConfigGenerated(false) - runDir("../run/server") - vmArgs("-Dio.netty.leakDetection.level=advanced") - } - } + id 'unimined-neoforge' } +// ==================== Mod Dependency Helper ==================== def addMod(path, enabled) { if (enabled == "2") - dependencies { implementation(path) } + dependencies { modImplementation(path) } else if (enabled == "1") - dependencies { modCompileOnly(path) } + dependencies { compileOnly(path) } } -dependencies { - minecraft "com.mojang:minecraft:${rootProject.minecraft_version}" - mappings loom.layered() - { - // Mojmap mappings - officialMojangMappings() - // Parchment mappings (it adds parameter mappings & javadoc) - parchment("org.parchmentmc.data:parchment-${rootProject.parchment_version}@zip") - } - - - // Neoforge - neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}" + +// ==================== Dependencies ==================== + +dependencies { // Iris addMod("maven.modrinth:iris:${rootProject.neo_iris_version}", rootProject.neo_enable_iris) - } +// ==================== Tasks ==================== task deleteResources(type: Delete) { delete file("build/resources/main") } -tasks.register('copyAllResources') { +processResources { dependsOn(copyCoreResources) dependsOn(copyCommonLoaderResources) } -processResources { - dependsOn(tasks.named('copyAllResources')) -} - tasks.named('runClient') { - dependsOn(tasks.named('copyAllResources')) + dependsOn(copyCoreResources) + dependsOn(copyCommonLoaderResources) finalizedBy(deleteResources) } -remapJar { - inputFile = shadowJar.archiveFile - dependsOn shadowJar - - atAccessWideners.add("distanthorizons.accesswidener") -} - sourcesJar { def commonSources = project(":common").sourcesJar dependsOn commonSources diff --git a/neoforge/gradle.properties b/neoforge/gradle.properties deleted file mode 100644 index 85e1db4b7..000000000 --- a/neoforge/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -loom.platform=neoForge \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 41c8850ea..f7ca39e42 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,49 +1,5 @@ -pluginManagement { - repositories { - maven { - name "Fabric" - url "https://maven.fabricmc.net/" - } - maven { - name "Forge" - url "https://maven.minecraftforge.net/" - } - maven { - name "NeoForge Releases" - url "https://maven.neoforged.net/releases/" - } - maven { - name "NeoForge Snapshot" - url "https://maven.neoforged.net/snapshots/" - } - maven { - name "Architectury" - url "https://maven.architectury.dev/" - } - maven { - name "Quilt" - url "https://maven.quiltmc.org/repository/release" - } - maven { // Used for Vanilla Minecraft's libraries - name "Sponge" - url "https://repo.spongepowered.org/repository/maven-public/" - } - maven { - name "ParchmentMC" - url "https://maven.parchmentmc.org" - } - mavenCentral() - gradlePluginPortal() - - // Not needed, but useful for debugging gradle plugins - mavenLocal() - } -} - - - -// Throw an error and a little help message if the user forgot to clone the core sub-project -if (!file("./coreSubProjects/LICENSE.txt").exists()) { // the LICENCE.txt file should always, and only exist if the core-sub-project was cloned +// Throw an error if the core sub-project wasn't cloned +if (!file("./coreSubProjects/LICENSE.txt").exists()) { println(''' It seems that the core sub project was not included... please make sure that when you were cloning the repo, you were using the `--recurse-submodules` flag on git. @@ -55,98 +11,55 @@ If you still need help with compiling, please read the Readme.md } +def loadVersionProperties() { + def mcVers = fileTree("versionProperties").files.collect { it.name.replaceAll("\\.properties", "") } + .sort { a, b -> + def aParts = a.tokenize('.'); def bParts = b.tokenize('.') + for (int i = 0; i < Math.min(aParts.size(), bParts.size()); i++) { + def aNum = aParts[i].isInteger() ? aParts[i].toInteger() : aParts[i] + def bNum = bParts[i].isInteger() ? bParts[i].toInteger() : bParts[i] + def compare = aNum <=> bNum + if (compare != 0) return compare + } + return aParts.size() <=> bParts.size() + } + def mcVersion = hasProperty("mcVer") ? mcVer : "" + def mcIndex = mcVers.indexOf(mcVersion) -/** Loads the VersionProperties fiel for the currently selected Minecraft version. */ -def loadProperties() -{ - def defaultMcVersion = "1.20.1" // 1.20.1 is our current most stable version so we use that if no version was defined - - def mcVersion = "" - def mcVers = fileTree("versionProperties").files.name // Get all the files in "versionProperties" - for (int i = 0; i < mcVers.size(); i++) - { - String version = mcVers[i]; - version = version.replaceAll("\\.properties", "") // As we are getting the file names, we should remove the ".properties" at the end to get the versions - mcVers[i] = version; + if (mcIndex == -1) { + def defaultVersion = "1.20.1" + println "No mcVer set or invalid. Defaulting to ${defaultVersion}." + println "Tip: Use -PmcVer=\"${defaultVersion}\" to set the MC version." + mcVersion = defaultVersion + mcIndex = mcVers.indexOf(defaultVersion) + assert mcIndex != -1 : "Default MC version ${defaultVersion} not found in ${mcVers}" } - mcVers.sort((a,b) -> sortSemanticVersionOldestToNewest(a,b)) // Sort so it always goes from oldest to newest + println "Available MC versions: ${mcVers}" + println "Loading properties file: ${mcVersion}.properties" - int mcIndex = -1 - println "Avalible MC versions: ${mcVers}" - if (hasProperty("mcVer")) - { - mcVersion = mcVer - mcIndex = mcVers.indexOf(mcVer) - } - - if (mcIndex == -1) - { - println "No mcVer set or the set mcVer is invalid! Defaulting to ${defaultMcVersion}." - println "Tip: Use -PmcVer=\"${defaultMcVersion}\" in cmd arg to set mcVer." - mcVersion = defaultMcVersion - mcIndex = mcVers.indexOf(defaultMcVersion) - assert mcIndex != -1 - } - - println "Loading properties file at " + mcVersion + ".properties" def props = new Properties() - props.load(new FileInputStream("$rootDir/versionProperties/"+"$mcVersion"+".properties")) + props.load(new FileInputStream("$rootDir/versionProperties/${mcVersion}.properties")) - props.each { prop -> - gradle.ext.set(prop.key, prop.value) - // println "Added prop [key:" + prop.key + ", value:" + prop.value + "]" - } + props.each { key, value -> gradle.ext.set(key, value) } gradle.ext.mcVers = mcVers gradle.ext.mcIndex = mcIndex } -/** - * input format: "major.minor.patch" - * needed so we can sort versions with different length strings - * IE: 1.21.1 should come before 1.21.10 - */ -private static int sortSemanticVersionOldestToNewest(String version1, String version2) -{ - String[] parts1 = version1.split("\\."); - String[] parts2 = version2.split("\\."); - - int major1 = Integer.parseInt(parts1[0]); - int major2 = Integer.parseInt(parts2[0]); - if (major1 != major2) - { - return Integer.compare(major1, major2); - } - - int minor1 = Integer.parseInt(parts1[1]); - int minor2 = Integer.parseInt(parts2[1]); - if (minor1 != minor2) - { - return Integer.compare(minor1, minor2); - } - - int patch1 = Integer.parseInt(parts1[2]); - int patch2 = Integer.parseInt(parts2[2]); - return Integer.compare(patch1, patch2); -} - -loadProperties() +loadVersionProperties() - - -// Minecraft independent sub-projects +// Minecraft-independent sub-projects include("core") project(":core").projectDir = file('coreSubProjects/core') include("api") project(":api").projectDir = file('coreSubProjects/api') -// Minecraft dependent sub-projects +// Minecraft-dependent sub-projects include("common") -// Enables or disables the subprojects depending on whats in the versionProperties/mcVer.properties -for (loader in ((String) gradle.builds_for).split(",")) { - def loaderName = loader.strip() // Strip it in case a space is added before or after the comma - println "Adding loader " + loaderName +((String) gradle.builds_for).split(",").each { loader -> + def loaderName = loader.trim() + println "Adding loader: ${loaderName}" include(loaderName) } diff --git a/versionProperties/1.20.6.properties b/versionProperties/1.20.6.properties index e3096bd7c..5693b1b3a 100644 --- a/versionProperties/1.20.6.properties +++ b/versionProperties/1.20.6.properties @@ -47,7 +47,7 @@ fabric_api_version=0.97.8+1.20.6 # NeoForge loader forge_version= -neoforge_version=20.6.136 +neoforge_version=136 neoforge_version_range=[*,) # NeoForge mod versions diff --git a/versionProperties/1.21.1.properties b/versionProperties/1.21.1.properties index a1535ff55..475422676 100644 --- a/versionProperties/1.21.1.properties +++ b/versionProperties/1.21.1.properties @@ -47,7 +47,7 @@ fabric_api_version=0.115.0+1.21.1 # NeoForge loader forge_version= -neoforge_version=21.1.216 +neoforge_version=216 neoforge_version_range=[*,) # NeoForge mod versions diff --git a/versionProperties/1.21.10.properties b/versionProperties/1.21.10.properties index 0904bac2f..cb48d1485 100644 --- a/versionProperties/1.21.10.properties +++ b/versionProperties/1.21.10.properties @@ -45,7 +45,7 @@ fabric_api_version=0.138.3+1.21.10 # NeoForge loader forge_version= -neoforge_version=21.10.56-beta +neoforge_version=56-beta neoforge_version_range=[21.10.6-beta,) # NeoForge mod versions diff --git a/versionProperties/1.21.11.properties b/versionProperties/1.21.11.properties index 24be330c0..b5b4c8908 100644 --- a/versionProperties/1.21.11.properties +++ b/versionProperties/1.21.11.properties @@ -45,7 +45,7 @@ fabric_api_version=0.139.4+1.21.11 # NeoForge loader forge_version= -neoforge_version=21.11.38-beta +neoforge_version=38-beta neoforge_version_range=[*,) # NeoForge mod versions diff --git a/versionProperties/1.21.3.properties b/versionProperties/1.21.3.properties index a6dedbe66..f9da295ff 100644 --- a/versionProperties/1.21.3.properties +++ b/versionProperties/1.21.3.properties @@ -47,7 +47,7 @@ fabric_api_version=0.110.0+1.21.3 # NeoForge loader forge_version= -neoforge_version=21.3.86 +neoforge_version=86 neoforge_version_range=[*,) # NeoForge mod versions diff --git a/versionProperties/1.21.4.properties b/versionProperties/1.21.4.properties index a753d179d..a79c98dc2 100644 --- a/versionProperties/1.21.4.properties +++ b/versionProperties/1.21.4.properties @@ -46,7 +46,7 @@ fabric_api_version=0.110.5+1.21.4 # NeoForge loader forge_version= -neoforge_version=21.4.147 +neoforge_version=147 # version range may not be necessary, but having compiled DH for an older version caused issues with shaders neoforge_version_range=[21.4.147,) diff --git a/versionProperties/1.21.5.properties b/versionProperties/1.21.5.properties index 7c306a476..2d3308215 100644 --- a/versionProperties/1.21.5.properties +++ b/versionProperties/1.21.5.properties @@ -46,7 +46,7 @@ fabric_api_version=0.119.5+1.21.5 # NeoForge loader forge_version= -neoforge_version=21.5.87 +neoforge_version=87 neoforge_version_range=[*,) # NeoForge mod versions diff --git a/versionProperties/1.21.6.properties b/versionProperties/1.21.6.properties index 11bbe88a6..45692e302 100644 --- a/versionProperties/1.21.6.properties +++ b/versionProperties/1.21.6.properties @@ -45,7 +45,7 @@ fabric_api_version=0.127.0+1.21.6 # NeoForge loader forge_version= -neoforge_version=21.6.20-beta +neoforge_version=20-beta # around 6.19 neo changed how their render API works, failing to meet this causes the game to crash neoforge_version_range=[21.6.19-beta,) diff --git a/versionProperties/1.21.8.properties b/versionProperties/1.21.8.properties index 5f8dd7e04..6330dff60 100644 --- a/versionProperties/1.21.8.properties +++ b/versionProperties/1.21.8.properties @@ -45,7 +45,7 @@ fabric_api_version=0.133.4+1.21.8 # NeoForge loader forge_version= -neoforge_version=21.8.52 +neoforge_version=52 # around 6.19 neo changed how their render API works, failing to meet this causes the game to crash neoforge_version_range=[*,) diff --git a/versionProperties/1.21.9.properties b/versionProperties/1.21.9.properties index c177f4caa..82ff98a6a 100644 --- a/versionProperties/1.21.9.properties +++ b/versionProperties/1.21.9.properties @@ -45,7 +45,7 @@ fabric_api_version=0.134.0+1.21.9 # NeoForge loader forge_version= -neoforge_version=21.9.15-beta +neoforge_version=15-beta # sometime before 21.9.15-beta Neoforge changed how their rendering API events handle levels # so we can't support both versions at once neoforge_version_range=[21.9.15-beta,)