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
Next revisionBoth sides next revision
tutorial:features [2020/04/23 18:18] – [Adding a Feature to a Biome] Update feature configuration 2xsaikotutorial:features [2020/09/06 10:41] – Improve consistency siglong
Line 1: Line 1:
-===== Generating Features in your World ===== +===== Adding Features ===== 
-Rocks, trees, ores, and ponds are all examples of Features. They are simple generation additions to the world which generate depending on how they are configured. In this tutorial, we'll look at generating a simple stone spiral feature in our world randomly.+Rocks, trees, ores, and ponds are all examples of Features. 
 +They are simple generation additions to the world which generate depending on how they are configured. 
 +In this tutorial, we'll look at generating a simple stone spiral feature in the plain biomes randomly.
  
-==== Creating a Feature class ====+There are 3 steps that are required to add a feature to a biome. 
 +  * Create a feature 
 +  * Configure a feature 
 +  * Add a configured feature to a biome 
 + 
 +==== Creating a feature ====
 A simple Feature looks like this: A simple Feature looks like this:
-<code java [enable_line_numbers="true"]>+ 
 +<code java>
 public class StoneSpiralFeature extends Feature<DefaultFeatureConfig> { public class StoneSpiralFeature extends Feature<DefaultFeatureConfig> {
 +  public StoneSpiralFeature(Codec<DefaultFeatureConfig> config) {
 +    super(config);
 +  }
  
-    public StoneSpiralFeature(Function<Dynamic<?>? extends DefaultFeatureConfigconfig) { +  @Override 
-        super(config); +  public boolean generate(StructureWorldAccess worldChunkGenerator generator, Random random, BlockPos pos, 
-    }+      DefaultFeatureConfig config) { 
 +    BlockPos topPos = world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos); 
 +    Direction offset = Direction.NORTH;
  
-    @Override +    for (int y = 1; y <= 15; y++) { 
-    public boolean generate(IWorld world, ChunkGenerator<? extends ChunkGeneratorConfig> chunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { +      offset = offset.rotateYClockwise(); 
-        BlockPos topPos = world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos); +      world.setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3);
-        Direction offset = Direction.NORTH; +
- +
-        for (int y = 1; y < 16; y++) { +
-            offset = offset.rotateYClockwise(); +
-            world.setBlockState(topPos.up(y).offset(offset), Blocks.STONE.getDefaultState(), 3)+
-        } +
- +
-        return true;+
     }     }
 +
 +    return true;
 +  }
 } }
 </code> </code>
  
-The constructor takes in a ''Function<Dynamic<? extends DefaultFeatureConfig>>'', which is a factory for data fixer config instances. You can pass in ''DefaultFeatureConfig::deserialize'' for default config features, either directly in the super call or when you instantiate the feature.+The ''Feature<DefaultFeatureConfig>'' constructor takes in a ''Codec<DefaultFeatureConfig>''. 
 +You can pass in ''DefaultFeatureConfig.CODEC'' for default config features, either directly in the super call in the constructor or when you instantiate the feature.
  
-`generateis called when the chunk decides to generate the feature. If the feature is configured to spawn every chunk, this would be called for each chunk being generated as well. In the case of the feature being configured to spawn at a certain rate per biome, `generatewould only be called in instances where the world wants to spawn the structure. +''generate'' is called when the chunk decides to generate the feature.  
 +If the feature is configured to spawn every chunk, this would be called for each chunk being generated as well. 
 +In the case of the feature being configured to spawn at a certain rate per biome, ''generate'' would only be called in instances where the world wants to spawn the structure. 
  
-In our implementation, we'll build a simple 16-block tall spiral of stone starting at the top block in the world:+In our implementation, we'll build a simple 15-block tall spiral of stone starting at the top block in the world
 + 
 +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> <code java>
-@Override +public class ExampleMod implements ModInitializer { 
-public boolean generate(IWorld world, ChunkGenerator<? extends ChunkGeneratorConfigchunkGenerator, Random random, BlockPos pos, DefaultFeatureConfig config) { +  private static final Feature<DefaultFeatureConfigSTONE_SPIRAL new StoneSpiralFeature(DefaultFeatureConfig.CODEC);
-    BlockPos topPos world.getTopPosition(Heightmap.Type.WORLD_SURFACE, pos)+
-    Direction offset = Direction.NORTH;+
  
-    for (int y = 1; y < 16; y++) { +  @Override 
-        offset = offset.rotateYClockwise(); +  public void onInitialize() { 
-        world.setBlockState(topPos.up(y).offset(offset)Blocks.STONE.getDefaultState(), 3); +    Registry.register(Registry.FEATURE, new Identifier("tutorial""stone_spiral"), STONE_SPIRAL); 
-    } +  }
- +
-    return true;+
 } }
 </code> </code>
  
-==== Registering Feature ==== +==== Configuring feature ==== 
-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+We need to give a configuration to a featureMake sure to register configured feature as well as feature. 
 <code java> <code java>
-private static final Feature<DefaultFeatureConfigLAVA_HOLE Registry.register+public class ExampleMod implements ModInitializer { 
- Registry.FEATURE, +  public static final ConfiguredFeature<?, ?STONE_SPIRAL_CONFIGURED STONE_SPIRAL.configure(FeatureConfig.DEFAULT) 
- new Identifier("tutorial", "stone_spiral"), +      .decorate(Decorator.CHANCE.configure(new ChanceDecoratorConfig(100))); 
- new StoneSpiralFeature(DefaultFeatureConfig::deserialize) + 
-);+  @Override 
 +  public void onInitialize() { 
 +    [...] 
 +     
 +    Registry.register(BuiltinRegistries.CONFIGURED_FEATURE, new Identifier("tutorial", "stone_spiral"), STONE_SPIRAL_CONFIGURED); 
 +  } 
 +}
 </code> </code>
  
-==== Adding a Feature to a Biome ==== +The Decorator represents how the world chooses to place your feature. 
-Biome has a method called ''addFeature'', which is used to add Features to the biome's generation process. You can view more detailed usage of this method inside each Biome class (such as ''ForestBiome'' or ''SavannaBiome'').+To choose the correct Decorator, check out vanilla features with a similar style to your own. 
 +The decorator config branches off this; in the case of ''CHANCE'', you would pass in an instance of ''ChanceDecoratorConfig''.  
 + 
 +==== Adding a configured feature to a biome ==== 
 +Vanilla features generated in the plain biomes are listed in ''DefaultBiomeFeatures.addPlainsFeatures''. We modify this method to add our feature to the plain biomes.
  
-We can iterate over ''Registry.BIOME'' to add our Feature to every Biome. 
 <code java> <code java>
-Registry.BIOME.forEach(biome -> biome.addFeature( +@Mixin(DefaultBiomeFeatures.class) 
-        GenerationStep.Feature.RAW_GENERATION, +public class DefaultBiomeFeaturesMixin { 
- LAVA_HOLE.configure(new DefaultFeatureConfig()) +  @Inject(method = "addPlainsFeatures(Lnet/minecraft/world/biome/GenerationSettings$Builder;)V", at = @At("TAIL")) 
- .configureDecorator(Decorator.CHANCE_HEIGHTMAPnew ChanceDecoratorConfig(100)); +  private static void addPlainsFeatures(GenerationSettings.Builder builderCallbackInfo ci{ 
-));+    builder.feature(GenerationStep.Feature.TOP_LAYER_MODIFICATION, ExampleMod.STONE_SPIRAL_CONFIGURED); 
 +  } 
 +}
 </code> </code>
  
-The first argument of ''addFeature'' 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''.+The first argument of ''feature'' 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''.
  
-The second argument of ''addFeature'' is a ConfiguredFeature, which you can create through ''Biome.configureFeature''The latter takes in an instance of your feature, an instance of your feature's config class, a decorator, and a decorator config.+=== Result === 
 +{{https://i.imgur.com/Kr59o0B.png}}
  
-The Decorator represents how the world chooses to place your Feature. ''CHANCE_HEIGHTMAP'' works by looking at a heightmap, whereas ''NOISE_HEIGHTMAP_32'' works with noise. To choose the correct Decorator, check out vanilla Features with a similar style to your own. The decorator config branches off this; in the case of ''CHANCE_HEIGHTMAP'', you would pass in an instance of ''ChanceHeightmapDecorator'' 
- 
-=== Results === 
-{{https://i.imgur.com/Kr59o0B.png}} 
tutorial/features.txt · Last modified: 2023/12/18 01:19 by solidblock