Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
1package net.lerariemann.infinity.features;
2
3import com.mojang.serialization.Codec;
4import com.mojang.serialization.codecs.RecordCodecBuilder;
5import net.minecraft.core.BlockPos;
6import net.minecraft.core.Direction;
7import net.minecraft.tags.BlockTags;
8import net.minecraft.util.RandomSource;
9import net.minecraft.world.level.LevelAccessor;
10import net.minecraft.world.level.WorldGenLevel;
11import net.minecraft.world.level.block.state.BlockState;
12import net.minecraft.world.level.levelgen.feature.Feature;
13import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
14import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
15import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
16
17public abstract class RandomMushroomFeature
18 extends Feature<RandomMushroomFeature.Config> {
19 public RandomMushroomFeature(Codec<Config> codec) {
20 super(codec);
21 }
22
23 protected void generateStem(LevelAccessor world, RandomSource random, BlockPos pos, Config config, int height, BlockPos.MutableBlockPos mutablePos) {
24 for (int i = 0; i < height; ++i) {
25 mutablePos.set(pos).move(Direction.UP, i);
26 if (world.getBlockState(mutablePos).isSolidRender(
27 //? if <1.21.2
28 /*world, mutablePos*/
29 )) continue;
30 this.setBlock(world, mutablePos, config.stemProvider().getState(random, pos));
31 }
32 }
33
34 protected int getHeight(RandomSource random, int h) {
35 int i = random.nextInt(3) + h - 1;
36 if (random.nextInt(12) == 0) {
37 i *= 2;
38 }
39 return i;
40 }
41
42 protected boolean canGenerate(LevelAccessor world, BlockPos pos, int height, BlockPos.MutableBlockPos mutablePos, Config config) {
43 int i = pos.getY();
44 //? if <1.21.2 {
45 /*var minY = world.getMinBuildHeight();
46 var maxY = world.getMaxBuildHeight();
47 *///?} else {
48 var minY = world.getMinY();
49 var maxY = world.getMaxY();
50 //?}
51 if (i < minY + 1 || i + height + 1 >= maxY) {
52 return false;
53 }
54 BlockState blockState = world.getBlockState(pos.below());
55 if (!blockState.getBlock().equals(config.validBaseBlock().getBlock())) {
56 return false;
57 }
58 for (int j = 0; j <= height; ++j) {
59 int k = this.getCapSize(-1, -1, config.foliageRadius(), j);
60 for (int l = -k; l <= k; ++l) {
61 for (int m = -k; m <= k; ++m) {
62 BlockState blockState2 = world.getBlockState(mutablePos.setWithOffset(pos, l, j, m));
63 if (blockState2.isAir() || blockState2.is(BlockTags.LEAVES)) continue;
64 return false;
65 }
66 }
67 }
68 return true;
69 }
70
71 @Override
72 public boolean place(FeaturePlaceContext<Config> context) {
73 BlockPos.MutableBlockPos mutable;
74 WorldGenLevel structureWorldAccess = context.level();
75 BlockPos blockPos = context.origin();
76 RandomSource random = context.random();
77 Config hugeMushroomFeatureConfig = context.config();
78 int i = this.getHeight(random, context.config().height());
79 if (!this.canGenerate(structureWorldAccess, blockPos, i, mutable = new BlockPos.MutableBlockPos(), hugeMushroomFeatureConfig)) {
80 return false;
81 }
82 this.generateCap(structureWorldAccess, random, blockPos, i, mutable, hugeMushroomFeatureConfig);
83 this.generateStem(structureWorldAccess, random, blockPos, hugeMushroomFeatureConfig, i, mutable);
84 return true;
85 }
86
87 protected abstract int getCapSize(int var1, int var2, int var3, int var4);
88
89 protected abstract void generateCap(LevelAccessor var1, RandomSource var2, BlockPos var3, int var4, BlockPos.MutableBlockPos var5, Config var6);
90
91 public record Config(BlockStateProvider capProvider, BlockStateProvider stemProvider,
92 BlockState validBaseBlock, int foliageRadius,
93 int height) implements FeatureConfiguration {
94 public static final Codec<Config> CODEC = RecordCodecBuilder.create(instance -> instance.group(
95 (BlockStateProvider.CODEC.fieldOf("cap_provider")).forGetter(a -> a.capProvider),
96 (BlockStateProvider.CODEC.fieldOf("stem_provider")).forGetter(a -> a.stemProvider),
97 (BlockState.CODEC.fieldOf("valid_base_block")).forGetter(a -> a.validBaseBlock),
98 (Codec.INT.fieldOf("foliage_radius")).orElse(2).forGetter(a -> a.foliageRadius),
99 (Codec.INT.fieldOf("height")).orElse(5).forGetter(a -> a.height)).apply(
100 instance, Config::new));
101 }
102}
103