Inspired by 2020's April Fools' 20w14infinite Snapshot, this mod brings endless randomly generated dimensions into Minecraft.
at master 261 lines 11 kB view raw
1package net.lerariemann.infinity.block.custom; 2 3import net.lerariemann.infinity.block.entity.BiomeBottleBlockEntity; 4import net.lerariemann.infinity.registry.core.ModBlockEntities; 5import net.lerariemann.infinity.util.VersionMethods; 6import net.minecraft.MethodsReturnNonnullByDefault; 7import net.minecraft.core.BlockPos; 8import net.minecraft.core.Holder; 9import net.minecraft.core.QuartPos; 10//? if >1.21 { 11import com.mojang.serialization.MapCodec; 12import net.lerariemann.infinity.registry.core.ModComponentTypes; 13import net.minecraft.core.component.DataComponentMap; 14import net.minecraft.core.component.DataComponents; 15import net.minecraft.world.item.component.BlockItemStateProperties; 16import net.minecraft.world.level.LevelReader; 17//?} 18import net.minecraft.core.Registry; 19import net.minecraft.core.particles.ParticleTypes; 20import net.minecraft.core.registries.Registries; 21import net.minecraft.resources.ResourceLocation; 22import net.minecraft.server.level.ServerLevel; 23import net.minecraft.sounds.SoundEvents; 24import net.minecraft.sounds.SoundSource; 25import net.minecraft.util.Mth; 26import net.minecraft.world.item.ItemStack; 27import net.minecraft.world.item.Rarity; 28import net.minecraft.world.level.BlockGetter; 29import net.minecraft.world.level.ChunkPos; 30import net.minecraft.world.level.Level; 31import net.minecraft.world.level.biome.Biome; 32import net.minecraft.world.level.block.BaseEntityBlock; 33import net.minecraft.world.level.block.Block; 34import net.minecraft.world.level.block.RenderShape; 35import net.minecraft.world.level.block.entity.BlockEntity; 36import net.minecraft.world.level.block.entity.BlockEntityTicker; 37import net.minecraft.world.level.block.entity.BlockEntityType; 38import net.minecraft.world.level.block.state.BlockState; 39import net.minecraft.world.level.block.state.StateDefinition; 40import net.minecraft.world.level.block.state.properties.IntegerProperty; 41import net.minecraft.world.level.chunk.ChunkAccess; 42import net.minecraft.world.phys.shapes.CollisionContext; 43import net.minecraft.world.phys.shapes.Shapes; 44import net.minecraft.world.phys.shapes.VoxelShape; 45import org.jetbrains.annotations.Nullable; 46//? if neoforge { 47/*import javax.annotation.ParametersAreNonnullByDefault; 48*///?} 49 50import java.util.*; 51import java.util.stream.Collectors; 52 53@MethodsReturnNonnullByDefault 54//? if neoforge { 55/*@ParametersAreNonnullByDefault 56*///?} 57public class BiomeBottleBlock extends BaseEntityBlock { 58 //? if >1.21 { 59 public static final MapCodec<BiomeBottleBlock> CODEC = simpleCodec(BiomeBottleBlock::new); 60 //?} 61 public static final IntegerProperty LEVEL = IntegerProperty.create("level", 0, 10); 62 public static final VoxelShape MAIN = Block.box(2, 0, 2, 14, 12, 14); 63 public static final VoxelShape TIP = Block.box(6, 12, 6, 10, 16, 10); 64 public static final VoxelShape CORK = Block.box(5, 14, 5, 11, 15, 11); 65 public static final VoxelShape SHAPE = Shapes.or(MAIN, TIP, CORK); 66 @Override 67 public VoxelShape getCollisionShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { 68 return SHAPE; 69 } 70 @Override 71 public VoxelShape getShape(BlockState state, BlockGetter world, BlockPos pos, CollisionContext context) { 72 return SHAPE; 73 } 74 75 public BiomeBottleBlock(Properties settings) { 76 super(settings); 77 this.registerDefaultState(defaultBlockState().setValue(LEVEL, 0)); 78 } 79 80 @Override 81 protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) { 82 builder.add(LEVEL); 83 } 84 85 //? if >1.21 { 86 @Override 87 protected MapCodec<? extends BaseEntityBlock> codec() { 88 return CODEC; 89 } 90 //?} 91 @Override 92 public RenderShape getRenderShape(BlockState state) { 93 return RenderShape.MODEL; 94 } 95 @Nullable 96 @Override 97 public BlockEntity newBlockEntity(BlockPos pos, BlockState state) { 98 return new BiomeBottleBlockEntity(pos, state); 99 } 100 @Nullable 101 @Override 102 public <T extends BlockEntity> BlockEntityTicker<T> getTicker(Level world, BlockState state, BlockEntityType<T> type) { 103 return world.isClientSide() ? null : createTickerHelper(type, ModBlockEntities.BIOME_BOTTLE.get(), BiomeBottleBlockEntity::serverTick); 104 } 105 106 107 @Override 108 public ItemStack getCloneItemStack( 109 //? if >1.21 { 110 LevelReader world 111 //?} else { 112 /*BlockGetter world 113 *///?} 114 , BlockPos pos, BlockState state 115 //? if >1.21.2 116 , boolean bl 117 ) { 118 return world.getBlockEntity(pos) instanceof BiomeBottleBlockEntity bbbe 119 ? bbbe.asStack() 120 : super.getCloneItemStack(world, pos, state 121 //? if >1.21.2 122 , bl 123 ); 124 } 125 126 public static final int maxAllowedCharge = 10000; 127 128 public static ResourceLocation defaultBiome() { 129 return VersionMethods.id("plains"); 130 } 131 132 public static Rarity getRarity(int charge) { 133 return charge < 1000 ? Rarity.COMMON : charge < 9000 ? Rarity.UNCOMMON : Rarity.RARE; 134 } 135 136 //? if >1.21 { 137 public static DataComponentMap.Builder updateCharge(DataComponentMap.Builder builder, int charge) { 138 return builder.set(ModComponentTypes.CHARGE.get(), charge) 139 .set(DataComponents.RARITY, getRarity(charge)) 140 .set(DataComponents.BLOCK_STATE, (new BlockItemStateProperties(Map.of())) 141 .with(LEVEL, getLevel(charge))); 142 } 143 public static void updateCharge(ItemStack stack, int charge) { 144 stack.applyComponents(updateCharge(DataComponentMap.builder(), charge).build()); 145 } 146 public static void updateCharge(ItemStack stack) { 147 int charge = getCharge(stack); 148 if (charge == 0) stack.remove(ModComponentTypes.BIOME_CONTENTS.get()); 149 updateCharge(stack, charge); 150 } 151 //?} else { 152 /*public static void updateCharge(ItemStack stack, int charge) { 153 if (stack.hasTag()) { 154 assert stack.getTag() != null; 155 stack.getTag().getCompound("BlockEntityTag").putInt("Charge", charge); 156 } 157 } 158 public static void updateCharge(ItemStack stack) { 159 int charge = getCharge(stack); 160 if (charge > 0) updateCharge(stack, charge); 161 } 162 *///?} 163 164 public static int getLevel(int charge) { 165 return Mth.clamp(charge / 100, 0, 10); 166 } 167 168 public static boolean isEmpty(ItemStack stack) { 169 return getCharge(stack) == 0; 170 } 171 172 public static ResourceLocation getBiome(ItemStack stack) { 173 //? if >1.21 { 174 return stack.getComponents().getOrDefault(ModComponentTypes.BIOME_CONTENTS.get(), defaultBiome()); 175 //?} else { 176 /*if (stack.hasTag()) { 177 assert stack.getTag() != null; 178 return VersionMethods.id(stack.getTag().getCompound("BlockEntityTag").getString("Biome")); 179 } 180 return defaultBiome(); 181 *///?} 182 } 183 184 public static int getCharge(ItemStack stack) { 185 //? if >1.21 { 186 return stack.getComponents().getOrDefault(ModComponentTypes.CHARGE.get(), 0); 187 //?} else { 188 /*if (stack.hasTag()) { 189 assert stack.getTag() != null; 190 return stack.getTag().getCompound("BlockEntityTag").getInt("Charge"); 191 } 192 return 0; 193 *///?} 194 195 } 196 197 public static void playSploosh(ServerLevel world, BlockPos pos) { 198 world.playSound(null, pos, SoundEvents.GENERIC_SPLASH, SoundSource.BLOCKS, 1f, 1f); 199 world.sendParticles(ParticleTypes.SPLASH, pos.getX() + 0.5, 200 pos.getY() + 0.5, pos.getZ() + 0.5, 30, 0.5, 0.5, 0.5, 0.2); 201 } 202 203 //? if >1.21 { 204 public static DataComponentMap.Builder addComponents(DataComponentMap.Builder componentMapBuilder, 205 ResourceLocation biome, int color, int charge) { 206 componentMapBuilder.set(ModComponentTypes.BIOME_CONTENTS.get(), biome); 207 componentMapBuilder.set(ModComponentTypes.COLOR.get(), color); 208 updateCharge(componentMapBuilder, charge); 209 return componentMapBuilder; 210 } 211 //?} 212 213 public static void spreadCircle(ServerLevel world, BlockPos origin, ResourceLocation biomeId, int charge) { 214 spreadRing(world, origin, biomeId, 0, charge); 215 } 216 public static void spreadRing(ServerLevel world, BlockPos origin, ResourceLocation biomeId, int chargemin, int chargemax) { 217 Set<BlockPos> posSet = new HashSet<>(); 218 Set<ChunkAccess> set = new HashSet<>(); 219 origin = origin.below(origin.getY()); 220 double ramax = chargemax / Math.PI; 221 double ramin = chargemin / Math.PI; 222 for (int i = 0; i*i < ramax; i++) { 223 for (int j = 0; i*i + j*j < ramax; j++) if (i*i + j*j >= ramin) { 224 List<BlockPos> signs = offsets(origin, i, j); 225 posSet.addAll(signs); 226 set.addAll(signs.stream().map(ChunkPos::new) 227 .map(chunkPos -> world.getChunk(chunkPos.getWorldPosition())) 228 .filter(Objects::nonNull).collect(Collectors.toSet())); 229 } 230 } 231 spread(world, set, posSet, VersionMethods.getFromId(VersionMethods.getRegistry(world.getServer().registryAccess(), Registries.BIOME), biomeId)); 232 } 233 234 public static void spread(ServerLevel world, Set<ChunkAccess> set, Set<BlockPos> posSet, @Nullable Holder<Biome> biome) { 235 if (biome == null) return; 236 set.forEach(chunk -> { 237 if (chunk != null) { 238 chunk.fillBiomesFromNoise((x, y, z, noise) -> { 239 int i = QuartPos.toBlock(x); 240 int k = QuartPos.toBlock(z); 241 Holder<Biome> registryEntry2 = chunk.getNoiseBiome(x, y, z); 242 if (posSet.contains(new BlockPos(i, 0, k))) { 243 return biome; 244 } 245 return registryEntry2; 246 }, world.getChunkSource().randomState().sampler()); 247 //? if >1.21.2 { 248 chunk.markUnsaved(); 249 //?} else { 250 /*chunk.setUnsaved(true); 251 *///?} 252 } 253 }); 254 world.getChunkSource().chunkMap.resendBiomesForChunks(set.stream().toList()); 255 } 256 257 public static List<BlockPos> offsets(BlockPos origin, int i, int j) { 258 return List.of(origin.offset(i, 0, j), origin.offset(j, 0, i), origin.offset(-i, 0, j), origin.offset(j, 0, -i), 259 origin.offset(i, 0, -j), origin.offset(-j, 0, i), origin.offset(-i, 0, -j), origin.offset(-j, 0, -i)); 260 } 261}