FIXME 本页有一段时间没有更新了,可能在未来版本不可用。请参考[[tutorial:features|英文页面]]进行更新。
===== 添加地物 [1.17] =====
岩石、树木、矿石、池塘都是地物的例子,是对世界的简单补充生成,并根据配置的方式生成。本教程中,我们将研究如何随机生成简单的石头螺旋地物。
往生物群系中地物特征需要3个步骤。
* 创建地物
* 配置地物
* 使用 [[https://github.com/FabricMC/fabric/pull/1097|Fabric API 中的 Biome Modification API]] 以往生物群系中添加地物。
注意 Biome Modification API 标记为实验性。如果 API 不起作用,考虑使用[[?rev=1599388928|mixin版本]]。
==== 创建地物 ====
一个简单的地物如下所示:
public class StoneSpiralFeature extends Feature {
public StoneSpiralFeature(Codec configCodec) {
super(configCodec);
}
@Override
public boolean generate(FeatureContext context) {
BlockPos topPos = context.getWorld().getTopPosition(Heightmap.Type.OCEAN_FLOOR_WG, context.getOrigin());
Direction offset = Direction.NORTH;
for (int y = 0; y < 15; y++) {
offset = offset.rotateYClockwise();
context.getWorld().setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3);
}
return true;
}
}
在我们的实现中,我们从世界最高位置的方块构建一个简单的15个方块高的岩石螺旋。
''Feature'' 构造器需要一个 ''Codec''。你可以通过直接在构造器的 super 调用中或者在实例化地物时传入 ''DefaultFeatureConfig.CODEC''。
区块决定生成地物时会调用 ''generate''。如果地物配置为在每个区块生成,则每个区块被生成时都会调用一次。如果地物被配置为在每个生物群系以特定的概率生成,''generate'' 只会在世界需要生成结构的实例中调用。
我们的地物目前使用 ''DefaultFeatureConfig'',这意味着暂时还不能配置。但是,你一般都应该尝试让你的地物可以配置,以允许我们为不同的东西使用它,同时也可以在需要时通过数据包去改变。我们的地物的简单的配置如下所示:
public record SpiralFeatureConfig(IntProvider height, BlockStateProvider block) implements FeatureConfig {
public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group(
IntProvider.VALUE_CODEC.fieldOf("height").forGetter(SpiralFeatureConfig::height),
BlockStateProvider.TYPE_CODEC.fieldOf("block").forGetter(SpiralFeatureConfig::block)
).apply(instance, instance.stable(SpiralFeatureConfig::new)));
}
注意我们为高度使用了 ''IntProvider'',并为方块使用了 ''BlockStateProvider'',而不是直接使用一个 ''int'' 或 ''BlockState''。这是因为前者更加强大。比如说,你可以配置地物使用 ''UniformIntProvider'',这样其高度可以变化。
现在,让我们的地物使用 ''SpiralFeatureConfig''(类名也改变了,因为地物现在不总是替换石头):
public class SpiralFeature extends Feature {
public SpiralFeature(Codec configCodec) {
super(configCodec);
}
@Override
public boolean generate(FeatureContext context) {
BlockPos pos = context.getOrigin();
SpiralFeatureConfig config = context.getConfig();
Direction offset = Direction.NORTH;
int height = config.height().get(context.getRandom());
for (int y = 0; y < height; y++) {
offset = offset.rotateYClockwise();
BlockPos blockPos = pos.up(y).offset(offset);
context.getWorld().setBlockState(blockPos, config.block().getBlockState(context.getRandom(), blockPos), 3);
}
return true;
}
}
和游戏内的许多其他内容一样,地物也可以注册,并且也没有你需要担心的特别地构建器或机制。
public class ExampleMod implements ModInitializer {
private static final Feature SPIRAL = new SpiralFeature(SpiralFeatureConfig.CODEC);
@Override
public void onInitialize() {
Registry.register(Registry.FEATURE, new Identifier("tutorial", "spiral"), SPIRAL);
}
}
==== 配置地物 ====
在将地物添加到生物群系之前,我们需要为地物提供配置。确保已配置的地物像地物一样都已经注册。
public class ExampleMod implements ModInitializer {
public static final ConfiguredFeature, ?> STONE_SPIRAL = SPIRAL.configure(new SpiralFeatureConfig(ConstantIntProvider.create(15), new SimpleBlockStateProvider(Blocks.STONE.getDefaultState())))
.decorate(Decorator.HEIGHTMAP.configure(new HeightmapDecoratorConfig(Heightmap.Type.OCEAN_FLOOR_WG)))
.spreadHorizontally()
.applyChance(5);
@Override
public void onInitialize() {
[...]
RegistryKey> stoneSpiral = RegistryKey.of(Registry.CONFIGURED_FEATURE_KEY,
new Identifier("tutorial", "stone_spiral"));
Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, stoneSpiral.getValue(), STONE_SPIRAL);
}
}
注意,螺旋的高度(15 个方块)和需要放置的方块(石头)现在已经可以配置。
装饰器(由 ''decorate'' 添加,或者像 ''spreadHorizontally'' 和 ''applyChange'' 那样的辅助方法)负责如何放置以及何处放置你的地物。要选择正确的装饰器,检查原版的类似地物以及你自己的。
==== 将地物添加到生物群系 ====
我们使用 Biome Modification API。
public class ExampleMod implements ModInitializer {
[...]
@Override
public void onInitialize() {
[...]
BiomeModifications.addFeature(BiomeSelectors.all(), GenerationStep.Feature.UNDERGROUND_ORES, stoneSpiral);
}
}
''addFeature'' 的第一个参数确定结构生成在什么生物群系中。
第二个参数帮助你确定结构何时生成。对于地上的房子,可以用 ''SURFACE_STRUCTURES'',对于洞穴,可以用 ''RAW_GENERATION''。
=== 结果 ===
{{https://i.imgur.com/Kr59o0B.png}}