minecraft-src/net/minecraft/world/level/levelgen/structure/structures/MineshaftPieces.java
2025-07-04 03:45:38 +03:00

1046 lines
39 KiB
Java

package net.minecraft.world.level.levelgen.structure.structures;
import com.google.common.collect.Lists;
import java.util.Collection;
import java.util.List;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceKey;
import net.minecraft.tags.BiomeTags;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.vehicle.MinecartChest;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.LevelAccessor;
import net.minecraft.world.level.LevelReader;
import net.minecraft.world.level.StructureManager;
import net.minecraft.world.level.WorldGenLevel;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.FallingBlock;
import net.minecraft.world.level.block.FenceBlock;
import net.minecraft.world.level.block.RailBlock;
import net.minecraft.world.level.block.WallTorchBlock;
import net.minecraft.world.level.block.entity.SpawnerBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.properties.RailShape;
import net.minecraft.world.level.chunk.ChunkGenerator;
import net.minecraft.world.level.levelgen.structure.BoundingBox;
import net.minecraft.world.level.levelgen.structure.StructurePiece;
import net.minecraft.world.level.levelgen.structure.StructurePieceAccessor;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceType;
import net.minecraft.world.level.storage.loot.BuiltInLootTables;
import net.minecraft.world.level.storage.loot.LootTable;
import org.jetbrains.annotations.Nullable;
public class MineshaftPieces {
private static final int DEFAULT_SHAFT_WIDTH = 3;
private static final int DEFAULT_SHAFT_HEIGHT = 3;
private static final int DEFAULT_SHAFT_LENGTH = 5;
private static final int MAX_PILLAR_HEIGHT = 20;
private static final int MAX_CHAIN_HEIGHT = 50;
private static final int MAX_DEPTH = 8;
public static final int MAGIC_START_Y = 50;
private static MineshaftPieces.MineShaftPiece createRandomShaftPiece(
StructurePieceAccessor pieces, RandomSource random, int x, int y, int z, @Nullable Direction orientation, int genDepth, MineshaftStructure.Type type
) {
int i = random.nextInt(100);
if (i >= 80) {
BoundingBox boundingBox = MineshaftPieces.MineShaftCrossing.findCrossing(pieces, random, x, y, z, orientation);
if (boundingBox != null) {
return new MineshaftPieces.MineShaftCrossing(genDepth, boundingBox, orientation, type);
}
} else if (i >= 70) {
BoundingBox boundingBox = MineshaftPieces.MineShaftStairs.findStairs(pieces, random, x, y, z, orientation);
if (boundingBox != null) {
return new MineshaftPieces.MineShaftStairs(genDepth, boundingBox, orientation, type);
}
} else {
BoundingBox boundingBox = MineshaftPieces.MineShaftCorridor.findCorridorSize(pieces, random, x, y, z, orientation);
if (boundingBox != null) {
return new MineshaftPieces.MineShaftCorridor(genDepth, random, boundingBox, orientation, type);
}
}
return null;
}
static MineshaftPieces.MineShaftPiece generateAndAddPiece(
StructurePiece piece, StructurePieceAccessor pieces, RandomSource random, int x, int y, int z, Direction direction, int genDepth
) {
if (genDepth > 8) {
return null;
} else if (Math.abs(x - piece.getBoundingBox().minX()) <= 80 && Math.abs(z - piece.getBoundingBox().minZ()) <= 80) {
MineshaftStructure.Type type = ((MineshaftPieces.MineShaftPiece)piece).type;
MineshaftPieces.MineShaftPiece mineShaftPiece = createRandomShaftPiece(pieces, random, x, y, z, direction, genDepth + 1, type);
if (mineShaftPiece != null) {
pieces.addPiece(mineShaftPiece);
mineShaftPiece.addChildren(piece, pieces, random);
}
return mineShaftPiece;
} else {
return null;
}
}
public static class MineShaftCorridor extends MineshaftPieces.MineShaftPiece {
private final boolean hasRails;
private final boolean spiderCorridor;
private boolean hasPlacedSpider;
private final int numSections;
public MineShaftCorridor(CompoundTag tag) {
super(StructurePieceType.MINE_SHAFT_CORRIDOR, tag);
this.hasRails = tag.getBooleanOr("hr", false);
this.spiderCorridor = tag.getBooleanOr("sc", false);
this.hasPlacedSpider = tag.getBooleanOr("hps", false);
this.numSections = tag.getIntOr("Num", 0);
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
tag.putBoolean("hr", this.hasRails);
tag.putBoolean("sc", this.spiderCorridor);
tag.putBoolean("hps", this.hasPlacedSpider);
tag.putInt("Num", this.numSections);
}
public MineShaftCorridor(int genDepth, RandomSource random, BoundingBox boundingBox, Direction orientation, MineshaftStructure.Type type) {
super(StructurePieceType.MINE_SHAFT_CORRIDOR, genDepth, type, boundingBox);
this.setOrientation(orientation);
this.hasRails = random.nextInt(3) == 0;
this.spiderCorridor = !this.hasRails && random.nextInt(23) == 0;
if (this.getOrientation().getAxis() == Direction.Axis.Z) {
this.numSections = boundingBox.getZSpan() / 5;
} else {
this.numSections = boundingBox.getXSpan() / 5;
}
}
@Nullable
public static BoundingBox findCorridorSize(StructurePieceAccessor pieces, RandomSource random, int x, int y, int z, Direction direction) {
for (int i = random.nextInt(3) + 2; i > 0; i--) {
int j = i * 5;
BoundingBox boundingBox = switch (direction) {
default -> new BoundingBox(0, 0, -(j - 1), 2, 2, 0);
case SOUTH -> new BoundingBox(0, 0, 0, 2, 2, j - 1);
case WEST -> new BoundingBox(-(j - 1), 0, 0, 0, 2, 2);
case EAST -> new BoundingBox(0, 0, 0, j - 1, 2, 2);
};
boundingBox.move(x, y, z);
if (pieces.findCollisionPiece(boundingBox) == null) {
return boundingBox;
}
}
return null;
}
@Override
public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) {
int i = this.getGenDepth();
int j = random.nextInt(4);
Direction direction = this.getOrientation();
if (direction != null) {
switch (direction) {
case NORTH:
default:
if (j <= 1) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ() - 1, direction, i
);
} else if (j == 2) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ(), Direction.WEST, i
);
} else {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ(), Direction.EAST, i
);
}
break;
case SOUTH:
if (j <= 1) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.maxZ() + 1, direction, i
);
} else if (j == 2) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.maxZ() - 3, Direction.WEST, i
);
} else {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.maxZ() - 3, Direction.EAST, i
);
}
break;
case WEST:
if (j <= 1) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ(), direction, i
);
} else if (j == 2) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
} else {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
}
break;
case EAST:
if (j <= 1) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ(), direction, i
);
} else if (j == 2) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() - 3, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
} else {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() - 3, this.boundingBox.minY() - 1 + random.nextInt(3), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
}
}
}
if (i < 8) {
if (direction != Direction.NORTH && direction != Direction.SOUTH) {
for (int k = this.boundingBox.minX() + 3; k + 3 <= this.boundingBox.maxX(); k += 5) {
int l = random.nextInt(5);
if (l == 0) {
MineshaftPieces.generateAndAddPiece(piece, pieces, random, k, this.boundingBox.minY(), this.boundingBox.minZ() - 1, Direction.NORTH, i + 1);
} else if (l == 1) {
MineshaftPieces.generateAndAddPiece(piece, pieces, random, k, this.boundingBox.minY(), this.boundingBox.maxZ() + 1, Direction.SOUTH, i + 1);
}
}
} else {
for (int kx = this.boundingBox.minZ() + 3; kx + 3 <= this.boundingBox.maxZ(); kx += 5) {
int l = random.nextInt(5);
if (l == 0) {
MineshaftPieces.generateAndAddPiece(piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY(), kx, Direction.WEST, i + 1);
} else if (l == 1) {
MineshaftPieces.generateAndAddPiece(piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY(), kx, Direction.EAST, i + 1);
}
}
}
}
}
@Override
protected boolean createChest(WorldGenLevel level, BoundingBox box, RandomSource random, int x, int y, int z, ResourceKey<LootTable> lootTable) {
BlockPos blockPos = this.getWorldPos(x, y, z);
if (box.isInside(blockPos) && level.getBlockState(blockPos).isAir() && !level.getBlockState(blockPos.below()).isAir()) {
BlockState blockState = Blocks.RAIL.defaultBlockState().setValue(RailBlock.SHAPE, random.nextBoolean() ? RailShape.NORTH_SOUTH : RailShape.EAST_WEST);
this.placeBlock(level, blockState, x, y, z, box);
MinecartChest minecartChest = EntityType.CHEST_MINECART.create(level.getLevel(), EntitySpawnReason.CHUNK_GENERATION);
if (minecartChest != null) {
minecartChest.setInitialPos(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5);
minecartChest.setLootTable(lootTable, random.nextLong());
level.addFreshEntity(minecartChest);
}
return true;
} else {
return false;
}
}
@Override
public void postProcess(
WorldGenLevel level, StructureManager structureManager, ChunkGenerator generator, RandomSource random, BoundingBox box, ChunkPos chunkPos, BlockPos pos
) {
if (!this.isInInvalidLocation(level, box)) {
int i = 0;
int j = 2;
int k = 0;
int l = 2;
int m = this.numSections * 5 - 1;
BlockState blockState = this.type.getPlanksState();
this.generateBox(level, box, 0, 0, 0, 2, 1, m, CAVE_AIR, CAVE_AIR, false);
this.generateMaybeBox(level, box, random, 0.8F, 0, 2, 0, 2, 2, m, CAVE_AIR, CAVE_AIR, false, false);
if (this.spiderCorridor) {
this.generateMaybeBox(level, box, random, 0.6F, 0, 0, 0, 2, 1, m, Blocks.COBWEB.defaultBlockState(), CAVE_AIR, false, true);
}
for (int n = 0; n < this.numSections; n++) {
int o = 2 + n * 5;
this.placeSupport(level, box, 0, 0, o, 2, 2, random);
this.maybePlaceCobWeb(level, box, random, 0.1F, 0, 2, o - 1);
this.maybePlaceCobWeb(level, box, random, 0.1F, 2, 2, o - 1);
this.maybePlaceCobWeb(level, box, random, 0.1F, 0, 2, o + 1);
this.maybePlaceCobWeb(level, box, random, 0.1F, 2, 2, o + 1);
this.maybePlaceCobWeb(level, box, random, 0.05F, 0, 2, o - 2);
this.maybePlaceCobWeb(level, box, random, 0.05F, 2, 2, o - 2);
this.maybePlaceCobWeb(level, box, random, 0.05F, 0, 2, o + 2);
this.maybePlaceCobWeb(level, box, random, 0.05F, 2, 2, o + 2);
if (random.nextInt(100) == 0) {
this.createChest(level, box, random, 2, 0, o - 1, BuiltInLootTables.ABANDONED_MINESHAFT);
}
if (random.nextInt(100) == 0) {
this.createChest(level, box, random, 0, 0, o + 1, BuiltInLootTables.ABANDONED_MINESHAFT);
}
if (this.spiderCorridor && !this.hasPlacedSpider) {
int p = 1;
int q = o - 1 + random.nextInt(3);
BlockPos blockPos = this.getWorldPos(1, 0, q);
if (box.isInside(blockPos) && this.isInterior(level, 1, 0, q, box)) {
this.hasPlacedSpider = true;
level.setBlock(blockPos, Blocks.SPAWNER.defaultBlockState(), 2);
if (level.getBlockEntity(blockPos) instanceof SpawnerBlockEntity spawnerBlockEntity) {
spawnerBlockEntity.setEntityId(EntityType.CAVE_SPIDER, random);
}
}
}
}
for (int n = 0; n <= 2; n++) {
for (int ox = 0; ox <= m; ox++) {
this.setPlanksBlock(level, box, blockState, n, -1, ox);
}
}
int n = 2;
this.placeDoubleLowerOrUpperSupport(level, box, 0, -1, 2);
if (this.numSections > 1) {
int ox = m - 2;
this.placeDoubleLowerOrUpperSupport(level, box, 0, -1, ox);
}
if (this.hasRails) {
BlockState blockState2 = Blocks.RAIL.defaultBlockState().setValue(RailBlock.SHAPE, RailShape.NORTH_SOUTH);
for (int p = 0; p <= m; p++) {
BlockState blockState3 = this.getBlock(level, 1, -1, p, box);
if (!blockState3.isAir() && blockState3.isSolidRender()) {
float f = this.isInterior(level, 1, 0, p, box) ? 0.7F : 0.9F;
this.maybeGenerateBlock(level, box, random, f, 1, 0, p, blockState2);
}
}
}
}
}
private void placeDoubleLowerOrUpperSupport(WorldGenLevel level, BoundingBox box, int x, int y, int z) {
BlockState blockState = this.type.getWoodState();
BlockState blockState2 = this.type.getPlanksState();
if (this.getBlock(level, x, y, z, box).is(blockState2.getBlock())) {
this.fillPillarDownOrChainUp(level, blockState, x, y, z, box);
}
if (this.getBlock(level, x + 2, y, z, box).is(blockState2.getBlock())) {
this.fillPillarDownOrChainUp(level, blockState, x + 2, y, z, box);
}
}
@Override
protected void fillColumnDown(WorldGenLevel level, BlockState state, int x, int y, int z, BoundingBox box) {
BlockPos.MutableBlockPos mutableBlockPos = this.getWorldPos(x, y, z);
if (box.isInside(mutableBlockPos)) {
int i = mutableBlockPos.getY();
while (this.isReplaceableByStructures(level.getBlockState(mutableBlockPos)) && mutableBlockPos.getY() > level.getMinY() + 1) {
mutableBlockPos.move(Direction.DOWN);
}
if (this.canPlaceColumnOnTopOf(level, mutableBlockPos, level.getBlockState(mutableBlockPos))) {
while (mutableBlockPos.getY() < i) {
mutableBlockPos.move(Direction.UP);
level.setBlock(mutableBlockPos, state, 2);
}
}
}
}
protected void fillPillarDownOrChainUp(WorldGenLevel level, BlockState state, int x, int y, int z, BoundingBox box) {
BlockPos.MutableBlockPos mutableBlockPos = this.getWorldPos(x, y, z);
if (box.isInside(mutableBlockPos)) {
int i = mutableBlockPos.getY();
int j = 1;
boolean bl = true;
for (boolean bl2 = true; bl || bl2; j++) {
if (bl) {
mutableBlockPos.setY(i - j);
BlockState blockState = level.getBlockState(mutableBlockPos);
boolean bl3 = this.isReplaceableByStructures(blockState) && !blockState.is(Blocks.LAVA);
if (!bl3 && this.canPlaceColumnOnTopOf(level, mutableBlockPos, blockState)) {
fillColumnBetween(level, state, mutableBlockPos, i - j + 1, i);
return;
}
bl = j <= 20 && bl3 && mutableBlockPos.getY() > level.getMinY() + 1;
}
if (bl2) {
mutableBlockPos.setY(i + j);
BlockState blockState = level.getBlockState(mutableBlockPos);
boolean bl3 = this.isReplaceableByStructures(blockState);
if (!bl3 && this.canHangChainBelow(level, mutableBlockPos, blockState)) {
level.setBlock(mutableBlockPos.setY(i + 1), this.type.getFenceState(), 2);
fillColumnBetween(level, Blocks.CHAIN.defaultBlockState(), mutableBlockPos, i + 2, i + j);
return;
}
bl2 = j <= 50 && bl3 && mutableBlockPos.getY() < level.getMaxY();
}
}
}
}
private static void fillColumnBetween(WorldGenLevel level, BlockState state, BlockPos.MutableBlockPos pos, int minY, int maxY) {
for (int i = minY; i < maxY; i++) {
level.setBlock(pos.setY(i), state, 2);
}
}
private boolean canPlaceColumnOnTopOf(LevelReader level, BlockPos pos, BlockState state) {
return state.isFaceSturdy(level, pos, Direction.UP);
}
private boolean canHangChainBelow(LevelReader level, BlockPos pos, BlockState state) {
return Block.canSupportCenter(level, pos, Direction.DOWN) && !(state.getBlock() instanceof FallingBlock);
}
private void placeSupport(WorldGenLevel level, BoundingBox box, int minX, int minY, int z, int maxY, int maxX, RandomSource random) {
if (this.isSupportingBox(level, box, minX, maxX, maxY, z)) {
BlockState blockState = this.type.getPlanksState();
BlockState blockState2 = this.type.getFenceState();
this.generateBox(level, box, minX, minY, z, minX, maxY - 1, z, blockState2.setValue(FenceBlock.WEST, true), CAVE_AIR, false);
this.generateBox(level, box, maxX, minY, z, maxX, maxY - 1, z, blockState2.setValue(FenceBlock.EAST, true), CAVE_AIR, false);
if (random.nextInt(4) == 0) {
this.generateBox(level, box, minX, maxY, z, minX, maxY, z, blockState, CAVE_AIR, false);
this.generateBox(level, box, maxX, maxY, z, maxX, maxY, z, blockState, CAVE_AIR, false);
} else {
this.generateBox(level, box, minX, maxY, z, maxX, maxY, z, blockState, CAVE_AIR, false);
this.maybeGenerateBlock(
level, box, random, 0.05F, minX + 1, maxY, z - 1, Blocks.WALL_TORCH.defaultBlockState().setValue(WallTorchBlock.FACING, Direction.SOUTH)
);
this.maybeGenerateBlock(
level, box, random, 0.05F, minX + 1, maxY, z + 1, Blocks.WALL_TORCH.defaultBlockState().setValue(WallTorchBlock.FACING, Direction.NORTH)
);
}
}
}
private void maybePlaceCobWeb(WorldGenLevel level, BoundingBox box, RandomSource random, float chance, int x, int y, int z) {
if (this.isInterior(level, x, y, z, box) && random.nextFloat() < chance && this.hasSturdyNeighbours(level, box, x, y, z, 2)) {
this.placeBlock(level, Blocks.COBWEB.defaultBlockState(), x, y, z, box);
}
}
private boolean hasSturdyNeighbours(WorldGenLevel level, BoundingBox box, int x, int y, int z, int required) {
BlockPos.MutableBlockPos mutableBlockPos = this.getWorldPos(x, y, z);
int i = 0;
for (Direction direction : Direction.values()) {
mutableBlockPos.move(direction);
if (box.isInside(mutableBlockPos) && level.getBlockState(mutableBlockPos).isFaceSturdy(level, mutableBlockPos, direction.getOpposite())) {
if (++i >= required) {
return true;
}
}
mutableBlockPos.move(direction.getOpposite());
}
return false;
}
}
public static class MineShaftCrossing extends MineshaftPieces.MineShaftPiece {
private final Direction direction;
private final boolean isTwoFloored;
public MineShaftCrossing(CompoundTag tag) {
super(StructurePieceType.MINE_SHAFT_CROSSING, tag);
this.isTwoFloored = tag.getBooleanOr("tf", false);
this.direction = (Direction)tag.read("D", Direction.LEGACY_ID_CODEC_2D).orElse(Direction.SOUTH);
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
tag.putBoolean("tf", this.isTwoFloored);
tag.store("D", Direction.LEGACY_ID_CODEC_2D, this.direction);
}
public MineShaftCrossing(int genDepth, BoundingBox boundingBox, @Nullable Direction direction, MineshaftStructure.Type type) {
super(StructurePieceType.MINE_SHAFT_CROSSING, genDepth, type, boundingBox);
this.direction = direction;
this.isTwoFloored = boundingBox.getYSpan() > 3;
}
@Nullable
public static BoundingBox findCrossing(StructurePieceAccessor pieces, RandomSource random, int x, int y, int z, Direction direction) {
int i;
if (random.nextInt(4) == 0) {
i = 6;
} else {
i = 2;
}
BoundingBox boundingBox = switch (direction) {
default -> new BoundingBox(-1, 0, -4, 3, i, 0);
case SOUTH -> new BoundingBox(-1, 0, 0, 3, i, 4);
case WEST -> new BoundingBox(-4, 0, -1, 0, i, 3);
case EAST -> new BoundingBox(0, 0, -1, 4, i, 3);
};
boundingBox.move(x, y, z);
return pieces.findCollisionPiece(boundingBox) != null ? null : boundingBox;
}
@Override
public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) {
int i = this.getGenDepth();
switch (this.direction) {
case NORTH:
default:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.WEST, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.EAST, i
);
break;
case SOUTH:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.WEST, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.EAST, i
);
break;
case WEST:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.WEST, i
);
break;
case EAST:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, Direction.EAST, i
);
}
if (this.isTwoFloored) {
if (random.nextBoolean()) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY() + 3 + 1, this.boundingBox.minZ() - 1, Direction.NORTH, i
);
}
if (random.nextBoolean()) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY() + 3 + 1, this.boundingBox.minZ() + 1, Direction.WEST, i
);
}
if (random.nextBoolean()) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY() + 3 + 1, this.boundingBox.minZ() + 1, Direction.EAST, i
);
}
if (random.nextBoolean()) {
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + 1, this.boundingBox.minY() + 3 + 1, this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
}
}
}
@Override
public void postProcess(
WorldGenLevel level, StructureManager structureManager, ChunkGenerator generator, RandomSource random, BoundingBox box, ChunkPos chunkPos, BlockPos pos
) {
if (!this.isInInvalidLocation(level, box)) {
BlockState blockState = this.type.getPlanksState();
if (this.isTwoFloored) {
this.generateBox(
level,
box,
this.boundingBox.minX() + 1,
this.boundingBox.minY(),
this.boundingBox.minZ(),
this.boundingBox.maxX() - 1,
this.boundingBox.minY() + 3 - 1,
this.boundingBox.maxZ(),
CAVE_AIR,
CAVE_AIR,
false
);
this.generateBox(
level,
box,
this.boundingBox.minX(),
this.boundingBox.minY(),
this.boundingBox.minZ() + 1,
this.boundingBox.maxX(),
this.boundingBox.minY() + 3 - 1,
this.boundingBox.maxZ() - 1,
CAVE_AIR,
CAVE_AIR,
false
);
this.generateBox(
level,
box,
this.boundingBox.minX() + 1,
this.boundingBox.maxY() - 2,
this.boundingBox.minZ(),
this.boundingBox.maxX() - 1,
this.boundingBox.maxY(),
this.boundingBox.maxZ(),
CAVE_AIR,
CAVE_AIR,
false
);
this.generateBox(
level,
box,
this.boundingBox.minX(),
this.boundingBox.maxY() - 2,
this.boundingBox.minZ() + 1,
this.boundingBox.maxX(),
this.boundingBox.maxY(),
this.boundingBox.maxZ() - 1,
CAVE_AIR,
CAVE_AIR,
false
);
this.generateBox(
level,
box,
this.boundingBox.minX() + 1,
this.boundingBox.minY() + 3,
this.boundingBox.minZ() + 1,
this.boundingBox.maxX() - 1,
this.boundingBox.minY() + 3,
this.boundingBox.maxZ() - 1,
CAVE_AIR,
CAVE_AIR,
false
);
} else {
this.generateBox(
level,
box,
this.boundingBox.minX() + 1,
this.boundingBox.minY(),
this.boundingBox.minZ(),
this.boundingBox.maxX() - 1,
this.boundingBox.maxY(),
this.boundingBox.maxZ(),
CAVE_AIR,
CAVE_AIR,
false
);
this.generateBox(
level,
box,
this.boundingBox.minX(),
this.boundingBox.minY(),
this.boundingBox.minZ() + 1,
this.boundingBox.maxX(),
this.boundingBox.maxY(),
this.boundingBox.maxZ() - 1,
CAVE_AIR,
CAVE_AIR,
false
);
}
this.placeSupportPillar(level, box, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, this.boundingBox.maxY());
this.placeSupportPillar(level, box, this.boundingBox.minX() + 1, this.boundingBox.minY(), this.boundingBox.maxZ() - 1, this.boundingBox.maxY());
this.placeSupportPillar(level, box, this.boundingBox.maxX() - 1, this.boundingBox.minY(), this.boundingBox.minZ() + 1, this.boundingBox.maxY());
this.placeSupportPillar(level, box, this.boundingBox.maxX() - 1, this.boundingBox.minY(), this.boundingBox.maxZ() - 1, this.boundingBox.maxY());
int i = this.boundingBox.minY() - 1;
for (int j = this.boundingBox.minX(); j <= this.boundingBox.maxX(); j++) {
for (int k = this.boundingBox.minZ(); k <= this.boundingBox.maxZ(); k++) {
this.setPlanksBlock(level, box, blockState, j, i, k);
}
}
}
}
private void placeSupportPillar(WorldGenLevel level, BoundingBox box, int x, int y, int z, int maxY) {
if (!this.getBlock(level, x, maxY + 1, z, box).isAir()) {
this.generateBox(level, box, x, y, z, x, maxY, z, this.type.getPlanksState(), CAVE_AIR, false);
}
}
}
abstract static class MineShaftPiece extends StructurePiece {
protected MineshaftStructure.Type type;
public MineShaftPiece(StructurePieceType structurePieceType, int genDepth, MineshaftStructure.Type type, BoundingBox boundingBox) {
super(structurePieceType, genDepth, boundingBox);
this.type = type;
}
public MineShaftPiece(StructurePieceType structurePieceType, CompoundTag compoundTag) {
super(structurePieceType, compoundTag);
this.type = MineshaftStructure.Type.byId(compoundTag.getIntOr("MST", 0));
}
@Override
protected boolean canBeReplaced(LevelReader level, int x, int y, int z, BoundingBox box) {
BlockState blockState = this.getBlock(level, x, y, z, box);
return !blockState.is(this.type.getPlanksState().getBlock())
&& !blockState.is(this.type.getWoodState().getBlock())
&& !blockState.is(this.type.getFenceState().getBlock())
&& !blockState.is(Blocks.CHAIN);
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
tag.putInt("MST", this.type.ordinal());
}
protected boolean isSupportingBox(BlockGetter level, BoundingBox box, int xStart, int xEnd, int y, int z) {
for (int i = xStart; i <= xEnd; i++) {
if (this.getBlock(level, i, y + 1, z, box).isAir()) {
return false;
}
}
return true;
}
protected boolean isInInvalidLocation(LevelAccessor level, BoundingBox boundingBox) {
int i = Math.max(this.boundingBox.minX() - 1, boundingBox.minX());
int j = Math.max(this.boundingBox.minY() - 1, boundingBox.minY());
int k = Math.max(this.boundingBox.minZ() - 1, boundingBox.minZ());
int l = Math.min(this.boundingBox.maxX() + 1, boundingBox.maxX());
int m = Math.min(this.boundingBox.maxY() + 1, boundingBox.maxY());
int n = Math.min(this.boundingBox.maxZ() + 1, boundingBox.maxZ());
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos((i + l) / 2, (j + m) / 2, (k + n) / 2);
if (level.getBiome(mutableBlockPos).is(BiomeTags.MINESHAFT_BLOCKING)) {
return true;
} else {
for (int o = i; o <= l; o++) {
for (int p = k; p <= n; p++) {
if (level.getBlockState(mutableBlockPos.set(o, j, p)).liquid()) {
return true;
}
if (level.getBlockState(mutableBlockPos.set(o, m, p)).liquid()) {
return true;
}
}
}
for (int o = i; o <= l; o++) {
for (int p = j; p <= m; p++) {
if (level.getBlockState(mutableBlockPos.set(o, p, k)).liquid()) {
return true;
}
if (level.getBlockState(mutableBlockPos.set(o, p, n)).liquid()) {
return true;
}
}
}
for (int o = k; o <= n; o++) {
for (int p = j; p <= m; p++) {
if (level.getBlockState(mutableBlockPos.set(i, p, o)).liquid()) {
return true;
}
if (level.getBlockState(mutableBlockPos.set(l, p, o)).liquid()) {
return true;
}
}
}
return false;
}
}
protected void setPlanksBlock(WorldGenLevel level, BoundingBox box, BlockState plankState, int x, int y, int z) {
if (this.isInterior(level, x, y, z, box)) {
BlockPos blockPos = this.getWorldPos(x, y, z);
BlockState blockState = level.getBlockState(blockPos);
if (!blockState.isFaceSturdy(level, blockPos, Direction.UP)) {
level.setBlock(blockPos, plankState, 2);
}
}
}
}
public static class MineShaftRoom extends MineshaftPieces.MineShaftPiece {
private final List<BoundingBox> childEntranceBoxes = Lists.<BoundingBox>newLinkedList();
public MineShaftRoom(int genDepth, RandomSource random, int x, int z, MineshaftStructure.Type type) {
super(
StructurePieceType.MINE_SHAFT_ROOM, genDepth, type, new BoundingBox(x, 50, z, x + 7 + random.nextInt(6), 54 + random.nextInt(6), z + 7 + random.nextInt(6))
);
this.type = type;
}
public MineShaftRoom(CompoundTag tag) {
super(StructurePieceType.MINE_SHAFT_ROOM, tag);
this.childEntranceBoxes.addAll((Collection)tag.read("Entrances", BoundingBox.CODEC.listOf()).orElse(List.of()));
}
@Override
public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) {
int i = this.getGenDepth();
int j = this.boundingBox.getYSpan() - 3 - 1;
if (j <= 0) {
j = 1;
}
int k = 0;
while (k < this.boundingBox.getXSpan()) {
k += random.nextInt(this.boundingBox.getXSpan());
if (k + 3 > this.boundingBox.getXSpan()) {
break;
}
MineshaftPieces.MineShaftPiece mineShaftPiece = MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + k, this.boundingBox.minY() + random.nextInt(j) + 1, this.boundingBox.minZ() - 1, Direction.NORTH, i
);
if (mineShaftPiece != null) {
BoundingBox boundingBox = mineShaftPiece.getBoundingBox();
this.childEntranceBoxes
.add(
new BoundingBox(boundingBox.minX(), boundingBox.minY(), this.boundingBox.minZ(), boundingBox.maxX(), boundingBox.maxY(), this.boundingBox.minZ() + 1)
);
}
k += 4;
}
k = 0;
while (k < this.boundingBox.getXSpan()) {
k += random.nextInt(this.boundingBox.getXSpan());
if (k + 3 > this.boundingBox.getXSpan()) {
break;
}
MineshaftPieces.MineShaftPiece mineShaftPiece = MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() + k, this.boundingBox.minY() + random.nextInt(j) + 1, this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
if (mineShaftPiece != null) {
BoundingBox boundingBox = mineShaftPiece.getBoundingBox();
this.childEntranceBoxes
.add(
new BoundingBox(boundingBox.minX(), boundingBox.minY(), this.boundingBox.maxZ() - 1, boundingBox.maxX(), boundingBox.maxY(), this.boundingBox.maxZ())
);
}
k += 4;
}
k = 0;
while (k < this.boundingBox.getZSpan()) {
k += random.nextInt(this.boundingBox.getZSpan());
if (k + 3 > this.boundingBox.getZSpan()) {
break;
}
MineshaftPieces.MineShaftPiece mineShaftPiece = MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY() + random.nextInt(j) + 1, this.boundingBox.minZ() + k, Direction.WEST, i
);
if (mineShaftPiece != null) {
BoundingBox boundingBox = mineShaftPiece.getBoundingBox();
this.childEntranceBoxes
.add(
new BoundingBox(this.boundingBox.minX(), boundingBox.minY(), boundingBox.minZ(), this.boundingBox.minX() + 1, boundingBox.maxY(), boundingBox.maxZ())
);
}
k += 4;
}
k = 0;
while (k < this.boundingBox.getZSpan()) {
k += random.nextInt(this.boundingBox.getZSpan());
if (k + 3 > this.boundingBox.getZSpan()) {
break;
}
StructurePiece structurePiece = MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY() + random.nextInt(j) + 1, this.boundingBox.minZ() + k, Direction.EAST, i
);
if (structurePiece != null) {
BoundingBox boundingBox = structurePiece.getBoundingBox();
this.childEntranceBoxes
.add(
new BoundingBox(this.boundingBox.maxX() - 1, boundingBox.minY(), boundingBox.minZ(), this.boundingBox.maxX(), boundingBox.maxY(), boundingBox.maxZ())
);
}
k += 4;
}
}
@Override
public void postProcess(
WorldGenLevel level, StructureManager structureManager, ChunkGenerator generator, RandomSource random, BoundingBox box, ChunkPos chunkPos, BlockPos pos
) {
if (!this.isInInvalidLocation(level, box)) {
this.generateBox(
level,
box,
this.boundingBox.minX(),
this.boundingBox.minY() + 1,
this.boundingBox.minZ(),
this.boundingBox.maxX(),
Math.min(this.boundingBox.minY() + 3, this.boundingBox.maxY()),
this.boundingBox.maxZ(),
CAVE_AIR,
CAVE_AIR,
false
);
for (BoundingBox boundingBox : this.childEntranceBoxes) {
this.generateBox(
level,
box,
boundingBox.minX(),
boundingBox.maxY() - 2,
boundingBox.minZ(),
boundingBox.maxX(),
boundingBox.maxY(),
boundingBox.maxZ(),
CAVE_AIR,
CAVE_AIR,
false
);
}
this.generateUpperHalfSphere(
level,
box,
this.boundingBox.minX(),
this.boundingBox.minY() + 4,
this.boundingBox.minZ(),
this.boundingBox.maxX(),
this.boundingBox.maxY(),
this.boundingBox.maxZ(),
CAVE_AIR,
false
);
}
}
@Override
public void move(int x, int y, int z) {
super.move(x, y, z);
for (BoundingBox boundingBox : this.childEntranceBoxes) {
boundingBox.move(x, y, z);
}
}
@Override
protected void addAdditionalSaveData(StructurePieceSerializationContext context, CompoundTag tag) {
super.addAdditionalSaveData(context, tag);
tag.store("Entrances", BoundingBox.CODEC.listOf(), this.childEntranceBoxes);
}
}
public static class MineShaftStairs extends MineshaftPieces.MineShaftPiece {
public MineShaftStairs(int genDepth, BoundingBox boundingBox, Direction orientation, MineshaftStructure.Type type) {
super(StructurePieceType.MINE_SHAFT_STAIRS, genDepth, type, boundingBox);
this.setOrientation(orientation);
}
public MineShaftStairs(CompoundTag tag) {
super(StructurePieceType.MINE_SHAFT_STAIRS, tag);
}
@Nullable
public static BoundingBox findStairs(StructurePieceAccessor pieces, RandomSource random, int x, int y, int z, Direction direction) {
BoundingBox boundingBox = switch (direction) {
default -> new BoundingBox(0, -5, -8, 2, 2, 0);
case SOUTH -> new BoundingBox(0, -5, 0, 2, 2, 8);
case WEST -> new BoundingBox(-8, -5, 0, 0, 2, 2);
case EAST -> new BoundingBox(0, -5, 0, 8, 2, 2);
};
boundingBox.move(x, y, z);
return pieces.findCollisionPiece(boundingBox) != null ? null : boundingBox;
}
@Override
public void addChildren(StructurePiece piece, StructurePieceAccessor pieces, RandomSource random) {
int i = this.getGenDepth();
Direction direction = this.getOrientation();
if (direction != null) {
switch (direction) {
case NORTH:
default:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY(), this.boundingBox.minZ() - 1, Direction.NORTH, i
);
break;
case SOUTH:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX(), this.boundingBox.minY(), this.boundingBox.maxZ() + 1, Direction.SOUTH, i
);
break;
case WEST:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.minX() - 1, this.boundingBox.minY(), this.boundingBox.minZ(), Direction.WEST, i
);
break;
case EAST:
MineshaftPieces.generateAndAddPiece(
piece, pieces, random, this.boundingBox.maxX() + 1, this.boundingBox.minY(), this.boundingBox.minZ(), Direction.EAST, i
);
}
}
}
@Override
public void postProcess(
WorldGenLevel level, StructureManager structureManager, ChunkGenerator generator, RandomSource random, BoundingBox box, ChunkPos chunkPos, BlockPos pos
) {
if (!this.isInInvalidLocation(level, box)) {
this.generateBox(level, box, 0, 5, 0, 2, 7, 1, CAVE_AIR, CAVE_AIR, false);
this.generateBox(level, box, 0, 0, 7, 2, 2, 8, CAVE_AIR, CAVE_AIR, false);
for (int i = 0; i < 5; i++) {
this.generateBox(level, box, 0, 5 - i - (i < 4 ? 1 : 0), 2 + i, 2, 7 - i, 2 + i, CAVE_AIR, CAVE_AIR, false);
}
}
}
}
}