Mission 01 · 学完能做什么
不是“照着敲完”,而是建立一张能继续成长的开发地图。
很多初学教程一上来就复制几十行注册代码,学生虽然看见游戏里多了东西,却不知道 JDK、Gradle、Fabric Loader 和 Fabric API 各自负责什么。一旦版本不同、包名改了或依赖下载失败,就完全不知道从哪里检查。本课先建立模型,再完成一个小而完整的作品。你会知道每个文件为何存在、每条命令在哪一层运行,以及错误信息应该从哪一行开始读。
独立搭建环境
确认 Java 版本,设置 IntelliJ 的 Project SDK 和 Gradle JVM,并判断“系统 Java”与“项目 Java”是否一致。
说清四个组件
区分 JDK、Gradle/Loom、Fabric Loader 与 Fabric API,理解它们怎样把普通 Java 代码送进游戏。
做出可见功能
注册 /hello_fabric 命令,让服务端给玩家发送消息并添加一颗绿宝石,而不是只输出一句日志。
导出可安装 JAR
用 Gradle 构建模组,找到正确 JAR,安装到普通 Fabric 客户端,并理解版本必须成套匹配。
/hello_fabric,看到中文消息、获得绿宝石,并能在 build/libs 找到构建产物。Version strategy · 先把版本固定住
模组开发最怕的不是代码难,而是把不同年代的教程拼在一起。
Fabric、Minecraft、Java、Loader、Loom 和 Fabric API 都有自己的版本。网络上 1.20.1、1.21.1、1.21.11 与 26.x 的类名和资源格式可能不同。看见“最新版本”就全部升级,往往会让一份本来正确的示例无法编译。为了让学生稳定复现,本课锁定 Minecraft Java 1.21.1 与 JDK 21,并使用 Fabric 官方示例工程当前为 1.21.1 分支给出的依赖组合。
| 组件 | 本课版本 | 负责什么 | 检查位置 |
|---|---|---|---|
| Minecraft Java | 1.21.1 | 目标游戏版本 | gradle.properties |
| JDK | 21 | 编译和运行 Java | java -version |
| Fabric Loader | 0.19.3 | 发现并加载模组 | loader_version |
| Fabric API | 0.116.15+1.21.1 | 事件、命令等开发接口 | fabric_api_version |
| Fabric Loom | 由模板给出 | Gradle 开发、映射、运行与打包插件 | loom_version |
| IntelliJ IDEA | Community 2025.x | 编辑、导航、Gradle 与调试 | Help → About |
开始之前请准备
- 一台可以运行 Minecraft Java Edition 的 Windows 电脑,以及你有权使用的正版游戏账号。
- 至少 8 GB 内存;第一次 Gradle 同步需要联网下载依赖,速度取决于网络。
- JDK 21。注意 JRE 只能“运行”,JDK 才包含
javac等开发工具。 - IntelliJ IDEA Community Edition。它足够完成 Fabric Java 开发,不需要购买 Ultimate。
- 一个纯英文、无空格、非 OneDrive 的工程路径,例如
C:\Projects\teacherma-fabric-intro。
Mental model · Fabric 到底是什么
它不是一个“做模组按钮”,而是一条可组合的 Java 工具链。
Fabric Loader 是加载器:启动游戏时读取每个模组的 fabric.mod.json,检查 ID、依赖和入口类,再调用你的代码。Fabric API 是常用开发接口集合:提供命令注册、事件、物品组、网络通信等更稳定的接入点。Fabric Loom 是 Gradle 插件:帮你下载游戏与映射、生成运行配置、启动开发客户端、重映射并构建 JAR。IntelliJ IDEA 则是你写代码和调试的工作台。
模组不是修改原版 JAR
现代开发不会直接把文件塞进 Minecraft 的原始 JAR。你的模组是独立产物,由 Loader 在启动阶段发现和加载,升级、移除和定位冲突都更清楚。
注册是“把对象交给游戏”
写出一个 Java 对象还不代表游戏认识它。物品、方块、实体、命令等都需要在正确阶段注册,游戏才能通过唯一 ID 找到它们。
客户端与服务端是两套职责
渲染、按键和画面属于客户端;世界规则、物品发放和实体状态应由逻辑服务端决定。即使单人游戏,内部也有客户端与集成服务器。
Gradle 是可重复构建说明书
它记录依赖和任务,让老师与学生在不同电脑上执行同样的 runClient 和 build,而不是手工复制一堆不明来源的 JAR。
Setup · 安装与创建工程
先验证工具,再生成模板;不要在空文件夹里凭记忆手写 Gradle 配置。
确认 JDK 21,而不是只确认“装过 Java”
打开 PowerShell,分别运行下面两条命令。第一条检查运行环境,第二条检查编译器。两者都应该显示 21。如果 javac 不存在,通常说明只装了 JRE,或系统 PATH 没有指向 JDK。
java -version
javac -version让 IntelliJ 的 Project SDK 与 Gradle JVM 都使用 JDK 21
进入 File → Project Structure → Project,把 SDK 设为 21;再进入 Settings → Build, Execution, Deployment → Build Tools → Gradle,把 Gradle JVM 也设为同一个 JDK 21。只改其中一处,仍可能出现“编辑器看起来正常,但构建失败”的情况。
21,Language level 同样保持 21。
Project SDK 21。从 Fabric Template Mod Generator 生成工程
打开官方生成器,填写:Mod Name 为 TeacherMa Fabric Intro,Mod ID 为 teacherma_fabric_intro,Package Name 为 dev.teacherma.fabricintro,Minecraft Version 选择 1.21.1,语言保持 Java。本课建议保留“拆分 client 与 main 源集”,它能更早发现把客户端类写到服务端代码里的错误。
解压到简单路径,并在 IntelliJ 中打开“工程根目录”
推荐路径是 C:\Projects\teacherma-fabric-intro。选择 File → Open 后,应打开包含 build.gradle、gradlew.bat 和 src 的那一层文件夹,不要只打开 src。看到 Gradle 构建脚本提示时选择导入,并等待索引和依赖下载结束。
src、build.gradle、gradlew.bat 和 settings.gradle;External Libraries 中显示 JDK 21。用课程 Starter 工程快速对照
如果你想先跑通再逐项比较,可以下载本课已经验证过的工程。它保留官方 Gradle Wrapper 和版本组合,并加入最终的命令代码。把它放在独立文件夹中打开,不要覆盖你自己的练习工程。
Project map · 看懂工程结构
能说出这些文件的职责,才算真正“打开了项目”。
teacherma-fabric-intro/
├─ gradle/ # Gradle Wrapper 运行文件
├─ src/
│ ├─ main/
│ │ ├─ java/
│ │ │ └─ dev/teacherma/fabricintro/
│ │ │ └─ FabricIntroMod.java # 通用/服务端入口逻辑
│ │ └─ resources/
│ │ └─ fabric.mod.json # 模组说明书
│ └─ client/ # 仅客户端代码与资源
├─ build.gradle # 插件、依赖与构建规则
├─ gradle.properties # Minecraft/Fabric 版本
├─ settings.gradle # 工程名称与插件仓库
└─ gradlew.bat # Windows 下执行 Gradlefabric.mod.json:Loader 先读的模组说明书
这里的 id 是整个模组的命名空间,必须使用小写字母、数字和下划线等安全字符;它也会出现在物品 ID、资源路径和日志中。entrypoints.main 必须与 Java 类的完整包名完全一致,任何一个字母不一致都会导致入口类找不到。depends 则声明最低 Loader 版本、目标 Minecraft、Java 和 Fabric API。
{
"schemaVersion": 1,
"id": "teacherma_fabric_intro",
"name": "TeacherMa Fabric Intro",
"environment": "*",
"entrypoints": {
"main": ["dev.teacherma.fabricintro.FabricIntroMod"]
},
"depends": {
"fabricloader": ">=0.19.3",
"minecraft": "~1.21.1",
"java": ">=21",
"fabric-api": "*"
}
}gradle.properties:版本要成套出现
版本不是越新越好,而是要彼此兼容。Minecraft 版本决定你面对哪一套游戏代码;Loader 负责加载;Fabric API 必须带有适配目标游戏的后缀。Loom 版本由同一模板生成器给出。升级时不要只把 minecraft_version 改成新数字,然后期待所有依赖自动兼容。
Code · 编写第一个可见功能
注册一个命令,让 Java 代码在服务端真正改变玩家状态。
我们选择命令作为第一项功能,因为它同时展示入口生命周期、Fabric API 事件、命令树、执行上下文、服务端玩家对象和游戏物品对象,又不需要先处理贴图、模型与语言文件。输入 /hello_fabric 后,命令在逻辑服务端执行,向当前玩家物品栏加入一颗绿宝石,并发送一条成功消息。
package dev.teacherma.fabricintro;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
import net.minecraft.commands.Commands;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class FabricIntroMod implements ModInitializer {
public static final String MOD_ID = "teacherma_fabric_intro";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) ->
dispatcher.register(Commands.literal("hello_fabric")
.executes(context -> {
var player = context.getSource().getPlayerOrException();
player.addItem(new ItemStack(Items.EMERALD));
context.getSource().sendSuccess(
() -> Component.literal("Hello Fabric! Java 已经改变了游戏世界。"),
false
);
return 1;
}))
);
LOGGER.info("TeacherMa Fabric Intro loaded successfully.");
}
}1. implements ModInitializer
这个接口说明该类是通用入口。Loader 准备好模组初始化阶段后,会调用 onInitialize()。这里适合注册命令、物品、方块和事件。
2. 注册回调,而不是立即执行
CommandRegistrationCallback.EVENT.register 的意思是“命令系统准备注册时,请调用这段逻辑”。页面加载时不会立刻给玩家绿宝石。
3. context 提供执行现场
命令可能由玩家、服务器控制台或命令方块执行。getPlayerOrException() 明确要求这次执行者必须是玩家,随后拿到服务端玩家对象。
4. 返回值 1 表示成功
Minecraft 命令系统使用整数结果表示执行状态。这里返回 1,便于命令方块、函数和后续自动化判断该命令已经成功完成。
net.minecraft.commands.Commands 和 Component。旧教程使用 Yarn 映射时可能写成 CommandManager 和 Text。概念相同,但类名不能混用。Run & verify · 运行与验收
第一次启动慢是正常的;“能进游戏”之后还要做四项验证。
在 IntelliJ 右侧打开 Gradle 工具窗口,找到 Fabric 相关运行任务并执行 runClient。也可以在工程根目录打开 PowerShell,使用 Wrapper 启动。Wrapper 会确保项目使用规定的 Gradle 版本,不要求学生全局安装 Gradle。
teacherma-fabric-intro → Tasks → fabric,双击 runClient。第一次启动需要下载并准备游戏资源,等待控制台完成即可。./gradlew.bat runClient检查 1:日志
控制台中搜索 TeacherMa Fabric Intro loaded successfully。出现它说明 Loader 找到了入口并执行了初始化。
检查 2:Mods 列表
开发客户端启动后,确认模组名称与版本存在。若完全找不到,优先检查 fabric.mod.json 的 ID 与 entrypoint。
检查 3:命令建议
进入世界,在聊天框输入 /hello。自动补全应出现 /hello_fabric,这说明命令已经进入调度树。
检查 4:游戏结果
执行命令,看到中文消息,并确认物品栏增加一颗绿宝石。多执行几次,应该每次都增加一颗。
检查 5:只改一处
把绿宝石改成 Items.DIAMOND,重新启动并验证。一次只改一个变量,能建立代码与结果的对应关系。
检查 6:读日志首错
如果失败,从日志中第一条包含 ERROR 或 Caused by 的位置开始,不要只截最后一屏重复堆栈。
runClient 使用工程下的开发运行目录,不会自动把模组安装到你平时启动器的 .minecraft。这样测试更安全,也不会污染常用世界。Debug clinic · 常见错误
先判断错误发生在哪一层,再决定该改设置、依赖还是 Java。
错误:Unsupported class file major version / invalid source release
原因:Gradle JVM、Project SDK 或系统 Java 不是项目要求的 JDK 21。处理:重新运行 java -version 和 javac -version,再检查 IntelliJ 的 Project SDK 与 Gradle JVM。改完后重新加载 Gradle 项目。
错误:Could not resolve / Read timed out / 下载依赖失败
原因:第一次构建需要访问 Fabric Maven、Maven Central 与游戏依赖服务器,网络中断或代理设置可能导致失败。处理:先确认浏览器能访问 Fabric 官网;不要反复删除源码。网络恢复后,在 Gradle 工具窗口重新加载,或执行 ./gradlew.bat --refresh-dependencies build。
错误:Could not find or load main class / entrypoint 找不到
原因:fabric.mod.json 中的完整类名与 Java 文件顶部的 package 不一致。处理:核对 dev.teacherma.fabricintro.FabricIntroMod 的每一段,并确认文件位于对应目录。包名使用全小写,类名保持大小写。
错误:Mod resolution encountered an incompatible mod set
原因:Minecraft、Loader、Fabric API 或 Java 版本不满足 depends。处理:阅读错误中列出的“requires”与当前版本,不要随便删除依赖声明。回到生成器为同一个 Minecraft 版本重新生成,通常比猜版本更可靠。
可以进游戏,但没有 /hello_fabric
先在日志里找入口成功信息。如果没有,检查 fabric.mod.json;如果有,确认代码保存且 Gradle 重新编译。还要确认你启动的是这个工程的 runClient,不是桌面上的普通 Minecraft Launcher。
代码中的类名与网上教程不同
这通常不是“Fabric 坏了”,而是映射体系或游戏版本不同。旧 Yarn 教程和当前 Mojang 官方映射会给同一概念不同名字。选择一套模板与文档后保持一致,不要从多个版本各复制一半。
用 IntelliJ 断点观察命令执行
点击 var player = ... 左侧行号添加红色断点,然后以 Debug 模式启动客户端。进入世界执行命令时,程序会暂停。此时在 Variables 窗口查看 context、player 与玩家物品栏。按 F8 单步执行,你会亲眼看到“取得玩家 → 添加物品 → 发送消息 → 返回 1”的顺序。这比背 API 更能建立程序执行模型。
var player = ... 这一行,再用顶部的 Debug 按钮启动;命令真正执行到这里时程序才会暂停。Build & install · 构建并安装
开发环境里能运行,最后还要变成普通启动器可以加载的 JAR。
关闭开发客户端,在工程根目录执行构建。Gradle 会编译 Java、处理资源、重映射名称并生成可发布文件。构建成功后打开 build/libs,选择文件名最短、且不包含 sources 的 JAR;sources 包是给开发者阅读源码用的,不是普通玩家安装包。
./gradlew.bat clean build
build → libs。安装 teacherma-fabric-intro-1.0.0.jar;带 -sources 的文件只用于阅读源码。备份世界
安装任何新模组前都先备份重要世界。开发版模组可能写入实体、物品或存档数据,移除后未必能恢复。
安装匹配版本的 Fabric Loader
从 Fabric 官方 Installer 页面下载工具,选择 Minecraft 1.21.1、对应 Loader 与正确游戏目录,创建 Fabric 启动配置。不要使用第三方转载的未知安装器。
准备 mods 文件夹
Windows 默认目录通常是 %appdata%\.minecraft\mods。把 Fabric API 的 1.21.1 JAR 与你构建的模组 JAR 一起放进去;同一模组只保留一个版本。
从 Fabric 配置启动
在官方启动器选择刚创建的 Fabric 1.21.1 配置。进入游戏后检查 Mods 信息和日志,再用测试世界执行命令。不要直接在唯一的生存主世界上做首次验证。
Practice · 练习与自测
把“看懂”变成“能独立改动”:完成三个难度递增的小任务。
换奖励
把 Items.EMERALD 改成 Items.DIAMOND,把消息改成自己的课程口号。预测结果后再运行。
增加数量
研究 new ItemStack(Items.EMERALD, 3) 的第二个参数,让一次命令给予三颗绿宝石,并解释构造函数参数。
增加第二个命令
复制注册结构,创建 /fabric_level,只发送“我已经完成第一课”,但不发放物品。避免把两个命令嵌套在一起。
五分钟自测
1. Fabric Loader 与 Fabric API 的区别是什么?
Loader 负责发现模组、检查依赖并调用入口;Fabric API 是模组可选或必需依赖的接口集合,提供事件、命令、注册辅助等功能。只有 API 而没有 Loader,模组不会被正常加载。
2. 为什么本课同时检查 Project SDK 和 Gradle JVM?
编辑器分析代码使用 Project SDK,而 Gradle 构建可能使用另一套 JVM。两者不一致时会出现编辑器无红线、构建却报 Java 版本错误的情况。
3. fabric.mod.json 的 entrypoint 写错会发生什么?
Loader 能读到模组描述,但无法找到并实例化指定入口类,onInitialize() 不会执行,命令也不会注册。日志通常会明确指出入口加载失败。
4. 为什么发放物品的代码应该在逻辑服务端执行?
物品栏和世界状态由服务端作为权威来源。只在客户端修改会造成画面暂时变化、随后被服务端纠正,甚至引发不同步。单人游戏内部同样存在集成服务器。
5. 怎样找到正确的发布 JAR?
执行 build 后查看 build/libs,通常选择文件名最短且不含 sources 的 JAR。安装前还要确认目标 Minecraft、Loader、Fabric API 和 Java 版本匹配。
术语卡
| 术语 | 一句话解释 |
|---|---|
| Mod ID | 模组在代码和资源中的唯一命名空间,例如 teacherma_fabric_intro。 |
| Entrypoint | Loader 在指定生命周期阶段调用的 Java 类。 |
| Registry | 游戏保存可识别对象与唯一 ID 对应关系的注册系统。 |
| Mapping | 把混淆后的游戏成员映射成开发者可阅读类名和方法名的命名体系。 |
| Dependency | 当前项目编译或运行所依赖的外部组件,例如 Fabric API。 |
| Logical Server | 负责世界规则和权威状态的一侧,单人游戏里也存在。 |
Official references · 官方资料
课程内容以官方模板与文档为基线。
Fabric 发展很快。课程讲清的是稳定原理;具体版本号与类名应在升级时重新核对。建议收藏以下官方入口:
- Fabric Template Mod Generator:生成与目标版本匹配的工程。
- Creating a Project:包名、工程路径与 IntelliJ 导入说明。
- Project Structure:入口、资源目录与
fabric.mod.json。 - Building a Mod:Gradle 构建与 JAR 选择。
- Fabric Example Mod 1.21.1:本课 Starter 的 CC0 官方模板来源。
Lesson complete
你已经跨过最关键的一步:让自己的 Java 逻辑进入了游戏。
下一阶段可以开始学习注册第一个自定义物品:建立唯一 ID、物品类、创造模式分组、语言文本、模型 JSON 和 16×16 贴图。请先保存本课工程的可运行版本,再复制出新分支做实验;一个始终能运行的基线,是专业开发习惯的一部分。