From f9c49ba4aa3789d683cadef9471efc47b85cb7f0 Mon Sep 17 00:00:00 2001 From: paulevsGitch Date: Sun, 29 Nov 2020 16:31:27 +0300 Subject: [PATCH] Crashed ships, better erosion --- .../ru/betterend/registry/EndFeatures.java | 5 + .../java/ru/betterend/util/BlocksHelper.java | 1 + .../ru/betterend/util/StructureHelper.java | 122 +++++++++++++++++- .../world/features/CrashedShipFeature.java | 88 +++++++++++++ .../betterend/world/features/ListFeature.java | 4 + .../world/features/NBTStructureFeature.java | 5 +- 6 files changed, 223 insertions(+), 2 deletions(-) create mode 100644 src/main/java/ru/betterend/world/features/CrashedShipFeature.java diff --git a/src/main/java/ru/betterend/registry/EndFeatures.java b/src/main/java/ru/betterend/registry/EndFeatures.java index fdb26aee..b91818c2 100644 --- a/src/main/java/ru/betterend/registry/EndFeatures.java +++ b/src/main/java/ru/betterend/registry/EndFeatures.java @@ -12,6 +12,7 @@ import net.minecraft.world.gen.feature.ConfiguredFeature; import ru.betterend.world.biome.EndBiome; import ru.betterend.world.features.BlueVineFeature; import ru.betterend.world.features.CavePlantFeature; +import ru.betterend.world.features.CrashedShipFeature; import ru.betterend.world.features.DoublePlantFeature; import ru.betterend.world.features.EndFeature; import ru.betterend.world.features.EndLilyFeature; @@ -98,6 +99,9 @@ public class EndFeatures { public static final EndFeature VIOLECITE_LAYER = EndFeature.makeLayerFeature("violecite_layer", EndBlocks.VIOLECITE, 15, 4, 96, 8); public static final EndFeature FLAVOLITE_LAYER = EndFeature.makeLayerFeature("flavolite_layer", EndBlocks.FLAVOLITE, 12, 4, 96, 6); + // Buildings + public static final EndFeature CRASHED_SHIP = EndFeature.makeChansedFeature("crashed_ship", new CrashedShipFeature(), 500); + public static void registerBiomeFeatures(Identifier id, Biome biome, List>>> features) { if (id.getNamespace().equals("minecraft")) { String path = id.getPath(); @@ -115,6 +119,7 @@ public class EndFeatures { addFeature(FLAVOLITE_LAYER, features); addFeature(ENDER_ORE, features); + addFeature(CRASHED_SHIP, features); if (!id.getPath().equals("blossoming_spires")) { addFeature(ROUND_CAVE_RARE, features); diff --git a/src/main/java/ru/betterend/util/BlocksHelper.java b/src/main/java/ru/betterend/util/BlocksHelper.java index d2ee0f20..b972a09a 100644 --- a/src/main/java/ru/betterend/util/BlocksHelper.java +++ b/src/main/java/ru/betterend/util/BlocksHelper.java @@ -39,6 +39,7 @@ public class BlocksHelper { public static final int SET_SILENT = FLAG_UPDATE_BLOCK | FLAG_IGNORE_OBSERVERS | FLAG_SEND_CLIENT_CHANGES; public static final Direction[] HORIZONTAL = makeHorizontal(); + public static final Direction[] DIRECTIONS = Direction.values(); private static final Mutable POS = new Mutable(); protected static final BlockState AIR = Blocks.AIR.getDefaultState(); diff --git a/src/main/java/ru/betterend/util/StructureHelper.java b/src/main/java/ru/betterend/util/StructureHelper.java index a9bf2b40..96446815 100644 --- a/src/main/java/ru/betterend/util/StructureHelper.java +++ b/src/main/java/ru/betterend/util/StructureHelper.java @@ -3,6 +3,9 @@ package ru.betterend.util; import java.io.IOException; import java.io.InputStream; import java.util.Random; +import java.util.Set; + +import com.google.common.collect.Sets; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; @@ -165,7 +168,7 @@ public class StructureHelper { BlockState state = world.getBlockState(mut); if (!ignore(state) && world.isAir(mut.down())) { BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); - for (int py = mut.getY(); y >= bounds.minY - 10; y--) { + for (int py = mut.getY(); py >= bounds.minY - 10; py--) { mut.setY(py - 1); if (!world.isAir(mut)) { mut.setY(py); @@ -178,7 +181,124 @@ public class StructureHelper { } } } + + public static void erodeIntense(StructureWorldAccess world, BlockBox bounds, Random random) { + Mutable mut = new Mutable(); + Mutable mut2 = new Mutable(); + 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)) { + 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 (y > 50 && state.canPlaceAt(world, mut2)) { + mut2.setY(mut2.getY() + 1); + BlocksHelper.setWithoutUpdate(world, mut2, state); + } + } + } + else if (random.nextInt(8) == 0 && !world.getBlockState(mut.up()).isOf(EndBlocks.ETERNAL_PEDESTAL)) { + BlocksHelper.setWithoutUpdate(world, mut, Blocks.AIR); + } + } + } + } + } + + drop(world, bounds); + } + private static boolean isTerrainNear(StructureWorldAccess world, BlockPos pos) { + for (Direction dir: BlocksHelper.DIRECTIONS) { + if (world.getBlockState(pos.offset(dir)).isIn(EndTags.GEN_TERRAIN)) { + return true; + } + } + return false; + } + + private static void drop(StructureWorldAccess world, BlockBox bounds) { + Mutable mut = new Mutable(); + + 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) && isTerrainNear(world, mut)) { + edge.add(mut.toImmutable()); + } + } + } + } + + if (edge.isEmpty()) { + return; + } + + while (!edge.isEmpty()) { + for (BlockPos center: edge) { + for (Direction dir: BlocksHelper.DIRECTIONS) { + BlockState state = world.getBlockState(center); + if (state.isFullCube(world, center)) { + mut.set(center).move(dir); + if (bounds.contains(mut)) { + state = world.getBlockState(mut); + if (!ignore(state) && !blocks.contains(mut)) { + add.add(mut.toImmutable()); + } + } + } + } + } + + 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) && !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) { return state.getMaterial().isReplaceable() || !state.getFluidState().isEmpty() diff --git a/src/main/java/ru/betterend/world/features/CrashedShipFeature.java b/src/main/java/ru/betterend/world/features/CrashedShipFeature.java new file mode 100644 index 00000000..3475e9d8 --- /dev/null +++ b/src/main/java/ru/betterend/world/features/CrashedShipFeature.java @@ -0,0 +1,88 @@ +package ru.betterend.world.features; + +import java.util.Random; + +import net.minecraft.structure.Structure; +import net.minecraft.structure.StructurePlacementData; +import net.minecraft.structure.processor.BlockIgnoreStructureProcessor; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.math.BlockBox; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.StructureWorldAccess; +import net.minecraft.world.gen.chunk.ChunkGenerator; +import net.minecraft.world.gen.feature.DefaultFeatureConfig; +import ru.betterend.registry.EndTags; +import ru.betterend.util.BlocksHelper; +import ru.betterend.util.MHelper; +import ru.betterend.util.StructureHelper; + +public class CrashedShipFeature extends NBTStructureFeature { + private static final String STRUCTURE_PATH = "/data/minecraft/structures/end_city/ship.nbt"; + + @Override + protected Structure getStructure(StructureWorldAccess world, BlockPos pos, Random random) { + return StructureHelper.readStructure(STRUCTURE_PATH); + } + + @Override + protected boolean canSpawn(StructureWorldAccess world, BlockPos pos, Random random) { + int cx = pos.getX() >> 4; + int cz = pos.getZ() >> 4; + return ((cx + cz) & 1) == 0 && pos.getY() > 58 && world.getBlockState(pos.down()).isIn(EndTags.GEN_TERRAIN); + } + + @Override + protected BlockRotation getRotation(StructureWorldAccess world, BlockPos pos, Random random) { + return BlockRotation.random(random); + } + + @Override + protected BlockMirror getMirror(StructureWorldAccess world, BlockPos pos, Random random) { + return BlockMirror.values()[random.nextInt(3)]; + } + + @Override + protected int getYOffset(Structure structure, StructureWorldAccess world, BlockPos pos, Random random) { + int min = structure.getSize().getY() >> 3; + int max = structure.getSize().getY() >> 2; + return -MHelper.randRange(min, max, random); + } + + @Override + protected TerrainMerge getTerrainMerge(StructureWorldAccess world, BlockPos pos, Random random) { + return TerrainMerge.NONE; + } + + @Override + public boolean generate(StructureWorldAccess world, ChunkGenerator chunkGenerator, Random random, BlockPos center, DefaultFeatureConfig featureConfig) { + center = new BlockPos(((center.getX() >> 4) << 4) | 8, 128, ((center.getZ() >> 4) << 4) | 8); + center = getGround(world, center); + + if (!canSpawn(world, center, random)) { + return false; + } + + Structure structure = getStructure(world, center, random); + BlockRotation rotation = getRotation(world, center, random); + BlockMirror mirror = getMirror(world, center, random); + BlockPos offset = Structure.transformAround(structure.getSize(), mirror, rotation, BlockPos.ORIGIN); + center = center.add(0, getYOffset(structure, world, center, random) + 0.5, 0); + + BlockBox bounds = makeBox(center); + StructurePlacementData placementData = new StructurePlacementData().setRotation(rotation).setMirror(mirror).setBoundingBox(bounds); + addStructureData(placementData); + center = center.add(-offset.getX() * 0.5, 0, -offset.getZ() * 0.5); + structure.place(world, center, placementData, random); + + StructureHelper.erodeIntense(world, bounds, random); + BlocksHelper.fixBlocks(world, new BlockPos(bounds.minX, bounds.minY, bounds.minZ), new BlockPos(bounds.maxX, bounds.maxY, bounds.maxZ)); + + return true; + } + + @Override + protected void addStructureData(StructurePlacementData data) { + data.addProcessor(BlockIgnoreStructureProcessor.IGNORE_AIR_AND_STRUCTURE_BLOCKS).setIgnoreEntities(true); + } +} diff --git a/src/main/java/ru/betterend/world/features/ListFeature.java b/src/main/java/ru/betterend/world/features/ListFeature.java index 012e84e2..a2fd9143 100644 --- a/src/main/java/ru/betterend/world/features/ListFeature.java +++ b/src/main/java/ru/betterend/world/features/ListFeature.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Random; import net.minecraft.structure.Structure; +import net.minecraft.structure.StructurePlacementData; import net.minecraft.util.BlockMirror; import net.minecraft.util.BlockRotation; import net.minecraft.util.math.BlockPos; @@ -51,6 +52,9 @@ public class ListFeature extends NBTStructureFeature { return selected.terrainMerge; } + @Override + protected void addStructureData(StructurePlacementData data) {} + public static final class StructureInfo { public final TerrainMerge terrainMerge; public final Structure structure; diff --git a/src/main/java/ru/betterend/world/features/NBTStructureFeature.java b/src/main/java/ru/betterend/world/features/NBTStructureFeature.java index 3a0aedab..2bb0dac0 100644 --- a/src/main/java/ru/betterend/world/features/NBTStructureFeature.java +++ b/src/main/java/ru/betterend/world/features/NBTStructureFeature.java @@ -42,6 +42,8 @@ public abstract class NBTStructureFeature extends DefaultFeature { protected abstract TerrainMerge getTerrainMerge(StructureWorldAccess world, BlockPos pos, Random random); + protected abstract void addStructureData(StructurePlacementData data); + protected BlockPos getGround(StructureWorldAccess world, BlockPos center) { Biome biome = world.getBiome(center); Identifier id = EndBiomes.getBiomeID(biome); @@ -91,6 +93,7 @@ public abstract class NBTStructureFeature extends DefaultFeature { BlockBox bounds = makeBox(center); StructurePlacementData placementData = new StructurePlacementData().setRotation(rotation).setMirror(mirror).setBoundingBox(bounds); + addStructureData(placementData); center = center.add(-offset.getX() * 0.5, 0, -offset.getZ() * 0.5); structure.place(world, center, placementData, random); @@ -158,7 +161,7 @@ public abstract class NBTStructureFeature extends DefaultFeature { return true; } - private BlockBox makeBox(BlockPos pos) { + protected BlockBox makeBox(BlockPos pos) { int sx = ((pos.getX() >> 4) << 4) - 16; int sz = ((pos.getZ() >> 4) << 4) - 16; int ex = sx + 47;