附魔 1.21 Fabric 长线教程计划
本篇教程的视频
本篇教程的源代码
GitHub地址:TutorialMod-Enchantment-1.21
本篇教程目标
- 学会添加附魔
前言
来到1.21
之后,附魔也变成数据驱动
的了
所以,其实你完全可以按照数据包的写法来写附魔,叠几个附魔在一起
高版本很多东西都改成数据驱动
的了,这对数据包开发来说是好事,但对于模组开发那可不太好
不过,如果要实现具体的附魔效果,比如像精准采集、火焰附加、荆棘等这种对工具属性进行改变的,
还是得通过代码的形式来添加
我们这里呢,源代码就不看了,具体思路是编写一个附魔类型,注册它,
再用数据生成来生成附魔相关的一些内容,比如等级、消耗的经验、可以附加在那些东西上
源代码我提一下,Enchantments
是原版的注册类,其中有个bootstrap
方法,用于数据生成
在net.minecraft.enchantment.effects
包下,放了原版那些附魔的类型
一些作用在实体上的附魔效果,比如迅捷
、火焰附加
等,这些是实现EnchantmentEntityEffect
接口的
附魔有些效果并没有单独的类,所以研究起来可能有一点困难,有些是直接在注册时,
用addEffec
t方法添加的效果,所以具体的源代码我就不提了
本篇教程参考Fabric
的官方文档:Enchantments
关于工具的附魔
在1.21
之前,如果我们添加自定义的工具,是可以附魔并有实际效果的
但在1.21
之后,,因为附魔变成数据驱动的缘故,工具还要给他们写Tag
才能在附魔台上附魔并产生效果
这里,我们先来写工具那些Tag
的数据生成
我们到ModItemTagsProvider
类中加上
1 | getOrCreateTagBuilder(ItemTags.SWORD_ENCHANTABLE) |
剑和其他开采用工具是分开写的
因为剑
属于武器,而其他是属于采集方块的工具,有些可以用在剑上的附魔是不能用在开采类工具上的
然后跑个数据生成
,再进入游戏进行测试,我们之前写的这些工具就可以在附魔台上附魔了
自定义附魔
那么,回到我们这篇教程的重点来,来添加我们自定义的附魔
创建自定义附魔
这里我们来创建一个TestEnchantmentEffect
,按照原版,实现EnchantmentEntityEffect
接口
还要注意的是,这个类我们写成record
类,与原版一致,当然这里我们没什么参数,就空着好了
1 | public record TestEnchantmentEffect() implements EnchantmentEntityEffect { |
实现EnchantmentEntityEffect
要我们重写两个方法,其中一个是CODEC
,是编解码器
,
这个是高版本都有的一个东西,用于数据传输的
所以这里我们得写一个
1 | public static final MapCodec<TestEnchantmentEffect> CODEC = MapCodec.unit(TestEnchantmentEffect::new); |
因为我们没有一些额外的参数,所以就写一个简单的编解码器就可以
然后在下面的getCodec
方法中返回
1 |
|
而后,我们回过头来看apply
方法,这个方法用来指定这个附魔会有什么效果
那么,参考Fabric
的文档,我们就按照不同等级给它不同的效果
1 | if (level == 1) { |
比较简单,也可以说有点草率
这些代码就是生成闪电LIGHTNING_BOLT
spawn
方法有三个参数,第一个是当前世界,第二个是生成闪电的位置,第三个是生成闪电的原因
当然,能做文章的东西很多,这里既然能生成闪电,那么也可以生成其他实体,
另外也可以结合其他的方法,比如药水效果
、粒子
等内容,制作更为复杂的附魔效果
注册自定义附魔
这里我们再创建一个ModEnchantments
类,用于自定义附魔的注册
1 | public class ModEnchantments { |
首先是一个注册方法
,用原版的方法再加上我们的命名空间
1 | private static RegistryKey<Enchantment> of(String id) { |
然后注册附魔的注册键
1 | public static final RegistryKey<Enchantment> TEST = of("test"); |
那么接下来就是bootstrap
方法,用于数据生成
1 | public static void bootstrap(Registerable<Enchantment> registry) { |
里面的参数
直接从原版搬过来就可以
另外还要一个注册方法
,用在数据生成里的注册方法
1 | private static void register(Registerable<Enchantment> registry, RegistryKey<Enchantment> key, Enchantment.Builder builder) { |
然后我们就可以在bootstrap
方法中注册了
1 | RegistryEntryLookup<Enchantment> registryEntryLookup2 = registry.getRegistryLookup(RegistryKeys.ENCHANTMENT); |
首先是两个RegistryEntryLookup
,这个就直接从原版搬过来的
我们重点来看注册方法中的definition
方法
它有8
个参数
第一个是支持附魔的物品
,第二个是主要
支持的附魔物品
第三个是权重
,即在附魔台出现的概率
第四个是最大等级
第五个是每个等级附魔台所需的最小经验消耗
,第六个是每个等级附魔台所需的最大经验消耗
,
leveledCost的两个参数,第一个是基础消耗
,第二个是每级递增的消耗
第七个是铁砧
附魔消耗的经验(附魔书直接附魔)
第八个是生效的槽位,一般为主手
生效
上面的这些参数可以在后面生成的数据文件中找到
exclusiveSet
方法是指定附魔所在的集合,因为附魔和药水效果不同,有些附魔是不能同时存在
,
这里的DAMAGE_EXCLUSIVE_SET
是其中一个伤害类附魔集合
addEffect
方法是指定附魔造成的效果,第一个参数是附魔的组件类型,可以理解为何时附魔生效,POST_ATTACK
是攻击后
生效,还有其他很多种,比如DAMAGE
,攻击造成伤害时
生效等等
第二个参数和第三个参数分别是攻击方
和被攻击方
,注意顺序
,不然按照我们上面的附魔效果,写反了就是我们被雷劈了
最后一个参数就是我们的自定义附魔了,实例化
它即可
数据生成类调用
我们到TutorialModDataGenerator
中来调用bootstrap
方法
1 | registryBuilder.addRegistry(RegistryKeys.ENCHANTMENT, ModEnchantments::bootstrap); |
另外,在ModWorldGen
中,也要加上对ENCHANTMENT
注册键的动态注册
1 | entries.addAll(registries.getWrapperOrThrow(RegistryKeys.ENCHANTMENT)); |
编解码器注册
实际上,在EnchantmentEntityEffect
接口中,还注册了很多编解码器
所以我们在自定义附魔类中写的编解码器也是要进行注册的
这里我们再创建一个ModEnchantmentEffects
类,用来注册编解码器
1 | public class ModEnchantmentEffects { |
首先写一个注册方法
1 | private static MapCodec<? extends EnchantmentEntityEffect> register(String name, MapCodec<? extends EnchantmentEntityEffect> codec) { |
这个也是从原版的EnchantmentEntityEffect
中搬过来的,再加上我们的命名空间
然后注册我们的编解码器
1 | public static final MapCodec<? extends EnchantmentEntityEffect> TEST = register("test", TestEnchantmentEffect.CODEC); |
另外,万变不离其宗的,一个用于初始化
的注册方法
1 | public static void registerModEnchantmentEffects() { |
再在模组主类
中调用这个方法
1 | ModEnchantmentEffects.registerModEnchantmentEffects(); |
然后我们就可以跑数据生成,而后,我们就能在data/tutorialmod/enchantment
目录下看到我们的附魔的json文件了
1 | { |
这里面的参数就是我们上面在bootstrap
方法中写的