User Tools

Site Tools


zh_cn:tutorial:structures_old

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
zh_cn:tutorial:structures_old [2024/08/25 13:41] – removed - external edit (Unknown date) 127.0.0.1zh_cn:tutorial:structures_old [2024/08/25 13:52] (current) – ↷ Links adapted because of a move operation 52.167.144.180
Line 1: Line 1:
 +====== 添加结构地物 [1.16.3] ======
 +:!: //**对于 1.18 以上版本,Fabric Structure API 不再存在,结构可完全由数据包完成。请参阅 [[https://minecraft.wiki/w/Tutorials/Custom_structures|Minecraft Wiki 中的教程]]。** //
  
 +:!: 本页的翻译质量不佳。如果需要给旧版本添加结构地物,可阅读[[tutorial:structures_old|英文版教程]]。
 +
 +现在,往世界中注册并放置一些结构。
 +
 +如要查看原版结构的实例,可以从简单的 ''IglooFeature'' 和 ''IglooGenerator'' 开始。然而,制作新结构的上升的标准是使用拼图结构,这样更易于使用并可以让你少打一些代码。[[zh_cn:tutorial:jigsaw_old|这里有关于拼图结构和制作方法的教程。]]
 +
 +对于大多数基本的结构,你需要地物(feature)和生成器(generator)。地物处理注册结构并在生成世界时加载的过程。生成器处理方块的放置,或者在结构文件中加载(如果选择这样做)。
 +
 +注意本教程依赖标记为实验性的 [[https://github.com/FabricMC/fabric/pull/1097|Fabric API 中的生物群系修改 API]]。如果 API 不起作用,考虑使用[[start?rev=1599808070|mixin 版本]]。
 +
 +===== 创建地物 =====
 +要创建基本的地物(feature),我们推荐创建继承 ''StructureFeature<DefaultFeatureConfig>'' 的类。大多数原版结构,如沉船、雪屋、神殿都是以 ''StructureFeature<DefaultFeatureConfig>'' 为基础,
 +
 +你需要覆盖 ''getStructureStartFactory'' 方法。对于 ''getStructureStartFactory'',大多数原版的结构在其地物类中创建扩展 ''StructureStart'' 的类。
 +
 +<code java>
 +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();
 +    }
 +  }
 +}
 +</code>
 +
 +===== 创建生成器 =====
 +你可能已经注意到,我们需要创建生成器。
 +
 +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.
 +
 +本教程中,使用结构文件,不需要覆盖任何内容,但确实需要:
 +  * 指向结构文件的 ID,例如 ''"igloo/top"''
 +  * 一些安装方法——例如 ''addPieces'' 就很不错。
 +
 +<code java>
 +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));
 +  }
 +}
 +</code>
 +
 +在 ''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:
 +
 +<code java>
 +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) {
 +  }
 +}
 +</code>
 +    
 +''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!)
 +<code>/setblock ~ ~ ~ minecraft:chest[facing=north]{LootTable:"modid:loottable"}</code>
 +
 +We set the ''StructurePieceType'' to ''ExampleMod.MY_PIECE''; this is the variable that holds your registered structure piece. 
 +
 +==== 注册地物 ====
 +
 +最后一步是注册我们的地物。 我们需要注册:
 +
 +  * StructurePieceType
 +  * StructureFeature<DefaultFeatureConfig>
 +  * StructureFeature<?>
 +
 +我们还需要将结构添加到“结构”列表中,并将其添加到每个生物群系中,作为地物部件和生成步骤。
 +
 +注册件类型:
 +<code java>
 +public static final StructurePieceType myStructurePieceType = Registry.register(Registry.STRUCTURE_PIECE, "my_piece", MyGenerator.Piece::new);
 +</code>
 +  
 +注册地物:
 +<code java>
 +public static final StructureFeature<DefaultFeatureConfig> myFeature = Registry.register(Registry.FEATURE, "my_feature", new MyFeature());
 +</code>
 +  
 +注册结构:
 +<code java>
 +public static final StructureFeature<?> myStructure = Registry.register(Registry.STRUCTURE_FEATURE, "my_structure", myFeature);
 +</code>
 +  
 +要将地物放入地物列表,可以使用:
 +<code java>
 +Feature.STRUCTURES.put("My Awesome Feature", myFeature);
 +</code>
 +  
 +对于测试,将地物注册到每个生物群系并将生成率设置为 100% 是个好主意,这样您就可以确保其生成并正常工作。您可能不希望您的结构漂浮在水中,因此我们也将其过滤掉。通过遍历生物群系列表并将其添加为特征和生成步骤,将其添加到每个生物群系:
 +
 +<code java [enable_line_numbers="true"]>
 +for(Biome biome : Registry.BIOME) {
 +    if(biome.getCategory() != Biome.Category.OCEAN && biome.getCategory() != Biome.Category.RIVER) {
 +        biome.addStructureFeature(myFeature, new DefaultFeatureConfig());
 +        biome.addFeature(GenerationStep.Feature.SURFACE_STRUCTURES, Biome.configureFeature(myFeature, new DefaultFeatureConfig(), Decorator.CHANCE_PASSTHROUGH, new ChanceDecoratorConfig(0)));
 +    }
 +}
 +</code>
 +
 +ChanceDecoratorConfig 的参数基本上是在生成之前将跳过多少个块。 0是每个块,1是彼此,并且100是每100。
 +
 +您需要将结构添加为特征,以便您的生物群系知道其存在,然后作为生成步骤,以使其实际生成。
 +
 +加载到您的世界中,如果一切顺利,应该会遇到//很多//的雪屋。