本篇教程的视频:
本篇教程源代码
介绍
前面我们写方块的时候,我们已经添加了一些矿物方块
,那这篇教程我们将让矿物也生成在世界中,这样玩家才能在世界中找到矿物
这里和前面的两篇世界生成的教程一样,也是要为矿物编写构造特征
和放置特征
同样的,这里我们就不讲解源代码了,可以自行研究
创建ModOrePlacements类
我们先创建一个类,这个类里面存放一些方法,这里的方法来自OrePlacedFeatures
(这个类也是关于矿物的放置特征的
)
我们要用到里面的一些方法,但那些方法它的private
的,所以我们得把他们搬过来,改成public
的
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class ModOrePlacements { public static List<PlacementModifier> modifiers(PlacementModifier countModifier, PlacementModifier heightModifier) { return List.of(countModifier, SquarePlacementModifier.of(), heightModifier, BiomePlacementModifier.of()); }
public static List<PlacementModifier> modifiersWithCount(int count, PlacementModifier heightModifier) { return modifiers(CountPlacementModifier.of(count), heightModifier); }
public static List<PlacementModifier> modifiersWithRarity(int chance, PlacementModifier heightModifier) { return modifiers(RarityFilterPlacementModifier.of(chance), heightModifier); } }
|
不过在这篇教程中,我们没有用到其中的modifiersWithRarity
方法,这是按照稀有度生成的方法
值得一提的是,原版很少使用这个方法,上层安山岩、花岗岩、闪长岩
和大型钻石矿
这四个用到了这个方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| PlacedFeatures.register( featureRegisterable, ORE_GRANITE_UPPER, registryEntry9, modifiersWithRarity(6, HeightRangePlacementModifier.uniform(YOffset.fixed(64), YOffset.fixed(128))) );
PlacedFeatures.register( featureRegisterable, ORE_DIORITE_UPPER, registryEntry10, modifiersWithRarity(6, HeightRangePlacementModifier.uniform(YOffset.fixed(64), YOffset.fixed(128))) );
PlacedFeatures.register( featureRegisterable, ORE_ANDESITE_UPPER, registryEntry11, modifiersWithRarity(6, HeightRangePlacementModifier.uniform(YOffset.fixed(64), YOffset.fixed(128))) );
PlacedFeatures.register( featureRegisterable, ORE_DIAMOND_LARGE, registryEntry22, modifiersWithRarity(9, HeightRangePlacementModifier.trapezoid(YOffset.aboveBottom(-80), YOffset.aboveBottom(80))) );
|
这是OrePlacedFeatures
中,在bootstrap
中注册的四个矿物的放置特征,这里用到了modifiersWithRarity
方法
当然,我对于世界生成了解的不多,感兴趣的同学可以自行研究
矿物的构造特征
接下来我们来写矿物的构造特征
首先是注册键
1 2 3
| public static final RegistryKey<ConfiguredFeature<?, ?>> ICE_ETHER_ORE_KEY = of("ice_ether_ore"); public static final RegistryKey<ConfiguredFeature<?, ?>> NETHER_ICE_ETHER_ORE_KEY = of("nether_ice_ether_ore"); public static final RegistryKey<ConfiguredFeature<?, ?>> END_ICE_ETHER_ORE_KEY = of("end_ice_ether_ore");
|
虽然说我们前面只写了一个矿石,但它可以生成在三个维度中,所以我们这里就写了三个注册键,分别代表ICE_ETHER_ORE
在主世界
、下界
、末地
中的生成
然后我们来写bootstrap
中的注册
不过我们得先写几个规则判断
1 2 3 4
| RuleTest stoneReplace = new TagMatchRuleTest(BlockTags.STONE_ORE_REPLACEABLES); RuleTest deepSlateReplace = new TagMatchRuleTest(BlockTags.DEEPSLATE_ORE_REPLACEABLES); RuleTest netherReplace = new TagMatchRuleTest(BlockTags.BASE_STONE_NETHER); RuleTest endReplace = new BlockMatchRuleTest(Blocks.END_STONE);
|
啥意思呢?规则判断是用于结构(地物)
的生成,用于检测区块状态是否符合生成条件
说白了,生成矿石必然要替代
世界中已有的一些方块,这个时候就要判断矿石的生成位置是否是那些可以替代的方块
那么这里除了末地
直接用末地石
判断之外,其他维度的都有对应的方块标签
(因为原版的末地并没有矿石,也就没有对应的标签)
接下来写构造特征的目标
1 2 3 4 5 6 7 8 9
| List<OreFeatureConfig.Target> overWorldTargets = List.of( OreFeatureConfig.createTarget(stoneReplace, ModBlocks.ICE_ETHER_ORE.getDefaultState()), OreFeatureConfig.createTarget(deepSlateReplace, ModBlocks.ICE_ETHER_ORE.getDefaultState()));
List<OreFeatureConfig.Target> netherTargets = List.of( OreFeatureConfig.createTarget(netherReplace, ModBlocks.ICE_ETHER_ORE.getDefaultState()));
List<OreFeatureConfig.Target> endTargets = List.of( OreFeatureConfig.createTarget(endReplace, ModBlocks.ICE_ETHER_ORE.getDefaultState()));
|
通过这里的createTarget
方法,我们可以看到,这个方法需要两个参数,一个是规则判断
,一个是方块状态
,将我们的替换方块和我们自己的矿物方块联系起来
最后便是真正的注册
1 2 3
| ConfiguredFeatures.register(featureRegisterable, ICE_ETHER_ORE_KEY, Feature.ORE, new OreFeatureConfig(overWorldTargets, 8)); ConfiguredFeatures.register(featureRegisterable, NETHER_ICE_ETHER_ORE_KEY, Feature.ORE, new OreFeatureConfig(netherTargets, 8)); ConfiguredFeatures.register(featureRegisterable, END_ICE_ETHER_ORE_KEY, Feature.ORE, new OreFeatureConfig(endTargets, 8));
|
这里的三条语句对应三个维度的矿物构造特征,OreFeatureConfig
的参数分别是目标
和矿脉大小
矿物的放置特征
解决了构造特征之后,我们来写放置特征
那么常规的,先是注册键
1 2 3
| public static final RegistryKey<PlacedFeature> ICE_ETHER_ORE_PLACED_KEY = of("ice_ether_ore_placed"); public static final RegistryKey<PlacedFeature> NETHER_ICE_ETHER_ORE_PLACED_KEY = of("nether_ice_ether_ore_placed"); public static final RegistryKey<PlacedFeature> END_ICE_ETHER_ORE_PLACED_KEY = of("end_ice_ether_ore_placed");
|
然后就是bootstrap
中的注册
1 2 3 4 5 6 7 8 9 10 11
| register(featureRegisterable, ICE_ETHER_ORE_PLACED_KEY, registryEntryLookup.getOrThrow(ModConfiguredFeatures.ICE_ETHER_ORE_KEY), ModOrePlacements.modifiersWithCount(12, HeightRangePlacementModifier.uniform(YOffset.fixed(-80), YOffset.fixed(80))));
register(featureRegisterable, NETHER_ICE_ETHER_ORE_PLACED_KEY, registryEntryLookup.getOrThrow(ModConfiguredFeatures.NETHER_ICE_ETHER_ORE_KEY), ModOrePlacements.modifiersWithCount(12, HeightRangePlacementModifier.uniform(YOffset.fixed(-80), YOffset.fixed(80))));
register(featureRegisterable, END_ICE_ETHER_ORE_PLACED_KEY, registryEntryLookup.getOrThrow(ModConfiguredFeatures.END_ICE_ETHER_ORE_KEY), ModOrePlacements.modifiersWithCount(12, HeightRangePlacementModifier.uniform(YOffset.fixed(-80), YOffset.fixed(80))));
|
这里我们调用了ModOrePlacements
中的modifiersWithCount
方法,这个方法是用于生成矿物的修饰符,参数分别是每个区块的生成数量
和高度范围
高度范围使用的是uniform
方法,这个方法是一个均匀分布
的高度范围,参数是最低高度
和最高高度
当然还有一个trapezoid
方法,这个方法是一个梯形分布
的高度范围,参数同样是最低高度
和最高高度
,但它的分布法是两端低,中间高
以这里-80
和80
为例,如果采用梯形分布
,那么在高度0
的位置,矿物的生成概率是最高的,而在-80
和80
的位置,矿物的生成概率是最低的
我们可以看一下Wiki上的那个图,那个图里的三角形就是采用梯形分布
的高度范围
矿物的生成器
之后我们还得写一个生成器,这个生成器是用来生成矿物的
我们创建一个ModOreGeneration
类,然后在里面写一个generateOres
方法
1 2 3 4 5 6 7 8 9 10 11
| public class ModOreGeneration {
public static void generateOres() { BiomeModifications.addFeature(BiomeSelectors.foundInOverworld(), GenerationStep.Feature.UNDERGROUND_ORES, ModPlacedFeatures.ICE_ETHER_ORE_PLACED_KEY); BiomeModifications.addFeature(BiomeSelectors.foundInTheNether(), GenerationStep.Feature.UNDERGROUND_ORES, ModPlacedFeatures.NETHER_ICE_ETHER_ORE_PLACED_KEY); BiomeModifications.addFeature(BiomeSelectors.foundInTheEnd(), GenerationStep.Feature.UNDERGROUND_ORES, ModPlacedFeatures.END_ICE_ETHER_ORE_PLACED_KEY); } }
|
这里我们区别于前面写的树和花,不是选定某个特定的生物群系,而是选定了主世界
、下界
、末地
这三个维度,这样我们的矿石理论上可以生成在任意生物群系中
而后,不要忘记调用generateOres
方法
1
| ModOreGeneration.generateOres();
|
那么在此之后,我们就可以跑数据生成,然后看看我们的矿物是否生成在世界中了(建议新建存档哦)