Minecraft 1.21 Fabric 模組開發(1)-前置準備
Minecraft 1.21 Fabric 模組開發(2)-新增物品
寫在前頭
1.不是JAVA教學所以不解釋程式碼為何這樣寫,想知道為什麼這麼寫可以在 Fabric docs 或 Fabric wiki 裡面找到。
2.我的模組名稱為mays-mod
,程式碼中看到 mays-mod 的地方請自行換成你的 mod 名稱。
3.圖片看不清的話可以點擊放大看。
創建方塊
src/main/java/com/<mod_id>/block
底下新增 ModBlocks.java
- ExperienceDroppingBlock 是會掉落經驗的方塊
- UniformIntProvider.create(2, 6) 代表掉落經驗 2~6
- strength(3.0f) 挖掘強度,作為參考 石頭是2.0f, 鐵礦、金礦、鑽石礦都是3.0f
- requiresTool() 需要工具挖掘
// block/ModBlocks.java
package com.may.firstmod.block;
import com.may.firstmod.MaysMod;
import com.may.firstmod.item.ModItemGroup;
import com.may.firstmod.item.ModItems;
import net.minecraft.block.Block;
import net.minecraft.block.ExperienceDroppingBlock;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraft.registry.Registries;
import net.minecraft.registry.Registry;
import net.minecraft.registry.RegistryKey;
import net.minecraft.sound.BlockSoundGroup;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.intprovider.UniformIntProvider;
public class ModBlocks {
public static final Block CREEPER_BLOCK = registerBlock(
"creeper_block",
new ExperienceDroppingBlock(
UniformIntProvider.create(2, 6),
Block.Settings.create().sounds(BlockSoundGroup.METAL).strength(4.0f).requiresTool()
),
ModItemGroup.CREEPER_GROUP_KEY
);
public static final Block CREEPER_ORE = registerBlock(
"creeper_ore",
new ExperienceDroppingBlock(
UniformIntProvider.create(2, 6),
Block.Settings.create().sounds(BlockSoundGroup.METAL).strength(4.0f).requiresTool()
),
ModItemGroup.CREEPER_GROUP_KEY
);
// 註冊方塊
public static Block registerBlock(String name, Block block, RegistryKey<ItemGroup>... itemGroups) {
BlockItem blockItem = new BlockItem(block, new Item.Settings());
Identifier id = Identifier.of(MaysMod.MOD_ID, name);
ModItems.registerItem(name, blockItem, itemGroups);
return Registry.register(Registries.BLOCK, id, block);
}
public static void initialize() {
MaysMod.LOGGER.debug("Registering mod blocks for" + MaysMod.MOD_ID);
}
}
XxxMod.java
中初始化 ModBlocks
// MayMod.java
package com.may.firstmod;
import com.may.firstmod.block.ModBlocks;
import com.may.firstmod.item.ModItemGroup;
import com.may.firstmod.item.ModItems;
import net.fabricmc.api.ModInitializer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MaysMod implements ModInitializer {
public static final String MOD_ID = "mays-mod";
public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID);
@Override
public void onInitialize() {
LOGGER.info("Hello Fabric world!");
ModItems.initialize();
ModItemGroup.initialize();
ModBlocks.initialize();
}
}
定義方塊
方塊紋理
將方塊的圖片(16×16, png)放到 assets/textures/block
裡面。
方塊模型
新增 assets/models/block/creeper_block.json
{
"parent": "block/cube_all",
"textures": {
"all": "mays-mod:block/creeper_block"
}
}
以及 creeper_ore.json
{
"parent": "block/cube_all",
"textures": {
"all": "mays-mod:block/creeper_ore"
}
}
物品模型
物品模型只需要繼承方塊的模型就好。
新增 assets/models/item/creeper_block.json
{
"parent": "mays-mod:block/creeper_block"
}
以及 creeper_ore.json
{
"parent": "mays-mod:block/creeper_ore"
}
方塊狀態
用於指示遊戲要渲染哪個模型
新增 assets/blockstates/creeper_block.json
{
"variants": {
"": { "model": "mays-mod:block/creeper_block" }
}
}
以及 creeper_ore.json
{
"variants": {
"": { "model": "mays-mod:block/creeper_ore" }
}
}
詳細的方塊狀態:https://docs.fabricmc.net/zh_cn/develop/blocks/blockstates
定義方塊挖掘工具和等級
在開始之前需要先了解方塊標籤這個概念
方塊標籤(Block Tags)
是用來對方快進行分類和標記的機制。
在遊戲中按 F3 準心對向方塊,右邊可以看到方塊標籤:
以鑽石礦為例:
- c:ores 礦物類
- minecraft:incorrect_for_wooden_tool 木製工具挖掘不掉落物品
- minecraft:mineable/pickaxe 稿才能有效挖掘
- minecraft:needs_iron_tool 鐵製工具挖掘會掉落物品
- minecraft:incorrect_for_stone_tool 石製工具挖掘不掉落物品
- minecraft:incorrect_for_gold_tool 金製工具挖掘不掉落物品
- minecraft:diamond_ores 鑽石礦
金礦多了一條特殊的
- minecraft:guarded_by_piglins 受豬布林保護的方塊,玩家如果在豬布林視線範圍內挖掘或者打掉這類方塊就會被豬布林攻擊
鐵礦多了一條
- Minecraft:overworld_carver_replaceables 生成洞穴時可被替換
新增資料包(data)
在 src/main/resources
底下新增以下資料夾:
data
data/minecraft
data/minecraft/tags/block/mineable
挖掘工具
data/minecraft/tags/block/mineable
底下新增 pickaxe.json
, axe.json
, hoe.json
, shovel.json
- replace: 要不要覆蓋原版裡其他方塊的標籤。假設為 true,那就只有 values 裡面定義的方塊可以被該工具加速挖掘,其他原本可以加速挖掘的方塊都變無效。
// pickaxe.json
{
"replace": false,
"values": [
"mays-mod:creeper_block",
"mays-mod:creeper_ore"
]
}
values 可以為空陣列
[]
,比如目前axe.json
,hoe.json
,shovel.json
的 values 都可以設成空陣列。
挖掘等級
data/minecraft/tags/block
底下新增 needs_stone_tool.json
, needs_iron_tool.json
, needs_diamond_tool.json
{
"replace": false,
"values": [
"mays-mod:creeper_block",
"mays-mod:creeper_ore"
]
}
values 可以為空陣列,比如目前
axe.json
,hoe.json
,shovel.json
的 values 都可以設成空陣列
定義方塊掉落物
可以用鐵原礦(iron_ore)來做參考。
新增 src/main/resources/data/loot_table/blocks/creeper_ore.json
貼上生成的戰利品表json
- silk_touch: 有附魔絲綢之觸的稿子挖掘方塊會掉落自身方塊。
- explosion_decay: 如果物品是因為方塊被爆炸破壞而產生,執行該函數的每個物品有1/爆炸半徑的機率消失,堆疊的物品會被分為多個單獨的物品計算;否則此物品修飾器不做任何處理。
{
"type": "minecraft:block",
"pools": [
{
"rolls": 1,
"bonus_rolls": 0,
"entries": [
{
"type": "minecraft:alternatives",
"children": [
{
"type": "minecraft:item",
"name": "mays-mod:creeper_ore",
"conditions": [
{
"condition": "minecraft:match_tool",
"predicate": {
"predicates": {
"minecraft:enchantments": [
{
"enchantments": "minecraft:silk_touch",
"levels": {
"min": 1
}
}
]
}
}
}
]
},
{
"type": "minecraft:item",
"name": "mays-mod:raw_creeper",
"functions": [
{
"function": "minecraft:apply_bonus",
"enchantment": "minecraft:fortune",
"formula": "minecraft:ore_drops"
},
{
"function": "minecraft:explosion_decay"
}
]
}
]
}
]
}
]
}
同理,新增 creeper_block.json 參考 iron_block 的戰利品表修改一下,這邊就不演示了。
方塊配方
配方(type)有很多種,分為:crafting_shaped(有序合成), crafting_shapeless(無序合成), smelting(熔爐), stonecutting(切石機), campfire_cooking(營火), blasting(高爐), smithing(鍛造台), smoking(煙燻爐)…
有序合成(crafting_shaped)
這一步要完成用苦力帕錠(creeper_ingot)合成苦力帕方塊(creeper_block)
從 minecraft 原始檔 data/Minecraft/recipe
裡面找到 iron_block.json
複製到 data/recipe
裡面。
iron_block.json
內容如下:
{
"type": "minecraft:crafting_shaped",
"category": "building",
"key": {
"#": {
"item": "minecraft:iron_ingot"
}
},
"pattern": [
"###",
"###",
"###"
],
"result": {
"count": 1,
"id": "minecraft:iron_block"
}
}
pattern 是用於有序合成,最大為3個字串元素,每個字串最多三個字元,每個字元代表的意思在key中定義。沒擺東西可以留空,比如說:
"# #",
" # ",
"# #"
也可以是 2*2 以內,這樣就不需要合成台才能製作。
"##"
假設我想使用九個苦力怕錠合成一個苦力怕方塊,先將檔名改為 creeper_block.json
然後將檔案中的 minecraft:iron_ingot
改為 mays-mod:creeper_ingot
,把 mays-mod:iron_block
改為 mays-mod:creeper_block
{
"type": "minecraft:crafting_shaped",
"category": "building",
"key": {
"#": {
"item": "mays-mod:creeper_ingot"
}
},
"pattern": [
"###",
"###",
"###"
],
"result": {
"count": 1,
"id": "mays-mod:creeper_block"
}
}
熔爐(smelting)
這一步要完成用苦力帕原礦(raw_creeper)冶煉成苦力帕錠(creeper_ingot)
從 minecraft 原始檔 data/Minecraft/recipe
裡面找到 copper_ingot_from_smelting_copper_ore.json
複製到 data/recipe
裡面
記得將檔名和檔案中的 minecraft:copper_ore
, minecraft:copper_ingot
替換掉。
- category: 可以為
food
(食物)、blocks
(方塊)或misc
(雜項)。 - cookingtime: (可選,對於smelting,預設為200;對於blasting、smoking和campfire_cooking,預設為100)以刻為單位的該配方的熔煉時間。如果預設,將使用預設時間。
{
"type": "minecraft:smelting",
"category": "misc",
"cookingtime": 200,
"experience": 0.7,
"group": "creeper_ingot",
"ingredient": {
"item": "mays-mod:raw_creeper"
},
"result": {
"id": "mays-mod:creeper_ingot"
}
}
因為有太多,這邊只能簡單介紹有序合成和熔爐兩個,其他請參考:https://minecraft.fandom.com/wiki/Recipe
標籤(Tags)
標籤可以用來分組不同模組的物品,使這些物品互相兼容。
假設我現在要新增一個標籤是 special_ores
,包含了:我自定義的苦力怕礦,還有原本就有的鐵礦、煤礦、金礦、鑽石礦、青金石礦、紅石礦、綠寶石礦、銅礦石,只需要新增 /data/<mod_id>/tags/block/special_ores.json
將這些礦通通寫進 values:
{
"replace": false,
"values": [
"mays-mod:creeper_ore",
"#minecraft:coal_ores",
"#minecraft:iron_ores",
"#minecraft:gold_ores",
"#minecraft:lapis_ores",
"#minecraft:diamond_ores",
"#minecraft:redstone_ores",
"#minecraft:emerald_ores",
"#minecraft:copper_ores"
]
}
接著在 java/com/<mod_id>/util
新增 ModTags.java
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> SPECIAL_ORES = createTag("special_ores");
private static TagKey<Block> createTag(String name) {
return TagKey.of(RegistryKeys.BLOCK, Identifier.of(MaysMod.MOD_ID, name));
}
}
public static class Items {
}
}
未來如果你需要檢查一個方塊是否屬於 special_ores
這個標籤,就可以這麼新增一個 isSpecialOres 方法:
private boolean isSpecialOres(BlockState state) {
return state.isIn(ModTags.Blocks.SPECIAL_ORES);
}