Heads up!
This page assumes you have exported the assets properly as per How to Export Your Project
How to animate Armor
Creating your custom AzItemAnimator
For this, you will create a class which extends AzItemAnimator
. This class will handle the registration of animation controllers and providing the animation file's location for the animations.
Example:
public class ExampleArmorAnimator extends AzItemAnimator {private static final ResourceLocation ANIMATIONS = ResourceLocation.fromNamespaceAndPath(YOUR_MOD_ID,"animations/item/examplearmor.animation.json");@Overridepublic void registerControllers(AzAnimationControllerContainer<ItemStack> animationControllerContainer) {animationControllerContainer.add(AzAnimationController.builder(this, "base_controller").build());}@Overridepublic @NotNull ResourceLocation getAnimationLocation(ItemStack animatable) {return ANIMATIONS;}}
Some highlights of the above example.
-
ANIMATIONS
: This stores theResourceLocation
reference to the animation JSON file. You need to replaceYOUR_MOD_ID
with your mod's ID and ensure the file path matches your JSON animation file. -
registerControllers()
Registers the animation controllers that will define the animation behavior and states for the item. You can multiple if needed.
Creating an Animation Dispatcher
This class isn't required but is highly suggested to help store your animation commands to call in other classes.
Example:
public class ExampleArmorDispatcher {private static final AzCommand EQUIP_COMMAND = AzCommand.create("base_controller","equipping",AzPlayBehaviors.PLAY_ONCE);private static final AzCommand IDLE_COMMAND = AzCommand.create("base_controller","idle",AzPlayBehaviors.LOOP);public void equip(Entity entity, ItemStack itemStack) {EQUIP_COMMAND.sendForItem(entity, itemStack);}public void idle(Entity entity, ItemStack itemStack) {IDLE_COMMAND.sendForItem(entity, itemStack);}}
Accessing your Dispatcher to trigger animations
You will now define your ExampleArmorDispatcher from above in your ArmorItem class.
Example:
public class ExampleArmor extends ArmorItem {// This is your class where you will setup the AzCommands/Animations you wish to playpublic final ExampleArmorDispatcher dispatcher;public ExampleArmor(Type type) {super(ArmorMaterials.NETHERITE, type, new Properties());// Create the instance of the class here to use later.this.dispatcher = new ExampleArmorDispatcher();}}
Now you can all your dispatcher in to trigger different animations, like if you want to trigger one when equipping the armor piece:
@Overridepublic @NotNull InteractionResultHolder<ItemStack> swapWithEquipmentSlot(Item item,Level level,Player player,InteractionHand hand) {var result = super.swapWithEquipmentSlot(item, level, player, hand);if (!level.isClientSide) {var slot = getEquipmentSlot();var itemStack = player.getItemBySlot(slot);// This is where you now trigger an animation to playdispatcher.equip(player, itemStack);}return result;}
or trigger an idle animation that should play all the time:
@Overridepublic void inventoryTick(ItemStack stack, Level level, Entity entity, int slotId, boolean isSelected) {if (!level.isClientSide && entity instanceof Player player ) {player.getArmorSlots().forEach(wornArmor -> {if (wornArmor != null && wornArmor.is(YourItemRegistry.YOUR_ARMOR_CHESTPLATE)) {dispatcher.serverIdleArmor(player, wornArmor);}});}}
Creating your Renderer
This renderer is responsible for how your armor is displayed in the game.
It connects the armor with the following:
- Geometry file (
geo.json
): Defines the 3D model of the armor. - Texture file (
.png
): The visual appearance of the armor (applies over the geometry). - Animator: Animations for the armor, provided by
ExampleArmorAnimator
.
Heads up!
See AzRendererConfigs 101 for all AzArmorRendererConfig#builder options.
public class ExampleArmorRenderer extends AzArmorRenderer {private static final ResourceLocation GEO = ResourceLocation.fromNamespaceAndPath(YOUR_MOD_ID,"geo/item/examplearmor.geo.json");private static final ResourceLocation TEX = ResourceLocation.fromNamespaceAndPath(YOUR_MOD_ID,"textures/item/examplearmor.png");public ExampleArmorRenderer() {super(AzArmorRendererConfig.builder(GEO, TEX).setAnimatorProvider(ExampleArmorAnimator::new).build());}}
Registering your Renderer
Now simply call the AzArmorRendererRegistry#register()
in your onInitializeClient
for Fabric and FMLClientSetupEvent
for Neoforge/Forge
AzArmorRendererRegistry.register(ExampleArmorRenderer::new, YourItemRegistry.YOUR_ARMOR_HELMET,YourItemRegistry.YOUR_ARMOR_CHESTPLATE,YourItemRegistry.YOUR_ARMOR_LEGGINGS,YourItemRegistry.YOUR_ARMOR_BOOTS);
Registering your Armor for proper animation triggering
To ensure trigger animations work properly, you will need to also call AzIdentityRegistry#register()
in your onInitialize
for Fabric and FMLCommonSetupEvent
for NeoForge/Forge like so:
AzIdentityRegistry.register(YourItemRegistry.YOUR_ARMOR_HELMET,YourItemRegistry.YOUR_ARMOR_CHESTPLATE,YourItemRegistry.YOUR_ARMOR_LEGGINGS,YourItemRegistry.YOUR_ARMOR_BOOTS);