Table of Contents

如果你在找 1.19.3,矿石应该完全使用 json 完成。你可以了解到的有用的工具:Configured FeaturesPlaced Features

生成自定义的矿石 [1.19.3+]

许多模组会添加自己的矿石,您需要找到一种方法以将其放置在现有生物群系中让玩家寻找。在本教程中,我们将研究将矿石添加到现有生物群系以及其他模组添加的生物群系。将矿石添加到生物群系需要2个步骤。

为了简化,我们使用原版的末地烛作为矿石,因为末地烛可以轻易地在地下发现,旁观模式下很容易看到。

添加到主世界生物群系

在这个章节中,我们会在主世界生成矿石。

首先,在你的模组的目录创建两个 JSON 文件:

src\main\resources\data\tutorial\worldgen\configured_feature\ore_custom.json
{
  "type": "minecraft:ore",
  "config": {
    "discard_chance_on_air_exposure": 0.0,
    "size": 12,
    "targets": [
      {
        "state": {
          "Name": "minecraft:end_rod"
        },
        "target": {
          "predicate_type": "minecraft:tag_match",
          "tag": "minecraft:stone_ore_replaceables"
        }
      },
      {
        "state": {
          "Name": "minecraft:end_rod"
        },
        "target": {
          "predicate_type": "minecraft:tag_match",
          "tag": "minecraft:deepslate_ore_replaceables"
        }
      }
    ]
  }
}

这个已配置的地物(configured feature)会告诉游戏矿脉的大小、哪些矿石方块会因为空气暴露而被移除,以及,最重要的还有这个矿石能够替换哪些方块。注意我们的 target 数组中有两个 target 对象:一个是生成在石头中的矿石,还有一个是深板岩中的矿石。为了简化,我们都用末地烛。

src\main\resources\data\tutorial\worldgen\placed_feature\ore_custom.json
{
  "feature": "tutorial:ore_custom",
  "placement": [
    {
      "type": "minecraft:count",
      "count": 20
    },
    {
      "type": "minecraft:in_square"
    },
    {
      "type": "minecraft:height_range",
      "height": {
        "type": "minecraft:trapezoid",
        "max_inclusive": {
          "absolute": 70
        },
        "min_inclusive": {
          "absolute": -24
        }
      }
    },
    {
      "type": "minecraft:biome"
    }
  ]
}

已放置的地物(placed feature)告诉游戏,一个区块内应该放置多少的矿脉,矿脉应该以什么形状放置,以及放置在哪些 y 轴级别上。注意,放置的地物的第一行引用了我们刚刚创建的配置的地物。

手写 JSON 文件可能会有些麻烦。注意这些工作可以借助像 Configured Features generator 或者 Placed Features generator 来完成。你也可以打开原版的 Minecraft 的 .jar 文件,将原版的文件作为参考。

现在我们的数据已经创建好了,是时候编写代码了!好在 Minecraft 1.19.3 以来的更改,在世界中添加矿石需要的 Java 代码非常少。我们所需要做的,就只是注册这个地物,然后使用 Fabric Biome Modification API 来告诉 Minecraft,在哪些地方生成这些矿石,以及在哪些阶段生成这些矿石。

在这个类中,我们创建新的 RegistryKey

src/main/java/net/fabricmc/example/ExampleMod.java
public class ExampleMod implements ModInitializer {
 
	public static final RegistryKey<PlacedFeature> CUSTOM_ORE_PLACED_KEY = RegistryKey.of(RegistryKeys.PLACED_FEATURE, new Identifier("tutorial","ore_custom"));
 
	@Override
	public void onInitialize() {
 
		//Your other code here...
 
	}
}

注意两件事:

现在将地物添加到生物群系中:

src/main/java/net/fabricmc/example/ExampleMod.java
@Override
	public void onInitialize() {
 
		//Your other code here...
		BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), GenerationStep.Feature.UNDERGROUND_ORES, CUSTOM_ORE_PLACED_KEY);
	}

测试

要测试你的新矿石,生成一个新世界。你也可以打开已存在的世界,但需要走到新的区块。在这个末地烛的示例中,矿石可以直接在地下在旁观模式下看到。

添加到下界或末地

将矿石添加到其他维度的过程和添加到主世界的过程很类似。

就像在主世界中一样,我们创建 JSON 文件。如果以原版的下界金矿石为例,我们的已放置的地物看起来应该会像这样:

src/main/resources/data/tutorial/worldgen/placed_feature/ore_custom_nether.json
{
  "feature": "tutorial:ore_nether_custom",
  "placement": [
    {
      "type": "minecraft:count",
      "count": 20
    },
    {
      "type": "minecraft:in_square"
    },
    {
      "type": "minecraft:height_range",
      "height": {
        "type": "minecraft:uniform",
        "max_inclusive": {
          "below_top": 10
        },
        "min_inclusive": {
          "above_bottom": 10
        }
      }
    },
    {
      "type": "minecraft:biome"
    }
  ]
}

注意区别在于,其高度范围是以不同的方式描述的,高度类型是 uniform 而不是 trapezoid。trapezoid 的形状和绝对的高度范围在下界仍是有效的,但我们只是遵循原版 Minecraft 的游戏设计。

和之前一样,添加配置的地物。

src/main/resources/data/tutorial/worldgen/configured_feature/ore_nether_custom.json
{
  "type": "minecraft:ore",
  "config": {
    "discard_chance_on_air_exposure": 0.0,
    "size": 20,
    "targets": [
      {
        "state": {
          "Name": "minecraft:end_rod"
        },
        "target": {
          "block": "minecraft:netherrack",
          "predicate_type": "minecraft:block_match"
        }
      }
    ]
  }
}

在配置的地物中,记住 Name 是你的矿石方块的名字,而不是放置的地物的名字。

最后,回到 Java 代码,再添加一行 BiomdModifaction 的内容:

src/main/java/net/fabricmc/example/ExampleMod.java
		BiomeModifications.addFeature(BiomeSelectors.foundInNether(), GenerationStep.Feature.UNDERGROUND_ORES, CUSTOM_ORE_PLACED_KEY);

生成自定义的矿石 [1.18.2 / 1.19.2]

我们假设您此时已经创建了自己的矿石。本教程中,我们使用羊毛方块进行替换。你可以适时将羊毛改成你自己的矿石。

添加到主世界生物群系

本段落将会在主世界生成矿石。

我们需要创建一个已配置的地物,确保在 onInitialize 中注册你的已配置的地物,你可以自由地改变一些值以适应你的模组。

public class ExampleMod implements ModInitializer {
  private static ConfiguredFeature<?, ?> OVERWORLD_WOOL_ORE_CONFIGURED_FEATURE = new ConfiguredFeature
      (Feature.ORE, new OreFeatureConfig(
          OreConfiguredFeatures.STONE_ORE_REPLACEABLES,
          Blocks.WHITE_WOOL.getDefaultState(),
          9)); // 矿脉大小
 
  public static PlacedFeature OVERWORLD_WOOL_ORE_PLACED_FEATURE = new PlacedFeature(
      RegistryEntry.of(OVERWORLD_WOOL_ORE_CONFIGURED_FEATURE),
      Arrays.asList(
          CountPlacementModifier.of(20), // 每个区块的矿脉数量
          SquarePlacementModifier.of(), // 水平传播
          HeightRangePlacementModifier.uniform(YOffset.getBottom(), YOffset.fixed(64))
      )); // 高度
 
  @Override
  public void onInitialize() {
    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE,
        new Identifier("tutorial", "overworld_wool_ore"), OVERWORLD_WOOL_ORE_CONFIGURED_FEATURE);
    Registry.register(BuiltinRegistries.PLACED_FEATURE, new Identifier("tutorial", "overworld_wool_ore"),
        OVERWORLD_WOOL_ORE_PLACED_FEATURE);
    BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), GenerationStep.Feature.UNDERGROUND_ORES,
        RegistryKey.of(Registry.PLACED_FEATURE_KEY,
            new Identifier("tutorial", "overworld_wool_ore")));
  }
}

结果

检查你的世界生成结果时,记得要创建新世界。你应该看见羊毛在主世界生成了。你可以使用下面的命令移除周围的石头方块。

/fill ~-8 0 ~-8 ~8 ~ ~8 minecraft:air replace minecraft:stone

添加到下界生物群系

本段落将会基于前面的段落添加矿石到下界生物群系。

在下界,需要替换的方块和主世界地不同,所以需要把 OreConfiguredFeatures.STONE_ORE_REPLACEABLES 替换成 OreConfiguredFeatures.NETHERRACK

public class ExampleMod implements ModInitializer {
  private static ConfiguredFeature<?, ?> NETHER_WOOL_ORE_CONFIGURED_FEATURE = new ConfiguredFeature
      (Feature.ORE, new OreFeatureConfig(
          OreConfiguredFeatures.NETHERRACK, // 我们这里使用 OreConfiguredFeatures.NETHERRACK
          Blocks.WHITE_WOOL.getDefaultState(),
          9));
 
  public static PlacedFeature NETHER_WOOL_ORE_PLACED_FEATURE = new PlacedFeature(
      RegistryEntry.of(NETHER_WOOL_ORE_CONFIGURED_FEATURE),
      Arrays.asList(
          CountPlacementModifier.of(20),
          SquarePlacementModifier.of(),
          HeightRangePlacementModifier.uniform(YOffset.getBottom(), YOffset.fixed(64))));
 
  @Override
  public void onInitialize() {
    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE,
        new Identifier("tutorial", "nether_wool_ore"), NETHER_WOOL_ORE_CONFIGURED_FEATURE);
    Registry.register(BuiltinRegistries.PLACED_FEATURE, new Identifier("tutorial", "nether_wool_ore"),
        NETHER_WOOL_ORE_PLACED_FEATURE);
    BiomeModifications.addFeature(BiomeSelectors.foundInTheNether(), GenerationStep.Feature.UNDERGROUND_ORES,
        RegistryKey.of(Registry.PLACED_FEATURE_KEY,
            new Identifier("tutorial", "nether_wool_ore")));
  }
}

添加到末地生物群系

本段落将会基于主世界的代码添加矿石到末地生物群系。

在末地,基础方块是末地石,所以需要把 OreConfiguredFeatures.STONE_ORE_REPLACEABLES 替换成 new BlockMatchRuleTest(Blocks.END_STONE)

public class ExampleMod implements ModInitializer {
  private static ConfiguredFeature<?, ?> END_WOOL_ORE_CONFIGURED_FEATURE = new ConfiguredFeature
      (Feature.ORE, new OreFeatureConfig(
          new BlockMatchRuleTest(Blocks.END_STONE), // 我们这里使用 new BlockMatchRuleTest(Blocks.END_STONE)
          Blocks.WHITE_WOOL.getDefaultState(),
          9));
 
  public static PlacedFeature END_WOOL_ORE_PLACED_FEATURE = new PlacedFeature(
      RegistryEntry.of(END_WOOL_ORE_CONFIGURED_FEATURE),
      Arrays.asList(
          CountPlacementModifier.of(20),
          SquarePlacementModifier.of(),
          HeightRangePlacementModifier.uniform(YOffset.getBottom(), YOffset.fixed(64))));
 
  @Override
  public void onInitialize() {
    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE,
        new Identifier("tutorial", "end_wool_ore"), END_WOOL_ORE_CONFIGURED_FEATURE);
    Registry.register(BuiltinRegistries.PLACED_FEATURE, new Identifier("tutorial", "end_wool_ore"),
        END_WOOL_ORE_PLACED_FEATURE);
    BiomeModifications.addFeature(BiomeSelectors.foundInTheEnd(), GenerationStep.Feature.UNDERGROUND_ORES,
        RegistryKey.of(Registry.PLACED_FEATURE_KEY,
            new Identifier("tutorial", "end_wool_ore")));
  }
}