本篇教程的视频

本篇教程的源代码

GitHub地址:TutorialMod-1.21.1-NeoForge-Start

前言

同样的,我们就来一个简短的前言

本系列教程为NeoForge的长线教程计划,与同期开行的Forge长线教程计划一样,
不再像Fabric,通过讲解源代码来做教程,而是回到那种它们的文档怎么写的,
那么我们就怎么写的状态

当然,我会穿插关于源代码的部分,有些地方还是会用上的

至于为什么这样做,就参见Forge长线教程计划的第一期内容

另外呢,还是那句老话,模组开发,通其一,便可通其二

你学过其中一端,再到另外一端,把基础内容过一遍,上手很快的

准备工作

那么从本期教程开始,我们正式的开始,这个1.21.1 NeoForge模组的开发教程

注意,目前开行的1.21.1 NeoForge长线教程计划同已有的1.21 Fabric长线教程计划一样,
版本只适用于1.21-1.21.1,由于1.21.2及其以上的版本改动的东西很多,
等到了一定的程度,再往高版本升级

可参见1.21 Fabric长线教程计划,NeoForgeFabric的教程内容基本一致,
到后期再来升级版本,但Forge的长线教程计划就只限于1.20.1

NeoForge是从1.20开始从Forge中分离出来的

在高版本上的话,应该是NeoForge用得更多,所以我们的长线教程计划,高版本就不做Forge

那么第一期教程的话,和以往一样,我们就来进行开发环境的配置

JDK21

那么我们的Minecraft的话,它是拿Java去写的

而我们要进行开发的话,就得装一个JDK

这个JDK的全称的话就是Java Development Kit(开发工具包),简称JDK

大家学Java的时候的话,应该也都是装过这个东西的

不管是8也好,还是17也好,还是21,应该都是装过这个东西的

上了1.21.1它这个版本,它应该是拿Java 21去写的,
所以说我们安装的版本的话,应该要装的是这个JDK21

关于它的下载的话,我这里提供Oracle官网上的Java下载

链接:Oracle

链接里点进去,我们就能直接看到JDK21的下载
Oracle官网

它分三个端,三个端的不同的安装程序,下载你自己对应系统

这里我们以Windows为例

那么它还分一些不同的安装方式,有三个东西

其中一个是zip,这是压缩文件,它是已经完全安装好的Java,你可以下载解压之后,放到你自己的Java目录中

另外两个exemsi,这两个的话都是安装程序,可以自己选择下载安装

安装的话,默认是安装到C盘的,其实也不用改安装路径,IDEA会默认到C盘找你的Java

当然你也可以选择安装到其他位置,只要你自己找得到就行

目前,在Oracle上下载JDK21的话,还不用注册登录,直接下载就行

IDEA

IDEA的全称是IntelliJ IDEA,是JetBrains公司的一款Java IDE

那么现在我们就用它作为我们模组开发的编辑器,其他编辑器当然也可以,只是我个人建议使用IDEA,有些操作会方便一点

那么下载这里我提供官方的下载链接

链接:IDEA下载

那么到下载界面,先别捉急下载,开头的那个IntelliJ IDEA Ultimate,什么30天免费试用,咱不要

那玩意是专业版,其实就对模组开发而言,社区版足矣,我们用不着专业版的一些功能

然后往下翻,找到IntelliJ IDEA Community,下载社区版就行,社区版是完全免费的

IDEA下载

IDEA的安装默认也在C盘,这个的话,你就改到其他的位置好了,如果你C盘够大,也可以装C盘里

那么,在安装中,会有一个更新path变量的选项,这个选项的话,勾选了的话,需要重启电脑才能生效

PS:以上两个部分直接引自【1.20.1 Fabric 长线教程计划】的第一期,因为差不多,拿过来就能用了

模板文件

获取模板文件两个方法,一个是从它的GitHub仓库直接获取对应版本的Mdk,一个是模板生成网站

GitHub仓库

链接:NeoForge MDKs GitHub仓库

找到我们要开发的版本的仓库MDK-1.21.1-ModDevGradle

随后,点击Code,选择Download ZIP,下载对应的ZIP文件,然后我们就获得了一个zip文件

把它解压出来,放到一个地方,将整个文件夹用IDEA打开

当然,因为我们后面还要改mod id之类的,所以我并不推荐这个方法

模板生成网站

NeoForge其实也有一个类似于Fabric的模板生成网站,在它的官网上

链接:NeoForge模板生成

NeoForge模板生成

进去之后,我们就看到了一些要填的参数

Mod Name

模组名称,这个的话,就自己填一个,我这里做教程就用Tutorial Mod

Mod ID

这个默认是通过Mod Name生成的,取消勾选下面的Generate mod ID from name我们就能自定义了

因为我上面用了Tutorial Mod,所以这里我填上tutorial_mod,用下划线代替空格

当然注意,在你自定义Mod ID时,不能使用大写字母,只能使用小写字母数字下划线

这个是与Forge那边一样的,Fabric中使用的-短横同样不能使用

Package Name

包名,也就是存放模组主类的路径,自己自定义,我这里就写com.besson.tutorial

Minecraft Version

Minecraft版本,这里我们选择1.21.1

Gradle Plugin

Gradle插件,这里我们选择ModDevGradle

Advanced Options

高级选项里面,还有一个Add mixin configuration,可以选择,这样你就可以写一些Mixin类了

NeoForgeMixin用的其实也就是Fabric的,来自Sponge项目

下载

最后参数填写完成之后,我们就选择DOWNLOAD MOD PROJECT,下载对应的ZIP文件

在此之前你也可以选择PREVIEW MOD PROJECT,预览一下模组项目

下载解压zip文件到一个地方,记得新建一个文件夹,然后将整个文件夹拖到IDEA中打开

初始化项目

Gradle构建

进入IDEA之后,它会自动开始Gradle的构建,当然,这个过程不出意外的话还是要魔法

同理,出现BUILD SUCCESSFUL之后,就说明构建成功了,当然可能会出现一些警告,不用管他

Gradle使用的Java版本

构建完成之后,我们可以到build.gradle文件中,当前项目使用的Java版本

1
2
// Mojang ships Java 21 to end users in 1.21.1, so mods should target Java 21.
java.toolchain.languageVersion = JavaLanguageVersion.of(21)

可以看到,它默认使用的是Java 21,这个是没问题的

项目结构

接下来我们来看看项目结构里的设置是否正确

项目结构的快捷键是Shift+Alt+Ctrl+S,也找到设置中的项目结构打开,在项目界面,找到SDK,确认一下使用的是JDK17

在后面一个模块中,也可以设置使用的SDK,这里我们选择21

项目结构

Gradle JVM

虽然说我们看到build.gradle里,它默认使用的是21,但是,有时候IDEA会自己给你选择其他的版本,我们也来检查一下

设置 -> 构建、执行、部署 -> 构建工具 -> Gradle,检查Gradle JVM是否为JDK21

Gradle JVM

IDEA一些小设置

IDEA 2024.3版本之后,我们就不再需要安装中文语言包这个插件了,因为这个时候中文已经是IDEA内置语言

外观与行为->系统设置->语言和区域,我们可以更改语言设置(当然需要重新启动

语言设置

那么另外的插件方面,Minecraft Development可以装一下,像Translation这样的翻译插件也可以装一个

模组基本配置

模组主类

接下来我们来看看模组主类,我们使用模板文件创建的主类名字是TutorialMod

这个类会在模组加载中调用,用来加载模组

然后在这个类中,我们可以看到一些示例,比如注册物品方块物品栏等等

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Create a Deferred Register to hold Blocks which will all be registered under the "tutorial_mod" namespace
public static final DeferredRegister.Blocks BLOCKS = DeferredRegister.createBlocks(MODID);
// Create a Deferred Register to hold Items which will all be registered under the "tutorial_mod" namespace
public static final DeferredRegister.Items ITEMS = DeferredRegister.createItems(MODID);
// Create a Deferred Register to hold CreativeModeTabs which will all be registered under the "tutorial_mod" namespace
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS = DeferredRegister.create(Registries.CREATIVE_MODE_TAB, MODID);

// Creates a new Block with the id "tutorial_mod:example_block", combining the namespace and path
public static final DeferredBlock<Block> EXAMPLE_BLOCK = BLOCKS.registerSimpleBlock("example_block", BlockBehaviour.Properties.of().mapColor(MapColor.STONE));
// Creates a new BlockItem with the id "tutorial_mod:example_block", combining the namespace and path
public static final DeferredItem<BlockItem> EXAMPLE_BLOCK_ITEM = ITEMS.registerSimpleBlockItem("example_block", EXAMPLE_BLOCK);

// Creates a new food item with the id "tutorial_mod:example_id", nutrition 1 and saturation 2
public static final DeferredItem<Item> EXAMPLE_ITEM = ITEMS.registerSimpleItem("example_item", new Item.Properties().food(new FoodProperties.Builder()
.alwaysEdible().nutrition(1).saturationModifier(2f).build()));

// Creates a creative tab with the id "tutorial_mod:example_tab" for the example item, that is placed after the combat tab
public static final DeferredHolder<CreativeModeTab, CreativeModeTab> EXAMPLE_TAB = CREATIVE_MODE_TABS.register("example_tab", () -> CreativeModeTab.builder()
.title(Component.translatable("itemGroup.tutorial_mod")) //The language key for the title of your CreativeModeTab
.withTabsBefore(CreativeModeTabs.COMBAT)
.icon(() -> EXAMPLE_ITEM.get().getDefaultInstance())
.displayItems((parameters, output) -> {
output.accept(EXAMPLE_ITEM.get()); // Add the example item to the tab. For your own tabs, this method is preferred over the event
}).build());

这些也都是我们后面会讲到的,在这里的话就全删了,我们后面会单开类去注册各个内容的

删掉以后,在构造函数中出现的报错也删掉,addCreative方法中报错的也删掉

另外的一些LOGGER之类的,也可以删掉,那些是日志输出的

但注意不要把MODID下的那个LOGGER字段删了

MODID

TutorialMod类中,我们可以看到MODID字段,这个字段是模组的唯一标识符

在我们模组开发中,这个东西是最重要的东西,它是我们的命名空间

这个MODID可以重构成MOD_ID,看起来更好看一点

1
public static final String MOD_ID = "tutorial_mod";

敲重点!!!这个ID在自己定义的时候,只能用小写字母和下划线!不能有其他字符!否则在加载模组时会崩溃!

Fabric那边还能用短横线,但在ForgeNeoForge这里就不行

注意使用IDEA的重命名功能来进行,快捷键是Shift+F6,不然会报错

gradle.properties

接下来我们就来看看这个文件,这个是整个项目,或者说模组的配置文件

模组的名称mod id版本等等信息都是在这个文件中定义的,所以这也是一个很重要的文件

parchment_minecraft/mappings_version

1
2
3
4
#read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
parchment_minecraft_version=1.21.1
parchment_mappings_version=2024.11.17

这个是映射版本,NeoForge默认使用羊皮纸映射,也就是这个parchment

什么是映射?我简单解释一下(引自Forge长线教程计划第一期

Minecraft闭源的商业游戏,如果你拆过它的jar包就会发现,你尝试去找它的源码时,
你会发现一大堆奇怪的类名、方法名,这些都不是正常的类名、方法名,而是被混淆过的

映射的作用,就是将混淆过的类名、方法名还原成正常的类名、方法名

Mojang也公开了一部分映射,ForgeNeoForge也已经使用这些映射,而Fabric还有Yarn映射

Mojang的映射并不完整,使用我们在看源代码的时候,还是会看到很多filed_XXXmethod_XXX这样的类名、方法名,
它们并没有完全反编译过来,在开发中可能得理解好久才能反应过来

这里使用的羊皮纸映射,也就是Parchment,它完善了Mojang的映射,这个映射同样可以用在Fabric上

这里既然已经写好了,我们就不用动了

minecraft_version

1
2
3
4
5
6
7
8
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
# The Minecraft version must agree with the Neo version to get a valid artifact
minecraft_version=1.21.1

# The Minecraft version range can use any release version of Minecraft as bounds.
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21.1]

显然易见,这个是定义Minecraft版本的,这里我们使用1.21.1版本

后面是这个模组适用的Minecraft版本范围

neo_version

1
2
3
4
5
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.1.193

# The loader version range can only use the major version of FML as bounds
loader_version_range=[1,)

这个是定义NeoForge版本的,这里我们使用21.1.193版本

后面是这个模组适用的NeoForge加载器版本范围

Mod Properties

这里我们再来看下半部分的Mod Properties,这是模组的一些属性

mod_id

这个要对应模组主类中的MOD ID,否则会报错

1
2
3
# The unique mod identifier for the mod. Must be lowercase in English locale. Must fit the regex [a-z][a-z0-9_]{1,63}
# Must match the String constant located in the main mod class annotated with @Mod.
mod_id=tutorial_mod

mod_name

这个是模组在模组列表中显示的名字

1
2
# The human-readable display name for the mod.
mod_name=Tutorial Mod

这里你写啥字符都行

mod_license

这个是模组使用的许可证,像一些开源许可证,比如说MITGPL3.0等等

1
2
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT

这里更改之后,在项目文件下还有一个TEMPLATE_LICENSE.txt文件,这个文件就是许可证文件

mod_version

这个是模组的版本,我的建议是带上Minecraft的版本号,这样你自己进行多版本移植的时候也清楚

1
2
# The mod version. See https://semver.org/
mod_version=1.0.0-1.20.1

mod_group_id

这个就是文件夹结构,其实就是我们在创建模板文件时输入的

1
2
3
4
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html
mod_group_id=com.besson.tutorial

如果这个mod_group_id不正确,模组加载器就找不到你的模组主类,也无法加载你的模组

mod_authors

这个是模组的作者

1
2
# The authors of the mod. This is a simple text string that is used for display purposes in the mod list.
mod_authors=Besson

mod_description

这个是模组的描述,这里我们写一个简单的描述

注意换行不是直接回车,要使用\n转义

1
2
# The description of the mod. This is a simple multiline text string that is used for display purposes in the mod list.
mod_description=This is a Tutorial Mod\nLet's Develop Minecraft Mods NOW!

重构项目

做完这一切之后,我们点击右上角冒出来的大象图标,同步更改Gradle设置,对项目进行重构

同样也是出现BUILD SUCCESSFUL,说明重构成功

下载源代码

点击右侧Gradle(大象)的图标,在上方菜单栏中找到下载图标,下载源代码,点击下载

而后,在你打开Minecarft的源代码文件时,如果上面出现蓝色的一条内容,就选择附加源
即可转变成下载过来的源代码文件

启动!

那么最后一步了,在Gradle项目的Tasks/mod development下有一个runClient,双击运行

你也可以找到上方运行菜单中的Client,点击运行

这个就是启动游戏,那么当熟悉的音乐出来之后,你能够进入游戏,说明开发环境没有问题

那么恭喜你,正式踏入了我们1.21.1 NeoForge模组开发的大门!