Fabric Loom
Fabric Loom,或者简称为 Loom,是个 Gradle 插件,用于 Fabric 生态系统的模组开发中。Loom 提供了在开发环境中安装 Minecraft 和模组的一系列工具,所以你可以针对 Minecraft 混淆及其发行版和版本之间的差异来将 Loom 与 Minecraft 链接起来。Loom 还提供了用于 Fabric 加载器的运行配置、mixin 编译处理,以及用于 Fabric Loader 的 jar-in-jar 系统的工具。
常用任务
migrateMappings
:将当前源代码合并到指定的映射中。见 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
:只有在 AbstractArchiveTasksourcesJar
存在时存在。将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 } // 删除内置服务器配置的示例 remove server } // 配置所有运行配置以生成 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 } } // 创建 modExampleImplementation 和重映射 mods 的相关配置。 createRemapConfigurations(sourceSets.example) } 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)。
- 处理并包含模组增强的依赖。
缓存
${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。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 参数。