User Tools

Site Tools


tutorial:features

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
tutorial:features [2020/01/08 12:17] lightcolourtutorial:features [2023/12/18 01:19] (current) – [Adding a configured feature to a biome] update code solidblock
Line 1: Line 1:
-===== 在您的世界中生成Feature ===== +===== Adding Features ===== 
-岩石,树木,矿石和池塘都是Feature的示例。 它们是对世界的简单补充,它们的生成取决于它们的配置方式。 在本教程中,我们将研究如何在我们的世界中随机生成一个简单的石螺旋Feature。 +Rocks, trees, ores, and ponds are all examples of features. 
-==== 创建Feature类 ==== +They are simple generation additions to the world which generate depending on how they are configured. 
-一个简单的Feature如下所示: +In this tutorial, we'll generate a simple pillar feature.
-<code java [enable_line_numbers="true"]> +
-public class StoneSpiralFeature extends Feature<DefaultFeatureConfig> {+
  
-    public StoneSpiralFeature(Function<Dynamic<?>? extends DefaultFeatureConfig> config) { +If you want to do something similar to vanilla (like ores or flower patches)you should first look for an existing feature you can use. 
-        super(config); +In that case, skip the "Creating a feature" part of this tutorial.
-    }+
  
-    @Override +There are 3 steps that are required to add a feature to a biome. 
-    public boolean generate(IWorld world, ChunkGenerator<? extends ChunkGeneratorConfig> chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { +  * Create a feature 
-        BlockPos topPos = world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos); +  * Configure a feature 
-        Direction offset = Direction.NORTH;+  * Use [[https://github.com/FabricMC/fabric/pull/1097|Biome Modification API in Fabric API]] to add your feature to biomes.
  
-        for (int y = 1; y < 16; y++) { + 
-            offset offset.rotateYClockwise(); +==== Creating a feature ==== 
-            world.setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3);+Let's create a feature that spawns a 1x1 pillar of blocks on the ground. As an added challenge, let's also make it configurable, so we can change the height and material of the pillars. 
 + 
 +We'll first create a new class for our feature. This is where the generation logic will go. 
 + 
 +<yarncode java> 
 +public class ExampleFeature extends class_3031<ExampleFeatureConfig>
 +  public ExampleFeature(Codec<FeatureConfig> configCodec) { 
 +    super(configCodec); 
 +  } 
 + 
 +  // this method is what is called when the game tries to generate the feature. it is where the actual blocks get placed into the world. 
 +  @Override 
 +  public boolean method_13151(class_5821<ExampleFeatureConfig> context) { 
 +        class_5281 world = context.method_34383(); 
 +        // the origin is the place where the game starts trying to place the feature 
 +        class_2338 origin = context.getOrigin(); 
 +        // we won't use the random here, but we could if we wanted to 
 +        class_5819 random = context.method_33654(); 
 +        ExampleFeatureConfig config = context.method_33656(); 
 + 
 +        // don't worry about where these come from-- we'll implement these methods soon 
 +        int number = config.number(); 
 +        class_2960 blockId = config.blockId(); 
 + 
 +        class_2680 blockState = class_7923.field_41175.get(blockId).method_9564(); 
 +        // ensure the ID is okay 
 +        if (blockState == null) throw new IllegalStateException(blockId + " could not be parsed to a valid block identifier!"); 
 + 
 +        // find the surface of the world 
 +        class_2338 testPos = new class_2338(origin); 
 +        for (int y = 0; y < world.method_31605(); y++) { 
 +            testPos testPos.method_10086(); 
 +            // the tag name is dirt, but includes grass, mud, podzol, etc. 
 +            if (world.method_8320(testPos).isIn(class_3481.field_29822)) { 
 +                if (world.method_8320(testPos.method_10086()).isOf(class_2246.field_10124)) { 
 +                    for (int i = 0; i < number; i++
 +                        // create a simple pillar of blocks 
 +                        world.method_8501(testPosblockState, 0x10); 
 +                        testPos = testPos.method_10086(); 
 + 
 +                        // ensure we don't try to place blocks outside the world 
 +                        if (testPos.getY() >= world.method_8624()) break; 
 +                    } 
 +                    return true; 
 +                } 
 +            }
         }         }
 +       // the game couldn't find a place to put the pillar
 +        return false;
 +    }
 +}
  
-        return true;+</yarncode> 
 +Now, we need to implement that ''ExampleFeatureConfig'' record. This is where we define the variables that we use in our ''Feature''. This config is essentially a wrapper for the parameters we want to pass to our feature. Note: while this tutorial only uses integers and BlockStates, other useful objects in the game also have codecs that can give you more control over how your feature generates. ''BlockStateProvider''s are a good example of this. 
 +<yarncode java> 
 +public record ExampleFeatureConfig(int number, Identifier blockId) implements FeatureConfig { 
 +    public static final Codec<ExampleFeatureConfig> CODEC = RecordCodecBuilder.create( 
 +        instance -> instance.group( 
 +                        // you can add as many of these as you want, one for each parameter 
 +                        Codecs.POSITIVE_INT.fieldOf("number").forGetter(ExampleFeatureConfig::number), 
 +                        Identifier.CODEC.fieldOf("blockID").forGetter(ExampleFeatureConfig::blockId)) 
 +                .apply(instance, ExampleFeatureConfig::new)); 
 +
 +</yarncode> 
 + 
 +Now that we have our config defined, the errors in our feature class will resolve. But we're not done yet-- now we need to add our feature to the game. Features can be registered like most other content in the game, and there aren't any special builders or mechanics you'll have to worry about. 
 + 
 +<code java> 
 +public class ExampleMod implements ModInitializer { 
 +    public static final Identifier EXAMPLE_FEATURE_ID = new Identifier("tutorial", "example_feature"); 
 +    public static final ExampleFeature EXAMPLE_FEATURE = new ExampleFeature(ExampleFeatureConfig.CODEC); 
 + 
 +    @Override 
 +    public void onInitialize() { 
 +        Registry.register(Registries.FEATURE, EXAMPLE_FEATURE_ID, EXAMPLE_FEATURE);
     }     }
 } }
 </code> </code>
  
-构造函数采用''Function<Dynamic<? extends DefaultFeatureConfig>>'',这是数据修复程序配置实例的工厂。 您可以直接在超级调用中或在实例化功能时为默认配置功能传递''DefaultFeatureConfig :: deserialize''+If you plan to configure and use your feature using datapacks, you can stop here. To implement it in code, read on.
  
-当块决定生成Feature时,将调用``generate``。 如果将功能配置为产生每个块,则也会为正在生成的每个块调用此功能。 在将功能配置为以每个生物群落以一定速率生成的情况下,仅在世界想要生成结构的情况下才调用``generate``。+==== Configuring a feature ==== 
 +We need to give a configuration to a feature, before we can add it to biomes. Make sure to register configured features as well as features. Here is where we specify the parameters of our feature. We'll generate 10-block-high pillars out of netherite. In fact, we could register as many of these ''ConfiguredFeatures'' as we wanted, just changing the config parameters each time.
  
-在我们的实现中,我们将从世界的最高位置开始构建一个简单的16块高的石头螺旋:+<yarncode java> 
 +public class FeatureExampleMod implements ModInitializer {
  
-<code java> +    public static final Identifier EXAMPLE_FEATURE_ID = new Identifier("tutorial""example_feature"); 
-@Override +    public static final ExampleFeature EXAMPLE_FEATURE new ExampleFeature(ExampleFeatureConfig.CODEC);
-public boolean generate(IWorld worldChunkGenerator<? extends ChunkGeneratorConfig> chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config{ +
-    BlockPos topPos world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos)+
-    Direction offset = Direction.NORTH;+
  
-    for (int y 1; y 16; y++) { +    public static final ConfiguredFeature<ExampleFeatureConfig, ExampleFeature> EXAMPLE_FEATURE_CONFIGURED new ConfiguredFeature<>
-        offset = offset.rotateYClockwise(); +                    EXAMPLE_FEATURE, 
-        world.setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3); +                    new ExampleFeatureConfig(10, new Identifier("minecraft", "netherite_block"))); 
-    }+    );
  
-    return true;+ 
 +    @Override 
 +    public void onInitialize() { 
 +        Registry.register(Registry.FEATURE, EXAMPLE_FEATURE_ID, EXAMPLE_FEATURE); 
 +        Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, EXAMPLE_FEATURE_ID, EXAMPLE_FEATURE_CONFIGURED); 
 +    }
 } }
-</code>+</yarncode
  
-==== 注册一个Feature ==== +FIXME The last line has to be updated
-可以像注册游戏中的其他大多数内容一样注册Feature,而且您不必担心任何特殊的构建器或机制。 +
-<code java> +
-private static final Feature<DefaultFeatureConfig> LAVA_HOLE = Registry.register( +
- Registry.FEATURE, +
- new Identifier("tutorial", "stone_spiral"), +
- new StoneSpiralFeature(DefaultFeatureConfig::deserialize) +
-); +
-</code>+
  
-==== 向生物群落添加Feature ==== +==== Adding a configured feature to a biome ==== 
-生物群系有一种称为''addFeature''的方法,用于将Feature添加到生物群落的生成过程中。 您可以在每个生物群落类(例如''ForestBiome''''SavannaBiome'')中查看此方法的更详细用法。+We use the Biome Modification API. The final stage of feature configuration is creating a ''PlacedFeature''. This class is a replacement for ''Decorators'' on ''ConfiguredFeatures''. Don't forget to register it as well!
  
-我们可以遍历''Registry.BIOME''以将我们的Feature添加到每个生物群系中。 +Our final initializer class looks like this: 
-<code java> +<yarncode java> 
-Registry.BIOME.forEach(biome -> biome.addFeature+public class ExampleMod implements ModInitializer { 
-        GenerationStep.Feature.RAW_GENERATION+ 
- Biome.configureFeature+    public static final Identifier EXAMPLE_FEATURE_ID = new Identifier("tutorial", "example_feature"); 
- LAVA_HOLE, +    public static final ExampleFeature EXAMPLE_FEATURE = new ExampleFeature(ExampleFeatureConfig.CODEC); 
- new DefaultFeatureConfig(), +    public static final ConfiguredFeature<ExampleFeatureConfig, ExampleFeature> EXAMPLE_FEATURE_CONFIGURED = new ConfiguredFeature<>( 
- Decorator.CHANCE_HEIGHTMAP+                    EXAMPLE_FEATURE, 
- new ChanceDecoratorConfig(100) +                    new ExampleFeatureConfig(10, new Identifier("minecraft", "netherite_block")) 
-+    ); 
-)); +    // our PlacedFeature. this is what gets passed to the biome modification API to add to the biome. 
-</code>+    public static PlacedFeature EXAMPLE_FEATURE_PLACED = new PlacedFeature( 
 +            RegistryEntry.of( 
 +                    EXAMPLE_FEATURE_CONFIGURED 
 +                  //  the SquarePlacementModifier makes the feature generate a cluster of pillars each time 
 +            ), List.of(SquarePlacementModifier.of()) 
 +    ); 
 + 
 +    @Override 
 +    public void onInitialize() { 
 +        // register the features 
 +        Registry.register(class_7923.field_41144EXAMPLE_FEATURE_ID, EXAMPLE_FEATURE); 
 + 
 +        // add it to overworld biomes using FAPI 
 +        BiomeModifications.addFeature
 +                BiomeSelectors.foundInOverworld(), 
 +                // the feature is to be added while flowers and trees are being generated 
 +                GenerationStep.Feature.VEGETAL_DECORATION
 +                RegistryKey.of(RegistryKeys.PLACED_FEATURE, EXAMPLE_FEATURE_ID)); 
 +    } 
 +} 
 +</yarncode> 
 + 
 +The first argument of ''addFeature'' determines what biomes the structure is generated in. 
 + 
 +The second argument helps determine when the structure is generated. 
 +For above-ground houses you may go with ''SURFACE_STRUCTURES'', and for caves, you might go with ''RAW_GENERATION''.
  
-''addFeature''的第一个参数有助于确定何时生成结构。 对于地上的房屋,您可以使用''SURFACE_STRUCTURES'',对于洞穴,您可以使用'' RAW_GENERATION''+For more information, the code used in this tutorial is available [[https://github.com/itsmiir/wiki-example/tree/1.19/src/main/java/com/miir/example/feature|on Github]].
  
-''addFeature''的第二个参数是ConfiguredFeature,可以通过''Biome.configureFeature''创建。 后者接收功能的实例,功能的config类,装饰器和装饰器配置的实例。 
  
-装饰器代表世界如何选择放置要素。 ''CHANCE_HEIGHTMAP''可通过查看高度图来工作,而''NOISE_HEIGHTMAP_32''可使用噪声来工作。 要选择正确的装饰器,请签出与您自己风格相似的香草功能。 装饰器配置将分支此分支; 对于''CHANCE_HEIGHTMAP'',您将传入''ChanceHeightmapDecorator的实例。 
  
-=== 结果 === 
-{{https://i.imgur.com/Kr59o0B.png}} 
tutorial/features.txt · Last modified: 2023/12/18 01:19 by solidblock