tutorial:armor
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionNext revisionBoth sides next revision | ||
tutorial:armor [2020/10/09 19:04] – Knockback warning sakira | tutorial:armor [2021/03/06 12:53] – [Creating an Armor Material class] fix typo juuz | ||
---|---|---|---|
Line 3: | Line 3: | ||
==== Introduction ==== | ==== Introduction ==== | ||
- | While Armor is a bit more complicated to add then a normal block/item, once you can understand it, it becomes simple to make. | + | While armor is a bit more complicated to implement than a normal block or item, once you understand it, it becomes simple to implement. To add armor, we'll first make a CustomArmorMaterial class, then register the items. We'll also take a look at how to texture them. There' |
- | To add Armor, we'll first make a CustomArmorMaterial class, then register the items. We'll also take a look at how to texture them. | + | |
- | There' | + | An example for this document can be found in [[https:// |
==== Creating an Armor Material class ==== | ==== Creating an Armor Material class ==== | ||
- | Since new armor needs to be set with a new name (as well as extra things like armor points and durability), | + | Since new armor needs to be set with a new name (as well as extra things like armor points and durability), |
- | This class will implement ArmorMaterial and will be an enum type. It' | + | This class will implement ArmorMaterial, and it' |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public | + | public |
- | | + | private static final int[] BASE_DURABILITY = new int[] {13, 15, 16, 11}; |
- | + | private static final int[] PROTECTION_VALUES = new int[] {A, B, C, D}; | |
- | } | + | |
+ | // In which A is helmet, B chestplate, C leggings and D boots. | ||
+ | // For reference, Leather uses {1, 2, 3, 1}, and Diamond/ | ||
} | } | ||
</ | </ | ||
- | Since there' | + | The next arguments |
- | - A String name. This will be used as a sort of "armor tag" for later. | + | - getDurability: |
- | - A durability multiplier. This will be the number that will be used to determine the durability based on the base values. | + | - getProtectionAmount: |
- | - Armor values, or " | + | - getEnchantability: |
- | - Enchantability. | + | - SoundEvent getEquipSound: |
- | - A sound event. | + | - Ingredient getRepairIngridient: |
- | - Toughness. This is a second protection value where the armor is more durable against high value attacks. | + | - String getName: what the parent item of the armor is. In Diamond armor, it'd be " |
- | - A repair ingredient. This will be a '' | + | - getToughness: |
- | If you' | + | And the new value introduced |
- | - Knockback Resistance. This is the scale of the amount of knockback | + | - getKnockbackResistance: |
- | With those arguments, it should now look something like this: | ||
- | <code java [enable_line_numbers=" | + | I'll leave all variables written as X or A, B, C, D. With those arguments, it should |
- | public enum CustomArmorMaterial implements ArmorMaterial { | + | |
- | CustomArmorMaterial(String name, int durabilityMultiplier, int[] armorValueArr, int enchantability, SoundEvent soundEvent, float toughness, float knockbackResistance, | + | |
- | + | ||
- | } | + | |
- | } | + | |
- | </ | + | |
- | + | ||
- | We'll also have to define those values and make it usable, so now it' | + | |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public | + | public |
- | | + | private |
- | | + | private |
- | private final int[] armorValues; | + | |
- | private final int enchantability; | + | |
- | private final SoundEvent equipSound; | + | |
- | private final float toughness; | + | |
- | private final float knockbackResistance; | + | |
- | private final Lazy< | + | |
- | + | ||
- | CustomArmorMaterial(String name, int durabilityMultiplier, | + | |
- | this.name = name; | + | |
- | this.durabilityMultiplier = durabilityMultiplier; | + | |
- | this.armorValues = armorValueArr; | + | |
- | this.enchantability = enchantability; | + | |
- | this.equipSound = soundEvent; | + | |
- | this.toughness = toughness; | + | |
- | this.knockbackResistance = knockbackResistance; | + | |
- | this.repairIngredient = new Lazy(repairIngredient); | + | |
- | } | + | |
- | } | + | |
- | </ | + | |
- | '' | + | @Override |
+ | public int getDurability(EquipmentSlot slot) { | ||
+ | return BASE_DURABILITY[slot.getEntitySlotId()] * X; | ||
+ | } | ||
- | We'll also have to add our base durability values, so for now we'll use the vanilla values '' | + | @Override |
+ | public int getProtectionAmount(EquipmentSlot slot) { | ||
+ | return PROTECTION_VALUES[slot.getEntitySlotId()]; | ||
+ | } | ||
- | <code java [enable_line_numbers=" | + | @Override |
- | public | + | public int getEnchantability() { |
- | private static final int[] baseDurability = {13, 15, 16, 11}; | + | return |
- | private final String name; | + | } |
- | private final int durabilityMultiplier; | + | |
- | private final int[] armorValues; | + | |
- | private final int enchantability; | + | |
- | private final SoundEvent equipSound; | + | |
- | private final float toughness; | + | |
- | private final float knockbackResistance; | + | |
- | private final Lazy< | + | |
- | + | ||
- | CustomArmorMaterial(String name, int durabilityMultiplier, | + | |
- | | + | |
- | this.durabilityMultiplier = durabilityMultiplier; | + | |
- | this.armorValues = armorValueArr; | + | |
- | this.enchantability = enchantability; | + | |
- | this.equipSound = soundEvent; | + | |
- | this.toughness = toughness; | + | |
- | this.repairIngredient = new Lazy(repairIngredient); | + | |
- | } | + | |
- | + | ||
- | public int getDurability(EquipmentSlot equipmentSlot_1) { | + | |
- | | + | |
- | } | + | |
- | | + | @Override |
- | return | + | public |
- | } | + | return |
+ | } | ||
- | | + | @Override |
- | return | + | public |
- | } | + | return |
+ | } | ||
- | | + | @Override |
- | return | + | public |
- | } | + | return |
+ | } | ||
- | | + | @Override |
- | // We needed to make it a Lazy type so we can actually get the Ingredient from the Supplier. | + | public |
- | | + | return |
- | } | + | } |
- | | + | @Override |
- | public String getName() { | + | public float getKnockbackResistance() { |
- | return this.name; | + | return |
- | } | + | } |
- | + | ||
- | public float getToughness() { | + | |
- | return this.toughness; | + | |
- | } | + | |
- | | + | |
- | public float getKnockbackResistance() { | + | |
- | return | + | |
- | } | + | |
} | } | ||
</ | </ | ||
- | Now that you have the basics of the armor material class, | + | |
+ | Now that you have the basics of the armor material class, | ||
+ | |||
+ | ==== Creating Armor Items ==== | ||
+ | |||
+ | We're gonna make a new class called RegisterItems to implement | ||
+ | |||
+ | The syntax of groups is // | ||
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public | + | public |
- | WOOL(" | + | |
- | return Ingredient.ofItems(Items.WHITE_WOOL); | + | |
- | | + | |
- | | + | // If you made a new material, this is where you would note it. |
+ | public static final Item CUSTOM_MATERIAL_HELMET = new ArmorItem(CustomArmorMaterial, EquipmentSlot.HEAD, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); | ||
+ | public static final Item CUSTOM_MATERIAL_CHESTPLATE = new ArmorItem(CustomArmorMaterial, EquipmentSlot.CHEST, new Item.Settings().group(ExampleMod.EXAMPLE_MOD_GROUP)); | ||
+ | | ||
+ | | ||
} | } | ||
</ | </ | ||
- | Feel free to change any values. | + | Now that your items are properly created, lets register them and give them proper names. Your first parameter is going to be your namespace, which is your ModID, and then next one the name you want to give to your item. |
- | + | ||
- | ==== Creating Armor Items ==== | + | |
- | Back in the main class, you can now create it like so: | + | We'll be writing this right below your last ArmorItem. |
<code java [enable_line_numbers=" | <code java [enable_line_numbers=" | ||
- | public | + | public |
- | | + | Registry.register(Registry.ITEM, new Identifier(" |
- | | + | Registry.register(Registry.ITEM, new Identifier(" |
- | | + | Registry.register(Registry.ITEM, new Identifier(" |
- | | + | Registry.register(Registry.ITEM, new Identifier(" |
+ | Registry.register(Registry.ITEM, new Identifier(" | ||
} | } | ||
</ | </ | ||
- | ==== Registering Armor Items ==== | + | Your armor items are done. Now we'll just call the Registry on our main class (and annotate the new group). |
- | Register them the same way you'd register a normal item. | + | <code java [enable_line_numbers=" |
+ | public static final ItemGroup EXAMPLE_MOD_GROUP = FabricItemGroupBuilder.create( | ||
+ | new Identifier(" | ||
+ | .icon(() -> new ItemStack(RegisterItems.CUSTOM_MATERIAL)) // This uses the model of the new material you created as an icon, but you can reference to whatever | ||
+ | | ||
- | <code java [enable_line_numbers=true]> | + | @Override |
- | [...] | + | |
public void onInitialize() { | public void onInitialize() { | ||
- | | + | |
- | Registry.register(Registry.ITEM, | + | |
- | Registry.register(Registry.ITEM, | + | |
- | Registry.register(Registry.ITEM, | + | |
} | } | ||
</ | </ | ||
+ | |||
+ | That's it! Your armor should now exist in game, untextured still, but present and able to be given with /give. | ||
+ | |||
+ | Now we'll be assigning the textures to each piece. | ||
+ | |||
+ | |||
==== Texturing ==== | ==== Texturing ==== | ||
- | Since you already know how to make item models and textures, we won't go over them here. (They' | + | We're going to assume |
+ | * Have the textures for each armor item (x_helmet.png, x_chestplate.png etc.) | ||
+ | * Have the textures | ||
- | < | + | And assign them to each armor item. |
+ | |||
+ | The following should be the same with all armor items, only changing which part are we using. We'll use helmet for our example. | ||
+ | |||
+ | < | ||
{ | { | ||
- | | + | "parent": |
- | "pack_format": | + | "textures": |
- | "description": "Tutorial Mod" | + | "layer0": "examplemod: |
- | } | + | } |
} | } | ||
</ | </ | ||
- | Now you can finally place your textures here in '' | + | Repeat with all armor items. |
+ | |||
+ | To give your on-body armor a texture, simply place X_layer_1.png and X_layer_2.png (where X is the getName argument | ||
+ | |||
If you followed everything, you should now be able to have a full armor set! | If you followed everything, you should now be able to have a full armor set! | ||
+ | |||
+ | ====Adding Knockback Protection==== | ||
+ | |||
+ | And here comes the so very cursed! | ||
+ | |||
+ | Mojang decided that they were not only going to hardcode getKnockbackResistance, | ||
+ | |||
+ | To get around this, we're gonna make a mixin that goes into ArmorItem. If this is your first time, [[tutorial: | ||
+ | |||
+ | We'll make a class called ArmorItemMixin, | ||
+ | |||
+ | <code java [enable_line_numbers:" | ||
+ | @Mixin (ArmorItem.class) | ||
+ | public abstract class ArmorItemMixin { | ||
+ | |||
+ | } | ||
+ | </ | ||
+ | |||
+ | Now we have to make a @Shadow to modify knockbackResistance, | ||
+ | |||
+ | <code java [enable_line_numbers:" | ||
+ | @Mixin (ArmorItem.class) | ||
+ | public abstract class ArmorItemMixin { | ||
+ | @Shadow @Final private static UUID[] MODIFIERS; | ||
+ | @Shadow @Final @Mutable private Multimap< | ||
+ | @Shadow @Final protected float knockbackResistance; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Next we @Inject our GENERIC_KNOCKBACK_RESISTANCE into the ArmorMaterial constructor. | ||
+ | |||
+ | <code java [enable_line_numbers:" | ||
+ | @Mixin (ArmorItem.class) | ||
+ | public abstract class ArmorItemMixin { | ||
+ | |||
+ | @Shadow @Final private static UUID[] MODIFIERS; | ||
+ | @Shadow @Final @Mutable private Multimap< | ||
+ | @Shadow @Final protected float knockbackResistance; | ||
+ | | ||
+ | @Inject(method = "< | ||
+ | private void constructor(ArmorMaterial material, EquipmentSlot slot, Item.Settings settings, CallbackInfo ci) { | ||
+ | UUID uUID = MODIFIERS[slot.getEntitySlotId()]; | ||
+ | |||
+ | if (material == RegisterItems.customArmorMaterial) { | ||
+ | ImmutableMultimap.Builder< | ||
+ | |||
+ | this.attributeModifiers.forEach(builder:: | ||
+ | |||
+ | 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. |
tutorial/armor.txt · Last modified: 2024/07/04 16:32 by mineblock11