Minecraft 1.21 Fabric 模組開發(1)-前置準備
Minecraft 1.21 Fabric 模組開發(2)-新增物品
Minecraft 1.21 Fabric 模組開發(3)-新增方塊
Minecraft 1.21 Fabric 模組開發(4)-資料產生(Data Generation)
寫在前頭
1.不是JAVA教學所以不解釋程式碼為何這樣寫,想知道為什麼這麼寫可以在 Fabric docs 或 Fabric wiki 裡面找到。
2.我的模組名稱為mays-mod
,程式碼中看到 mays-mod 的地方請自行換成你的 mod 名稱。
3.圖片看不清的話可以點擊放大看。
創建工具材質類
新增枚舉類 /java/com/<mod_id>/ModToolMaterial.java
:
package com.may.firstmod.item;
import com.may.firstmod.util.ModTags;
import net.minecraft.block.Block;
import net.minecraft.item.ToolMaterial;
import net.minecraft.recipe.Ingredient;
import net.minecraft.registry.tag.TagKey;
import java.util.function.Supplier;
public enum ModToolMaterial implements ToolMaterial {
// 可以參考 net/minecraft/item/ToolMaterials.java
CREEPER_INGOT(
ModTags.Blocks.INCORRECT_FOR_CREEPER_TOOL, // Inverse Tag: 該工具無法挖掘的內容
600, // 耐久度
4.5f, // 採礦速度
3.5f, // 攻擊傷害
25, // 附魔能力
() -> Ingredient.ofItems(ModItems.CREEPER_INGOT) // 修復道具
);
private final TagKey<Block> inverseTag;
private final int itemDurability;
private final float miningSpeed;
private final float attackDamage;
private final int enchantability;
private final Supplier<Ingredient> repairIngredient;
ModToolMaterial(TagKey<Block> inverseTag, int itemDurability, float miningSpeed, float attackDamage, int enchantability, Supplier<Ingredient> repairIngredient) {
this.inverseTag = inverseTag;
this.itemDurability = itemDurability;
this.miningSpeed = miningSpeed;
this.attackDamage = attackDamage;
this.enchantability = enchantability;
this.repairIngredient = repairIngredient;
}
@Override
public int getDurability() {
return this.itemDurability;
}
@Override
public float getMiningSpeedMultiplier() {
return this.miningSpeed;
}
@Override
public float getAttackDamage() {
return this.attackDamage;
}
@Override
public TagKey<Block> getInverseTag() {
return this.inverseTag;
}
@Override
public int getEnchantability() {
return this.enchantability;
}
@Override
public Ingredient getRepairIngredient() {
return this.repairIngredient.get();
}
}
可以參考 net/minecraft/item/ToolMaterials.java
public enum ToolMaterials implements ToolMaterial {
WOOD(BlockTags.INCORRECT_FOR_WOODEN_TOOL, 59, 2.0F, 0.0F, 15, () -> Ingredient.fromTag(ItemTags.PLANKS)),
STONE(BlockTags.INCORRECT_FOR_STONE_TOOL, 131, 4.0F, 1.0F, 5, () -> Ingredient.fromTag(ItemTags.STONE_TOOL_MATERIALS)),
IRON(BlockTags.INCORRECT_FOR_IRON_TOOL, 250, 6.0F, 2.0F, 14, () -> Ingredient.ofItems(Items.IRON_INGOT)),
DIAMOND(BlockTags.INCORRECT_FOR_DIAMOND_TOOL, 1561, 8.0F, 3.0F, 10, () -> Ingredient.ofItems(Items.DIAMOND)),
GOLD(BlockTags.INCORRECT_FOR_GOLD_TOOL, 32, 12.0F, 0.0F, 22, () -> Ingredient.ofItems(Items.GOLD_INGOT)),
NETHERITE(BlockTags.INCORRECT_FOR_NETHERITE_TOOL, 2031, 9.0F, 4.0F, 15, () -> Ingredient.ofItems(Items.NETHERITE_INGOT));
// ...
/java/com/<mod_id>/util/ModTags.java
新增 INCORRECT_FOR_CREEPER_TOOL
package com.may.firstmod.util;
import com.may.firstmod.MaysMod;
import net.minecraft.block.Block;
import net.minecraft.registry.RegistryKeys;
import net.minecraft.registry.tag.TagKey;
import net.minecraft.util.Identifier;
public class ModTags {
public static class Blocks {
public static final TagKey<Block> INCORRECT_FOR_CREEPER_TOOL = createTag("incorrect_for_creeper_tool");
private static TagKey<Block> createTag(String name) {
return TagKey.of(RegistryKeys.BLOCK, Identifier.of(MaysMod.MOD_ID, name));
}
}
public static class Items {
}
}
建立工具物品
新增工具到 ModItems.java
public static final Item CREEPER_PICKAXE = registerItem(
"creeper_pickaxe",
new PickaxeItem(
ModToolMaterial.CREEPER_INGOT,
new Item.Settings().attributeModifiers(PickaxeItem.createAttributeModifiers(ModToolMaterial.CREEPER_INGOT, 1.0F, -2.8F))
),
CREEPER_GROUP_KEY
);
public static final Item CREEPER_AXE = registerItem(
"creeper_axe",
new AxeItem(
ModToolMaterial.CREEPER_INGOT,
new Item.Settings().attributeModifiers(AxeItem.createAttributeModifiers(ModToolMaterial.CREEPER_INGOT, 5.0F, -3.0F))
),
CREEPER_GROUP_KEY
);
public static final Item CREEPER_SHOVEL = registerItem(
"creeper_shovel",
new ShovelItem(
ModToolMaterial.CREEPER_INGOT,
new Item.Settings().attributeModifiers(ShovelItem.createAttributeModifiers(ModToolMaterial.CREEPER_INGOT, 1.5F, -3.0F))
),
CREEPER_GROUP_KEY
);
public static final Item CREEPER_HOE = registerItem(
"creeper_hoe",
new HoeItem(
ModToolMaterial.CREEPER_INGOT,
new Item.Settings().attributeModifiers(HoeItem.createAttributeModifiers(ModToolMaterial.CREEPER_INGOT, -3.0F, 0.0F))
),
CREEPER_GROUP_KEY
);
public static final Item CREEPER_SWORD = registerItem(
"creeper_sword",
new SwordItem(
ModToolMaterial.CREEPER_INGOT,
new Item.Settings().fireproof().attributeModifiers(SwordItem.createAttributeModifiers(ModToolMaterial.CREEPER_INGOT, 3, -2.4F))
),
CREEPER_GROUP_KEY
);
修改 Providers
BlockTag
/java/com/datagen/ModBlockTagProvider.java 新增 INCORRECT_FOR_CREEPER_TOOL
package com.may.firstmod.datagen;
import com.may.firstmod.block.ModBlocks;
import com.may.firstmod.util.ModTags;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.tag.BlockTags;
import java.util.concurrent.CompletableFuture;
public class ModBlockTagProvider extends FabricTagProvider.BlockTagProvider {
public ModBlockTagProvider(FabricDataOutput output, CompletableFuture<RegistryWrapper.WrapperLookup> registriesFuture) {
super(output, registriesFuture);
}
@Override
protected void configure(RegistryWrapper.WrapperLookup arg) {
// ...
getOrCreateTagBuilder(ModTags.Blocks.INCORRECT_FOR_CREEPER_TOOL);
}
}
ItemTag
為了讓自訂工具也能使用附魔,需要向 SWORD_ENCHANTABLE, MINING_LOOT_ENCHANTABLE 添加我們的工具:
package com.may.firstmod.datagen;
import com.may.firstmod.item.ModItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricTagProvider;
import net.minecraft.registry.RegistryWrapper;
import net.minecraft.registry.tag.ItemTags;
import java.util.concurrent.CompletableFuture;
public class ModItemTagProvider extends FabricTagProvider.ItemTagProvider {
// ...
@Override
protected void configure(RegistryWrapper.WrapperLookup wrapperLookup) {
// ...
getOrCreateTagBuilder(ItemTags.SWORD_ENCHANTABLE)
.add(ModItems.CREEPER_SWORD);
getOrCreateTagBuilder(ItemTags.MINING_ENCHANTABLE)
.add(ModItems.CREEPER_AXE, ModItems.CREEPER_HOE, ModItems.CREEPER_SHOVEL, ModItems.CREEPER_PICKAXE);
}
}
Models
/java/com/datagen/ModModelsProvider.java
package com.may.firstmod.datagen;
import com.may.firstmod.block.ModBlocks;
import com.may.firstmod.item.ModItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricModelProvider;
import net.minecraft.data.client.BlockStateModelGenerator;
import net.minecraft.data.client.ItemModelGenerator;
import net.minecraft.data.client.Models;
public class ModModelsProvider extends FabricModelProvider {
// ...
@Override
public void generateItemModels(ItemModelGenerator itemModelGenerator) {
// ...
itemModelGenerator.register(ModItems.CREEPER_AXE, Models.HANDHELD);
itemModelGenerator.register(ModItems.CREEPER_PICKAXE, Models.HANDHELD);
itemModelGenerator.register(ModItems.CREEPER_HOE, Models.HANDHELD);
itemModelGenerator.register(ModItems.CREEPER_SWORD, Models.HANDHELD);
itemModelGenerator.register(ModItems.CREEPER_SHOVEL, Models.HANDHELD);
}
}
Recipes
添加工具的合成表
/java/com/datagen/ModRecipesProvider.java
package com.may.firstmod.datagen;
import com.may.firstmod.block.ModBlocks;
import com.may.firstmod.item.ModItems;
import net.fabricmc.fabric.api.datagen.v1.FabricDataOutput;
import net.fabricmc.fabric.api.datagen.v1.provider.FabricRecipeProvider;
import net.minecraft.data.server.recipe.RecipeExporter;
import net.minecraft.data.server.recipe.ShapedRecipeJsonBuilder;
import net.minecraft.item.ItemConvertible;
import net.minecraft.item.Items;
import net.minecraft.recipe.book.RecipeCategory;
import net.minecraft.registry.RegistryWrapper;
import java.util.List;
import java.util.concurrent.CompletableFuture;
public class ModRecipesProvider extends FabricRecipeProvider {
// ...
@Override
public void generate(RecipeExporter exporter) {
// ...
ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, ModItems.CREEPER_AXE)
.input('#', Items.STICK)
.input('X', ModItems.CREEPER_INGOT)
.pattern("XX")
.pattern("X#")
.pattern(" #")
.criterion("has_creeper_ingot", conditionsFromItem(ModItems.CREEPER_INGOT))
.offerTo(exporter);
ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, ModItems.CREEPER_HOE)
.input('#', Items.STICK)
.input('X', ModItems.CREEPER_INGOT)
.pattern("XX")
.pattern(" #")
.pattern(" #")
.criterion("has_creeper_ingot", conditionsFromItem(ModItems.CREEPER_INGOT))
.offerTo(exporter);
ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, ModItems.CREEPER_PICKAXE)
.input('#', Items.STICK)
.input('X', ModItems.CREEPER_INGOT)
.pattern("XXX")
.pattern(" # ")
.pattern(" # ")
.criterion("has_creeper_ingot", conditionsFromItem(ModItems.CREEPER_INGOT))
.offerTo(exporter);
ShapedRecipeJsonBuilder.create(RecipeCategory.TOOLS, ModItems.CREEPER_SHOVEL)
.input('#', Items.STICK)
.input('X', ModItems.CREEPER_INGOT)
.pattern("X")
.pattern("#")
.pattern("#")
.criterion("has_creeper_ingot", conditionsFromItem(ModItems.CREEPER_INGOT))
.offerTo(exporter);
ShapedRecipeJsonBuilder.create(RecipeCategory.COMBAT, ModItems.CREEPER_SWORD)
.input('#', Items.STICK)
.input('X', ModItems.CREEPER_INGOT)
.pattern("X")
.pattern("X")
.pattern("#")
.criterion("has_creeper_ingot", conditionsFromItem(ModItems.CREEPER_INGOT))
.offerTo(exporter);
}
}
記得語系檔中添加工具的名稱。
註冊工具材質
將物品材質放入 /assets/<mod_id>/textures/item
圖可以參考官方的拿來修改。
我使用的圖片:https://imgur.com/a/h64ETYX