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.google.common.collect.ImmutableList;
4import com.mojang.serialization.Codec;
5import com.mojang.serialization.codecs.RecordCodecBuilder;
6import net.minecraft.core.BlockPos;
7import net.minecraft.core.Direction;
8import net.minecraft.util.RandomSource;
9import net.minecraft.util.valueproviders.IntProvider;
10import net.minecraft.world.level.LevelAccessor;
11import net.minecraft.world.level.WorldGenLevel;
12import net.minecraft.world.level.block.Block;
13import net.minecraft.world.level.block.Blocks;
14import net.minecraft.world.level.block.LiquidBlock;
15import net.minecraft.world.level.block.state.BlockState;
16import net.minecraft.world.level.levelgen.feature.Feature;
17import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext;
18import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration;
19import net.minecraft.world.level.levelgen.feature.stateproviders.BlockStateProvider;
20import org.jetbrains.annotations.Nullable;
21
22public class RandomColumnsFeature
23 extends Feature<RandomColumnsFeature.Config> {
24 private static final ImmutableList<Block> CANNOT_REPLACE_BLOCKS = ImmutableList.of(Blocks.LAVA, Blocks.BEDROCK, Blocks.WATER, Blocks.END_GATEWAY, Blocks.CHEST, Blocks.SPAWNER);
25
26 public RandomColumnsFeature(Codec<Config> codec) {
27 super(codec);
28 }
29
30 @Override
31 public boolean place(FeaturePlaceContext<Config> context) {
32 int i = context.chunkGenerator().getSeaLevel();
33 BlockPos blockPos = context.origin();
34 WorldGenLevel structureWorldAccess = context.level();
35 RandomSource random = context.random();
36 Config randomColumnsFeatureConfig = context.config();
37 if (!RandomColumnsFeature.canPlaceAt(structureWorldAccess, i, blockPos.mutable())) {
38 return false;
39 }
40 int j = randomColumnsFeatureConfig.height().sample(random);
41 boolean bl = random.nextFloat() < 0.9f;
42 int k = Math.min(j, bl ? 5 : 8);
43 int l = bl ? 50 : 15;
44 boolean bl2 = false;
45 for (BlockPos blockPos2 : BlockPos.randomBetweenClosed(random, l, blockPos.getX() - k, blockPos.getY(), blockPos.getZ() - k, blockPos.getX() + k, blockPos.getY(), blockPos.getZ() + k)) {
46 int m = j - blockPos2.distManhattan(blockPos);
47 if (m < 0) continue;
48 BlockState state = context.config().block().getState(random, blockPos2);
49 bl2 |= this.placeBasaltColumn(structureWorldAccess, i, blockPos2, m, randomColumnsFeatureConfig.reach().sample(random), state);
50 }
51 return bl2;
52 }
53
54 private boolean placeBasaltColumn(LevelAccessor world, int seaLevel, BlockPos pos, int height, int reach, BlockState state) {
55 boolean bl = false;
56 block0: for (BlockPos blockPos : BlockPos.betweenClosed(pos.getX() - reach, pos.getY(), pos.getZ() - reach,
57 pos.getX() + reach, pos.getY(), pos.getZ() + reach)) {
58 int i = blockPos.distManhattan(pos);
59 BlockPos blockPos2 = RandomColumnsFeature.isAirOrOcean(world, seaLevel, blockPos) ?
60 RandomColumnsFeature.moveDownToGround(world, seaLevel, blockPos.mutable(), i) :
61 RandomColumnsFeature.moveUpToAir(world, blockPos.mutable(), i);
62 if (blockPos2 == null) continue;
63 BlockPos.MutableBlockPos mutable = blockPos2.mutable();
64 for (int j = height - i / 2; j >= 0; --j) {
65 if (RandomColumnsFeature.isAirOrOcean(world, seaLevel, mutable)) {
66 this.setBlock(world, mutable, state);
67 mutable.move(Direction.UP);
68 bl = true;
69 continue;
70 }
71 if (!world.getBlockState(mutable).is(state.getBlock())) continue block0;
72 mutable.move(Direction.UP);
73 }
74 }
75 return bl;
76 }
77
78 @Nullable
79 private static BlockPos moveDownToGround(LevelAccessor world, int seaLevel, BlockPos.MutableBlockPos mutablePos, int distance) {
80 //? if <1.21.2 {
81 /*var minY = world.getMinBuildHeight();
82 *///?} else {
83 var minY = world.getMinY();
84 //?}
85 while (mutablePos.getY() > minY + 1 && distance > 0) {
86 --distance;
87 if (RandomColumnsFeature.canPlaceAt(world, seaLevel, mutablePos)) {
88 return mutablePos;
89 }
90 mutablePos.move(Direction.DOWN);
91 }
92 return null;
93 }
94
95 private static boolean canPlaceAt(LevelAccessor world, int seaLevel, BlockPos.MutableBlockPos mutablePos) {
96 if (RandomColumnsFeature.isAirOrOcean(world, seaLevel, mutablePos)) {
97 BlockState blockState = world.getBlockState(mutablePos.move(Direction.DOWN));
98 mutablePos.move(Direction.UP);
99 return !blockState.isAir() && !CANNOT_REPLACE_BLOCKS.contains(blockState.getBlock());
100 }
101 return false;
102 }
103
104 @Nullable
105 private static BlockPos moveUpToAir(LevelAccessor world, BlockPos.MutableBlockPos mutablePos, int distance) {
106 //? if <1.21.2 {
107 /*var maxY = world.getMaxBuildHeight();
108 *///?} else {
109 var maxY = world.getMaxY();
110 //?}
111 while (mutablePos.getY() < maxY && distance > 0) {
112 --distance;
113 BlockState blockState = world.getBlockState(mutablePos);
114 if (CANNOT_REPLACE_BLOCKS.contains(blockState.getBlock())) {
115 return null;
116 }
117 if (blockState.isAir()) {
118 return mutablePos;
119 }
120 mutablePos.move(Direction.UP);
121 }
122 return null;
123 }
124
125 private static boolean isAirOrOcean(LevelAccessor world, int seaLevel, BlockPos pos) {
126 BlockState blockState = world.getBlockState(pos);
127 return blockState.isAir() || (blockState.getBlock() instanceof LiquidBlock) && pos.getY() <= seaLevel;
128 }
129
130 public record Config(IntProvider reach, IntProvider height,
131 BlockStateProvider block) implements FeatureConfiguration {
132 public static final Codec<Config> CODEC = RecordCodecBuilder.create(instance -> instance.group(
133 (IntProvider.codec(0, 3).fieldOf("reach")).forGetter(a -> a.reach),
134 (IntProvider.codec(1, 15).fieldOf("height")).forGetter(a -> a.height),
135 (BlockStateProvider.CODEC.fieldOf("block_provider")).forGetter(a -> a.block)).apply(
136 instance, Config::new));
137 }
138}
139