跳转至

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] 模组加载中!");
    }
}

注册三件套

  1. DeferredRegister.create(注册表类型, modid) 创建注册器
  2. ITEMS.register("id", () -> new ...) 注册内容
  3. 构造器里 ITEMS.register(modEventBus) 挂到总线

22.7 给物品加贴图(最小实现)

  1. 创建语言文件 src/main/resources/assets/ffsmod/lang/zh_cn.json:
{
  "item.ffsmod.magic_ingot": "魔法锭"
}
  1. 放一张贴图 assets/ffsmod/textures/item/magic_ingot.png(16×16 像素)

  2. 创建模型文件 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 小练习

  1. 注册第二个物品 ffs_stick(普通物品)
  2. 订阅 PlayerEvent.PlayerLoggedOutEvent(退出登录),打印日志
  3. 给魔法锭写英文语言文件 en_us.json
  4. 改 mods.toml 的 description 和 version,重新 build 出 jar,扔进 mods 文件夹测试(发个群友测试!)

本章小结

  • 主类加 @Mod,mods.toml 是元数据
  • @SubscribeEvent 订阅事件(观察者模式)
  • DeferredRegister 注册物品/方块
  • 贴图 = lang 文件 + 贴图 + 模型文件
  • 所有模组内容都要注册进注册表

下一章:23 Forge 核心机制与 Java 对照

🏠 返回总站