package org.betterx.bclib.util; import org.betterx.bclib.api.v2.levelgen.biomes.BiomeAPI; import org.betterx.worlds.together.tag.v3.CommonBlockTags; import net.minecraft.core.BlockPos; import net.minecraft.core.BlockPos.MutableBlockPos; import net.minecraft.core.Direction; import net.minecraft.tags.BlockTags; import net.minecraft.util.RandomSource; import net.minecraft.world.level.WorldGenLevel; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.levelgen.structure.BoundingBox; import net.minecraft.world.level.material.Material; import com.google.common.collect.Sets; import java.util.Set; public class StructureErode { private static final Direction[] DIR = BlocksHelper.makeHorizontal(); public static void erode(WorldGenLevel world, BoundingBox bounds, int iterations, RandomSource random) { MutableBlockPos mut = new MutableBlockPos(); boolean canDestruct = true; for (int i = 0; i < iterations; i++) { for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); for (int y = bounds.maxY(); y >= bounds.minY(); y--) { mut.setY(y); BlockState state = world.getBlockState(mut); boolean ignore = ignore(state, world, mut); if (canDestruct && BlocksHelper.isInvulnerable( state, world, mut ) && random.nextInt(8) == 0 && world.isEmptyBlock( mut.below(2))) { int r = MHelper.randRange(1, 4, random); int cx = mut.getX(); int cy = mut.getY(); int cz = mut.getZ(); int x1 = cx - r; int y1 = cy - r; int z1 = cz - r; int x2 = cx + r; int y2 = cy + r; int z2 = cz + r; for (int px = x1; px <= x2; px++) { int dx = px - cx; dx *= dx; mut.setX(px); for (int py = y1; py <= y2; py++) { int dy = py - cy; dy *= dy; mut.setY(py); for (int pz = z1; pz <= z2; pz++) { int dz = pz - cz; dz *= dz; mut.setZ(pz); if (dx + dy + dz <= r && BlocksHelper.isInvulnerable( world.getBlockState(mut), world, mut )) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); } } } } mut.setX(cx); mut.setY(cy); mut.setZ(cz); canDestruct = false; continue; } else if (ignore) { continue; } if (!state.isAir() && random.nextBoolean()) { MHelper.shuffle(DIR, random); for (Direction dir : DIR) { if (world.isEmptyBlock(mut.relative(dir)) && world.isEmptyBlock(mut.below() .relative(dir))) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); mut.move(dir).move(Direction.DOWN); for (int py = mut.getY(); y >= bounds.minY() - 10; y--) { mut.setY(py - 1); if (!world.isEmptyBlock(mut)) { mut.setY(py); BlocksHelper.setWithoutUpdate(world, mut, state); break; } } } } break; } else if (random.nextInt(8) == 0 && !BlocksHelper.isInvulnerable( world.getBlockState(mut.above()), world, mut )) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); } } } } } for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); for (int y = bounds.maxY(); y >= bounds.minY(); y--) { mut.setY(y); BlockState state = world.getBlockState(mut); if (!ignore(state, world, mut) && world.isEmptyBlock(mut.below())) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); for (int py = mut.getY(); py >= bounds.minY() - 10; py--) { mut.setY(py - 1); if (!world.isEmptyBlock(mut)) { mut.setY(py); BlocksHelper.setWithoutUpdate(world, mut, state); break; } } } } } } } public static void erodeIntense(WorldGenLevel world, BoundingBox bounds, RandomSource random) { MutableBlockPos mut = new MutableBlockPos(); MutableBlockPos mut2 = new MutableBlockPos(); int minY = bounds.minY() - 10; for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); for (int y = bounds.maxY(); y >= bounds.minY(); y--) { mut.setY(y); BlockState state = world.getBlockState(mut); if (!ignore(state, world, mut)) { if (random.nextInt(6) == 0) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); if (random.nextBoolean()) { int px = MHelper.floor(random.nextGaussian() * 2 + x + 0.5); int pz = MHelper.floor(random.nextGaussian() * 2 + z + 0.5); mut2.set(px, y, pz); while (world.getBlockState(mut2).getMaterial().isReplaceable() && mut2.getY() > minY) { mut2.setY(mut2.getY() - 1); } if (!world.getBlockState(mut2).isAir() && state.canSurvive(world, mut2)) { mut2.setY(mut2.getY() + 1); BlocksHelper.setWithoutUpdate(world, mut2, state); } } } else if (random.nextInt(8) == 0) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); } } } } } drop(world, bounds); } private static void drop(WorldGenLevel world, BoundingBox bounds) { MutableBlockPos mut = new MutableBlockPos(); Set blocks = Sets.newHashSet(); Set edge = Sets.newHashSet(); Set add = Sets.newHashSet(); for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); for (int y = bounds.minY(); y <= bounds.maxY(); y++) { mut.setY(y); BlockState state = world.getBlockState(mut); if (!ignore(state, world, mut) && isTerrainNear(world, mut)) { edge.add(mut.immutable()); } } } } if (edge.isEmpty()) { return; } while (!edge.isEmpty()) { for (BlockPos center : edge) { for (Direction dir : BlocksHelper.DIRECTIONS) { BlockState state = world.getBlockState(center); if (state.isCollisionShapeFullBlock(world, center)) { mut.set(center).move(dir); if (bounds.isInside(mut)) { state = world.getBlockState(mut); if (!ignore(state, world, mut) && !blocks.contains(mut)) { add.add(mut.immutable()); } } } } } blocks.addAll(edge); edge.clear(); edge.addAll(add); add.clear(); } int minY = bounds.minY() - 10; for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); for (int y = bounds.minY(); y <= bounds.maxY(); y++) { mut.setY(y); BlockState state = world.getBlockState(mut); if (!ignore(state, world, mut) && !blocks.contains(mut)) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); while (world.getBlockState(mut).getMaterial().isReplaceable() && mut.getY() > minY) { mut.setY(mut.getY() - 1); } if (mut.getY() > minY) { mut.setY(mut.getY() + 1); BlocksHelper.setWithoutUpdate(world, mut, state); } } } } } } private static boolean ignore(BlockState state, WorldGenLevel world, BlockPos pos) { if (state.is(CommonBlockTags.GEN_END_STONES) || state.is(BlockTags.NYLIUM)) { return true; } return !state.getMaterial().equals(Material.STONE) || BlocksHelper.isInvulnerable(state, world, pos); } private static boolean isTerrainNear(WorldGenLevel world, BlockPos pos) { for (Direction dir : BlocksHelper.DIRECTIONS) { if (world.getBlockState(pos.relative(dir)).is(CommonBlockTags.GEN_END_STONES)) { return true; } } return false; } public static void cover(WorldGenLevel world, BoundingBox bounds, RandomSource random, BlockState defaultBlock) { MutableBlockPos mut = new MutableBlockPos(); for (int x = bounds.minX(); x <= bounds.maxX(); x++) { mut.setX(x); for (int z = bounds.minZ(); z <= bounds.maxZ(); z++) { mut.setZ(z); BlockState top = BiomeAPI.findTopMaterial(world.getBiome(mut)).orElse(defaultBlock); if (top == null) continue; for (int y = bounds.maxY(); y >= bounds.minY(); y--) { mut.setY(y); BlockState state = world.getBlockState(mut); if (state.is(CommonBlockTags.TERRAIN) && !world.getBlockState(mut.above()) .getMaterial() .isSolidBlocking()) { BlocksHelper.setWithoutUpdate(world, mut, top); } } } } } }