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.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