本篇教程的视频

本篇教程的源代码

GitHub地址:TutorialMod-Armor-1.20.1

本篇教程目标

  • 理解原版盔甲材料的添加、盔甲物品的注册
  • 学会创建盔甲材料、注册盔甲物品

查看源代码

这里我们也还是先来看源代码,找到Items类中的盔甲相关的内容

盔甲注册

1
2
3
4
public static final Item IRON_HELMET = register("iron_helmet", new ArmorItem(ArmorMaterials.IRON, ArmorItem.Type.HELMET, new Item.Settings()));
public static final Item IRON_CHESTPLATE = register("iron_chestplate", new ArmorItem(ArmorMaterials.IRON, ArmorItem.Type.CHESTPLATE, new Item.Settings()));
public static final Item IRON_LEGGINGS = register("iron_leggings", new ArmorItem(ArmorMaterials.IRON, ArmorItem.Type.LEGGINGS, new Item.Settings()));
public static final Item IRON_BOOTS = register("iron_boots", new ArmorItem(ArmorMaterials.IRON, ArmorItem.Type.BOOTS, new Item.Settings()));

盔甲的话一共是4个部分,分别是头盔胸甲护腿靴子,每个盔甲物品都是实例化ArmorItem的,

ArmorItem的第一个参数是ArmorMaterials,这是盔甲材料,这个倒是和我们之前写的工具差不多

第二个参数是盔甲的类型,分头盔胸甲护腿靴子

最后一个参数则是物品的设置

盔甲材料

我们到ArmorMaterials类中来看看,同样这个类也是一个枚举类,罗列了原版所有的盔甲材料

和前面工具材料一样,我们直接看其中一个盔甲材料和构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
IRON("iron", 15, Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 2);
map.put(ArmorItem.Type.LEGGINGS, 5);
map.put(ArmorItem.Type.CHESTPLATE, 6);
map.put(ArmorItem.Type.HELMET, 2);
}), 9, SoundEvents.ITEM_ARMOR_EQUIP_IRON, 0.0F, 0.0F, () -> Ingredient.ofItems(Items.IRON_INGOT))
...

private ArmorMaterials(
String name,
int durabilityMultiplier,
EnumMap<ArmorItem.Type, Integer> protectionAmounts,
int enchantability,
SoundEvent equipSound,
float toughness,
float knockbackResistance,
Supplier<Ingredient> repairIngredientSupplier
) {
this.name = name;
this.durabilityMultiplier = durabilityMultiplier;
this.protectionAmounts = protectionAmounts;
this.enchantability = enchantability;
this.equipSound = equipSound;
this.toughness = toughness;
this.knockbackResistance = knockbackResistance;
this.repairIngredientSupplier = new Lazy<>(repairIngredientSupplier);
}

name是盔甲材料的名称

durabilityMultiplier是盔甲的耐久倍数

protectionAmounts是盔甲提供的护甲值,是决定减伤比例区间的属性,每1点护甲值使伤害减少4%、至多被伤害降低至下限0.8%(Wiki)

equipSound是盔甲装备时的音效

toughness是盔甲的韧性,是决定降低护甲值减伤比例需要的伤害的属性(Wiki)

knockbackResistance是盔甲的击退抗性,原版只有下界合金有击退抗性

repairIngredientSupplier是盔甲的修复材料

1
2
3
4
5
6
7
8
9
10
11
private static final EnumMap<ArmorItem.Type, Integer> BASE_DURABILITY = Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 13);
map.put(ArmorItem.Type.LEGGINGS, 15);
map.put(ArmorItem.Type.CHESTPLATE, 16);
map.put(ArmorItem.Type.HELMET, 11);
});

@Override
public int getDurability(ArmorItem.Type type) {
return (Integer)BASE_DURABILITY.get(type) * this.durabilityMultiplier;
}

结合下面重写的getDurability方法,我们可以看到每个部位盔甲的最终耐久度是怎么计算的

它是由一个BASE_DURABILITY提供的每个部位的基础耐久度,乘以盔甲材料的耐久倍数得到的

再后面,我们看看protectionAmounts这个EnumMap类型的参数,
这里就是将4个部位提供的不同护甲值给罗列出来

注意一下护甲值这个东西,原版能够在HUD显示出来的最大护甲值只有20,下界合金正好是20,超过的部分虽然有效,但不会在HUD显示出来

注册物品

创建盔甲材料

这里我们先来创建自己的盔甲材料,我们创建一个ModArmorMaterials类,实现StringIdentifiableArmorMaterial这两个接口

1
2
3
public class ModArmorMaterials implements StringIdentifiable, ArmorMaterial {
;
}

然后是要重写一些方法的,但我们还是先从原版搬一些变量过来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static final EnumMap<ArmorItem.Type, Integer> BASE_DURABILITY = Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 13);
map.put(ArmorItem.Type.LEGGINGS, 15);
map.put(ArmorItem.Type.CHESTPLATE, 16);
map.put(ArmorItem.Type.HELMET, 11);
});

private final String name;
private final int durabilityMultiplier;
private final EnumMap<ArmorItem.Type, Integer> protectionAmounts;
private final int enchantability;
private final SoundEvent equipSound;
private final float toughness;
private final float knockbackResistance;
private final Supplier<Ingredient> repairIngredientSupplier;

这里我们把BASE_DURABILITY和另外的一堆变量给拿过来,注意最后的修复材料,我们也改成Supplier类型的

然后是构造函数,这里我们直接把原版盔甲材料的构造函数搬过来,改一下就可以了

1
2
3
4
5
6
7
8
9
10
ModArmorMaterials(String name, int durabilityMultiplier, EnumMap<ArmorItem.Type, Integer> protectionAmounts, int enchantability, SoundEvent equipSound, float toughness, float knockbackResistance, Supplier<Ingredient> repairIngredientSupplier) {
this.name = name;
this.durabilityMultiplier = durabilityMultiplier;
this.protectionAmounts = protectionAmounts;
this.enchantability = enchantability;
this.equipSound = equipSound;
this.toughness = toughness;
this.knockbackResistance = knockbackResistance;
this.repairIngredientSupplier = repairIngredientSupplier;
}

那么重写的方法就可以补全了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
@Override
public int getDurability(ArmorItem.Type type) {
return (Integer)BASE_DURABILITY.get(type) * this.durabilityMultiplier;
}

@Override
public int getProtection(ArmorItem.Type type) {
return (Integer)this.protectionAmounts.get(type);
}

@Override
public int getEnchantability() {
return this.enchantability;
}

@Override
public SoundEvent getEquipSound() {
return this.equipSound;
}

@Override
public Ingredient getRepairIngredient() {
return this.repairIngredientSupplier.get();
}

@Override
public String getName() {
return TutorialMod.MOD_ID + ":" + this.name;
}

@Override
public float getToughness() {
return this.toughness;
}

@Override
public float getKnockbackResistance() {
return this.knockbackResistance;
}

@Override
public String asString() {
return this.name;
}

注意,其中的getName方法,我们要加上我们模组的modid,因为这个关乎资源文件的定位,
没有我们模组的命名空间的话,就又找到MC这个命名空间下去了

那么最后,我们就可以编写盔甲材料了

1
2
3
4
5
6
ICE_ETHER("ice_ether", 40, Util.make(new EnumMap(ArmorItem.Type.class), map -> {
map.put(ArmorItem.Type.BOOTS, 3);
map.put(ArmorItem.Type.LEGGINGS, 6);
map.put(ArmorItem.Type.CHESTPLATE, 8);
map.put(ArmorItem.Type.HELMET, 3);
}), 30, SoundEvents.ITEM_ARMOR_EQUIP_NETHERITE, 3.0F, 0.1F, () -> Ingredient.ofItems(ModItems.ICE_ETHER));

按照原版的写法就好了,不过是会有一些警告的,不用管他,因为原版这么写的,我们也这么写,自然没问题

这个穿戴盔甲的声音我们还没有自己的声音事件,所以就拿原版的好了

注册盔甲

随后那就是盔甲的注册

1
2
3
4
5
6
7
8
public static final Item ICE_ETHER_HELMET = registerItems("ice_ether_helmet",
new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.HELMET, new Item.Settings()));
public static final Item ICE_ETHER_CHESTPLATE = registerItems("ice_ether_chestplate",
new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.CHESTPLATE, new Item.Settings()));
public static final Item ICE_ETHER_LEGGINGS = registerItems("ice_ether_leggings",
new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.LEGGINGS, new Item.Settings()));
public static final Item ICE_ETHER_BOOTS = registerItems("ice_ether_boots",
new ArmorItem(ModArmorMaterials.ICE_ETHER, ArmorItem.Type.BOOTS, new Item.Settings()));

实例化ArmorItem,然后指定对应的盔甲材料和盔甲类型

加入物品栏

最后,我们还要把盔甲加入到物品栏中,这里我们直接在注册物品栏的方法中添加

1
2
3
4
entries.add(ModItems.ICE_ETHER_HELMET);
entries.add(ModItems.ICE_ETHER_CHESTPLATE);
entries.add(ModItems.ICE_ETHER_LEGGINGS);
entries.add(ModItems.ICE_ETHER_BOOTS);

数据文件

物品标签

高版本中,加入了锻造模板,盔甲可以使用锻造模板,在锻造台进行加工

但要让我们的盔甲可以锻造,需要写对应的物品标签

1
2
getOrCreateTagBuilder(ItemTags.TRIMMABLE_ARMOR)
.add(ModItems.ICE_ETHER_HELMET, ModItems.ICE_ETHER_CHESTPLATE, ModItems.ICE_ETHER_LEGGINGS, ModItems.ICE_ETHER_BOOTS);

TRIMMABLE_ARMOR即为可锻造盔甲的标签,我们将注册好的盔甲物品加入即可

语言文件

1
2
3
4
translationBuilder.add(ModItems.ICE_ETHER_HELMET, "Ice Ether Helmet");
translationBuilder.add(ModItems.ICE_ETHER_CHESTPLATE, "Ice Ether Chestplate");
translationBuilder.add(ModItems.ICE_ETHER_LEGGINGS, "Ice Ether Leggings");
translationBuilder.add(ModItems.ICE_ETHER_BOOTS, "Ice Ether Boots");

模型文件

1
2
3
4
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_HELMET);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_CHESTPLATE);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_LEGGINGS);
itemModelGenerator.registerArmor((ArmorItem) ModItems.ICE_ETHER_BOOTS);

盔甲的模型文件有单独的方法,这里我们要调用registerArmor方法,传入我们的盔甲物品

贴图

盔甲的材质贴图是与一般物品不一样的,它是除了物品栏中的物品图标的材质文件

还有一类是模型类的文件

我们要将贴图放在textures/models/armor文件夹下

注意,贴图文件分为2个,其中的12有是用_分开的,可参见原版的贴图文件

测试

数据生成跑完之后,我们就可以进入游戏进行测试了