====== Fabric Loom ====== Fabric Loom,或者简称为 Loom,是个 [[https://gradle.org/|Gradle]] 插件,用于 Fabric 生态系统的模组开发中。Loom 提供了在开发环境中安装 Minecraft 和模组的一系列工具,所以你可以针对 Minecraft 混淆及其发行版和版本之间的差异来将 Loom 与 Minecraft 链接起来。Loom 还提供了用于 Fabric 加载器的运行配置、mixin 编译处理,以及用于 Fabric Loader 的 jar-in-jar 系统的工具。 ==== 常用任务 ==== * ''migrateMappings'':将当前源代码合并到指定的映射中。见 [[zh_cn:tutorial:migratemappings]]。 * ''remapJar'':产生包含 ''jar'' 任务的重映射的输出的 jar。同时也会将 jar-in-jar 包含在模组中。运行 ''build'' 时会调用。 * ''genSources'':使用默认的反编译器(CFR)反编译 Minecraft jar。 * ''downloadAssets'':下载配置的 Minecraft 版本的资源索引和对象,下载到用户缓存中。 * ''genEclipseRuns'':安装 Eclipse 运行配置并创建运行目录(如果还不存在)。 * ''vscode'':生成或覆盖 Visual Studio Code 的 ''launch.json'' 文件,启动配置在 ''.vscode'' 文件夹中,并创建运行目录,如果还不存在。 * ''ideaSyncTask'':生成(但是不会覆盖)Intellij IDEA 的启动配置,包括客户端和服务器。 * ''remapSourcesJar'':只有在 AbstractArchiveTask ''sourcesJar'' 存在时存在。将 ''sourcesJar'' 任务的输出重映射。 * ''runClient'':将 Fabric Loader 作为 Minecraft 客户端运行的 JavaExec 任务。 * ''runServer'':将 Fabric Loader 作为 Minecraft 专用服务器运行的 JavaExec 任务。 ==== 依赖子项目 ==== 设立依赖其他 loom 项目的多项目构建时,你应该在依赖其他项目时使用 ''namedElements'' 配置。默认情况下,项目的“输出”会映射到中间名。''namedElements'' 配置包含还未重映射的项目输出。 dependencies { implementation project(path: ":name", configuration: "namedElements") } 如果你在多项目构建中使用分离源集,你还需要为其他项目客户端源集添加依赖项。 dependencies { clientImplementation project(":name").sourceSets.client.output } ==== 分离客户端与常规代码 ==== 多年来,服务器崩溃往往是因为安装在服务器上时意外调用客户端代码。最新的 loom 和 loader 版本提供了一个选项,要求将所有客户端代码移动到其自己的源集中。这样做是为了提供编译时的保证,以防止在服务器上调用仅限客户端的 Minecraft 代码或仅限客户端的 API。在客户端和服务器上都可以使用的单个 jar 文件仍然是从两个源集构建的。 以下 build.gradle 文件片段展示了如何为您的模组启用此功能。由于您的模组现在将拆分为两个源集,因此您将需要使用新的 DSL 来定义您的模组源集。这将会让 Fabric Loader 将您的模组类路径组合在一起,对于其他一些复杂的多项目设置也有用。 要分享客户端与服务器的代码,需要 Minecraft 1.18(建议 1.19)、Loader 0.14 和 Loom 1.0 以上的版本。 loom { splitEnvironmentSourceSets() mods { modid { sourceSet sourceSets.main sourceSet sourceSets.client } } } ==== 多项目优化 ==== 如果你的 Gradle 项目有多个子项目并使用相同的 Minecraft 版本,如 Fabric API,从 Loom 1.1 开始,你可以选择使用高级的优化。在 gradle.properties 中加入 fabric.loom.multiProjectOptimisation=true从而减少构建时间和内存使用,因为会在重映射多个输出的 jar 时在项目之间共享 Tiny Remapper 实例。 ==== 选项 ==== loom { // 设置访问加宽的路径,参见 https://fabricmc.net/wiki/zh_cn:tutorial:accesswideners accessWidenerPath = file("src/main/resources/modid.accesswidener") // 添加额外的 log4j 配置文件。 log4jConfigs.from(file("log4j.xml")) // 若启用,输出的存档会自动重映射。 remapArchives = true // 若启用,*Elements 配置中的 -dev jars 会被替换为重映射的 jar。 setupRemappedVariants = true // 若启用,传递性的访问加宽会从依赖中应用。 enableTransitiveAccessWideners = true // 若启用,log4j 只会在运行时类路径中,强制使用 SLF4j。 runtimeOnlyLog4j = false // 若启用,只有与服务器有关的特性和 jars 会被设置。 serverOnlyMinecraftJar() // 若设置,minecraft jar 会分为常规和仅客户端。这只是实验性的。Fabric 加载器暂时还不支持这个功能。 splitMinecraftJar() // 用于配置存在的或者新的运行配置 runs { client { // 添加 VM 变量 vmArgs "-Dexample=true" // 添加 JVM 属性 property("example", "true") // 添加 program 变量 programArg "--example" // 需要运行的环境(或端),通常是 client 或 server。 environment = "client" // 运行配置的完整名称,例如“Minecraft 客户端”。默认由基础名称决定。 configName = "Minecraft 客户端" // 运行配置的默认主类。使用带有 fabric_installer.json 文件的模组加载器时,就会覆盖这个。 defaultMainClass = "" // 此配置的运行目录,与根项目目录有关。 runDir = "run" // 运行的源集,通常设为 sourceSets.test source = sourceSets.main // 若为 true,运行配置会为 IDE 生成。默认仅对根项目为 true。 ideConfigGenerated = true // 配置以默认的客户端选项运行配置。 client() // 配置以默认的服务器选项运行配置。 server() } // 为测试创建基本运行配置的示例 testClient { // 从另一个运行配置复制设置。 inherit client configName = "测试 Minecraft 客户端" source = sourceSets.test } } // 配置所有运行配置以生成 ide 运行配置。对子项目很有用。 runConfigs.configureEach { ideConfigGenerated = true } // 用于配置 mixin 选项,或应用到额外的源集。 mixin { // 若禁用,会使用 tiny remapper 来重映射 Mixin 而非 AP。实验性。 useLegacyMixinAp = true // 设置默认的 refmap 名称 defaultRefmapName = "example.refmap.json" // 关于添加额外资源集的选项,参见 https://github.com/FabricMC/fabric-loom/blob/dev/0.11/src/main/java/net/fabricmc/loom/api/MixinExtensionAPI.java } // 配置或添加新的反编译器 decompilers { // 配置默认的反编译器,cfr 或 fernflower cfr { // 将额外选项传递到编译器 options += [ key: "value" ] // 设置分叉 JVM 时使用的内存量(以兆字节为单位) memory = 4096 // 设置反编译器可以使用的最大线程数。 maxThreads = 8 } } interfaceInjection { // 若启用,将会应用配置的注入的接口。 enableDependencyInterfaceInjection = true } // 将 Minecraft jar 和传入的依赖项拆分到 main(common)和仅限客户端的源集。 // 这可以在编译期间就确保访问仅限客户端的代码时的安全。 splitEnvironmentSourceSets() // 这个 mods 语句块用于将由多个类路径的项组合在一起。 mods { modid { // 使用分离的资源时,你应该添加 main 和 common 源集 sourceSet sourceSets.main sourceSet sourceSets.client } } } remapJar { // 设置任务的输出 jar,同样对 remapSourcesJar 有效 inputFile = file("example.jar") // 设置资源命名空间,同样对 remapSourcesJar 有效 sourceNamespace = "named" // 设置目标命名空间,同样对 remapSourcesJar 有效 targetNamespace = "intermediary" // 给重映射类路径添加额外的 jar,同样对 remapSourcesJar 有效 classpath.from file("classpath.jar") // 将嵌套的模组 jar 添加到该任务,include 配置应该用于 maven 库和模组。 nestedJars.from file("nested.jar") // 若启用,输出的 jar 中会包含嵌套的 jar。 addNestedDependencies = true } dependencies { // 设置 Minecraft 版本。 minecraft "com.mojang:minecraft:1.18.1" // 使用 maven 中的映射。 mappings "net.fabricmc:yarn:1.18.1+build.22:v2" // 使用官方 mojang 映射 mappings loom.officialMojangMappings() // 使用官方 mojang 映射和 parchment 的分层映射。 mappings loom.layered() { officialMojangMappings() // 使用 parchment 映射。注意:必须手动添加 Parchment maven(https://maven.parchmentmc.org) parchment("org.parchmentmc.data:parchment-1.17.1:2021.09.05@zip") } // 从 maven 中重映射一个模组,并应用到 gradle 的 implementation 配置 // (小的细节:不会准确地应用*到*配置,但是会克隆一份以用于模组依赖) modImplementation "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 从 maven 中重映射一个模组,并应用到 gradle 的 api 配置 modApi "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 从 maven 中重映射一个模组,并应用到 gradle 的 compileOnly 配置 modCompileOnly "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 从 maven 中重映射一个模组,并应用到 gradle 的 compileOnlyApi 配置 modCompileOnlyApi "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 从 maven 中重映射一个模组,并应用到 gradle 的 runtimeOnly配置 modRuntimeOnly "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 从 maven 中重映射一个模组,并应用到 loom 的 localRuntime 配置。 // 和 runtimeOnly 的做法类似,但是不会暴露到依赖项中。有点像 testRuntimeOnly,不过是对于模组的。 modLocalRuntime "net.fabricmc.fabric-api:fabric-api:0.46.2+1.18" // 在重映射的 jar 中包含一个模组 jar。不可传递。 include "example:example-mod:1.1.1" // 在重映射的 jar 中包含一个空模组库。会生成空模组。不可传递。 include "example:example-lib:1.1.1" // 根据特定的结构 api 版本提供帮助的助手。 modImplementation fabricApi.module("fabric-api-base", "0.46.2+1.18") // 使用 namedElements 配置,依赖一个 loom 子项目。 implementation project(path: ":name", configuration: "namedElements") } ==== 解决问题 ==== Loom 或者 gradle 可能会由于缓存文件有问题而失败。运行 ''./gradlew build --refresh-dependencies'' 将强制 gradle 和 loom 重新下载并重新创建所有文件。这可能需要几分钟,但是处理与缓存有关的问题时非常有用。 ==== 开发环境设置 ==== Loom 旨在通过简单地在用户选择的 IDE 中设置工作区来开箱即用,因此背后做了很多事以创建带有 Minecraft 的开发环境: - 从官方渠道下载指定版本 Minecraft 的客户端和服务器 jar。 - 将客户端和服务器 jar 合并到一起以生成一个合并的 jar,并加上 ''@Environment'' 和 ''@EnvironmentInterface'' 注解。 - 下载配置的映射。 - 使用中间映射重映射合并的 jar 产生一个中间 jar。 - 使用 yarn 映射重映射合并的 jar 产生一个映射的 jar。 - 可选的:反编译映射了的 jar,产生一个映射的源 jar 和行映射,并将行映射应用到合并的 jar。 - 添加 Minecraft 的依赖。 - 下载 Minecraft 资源文件(assets)。 - 处理并包含模组增强的依赖(还可以导出并重映射嵌套的 JAR)。 ==== 缓存 ==== * ''${GRADLE_HOME}/caches/fabric-loom'':用户缓存,用户所有 Loom 项目共用的缓存。用来缓存 Minecraft 资源文件(assets)、jars、合并的 jars、中间 jars 和映射的 jars。 * ''.gradle/loom-cache'':根项目持久缓存,项目和子项目共用的缓存。用来缓存重映射的模组以及生成的包含的模组 JAR。 * ''build/loom-cache'':根项目构建缓存。 * ''**/build/loom-cache'':项目和子项目的构建缓存。 ==== 依赖配置 ==== * ''minecraft'':定义用于开发环境的 Minecraft 版本。 * ''mappings'':定义用于开发环境的映射。 * ''modCompile''、''modImplementation''、''modApi'' 和''modRuntime'':相当于''compile''、''implementation''、''api''和''runtime''的增强型变种,用于模组依赖。会被重映射以对应开发环境,并且会移除嵌套的 JAR。可以选择导出并重映射嵌套的 JAR。 * ''include'':生命一个应在 ''remapJar'' 输出中包含的 jar-in-jar 依赖。该依赖配置是不可传递的。对于非模组依赖,Loom 会生成一个模组 JAR,其中 fabric.mod.json 使用模组 ID 的名称和相同版本。 ==== 默认配置 ==== * 应用以下插件:''java''、''eclipse'' 和 ''idea''。 * 添加以下的 Maven 仓库:Fabric [[https://maven.fabricmc.net/]]、Mojang [[https://libraries.minecraft.net/]] 和 Maven Central。 * 配置 ''idea'' 扩展以排除目录 ''.gradle''、''build''、''.idea'' 和 ''out'',以下载 javadocs 源,并继承输出目录。 * 配置 ''idea'' 任务,并由 ''genIdeaWorkspace'' 任务确定。 * 配置 ''eclipse'' 任务,并由 ''genEclipseRuns'' 任务确定。 * 如果根项目存在 ''.idea'' 文件夹,下载资源(如果没有及时更新)并在 ''.idea/runConfigurations'' 安装 run 配置。 * 添加 ''net.fabricmc:fabric-mixin-compile-extensions'' 以及其依赖,使用 ''annotationProcessor'' 依赖配置。 * 配置所有的非 test JavaCompile 任务,使用 Mixin 注解处理器的配置。 * 配置 ''remapJar'' 任务,输出名称与 ''jar'' 任务输出的相同的 JAR,然后给 ''jar'' 任务添加一个“dev”分类器。 * 配置 ''remapSourcesJar'' 任务,以处理 ''sourcesJar'' 任务输出,如果该任务存在。 * 将 ''remapJar'' 任务和 ''remapSourcesJar'' 任务添加为 ''build'' 任务的依赖。 * 配置 ''remapJar'' 任务和 ''remapSourcesJar'' 任务以在执行时将其输出添加为 ''archives'' 成品。 * 为每个 MavenPublication (从 ''maven-publish'' 插件): * 手动将依赖附加到 POM 之后,以进行模组增强的依赖配置,前提是依赖配置具有 Maven 范围。 所有的运行配置都有运行目录 ''${projectDir}/run'' 和 VM 参数 ''-Dfabric.development=true''。运行配置的主类通常是由 Fabric 加载器 JAR 文件的根部的 ''fabric-installer.json'' 文件定义的(如果该文件包含在模组依赖中的话),但是文件可以由模组依赖定义。如果没有找到这样的文件,则主类默认为 ''net.fabricmc.loader.launch.knot.KnotClient'' 和 ''net.fabricmc.loader.launch.knot.KnotServer''。 客户端运行配置是使用 ''--assetsIndex'' 和 ''--assetsDir'' 程序参数配置的,指向包含资源文件和配置的 Minecraft 版本的索引文件的 loom 缓存目录。在 OSX 上运行时,添加了 ''-XstartOnFirstThread'' VM 参数。