Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at master 145 lines 7.1 kB view raw
1package net.lerariemann.infinity.features; 2 3import com.mojang.logging.LogUtils; 4import com.mojang.serialization.Codec; 5import java.util.function.Predicate; 6import net.minecraft.core.BlockPos; 7import net.minecraft.core.Direction; 8import net.minecraft.tags.BlockTags; 9import net.minecraft.util.RandomSource; 10//? if >1.21 { 11import net.minecraft.world.RandomizableContainer; 12 //?} else { 13/*import net.minecraft.world.level.block.entity.RandomizableContainerBlockEntity; 14*///?} 15import net.minecraft.world.entity.EntityType; 16import net.minecraft.world.level.WorldGenLevel; 17import net.minecraft.world.level.block.Block; 18import net.minecraft.world.level.block.Blocks; 19import net.minecraft.world.level.block.entity.BlockEntity; 20import net.minecraft.world.level.block.entity.SpawnerBlockEntity; 21import net.minecraft.world.level.block.state.BlockState; 22import net.minecraft.world.level.levelgen.feature.Feature; 23import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext; 24import net.minecraft.world.level.levelgen.feature.configurations.FeatureConfiguration; 25import net.minecraft.world.level.levelgen.structure.StructurePiece; 26import net.minecraft.world.level.storage.loot.BuiltInLootTables; 27import com.mojang.serialization.codecs.RecordCodecBuilder; 28import org.slf4j.Logger; 29 30public class RandomDungeonFeature extends Feature<RandomDungeonFeature.Config> { 31 private static final Logger LOGGER = LogUtils.getLogger(); 32 private static final BlockState AIR = Blocks.CAVE_AIR.defaultBlockState(); 33 34 public RandomDungeonFeature(Codec<Config> codec) { 35 super(codec); 36 } 37 38 @Override 39 public boolean place(FeaturePlaceContext<Config> context) { 40 BlockPos blockPos2; 41 int u; 42 int t; 43 int s; 44 Predicate<BlockState> predicate = Feature.isReplaceable(BlockTags.FEATURES_CANNOT_REPLACE); 45 BlockPos blockPos = context.origin(); 46 RandomSource random = context.random(); 47 WorldGenLevel structureWorldAccess = context.level(); 48 int j = random.nextInt(2) + context.config().size(); 49 int k = -j - 1; 50 int l = j + 1; 51 int o = random.nextInt(2) + context.config().size(); 52 int p = -o - 1; 53 int q = o + 1; 54 int r = 0; 55 for (s = k; s <= l; ++s) { 56 for (t = -1; t <= 4; ++t) { 57 for (u = p; u <= q; ++u) { 58 blockPos2 = blockPos.offset(s, t, u); 59 boolean bl = structureWorldAccess.getBlockState(blockPos2).isSolid(); 60 if (t == -1 && !bl) { 61 return false; 62 } 63 if (t == 4 && !bl) { 64 return false; 65 } 66 if (s != k && s != l && u != p && u != q || t != 0 || !structureWorldAccess.isEmptyBlock(blockPos2) || !structureWorldAccess.isEmptyBlock(blockPos2.above())) continue; 67 ++r; 68 } 69 } 70 } 71 if (r < 1 || r > 5) { 72 return false; 73 } 74 for (s = k; s <= l; ++s) { 75 for (t = 3; t >= -1; --t) { 76 for (u = p; u <= q; ++u) { 77 blockPos2 = blockPos.offset(s, t, u); 78 BlockState blockState = structureWorldAccess.getBlockState(blockPos2); 79 if (s == k || t == -1 || u == p || s == l || t == 4 || u == q) { 80 //? if <1.21.2 { 81 /*var minY = structureWorldAccess.getMinBuildHeight(); 82 *///?} else { 83 var minY = structureWorldAccess.getMinY(); 84 //?} 85 if (blockPos2.getY() >= minY && !structureWorldAccess.getBlockState(blockPos2.below()).isSolid()) { 86 structureWorldAccess.setBlock(blockPos2, AIR, Block.UPDATE_CLIENTS); 87 continue; 88 } 89 if (!blockState.isSolid() || blockState.is(Blocks.CHEST)) continue; 90 if (t == -1 && random.nextInt(4) != 0) { 91 this.safeSetBlock(structureWorldAccess, blockPos2, context.config().decorationProvider(), predicate); 92 continue; 93 } 94 this.safeSetBlock(structureWorldAccess, blockPos2, context.config().mainProvider(), predicate); 95 continue; 96 } 97 if (blockState.is(Blocks.CHEST) || blockState.is(Blocks.SPAWNER)) continue; 98 this.safeSetBlock(structureWorldAccess, blockPos2, AIR, predicate); 99 } 100 } 101 } 102 block6: for (s = 0; s < 2; ++s) { 103 for (t = 0; t < 3; ++t) { 104 u = blockPos.getX() + random.nextInt(j * 2 + 1) - j; 105 BlockPos blockPos3 = new BlockPos(u, blockPos.getY(), blockPos.getZ() + random.nextInt(o * 2 + 1) - o); 106 if (!structureWorldAccess.isEmptyBlock(blockPos3)) continue; 107 int x = 0; 108 for (Direction direction : Direction.Plane.HORIZONTAL) { 109 if (!structureWorldAccess.getBlockState(blockPos3.relative(direction)).isSolid()) continue; 110 ++x; 111 } 112 if (x != 1) continue; 113 this.safeSetBlock(structureWorldAccess, blockPos3, StructurePiece.reorient(structureWorldAccess, blockPos3, Blocks.CHEST.defaultBlockState()), predicate); 114 //? if >1.21 { 115 RandomizableContainer.setBlockEntityLootTable 116 //?} else { 117 /*RandomizableContainerBlockEntity.setLootTable 118 *///?} 119 (structureWorldAccess, random, blockPos3, BuiltInLootTables.SIMPLE_DUNGEON); 120 continue block6; 121 } 122 } 123 this.safeSetBlock(structureWorldAccess, blockPos, Blocks.SPAWNER.defaultBlockState(), predicate); 124 BlockEntity blockEntity = structureWorldAccess.getBlockEntity(blockPos); 125 if (blockEntity instanceof SpawnerBlockEntity mobSpawnerBlockEntity) { 126 mobSpawnerBlockEntity.setEntityId(EntityType.byString(context.config().mob()).orElse(EntityType.PIG), random); 127 } else { 128 LOGGER.error("Failed to fetch mob spawner entity at ({}, {}, {})", blockPos.getX(), blockPos.getY(), blockPos.getZ()); 129 } 130 return true; 131 } 132 133 public record Config(BlockState mainProvider, BlockState decorationProvider, String mob, 134 int size) implements FeatureConfiguration { 135 public static final Codec<Config> CODEC = RecordCodecBuilder.create(instance -> instance.group( 136 (BlockState.CODEC.fieldOf("main_state")).forGetter(a -> a.mainProvider), 137 (BlockState.CODEC.fieldOf("decor_state")).forGetter(a -> a.decorationProvider), 138 (Codec.STRING.fieldOf("mob")).orElse("minecraft:pig").forGetter(a -> a.mob), 139 (Codec.INT.fieldOf("size")).orElse(2).forGetter(a -> a.size)).apply( 140 instance, Config::new)); 141 142 } 143} 144 145