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.access.Timebombable;
4import net.lerariemann.infinity.util.InfinityMethods;
5import net.lerariemann.infinity.registry.var.ModCriteria;
6import net.lerariemann.infinity.registry.core.ModItems;
7import net.lerariemann.infinity.registry.var.ModSounds;
8import net.lerariemann.infinity.registry.var.ModStats;
9import net.lerariemann.infinity.util.teleport.PortalCreator;
10import net.minecraft.MethodsReturnNonnullByDefault;
11import net.minecraft.core.BlockPos;
12import net.minecraft.core.particles.ParticleTypes;
13//? if >1.21.9 {
14/*import net.minecraft.core.particles.PowerParticleOption;
15*///?}
16import net.minecraft.network.chat.Component;
17import net.minecraft.server.level.ServerLevel;
18import net.minecraft.server.level.ServerPlayer;
19import net.minecraft.sounds.SoundEvents;
20import net.minecraft.sounds.SoundSource;
21import net.minecraft.world.InteractionHand;
22import net.minecraft.world.InteractionResult;
23import net.minecraft.world.entity.AreaEffectCloud;
24import net.minecraft.world.entity.Entity;
25import net.minecraft.world.entity.player.Player;
26import net.minecraft.world.level.BlockGetter;
27import net.minecraft.world.level.Level;
28import net.minecraft.world.level.block.Block;
29import net.minecraft.world.level.block.Blocks;
30import net.minecraft.world.level.block.LevelEvent;
31import net.minecraft.world.level.block.RenderShape;
32import net.minecraft.world.level.block.state.BlockState;
33import net.minecraft.world.level.block.state.StateDefinition;
34import net.minecraft.world.level.block.state.properties.BooleanProperty;
35import net.minecraft.world.level.entity.EntityTypeTest;
36import net.minecraft.world.level.storage.LevelResource;
37import net.minecraft.world.phys.AABB;
38import net.minecraft.world.phys.BlockHitResult;
39import net.minecraft.world.phys.shapes.CollisionContext;
40import net.minecraft.world.phys.shapes.Shapes;
41import net.minecraft.world.phys.shapes.VoxelShape;
42import org.apache.commons.io.FileUtils;
43
44import java.io.IOException;
45import java.nio.file.Path;
46
47@MethodsReturnNonnullByDefault
48public class TimeBombBlock extends Block {
49 public static final BooleanProperty ACTIVE = BooleanProperty.create("active");
50 public static final VoxelShape TOP_SHAPE = Block.box(3, 0, 3, 13, 2, 13);
51 public static final VoxelShape BOTTOM_SHAPE = Block.box(3, 12, 3, 13, 14, 13);
52 public static final VoxelShape INNER_SHAPE = Block.box(4, 2, 4, 12, 12, 12);
53 public static final VoxelShape TIP_SHAPE = Block.box(7, 14, 7, 9, 16, 9);
54 public static final VoxelShape SHAPE = Shapes.or(BOTTOM_SHAPE, TOP_SHAPE, INNER_SHAPE, TIP_SHAPE);
55 @Override
56 public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
57 return SHAPE;
58 }
59 @Override
60 public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) {
61 return SHAPE;
62 }
63 @Override
64 public RenderShape getRenderShape(BlockState state) {
65 return RenderShape.MODEL;
66 }
67
68 public TimeBombBlock(Properties settings) {
69 super(settings);
70 this.registerDefaultState(defaultBlockState().setValue(ACTIVE, false));
71 }
72
73 @Override
74 protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
75 builder.add(ACTIVE);
76 }
77
78 void eraseWorld(ServerLevel world) {
79 ((Timebombable)world).infinity$timebomb();
80 Path path = world.getServer().getWorldPath(LevelResource.DATAPACK_DIR).resolve(world.dimension().location().getPath());
81 try {
82 FileUtils.deleteDirectory(path.toFile());
83 } catch (IOException ignored) {
84 }
85 }
86
87 static AreaEffectCloud genCloud(Level world, BlockPos pos) {
88 AreaEffectCloud e = new AreaEffectCloud(world, pos.getCenter().x(), pos.getCenter().y(), pos.getCenter().z());
89 //? if >1.21.9 {
90 /*e.setCustomParticle(PowerParticleOption.create(ParticleTypes.DRAGON_BREATH, 1));
91 *///?} else if >1.21.5 {
92 e.setCustomParticle(ParticleTypes.DRAGON_BREATH);
93 //?} else {
94 /*e.setParticle(ParticleTypes.DRAGON_BREATH);
95 *///?}
96 e.setRadius(1.0f);
97 e.setDuration(3500);
98 e.setRadiusPerTick(0.006f);
99 world.levelEvent(LevelEvent.PARTICLES_DRAGON_FIREBALL_SPLASH, pos, 1);
100 return e;
101 }
102
103 @Override
104 //? if <1.21 {
105 /*public InteractionResult use(BlockState state, Level world, BlockPos pos, Player player, InteractionHand hand, BlockHitResult hit) {
106 *///?} else {
107 protected InteractionResult useWithoutItem(BlockState state, Level world, BlockPos pos, Player player, BlockHitResult hit) {
108 //?}
109 if (state.getValue(ACTIVE)) {
110 if (world instanceof ServerLevel w && !InfinityMethods.isTimebombed(w)) {
111 world.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
112 world.getEntities(EntityTypeTest.forClass(AreaEffectCloud.class), AABB.ofSize(pos.getCenter(), 1.0, 1.0, 1.0), Entity::isAlive).
113 forEach(e -> e.remove(Entity.RemovalReason.DISCARDED));
114 return InteractionResult.SUCCESS;
115 } //remove after regenerating a dimension
116 return InteractionResult.FAIL;
117 }
118 else if (player.getItemInHand(InteractionHand.MAIN_HAND).isEmpty()) {
119 if (player.isShiftKeyDown()) {
120 if (InfinityMethods.isInfinity(world)) {
121 if (world instanceof ServerLevel w && !InfinityMethods.isTimebombed(w)) {
122 eraseWorld(w);
123 world.addFreshEntity(genCloud(world, pos));
124 player.awardStat(ModStats.WORLDS_DESTROYED_STAT, 1);
125 ModCriteria.DIMS_CLOSED.get().trigger((ServerPlayer)player);
126 world.setBlockAndUpdate(pos, state.setValue(ACTIVE, true));
127 world.playSound(null, pos, ModSounds.IVORY_MUSIC_CHALLENGER_EVENT, SoundSource.RECORDS, 1f, 1f);
128 } //activate
129 return InteractionResult.SUCCESS;
130 }
131 else if (world instanceof ServerLevel) {
132 world.playSound(null, pos, ModSounds.portalFail, SoundSource.BLOCKS, 1f, 1f);
133 player.displayClientMessage(Component.translatable("error.infinity.timebomb.fail"), false);
134 }
135 }
136 else {
137 world.setBlockAndUpdate(pos, Blocks.AIR.defaultBlockState());
138 if (!player.isCreative()) player.getInventory().add(ModItems.TIME_BOMB_ITEM.get().getDefaultInstance());
139 return InteractionResult.SUCCESS;
140 } //pick up
141 }
142 return InteractionResult.PASS;
143 }
144}