本帖最后由 StarFish_ 于 2020-7-11 22:09 编辑
顺便:1.16必是Fabric的时代!
前言
之所以想要写这个教程,主要还是因为自己在开发Farbric Mod的时候发现官方文档更多起到的是一个抛砖引玉的效果。对于像我我这样的半吊子开发者来说,官方文档的内容还是不够详细,所以就萌生了把这个阶段摸索的东西分享出来的想法,如果其中有什么错误还请指出,不胜感激。也是希望Fabric的开发者能更多,MCBBS的开发氛围能够更好。本篇教程主要基于1.16.1 Fabric,且MOD名为example。Fabric的教程真的好少(小声比比顺便:1.16必是Fabric的时代!
1.如何在Fabric中创建一种作物
首先得明确一点,作物其实就是一个带随机刻的方块,所以我们创建一种作物也就是创建一种方块。而创建方块的第一步就是添加并注册这个方块。
可以看到在添加这个方块的时候我们使用的类是TestCrop(下文会讲)。既然是作物,那总不能有碰撞体积吧,所以有noCollision()这个属性,也不能不生长吧,所以有ticksRandomly()这个属性,作物也不至于得像挖石头一样挖个好几秒吧,所以添加了breakInstantly()这个属性。而下面这行代码也是很重要的一部分,主要是将没有材质的地方透明化,如果不加这行代码,就会发生如下的惨状。

惨状当我们添加和注册好我们的作物的时候,最重要的一个环节来了,TestCrop这个类的编写,具体可以参考(以胡萝卜为例)net.minecraft.block.CarrotsBlock这个类。我们不难写出如下代码。
其中我们唯一需要修改的就是这里的返回值,我们返回刚刚已经添加注册好的test_crop。
接下来就是本地化这个作物,(总得给它个名字不是吗)
在resources/assets/example/lang 创建 en_us.json(简中就是zh_cn.json)并如下添加
再接下来我们要做的就是给这个作物添加材质。resources/assets/example/blockstates 创建 test_crop.json,并如下修改
resources/assets/example/models/block 创建 test_crop0.json,test_crop1.json ,......, test_crop7.json 并如下修改(以test_crop0.json为例)
resources/assets/example/models/item 创建 test_crop.json 并如下修改
在resources/textures/block 里添加 test_crop0.png , test_crop1.png , ...... , test_crop7.png 这里是作物不同阶段的材质
在resources/textures/item 里添加 test_crop.png 这是作物在物品栏里、拿在手上时看到的样子
当我们做好了这一切之后,为了使得当我们破坏作物的时候会掉落物品,我们还得给它添加战利品表。
在resources/data/example/loot_tables/blocks 创建 test_crop.json 并如下修改,其中 extra 就是额外掉落的数量, probability 就是额外掉落这个事件的概率,可以根据自己的需求修改。
那或许有人就问了,你这个作物它可以吃吗?答案自然是可以的。
只需要新建一个类,这里我们命名为FoodComponents,并如下添加
其中hunger是回复的饥饿度,saturationModifier是回复的饱食度。具体方法可以在FoodComponent这个类中查看。
并将主类中注册的test_crop改成
至此,如何关于如何在Fabric中创建作物的教程就算完成了。
2.如何在Fabric中创建一套盔甲并赋予套装效果
因为创建盔甲在官方文档中有,所以我们这就一笔带过。
首先可以先查看一下 net.minecraft.item.ArmorMaterial 这个类,这个类与盔甲的建立息息相关,其中有几个方法
1.名称(name),稍后会用做“护甲标签”。
2.耐久因子(durabilityMultiplier),基础数值乘以耐久因子即为最终耐久。
3.护甲值(armorValues),或者原版代码中的“保护点数(Protection Amounts)” ,这是个整型数组。
4.附魔能力(EnchantAbility),代表了护甲在附魔时得到高级附魔或者多个附魔的概率。
5.声音事件(equipSound),用在原版护甲的声音事件是SoundEvents.ITEM.EQUIP.ARMOR.X, X是护甲的类型。
6.护甲韧性(toughness). 这是第二个保护值,遭受高伤害时护甲会更加坚韧,掉耐久少(译注:只有钻石护甲有这个参数)。
7.修复材料(repairIngredient),这是一个 Supplier<Ingredient>实例而不是物品(Item)。
8.基础耐久值(BASE_DURABILITY), 这里采用原版的{13, 15, 16, 11}。
然后我们可以新建一个枚举类 TestArmor 实现 ArmorMaterial。具体代码如下所示。
然后就是盔甲的添加,注册,材质,模型 的添加以及本地化。具体如下。
添加和注册
材质与模型
resources/assets/example/models/item 添加 test_helmet.json, test_chestplate.json, test_leggings.json, test_boots.json
并做如下修改(以helmet为例)
resources/assets/textures/item 添加 test_helmet.png, test_chestplate.png, test_leggins.png, test_boots.png 这里是盔甲在物品栏、拿在手中时的材质
注意
盔甲模型添加在resources/assets/minecraft/textures/models/armor 且xx_layer_1/2.png中的 xx 就是 ArmorMaterial 中的 name 变量
其中test_layer_1.png对应的是头和胸甲,test_layer_2.png对应的是护腿和鞋子
本地化
resources/assets/land 在 en_us.json 中添加
至此,盔甲的创建就算完成。
接下来就是套装效果的实现。
首先看到example.mixins.json这个文件,我们对他进行如下修改,其中""mixins"里面的"PlayerEntityMixin"就是我们等会要实现套装效果的类
然后在 net.fabricmc.example.mixin 下新建一个类并命名为 PlayerEntityMixin 并让这个类继承 LivingEntity 这个类
再注入 LivingEntity 中的方法 tick ,这主要是为了下面的判定而服务
最后就是对玩家的装备进行读取以及判定,定义了4个临时的变量作为判定,如果要添加效果的话就在 if 语句中添加
例如上分的程序段就实现了判定玩家是否4个部位都穿着了test套装,如果判定通过则给与玩家 夜视I 的效果 20tick * 3 也就是 3秒
至此,套装效果的实现也就结束了
3.创建一个简单的机器(施工中)
前言
之所以想要写这个教程,主要还是因为自己在开发Farbric Mod的时候发现官方文档更多起到的是一个抛砖引玉的效果。对于像我我这样的半吊子开发者来说,官方文档的内容还是不够详细,所以就萌生了把这个阶段摸索的东西分享出来的想法,如果其中有什么错误还请指出,不胜感激。也是希望Fabric的开发者能更多,MCBBS的开发氛围能够更好。
本篇教程主要基于1.16.1 Fabric,且MOD名为example。
Fabric的教程真的好少(小声比比
2021.12 数据,可能有更多内容
前言
之所以想要写这个教程,主要还是因为自己在开发Farbric Mod的时候发现官方文档更多起到的是一个抛砖引玉的效果。对于像我我这样的半吊子开发者来说,官方文档的内容还是不够详细,所以就萌生了把这个阶段摸索的东西分享出来的想法,如果其中有什么错误还请指出,不胜感激。也是希望Fabric的开发者能更多,MCBBS的开发氛围能够更好。本篇教程主要基于1.16.1 Fabric,且MOD名为example。Fabric的教程真的好少(小声比比
1.如何在Fabric中创建一种作物
首先得明确一点,作物其实就是一个带随机刻的方块,所以我们创建一种作物也就是创建一种方块。而创建方块的第一步就是添加并注册这个方块。
代码:
- public class ExampleMod implements ModInitializer {
- @Override
- public void onInitialize() {
- BlockRenderLayerMap.INSTANCE.putBlock(test_crop, RenderLayer.getCutout());
- Registry.register(Registry.BLOCK, new Identifier("example", "test_crop"), test_crop);
- Registry.register(Registry.ITEM, new Identifier("example", "test_crop"), new BlockItem(test_crop, new Item.Settings().group(ItemGroup.MISC).food(FoodComponents.test_crop)));
- }
- public static Block test_crop = new TestCrop(FabricBlockSettings.of(Material.PLANT).noCollision().ticksRandomly().breakInstantly().sounds(BlockSoundGroup.CROP));
- }
可以看到在添加这个方块的时候我们使用的类是TestCrop(下文会讲)。既然是作物,那总不能有碰撞体积吧,所以有noCollision()这个属性,也不能不生长吧,所以有ticksRandomly()这个属性,作物也不至于得像挖石头一样挖个好几秒吧,所以添加了breakInstantly()这个属性。而下面这行代码也是很重要的一部分,主要是将没有材质的地方透明化,如果不加这行代码,就会发生如下的惨状。
代码:
- BlockRenderLayerMap.INSTANCE.putBlock(test_crop, RenderLayer.getCutout());

惨状当我们添加和注册好我们的作物的时候,最重要的一个环节来了,TestCrop这个类的编写,具体可以参考(以胡萝卜为例)net.minecraft.block.CarrotsBlock这个类。我们不难写出如下代码。
代码:
- public class TestCrop extends CropBlock {
- private static final VoxelShape[] AGE_TO_SHAPE = new VoxelShape[]{
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 4.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 5.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 6.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 7.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D),
- Block.createCuboidShape(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D)};
- public TestCrop(Settings settings) {
- super(settings);
- }
其中我们唯一需要修改的就是这里的返回值,我们返回刚刚已经添加注册好的test_crop。
代码:
- @Environment(EnvType.CLIENT)
- protected ItemConvertible getSeedsItem() {
- return ExampleMod.test_crop;
接下来就是本地化这个作物,(总得给它个名字不是吗)
在resources/assets/example/lang 创建 en_us.json(简中就是zh_cn.json)并如下添加
代码:
- {
- "block.example.test_crop": "test_crop"
- }
再接下来我们要做的就是给这个作物添加材质。resources/assets/example/blockstates 创建 test_crop.json,并如下修改
代码:
- {
- "variants": {
- "age=0": { "model": "example:block/test_crop0" },
- "age=1": { "model": "example:block/test_crop1" },
- "age=2": { "model": "example:block/test_crop2" },
- "age=3": { "model": "example:block/test_crop3" },
- "age=4": { "model": "example:block/test_crop4" },
- "age=5": { "model": "example:block/test_crop5" },
- "age=6": { "model": "example:block/test_crop6" },
- "age=7": { "model": "example:block/test_crop7" }
- }
- }
resources/assets/example/models/block 创建 test_crop0.json,test_crop1.json ,......, test_crop7.json 并如下修改(以test_crop0.json为例)
代码:
- {
- "parent": "block/crop",
- "textures": {
- "crop": "example:block/test_crop0"
- }
- }
resources/assets/example/models/item 创建 test_crop.json 并如下修改
代码:
- {
- "parent" : "item/generated" ,
- "textures" : {
- "layer0" : "example:item/test_crop"
- }
- }
在resources/textures/block 里添加 test_crop0.png , test_crop1.png , ...... , test_crop7.png 这里是作物不同阶段的材质
在resources/textures/item 里添加 test_crop.png 这是作物在物品栏里、拿在手上时看到的样子
当我们做好了这一切之后,为了使得当我们破坏作物的时候会掉落物品,我们还得给它添加战利品表。
在resources/data/example/loot_tables/blocks 创建 test_crop.json 并如下修改,其中 extra 就是额外掉落的数量, probability 就是额外掉落这个事件的概率,可以根据自己的需求修改。
代码:
- {
- "type": "minecraft:block",
- "pools": [
- {
- "rolls": 1.0,
- "entries": [
- {
- "type": "minecraft:item",
- "name": "example:test_crop"
- }
- ]
- },
- {
- "rolls": 1.0,
- "entries": [
- {
- "type": "minecraft:item",
- "functions": [
- {
- "function": "minecraft:apply_bonus",
- "enchantment": "minecraft:fortune",
- "formula": "minecraft:binomial_with_bonus_count",
- "parameters": {
- "extra": 2,
- "probability": 0.5
- }
- }
- ],
- "name": "example:test_crop"
- }
- ],
- "conditions": [
- {
- "condition": "minecraft:block_state_property",
- "block": "example:test_crop",
- "properties": {
- "age": "7"
- }
- }
- ]
- }
- ],
- "functions": [
- {
- "function": "minecraft:explosion_decay"
- }
- ]
- }
那或许有人就问了,你这个作物它可以吃吗?答案自然是可以的。
只需要新建一个类,这里我们命名为FoodComponents,并如下添加
其中hunger是回复的饥饿度,saturationModifier是回复的饱食度。具体方法可以在FoodComponent这个类中查看。
代码:
- public class FoodComponents {
- public static final FoodComponent test_crop;
- private static FoodComponent create(int hunger) {
- return (new Builder()).hunger(hunger).saturationModifier(0.6F).build();
- }
- static {
- test_crop = (new Builder()).hunger(4).saturationModifier(0.6F).build();
- }
- }
代码:
- Registry.register(Registry.ITEM, new Identifier("example", "test_crop"), new BlockItem(test_crop, new Item.Settings().group(ItemGroup.MISC).food(FoodComponents.test_crop)));
至此,如何关于如何在Fabric中创建作物的教程就算完成了。
2.如何在Fabric中创建一套盔甲并赋予套装效果
因为创建盔甲在官方文档中有,所以我们这就一笔带过。
首先可以先查看一下 net.minecraft.item.ArmorMaterial 这个类,这个类与盔甲的建立息息相关,其中有几个方法
1.名称(name),稍后会用做“护甲标签”。
2.耐久因子(durabilityMultiplier),基础数值乘以耐久因子即为最终耐久。
3.护甲值(armorValues),或者原版代码中的“保护点数(Protection Amounts)” ,这是个整型数组。
4.附魔能力(EnchantAbility),代表了护甲在附魔时得到高级附魔或者多个附魔的概率。
5.声音事件(equipSound),用在原版护甲的声音事件是SoundEvents.ITEM.EQUIP.ARMOR.X, X是护甲的类型。
6.护甲韧性(toughness). 这是第二个保护值,遭受高伤害时护甲会更加坚韧,掉耐久少(译注:只有钻石护甲有这个参数)。
7.修复材料(repairIngredient),这是一个 Supplier<Ingredient>实例而不是物品(Item)。
8.基础耐久值(BASE_DURABILITY), 这里采用原版的{13, 15, 16, 11}。
然后我们可以新建一个枚举类 TestArmor 实现 ArmorMaterial。具体代码如下所示。
代码:
- public enum TestArmor implements ArmorMaterial {
- test("test", 15, new int[]{2, 5, 6, 2}, 9, SoundEvents.ITEM_ARMOR_EQUIP_IRON, 0.0F, 0.0F, () -> {
- return Ingredient.ofItems(new ItemConvertible[]{Items.IRON_INGOT});
- }),;
- private static final int[] BASE_DURABILITY = new int[]{13, 15, 16, 11};
- private final String name;
- private final int durabilityMultiplier;
- private final int[] protectionAmounts;
- private final int enchantability;
- private final SoundEvent equipSound;
- private final float toughness;
- private final float knockbackResistance;
- private final Lazy<Ingredient> repairIngredientSupplier;
-
- private TestArmor(String name, int durabilityMultiplier, int[] protectionAmounts, int enchantability, SoundEvent equipSound, float toughness, float knockbackResistance, Supplier<Ingredient> supplier) {
- this.name = name;
- this.durabilityMultiplier = durabilityMultiplier;
- this.protectionAmounts = protectionAmounts;
- this.enchantability = enchantability;
- this.equipSound = equipSound;
- this.toughness = toughness;
- this.knockbackResistance = knockbackResistance;
- this.repairIngredientSupplier = new Lazy(supplier);
- }
- public int getDurability(EquipmentSlot slot) {
- return BASE_DURABILITY[slot.getEntitySlotId()] * this.durabilityMultiplier;
- }
-
- public int getProtectionAmount(EquipmentSlot slot) {
- return this.protectionAmounts[slot.getEntitySlotId()];
- }
- public int getEnchantability() {
- return this.enchantability;
- }
- public SoundEvent getEquipSound() {
- return this.equipSound;
- }
- public Ingredient getRepairIngredient() {
- return (Ingredient)this.repairIngredientSupplier.get();
- }
- @Environment(EnvType.CLIENT)
- public String getName() { return this.getName(); }
- public float getToughness() { return this.toughness; }
- public float getKnockbackResistance() { return this.knockbackResistance; }
- }
然后就是盔甲的添加,注册,材质,模型 的添加以及本地化。具体如下。
添加和注册
代码:
- public class ExampleMod implements ModInitializer {
- public void onInitialize() {
- Registry.register(Registry.ITEM, new Identifier("example", "test_helmet"), test_helmet);
- Registry.register(Registry.ITEM, new Identifier("example", "test_chestplate"), test_chestplate);
- Registry.register(Registry.ITEM, new Identifier("example", "test_leggings"), test_leggings);
- Registry.register(Registry.ITEM, new Identifier("example", "test_boots"), test_boots);
- }
- public static final Item test_helmet = new ArmorItem(TestArmor.test, EquipmentSlot.HEAD, (new Item.Settings().group(ItemGroup.COMBAT)));
- public static final Item test_chestplate = new ArmorItem(TestArmor.test, EquipmentSlot.CHEST, (new Item.Settings().group(ItemGroup.COMBAT)));
- public static final Item test_leggings = new ArmorItem(TestArmor.test, EquipmentSlot.LEGS, (new Item.Settings().group(ItemGroup.COMBAT)));
- public static final Item test_boots = new ArmorItem(TestArmor.test, EquipmentSlot.FEET, (new Item.Settings().group(ItemGroup.COMBAT)));
- }
材质与模型
resources/assets/example/models/item 添加 test_helmet.json, test_chestplate.json, test_leggings.json, test_boots.json
并做如下修改(以helmet为例)
代码:
- {
- "parent" : "item/generated" ,
- "textures" : {
- "layer0" : "example:item/test_helmet"
- }
- }
resources/assets/textures/item 添加 test_helmet.png, test_chestplate.png, test_leggins.png, test_boots.png 这里是盔甲在物品栏、拿在手中时的材质
注意
盔甲模型添加在resources/assets/minecraft/textures/models/armor 且xx_layer_1/2.png中的 xx 就是 ArmorMaterial 中的 name 变量
其中test_layer_1.png对应的是头和胸甲,test_layer_2.png对应的是护腿和鞋子
本地化
resources/assets/land 在 en_us.json 中添加
代码:
- {
- "item.example.test_helmet": "test_helmet",
- "item.example.test_chestplate": "test_chestplate",
- "item.example.test_leggings": "test_leggings",
- "item.example.test_boots": "test_boots"
- }
接下来就是套装效果的实现。
首先看到example.mixins.json这个文件,我们对他进行如下修改,其中""mixins"里面的"PlayerEntityMixin"就是我们等会要实现套装效果的类
代码:
- {
- "required": true,
- "minVersion": "0.8",
- "package": "net.fabricmc.example.mixin",
- "compatibilityLevel": "JAVA_8",
- "mixins": [
- "PlayerEntityMixin"
- ],
- "client": [
- ],
- "injectors": {
- "defaultRequire": 1
- }
- }
然后在 net.fabricmc.example.mixin 下新建一个类并命名为 PlayerEntityMixin 并让这个类继承 LivingEntity 这个类
代码:
- @Mixin(PlayerEntity.class)
- public abstract class PlayerEntityMixin extends LivingEntity {
- @Shadow public abstract void addExperience(int experience);
- protected PlayerEntityMixin(EntityType<? extends LivingEntity> entityType, World world) {
- super(entityType, world);
- }
- }
再注入 LivingEntity 中的方法 tick ,这主要是为了下面的判定而服务
代码:
- @Inject(
- method = "tick",
- at = @At("HEAD")
- )
最后就是对玩家的装备进行读取以及判定,定义了4个临时的变量作为判定,如果要添加效果的话就在 if 语句中添加
代码:
- private void tick(CallbackInfo ci) {
- Item helmet = this.getEquippedStack(EquipmentSlot.HEAD).getItem();
- Item chestplate = this.getEquippedStack(EquipmentSlot.CHEST).getItem();
- Item leggings = this.getEquippedStack(EquipmentSlot.LEGS).getItem();
- Item boots = this.getEquippedStack(EquipmentSlot.FEET).getItem();
-
- if (helmet.equals(ExampleMod.test_helmet) && chestplate.equals(ExampleMod.test_chestplate) && leggings.equals(ExampleMod.test_leggings) && boots.equals(ExampleMod.test_boots)) {
- this.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, 20 * 3, 0));
- }
- }
例如上分的程序段就实现了判定玩家是否4个部位都穿着了test套装,如果判定通过则给与玩家 夜视I 的效果 20tick * 3 也就是 3秒
至此,套装效果的实现也就结束了
3.创建一个简单的机器(施工中)
糟,我是不是被鞭尸了