User Tools

Site Tools


zh_cn:tutorial:armor

This is an old revision of the document!


添加盔甲

介绍

盔甲是比一般的方块或者物品更复杂一点的实现,但是只要了解了,实现还是很简单的。如需添加盔甲,需要先实现CustomArmorMaterial类,然后注册物品。我们还需要看看如何为盔甲提供纹理。本文最后有一个解释如何添加击退的特殊章节,因为此方法只能通过Mixin访问(对于1.16.3)。

本文档的一个例子可以在本模组GitHub仓库找到。

创建盔甲材料类

新的盔甲需要和一个新的名称(以及额外的一些内容,例如盔甲点和耐久度)一起设置,我们需要为我们的CustomArmorMaterial创建一个新的类。

本类实现ArmorMaterial,并以指定值为盔甲点(称为PROTECTION_VALUES)开始。所有这些参数都会充分利用 @Override。

  1. public class CustomArmorMaterial implements ArmorMaterial {
  2. private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11};
  3. private static final int[] PROTECTION_VALUES = new int[] {A, B, C, D};
  4.  
  5. // 其中A是头盔,B是胸甲,C是护腿,D是靴子。
  6. // 例如,皮革使用{1, 2, 3, 1},钻石和下界合金使用{3, 6, 8, 3}
  7. }

接下来的变量如下定义(无需担心名称,下面你会看到如何实现):

  1. getDurability: how many hits can armor take before breaking. Uses the int we wrote on 'BASE_DURABILITY' to calculate. Leather uses 5, Diamond 33, Netherite 37.
  2. getProtectionAmount: calls for the 'PROTECTION_VALUES' int we already wrote above.
  3. getEnchantability: This will be how likely the armor can get high level or multiple enchantments in an enchantment book.
  4. SoundEvent getEquipSound: The standard used by vanilla armor is SoundEvents.ITEM_ARMOR_EQUIP_X, X being the type of armor.
  5. Ingredient getRepairIngredient: what item are we gonna be using to repair the armor on an anvil. It can be either a vanilla item or one of your own.
  6. String getName: what the parent item of the armor is. In Diamond armor, it'd be “diamond”.
  7. getToughness: This is a second protection value where the armor is more durable against high value attacks. Value goes as 'X.0F'

在1.16引入的新值

  1. getKnockbackResistance: leave this value at 0. If you want to implement it, write '0.XF' (in which X is how much knockback protection you want), and I'll teach you how to make it work later on.

接下来所有的参数都会写成 X 或者 A、B、C、D。加上这些参数之后,效果应该如下:

  1. public class CustomArmorMaterial implements ArmorMaterial {
  2. private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11};
  3. private static final int[] PROTECTION_VALUES = new int[] {A, B, C, D};
  4.  
  5. @Override
  6. public int getDurability(EquipmentSlot slot) {
  7. return BASE_DURABILITY[slot.getEntitySlotId()] * X;
  8. }
  9.  
  10. @Override
  11. public int getProtectionAmount(EquipmentSlot slot) {
  12. return PROTECTION_VALUES[slot.getEntitySlotId()];
  13. }
  14.  
  15. @Override
  16. public int getEnchantability() {
  17. return X;
  18. }
  19.  
  20. @Override
  21. public SoundEvent getEquipSound() {
  22. return SoundEvents.ITEM_ARMOR_EQUIP_X;
  23. }
  24.  
  25. @Override
  26. public Ingredient getRepairIngredient() {
  27. return Ingredient.ofItems(RegisterItems.X);
  28. }
  29.  
  30. @Override
  31. public String getName() {
  32. return "name";
  33. }
  34.  
  35. @Override
  36. public float getToughness() {
  37. return X.0F;
  38. }
  39.  
  40. @Override
  41. public float getKnockbackResistance() {
  42. return 0.XF;
  43. }
  44. }

注意你有盔甲材料类的基础了,所以在新的类中注册你的盔甲物品,即RegisterItems。

创建盔甲物品

我们准备创建一个叫做RegisterItems的新的类以实现新的盔甲物件。这也会是注册工具的地方,如果你准备制作像锭这样的新物品(我们简单称为Custom_Material)。这一步同时还会将这些物品放在创造模式物品栏中,如果需要也可以删除这一部分。

物品分组的语法为 .group(你的模组名称.你的分组的大写名称)。这里将其称为ExampleMod:

  1. public class RegisterItems {
  2.  
  3. public static final ArmorMaterial CUSTOM_ARMOR_MATERIAL = new CustomArmorMaterial();
  4. public static final Item CUSTOM_MATERIAL = new CustomMaterialItem(new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP));
  5. // 如果创建了新的材料,则你需要注意这里。
  6. public static final Item CUSTOM_MATERIAL_HELMET = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.HEAD, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP));
  7. public static final Item CUSTOM_MATERIAL_CHESTPLATE = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.CHEST, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP));
  8. public static final Item CUSTOM_MATERIAL_LEGGINGS = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.LEGS, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP));
  9. public static final Item CUSTOM_MATERIAL_BOOTS = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.FEET, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP));
  10.  
  11. }

现在物品创建好了,将其注册并给予适当的名称,你的第一个参数是名字空间,也就是你的模组ID,第二个是你需要给予你的物品的名称。

我们会在最后一个ArmorItem的下面写这些。

  1. public static void register() {
  2. Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material"), CUSTOM_MATERIAL);
  3. Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_helmet"), CUSTOM_MATERIAL_HELMET);
  4. Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_chestplate"), CUSTOM_MATERIAL_CHESTPLATE);
  5. Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_leggings"), CUSTOM_MATERIAL_LEGGINGS);
  6. Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_boots"), CUSTOM_MATERIAL_BOOTS);
  7. }

你的盔甲物品已完成。现在我们在主类中调用Registry。

  1. public static final ItemGroup EXAMPLE_MOD_GROUP = FabricItemGroupBuilder.create(
  2. new Identifier("examplemod", "example_mod_group"))
  3. .icon(() -> new ItemStack(RegisterItems.CUSTOM_MATERIAL)) // 这里将你创建的新的材料的模型用作图标,但是你也可以随时使用你喜欢的
  4. .build();
  5.  
  6. @Override
  7. public void onInitialize() {
  8. RegisterItems.register();
  9. }

好了!你的盔甲现在应该存在于游戏中,虽然还没有纹理,但是已经可以通过/give来获得了。

现在分配纹理。

提供纹理

假定你已经:

  • 有了每一个盔甲物品的纹理(x_helmet.png、x_chestplate.png等)
  • 有了穿着的每个盔甲的纹理(x_layer_1.png和x_layer_2.png)

将其分配到每一个盔甲物品。

下列过程对于所有盔甲物品都是一样的,只需要修改我们使用的部分。这里以头盔为例。

resources/assets/examplemod/models/item/custom_material_helmet.json
{
	"parent": "item/generated",
	"textures": {
		"layer0": "examplemod:item/custom_material_helmet"
	}
}

重复上述过程,完成其他物品。

要给予穿着的盔甲的纹理,只需要将X_layer_1.png和X_layer_2.png(其中X是你在你的盔甲材料类中选择的参数)放到'resources/assets/minecraft/textures/models/armor'。

做完上述步骤,你应该会有一套完整的盔甲!

添加击退保护

来了,非常折磨!

Mojang 决定他们不仅要硬编码 getKnockbackResistance,而且还要让它不可变!笑死。

To get around this, we're gonna make a mixin that goes into ArmorItem. If this is your first time, here's how to register mixins on your fabric.mod.json

We'll make a class called ArmorItemMixin, and write:

@Mixin (ArmorItem.class)
public abstract class ArmorItemMixin {
 
}

Now we have to make a @Shadow to modify knockbackResistance, which is an EntityAttribute

@Mixin (ArmorItem.class)
public abstract class ArmorItemMixin {
	@Shadow @Final private static UUID[] MODIFIERS;
	@Shadow @Final @Mutable private Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers;
	@Shadow @Final protected float knockbackResistance;
}

Next we @Inject our GENERIC_KNOCKBACK_RESISTANCE into the ArmorMaterial constructor.

@Mixin (ArmorItem.class)
public abstract class ArmorItemMixin {
 
    @Shadow @Final private static UUID[] MODIFIERS;
    @Shadow @Final @Mutable private Multimap<EntityAttribute, EntityAttributeModifier> attributeModifiers;
    @Shadow @Final protected float knockbackResistance;
 
    @Inject(method = "<init>", at = @At(value = "RETURN"))
    private void constructor(ArmorMaterial material, EquipmentSlot slot, Item.Settings settings, CallbackInfo ci) {
        UUID uUID = MODIFIERS[slot.getEntitySlotId()];
 
        if (material == RegisterItems.customArmorMaterial) {
            ImmutableMultimap.Builder<EntityAttribute, EntityAttributeModifier> builder = ImmutableMultimap.builder();
 
            this.attributeModifiers.forEach(builder::put);
 
            builder.put(
                    EntityAttributes.GENERIC_KNOCKBACK_RESISTANCE,
                    new EntityAttributeModifier(uUID,
                            "Armor knockback resistance",
                            this.knockbackResistance,
                            EntityAttributeModifier.Operation.ADDITION
                    )
            );
 
            this.attributeModifiers = builder.build();
        }
    }
 
}

Now your armor has the knockback resistance value you assigned to it back on CustomArmorMaterial.

zh_cn/tutorial/armor.1660095618.txt.gz · Last modified: 2022/08/10 01:40 by xtexchooser