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