Хотя броня немного сложнее в реализации, чем обычный блок или предмет, как только вы поймете ее логику, броню станет проще реализовать. Чтобы добавить броню, мы сначала создадим класс CustomArmorMaterial
, а затем зарегистрируем предметы. Мы также рассмотрим, как их текстурировать. В конце этого документа есть специальная глава, в которой объясняется, как добавить сопротивление откидыванию к броне, поскольку этот метод доступен только через миксин (начиная с 1.16.3).
Пример этого документа можно найти в репозитории мода в GitHub'е.
Поскольку новая броня должна быть установлена с новым именем (а также дополнительными функциями, такими как очки брони и прочность), нам придется создать новый класс для нашего CustomArmorMaterial
.
Этот класс будет реализовывать ArmorMaterial
, и он начнет с присвоения значений точкам брони (называемых PROTECTION_VALUES
). Все его следующие аргументы будут использовать @Override
.
public class CustomArmorMaterial implements ArmorMaterial { private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11}; private static final int[] PROTECTION_VALUES = new int[] {A, B, C, D}; // Здесь A это шлем, B - нагрудник, C - поножи и D - ботинки. // Для справки, кожа использует {1, 2, 3, 1}, а алмаз/незерит {3, 6, 8, 3} }
Следующие аргументы определяются таким образом (не беспокойтесь об именах, вы увидите, как мы это реализуем под ними):
BASE_DURABILITY
для вычисления. Кожа использует 5, Алмаз 33, Незерит 37.PROTECTION_VALUES
, которое мы уже написали.SoundEvents.ITEM_ARMOR_EQUIP_X
, где X - тип брони.“diamond”
.X.0F
И новое значение, введенное на 1.16
0.XF
(в котором X - это степень защиты от откидывания, которую вы хотите), и я научу вас, как заставить его работать позже.Я оставлю все переменные записанными как X или A, B, C, D. С этими аргументами теперь это должно выглядеть примерно так:
public class CustomArmorMaterial implements ArmorMaterial { private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11}; private static final int[] PROTECTION_VALUES = new int[] {A, B, C, D}; @Override public int getDurability(EquipmentSlot slot) { return BASE_DURABILITY[slot.getEntitySlotId()] * X; } @Override public int getProtectionAmount(EquipmentSlot slot) { return PROTECTION_VALUES[slot.getEntitySlotId()]; } @Override public int getEnchantability() { return X; } @Override public SoundEvent getEquipSound() { return SoundEvents.ITEM_ARMOR_EQUIP_X; } @Override public Ingredient getRepairIngredient() { return Ingredient.ofItems(RegisterItems.X); } @Override // Всё должно быть маленькими буквами return "name"; } @Override public float getToughness() { return X.0F; } @Override public float getKnockbackResistance() { return 0.XF; } }
Теперь, когда у вас есть основы класса материалов брони, давайте зарегистрируем ваши предметы брони в новом классе, который мы просто назовем RegisterItems.
Мы собираемся создать новый класс под названием RegisterItems
для реализации ваших новых элементов брони. Это также будет место, например, для регистрации инструментов, если вы создаете новый предмет, такой как слиток (мы будем называть его Custom_Material
). . Эта настройка также поместит предметы на новую вкладку предметов в креативе, но вы можете удалить эту часть.
Синтаксис групп - .group(YourModName.YOUR_MOD_NAME_BUT_IN_CAPS_GROUP). Я буду ссылаться на это как на ExampleMod
:
public class RegisterItems { public static final ArmorMaterial CUSTOM_ARMOR_MATERIAL = new CustomArmorMaterial(); public static final Item CUSTOM_MATERIAL = new CustomMaterialItem(new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); // Если бы вы создали новый материал, вы бы отметили его именно здесь. public static final Item CUSTOM_MATERIAL_HELMET = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.HEAD, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); public static final Item CUSTOM_MATERIAL_CHESTPLATE = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.CHEST, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); public static final Item CUSTOM_MATERIAL_LEGGINGS = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.LEGS, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); public static final Item CUSTOM_MATERIAL_BOOTS = new ArmorItem(CUSTOM_ARMOR_MATERIAL, EquipmentSlot.FEET, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); }
Теперь, когда ваши элементы созданы должным образом, давайте зарегистрируем их и дадим им правильные имена. Вашим первым параметром будет ваше пространство имен, которое является вашим идентификатором мода, а затем следующим - имя, которое вы хотите присвоить своему элементу.
Мы напишем это прямо под вашим последним ArmorItem
.
public static void register() { }
Ваши доспехи готовы. Теперь мы просто вызовем регистрацию в нашем основном классе (и запишем новую группу).
public static final ItemGroup EXAMPLE_MOD_GROUP = FabricItemGroupBuilder.create( new Identifier("examplemod", "example_mod_group")) .icon(() -> new ItemStack(RegisterItems.CUSTOM_MATERIAL)) // Здесь в качестве значка используется модель нового материала, который вы создали, но вы можете ссылаться на все, что вам нравится .build(); @Override public void onInitialize() { RegisterItems.register(); }
Вот и все! Теперь ваша броня должна существовать в игре, все еще нетекстурированная, но присутствующая и способная быть выданной с помощью /give.
Теперь мы будем присваивать текстуры каждой детали.
Мы предполагаем, что у вас
x_helmet.png
, x_chestplate.png
и т.д.)x_layer_1.png
и x_layer_2.png
)Нужно назначить их каждому предмету брони.
Следующий код должен быть одинаковым со всеми предметами брони, меняется только то, какую часть мы используем. Мы будем использовать шлем для нашего примера.
{ "parent": "item/generated", "textures": { "layer0": "examplemod:item/custom_material_helmet" } }
Повторите со всеми предметами брони.
Чтобы придать вашей броне текстуру, просто поместите X_layer_1.png
и X_layer_2.png
(где X - аргумент getName
, который вы выбрали в своем классе материалов брони) в resources/assets/minecraft/textures/models/armor
.
Если вы следовали всем инструкциям, то теперь у вас должен быть полный комплект брони!
И вот пришли к самому проклятому!
Mojang решили, что они не только собираются жестко запрограммировать getKnockbackResistance
, но и сделают его неизменяемым! Забавная штука.
Чтобы обойти это, мы собираемся сделать миксин, который войдет в ArmorItem
. Если это ваш первый раз, здесь о том, как зарегистрировать миксины в вашем fabric.mod.json
Мы создадим класс под названием ArmorItemMixin
и напишем:
@Mixin (ArmorItem.class) public abstract class ArmorItemMixin { }
Теперь мы должны создать @Shadow, чтобы изменить knockbackResistance
, который является 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; }
Затем мы внедряем через @Inject
наш GENERIC_KNOCKBACK_RESISTANCE
в конструктор ArmorMaterial
.
@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(); } } }
Теперь ваша броня имеет значение сопротивления откидыванию, которое вы присвоили ей еще в CustomArmorMaterial
.