Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at master 139 lines 6.5 kB view raw
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