User Tools

Site Tools


zh_cn:tutorial:structures

This is an old revision of the document!


添加结构特征 [1.16.3]

现在,往世界中注册并放置一些结构。

入药查看原版结构的实例,可以从简单的IglooFeatureIglooGenerator开始。然而,制作新结构的上升的标准是使用拼图结构,这样更易于使用并可以让你少打一些代码。这里有关于拼图结构和制作方法的教程。

对于大多数基本的结构,你需要地物(feature)和生成器(generator)。地物处理注册结构并在生成世界时加载的过程。生成器处理方块的放置,或者在结构文件中加载(如果选择这样做)。

注意本教程依赖标记为实验性的Fabric API中的生物群系修改API。如果API不起作用,考虑使用mixin版本

创建地物

要创建基本的地物(feature),我们推荐创建扩展StructureFeature<DefaultFeatureConfig>的类。大多数原版结构,如沉船、雪屋、神殿都是以StructureFeature<DefaultFeatureConfig>为基础,

你需要覆写getStructureStartFactory方法。对于getStructureStartFactory,大多数原版的结构在其地物类中创建扩展StructureStart的类。

public class MyFeature extends StructureFeature<DefaultFeatureConfig> {
  public MyFeature(Codec<DefaultFeatureConfig> codec) {
    super(codec);
  }
 
  @Override
  public StructureFeature.StructureStartFactory<DefaultFeatureConfig> getStructureStartFactory() {
    return Start::new;
  }
 
  public static class Start extends StructureStart<DefaultFeatureConfig> {
    public Start(StructureFeature<DefaultFeatureConfig> feature, int chunkX, int chunkZ, BlockBox box, int references,
        long seed) {
      super(feature, chunkX, chunkZ, box, references, seed);
    }
 
    // 世界尝试在新的结构中生成时调用,同时也是地物和结构之间的“空隙(gap)”。
    public void init(DynamicRegistryManager registryManager, ChunkGenerator chunkGenerator, StructureManager manager, int chunkX,
        int chunkZ, Biome biome, DefaultFeatureConfig config) {
      int x = chunkX * 16;
      int z = chunkZ * 16;
      int y = chunkGenerator.getHeight(x, z, Heightmap.Type.WORLD_SURFACE_WG);
      BlockPos pos = new BlockPos(x, y, z);
      BlockRotation rotation = BlockRotation.random(this.random);
      MyGenerator.addPieces(manager, pos, rotation, this.children);
      this.setBoundingBoxFromChildren();
    }
  }
}

创建生成器

你可能已经注意到,我们需要创建生成器。

This is where structure files and generating straight from a generate method part ways. 有两种方式实现这样做:

  • If you want, you can simply override generate in your piece class and use addBlock to place blocks directly in the world. This is a valid option and was popular pre-1.13.
  • Use structure files. These are rather powerful at this point and are highly recommended.

本教程中,使用结构文件,不需要override任何内容,但确实需要:

  • 指向结构文件的标识符(identifier,例如“igloo/top”
  • 一些安装方法——例如addPieces就很不错。
public class MyGenerator {
  private static final Identifier IGLOO_TOP = new Identifier("igloo/top");
 
  public static void addPieces(StructureManager manager, BlockPos pos, BlockRotation rotation, List<StructurePiece> pieces) {
    pieces.add(new MyPiece(manager, pos, IGLOO_TOP, rotation));
  }
}

addPieces方法中,你可以选择往你的生成过程中添加哪些结构。

我们现在在生成器类中创建我们刚刚提到的结构,创建名为MyPiece的类,继承SimpleStructurePiece

Override required methods, and add a constructor that takes in a StructureManager, BlockPos, Identifier and Rotation. toNbt isn't required but is available if you need it. We're also implementing initializeStructureData, which is not an override. We also have 2 constructors: 1 for our own pieces, and one for registry. A basic template would be:

public static class MyPiece extends SimpleStructurePiece {
  private final BlockRotation rotation;
  private final Identifier template;
 
  public MyPiece(StructureManager structureManager, CompoundTag compoundTag) {
    super(ExampleMod.MY_PIECE, compoundTag);
    this.template = new Identifier(compoundTag.getString("Template"));
    this.rotation = BlockRotation.valueOf(compoundTag.getString("Rot"));
    this.initializeStructureData(structureManager);
  }
 
  public MyPiece(StructureManager structureManager, BlockPos pos, Identifier template, BlockRotation rotation) {
    super(ExampleMod.MY_PIECE, 0);
    this.pos = pos;
    this.rotation = rotation;
    this.template = template;
 
    this.initializeStructureData(structureManager);
  }
 
  private void initializeStructureData(StructureManager structureManager) {
    Structure structure = structureManager.getStructureOrBlank(this.template);
    StructurePlacementData placementData = (new StructurePlacementData())
      .setRotation(this.rotation)
      .setMirror(BlockMirror.NONE)
      .addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS);
    this.setStructureData(structure, this.pos, placementData);
  }
 
  protected void toNbt(CompoundTag tag) {
    super.toNbt(tag);
    tag.putString("Template", this.template.toString());
    tag.putString("Rot", this.rotation.name());
  }
 
  @Override
  protected void handleMetadata(String metadata, BlockPos pos, ServerWorldAccess serverWorldAccess, Random random,
      BlockBox boundingBox) {
  }
}

handleMetadata is where you look at data blocks within your structure and can do tasks based on what you find. This can be good for dynamic stuff such as placing certain mobs based on what mod is on and so on.

In vanilla structures, data blocks are placed above chests so they can be filled with loot in this method. HOWEVER, you do not need to use datablocks to place chests with loot. Instead, use this command to set a north facing chest with a loottable. Save this chest into your structure's nbt file and it will generate loot when opened for the first time. (Don't open the chest before saving to the nbt file!)

/setblock ~ ~ ~ minecraft:chest[facing=north]{LootTable:"modid:loottable"}

We set the StructurePieceType to ExampleMod.MY_PIECE; this is the variable that holds your registered structure piece.

注册功能

最后一步是注册我们的功能。 我们需要注册:

  • StructurePieceType
  • StructureFeature<DefaultFeatureConfig>
  • StructureFeature<?>

我们还需要将结构添加到“结构”列表中,并将其添加到每个生物群系中,作为功能部件和生成步骤。

注册件类型:

public static final StructurePieceType myStructurePieceType = Registry.register(Registry.STRUCTURE_PIECE, "my_piece", MyGenerator.Piece::new);

注册功能:

public static final StructureFeature<DefaultFeatureConfig> myFeature = Registry.register(Registry.FEATURE, "my_feature", new MyFeature());

注册结构:

public static final StructureFeature<?> myStructure = Registry.register(Registry.STRUCTURE_FEATURE, "my_structure", myFeature);

要将功能放入功能列表,可以使用:

Feature.STRUCTURES.put("My Awesome Feature", myFeature);

对于测试,将功能注册到每个生物群系并将生成率设置为100%是个好主意,这样您就可以确保其生成并正常工作。 您可能不希望您的结构漂浮在水中,因此我们也将其过滤掉。 通过遍历生物群系列表并将其添加为特征和生成步骤,将其添加到每个生物群系:

  1. for(Biome biome : Registry.BIOME) {
  2. if(biome.getCategory() != Biome.Category.OCEAN && biome.getCategory() != Biome.Category.RIVER) {
  3. biome.addStructureFeature(myFeature, new DefaultFeatureConfig());
  4. biome.addFeature(GenerationStep.Feature.SURFACE_STRUCTURES, Biome.configureFeature(myFeature, new DefaultFeatureConfig(), Decorator.CHANCE_PASSTHROUGH, new ChanceDecoratorConfig(0)));
  5. }
  6. }

ChanceDecoratorConfig的参数基本上是在生成之前将跳过多少个块。 0是每个块,1是彼此,并且100是每100。

您需要将结构添加为特征,以便您的生物群系知道其存在,然后作为生成步骤,以使其实际生成。

加载到您的世界中,如果一切顺利,应该会遇到很多的雪屋。

zh_cn/tutorial/structures.1627144461.txt.gz · Last modified: 2021/07/24 16:34 by solidblock