Appearance
简单实现 1.12.2 Forge 模组
更新: 7/4/2026 字数: 0 字 时长: 0 分钟
本方案实现一个 modid 为 demometal 的模组,包含:蓝金属锭、蓝金属矿石方块、整套盔甲、一把剑,并让矿石在主世界自然生成。
一、开发环境要求(1.12.2 专用,版本必须对齐)

| 项目 | 要求 | 说明 |
|---|---|---|
| JDK | JDK 8(如 1.8.0_202、Adoptium 8u4xx) | 1.12.2 必须用 JDK 8。用 JDK 9+ 会导致 ForgeGradle 2.3 构建失败,这是最常见的翻车点 |
| Forge MDK | 1.12.2 - 14.23.5.28xx(推荐 14.23.5.2860 稳定版) | 从 files.minecraftforge.net 选 1.12.2 的 Mdk 下载 |
| Gradle | 用 MDK 自带的 gradlew(内含 ForgeGradle 2.3) | 不要自己装高版本 Gradle,用项目自带包装器最稳 |
| IDE | IntelliJ IDEA 或 Eclipse | 均可,下面以通用命令为准 |
环境初始化命令(在 MDK 解压目录执行):
bash
# 生成 IDE 工程 + 反混淆运行环境(首次较慢,需联网下载依赖)
./gradlew setupDecompWorkspace
./gradlew genIntellijRuns # 若用 Eclipse 则执行 ./gradlew eclipse修改根目录 build.gradle 的版本区段(关键,决定编译目标):
groovy
version = "1.0.0"
group = "com.example.demometal"
archivesBaseName = "demometal"
minecraft {
version = "1.12.2-14.23.5.2860" // 对齐你下载的 Forge 版本
runDir = "run"
// 1.12.2 官方混淆映射,snapshot 版本按 MDK 默认即可
mappings = "snapshot_20171003"
}二、项目结构与模组主类

2.1 完整目录结构
src/main/
├── java/com/example/demometal/
│ ├── DemoMetal.java # 模组主类(@Mod 入口)
│ ├── ModItems.java # 物品:锭、剑、盔甲
│ ├── ModBlocks.java # 方块:矿石
│ ├── ModMaterials.java # 自定义工具/盔甲材质
│ ├── RegistryHandler.java # 统一注册事件处理
│ └── world/OreGenerator.java # 矿石世界生成
└── resources/
├── mcmod.info # 模组描述(1.12.2 用这个)
└── assets/demometal/
├── lang/en_us.lang
├── lang/zh_cn.lang
├── models/item/*.json # 物品模型
├── models/block/*.json # 方块模型
├── blockstates/*.json # 方块状态
└── textures/... # 纹理占位2.2 模组主类 DemoMetal.java
java
package com.example.demometal;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.Mod.EventHandler;
import net.minecraftforge.fml.common.event.FMLInitializationEvent;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraft.creativetab.CreativeTabs;
import net.minecraft.item.ItemStack;
// @Mod 是模组的身份声明,modid 全局唯一且必须全小写,Forge 靠它识别模组
@Mod(modid = DemoMetal.MODID, name = DemoMetal.NAME, version = DemoMetal.VERSION,
acceptedMinecraftVersions = "[1.12.2]")
public class DemoMetal {
public static final String MODID = "demometal"; // 唯一标识,资源路径也用它
public static final String NAME = "Demo Metal Mod";
public static final String VERSION = "1.0.0";
// 单例,方便别处引用
@Mod.Instance(MODID)
public static DemoMetal instance;
// 自定义创造模式物品栏分页,让新内容集中显示
public static final CreativeTabs DEMO_TAB = new CreativeTabs("demometal_tab") {
@Override
public ItemStack getTabIconItem() {
// 用金属锭作为标签页图标(ModItems.INGOT 在注册后可用)
return new ItemStack(ModItems.INGOT);
}
};
// 预初始化阶段:适合做世界生成注册等早期工作
@EventHandler
public void preInit(FMLPreInitializationEvent event) {
OreGeneratorRegister.register(); // 注册矿石生成器(见第四节)
}
// 初始化阶段:可放合成表等(本 Demo 不额外加合成,保持精简)
@EventHandler
public void init(FMLInitializationEvent event) {
}
}说明:
OreGeneratorRegister.register()是第四节的世界生成注册入口,为清晰起见单独成类,你也可以直接内联。
三、注册逻辑:材质、物品、方块与注册事件

1.12.2 的核心注册规范(务必遵守,否则物品不显示):
- 物品/方块不能在主类里 new 完就完事,必须在
RegistryEvent.Register<T>事件里注册; - 每个对象必须设
setRegistryName(modid, name),且要和setUnlocalizedName对应; - 物品模型(Model)必须在客户端
ModelRegistryEvent里用ModelLoader.setCustomModelResourceLocation注册——这是 1.12.2 物品显示为"黑紫块"的头号原因。
3.1 自定义材质 ModMaterials.java
java
package com.example.demometal;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor.ArmorMaterial;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.SoundEvents;
import net.minecraftforge.common.util.EnumHelper;
public class ModMaterials {
// 自定义工具材质:名称、挖掘等级、耐久、挖掘速度、攻击加成、附魔能力
public static final Item.ToolMaterial TOOL_DEMO = EnumHelper.addToolMaterial(
"demometal_tool", 3, 1200, 8.0F, 3.5F, 14);
// 自定义盔甲材质:名称、贴图前缀、耐久系数、各部位护甲值{脚,腿,胸,头}、
// 附魔能力、装备音效、韧性
public static final ArmorMaterial ARMOR_DEMO = EnumHelper.addArmorMaterial(
"demometal_armor", // 内部名
DemoMetal.MODID + ":demometal", // 盔甲贴图前缀 -> textures/models/armor/demometal_layer_1/2.png
18, // 耐久系数
new int[]{2, 6, 7, 3}, // 护甲值:靴、腿、胸、头
14, // 附魔能力
SoundEvents.ITEM_ARMOR_EQUIP_IRON, // 装备音效(复用铁)
2.0F); // 护甲韧性
}3.2 物品 ModItems.java(锭、剑、盔甲)
java
package com.example.demometal;
import net.minecraft.inventory.EntityEquipmentSlot;
import net.minecraft.item.Item;
import net.minecraft.item.ItemArmor;
import net.minecraft.item.ItemSword;
import net.minecraftforge.fml.common.registry.GameRegistry;
public class ModItems {
// @ObjectHolder 会在注册完成后自动把实例回填到这些字段,供别处安全引用
@GameRegistry.ObjectHolder(DemoMetal.MODID + ":demo_ingot")
public static Item INGOT;
// 金属锭:普通物品
public static final Item DEMO_INGOT = new Item()
.setUnlocalizedName(DemoMetal.MODID + ".demo_ingot") // 语言键
.setRegistryName(DemoMetal.MODID, "demo_ingot") // 注册名
.setCreativeTab(DemoMetal.DEMO_TAB); // 归入自定义标签页
// 金属剑:用自定义工具材质
public static final Item DEMO_SWORD = new ItemSword(ModMaterials.TOOL_DEMO)
.setUnlocalizedName(DemoMetal.MODID + ".demo_sword")
.setRegistryName(DemoMetal.MODID, "demo_sword")
.setCreativeTab(DemoMetal.DEMO_TAB);
// 四件盔甲:注意第二参数指定材质,第三参数是渲染索引,第四参数是部位
public static final Item DEMO_HELMET = new ItemArmor(
ModMaterials.ARMOR_DEMO, 1, EntityEquipmentSlot.HEAD)
.setUnlocalizedName(DemoMetal.MODID + ".demo_helmet")
.setRegistryName(DemoMetal.MODID, "demo_helmet")
.setCreativeTab(DemoMetal.DEMO_TAB);
public static final Item DEMO_CHESTPLATE = new ItemArmor(
ModMaterials.ARMOR_DEMO, 1, EntityEquipmentSlot.CHEST)
.setUnlocalizedName(DemoMetal.MODID + ".demo_chestplate")
.setRegistryName(DemoMetal.MODID, "demo_chestplate")
.setCreativeTab(DemoMetal.DEMO_TAB);
public static final Item DEMO_LEGGINGS = new ItemArmor(
ModMaterials.ARMOR_DEMO, 2, EntityEquipmentSlot.LEGS) // 腿部渲染索引为2
.setUnlocalizedName(DemoMetal.MODID + ".demo_leggings")
.setRegistryName(DemoMetal.MODID, "demo_leggings")
.setCreativeTab(DemoMetal.DEMO_TAB);
public static final Item DEMO_BOOTS = new ItemArmor(
ModMaterials.ARMOR_DEMO, 1, EntityEquipmentSlot.FEET)
.setUnlocalizedName(DemoMetal.MODID + ".demo_boots")
.setRegistryName(DemoMetal.MODID, "demo_boots")
.setCreativeTab(DemoMetal.DEMO_TAB);
}3.3 方块 ModBlocks.java(矿石)
java
package com.example.demometal;
import net.minecraft.block.Block;
import net.minecraft.block.material.Material;
import net.minecraft.block.SoundType;
public class ModBlocks {
// 矿石方块:石质材料、需镐挖掘
public static final Block DEMO_ORE = new Block(Material.ROCK)
.setUnlocalizedName(DemoMetal.MODID + ".demo_ore")
.setRegistryName(DemoMetal.MODID, "demo_ore")
.setHardness(3.0F) // 硬度(挖掘时间)
.setResistance(5.0F) // 抗爆炸
.setSoundType(SoundType.STONE)
.setCreativeTab(DemoMetal.DEMO_TAB);
static {
// 需要铁镐及以上才能挖出,等级2对应铁镐
DEMO_ORE.setHarvestLevel("pickaxe", 2);
}
}3.4 统一注册处理 RegistryHandler.java(核心中的核心)
java
package com.example.demometal;
import net.minecraft.block.Block;
import net.minecraft.item.Item;
import net.minecraft.item.ItemBlock;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraftforge.client.event.ModelRegistryEvent;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;
// @Mod.EventBusSubscriber 自动把本类注册到事件总线,无需手动 register
@Mod.EventBusSubscriber(modid = DemoMetal.MODID)
public class RegistryHandler {
// === 注册所有物品(含盔甲、剑、锭) ===
@SubscribeEvent
public static void registerItems(RegistryEvent.Register<Item> event) {
event.getRegistry().registerAll(
ModItems.DEMO_INGOT,
ModItems.DEMO_SWORD,
ModItems.DEMO_HELMET,
ModItems.DEMO_CHESTPLATE,
ModItems.DEMO_LEGGINGS,
ModItems.DEMO_BOOTS
);
// 方块必须同时注册它的 ItemBlock,否则物品栏里拿不到、也无法放置
event.getRegistry().register(
new ItemBlock(ModBlocks.DEMO_ORE)
.setRegistryName(ModBlocks.DEMO_ORE.getRegistryName())
);
}
// === 注册所有方块 ===
@SubscribeEvent
public static void registerBlocks(RegistryEvent.Register<Block> event) {
event.getRegistry().register(ModBlocks.DEMO_ORE);
}
// === 注册模型(仅客户端):1.12.2 物品显示的关键,缺了就是黑紫块 ===
@SubscribeEvent
@SideOnly(Side.CLIENT)
public static void registerModels(ModelRegistryEvent event) {
// 物品模型
reg(ModItems.DEMO_INGOT);
reg(ModItems.DEMO_SWORD);
reg(ModItems.DEMO_HELMET);
reg(ModItems.DEMO_CHESTPLATE);
reg(ModItems.DEMO_LEGGINGS);
reg(ModItems.DEMO_BOOTS);
// 方块的物品模型
regBlock(ModBlocks.DEMO_ORE);
}
// 把物品与其 json 模型绑定(inventory 变体)
@SideOnly(Side.CLIENT)
private static void reg(Item item) {
ModelLoader.setCustomModelResourceLocation(item, 0,
new ModelResourceLocation(item.getRegistryName(), "inventory"));
}
@SideOnly(Side.CLIENT)
private static void regBlock(Block block) {
Item item = Item.getItemFromBlock(block);
ModelLoader.setCustomModelResourceLocation(item, 0,
new ModelResourceLocation(block.getRegistryName(), "inventory"));
}
}四、矿石世界生成配置

1.12.2 世界生成靠实现 IWorldGenerator 接口,再用 GameRegistry.registerWorldGenerator 注册。
4.1 OreGenerator.java
java
package com.example.demometal.world;
import com.example.demometal.ModBlocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraft.world.chunk.IChunkProvider;
import net.minecraft.world.gen.IChunkGenerator;
import net.minecraft.world.gen.feature.WorldGenMinable;
import net.minecraft.init.Blocks;
import net.minecraftforge.fml.common.IWorldGenerator;
import net.minecraft.block.state.pattern.BlockMatcher;
import java.util.Random;
public class OreGenerator implements IWorldGenerator {
// WorldGenMinable:矿脉生成器,参数=生成的方块状态、每簇矿石数量、替换目标
private final WorldGenMinable oreGen = new WorldGenMinable(
ModBlocks.DEMO_ORE.getDefaultState(), 6, // 每簇最多6个
BlockMatcher.forBlock(Blocks.STONE)); // 只在石头里生成
@Override
public void generate(Random random, int chunkX, int chunkZ, World world,
IChunkGenerator chunkGenerator, IChunkProvider chunkProvider) {
// dimension 0 = 主世界,只在主世界生成
if (world.provider.getDimension() == 0) {
runGenerator(world, random, chunkX, chunkZ,
8, // 每区块尝试生成次数(矿脉数)
5, // 最低高度 Y
45); // 最高高度 Y
}
}
private void runGenerator(World world, Random rand, int chunkX, int chunkZ,
int chancesPerChunk, int minY, int maxY) {
for (int i = 0; i < chancesPerChunk; i++) {
// 在当前区块内随机取坐标(*16 转成方块坐标,+8 居中避免跨区块接缝)
int x = chunkX * 16 + rand.nextInt(16);
int y = minY + rand.nextInt(maxY - minY);
int z = chunkZ * 16 + rand.nextInt(16);
oreGen.generate(world, rand, new BlockPos(x, y, z));
}
}
}4.2 注册入口(配合主类 preInit 调用)
在 com.example.demometal 包下新建 OreGeneratorRegister.java:
java
package com.example.demometal;
import com.example.demometal.world.OreGenerator;
import net.minecraftforge.fml.common.registry.GameRegistry;
public class OreGeneratorRegister {
public static void register() {
// 第二个参数是生成权重,数字越大越晚生成(越靠上层覆盖)
GameRegistry.registerWorldGenerator(new OreGenerator(), 3);
}
}五、资源文件:目录结构与核心内容

1.12.2 资源路径全部小写,assets/demometal/ 下按类型分目录。
5.1 mcmod.info(模组描述,放 resources 根目录)
json
[
{
"modid": "demometal",
"name": "Demo Metal Mod",
"description": "一个简易的自定义金属模组:锭、矿石、盔甲、剑。",
"version": "1.0.0",
"mcversion": "1.12.2",
"authorList": ["YourName"]
}
]5.2 语言文件
assets/demometal/lang/zh_cn.lang:
properties
itemGroup.demometal_tab=演示金属
item.demometal.demo_ingot.name=蓝金属锭
item.demometal.demo_sword.name=蓝金属剑
item.demometal.demo_helmet.name=蓝金属头盔
item.demometal.demo_chestplate.name=蓝金属胸甲
item.demometal.demo_leggings.name=蓝金属护腿
item.demometal.demo_boots.name=蓝金属靴子
tile.demometal.demo_ore.name=蓝金属矿石assets/demometal/lang/en_us.lang:
properties
itemGroup.demometal_tab=Demo Metal
item.demometal.demo_ingot.name=Blue Metal Ingot
item.demometal.demo_sword.name=Blue Metal Sword
item.demometal.demo_helmet.name=Blue Metal Helmet
item.demometal.demo_chestplate.name=Blue Metal Chestplate
item.demometal.demo_leggings.name=Blue Metal Leggings
item.demometal.demo_boots.name=Blue Metal Boots
tile.demometal.demo_ore.name=Blue Metal Ore5.3 物品模型 JSON(assets/demometal/models/item/)
锭/剑/盔甲都用标准平面物品模型。以 demo_ingot.json 为例(其余把 layer0 后缀换成对应物品名即可):
json
{
"parent": "item/generated",
"textures": {
"layer0": "demometal:items/demo_ingot"
}
}需要创建的物品模型文件清单(内容同上,仅改 texture 名): demo_ingot.json、demo_sword.json、demo_helmet.json、demo_chestplate.json、demo_leggings.json、demo_boots.json。
5.4 方块相关 JSON
assets/demometal/blockstates/demo_ore.json:
json
{
"variants": {
"normal": { "model": "demometal:demo_ore" }
}
}assets/demometal/models/block/demo_ore.json:
json
{
"parent": "block/cube_all",
"textures": {
"all": "demometal:blocks/demo_ore"
}
}assets/demometal/models/item/demo_ore.json(方块在物品栏的样子):
json
{
"parent": "demometal:block/demo_ore"
}5.5 纹理占位说明(assets/demometal/textures/)
| 纹理路径 | 尺寸 | 用途 |
|---|---|---|
textures/items/demo_ingot.png | 16×16 | 锭图标 |
textures/items/demo_sword.png | 16×16 | 剑图标 |
textures/items/demo_helmet.png 等 4 个 | 16×16 | 盔甲物品图标 |
textures/blocks/demo_ore.png | 16×16 | 矿石方块贴图 |
textures/models/armor/demometal_layer_1.png | 64×32 | 盔甲穿身效果(头/胸/靴) |
textures/models/armor/demometal_layer_2.png | 64×32 | 盔甲穿身效果(腿部) |
占位做法:先随便放同尺寸的纯色 PNG 保证不报错,后期再替换成正式美术。盔甲穿身贴图的
layer_1/layer_2命名必须和ModMaterials里的贴图前缀demometal严格对应,否则穿上盔甲身体是隐形/紫黑。
六、打包步骤与常见报错排查

6.1 打包操作
bash
# 在项目根目录执行
./gradlew build构建成功后,成品 jar 位于:
build/libs/demometal-1.0.0.jar把这个 jar 放进 .minecraft/mods/ 文件夹(游戏必须是 1.12.2 + 对应 Forge),启动即可。
注意:
build/libs里若出现demometal-1.0.0-sources.jar,那是源码包,不要放进 mods,只放主 jar。
6.2 上线前自检清单(对照排查,避免遗漏)
| 检查项 | 确认点 |
|---|---|
| 注册名一致 | 每个 Item/Block 都调了 setRegistryName,且和模型 json 文件名完全一致 |
| 模型已注册 | ModelRegistryEvent 里每个物品都调了 setCustomModelResourceLocation |
| ItemBlock 已注册 | 矿石方块的 ItemBlock 在物品注册事件里注册了,否则物品栏拿不到 |
| 路径全小写 | assets/demometal/... 及所有 json/png 文件名全小写 |
| 语言键对应 | setUnlocalizedName 的值和 .lang 里的 key 严格对应 |
6.3 常见加载报错排查要点
游戏能进但物品是"黑紫方块 / MISSING TEXTURE" → 模型或纹理没对上。检查:
ModelRegistryEvent是否漏注册;models/item/*.json文件名是否等于注册名;textures路径是否写对(注意 json 里写demometal:items/xxx,实际文件在textures/items/xxx.png)。启动崩溃,日志报
Registry Object not found/Missing registry name→ 某个 Item/Block 忘了setRegistryName,或在事件外提前注册。所有注册必须走RegistryEvent.Register。启动崩溃,报 JDK / Gradle 相关错误 → 十有八九是用了 JDK 9+。改回 JDK 8,并确认
JAVA_HOME指向 JDK 8。物品栏找不到新内容 →
setCreativeTab没设,或设错标签页;确认物品确实注册成功(日志无报错)。矿石不生成 →
registerWorldGenerator没在preInit调用;或维度判断写错(主世界是getDimension() == 0);或高度区间 minY/maxY 设得不合理。注意已生成的旧区块不会补生成,需去新区块或新建世界验证。盔甲能拿到但穿上身体隐形 →
models/armor/下的demometal_layer_1.png/demometal_layer_2.png缺失或命名不符材质前缀。mods里 jar 完全不被识别 → 检查@Mod的modid是否全小写、acceptedMinecraftVersions是否为[1.12.2];确认放的是主 jar 不是 sources jar。
总结
按上述六步操作,最终你将得到一个 modid 为 demometal 的标准 1.12.2 Forge 模组,打包出的 demometal-1.0.0.jar 放入 mods 文件夹后可实现:
- ✅ 创造模式物品栏"演示金属"分页下可找到:蓝金属锭、剑、整套盔甲、矿石方块;
- ✅ 蓝金属矿石在主世界 Y=5~45 的石头层自然成簇生成,需铁镐及以上挖掘;
- ✅ 剑具备自定义攻击/耐久属性,盔甲穿戴后护甲值、韧性、附魔能力正常生效。