Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
1package net.lerariemann.infinity.block.custom;
2
3import net.lerariemann.infinity.registry.core.ModBlocks;
4import net.lerariemann.infinity.util.platform.InfinityPlatform;
5import net.lerariemann.infinity.util.VersionMethods;
6import net.lerariemann.infinity.util.var.BishopBattle;
7import net.minecraft.MethodsReturnNonnullByDefault;
8import net.minecraft.core.BlockPos;
9import net.minecraft.core.Direction;
10import net.minecraft.core.registries.BuiltInRegistries;
11import net.minecraft.server.level.ServerLevel;
12import net.minecraft.world.InteractionHand;
13import net.minecraft.world.InteractionResult;
14import net.minecraft.world.entity.player.Player;
15import net.minecraft.world.item.context.BlockPlaceContext;
16import net.minecraft.world.level.Level;
17import net.minecraft.world.level.block.Block;
18import net.minecraft.world.level.block.Blocks;
19import net.minecraft.world.level.block.HorizontalDirectionalBlock;
20import net.minecraft.world.level.block.state.BlockState;
21import net.minecraft.world.level.block.state.StateDefinition;
22import net.minecraft.world.phys.BlockHitResult;
23import org.jetbrains.annotations.NotNull;
24import org.jetbrains.annotations.Nullable;
25
26//? if >1.21 {
27import com.mojang.serialization.MapCodec;
28//?}
29//? if neoforge {
30/*import javax.annotation.ParametersAreNonnullByDefault;
31*///?}
32import java.util.Objects;
33import java.util.logging.Handler;
34
35@MethodsReturnNonnullByDefault
36//? if neoforge {
37/*@ParametersAreNonnullByDefault
38 *///?}
39public class AntBlock extends HorizontalDirectionalBlock {
40 //? if >1.21 {
41 public static final MapCodec<AntBlock> CODEC = simpleCodec(AntBlock::new);
42 //?}
43
44 public AntBlock(Properties settings) {
45 super(settings);
46 this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH));
47 }
48
49 //? if >1.21 {
50 @Override
51 protected @NotNull MapCodec<? extends HorizontalDirectionalBlock> codec() {
52 return CODEC;
53 }
54 //?}
55
56 private static boolean inverseExists(Block down) {
57 var s = BuiltInRegistries.BLOCK.getKey(down);
58 var state = down.defaultBlockState();
59 if (InfinityPlatform.INSTANCE.isInBlack(state)) {
60 return BuiltInRegistries.BLOCK.containsKey(VersionMethods.id(s.toString().replace("black", "white")));
61 }
62 if (InfinityPlatform.INSTANCE.isInWhite(state)) {
63 return BuiltInRegistries.BLOCK.containsKey(VersionMethods.id(s.toString().replace("white", "black")));
64 }
65 return false;
66 }
67 public static boolean isSafeToRecolor(Level world, BlockPos pos) {
68 return inverseExists(world.getBlockState(pos).getBlock()) && (world.getBlockEntity(pos) == null);
69 }
70
71 @Nullable
72 public static Block recolor(Block down, boolean toWhite) {
73 String s = VersionMethods.getNameAsString(BuiltInRegistries.BLOCK, down);
74 var state = down.defaultBlockState();
75 if (InfinityPlatform.INSTANCE.isInBlack(state)) {
76 return toWhite ? VersionMethods.getFromRegistry(BuiltInRegistries.BLOCK, VersionMethods.id(s.replace("black", "white"))) : down;
77 }
78 if (InfinityPlatform.INSTANCE.isInWhite(state)) {
79 return toWhite ? down : VersionMethods.getFromRegistry(BuiltInRegistries.BLOCK, VersionMethods.id(s.replace("white", "black")));
80 }
81 return null;
82 }
83
84 @Nullable
85 public static Clockwiseness getCW(Block down) {
86 String s = VersionMethods.getNameAsString(BuiltInRegistries.BLOCK, down);
87 if (s.contains("black")) {
88 return Clockwiseness.CCW;
89 }
90 if (s.contains("white")) {
91 return Clockwiseness.CW;
92 }
93 return null;
94 }
95
96 @Override
97 public void tick(BlockState state, ServerLevel world, BlockPos pos, net.minecraft.util.RandomSource random) {
98 super.tick(state, world, pos, random);
99 if (isSafeToRecolor(world, pos.below())) {
100 this.safeMove(state, world, pos);
101 }
102 }
103
104 @Override
105 public InteractionResult
106 //? if >1.21 {
107 useWithoutItem
108 //?} else {
109 /*use
110 *///?}
111 (BlockState state, Level world, BlockPos pos, Player player,
112 //? if <1.21 {
113 /*InteractionHand hand,
114 *///?}
115 BlockHitResult hit) {
116 return move(state, world, pos);
117 }
118
119 private InteractionResult move(BlockState blockState, Level world, BlockPos pos) {
120 if (isSafeToRecolor(world, pos.below())) return safeMove(blockState, world, pos);
121 return InteractionResult.FAIL;
122 }
123
124 private InteractionResult safeMove(BlockState blockState, Level world, BlockPos pos) {
125 BlockState down = world.getBlockState(pos.below());
126 Clockwiseness clockwiseness = getCW(down.getBlock());
127 if (clockwiseness == null) return InteractionResult.FAIL;
128 Direction direction = blockState.getValue(FACING);
129 Direction direction2 = clockwiseness == Clockwiseness.CW ? direction.getClockWise() : direction.getCounterClockWise();
130 BlockPos blockPos = pos.relative(direction2);
131 if (world.isLoaded(blockPos) && world.getBlockState(blockPos).canBeReplaced()) {
132 switch (clockwiseness) {
133 case CW:
134 world.setBlock(pos.below(), Objects.requireNonNull(recolor(down.getBlock(), false)).withPropertiesOf(down), 19);
135 world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
136 world.setBlock(blockPos, blockState.setValue(FACING, direction2), 3);
137 break;
138 case CCW:
139 world.setBlock(pos.below(), Objects.requireNonNull(recolor(down.getBlock(), true)).withPropertiesOf(down), 19);
140 world.setBlock(pos, Blocks.AIR.defaultBlockState(), 3);
141 world.setBlock(blockPos, blockState.setValue(FACING, direction2), 3);
142 }
143 }
144 return InteractionResult.SUCCESS;
145 }
146
147 @Override
148 public BlockState getStateForPlacement(BlockPlaceContext ctx) {
149 return this.defaultBlockState().setValue(FACING, ctx.getHorizontalDirection().getOpposite());
150 }
151 @Override
152 public void onPlace(BlockState state, Level world, BlockPos pos, BlockState oldState, boolean notify) {
153 //bishop miniboss battle
154 if (world instanceof ServerLevel level && world.getBlockState(pos.below()).is(ModBlocks.ALTAR.get())) {
155 world.removeBlock(pos, false);
156 world.removeBlock(pos.below(), false);
157 (new BishopBattle(level)).start(pos.below());
158 }
159 else world.scheduleTick(pos, this, 1);
160 }
161
162 protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
163 builder.add(FACING);
164 }
165
166 public enum Clockwiseness {
167 CW,
168 CCW
169 }
170}