package net.minecraft.world.level.levelgen.structure.structures; import com.mojang.datafixers.util.Either; import com.mojang.serialization.Codec; import com.mojang.serialization.MapCodec; import com.mojang.serialization.codecs.RecordCodecBuilder; import java.util.Optional; import java.util.function.IntFunction; import net.minecraft.core.BlockPos; import net.minecraft.util.ByIdMap; import net.minecraft.util.Mth; import net.minecraft.util.StringRepresentable; import net.minecraft.util.ByIdMap.OutOfBoundsStrategy; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.chunk.ChunkGenerator; import net.minecraft.world.level.levelgen.Heightmap; import net.minecraft.world.level.levelgen.WorldgenRandom; import net.minecraft.world.level.levelgen.structure.Structure; import net.minecraft.world.level.levelgen.structure.StructureType; import net.minecraft.world.level.levelgen.structure.Structure.GenerationContext; import net.minecraft.world.level.levelgen.structure.Structure.GenerationStub; import net.minecraft.world.level.levelgen.structure.Structure.StructureSettings; import net.minecraft.world.level.levelgen.structure.pieces.StructurePiecesBuilder; public class MineshaftStructure extends Structure { public static final MapCodec CODEC = RecordCodecBuilder.mapCodec( instance -> instance.group( settingsCodec(instance), MineshaftStructure.Type.CODEC.fieldOf("mineshaft_type").forGetter(mineshaftStructure -> mineshaftStructure.type) ) .apply(instance, MineshaftStructure::new) ); private final MineshaftStructure.Type type; public MineshaftStructure(StructureSettings settings, MineshaftStructure.Type type) { super(settings); this.type = type; } @Override public Optional findGenerationPoint(GenerationContext context) { context.random().nextDouble(); ChunkPos chunkPos = context.chunkPos(); BlockPos blockPos = new BlockPos(chunkPos.getMiddleBlockX(), 50, chunkPos.getMinBlockZ()); StructurePiecesBuilder structurePiecesBuilder = new StructurePiecesBuilder(); int i = this.generatePiecesAndAdjust(structurePiecesBuilder, context); return Optional.of(new GenerationStub(blockPos.offset(0, i, 0), Either.right(structurePiecesBuilder))); } private int generatePiecesAndAdjust(StructurePiecesBuilder builder, GenerationContext context) { ChunkPos chunkPos = context.chunkPos(); WorldgenRandom worldgenRandom = context.random(); ChunkGenerator chunkGenerator = context.chunkGenerator(); MineshaftPieces.MineShaftRoom mineShaftRoom = new MineshaftPieces.MineShaftRoom(0, worldgenRandom, chunkPos.getBlockX(2), chunkPos.getBlockZ(2), this.type); builder.addPiece(mineShaftRoom); mineShaftRoom.addChildren(mineShaftRoom, builder, worldgenRandom); int i = chunkGenerator.getSeaLevel(); if (this.type == MineshaftStructure.Type.MESA) { BlockPos blockPos = builder.getBoundingBox().getCenter(); int j = chunkGenerator.getBaseHeight(blockPos.getX(), blockPos.getZ(), Heightmap.Types.WORLD_SURFACE_WG, context.heightAccessor(), context.randomState()); int k = j <= i ? i : Mth.randomBetweenInclusive(worldgenRandom, i, j); int l = k - blockPos.getY(); builder.offsetPiecesVertically(l); return l; } else { return builder.moveBelowSeaLevel(i, chunkGenerator.getMinY(), worldgenRandom, 10); } } @Override public StructureType type() { return StructureType.MINESHAFT; } public static enum Type implements StringRepresentable { NORMAL("normal", Blocks.OAK_LOG, Blocks.OAK_PLANKS, Blocks.OAK_FENCE), MESA("mesa", Blocks.DARK_OAK_LOG, Blocks.DARK_OAK_PLANKS, Blocks.DARK_OAK_FENCE); public static final Codec CODEC = StringRepresentable.fromEnum(MineshaftStructure.Type::values); private static final IntFunction BY_ID = ByIdMap.continuous(Enum::ordinal, values(), OutOfBoundsStrategy.ZERO); private final String name; private final BlockState woodState; private final BlockState planksState; private final BlockState fenceState; private Type(final String name, final Block woodBlock, final Block planksBlock, final Block fenceBlock) { this.name = name; this.woodState = woodBlock.defaultBlockState(); this.planksState = planksBlock.defaultBlockState(); this.fenceState = fenceBlock.defaultBlockState(); } public String getName() { return this.name; } public static MineshaftStructure.Type byId(int id) { return (MineshaftStructure.Type)BY_ID.apply(id); } public BlockState getWoodState() { return this.woodState; } public BlockState getPlanksState() { return this.planksState; } public BlockState getFenceState() { return this.fenceState; } @Override public String getSerializedName() { return this.name; } } }