diff --git a/src/main/java/kaptainwutax/seedcracker/finder/AbstractTempleFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/AbstractTempleFinder.java new file mode 100644 index 0000000..f0cfd31 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/finder/AbstractTempleFinder.java @@ -0,0 +1,54 @@ +package kaptainwutax.seedcracker.finder; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3i; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public abstract class AbstractTempleFinder extends Finder { + + protected List finders = new ArrayList<>(); + protected final Vec3i size; + + protected Map posToLayout = new HashMap<>(); + + public AbstractTempleFinder(World world, ChunkPos chunkPos, Vec3i size) { + super(world, chunkPos); + + Direction.Type.HORIZONTAL.forEach(direction -> { + PieceFinder finder = new PieceFinder(world, chunkPos, direction, size, pos -> { + if(pos.getX() != 0)return false; + if(pos.getY() < 63)return false; + if(pos.getZ() != 0)return false; + return true; + }); + + buildStructure(finder); + finders.add(finder); + }); + + this.size = size; + } + + @Override + public List findInChunk() { + List result = new ArrayList<>(); + + this.finders.forEach(finder -> { + List rawResult = finder.findInChunk(); + rawResult.forEach(raw -> posToLayout.put(raw, finder.getLayout())); + result.addAll(rawResult); + }); + + return result; + } + + public abstract void buildStructure(PieceFinder finder); + +} diff --git a/src/main/java/kaptainwutax/seedcracker/finder/PieceFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/PieceFinder.java new file mode 100644 index 0000000..d530180 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/finder/PieceFinder.java @@ -0,0 +1,215 @@ +package kaptainwutax.seedcracker.finder; + +import kaptainwutax.seedcracker.world.ChunkWrapper; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.util.BlockMirror; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.math.*; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +public class PieceFinder extends Finder { + + protected Map structure = new HashMap<>(); + private MutableIntBoundingBox boundingBox; + private final Predicate searchPredicate; + + protected Direction facing; + private BlockMirror mirror; + private BlockRotation rotation; + + //SizeX, width here for clarity when comparing with original code. + protected int width; + + //SizeY, width here for clarity when comparing with original code. + protected int height; + + //SizeZ, width here for clarity when comparing with original code. + protected int depth; + + public PieceFinder(World world, ChunkPos chunkPos, Direction facing, Vec3i size, Predicate searchPredicate) { + super(world, chunkPos); + this.setOrientation(facing); + + this.width = size.getX(); + this.height = size.getY(); + this.depth = size.getZ(); + + if(this.facing.getAxis() == Direction.Axis.Z) { + this.boundingBox = new MutableIntBoundingBox( + 0, 0, 0, + size.getX() - 1, size.getY() - 1, size.getZ() - 1 + ); + } else { + this.boundingBox = new MutableIntBoundingBox( + 0, 0, 0, + size.getZ() - 1, size.getY() - 1, size.getX() - 1 + ); + } + + this.searchPredicate = searchPredicate; + } + + public Vec3i getLayout() { + if(this.facing.getAxis() != Direction.Axis.Z) { + return new Vec3i(this.depth, this.height, this.width); + } + + return new Vec3i(this.width, this.height, this.depth); + } + + @Override + public List findInChunk() { + List result = new ArrayList<>(); + + ChunkWrapper chunkWrapper = new ChunkWrapper(this.world, this.chunkPos); + Chunk chunk = chunkWrapper.getChunk(); + + for(BlockPos center: CHUNK_POSITIONS) { + if(!this.searchPredicate.test(center))continue; + + boolean found = true; + + for(Map.Entry entry: this.structure.entrySet()) { + BlockPos pos = this.chunkPos.getCenterBlockPos().add(center.add(entry.getKey())); + BlockState state = this.world.getBlockState(pos); + + //Blockstate may change when it gets placed in the world, that's why it's using the block here. + if(!state.getBlock().equals(entry.getValue().getBlock())) { + found = false; + break; + } + } + + if(found) { + result.add(this.chunkPos.getCenterBlockPos().add(center)); + } + } + + return result; + } + + public void setOrientation(Direction facing) { + this.facing = facing; + + if(facing == null) { + this.rotation = BlockRotation.NONE; + this.mirror = BlockMirror.NONE; + } else { + switch(facing) { + case SOUTH: + this.mirror = BlockMirror.LEFT_RIGHT; + this.rotation = BlockRotation.NONE; + break; + case WEST: + this.mirror = BlockMirror.LEFT_RIGHT; + this.rotation = BlockRotation.CLOCKWISE_90; + break; + case EAST: + this.mirror = BlockMirror.NONE; + this.rotation = BlockRotation.CLOCKWISE_90; + break; + default: + this.mirror = BlockMirror.NONE; + this.rotation = BlockRotation.NONE; + } + } + + } + + protected int applyXTransform(int x, int z) { + if (this.facing == null) { + return x; + } else { + switch(this.facing) { + case NORTH: + case SOUTH: + return this.boundingBox.minX + x; + case WEST: + return this.boundingBox.maxX - z; + case EAST: + return this.boundingBox.minX + z; + default: + return x; + } + } + } + + protected int applyYTransform(int y) { + return this.facing == null ? y : y + this.boundingBox.minY; + } + + protected int applyZTransform(int x, int z) { + if (this.facing == null) { + return z; + } else { + switch(this.facing) { + case NORTH: + return this.boundingBox.maxZ - z; + case SOUTH: + return this.boundingBox.minZ + z; + case WEST: + case EAST: + return this.boundingBox.minZ + x; + default: + return z; + } + } + } + + protected BlockState getBlockAt(int ox, int oy, int oz) { + int x = this.applyXTransform(ox, oz); + int y = this.applyYTransform(oy); + int z = this.applyZTransform(ox, oz); + BlockPos pos = new BlockPos(x, y, z); + + return !this.boundingBox.contains(pos) ? + Blocks.AIR.getDefaultState() : + this.structure.getOrDefault(pos, Blocks.AIR.getDefaultState()); + } + + protected void fillWithOutline(int minX, int minY, int minZ, int maxX, int maxY, int maxZ, BlockState outline, BlockState inside, boolean onlyReplaceAir) { + for(int y = minY; y <= maxY; ++y) { + for(int x = minX; x <= maxX; ++x) { + for(int z = minZ; z <= maxZ; ++z) { + if(!onlyReplaceAir || !this.getBlockAt(x, y, z).isAir()) { + if(y != minY && y != maxY && x != minX && x != maxX && z != minZ && z != maxZ) { + this.addBlock(inside, x, y, z); + } else { + this.addBlock(outline, x, y, z); + } + } + } + } + } + + } + + protected void addBlock(BlockState state, int x, int y, int z) { + BlockPos pos = new BlockPos( + this.applyXTransform(x, z), + this.applyYTransform(y), + this.applyZTransform(x, z) + ); + + if(this.boundingBox.contains(pos)) { + if (this.mirror != BlockMirror.NONE) { + state = state.mirror(this.mirror); + } + + if (this.rotation != BlockRotation.NONE) { + state = state.rotate(this.rotation); + } + + this.structure.put(pos, state); + } + } + +} diff --git a/src/main/java/kaptainwutax/seedcracker/finder/SwampHutFinder.java b/src/main/java/kaptainwutax/seedcracker/finder/SwampHutFinder.java new file mode 100644 index 0000000..dad9f31 --- /dev/null +++ b/src/main/java/kaptainwutax/seedcracker/finder/SwampHutFinder.java @@ -0,0 +1,77 @@ +package kaptainwutax.seedcracker.finder; + +import kaptainwutax.seedcracker.render.Cuboid; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.StairsBlock; +import net.minecraft.block.enums.StairShape; +import net.minecraft.client.util.math.Vector4f; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Vec3i; +import net.minecraft.world.World; +import net.minecraft.world.biome.Biome; +import net.minecraft.world.gen.feature.Feature; + +import java.util.List; + +public class SwampHutFinder extends AbstractTempleFinder { + + public SwampHutFinder(World world, ChunkPos chunkPos) { + super(world, chunkPos, new Vec3i(7, 7, 9)); + } + + @Override + public List findInChunk() { + List result = super.findInChunk(); + + result.removeIf(pos -> { + Biome biome = world.getBiome(pos); + if(!biome.hasStructureFeature(Feature.SWAMP_HUT))return true; + + return false; + }); + + result.forEach(pos -> this.renderers.add(new Cuboid(pos, this.posToLayout.get(pos), new Vector4f(1.0f, 0.0f, 1.0f, 1.0f)))); + return result; + } + + @Override + public void buildStructure(PieceFinder finder) { + finder.fillWithOutline(1, 1, 1, 5, 1, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(1, 4, 2, 5, 4, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(2, 1, 0, 4, 1, 0, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(2, 2, 2, 3, 3, 2, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(1, 2, 3, 1, 3, 6, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(5, 2, 3, 5, 3, 6, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(2, 2, 7, 4, 3, 7, Blocks.SPRUCE_PLANKS.getDefaultState(), Blocks.SPRUCE_PLANKS.getDefaultState(), false); + finder.fillWithOutline(1, 0, 2, 1, 3, 2, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); + finder.fillWithOutline(5, 0, 2, 5, 3, 2, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); + finder.fillWithOutline(1, 0, 7, 1, 3, 7, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); + finder.fillWithOutline(5, 0, 7, 5, 3, 7, Blocks.OAK_LOG.getDefaultState(), Blocks.OAK_LOG.getDefaultState(), false); + finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 2, 3, 2); + finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 3, 3, 7); + finder.addBlock(Blocks.AIR.getDefaultState(), 1, 3, 4); + finder.addBlock(Blocks.AIR.getDefaultState(), 5, 3, 4); + finder.addBlock(Blocks.AIR.getDefaultState(), 5, 3, 5); + finder.addBlock(Blocks.POTTED_RED_MUSHROOM.getDefaultState(), 1, 3, 5); + finder.addBlock(Blocks.CRAFTING_TABLE.getDefaultState(), 3, 2, 6); + finder.addBlock(Blocks.CAULDRON.getDefaultState(), 4, 2, 6); + finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 1, 2, 1); + finder.addBlock(Blocks.OAK_FENCE.getDefaultState(), 5, 2, 1); + BlockState northStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.NORTH); + BlockState eastStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.EAST); + BlockState westStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.WEST); + BlockState southStairs = Blocks.SPRUCE_STAIRS.getDefaultState().with(StairsBlock.FACING, Direction.SOUTH); + finder.fillWithOutline(0, 4, 1, 6, 4, 1, northStairs, northStairs, false); + finder.fillWithOutline(0, 4, 2, 0, 4, 7, eastStairs, eastStairs, false); + finder.fillWithOutline(6, 4, 2, 6, 4, 7, westStairs, westStairs, false); + finder.fillWithOutline(0, 4, 8, 6, 4, 8, southStairs, southStairs, false); + finder.addBlock(northStairs.with(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), 0, 4, 1); + finder.addBlock(northStairs.with(StairsBlock.SHAPE, StairShape.OUTER_LEFT), 6, 4, 1); + finder.addBlock(southStairs.with(StairsBlock.SHAPE, StairShape.OUTER_LEFT), 0, 4, 8); + finder.addBlock(southStairs.with(StairsBlock.SHAPE, StairShape.OUTER_RIGHT), 6, 4, 8); + } + +}