User Tools

Site Tools


zh_cn:tutorial:structures

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
Last revisionBoth sides next revision
zh_cn:tutorial:structures [2020/02/04 10:50] – [创建特征] lightcolourzh_cn:tutorial:structures [2021/07/24 16:34] – [创建一个生成器] not done solidblock
Line 1: Line 1:
-====== 生成结构 ======+====== 添加结构特征 [1.16.3] ====== 
 +现在,往世界中注册并放置一些结构。
  
-===== 特征 =====+入药查看原版结构的实例,可以从简单的''IglooFeature''和''IglooGenerator''开始。然而,制作新结构的上升的标准是使用拼图结构,这样更易于使用并可以让你少打一些代码。[[zh_cn:tutorial:jigsaw|这里有关于拼图结构和制作方法的教程。]]
  
-教程中使用所有代码都可以获得: [[https://github.com/Draylar/fabric-structure-example-repo|fabric-structure-example-repo]]+对于大多数基本的结构,你需要地物(feature)和生成器(generator)。地物处理注册结构并生成世界时加载的过程。生成器理方块的放置,或者在结构文件中加载(如果选择这样做)。
  
-==== 介绍 ====+注意本教程依赖标记为实验性的[[https://github.com/FabricMC/fabric/pull/1097|Fabric API中的生物群系修改API]]。如果API不起作用,考虑使用[[?rev=1599808070|mixin版本]]。
  
-我们将研究如何在您世界中注册和放置结构+===== 创建地物 ===== 
 +要创建基本的地物(feature),我们推荐创建扩展''StructureFeature<DefaultFeatureConfig>''类。大多数原版结构,如沉船、雪屋、神殿都是以''StructureFeature<DefaultFeatureConfig>''为基础,
  
-查看实际使用的1.14原版结构的示例,IglooGenerator和IglooFeature是一个良好的开端+你需覆写''getStructureStartFactory''方法。对于''getStructureStartFactory'',大多数原版结构在其地物类中创建扩展''StructureStart''
  
-对于最基本的结构,您将需要一个功能部件和生成器。 该功能处理在生成世界时注册结构并将其加载的过程-回答诸如“我应该在这里生成吗?”和‘我叫什么名字?’之类的问题,生成器处理块的放置或加载 结构文件(如果您选择这样做)。 +<code java> 
-==== 创建特征 ====+public class MyFeature extends StructureFeature<DefaultFeatureConfig>
 +  public MyFeature(Codec<DefaultFeatureConfig> codec) { 
 +    super(codec); 
 +  }
  
-要创建基本功能,我们建议创建一个扩展AbstractTempleFeature <DefaultFeatureConfig>的类。 海难,雪屋和神殿等各种原版结构都使用AbstractTempleFeature作为基础。 您将必须重写以下方法:+  @Override 
 +  public StructureFeature.StructureStartFactory<DefaultFeatureConfig> getStructureStartFactory() { 
 +    return Start::new; 
 +  }
  
-   * shouldStartAt:出于测试目的,返回true。 +  public static class Start extends StructureStart<DefaultFeatureConfig>
-   * getName:您的结构的名称 +    public Start(StructureFeature<DefaultFeatureConfig> feature, int chunkX, int chunkZ, BlockBox box, int references, 
-   * getRadius:结构的半径,用于放置 +        long seed) { 
-   * getSeeedModifier+      super(feature, chunkX, chunkZ, box, references, seed); 
 +    }
  
-您可以将DefaultFeatureConfig :: deserialize传递给造函数进行测试。 +    // 世界尝试在新的结中生成时调用同时也是地物和结构之间“空隙(gap)”。 
- +    public void init(DynamicRegistryManager registryManager, ChunkGenerator chunkGenerator, StructureManager manager, int chunkX, 
-对于getStructureStartFactory大多数原始结构会创建一个在其Feature类中扩展StructureStart类: +        int chunkZ, Biome biome, DefaultFeatureConfig config) { 
- +      int x = chunkX * 16; 
-<code java [enable_line_numbers="true"]> +      int z = chunkZ * 16; 
-public static class MyStructureStart extends StructureStart { +      int y = chunkGenerator.getHeight(x, z, Heightmap.Type.WORLD_SURFACE_WG); 
-    public MyStructureStart (StructureFeature<?> structureFeature_1int int_1, int int_2, Biome biome_1, MutableIntBoundingBox mutableIntBoundingBox_1, int int_3, long long_1) { +      BlockPos pos = new BlockPos(x, y, z); 
-        super(structureFeature_1, int_1, int_2, biome_1, mutableIntBoundingBox_1, int_3, long_1); +      BlockRotation rotation = BlockRotation.random(this.random); 
-    } +      MyGenerator.addPieces(managerpos, rotation, this.children); 
-    @Override +      this.setBoundingBoxFromChildren();
-    public void initialize(ChunkGenerator<?> chunkGenerator, StructureManager structureManager, int chunkX, int chunkZ, Biome biome) { +
-        DefaultFeatureConfig defaultFeatureConfig = chunkGenerator.getStructureConfig(biome, MyMainclass.myFeature); +
-        int x = chunkX * 16; +
-        int z = chunkZ * 16; +
-        BlockPos startingPos = new BlockPos(x, 0, z); +
-        Rotation rotation = Rotation.values()[this.random.nextInt(Rotation.values().length)]+
-        MyGenerator.addParts(structureManagerstartingPos, rotation, this.children, this.random, defaultFeatureConfig); +
-        this.setBoundingBoxFromChildren();+
     }     }
 +  }
 } }
 </code> </code>
-     
-当世界尝试以新结构生成时,这称为“要素”和“生成器”之间的差距。 在您的主类中对该变量的引用尚不存在,但我们将在最后创建它。 您也可以将配置设置为等于新的DefaultFeatureConfig。 您可以在getStructureStartFactory中使用返回MyStructureStart :: new返回此函数。 
-这是结构文件和直接从generate方法生成的部分方式。 有两种解决方法: 
  
-   *如果需要,您可以简单地在Feature类中重写generate,并使用setBlockState将块直接放置在世界上。 这是一个有效的选项,在1.13之前很流行。 +===== 创建生成器 ===== 
-   *使用结构文件和生成器。 在这一点上,这些功非常强大因此强烈议使用+你可已经注意到我们需要创生成器
  
-==== Creating Generator ====+This is where structure files and generating straight from ''generate'' method part ways. 有两种方式实现这样做:
  
-As you have probably noticedwe need to create a generator. We'll name it MyGenerator, and it's referenced in the initialize method of your StructureStart class. It doesn't need to override anything, but does require the following:+  * If you wantyou 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.
  
-  An Identifier that points to your structure file; use "igloo/top" if you need an example. +本教程中,使用结构文件,不需要override任何内容,但确实需要: 
-  * Some sort of setup method - addParts is a good name:+  指向结构文件的标识符(identifier,例如''"igloo/top"'' 
 +  * 一些安装方法——例如''addPieces''就很不错。
  
 <code java> <code java>
-public static void addParts(StructureManager structureManager_1, BlockPos blockPos_1Rotation rotation_1 +public class MyGenerator { 
-    List<StructurePiece> list_1Random random_1DefaultFeatureConfig featureConfig+  private static final Identifier IGLOO_TOP = new Identifier("igloo/top"); 
-    + 
 +  public static void addPieces(StructureManager manager, BlockPos posBlockRotation rotation, List<StructurePiece> pieces) { 
 +    pieces.add(new MyPiece(managerposIGLOO_TOP, rotation)); 
 +  }
 } }
 </code> </code>
-     + 
-In your addParts method, you can choose which structure pieces are added to your generation processYou can add a piece like this:+在''addPieces''方法中,你可以选择往你的生成过程中添加哪些结构。 
 + 
 +我们现在//在生成器类中//创建我们刚刚提到的结构,创建名为''MyPiece''的类,继承''SimpleStructurePiece''。 
 + 
 +Override required methodsand 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> <code java>
-list_1.add(new MyGenerator.Piece(structureManager_1, identifier, blockPos, rotation_1)); +public static class MyPiece extends SimpleStructurePiece { 
-</code> +  private final BlockRotation rotation; 
-   +  private final Identifier template;
-where the identifier is the path we created recently.+
  
-We're now going to create the Piece we just referencedmake a class called Piece that extends SimpleStructurePiece //within your generator class//.+  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); 
 +  }
  
-Override required methods, and add a constructor that takes in a StructureManager, Identifier, BlockPos, and Rotation. **toNbt isn't required but is available if you need it**. We're also implementing our own setStructureData with different argumentsso it's not an overrideWe also have 2 constructors: 1 for our own piecesand one for registryA basic template would be:+  public MyPiece(StructureManager structureManager, BlockPos posIdentifier templateBlockRotation rotation) { 
 +    super(ExampleMod.MY_PIECE0); 
 +    this.pos = pos; 
 +    this.rotation = rotation; 
 +    this.template = template;
  
-<code java [enable_line_numbers="true"]> +    this.initializeStructureData(structureManager); 
-public static class Piece extends SimpleStructurePiece { +  } 
-    private Rotation rotation; + 
-    private Identifier template; +  private void initializeStructureData(StructureManager structureManager) { 
-     +    Structure structure structureManager.getStructureOrBlank(this.template); 
-    public Piece(StructureManager structureManager_1, Identifier identifier_1, BlockPos blockPos_1, Rotation rotation_1) { +    StructurePlacementData placementData = (new StructurePlacementData()
-        super(MyModClass.myStructurePieceType, 0); +      .setRotation(this.rotation
-         +      .setMirror(BlockMirror.NONE
-        this.pos blockPos_1; +      .addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS); 
-        this.rotation = rotation_1; +    this.setStructureData(structure, this.pos, placementData); 
-        this.template = identifier_1; +  
-         + 
-        this.setStructureData(structureManager_1); +  protected void toNbt(CompoundTag tag) { 
-    +    super.toNbt(tag); 
-     +    tag.putString("Template", this.template.toString()); 
-    public Piece(StructureManager structureManager_1, CompoundTag compoundTag_1{ +    tag.putString("Rot", this.rotation.name()); 
-        super(MyModClass.myStructurePieceType, compoundTag_1); +  
-        this.identifier = new Identifier(compoundTag_1.getString("Template")); + 
-        this.rotation = Rotation.valueOf(compoundTag_1.getString("Rot")); +  @Override 
-        this.setStructureData(structureManager_1); +  protected void handleMetadata(String metadata, BlockPos posServerWorldAccess serverWorldAccess, Random random
-    +      BlockBox boundingBox) { 
-     +  }
-    @Override +
-    protected void toNbt(CompoundTag compoundTag_1) { +
-        super.toNbt(compoundTag_1); +
-        compoundTag_1.putString("Template", this.template.toString()); +
-        compoundTag_1.putString("Rot", this.rotation.name()); +
-    +
-     +
-    public void setStructureData(StructureManager structureManager) { +
-        Structure structure_1 = structureManager.getStructureOrBlank(this.identifier); +
-        StructurePlacementData structurePlacementData_1 = (new StructurePlacementData()).setRotation(this.rotation).setMirrored(Mirror.NONE).setPosition(pos).addProcessor(BlockIgnoreStructureProcessor.IGNORE_STRUCTURE_BLOCKS); +
-        this.setStructureData(structure_1, this.pos, structurePlacementData_1); +
-    } +
-     +
-    @Override +
-    protected void handleMetadata(String string_1, BlockPos blockPos_1IWorld iWorld_1, Random random_1MutableIntBoundingBox mutableIntBoundingBox_1) { +
-         +
-    } +
-     +
-    @Override +
-    public boolean generate(IWorld iWorld_1, Random random_1, MutableIntBoundingBox mutableIntBoundingBox_1, ChunkPos chunkPos_1) { +
-       +
-    }+
 } }
 </code> </code>
          
-handleMetadata is where you look at data blocks within your structure and do tasks based on what you find. In vanilla structures, data blocks are placed above chests so they can be filled with loot in this method.+''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.
  
-We set the StructurePieceType to MyModClass.myStructurePiece type; this is the variable that holds your registered structure pieceWe'll handle that after we finish the generate function, which sets the position of your structure and generates it:+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 lootInstead, 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>
  
-<code java [enable_line_numbers="true"]> +We set the ''StructurePieceType'' to ''ExampleMod.MY_PIECE''; this is the variable that holds your registered structure piece
-@Override +
-public boolean generate(IWorld iWorld_1, Random random_1, MutableIntBoundingBox mutableIntBoundingBox_1, ChunkPos chunkPos_1) { +
-    int yHeight = iWorld_1.getTop(Heightmap.Type.WORLD_SURFACE_WG, this.pos.getX() + 8, this.pos.getZ() + 8); +
-    this.pos = this.pos.add(0, yHeight - 1, 0); +
-    return super.generate(iWorld_1, random_1, mutableIntBoundingBox_1, chunkPos_1); +
-+
-</code> +
-     +
-In this case, we simply get the y position of the highest block in the middle of our chunk and generate the structure off that position+
  
-==== Registering Features ====+==== 注册功能 ====
  
-The last step is to register our features. We're going to need to register:+最后一步是注册我们的功能。 我们需要注册:
  
   * StructurePieceType   * StructurePieceType
Line 145: Line 138:
   * StructureFeature<?>   * StructureFeature<?>
  
-We're also going to need to add the structure to the STRUCTURES list and add it to each biome as a feature and generation step.+我们还需要将结构添加到“结构”列表中,并将其添加到每个生物群系中,作为功能部件和生成步骤。
  
-Registering piece type:+注册件类型:
 <code java> <code java>
 public static final StructurePieceType myStructurePieceType = Registry.register(Registry.STRUCTURE_PIECE, "my_piece", MyGenerator.Piece::new); public static final StructurePieceType myStructurePieceType = Registry.register(Registry.STRUCTURE_PIECE, "my_piece", MyGenerator.Piece::new);
 </code> </code>
      
-Registering feature:+注册功能:
 <code java> <code java>
 public static final StructureFeature<DefaultFeatureConfig> myFeature = Registry.register(Registry.FEATURE, "my_feature", new MyFeature()); public static final StructureFeature<DefaultFeatureConfig> myFeature = Registry.register(Registry.FEATURE, "my_feature", new MyFeature());
 </code> </code>
      
-Registering structure:+注册结构:
 <code java> <code java>
 public static final StructureFeature<?> myStructure = Registry.register(Registry.STRUCTURE_FEATURE, "my_structure", myFeature); public static final StructureFeature<?> myStructure = Registry.register(Registry.STRUCTURE_FEATURE, "my_structure", myFeature);
 </code> </code>
      
-To put your feature in the features list, you can use:+要将功能放入功能列表,可以使用:
 <code java> <code java>
 Feature.STRUCTURES.put("My Awesome Feature", myFeature); Feature.STRUCTURES.put("My Awesome Feature", myFeature);
 </code> </code>
      
-For testing, it's a good idea to register your feature to every biome and set the spawn rate to 100% so you can be sure it's spawning and working. You probably don't want your structure floating in the water, so we'll also filter that out. Add it to every biome by iterating over the biome list and adding it as a feature and generation step:+对于测试,将功能注册到每个生物群系并将生成率设置为100%是个好主意,这样您就可以确保其生成并正常工作。 您可能不希望您的结构漂浮在水中,因此我们也将其过滤掉。 通过遍历生物群系列表并将其添加为特征和生成步骤,将其添加到每个生物群系:
  
 <code java [enable_line_numbers="true"]> <code java [enable_line_numbers="true"]>
Line 178: Line 171:
 </code> </code>
  
-ChanceDecoratorConfig's argument is basically how many chunks it will skip over before generating. is every chunk, is every other, and 100 is every 100.+ChanceDecoratorConfig的参数基本上是在生成之前将跳过多少个块。 0是每个块,1是彼此,并且100是每100
  
-You need to add your structure as a feature so your biome knows it exists, and then as a generation step so it's actually generated.+您需要将结构添加为特征,以便您的生物群系知道其存在,然后作为生成步骤,以使其实际生成。
  
-Load into your world, and if all went well, you should be met with a //lot// of Igloos.+加载到您的世界中,如果一切顺利,应该会遇到//很多//的雪屋。