diff --git a/patches/minecraft/net/minecraft/world/level/levelgen/feature/trunkplacers/TrunkPlacer.java.patch b/patches/minecraft/net/minecraft/world/level/levelgen/feature/trunkplacers/TrunkPlacer.java.patch new file mode 100644 index 0000000000..7004dcaac7 --- /dev/null +++ b/patches/minecraft/net/minecraft/world/level/levelgen/feature/trunkplacers/TrunkPlacer.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/level/levelgen/feature/trunkplacers/TrunkPlacer.java ++++ b/net/minecraft/world/level/levelgen/feature/trunkplacers/TrunkPlacer.java +@@ -58,7 +_,7 @@ + } + + protected static void m_226169_(LevelSimulatedReader p_226170_, BiConsumer p_226171_, RandomSource p_226172_, BlockPos p_226173_, TreeConfiguration p_226174_) { +- if (p_226174_.f_161215_ || !m_70295_(p_226170_, p_226173_)) { ++ if (!(((net.minecraft.world.level.LevelReader) p_226170_).m_8055_(p_226173_).onTreeGrow((net.minecraft.world.level.LevelReader) p_226170_, p_226171_, p_226172_, p_226173_, p_226174_)) && (p_226174_.f_161215_ || !m_70295_(p_226170_, p_226173_))) { + p_226171_.accept(p_226173_, p_226174_.f_161212_.m_213972_(p_226172_, p_226173_)); + } + diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java index 1a6a3d49fa..4dab3c4bd2 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlock.java @@ -6,6 +6,7 @@ package net.minecraftforge.common.extensions; import java.util.Optional; +import java.util.function.BiConsumer; import net.minecraft.client.Camera; import net.minecraft.util.RandomSource; @@ -24,6 +25,7 @@ import net.minecraft.world.item.*; import net.minecraft.world.item.context.UseOnContext; import net.minecraft.world.level.block.*; import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.level.material.MaterialColor; import net.minecraft.world.level.pathfinder.BlockPathTypes; @@ -326,6 +328,30 @@ public interface IForgeBlock */ boolean canSustainPlant(BlockState state, BlockGetter level, BlockPos pos, Direction facing, IPlantable plantable); + /** + * Called when a tree grows on top of this block and tries to set it to dirt by the trunk placer. + * An override that returns true is responsible for using the place function to + * set blocks in the world properly during generation. A modded grass block might override this method + * to ensure it turns into the corresponding modded dirt instead of regular dirt when a tree grows on it. + * For modded grass blocks, returning true from this method is NOT a substitute for adding your block + * to the #minecraft:dirt tag, rather for changing the behaviour to something other than setting to dirt. + * + * NOTE: This happens DURING world generation, the generation may be incomplete when this is called. + * Use the placeFunction when modifying the level. + * + * @param state The current state + * @param level The current level + * @param placeFunction Function to set blocks in the level for the tree, use this instead of the level directly + * @param randomSource The random source + * @param pos Position of the block to be set to dirt + * @param config Configuration of the trunk placer. Consider azalea trees, which should place rooted dirt instead of regular dirt. + * @return True to ignore vanilla behaviour + */ + default boolean onTreeGrow(BlockState state, LevelReader level, BiConsumer placeFunction, RandomSource randomSource, BlockPos pos, TreeConfiguration config) + { + return false; + } + /** * Checks if this soil is fertile, typically this means that growth rates * of plants on this soil will be slightly sped up. diff --git a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java index fe55e30aeb..9b796c4f50 100644 --- a/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java +++ b/src/main/java/net/minecraftforge/common/extensions/IForgeBlockState.java @@ -6,6 +6,7 @@ package net.minecraftforge.common.extensions; import java.util.Optional; +import java.util.function.BiConsumer; import net.minecraft.client.Camera; import net.minecraft.util.RandomSource; @@ -18,6 +19,7 @@ import net.minecraft.world.entity.item.ItemEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.projectile.FishingHook; import net.minecraft.world.item.context.UseOnContext; +import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration; import net.minecraft.world.level.material.FluidState; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.pathfinder.BlockPathTypes; @@ -275,6 +277,29 @@ public interface IForgeBlockState return self().getBlock().canSustainPlant(self(), level, pos, facing, plantable); } + /** + * Called when a tree grows on top of this block and tries to set it to dirt by the trunk placer. + * An override that returns true is responsible for using the place function to + * set blocks in the world properly during generation. A modded grass block might override this method + * to ensure it turns into the corresponding modded dirt instead of regular dirt when a tree grows on it. + * For modded grass blocks, returning true from this method is NOT a substitute for adding your block + * to the #minecraft:dirt tag, rather for changing the behaviour to something other than setting to dirt. + * + * NOTE: This happens DURING world generation, the generation may be incomplete when this is called. + * Use the placeFunction when modifying the level. + * + * @param level The current level + * @param placeFunction Function to set blocks in the level for the tree, use this instead of the level directly + * @param randomSource The random source + * @param pos Position of the block to be set to dirt + * @param config Configuration of the trunk placer. Consider azalea trees, which should place rooted dirt instead of regular dirt. + * @return True to ignore vanilla behaviour + */ + default boolean onTreeGrow(LevelReader level, BiConsumer placeFunction, RandomSource randomSource, BlockPos pos, TreeConfiguration config) + { + return self().getBlock().onTreeGrow(self(), level, placeFunction, randomSource, pos, config); + } + /** * Checks if this soil is fertile, typically this means that growth rates * of plants on this soil will be slightly sped up. diff --git a/src/test/java/net/minecraftforge/debug/block/OnTreeGrowBlockTest.java b/src/test/java/net/minecraftforge/debug/block/OnTreeGrowBlockTest.java new file mode 100644 index 0000000000..97fc320d07 --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/block/OnTreeGrowBlockTest.java @@ -0,0 +1,86 @@ +package net.minecraftforge.debug.block; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.util.RandomSource; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.LevelReader; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SaplingBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.material.MaterialColor; +import net.minecraftforge.common.IPlantable; +import net.minecraftforge.common.extensions.IForgeBlockState; +import net.minecraftforge.eventbus.api.IEventBus; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.ForgeRegistries; +import net.minecraftforge.registries.RegistryObject; + +import java.util.function.BiConsumer; + +/** + * A test case used to ensure that {@link IForgeBlockState#onTreeGrow(LevelReader, BiConsumer, RandomSource, BlockPos, TreeConfiguration)} + * works properly, using a custom grass block that should revert to its custom dirt form after a tree grows on + * top of it instead of turning to dirt. + */ +@Mod(OnTreeGrowBlockTest.ID) +public class OnTreeGrowBlockTest +{ + public static final boolean ENABLED = true; + + static final String ID = "on_tree_grow_block_test"; + + public static final DeferredRegister BLOCKS = DeferredRegister.create(ForgeRegistries.Keys.BLOCKS, ID); + public static final DeferredRegister ITEMS = DeferredRegister.create(ForgeRegistries.Keys.ITEMS, ID); + + public static final RegistryObject TEST_GRASS_BLOCK = BLOCKS.register("test_grass_block", () -> new Block(BlockBehaviour.Properties.of(Material.GRASS, MaterialColor.COLOR_LIGHT_BLUE).destroyTime(1.5f)) + { + @Override + public boolean canSustainPlant(BlockState state, BlockGetter world, BlockPos pos, Direction facing, IPlantable plantable) + { + return plantable instanceof SaplingBlock; + } + + @Override + public boolean onTreeGrow(BlockState state, LevelReader level, BiConsumer placeFunction, RandomSource randomSource, BlockPos pos, TreeConfiguration config) + { + // Respect vanilla behavior for trees that want custom dirt blocks + if (config.forceDirt) + { + return false; + } + else + { + placeFunction.accept(pos, TEST_DIRT.get().defaultBlockState()); + return true; + } + } + }); + public static final RegistryObject TEST_DIRT = BLOCKS.register("test_dirt", () -> new Block(BlockBehaviour.Properties.of(Material.GRASS, MaterialColor.COLOR_LIGHT_BLUE).destroyTime(1.5f)) + { + @Override + public boolean canSustainPlant(BlockState state, BlockGetter world, BlockPos pos, Direction facing, IPlantable plantable) + { + return plantable instanceof SaplingBlock; + } + }); + public static final RegistryObject TEST_GRASS_BLOCK_ITEM = ITEMS.register("test_grass_block", () -> new BlockItem(TEST_GRASS_BLOCK.get(), new Item.Properties())); + public static final RegistryObject TEST_DIRT_ITEM = ITEMS.register("test_dirt", () -> new BlockItem(TEST_DIRT.get(), new Item.Properties())); + + public OnTreeGrowBlockTest() + { + if (ENABLED) + { + IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus(); + BLOCKS.register(modBus); + ITEMS.register(modBus); + } + } +} diff --git a/src/test/resources/META-INF/mods.toml b/src/test/resources/META-INF/mods.toml index 8bb3a9b314..00f559698f 100644 --- a/src/test/resources/META-INF/mods.toml +++ b/src/test/resources/META-INF/mods.toml @@ -22,6 +22,8 @@ license="LGPL v2.1" +[[mods]] +modId="on_tree_grow_block_test" [[mods]] modId="containertypetest" [[mods]] diff --git a/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_dirt.json b/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_dirt.json new file mode 100644 index 0000000000..2094227ae8 --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_dirt.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "on_tree_grow_block_test:block/test_dirt"} + } +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_grass_block.json b/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_grass_block.json new file mode 100644 index 0000000000..3ee19ad9e2 --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/blockstates/test_grass_block.json @@ -0,0 +1,5 @@ +{ + "variants": { + "": { "model": "on_tree_grow_block_test:block/test_grass_block"} + } +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/models/block/test_dirt.json b/src/test/resources/assets/on_tree_grow_block_test/models/block/test_dirt.json new file mode 100644 index 0000000000..832a25fb37 --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/models/block/test_dirt.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:block/cube_all", + "textures": { + "all": "on_tree_grow_block_test:blocks/test_dirt" + } +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/models/block/test_grass_block.json b/src/test/resources/assets/on_tree_grow_block_test/models/block/test_grass_block.json new file mode 100644 index 0000000000..166ded41ea --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/models/block/test_grass_block.json @@ -0,0 +1,11 @@ +{ + "parent": "minecraft:block/grass_block", + "textures": { + "particle": "on_tree_grow_block_test:blocks/test_dirt", + "bottom": "on_tree_grow_block_test:blocks/test_dirt", + "top": "on_tree_grow_block_test:blocks/test_grass_block_top", + "side": "on_tree_grow_block_test:blocks/test_grass_block_side", + "overlay": "on_tree_grow_block_test:blocks/test_grass_block_side_overlay" + }, + "render_type": "cutout_mipped" +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/models/item/test_dirt.json b/src/test/resources/assets/on_tree_grow_block_test/models/item/test_dirt.json new file mode 100644 index 0000000000..d3fcfccb89 --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/models/item/test_dirt.json @@ -0,0 +1,3 @@ +{ + "parent": "on_tree_grow_block_test:block/test_dirt" +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/models/item/test_grass_block.json b/src/test/resources/assets/on_tree_grow_block_test/models/item/test_grass_block.json new file mode 100644 index 0000000000..31e5d38959 --- /dev/null +++ b/src/test/resources/assets/on_tree_grow_block_test/models/item/test_grass_block.json @@ -0,0 +1,3 @@ +{ + "parent": "on_tree_grow_block_test:block/test_grass_block" +} \ No newline at end of file diff --git a/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_dirt.png b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_dirt.png new file mode 100644 index 0000000000..34f4a5e0a3 Binary files /dev/null and b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_dirt.png differ diff --git a/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side.png b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side.png new file mode 100644 index 0000000000..e371500112 Binary files /dev/null and b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side.png differ diff --git a/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side_overlay.png b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side_overlay.png new file mode 100644 index 0000000000..32e3f7cc8b Binary files /dev/null and b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_side_overlay.png differ diff --git a/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_top.png b/src/test/resources/assets/on_tree_grow_block_test/textures/blocks/test_grass_block_top.png new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/test/resources/data/on_tree_grow_block_test/tags/blocks/dirt.json b/src/test/resources/data/on_tree_grow_block_test/tags/blocks/dirt.json new file mode 100644 index 0000000000..4cf122c19e --- /dev/null +++ b/src/test/resources/data/on_tree_grow_block_test/tags/blocks/dirt.json @@ -0,0 +1,7 @@ +{ + "replace": false, + "values": [ + "on_tree_grow_block_test:test_dirt", + "on_tree_grow_block_test:test_grass_block" + ] +} \ No newline at end of file