22 第一个 Forge 模组¶
本章目标¶
- 掌握模组主类与 @Mod
- 掌握 mods.toml / mcmod.toml
- 写一个能进游戏的功能模组
- 理解"注册"的概念
前置:已完成 21 Gradle 入门(MDK 导入 IDEA、runClient 能启动)。
22.1 模组基本结构¶
一个 Forge 模组最少包含:
src/main/java/com/ffs/ffsmod/
└── FfsMod.java # 模组主类
src/main/resources/
├── META-INF/mods.toml # 模组元数据(必填)
├── pack.mcmeta # 资源包信息(必填)
└── assets/ffsmod/ # 贴图、模型、语言文件
22.2 mods.toml:模组身份证¶
modLoader = "javafml"
loaderVersion = "[47,)"
license = "All Rights Reserved"
[[mods]]
modId = "ffsmod" # 模组 ID(唯一标识,对应 @Mod)
version = "1.0.0"
displayName = "FFS Mod"
authors = "pyz"
description = '''我的第一个 Forge 模组'''
modId 规则
小写字母、数字、下划线,不能有空格。全工程保持一致(@Mod 注解、资源目录名、物品注册名都用它)。
22.3 pack.mcmeta¶
{
"pack": {
"description": "FFS Mod resources",
"pack_format": 15
}
}
22.4 模组主类¶
package com.ffs.ffsmod;
import net.minecraftforge.fml.common.Mod;
@Mod(FfsMod.MODID) // 声明这是模组主类,注册到 Forge
public class FfsMod {
public static final String MODID = "ffsmod";
public FfsMod() { // 构造器:模组加载时执行
System.out.println("[FFSMod] 模组加载中!");
}
}
运行 ./gradlew runClient,启动日志里能看到 [FFSMod] 模组加载中!——你的第一个模组就活了!🎉
22.5 加个事件:欢迎玩家¶
在 FfsMod.java 旁边建 ModEvents.java:
package com.ffs.ffsmod;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Player;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
@Mod.EventBusSubscriber(modid = FfsMod.MODID) // 自动注册到事件总线
public class ModEvents {
@SubscribeEvent // 订阅"玩家登录"事件
public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
Player player = event.getEntity();
player.sendSystemMessage(Component.literal("§6欢迎 " + player.getName().getString() + " 加入!"));
}
}
看到熟悉的模式了吗?
@Mod.EventBusSubscriber + @SubscribeEvent 就是第 20 章讲的观察者模式,Component.literal 是 Builder 模式。前面学的 Java 全用上了。
22.6 注册你的第一个物品¶
模组要添加新内容(物品/方块/实体),必须注册到 Forge 的注册表。这是模组开发的核心动作。
package com.ffs.ffsmod;
import net.minecraft.world.item.Item;
import net.minecraftforge.registries.DeferredRegister;
import net.minecraftforge.registries.ForgeRegistries;
import net.minecraftforge.registries.RegistryObject;
import net.minecraftforge.eventbus.api.IEventBus;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
@Mod(FfsMod.MODID)
public class FfsMod {
public static final String MODID = "ffsmod";
// DeferredRegister:延迟注册器(推荐的标准注册方式)
public static final DeferredRegister<Item> ITEMS =
DeferredRegister.create(ForgeRegistries.ITEMS, MODID);
// 注册一个物品:ID 是 ffsmod:magic_ingot
public static final RegistryObject<Item> MAGIC_INGOT =
ITEMS.register("magic_ingot", () -> new Item(new Item.Properties()));
public FfsMod() {
// 把注册器挂到模组事件总线
ITEMS.register(FMLJavaModLoadingContext.get().getModEventBus());
System.out.println("[FFSMod] 模组加载中!");
}
}
注册三件套
DeferredRegister.create(注册表类型, modid)创建注册器ITEMS.register("id", () -> new ...)注册内容- 构造器里
ITEMS.register(modEventBus)挂到总线
22.7 给物品加贴图(最小实现)¶
- 创建语言文件
src/main/resources/assets/ffsmod/lang/zh_cn.json:
{
"item.ffsmod.magic_ingot": "魔法锭"
}
-
放一张贴图
assets/ffsmod/textures/item/magic_ingot.png(16×16 像素) -
创建模型文件
assets/ffsmod/models/item/magic_ingot.json:
{
"parent": "item/generated",
"textures": {
"layer0": "ffsmod:item/magic_ingot"
}
}
重新 runClient,输入 /give @s ffsmod:magic_ingot,就能拿到中文名"魔法锭"的黄色物品了!
22.8 理解注册表(Registry)¶
Minecraft 用注册表管理所有内容:
Registries.ITEM 物品
Registries.BLOCK 方块
Registries.ENTITY_TYPE 实体
Registries.SOUND_EVENT 音效
Registries.MENU 界面
...
注册 = 把"ID → 实例"登记进注册表。之后游戏里 ffsmod:magic_ingot 就指向你的物品。所有模组内容都必须注册,这是和普通 Java 程序最大的区别。
22.9 小练习¶
- 注册第二个物品
ffs_stick(普通物品) - 订阅
PlayerEvent.PlayerLoggedOutEvent(退出登录),打印日志 - 给魔法锭写英文语言文件 en_us.json
- 改 mods.toml 的 description 和 version,重新 build 出 jar,扔进 mods 文件夹测试(发个群友测试!)
本章小结¶
- 主类加 @Mod,mods.toml 是元数据
- @SubscribeEvent 订阅事件(观察者模式)
- DeferredRegister 注册物品/方块
- 贴图 = lang 文件 + 贴图 + 模型文件
- 所有模组内容都要注册进注册表