Table of Contents

Making a Custom Shield in Minecraft [1.19-1.21.1]

:!: The tutorial depends on third-party libraries.

Congrats! You just learned how to create your custom tools in the last tutorial! Now imagine you want to shield yourself from that sword if your friend got it. If you made it too op, a regular shield won't do. So we will see how to make a custom shield.

Luckily, StellarWind22 has already made a library to help with this! If she didn't, you probably would be sitting here for the next hour following this tutorial, so thanks StellarWind22!

The library source is available at https://github.com/CrimsonDawn45/Fabric-Shield-Lib

Library compiled as a jar is available at https://www.curseforge.com/minecraft/mc-mods/fabric-shield-lib

Adding the library to your project

Add the following code to the files mentioned:

gradle.properties

gradle.properties
fabric_shield_lib_version=1.7.2-1.21.1
midnightlib_version=1.5.8-fabric
mod_menu_version=11.0.1
fabricasm_version=2.3

build.gradle (under dependencies block)

build.gradle
	modImplementation "com.github.CrimsonDawn45:Fabric-Shield-Lib:v${project.fabric_shield_lib_version}"
	modImplementation "com.terraformersmc:modmenu:${project.mod_menu_version}"
	modImplementation "maven.modrinth:midnightlib:${project.midnightlib_version}"
	modImplementation "com.github.Chocohead:Fabric-ASM:v${project.fabricasm_version}"

At the time of writing, the latest project.fabric_shield_lib_version should be 1.7.2, which supports versions:

build.gradle (inside repositories block)

build.gradle
	maven {url = 'https://jitpack.io'}
	maven {url "https://maven.terraformersmc.com/releases/"}
	maven {url = "https://api.modrinth.com/maven"}


Midnight Lib and FabricASM are included in the FabricShieldLib release (.jar on Curseforge/Modrinth) but need to be used as dependencies when developing

Adding a custom shield

If you want your shield to support banner decoration on your shield, please skip to the next section

On to the non-boring steps! We will now make a custom shield!

If you have followed the above steps correctly and refreshed the project, then you will have the FabricShieldLib installed.

If so, the first step to do is create a new instance of an Item (see items tutorial), like:

TutorialItems
public final class TutorialItems {
    // ...
    public static final Item NETHERITE_SHIELD = register(new FabricShieldItem(new FabricItemSettings().maxDamage(2500), 10, 13, Items.NETHERITE_INGOT), "netherite_shield"); 
    //The constructor for the item takes in the following values: FabricBannerShieldItem(settings.maxDamage(durability), cooldownTicks, enchantability, repairItems
    // ...
}

If you want to add your shield to a item groups, for example, the “Combat” group, use:

ExampleMod
public class ExampleMod implements ModInitializer {
    @Override
    public void onInitialize() {
        ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register(entries -> {
            entries.add(NETHERITE_SHIELD);
        });
    }
}

And our shield is (code-wise) done!

Now, we have to create the textures and models of the shield.

For the texture, you can use anything. A good place to start is to look at Mojang's shield texture and change it. Put it in resources/assets/tutorial/textures/item/netherite_shield.png

Now, for the models, we have to write a few .json files.

Inside resources/assets/tutorial/models/item/, create a netherite_shield.json file and put this inside it:

resources/assets/tutorial/models/item/netherite_shield.json
{
    "parent":"fabricshieldlib:item/fabric_shield",
    "textures":{
        "shield":"tutorial:item/netherite_shield"
    },
    "overrides": [
        {
            "predicate": {
                "blocking": 1
            },
            "model": "tutorial:item/netherite_shield_blocking"
        }
    ]
}

In the same folder, create another file, netherite_shield_blocking.json, and put his inside it:

resources/assets/tutorial/models/item/netherite_shield_blocking.json
{
  "parent": "fabricshieldlib:item/fabric_shield_blocking",
  "textures":{
    "shield":"tutorial:item/netherite_shield"
  }
}

Then, as a conventional tag, create a shield.json file in resources/data/c/tags/item/tools/shield.json and add your shield to it:

resources/data/c/tags/items/shields.json
{
  "replace": false,
  "values": [
    "tutorial:netherite_shield"
  ]
}

Lastly, to make it enchantable, create a durability.json file in resources/data/minecraft/tags/item/enchantable/durability.json and add your shield to it:

resources/data/minecraft/tags/item/enchantable/durability.json
{
  "replace": false,
  "values": [
    "tutorial:netherite_shield"
  ]
}

Don't forget to add it to en_us.json in resources/assets/tutorial/lang/en_us.json

resources/assets/tutorial/lang/en_us.json
{
  "item.tutorial.netherite_shield": "Netherite Shield"
}


And with that, your non-decorateable shield is done!

Adding a custom shield with banner support

The process is slightly different if you want to make your shield accept banners and decorateable like a vanilla shield.

We still make the item in the same way, just make it a FabricBannerShieldItem:

TutorialItems
    public static final Item NETHERITE_BANNER_SHIELD = register(new FabricBannerShieldItem(new FabricItemSettings().maxDamage(2500), 10, 13, Items.NETHERITE_INGOT), "netherite_banner_shield");

If you want to add your shield to a item groups, for example, the “Combat” group, use:

ExampleMod
public class ExampleMod implements ModInitializer {	 
    @Override	 
    public void onInitialize() {	 
        ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register(entries -> {	 
            // ...	 
            entries.add(NETHERITE_BANNER_SHIELD);	 
        });	 
    }	 
}	 

Now the item is created, we need to set up its rendering. For these steps, we are going to be working in our client mod initializer, which should already be set up for you in the fabric example mod.

First, we will need to create an EntityModelLayer to use later.

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
    public static final EntityModelLayer NETHERITE_BANNER_SHIELD_MODEL_LAYER = new EntityModelLayer(Identifier.of("tutorial", "netherite_banner_shield"),"main");
 
    @Override
    public void onInitializeClient() {
 
    }
}

Next, we will register out EntityModelLayer that we made previously.

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
 
    public static final EntityModelLayer NETHERITE_SHIELD_MODEL_LAYER = new EntityModelLayer(Identifier.of("tutorial", "netherite_shield"),"main"); ​
 
    @Override
    public void onInitializeClient() {
	EntityModelLayerRegistry.registerModelLayer(NETHERITE_BANNER_SHILED_MODEL_LAYER, ShieldEntityModel::getTexturedModelData);
    }
}

Then we will create our shield model,

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
    public static final EntityModelLayer NETHERITE_SHIELD_MODEL_LAYER = new EntityModelLayer(Identifier.of("tutorial", "netherite_shield"), "main"); ​
 
    public static ShieldEntityModel modelNetheriteShield;
 
    @Override
    public void onInitializeClient() {
        EntityModelLayerRegistry.registerModelLayer(NETHERITE_SHIELD_MODEL_LAYER, ShieldEntityModel::getTexturedModelData);
    }
}

And then register that shield model,

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
    public static final EntityModelLayer NETHERITE_SHIELD_MODEL_LAYER = new EntityModelLayer(Identifier.of("tutorial", "netherite_shield"),"main"); ​
 
    public static ShieldEntityModel modelNetheriteShield;
 
    @Override
    public void onInitializeClient() {
        EntityModelLayerRegistry.registerModelLayer(NETHERITE_SHIELD_MODEL_LAYER, ShieldEntityModel::getTexturedModelData);
 
        ShieldSetModelCallback.EVENT.register((loader) -> {
	    modelNetheriteShield = new ShieldEntityModel(loader.getModelPart(netherite_banner_shield_model_layer));
	    return ActionResult.PASS;
	});
    }
}

Next, we have to create our two SpriteIdentifiers,

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
 
	public static final EntityModelLayer netherite_banner_shield_model_layer = new EntityModelLayer(Identifier.of("tutorial", "netherite_banner_shield"), "main");
 
	public static ShieldEntityModel modelNetheriteShield;
 
	public static final SpriteIdentifier NETHERITE_BANNER_SHIELD_BASE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier.of("tutorial", "entity/netherite_banner_shield_base"));
	public static final SpriteIdentifier NETHERITE_BANNER_SHIELD_BASE_NO_PATTERN = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier.of("tutorial", "entity/netherite_banner_shield_base_nopattern"));
 
	@Override
	public void onInitializeClient() {
            EntityModelLayerRegistry.registerModelLayer(NETHERITE_SHIELD_MODEL_LAYER, ShieldEntityModel::getTexturedModelData);
 
            ShieldSetModelCallback.EVENT.register((loader) -> {
	        modelNetheriteShield = new ShieldEntityModel(loader.getModelPart(netherite_banner_shield_model_layer));
	        return ActionResult.PASS;
	    });
	}
}

Finally, we are going to register our shield with the BuiltinItemRendererRegistry,

@Environment(EnvType.CLIENT)
public class ExampleModClient implements ClientModInitializer {
	public static final EntityModelLayer netherite_banner_shield_model_layer = new EntityModelLayer(Identifier.of("tutorial", "netherite_banner_shield"),"main");
 
	public static ShieldEntityModel modelNetheriteShield;
 
	public static final SpriteIdentifier NETHERITE_BANNER_SHIELD_BASE = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier.of("tutorial", "entity/netherite_banner_shield_base"));
	public static final SpriteIdentifier NETHERITE_BANNER_SHIELD_BASE_NO_PATTERN = new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, Identifier.of("tutorial", "entity/netherite_banner_shield_base_nopattern"));
 
	@Override
	public void onInitializeClient() {
            EntityModelLayerRegistry.registerModelLayer(NETHERITE_SHIELD_MODEL_LAYER, ShieldEntityModel::getTexturedModelData);
 
            ShieldSetModelCallback.EVENT.register((loader) -> {
	        modelNetheriteShield = new ShieldEntityModel(loader.getModelPart(netherite_banner_shield_model_layer));
	        return ActionResult.PASS;
	    });
 
            BuiltinItemRendererRegistry.INSTANCE.register(ExampleMod.NETHERITE_BANNER_SHIELD, (stack, mode, matrices, vertexConsumers, light, overlay) -> {
		renderBanner(stack, matrices, vertexConsumers, light, overlay, modelNetheriteShield, NETHERITE_BANNER_SHIELD_BASE, NETHERITE_BANNER_SHIELD_BASE_NO_PATTERN);
                //The first five parameters are taken from the method, while the last 3 you provide yourself. You will provide the model, and then your 2 sprite identifiers in the order of SHIELD_NAME_BASE and then SHIELD_NAME_BASE_NOPATTERN.
	    });
	}
}

That is all of our code done, we only have a few json files to make.

First, create a blocks.json file inside of resources/assets/minecraft/atlases/. Inside of it, you will have to list your SpriteIdentifiers from your client mod initializer like this:

resources/assets/minecraft/atlases/blocks.json
{
  "sources": [
    {
      "type": "single",
      "resource": "tutorial:entity/netherite_banner_shield_base"
    },
    {
      "type": "single",
      "resource": "tutorial:entity/netherite_banner_shield_base_nopattern"
    }
  ]
}

Next, inside resources/assets/tutorial/models/item/, create a netherite_banner_shield.json file and put this inside it:

resources/assets/tutorial/models/item/etherite_banner_shield.json
{
  "parent":"fabricshieldlib:item/fabric_banner_shield",
  "overrides": [
    {
      "predicate": {
        "blocking": 1
      },
      "model": "tutorial:item/netherite_banner_shield_blocking"
    }
  ]
}

In the same folder, create another file, netherite_banner_shield_blocking.json, and put his inside it:

resources/assets/tutorial/models/item/etherite_banner_shield_blocking.json
{
  "parent":"fabricshieldlib:item/fabric_banner_shield_blocking",
  "textures":{
    "shield":"tutorial:item/netherite_banner_shield"
  }
}

For this next step, you will add a netherite_shield_base_nopattern texture, which will be a standard shield texture. Then, you will need to make a base version for your shield texture, so netherite_shield_base. I recommend looking at the vanilla shield's base texture.

Then, you will move both of these textures into resources/assets/<modid>/textures/entity.

Next, create a shields.json file in resources/data/c/tags/items/shields.json and add your shield to it:

resources/data/c/tags/items/shields.json
{
  "replace": false,
  "values": [
    "tutorial:netherite_banner_shield"
  ]
}

Finally create a durability.json file in resources/data/minecraft/tags/item/enchantable/durability.json and add your shield to it:

resources/data/minecraft/tags/item/enchantable/durability.json
{
  "replace": false,
  "values": [
    "tutorial:netherite_banner_shield"
  ]
}

Don't forget to add it to en_us.json in resources/assets/lang/en_us.json along with the color variants,

{
  "item.tutorial.netherite_banner_shield": "Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.red": "Red Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.orange": "Orange Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.yellow": "Yellow Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.lime": "Lime Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.green": "Green Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.light_blue": "Light Blue Banner Netherite Shield",
  "item.tutorial.netherite_banner_shield.cyan": "Cyan Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.blue": "Blue Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.purple": "Purple Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.magenta": "Magenta Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.pink": "Pink Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.brown": "Brown Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.white": "White Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.light_gray": "Light Gray Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.gray": "Gray Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.dark_gray": "Dark Gray Netherite Banner Shield",
  "item.tutorial.netherite_banner_shield.black": "Black Netherite Banner Shield"
}

And now your shield is fully completed and supports banner decoration!

Changes for 1.20.6

If you are working in 1.20.6, first change the FabricShieldLib and FAPI versions accordingly and change your other dependencies to these versions:

gradle.properties
mod_menu_version=10.0.0-beta.1
midnightlib_version=1.5.5-fabric

Next, change all instances of Identifier.of to new Identifier; these are when you are registering your item, creating your EntityModelLayer, and creating your SpriteIdentifiers.

Then, change your shield.json in resources/data/c/tags/item/tools/shield.json to shields.json file in resources/data/c/tags/items/shields.json

Finally, move your durability.json from resources/data/minecraft/tags/items/enchantable/durability.json to resources/data/minecraft/tags/item/enchantable/durability.json

Changes for 1.20.4

If you are working in 1.20.4, follow the changes for 1.20.6 first, then change the FabricShieldLib and FAPI versions accordingly and change your other dependencies to these versions:

gradle.properties

gradle.properties
midnightlib_version=1.5.2-fabric
mod_menu_version=9.0.0-pre.1

Additionally, remove the durability.json file completely.

Changes for 1.19

If you are working in 1.19, follow the changes for 1.20.6 and 1.20.4 first, then change the FabricShieldLib and FAPI versions accordingly and change your other dependencies to these versions:

gradle.properties

gradle.properties
midnightlib_version=1.0.0-fabric
mod_menu_version=4.2.0-beta.2