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.MapCodec;
5import com.mojang.serialization.codecs.RecordCodecBuilder;
6import net.lerariemann.infinity.registry.core.ModFeatures;
7import net.minecraft.core.BlockPos;
8import net.minecraft.core.Direction;
9import net.minecraft.util.ExtraCodecs;
10import net.minecraft.util.RandomSource;
11import net.minecraft.world.level.LevelSimulatedReader;
12import net.minecraft.world.level.block.state.BlockState;
13import net.minecraft.world.level.block.state.properties.BlockStateProperties;
14import net.minecraft.world.level.levelgen.feature.configurations.TreeConfiguration;
15import net.minecraft.world.level.levelgen.feature.foliageplacers.FoliagePlacer;
16import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacer;
17import net.minecraft.world.level.levelgen.feature.trunkplacers.TrunkPlacerType;
18import java.util.List;
19import java.util.function.BiConsumer;
20import java.util.function.Function;
21
22public class WonkyTrunkPlacer extends TrunkPlacer {
23 public static final MapCodec<WonkyTrunkPlacer> CODEC = RecordCodecBuilder.mapCodec(
24 instance -> trunkPlacerParts(instance)
25 .and(
26 instance.group(
27 ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("weight_up", 1f).forGetter(a -> a.weightUp),
28 ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("weight_down", 0.1f).forGetter(a -> a.weightDown),
29 ExtraCodecs.POSITIVE_FLOAT.optionalFieldOf("weight_side", 0.5f).forGetter(a -> a.weightSide)
30 )
31 )
32 .apply(instance, WonkyTrunkPlacer::new));
33 final float weightUp;
34 final float weightDown;
35 final float weightSide;
36 Direction currentDir;
37
38 public WonkyTrunkPlacer(int baseHeight, int firstRandomHeight, int secondRandomHeight, float weightUp, float weightDown, float weightSide) {
39 super(baseHeight, firstRandomHeight, secondRandomHeight);
40 this.weightUp = Math.max(weightUp, 1f);
41 this.weightDown = Math.max(weightDown, 1f);
42 this.weightSide = Math.max(weightDown, 1f);
43 currentDir = Direction.UP;
44 }
45
46 @Override
47 protected TrunkPlacerType<?> type() {
48 return ModFeatures.WONKY_TRUNK.get();
49 }
50
51 @Override
52 public List<FoliagePlacer.FoliageAttachment> placeTrunk(LevelSimulatedReader world, BiConsumer<BlockPos, BlockState> replacer, RandomSource random, int height, BlockPos startPos, TreeConfiguration config) {
53 setDirtAt(world, replacer, random, startPos.below(), config);
54 BlockPos curr = startPos;
55 this.placeLog(world, replacer, random, startPos, config);
56 for (int i = 0; i < height; i++) {
57 double d = random.nextDouble() * (weightUp + weightDown + weightSide);
58 Direction dir;
59 if (d < weightUp) dir = Direction.UP;
60 else if (d < weightUp + weightDown) dir = Direction.DOWN;
61 else {
62 dir = switch (random.nextInt(4)) {
63 case 1 -> Direction.WEST;
64 case 2 -> Direction.EAST;
65 case 3 -> Direction.NORTH;
66 default -> Direction.SOUTH;
67 };
68 }
69 if (!this.validTreePos(world, curr.relative(dir))) dir = Direction.UP;
70 curr = curr.relative(dir);
71 currentDir = dir;
72 this.placeLog(world, replacer, random, curr, config);
73 }
74 return ImmutableList.of(new FoliagePlacer.FoliageAttachment(curr, 0, false));
75 }
76
77 @Override
78
79
80 protected boolean placeLog(
81 LevelSimulatedReader world,
82 BiConsumer<BlockPos, BlockState> replacer,
83 RandomSource random,
84 BlockPos pos,
85 TreeConfiguration config,
86 Function<BlockState, BlockState> function
87 ) {
88 if (this.validTreePos(world, pos)) {
89 BlockState bs = function.apply(config.trunkProvider.getState(random, pos));
90 Direction.Axis axis = currentDir.getAxis();
91 if (bs.hasProperty(BlockStateProperties.AXIS)) bs = bs.setValue(BlockStateProperties.AXIS, axis);
92 if (bs.hasProperty(BlockStateProperties.HORIZONTAL_AXIS) && axis.isHorizontal()) bs = bs.setValue(BlockStateProperties.HORIZONTAL_AXIS, axis);
93 if (bs.hasProperty(BlockStateProperties.FACING)) bs = bs.setValue(BlockStateProperties.FACING, currentDir);
94 if (bs.hasProperty(BlockStateProperties.HORIZONTAL_FACING) && axis.isHorizontal()) bs = bs.setValue(BlockStateProperties.HORIZONTAL_FACING, currentDir);
95 if (bs.hasProperty(BlockStateProperties.FACING_HOPPER) && currentDir != Direction.UP) bs = bs.setValue(BlockStateProperties.FACING_HOPPER, currentDir);
96 replacer.accept(pos, bs);
97 return true;
98 } else {
99 return false;
100 }
101 }
102}