====== Добавление брони ======
==== Вступление ====
Хотя броня немного сложнее в реализации, чем обычный блок или предмет, как только вы поймете ее логику, броню станет проще реализовать. Чтобы добавить броню, мы сначала создадим класс ''CustomArmorMaterial'', а затем зарегистрируем предметы. Мы также рассмотрим, как их текстурировать. В конце этого документа есть специальная глава, в которой объясняется, как добавить сопротивление откидыванию к броне, поскольку этот метод доступен только через миксин (начиная с 1.16.3).
Пример этого документа можно найти в [[https://github.com/gdude2002/Gilded-Netherite|репозитории мода в 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}
}
Следующие аргументы определяются таким образом (не беспокойтесь об именах, вы увидите, как мы это реализуем под ними):
* **getDurability:** Сколько ударов может выдержать броня, прежде чем сломается. Использует число, которое мы написали для ''BASE_DURABILITY'' для вычисления. Кожа использует 5, Алмаз 33, Незерит 37.
* **getProtectionAmount:** Вызывает число ''PROTECTION_VALUES'', которое мы уже написали.
* **getEnchantability:** Это будет зависеть от того, насколько вероятно, что броня может получить высокий уровень или несколько зачарований в книге зачарований.
* **SoundEvent getEquipSound:** Стандарт, используемый в ванильной броне - ''SoundEvents.ITEM_ARMOR_EQUIP_X'', где X - тип брони.
* **Ingredient getRepairIngredient:** Какой предмет мы будем использовать для ремонта брони на наковальне. Это может быть как ванильный предмет, так и один из ваших собственных.
* **String getName:** Какой родительский элемент брони. В алмазной броне это было бы ''"diamond"''.
* **getToughness:** Это второе значение защиты, при котором броня более прочна против атак с высоким значением. Отображается как ''X.0F''
И новое значение, введенное на 1.16
* **getKnockbackResistance:** Оставим это значение равным 0. Если вы хотите его реализовать, напишите ''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
public String getName() {
// Всё должно быть маленькими буквами
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() {
Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material"), CUSTOM_MATERIAL);
Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_helmet"), CUSTOM_MATERIAL_HELMET);
Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_chestplate"), CUSTOM_MATERIAL_CHESTPLATE);
Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_leggings"), CUSTOM_MATERIAL_LEGGINGS);
Registry.register(Registry.ITEM, new Identifier("examplemod", "custom_material_boots"), CUSTOM_MATERIAL_BOOTS);
}
Ваши доспехи готовы. Теперь мы просто вызовем регистрацию в нашем основном классе (и запишем новую группу).
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''. Если это ваш первый раз, [[ru:tutorial:mixin_registration|здесь о том, как зарегистрировать миксины в вашем 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 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 attributeModifiers;
@Shadow @Final protected float knockbackResistance;
@Inject(method = "", 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 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''.