[Java] Let's create a mod for Minecraft 1.16.1 [Add and generate trees]

(This article is one of a series of commentary articles)

First article: Introduction Previous article: Add Block Next article:

Notes

Up to this point, we have taken the body of continuous articles and assumed that the matters not otherwise specified are the same as before, but please be especially careful as we have changed the environment ** from this article.

environment

** Upgraded version of Minecraft Forge. ** This is because it is a version under development and there are many undeveloped parts. Also, please note that the version is still under development after the update, and updated versions are released every day.

version
OS Winsows 10 Home
Oracle JDK 8u212
Minecraft 1.16.1
Minecraft Forge 1.16.1 (32.0.108) -> 1.16.1 (33.0.22)
InteliJ IDEA 2020.1.3 (CE)

Add each block item

Add logs, leaves, and seedling blocks by referring to Add Block.

Blocks.java


package jp.koteko.liveinwater.block;

import jp.koteko.liveinwater.LiveInWater;
import jp.koteko.liveinwater.block.trees.WaterTree;
import net.minecraft.block.*;
import net.minecraft.block.material.Material;
import net.minecraft.block.material.MaterialColor;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderTypeLookup;
import net.minecraft.world.FoliageColors;
import net.minecraft.world.biome.BiomeColors;
import net.minecraftforge.client.event.ColorHandlerEvent;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

import java.util.ArrayList;
import java.util.List;

@Mod.EventBusSubscriber(modid = LiveInWater.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Blocks {
    public static List<Block> blockList = new ArrayList<Block>();
    public static Block WATERTREE_ROOT_BLOCK = register("watertree_root_block", new Block(AbstractBlock.Properties.create(Material.WOOD).hardnessAndResistance(2.5F).sound(SoundType.WOOD)));
    public static Block WATERTREE_LOG = register("watertree_log", new RotatedPillarBlock(AbstractBlock.Properties.create(Material.WOOD, MaterialColor.WOOD).hardnessAndResistance(2.0F).sound(SoundType.WOOD)));
    public static Block WATERTREE_LEAVES = register("watertree_leaves", new LeavesBlock(AbstractBlock.Properties.create(Material.LEAVES).hardnessAndResistance(0.2F).tickRandomly().sound(SoundType.PLANT).notSolid()));
    public static Block WATERTREE_SAPLING = register("watertree_sapling", new SaplingBlock(new WaterTree(), AbstractBlock.Properties.create(Material.PLANTS).doesNotBlockMovement().tickRandomly().zeroHardnessAndResistance().sound(SoundType.PLANT)));

    private static Block register(String key, Block blockIn){
        blockList.add(blockIn);
        return blockIn.setRegistryName(LiveInWater.MOD_ID, key);
    }

    @SubscribeEvent
    public static void registerBlocks(RegistryEvent.Register<Block> event) {
        for (Block block : blockList) {
            event.getRegistry().register(block);
            if (block instanceof SaplingBlock) {
                RenderTypeLookup.setRenderLayer(block, RenderType.getCutout());
            }
        }
    }

    @SubscribeEvent
    public static void registerBlockColors(ColorHandlerEvent.Block event) {
        event.getBlockColors().register((p_210229_0_, p_210229_1_, p_210229_2_, p_210229_3_) -> {
            return p_210229_1_ != null && p_210229_2_ != null ? BiomeColors.getFoliageColor(p_210229_1_, p_210229_2_) : FoliageColors.getDefault();
        }, WATERTREE_LEAVES);
    }
}

Logs are made in the Rotated Pillar Block class, leaves are made in the Leaves Block class, and seedlings are made in the Sapling Block class. Detailed settings are common to Block (for example, set hardness and resistance with.hardnessAndResistance ()), so change them as appropriate. Each of the above is (should) be a standard value. The first argument passed to the SaplingBlock constructor is an instance of the tree generated by the seedling. I haven't defined it yet, but I'll explain it later. In addition, a description has been added to the block registration part. This sets the render type in order to display the texture of the seedling block correctly. If this is not done, the part that should be transparent will be painted black. Reference Finally, the color of the leaf block is set to change according to the biome color. I brought the description of at 1.14.4 as it is, so I haven't looked deeply inside. You can see more by observing the BlockColors class. About biome color [reference page](https://minecraft-ja.gamepedia.com/%E3%83%90%E3%82%A4%E3%82%AA%E3%83%BC%E3%83% A0 # .E3.83.90.E3.82.A4.E3.82.AA.E3.83.BC.E3.83.A0.E3.82.AB.E3.83.A9.E3.83.BC.E3 See .81.AE.E6.B1.BA.E5.AE.9A). If this is not set, the texture color will be used as is for all biomes and can be omitted.

2020-09-16_22.33.19.png The color of the leaves changes according to the biome (the tree is not generated in the world at this point because it is the state after implementation until the natural generation at the end of the article)


Items.java


package jp.koteko.liveinwater.item;

import jp.koteko.liveinwater.LiveInWater;
import jp.koteko.liveinwater.block.Blocks;
import net.minecraft.block.Block;
import net.minecraft.item.BlockItem;
import net.minecraft.item.Item;
import net.minecraft.item.ItemGroup;
import net.minecraftforge.event.RegistryEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;

import java.util.ArrayList;
import java.util.List;

@Mod.EventBusSubscriber(modid = LiveInWater.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD)
public class Items {
    public static List<Item> itemList = new ArrayList<Item>();
    public static final Item WATERTREE_ROOT = register("watertree_root", new Item((new Item.Properties()).group(LiwItemGroup.DEFAULT)));
    public static final Item WATERTREE_ROOT_BLOCK = register("watertree_root_block", Blocks.WATERTREE_ROOT_BLOCK, LiwItemGroup.DEFAULT);
    public static final Item WATERTREE_LOG = register("watertree_log", Blocks.WATERTREE_LOG, LiwItemGroup.DEFAULT);
    public static final Item WATERTREE_LEAVES = register("watertree_leaves", Blocks.WATERTREE_LEAVES, LiwItemGroup.DEFAULT);
    public static final Item WATERTREE_SAPLING = register("watertree_sapling", Blocks.WATERTREE_SAPLING, LiwItemGroup.DEFAULT);

    private static Item register(String key, Item itemIn) {
        itemList.add(itemIn);
        return itemIn.setRegistryName(LiveInWater.MOD_ID, key);
    }
    private static Item register(String key, Block blockIn, ItemGroup itemGroupIn) {
        return register(key, new BlockItem(blockIn, (new Item.Properties()).group(itemGroupIn)));
    }

    @SubscribeEvent
    public static void registerItems(RegistryEvent.Register<Item> event) {
        for (Item item : itemList) {
            event.getRegistry().register(item);
        }
    }
}

Declare and register BlockItem. See also Add Item (https://qiita.com/koteko/items/578c3cfdfd7ef71df9c1).


Set resources.

\src\main\resources
   ├ assets
   │  └ example_mod
   │     ├ blockstates
   │     │  ├ watertree_leaves.json
   │     │  ├ watertree_log.json
   │     │  └ watertree_sapling.json
   │     ├ lang
   │     │  └ en_us.json
   │     │  └ ja_jp.json
   │     ├ models
   │     │  ├ block
   │     │  │  ├ watertree_leaves.json
   │     │  │  ├ watertree_log.json
   │     │  │  └ watertree_sapling.json
   │     │  └ item
   │     │     ├ example_leaves.json
   │     │     ├ example_log.json
   │     │     └ example_sapling.json
   │     └ textures
   │        ├ block
   │        │  ├ watertree_leaves.json
   │        │  ├ watertree_log.json
   │        │  └ watertree_sapling.json
   │        └ item
   │           └ watertree_sapling.json
   └ data
      └ liveinwater
         └ loot_tables
            └ blocks
               ├ example_leaves.json
               ├ example_log.json
               └ example_sapling.json

blockstates\watertree_leaves.json


{
  "variants": {
    "": { "model": "liveinwater:block/watertree_leaves" }
  }
}

blockstates\watertree_log.json


{
  "variants": {
    "axis=y": { "model": "liveinwater:block/watertree_log" },
    "axis=z": { "model": "liveinwater:block/watertree_log", "x": 90 },
    "axis=x": { "model": "liveinwater:block/watertree_log", "x": 90, "y": 90 }
  }
}

Rotate the model depending on the installation direction.

blockstates\watertree_sapling.json


{
  "variants": {
    "": { "model": "liveinwater:block/watertree_sapling" }
  }
}

en_us.jp


{
  "item.liveinwater.watertree_log": "WaterTree Log",
  "item.liveinwater.watertree_leaves": "WaterTree Leaves",
  "item.liveinwater.watertree_sapling": "WaterTree Sapling",
  "block.liveinwater.watertree_log": "WaterTree Log",
  "block.liveinwater.watertree_leaves": "WaterTree Leaves",
  "block.liveinwater.watertree_sapling": "WaterTree Sapling"
}

ja_jp.json


{
  "item.liveinwater.watertree_log": "Log of water tree",
  "item.liveinwater.watertree_leaves": "Water tree leaves",
  "item.liveinwater.watertree_sapling": "Water tree seedlings",
  "block.liveinwater.watertree_log": "Log of water tree",
  "block.liveinwater.watertree_leaves": "Water tree leaves",
  "block.liveinwater.watertree_sapling": "Water tree seedlings"
}

models\block\watertree_leaves.json


{
  "parent": "block/leaves",
  "textures": {
    "all": "liveinwater:block/watertree_leaves"
  }
}

models\block\watertree_log.json


{
  "parent": "block/cube_column",
  "textures": {
    "end": "liveinwater:block/watertree_log_top",
    "side": "liveinwater:block/watertree_log"
  }
}

Specify block / cube_column for parent, and apply a texture that distinguishes between the top and bottom and sides of the cube. Let's specify the path to each texture file.

models\block\watertree_sapling.json


{
  "parent": "block/cross",
  "textures": {
    "cross": "liveinwater:block/watertree_sapling"
  }
}

models\item\watertree_leaves.json


{
  "parent": "liveinwater:block/watertree_leaves"
}

models\item\watertree_log.json


{
  "parent": "liveinwater:block/watertree_log"
}

models\item\watertree_sapling.json


{
  "parent": "item/generated",
  "textures": {
    "layer0": "liveinwater:item/watertree_sapling"
  }
}

\loot_table\blocks\watertree_leaves.json


{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:alternatives",
          "children": [
            {
              "type": "minecraft:item",
              "conditions": [
                {
                  "condition": "minecraft:alternative",
                  "terms": [
                    {
                      "condition": "minecraft:match_tool",
                      "predicate": {
                        "item": "minecraft:shears"
                      }
                    },
                    {
                      "condition": "minecraft:match_tool",
                      "predicate": {
                        "enchantments": [
                          {
                            "enchantment": "minecraft:silk_touch",
                            "levels": {
                              "min": 1
                            }
                          }
                        ]
                      }
                    }
                  ]
                }
              ],
              "name": "liveinwater:watertree_leaves"
            },
            {
              "type": "minecraft:item",
              "conditions": [
                {
                  "condition": "minecraft:survives_explosion"
                },
                {
                  "condition": "minecraft:table_bonus",
                  "enchantment": "minecraft:fortune",
                  "chances": [
                    0.05,
                    0.0625,
                    0.083333336,
                    0.1
                  ]
                }
              ],
              "name": "liveinwater:watertree_sapling"
            }
          ]
        }
      ]
    }
  ]
}

For details, see [Reference Page](https://minecraft-ja.gamepedia.com/%E3%83%AB%E3%83%BC%E3%83%88%E3%83%86%E3%83%BC% E3% 83% 96% E3% 83% AB).

\loot_table\blocks\watertree_log.json


{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "liveinwater:watertree_log"
        }
      ]
    }
  ]
}

\loot_table\blocks\watertree_sapling.json


{
  "type": "minecraft:block",
  "pools": [
    {
      "rolls": 1,
      "entries": [
        {
          "type": "minecraft:item",
          "name": "liveinwater:watertree_sapling"
        }
      ]
    }
  ]
}

Add to tag

Add the added log block to the minecraft: logs tag. This is used to determine the disappearance of leaf blocks (although it may be used in other parts as well), so if this is not done, the generated leaf blocks will start to disappear immediately.

\src\main\resources
   ├ assets
   └ data
      ├ liveinwater
      └ minecraft
         └ tags
            └ blocks
               └ logs.json

** Create a ** \ src \ main \ resources \ data \ minecraft \ tags \ blocks folder in your project folder and place logs.json in it. Make sure this name is the same.

logs.json


{
  "replace": false,
  "values": [
    "liveinwater:watertree_log"
  ]
}

By giving false to replace, the description in this file will be integrated into minecraft: logs of the same name. Let's specify the block in values.


Similarly, add leaf blocks to the minecraft: leaves tag. This is necessary so that the leaf block is not judged as an obstacle when the tree grows from the seedling (if it is not in the leaves tag, it will not be overwritten when the tree is created).

\src\main\resources
   ├ assets
   └ data
      ├ liveinwater
      └ minecraft
         └ tags
            └ blocks
               ├ leaves.json
               └ logs.json

leaves.json


{
  "replace": false,
  "values": [
    "liveinwater:watertree_leaves"
  ]
}

2020-09-16_22.37.13.png When you press F3 in the game to display the debug display and move the cursor to the block, check that the tag (for example, # mineraft: logs) is displayed around the center right of the screen.

Add TreeFeature class and Tree class

These are difficult to explain in words, but both are classes that manage trees. The Tree class is a class that manages the tree itself and is required in connection with the seedlings that will be added later. On the other hand, the TreeFeature class manages things related to tree generation, and you can also get the corresponding TreeFeature from the Tree class.

\src\main\java\jp\koteko\liveinwater\
   ├ block
   │   └ trees
   │      └ WaterTree.java
   ├ item
   ├ world
   │   └ gen
   │      └ feature
   │         └ WaterTreeFeature.java
   └ LiveInWater.java

WaterTree.java


package jp.koteko.liveinwater.block.trees;

import jp.koteko.liveinwater.world.gen.TreeGenerator;
import net.minecraft.block.trees.Tree;
import net.minecraft.world.gen.feature.BaseTreeFeatureConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;

import javax.annotation.Nullable;
import java.util.Random;

public class WaterTree extends Tree {
    @Nullable
    protected ConfiguredFeature<BaseTreeFeatureConfig, ?> getTreeFeature(Random randomIn, boolean p_225546_2_) {
        return TreeGenerator.WATERTREE.setConfiguration();
    }
}

Extends the Tree abstract class to define the class. Let's define the abstract method getTreeFeature to return an instance of the BaseTreeFeatureConfig class with the config given to the WaterTreeFeature described below (TreeGenerator will be described in a later section). It is designed to receive random numbers, but this is used when the tree grows into a huge species with a probability, so change the value returned according to the random number if necessary.


WaterTreeFeature.java


package jp.koteko.liveinwater.world.gen.feature;

import com.google.common.collect.ImmutableList;
import com.mojang.serialization.Codec;
import jp.koteko.liveinwater.block.Blocks;
import net.minecraft.world.gen.blockstateprovider.SimpleBlockStateProvider;
import net.minecraft.world.gen.feature.*;
import net.minecraft.world.gen.foliageplacer.BlobFoliagePlacer;
import net.minecraft.world.gen.placement.AtSurfaceWithExtraConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraft.world.gen.treedecorator.BeehiveTreeDecorator;
import net.minecraft.world.gen.trunkplacer.StraightTrunkPlacer;

public class WaterTreeFeature extends TreeFeature {
    public WaterTreeFeature(Codec<BaseTreeFeatureConfig> codec) {
        super(codec);
    }

    public ConfiguredFeature<?, ?> configure() {
        return this.setConfiguration().withPlacement(Placement.field_242902_f.configure(new AtSurfaceWithExtraConfig(10, 0.1F, 1)).func_242728_a());
    }

    public ConfiguredFeature<BaseTreeFeatureConfig, ?> setConfiguration() {
        return this.withConfiguration(
                new BaseTreeFeatureConfig.Builder(
                        new SimpleBlockStateProvider(Blocks.WATERTREE_LOG.getDefaultState()),
                        new SimpleBlockStateProvider(Blocks.WATERTREE_LEAVES.getDefaultState()),
                        new BlobFoliagePlacer(FeatureSpread.func_242252_a(2), FeatureSpread.func_242252_a(0), 3),
                        new StraightTrunkPlacer(5, 2, 0),
                        new TwoLayerFeature(1, 0, 1)
                ).func_236700_a_().func_236703_a_(ImmutableList.of(new BeehiveTreeDecorator(0.002F))).build());
    }
}

Define the class by extending the TreeFeature class. Two methods are defined to deal with the restrictions imposed by generics (<BaseTreeFeatureConfig,?> Part) when using Features from other classes.

First, the setConfiguration () below sets what shape this tree will have (withConfiguration ()). A builder is prepared in the config, and the arguments are, in order, the provider of the trunk block, the provider of the leaf block, the leaf layout shape, the trunk layout shape, (argument ʻAbstractFeatureSizeTypeof unknown use). The name is hard to understand, butfunc_236700_a_ () gives a function that makes ʻignore_vines true, andfunc_236703_a_ ()gives an argument (in this example, one that creates a beehive with a probability of 0.002) as a decorator. Each is defined in the builder as a function. Finally, call build () to create a BaseTreeFeatureConfig and pass it as an argument towithConfiguration ().

Next, configure () gives the Feature that wassetConfiguration ()more setting of the placement location (withPlacement () ). It is known that there are many types of Placement, and it is also possible to use multiple types in layers. Therefore, you will need to take a closer look at the contents of the Placement to create your favorite placement. This time I checked and showed only one example. For example, Placement.field_242902_f determines the number of draws,func_242728_a ()finally appliesSquarePlacement and the getPosisions method returns a list of random coordinates in the chunk. Seems to be doing. If I understand this area a little deeper, I may summarize it in another article.

Tree generation

Finally, let's make the implemented tree automatically generated when the world is generated.

\src\main\java\jp\koteko\liveinwater\
   ├ block
   ├ item
   ├ world
   │   └ gen
   │      ├ feture
   │      └ TreeGenerator.java
   └ LiveInWater.java

WorldGenOres.java


package jp.koteko.liveinwater.world.gen;

import com.google.common.collect.Lists;
import jp.koteko.liveinwater.world.gen.feature.WaterTreeFeature;
import net.minecraft.util.RegistryKey;
import net.minecraft.util.registry.Registry;
import net.minecraft.util.registry.WorldGenRegistries;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.biome.BiomeGenerationSettings;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.feature.BaseTreeFeatureConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraftforge.fml.common.ObfuscationReflectionHelper;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public class TreeGenerator {
    public static WaterTreeFeature WATERTREE;
    public static ConfiguredFeature<?, ?> CONFIGURED_WATERTREE;

    public static void init() {
        WATERTREE = Registry.register(Registry.FEATURE, "liveinwater:watertree", new WaterTreeFeature(BaseTreeFeatureConfig.field_236676_a_));
        CONFIGURED_WATERTREE = Registry.register(WorldGenRegistries.field_243653_e, "liveinwater:watertree", WATERTREE.configure());
    }

    public static void setup() {
        addTreeToOverworld(CONFIGURED_WATERTREE);
    }

    private static void addTreeToOverworld(ConfiguredFeature<?, ?> featureIn){
        for(Map.Entry<RegistryKey<Biome>, Biome> biome : WorldGenRegistries.field_243657_i.func_239659_c_()) {
            if(!biome.getValue().getCategory().equals(Biome.Category.NETHER) && !biome.getValue().getCategory().equals(Biome.Category.THEEND)) {
                addFeatureToBiome(biome.getValue(), GenerationStage.Decoration.VEGETAL_DECORATION, featureIn);
            }
        }
    }

    public static void addFeatureToBiome(Biome biome, GenerationStage.Decoration decoration, ConfiguredFeature<?, ?> configuredFeature) {
        List<List<Supplier<ConfiguredFeature<?, ?>>>> biomeFeatures = new ArrayList<>(biome.func_242440_e().func_242498_c());
        while (biomeFeatures.size() <= decoration.ordinal()) {
            biomeFeatures.add(Lists.newArrayList());
        }
        List<Supplier<ConfiguredFeature<?, ?>>> features = new ArrayList<>(biomeFeatures.get(decoration.ordinal()));
        features.add(() -> configuredFeature);
        biomeFeatures.set(decoration.ordinal(), features);

        ObfuscationReflectionHelper.setPrivateValue(BiomeGenerationSettings.class, biome.func_242440_e(), biomeFeatures, "field_242484_f");
    }
}

It's hard to understand everything, so decide what to change if you need to (because I did). In version 1.16.1, [the same way as before](https://qiita.com/koteko/items/aebfc47cf73d7e49baa6#%E6%9C%A8%E3%81%AE%E7%94%9F%E6%88 It was not possible to register the Feature in Biome at% 90). Therefore, look for a reference code and refer to the code of BluePower. I was allowed to.

By defining ʻaddFeatureToBiomeat the bottom, it is possible to register a Feature in Biome in the same way as before. To briefly explain, it seems that the member variablefield_242484_f of the BiomeGenerationSettings` class has a list of Features, so it seems that we are doing the work of overwriting and adding.

Once addFeatureToBiome is defined, it can be implemented in a manner similar to the previous method. Defined ʻaddTreeToOverworld method to register in Overworld Biome and call it in setup method. In addition, each Feature is declared in advance and registered with the ʻinit` method. At this time, it seems that it will not work unless you register the Feature and the Configured Feature as described above (although it was quite packed, I could not understand it completely).


Finally, call the just defined TreeGenerator.init () TreeGenerator.setup () in the main file.

LiveInWater.java


package jp.koteko.liveinwater;

import jp.koteko.liveinwater.world.gen.TreeGenerator;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.event.lifecycle.InterModProcessEvent;
import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

@Mod(LiveInWater.MOD_ID)
public class LiveInWater
{
    public static final String MOD_ID = "liveinwater";
    private static final Logger LOGGER = LogManager.getLogger();

    public LiveInWater() {
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::enqueueIMC);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::processIMC);
        FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);

        TreeGenerator.init();

        MinecraftForge.EVENT_BUS.register(this);
    }

    private void setup(final FMLCommonSetupEvent event)
    {
        LOGGER.info("SETUP START");
        TreeGenerator.setup();
        LOGGER.info("SETUP END");
    }

    private void doClientStuff(final FMLClientSetupEvent event) {
        // do something that can only be done on the client
    }

    private void enqueueIMC(final InterModEnqueueEvent event)
    {
        // some example code to dispatch IMC to another mod
    }

    private void processIMC(final InterModProcessEvent event)
    {
        // some example code to receive and process InterModComms from other mods
    }

    @SubscribeEvent
    public void onServerStarting(FMLServerStartingEvent event) {
        LOGGER.info("server starting");
    }
}

Start the game and create a new world.

2020-09-17_13.09.03.png A tree is being generated (as described so far)

2020-09-17_13.11.40.png A tree is being generated (when Placement and Config are changed)

reference

[Java] Let's create a mod for Minecraft 1.14.4 [9. Add and generate trees] --Qiita BluePower/BPWorldGen.java at master · Qmunity/BluePower · GitHub 1.14.3 Tags help - Modder Support - Forge Forums [Biome-Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%83%90%E3%82%A4%E3%82%AA%E3%83%BC%E3%83%A0# .E3.83.90.E3.82.A4.E3.82.AA.E3.83.BC.E3.83.A0.E3.82.AB.E3.83.A9.E3.83.BC.E3.81 .AE.E6.B1.BA.E5.AE.9A) [Route Table --Minecraft Wiki](https://minecraft-ja.gamepedia.com/%E3%83%AB%E3%83%BC%E3%83%88%E3%83%86%E3%83%BC % E3% 83% 96% E3% 83% AB) [SOLVED] [1.15.2] A texture issue with cross models? - Modder Support - Forge Forums

Implementation record in Forge 1.16.1 32.0.108

For reference, I will record an example of implementing it to a level that works for the time being before the version upgrade of Forge.

Folding
It is a code group that depicts the additional generation of trees at a temporary level (seedlings and blocks that make up trees are not added).
\src\main\java\jp\koteko\liveinwater\
   ├ block
   ├ item
   ├ world
   │   └ gen
   │      ├ feature
   │      │  └ WaterTreeFeature.java
   │      └ TreeGenerator.java
   └ LiveInWater.java

WaterTreeFeature.java


package jp.koteko.liveinwater.world.gen.feature;

import com.mojang.serialization.Codec;
import net.minecraft.world.gen.feature.BaseTreeFeatureConfig;
import net.minecraft.world.gen.feature.TreeFeature;

public class WaterTreeFeature extends TreeFeature {
    public WaterTreeFeature(Codec<BaseTreeFeatureConfig> codec) {
        super(codec);
    }
}

This is pointless at this point, as it's actually no different from the parent class yet. Unlike around 1.14, it seems that an interface called Codec has been introduced. Somehow, when I look at it, it seems to be for general-purpose handling of objects of various classes.

TreeGenerator.java


package jp.koteko.liveinwater.world.gen;

import com.google.common.collect.ImmutableList;
import jp.koteko.liveinwater.world.gen.feature.WaterTreeFeature;
import net.minecraft.block.Blocks;
import net.minecraft.world.biome.Biome;
import net.minecraft.world.gen.GenerationStage;
import net.minecraft.world.gen.blockstateprovider.SimpleBlockStateProvider;
import net.minecraft.world.gen.feature.BaseTreeFeatureConfig;
import net.minecraft.world.gen.feature.ConfiguredFeature;
import net.minecraft.world.gen.feature.TwoLayerFeature;
import net.minecraft.world.gen.foliageplacer.BlobFoliagePlacer;
import net.minecraft.world.gen.placement.AtSurfaceWithExtraConfig;
import net.minecraft.world.gen.placement.Placement;
import net.minecraft.world.gen.treedecorator.BeehiveTreeDecorator;
import net.minecraft.world.gen.trunkplacer.StraightTrunkPlacer;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.OptionalInt;

public class TreeGenerator {
    public static void setup() {
        addTreeToOverworld(
                new WaterTreeFeature(BaseTreeFeatureConfig.field_236676_a_)
                        .withConfiguration(
                                (new BaseTreeFeatureConfig.Builder(
                                        new SimpleBlockStateProvider(Blocks.ACACIA_WOOD.getDefaultState()),
                                        new SimpleBlockStateProvider(Blocks.BLUE_WOOL.getDefaultState()),
                                        new BlobFoliagePlacer(2, 0, 0, 0, 3),
                                        new StraightTrunkPlacer(5, 2, 0),
                                        new TwoLayerFeature(0, 0, 0, OptionalInt.of(4)))
                                ).func_236700_a_().func_236703_a_(ImmutableList.of(new BeehiveTreeDecorator(0.002F))).build())
                        .withPlacement(Placement.COUNT_EXTRA_HEIGHTMAP.configure(new AtSurfaceWithExtraConfig(10, 0.1F, 1)))
        );
    }

    private static void addTreeToOverworld(ConfiguredFeature<?, ?> featureIn) {
        for(Biome biome : ForgeRegistries.BIOMES) {
            if (!biome.getCategory().equals(Biome.Category.NETHER) && !biome.getCategory().equals(Biome.Category.THEEND)) {
                biome.addFeature(GenerationStage.Decoration.VEGETAL_DECORATION, featureIn);
            }
        }
    }
}

It is basically the same as in 1.14, and it is generated by adding the feature of the tree to the biome you want to generate by Biome # addFeature. Many of the names were difficult to understand, and the treatment of Feature and ConfiguredFeature seemed to change, and Biome # createDecoratedFeature was also missing. The above code was written by observing the vanilla code. For ConfiguredFeature (new WaterTreeFeature () ), config (in this case, the block or shape of the tree) and placement (lottery at the time of natural generation) withwithConfiguration ()andwithPlacement () Location) is set. A builder was prepared for the config, so use this. In order, the trunk block (provider), the leaf block (provider), the leaf arrangement shape, the trunk arrangement shape, and the minimum size type (details unknown). Providers should pass an instance of the SimpleBlockStateProvider class unless they do something special. Change only the block type as appropriate. As for the arrangement shape of the leaves and trunk, some types are used in vanilla, so use the appropriate one. Observe the subclasses of FoliagePlacer, ʻAbstractTrunkPlacer. Specify the height etc. with the argument. Regarding the 5th argument of the builder, it seems to be an object of the ʻAbstractFeatureSizeType class managed by the name minimum_size, but I was not sure how it works, so I will match it with other code. Returns an instance of the config by calling build () to the builder. func_236700_a_ () specifies that ivy is not generated, and func_236703_a_ () specifies that a beehive is generated by passing an argument like this. Select the appropriate type of placement (see the Placement class) and set it withconfigure ().

Next article

Recommended Posts

[Java] Let's create a mod for Minecraft 1.16.1 [Add and generate trees]
[Java] Let's create a mod for Minecraft 1.14.4 [9. Add and generate trees]
[Java] Let's create a mod for Minecraft 1.14.4 [8. Add and generate ore]
[Java] Let's create a mod for Minecraft 1.14.4 [4. Add tools]
[Java] Let's create a mod for Minecraft 1.14.4 [5. Add armor]
[Java] Let's create a mod for Minecraft 1.14.4 [7. Add progress]
[Java] Let's create a mod for Minecraft 1.16.1 [Add item]
[Java] Let's create a mod for Minecraft 1.14.4 [1. Add items]
[Java] Let's create a mod for Minecraft 1.14.4 [2. Add block]
[Java] Let's create a mod for Minecraft 1.16.1 [Add block]
[Java] Let's create a mod for Minecraft 1.14.4 [3. Add creative tab]
[Java] Let's create a mod for Minecraft 1.14.4 [Introduction]
[Java] Let's create a mod for Minecraft 1.16.1 [Introduction]
[Java] Let's create a mod for Minecraft 1.14.4 [99. Mod output]
[Java] Let's create a mod for Minecraft 1.14.4 [0. Basic file]
[Java] Let's create a mod for Minecraft 1.14.4 [Extra edition]
[Java] Let's create a mod for Minecraft 1.16.1 [Basic file]
[Java] Create and apply a slide master
Let's create a Java development environment (updating)
Let's install Docker on Windows 10 and create a verification environment for CentOS 8!
Let's create a timed process with Java Timer! !!
Let's create a super-simple web framework in Java
Create a portfolio app using Java and Spring Boot
[Java basics] Let's make a triangle with a for statement
Create a JAVA WEB application and try OMC APM
Let's create a file upload system using Azure Computer Vision API and Azure Storage Java SDK
How to create a lightweight container image for Java apps
[Java twig] Create a parser combinator for recursive descent parsing 2
Create a MOB using the Minecraft Java Mythicmobs plugin | Preparation 1
Create a Java and JavaScript team development environment (gradle environment construction)
How to create and launch a Dockerfile for Payara Micro
[Java] Create a temporary file
Create table and add columns
Java while and for statements
Let's create a TODO application in Java 4 Implementation of posting function
Let's create a TODO application in Java 6 Implementation of search function
Create a JVM for app distribution with JDK9 modules and jlink
Create a high-performance enum with fields and methods like Java with JavaScript
Let's create a TODO application in Java 8 Implementation of editing function
Let's create a TODO application in Java 1 Brief explanation of MVC
Let's create a TODO application in Java 5 Switch the display of TODO
Create a development environment for Ruby 3.0.0 and Rails 6.1.0 on Ubuntu 20.04.1 LTS
Create a Docker Image for redoc-cli and register it on Docker Hub
Let's create a parameter polymorphic mechanism with Generic Dao and Hibernate
AWS SDK for Java 1.11.x and 2.x
Java for beginners, expressions and operators 1
How to sign a Minecraft MOD
Java for beginners, expressions and operators 2
Create a Java project using Eclipse
[Java] How to create a folder
Classes and instances Java for beginners
Create a fluentd server for testing
[Java] Create a jar file with both compressed and uncompressed with the jar command
[Java twig] Create a parser combinator for recursive descent parsing (also memoize)
[Docker] How to create a virtual environment for Rails and Nuxt.js apps
[Rails] How to create a table, add a column, and change the column type
Let's go with Watson Assistant (formerly Conversation) ⑤ Create a chatbot with Watson + Java + Slack
Create a java web application development environment with docker for mac part2
Let's create a TODO application in Java 9 Create TODO display Sort by date and time + Set due date default to today's date
Let's create a TODO application in Java 2 I want to create a template with Spring Initializr and make a Hello world