Strip all Phase references, TODO/FUTURE roadmap notes, and internal planning comments from the codebase. Run Prettier for consistent formatting across all Java files.
1369 lines
48 KiB
Java
1369 lines
48 KiB
Java
package com.tiedup.remake.worldgen;
|
|
|
|
import javax.annotation.Nullable;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.util.RandomSource;
|
|
import net.minecraft.world.level.WorldGenLevel;
|
|
import net.minecraft.world.level.block.Blocks;
|
|
import net.minecraft.world.level.block.LanternBlock;
|
|
import net.minecraft.world.level.block.state.BlockState;
|
|
import net.minecraft.world.level.block.state.properties.BlockStateProperties;
|
|
import net.minecraft.world.level.levelgen.structure.BoundingBox;
|
|
|
|
enum RoomTheme {
|
|
OUBLIETTE {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
if (
|
|
ry == 1 && r.nextFloat() < 0.30f
|
|
) return Blocks.MOSSY_COBBLESTONE.defaultBlockState();
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.CRACKED_DEEPSLATE_BRICKS.defaultBlockState()
|
|
: Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
boolean isCorner = (rx == 1 || rx == 11) && (rz == 1 || rz == 11);
|
|
if (isCorner) return Blocks.MOSSY_COBBLESTONE.defaultBlockState();
|
|
return r.nextFloat() < 0.15f
|
|
? Blocks.COBBLESTONE.defaultBlockState()
|
|
: Blocks.DEEPSLATE_TILES.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.CRACKED_DEEPSLATE_BRICKS.defaultBlockState()
|
|
: Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
int[][] corners = layout.innerCorners();
|
|
// Cobwebs at corners (low + high)
|
|
for (int[] c : corners) {
|
|
if (
|
|
layout.isInShape(c[0], c[1]) && !layout.isWall(c[0], c[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 1, baseZ + c[1]),
|
|
Blocks.COBWEB.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 9, baseZ + c[1]),
|
|
Blocks.COBWEB.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Water cauldron near first corner
|
|
int cx = corners[0][0] + 1,
|
|
cz = corners[0][1] + 1;
|
|
if (layout.isInShape(cx, cz) && !layout.isWall(cx, cz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + cx, floorY + 1, baseZ + cz),
|
|
Blocks.WATER_CAULDRON.defaultBlockState().setValue(
|
|
BlockStateProperties.LEVEL_CAULDRON,
|
|
3
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
// Soul lanterns on wall midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.SOUL_LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Corner furniture: barrel + brewing_stand + chain
|
|
int[] fc = corners[1];
|
|
int fcx = fc[0] + (fc[0] < 6 ? 1 : -1);
|
|
int fcz = fc[1] + (fc[1] < 6 ? 1 : -1);
|
|
if (layout.isInShape(fcx, fcz) && !layout.isWall(fcx, fcz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + fcx, floorY + 1, baseZ + fcz),
|
|
Blocks.BARREL.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
int fcx2 = fcx + (fcx < 6 ? 1 : -1);
|
|
if (layout.isInShape(fcx2, fcz) && !layout.isWall(fcx2, fcz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + fcx2, floorY + 1, baseZ + fcz),
|
|
Blocks.BREWING_STAND.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
// Chain above barrel
|
|
for (int cy = 8; cy <= 10; cy++) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + fcx, floorY + cy, baseZ + fcz),
|
|
Blocks.CHAIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Side chains
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
// Hanging lanterns
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (
|
|
ry == 1 || ry == 10
|
|
) return Blocks.POLISHED_DEEPSLATE.defaultBlockState();
|
|
return Blocks.DEEPSLATE_BRICK_WALL.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.40f) return Blocks.COBWEB.defaultBlockState();
|
|
if (f < 0.70f) return Blocks.CANDLE.defaultBlockState()
|
|
.setValue(BlockStateProperties.CANDLES, 1 + r.nextInt(3))
|
|
.setValue(BlockStateProperties.LIT, true);
|
|
return Blocks.MOSS_CARPET.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.POLISHED_DEEPSLATE.defaultBlockState();
|
|
}
|
|
},
|
|
INFERNO {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.CRACKED_NETHER_BRICKS.defaultBlockState()
|
|
: Blocks.NETHER_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
if (isEdge) return Blocks.MAGMA_BLOCK.defaultBlockState();
|
|
return r.nextFloat() < 0.08f
|
|
? Blocks.GILDED_BLACKSTONE.defaultBlockState()
|
|
: Blocks.BLACKSTONE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.CRACKED_NETHER_BRICKS.defaultBlockState()
|
|
: Blocks.NETHER_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.NETHER_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
int[][] corners = layout.innerCorners();
|
|
// Soul fire at corners: soul_sand at ry=0, soul_fire at ry=1
|
|
for (int[] c : corners) {
|
|
if (
|
|
layout.isInShape(c[0], c[1]) && !layout.isWall(c[0], c[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY, baseZ + c[1]),
|
|
Blocks.SOUL_SAND.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 1, baseZ + c[1]),
|
|
Blocks.SOUL_FIRE.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Crying obsidian accents at wall midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 2,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.CRYING_OBSIDIAN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Soul lanterns on wall midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.SOUL_LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Corner furniture: soul_campfire + cauldron(lava) + gilded_blackstone
|
|
int[][] icorners = layout.innerCorners();
|
|
int[] ifc = icorners[1];
|
|
int ifcx = ifc[0] + (ifc[0] < 6 ? 1 : -1);
|
|
int ifcz = ifc[1] + (ifc[1] < 6 ? 1 : -1);
|
|
if (layout.isInShape(ifcx, ifcz) && !layout.isWall(ifcx, ifcz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ifcx, floorY + 1, baseZ + ifcz),
|
|
Blocks.SOUL_CAMPFIRE.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
int ifcx2 = ifcx + (ifcx < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(ifcx2, ifcz) && !layout.isWall(ifcx2, ifcz)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ifcx2, floorY + 1, baseZ + ifcz),
|
|
Blocks.LAVA_CAULDRON.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
if (
|
|
layout.isInShape(ifcx, ifcz + (ifcz < 6 ? 1 : -1)) &&
|
|
!layout.isWall(ifcx, ifcz + (ifcz < 6 ? 1 : -1))
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + ifcx,
|
|
floorY + 1,
|
|
baseZ + ifcz + (ifcz < 6 ? 1 : -1)
|
|
),
|
|
Blocks.GILDED_BLACKSTONE.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Side chains
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
// Hanging lanterns
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (
|
|
ry == 1 || ry == 10
|
|
) return Blocks.QUARTZ_PILLAR.defaultBlockState();
|
|
return Blocks.NETHER_BRICK_WALL.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.40f) return Blocks.SOUL_SAND.defaultBlockState();
|
|
if (f < 0.70f) return Blocks.NETHER_WART_BLOCK.defaultBlockState();
|
|
return Blocks.BONE_BLOCK.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.RED_NETHER_BRICKS.defaultBlockState();
|
|
}
|
|
},
|
|
CRYPT {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
float f = r.nextFloat();
|
|
if (
|
|
ry == 1 && f < 0.20f
|
|
) return Blocks.MOSSY_COBBLESTONE.defaultBlockState();
|
|
if (f < 0.15f) return Blocks.MOSSY_STONE_BRICKS.defaultBlockState();
|
|
if (
|
|
f < 0.30f
|
|
) return Blocks.CRACKED_STONE_BRICKS.defaultBlockState();
|
|
return Blocks.STONE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
boolean isCorner = (rx == 1 || rx == 11) && (rz == 1 || rz == 11);
|
|
if (isCorner) return Blocks.MOSSY_COBBLESTONE.defaultBlockState();
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.COBBLESTONE.defaultBlockState()
|
|
: Blocks.STONE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.CRACKED_STONE_BRICKS.defaultBlockState()
|
|
: Blocks.STONE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.STONE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
int[][] corners = layout.innerCorners();
|
|
// Cobwebs at corners (low + high)
|
|
for (int[] c : corners) {
|
|
if (
|
|
layout.isInShape(c[0], c[1]) && !layout.isWall(c[0], c[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 1, baseZ + c[1]),
|
|
Blocks.COBWEB.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 9, baseZ + c[1]),
|
|
Blocks.COBWEB.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Wall torches at midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 0 },
|
|
{ 6, 12 },
|
|
{ 0, 6 },
|
|
{ 12, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
Direction torchDir = getTorchDirection(
|
|
wallPos[0],
|
|
wallPos[1]
|
|
);
|
|
if (torchDir != null) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.WALL_TORCH.defaultBlockState().setValue(
|
|
net.minecraft.world.level.block.WallTorchBlock.FACING,
|
|
torchDir
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
// Skull in first corner
|
|
int[] sc = corners[0];
|
|
if (
|
|
layout.isInShape(sc[0], sc[1]) && !layout.isWall(sc[0], sc[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + sc[0], floorY + 1, baseZ + sc[1]),
|
|
Blocks.SKELETON_SKULL.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
// Corner furniture: lectern + candles on floor
|
|
int[] cfc = corners[1];
|
|
int cfcx = cfc[0] + (cfc[0] < 6 ? 1 : -1);
|
|
int cfcz = cfc[1] + (cfc[1] < 6 ? 1 : -1);
|
|
if (layout.isInShape(cfcx, cfcz) && !layout.isWall(cfcx, cfcz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + cfcx, floorY + 1, baseZ + cfcz),
|
|
Blocks.LECTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
int cfcx2 = cfcx + (cfcx < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(cfcx2, cfcz) && !layout.isWall(cfcx2, cfcz)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + cfcx2, floorY + 1, baseZ + cfcz),
|
|
Blocks.CANDLE.defaultBlockState()
|
|
.setValue(BlockStateProperties.CANDLES, 4)
|
|
.setValue(BlockStateProperties.LIT, true),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (
|
|
ry == 1 || ry == 10
|
|
) return Blocks.CHISELED_STONE_BRICKS.defaultBlockState();
|
|
return Blocks.STONE_BRICK_WALL.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.40f) return Blocks.COBWEB.defaultBlockState();
|
|
if (f < 0.70f) return Blocks.CANDLE.defaultBlockState()
|
|
.setValue(BlockStateProperties.CANDLES, 1 + r.nextInt(3))
|
|
.setValue(BlockStateProperties.LIT, true);
|
|
return Blocks.BONE_BLOCK.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.MOSSY_STONE_BRICKS.defaultBlockState();
|
|
}
|
|
},
|
|
ICE {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.10f) return Blocks.ICE.defaultBlockState();
|
|
if (f < 0.30f) return Blocks.BLUE_ICE.defaultBlockState();
|
|
return Blocks.PACKED_ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
if (isEdge) return Blocks.BLUE_ICE.defaultBlockState();
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.SNOW_BLOCK.defaultBlockState()
|
|
: Blocks.PACKED_ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.BLUE_ICE.defaultBlockState()
|
|
: Blocks.PACKED_ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.PACKED_ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
int[][] corners = layout.innerCorners();
|
|
// Snow layers in corners
|
|
for (int[] c : corners) {
|
|
if (
|
|
layout.isInShape(c[0], c[1]) && !layout.isWall(c[0], c[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + c[0], floorY + 1, baseZ + c[1]),
|
|
Blocks.SNOW.defaultBlockState().setValue(
|
|
net.minecraft.world.level.block.SnowLayerBlock.LAYERS,
|
|
2 + random.nextInt(3)
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Lanterns on wall midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Ice stalactites near ceiling corners
|
|
for (int[] c : corners) {
|
|
int cx = c[0],
|
|
cz = c[1];
|
|
if (layout.isInShape(cx, cz) && !layout.isWall(cx, cz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + cx, floorY + 10, baseZ + cz),
|
|
Blocks.ICE.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Corner furniture: cauldron(powder_snow) + blue_ice seat + lantern
|
|
int[] ifc2 = corners[1];
|
|
int ifc2x = ifc2[0] + (ifc2[0] < 6 ? 1 : -1);
|
|
int ifc2z = ifc2[1] + (ifc2[1] < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(ifc2x, ifc2z) && !layout.isWall(ifc2x, ifc2z)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ifc2x, floorY + 1, baseZ + ifc2z),
|
|
Blocks.POWDER_SNOW_CAULDRON.defaultBlockState().setValue(
|
|
BlockStateProperties.LEVEL_CAULDRON,
|
|
3
|
|
),
|
|
chunkBB
|
|
);
|
|
int ifc2x2 = ifc2x + (ifc2x < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(ifc2x2, ifc2z) &&
|
|
!layout.isWall(ifc2x2, ifc2z)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ifc2x2, floorY + 1, baseZ + ifc2z),
|
|
Blocks.BLUE_ICE.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
if (
|
|
layout.isInShape(ifc2x, ifc2z + (ifc2z < 6 ? 1 : -1)) &&
|
|
!layout.isWall(ifc2x, ifc2z + (ifc2z < 6 ? 1 : -1))
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + ifc2x,
|
|
floorY + 2,
|
|
baseZ + ifc2z + (ifc2z < 6 ? 1 : -1)
|
|
),
|
|
Blocks.LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (ry == 1 || ry == 10) return Blocks.BLUE_ICE.defaultBlockState();
|
|
return r.nextFloat() < 0.5f
|
|
? Blocks.PACKED_ICE.defaultBlockState()
|
|
: Blocks.BLUE_ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.50f) return Blocks.SNOW.defaultBlockState().setValue(
|
|
net.minecraft.world.level.block.SnowLayerBlock.LAYERS,
|
|
1 + r.nextInt(2)
|
|
);
|
|
if (f < 0.70f) return Blocks.POWDER_SNOW.defaultBlockState();
|
|
return Blocks.ICE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.BLUE_ICE.defaultBlockState();
|
|
}
|
|
},
|
|
SCULK {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
float f = r.nextFloat();
|
|
if (
|
|
f < 0.10f
|
|
) return Blocks.CRACKED_DEEPSLATE_BRICKS.defaultBlockState();
|
|
if (f < 0.40f) return Blocks.SCULK.defaultBlockState();
|
|
return Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
if (isEdge) return Blocks.SCULK.defaultBlockState();
|
|
return r.nextFloat() < 0.30f
|
|
? Blocks.SCULK.defaultBlockState()
|
|
: Blocks.DEEPSLATE_TILES.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (
|
|
f < 0.10f
|
|
) return Blocks.CRACKED_DEEPSLATE_BRICKS.defaultBlockState();
|
|
if (f < 0.30f) return Blocks.SCULK.defaultBlockState();
|
|
return Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.DEEPSLATE_BRICKS.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
// Sculk veins on wall midpoints at ry=2
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 2,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.SCULK_VEIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Soul lanterns on wall midpoints at ry=3
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.SOUL_LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Sculk catalyst in first corner
|
|
int[][] corners = layout.innerCorners();
|
|
int[] sc = corners[0];
|
|
if (
|
|
layout.isInShape(sc[0], sc[1]) && !layout.isWall(sc[0], sc[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + sc[0], floorY + 1, baseZ + sc[1]),
|
|
Blocks.SCULK_CATALYST.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
// Corner furniture: sculk_shrieker + sculk_sensor + candle
|
|
int[][] scorners = layout.innerCorners();
|
|
int[] sfc = scorners[1];
|
|
int sfcx = sfc[0] + (sfc[0] < 6 ? 1 : -1);
|
|
int sfcz = sfc[1] + (sfc[1] < 6 ? 1 : -1);
|
|
if (layout.isInShape(sfcx, sfcz) && !layout.isWall(sfcx, sfcz)) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + sfcx, floorY + 1, baseZ + sfcz),
|
|
Blocks.SCULK_SHRIEKER.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
int sfcx2 = sfcx + (sfcx < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(sfcx2, sfcz) && !layout.isWall(sfcx2, sfcz)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + sfcx2, floorY + 1, baseZ + sfcz),
|
|
Blocks.SCULK_SENSOR.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
if (
|
|
layout.isInShape(sfcx, sfcz + (sfcz < 6 ? 1 : -1)) &&
|
|
!layout.isWall(sfcx, sfcz + (sfcz < 6 ? 1 : -1))
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + sfcx,
|
|
floorY + 1,
|
|
baseZ + sfcz + (sfcz < 6 ? 1 : -1)
|
|
),
|
|
Blocks.CANDLE.defaultBlockState()
|
|
.setValue(BlockStateProperties.CANDLES, 3)
|
|
.setValue(BlockStateProperties.LIT, true),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (ry == 1 || ry == 10) return Blocks.SCULK.defaultBlockState();
|
|
return r.nextFloat() < 0.3f
|
|
? Blocks.SCULK.defaultBlockState()
|
|
: Blocks.DEEPSLATE_TILE_WALL.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.50f) return Blocks.SCULK.defaultBlockState();
|
|
if (f < 0.80f) return Blocks.SCULK_VEIN.defaultBlockState();
|
|
return Blocks.MOSS_CARPET.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.SCULK_CATALYST.defaultBlockState();
|
|
}
|
|
},
|
|
SANDSTONE {
|
|
@Override
|
|
public BlockState wallBlock(RandomSource r, int ry) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.10f) return Blocks.CHISELED_SANDSTONE.defaultBlockState();
|
|
if (f < 0.30f) return Blocks.SANDSTONE.defaultBlockState();
|
|
return Blocks.CUT_SANDSTONE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
) {
|
|
return r.nextFloat() < 0.15f
|
|
? Blocks.SAND.defaultBlockState()
|
|
: Blocks.SMOOTH_SANDSTONE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState ceilingBlock(RandomSource r) {
|
|
return r.nextFloat() < 0.20f
|
|
? Blocks.SANDSTONE.defaultBlockState()
|
|
: Blocks.CUT_SANDSTONE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallShellBlock() {
|
|
return Blocks.CUT_SANDSTONE.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
public void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
// Wall torches at midpoints
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 0 },
|
|
{ 6, 12 },
|
|
{ 0, 6 },
|
|
{ 12, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
Direction torchDir = getTorchDirection(
|
|
wallPos[0],
|
|
wallPos[1]
|
|
);
|
|
if (torchDir != null) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 3,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.WALL_TORCH.defaultBlockState().setValue(
|
|
net.minecraft.world.level.block.WallTorchBlock.FACING,
|
|
torchDir
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
// Orange terracotta accents at wall midpoints ry=2
|
|
for (int[] wallPos : new int[][] {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
}) {
|
|
if (layout.isWall(wallPos[0], wallPos[1])) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + wallPos[0],
|
|
floorY + 2,
|
|
baseZ + wallPos[1]
|
|
),
|
|
Blocks.ORANGE_TERRACOTTA.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// TNT hidden in first corner
|
|
int[][] corners = layout.innerCorners();
|
|
int[] tc = corners[0];
|
|
if (
|
|
layout.isInShape(tc[0], tc[1]) && !layout.isWall(tc[0], tc[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + tc[0], floorY + 1, baseZ + tc[1]),
|
|
Blocks.TNT.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
// Corner furniture: barrel + flower_pot + orange_terracotta bench
|
|
int[] ssfc = corners[1];
|
|
int ssfcx = ssfc[0] + (ssfc[0] < 6 ? 1 : -1);
|
|
int ssfcz = ssfc[1] + (ssfc[1] < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(ssfcx, ssfcz) && !layout.isWall(ssfcx, ssfcz)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ssfcx, floorY + 1, baseZ + ssfcz),
|
|
Blocks.BARREL.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
int ssfcx2 = ssfcx + (ssfcx < 6 ? 1 : -1);
|
|
if (
|
|
layout.isInShape(ssfcx2, ssfcz) &&
|
|
!layout.isWall(ssfcx2, ssfcz)
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + ssfcx2, floorY + 1, baseZ + ssfcz),
|
|
Blocks.FLOWER_POT.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
if (
|
|
layout.isInShape(ssfcx, ssfcz + (ssfcz < 6 ? 1 : -1)) &&
|
|
!layout.isWall(ssfcx, ssfcz + (ssfcz < 6 ? 1 : -1))
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + ssfcx,
|
|
floorY + 1,
|
|
baseZ + ssfcz + (ssfcz < 6 ? 1 : -1)
|
|
),
|
|
Blocks.ORANGE_TERRACOTTA.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
placeSharedChains(level, baseX, baseZ, floorY, chunkBB);
|
|
placeSharedHangingLanterns(level, baseX, baseZ, floorY, chunkBB);
|
|
}
|
|
|
|
@Override
|
|
public BlockState pillarBlock(RandomSource r, int ry) {
|
|
if (
|
|
ry == 1 || ry == 10
|
|
) return Blocks.CHISELED_SANDSTONE.defaultBlockState();
|
|
return Blocks.SANDSTONE_WALL.defaultBlockState();
|
|
}
|
|
|
|
@Override
|
|
@Nullable
|
|
public BlockState scatterBlock(RandomSource r) {
|
|
float f = r.nextFloat();
|
|
if (f < 0.40f) return Blocks.SAND.defaultBlockState();
|
|
if (f < 0.70f) return Blocks.DEAD_BUSH.defaultBlockState();
|
|
return Blocks.CANDLE.defaultBlockState()
|
|
.setValue(BlockStateProperties.CANDLES, 1 + r.nextInt(3))
|
|
.setValue(BlockStateProperties.LIT, true);
|
|
}
|
|
|
|
@Override
|
|
public BlockState wallAccentBlock() {
|
|
return Blocks.CHISELED_SANDSTONE.defaultBlockState();
|
|
}
|
|
};
|
|
|
|
public abstract BlockState wallBlock(RandomSource r, int ry);
|
|
|
|
public abstract BlockState floorBlock(
|
|
RandomSource r,
|
|
int rx,
|
|
int rz,
|
|
boolean isEdge
|
|
);
|
|
|
|
public abstract BlockState ceilingBlock(RandomSource r);
|
|
|
|
/** Solid block used for wall positions on the floor layer. */
|
|
public abstract BlockState wallShellBlock();
|
|
|
|
public abstract void placeDecorations(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
);
|
|
|
|
/** Block used for pillars (may vary by height). */
|
|
public abstract BlockState pillarBlock(RandomSource r, int ry);
|
|
|
|
/** Random scatter block for floor decoration, or null to skip. */
|
|
@Nullable
|
|
public abstract BlockState scatterBlock(RandomSource r);
|
|
|
|
/** Accent block for decorative wall bands. */
|
|
public abstract BlockState wallAccentBlock();
|
|
|
|
// ── Shared structural features ──────────────────────────────────
|
|
|
|
/** Pillar positions -- verified to be inside all 4 layouts. */
|
|
private static final int[][] PILLAR_POSITIONS = {
|
|
{ 4, 4 },
|
|
{ 4, 8 },
|
|
{ 8, 4 },
|
|
{ 8, 8 },
|
|
};
|
|
|
|
/** Place 4 full-height pillars at verified positions. */
|
|
static void placeSharedPillars(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
RoomTheme theme,
|
|
BoundingBox chunkBB
|
|
) {
|
|
for (int[] p : PILLAR_POSITIONS) {
|
|
if (
|
|
!layout.isInShape(p[0], p[1]) || layout.isWall(p[0], p[1])
|
|
) continue;
|
|
for (int ry = 1; ry <= 10; ry++) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + p[0], floorY + ry, baseZ + p[1]),
|
|
theme.pillarBlock(random, ry),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Place random floor scatter (~12% of interior positions). */
|
|
static void placeSharedFloorScatter(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
RoomTheme theme,
|
|
BoundingBox chunkBB
|
|
) {
|
|
for (int rx = 1; rx <= 11; rx++) {
|
|
for (int rz = 1; rz <= 11; rz++) {
|
|
if (
|
|
!layout.isInShape(rx, rz) || layout.isWall(rx, rz)
|
|
) continue;
|
|
// Skip pillar positions
|
|
if ((rx == 4 || rx == 8) && (rz == 4 || rz == 8)) continue;
|
|
// Skip cage center area (5-7, 5-7)
|
|
if (rx >= 5 && rx <= 7 && rz >= 5 && rz <= 7) continue;
|
|
// Skip corner positions (used by decorations/chests)
|
|
if ((rx <= 2 || rx >= 10) && (rz <= 2 || rz >= 10)) continue;
|
|
if (random.nextFloat() < 0.12f) {
|
|
BlockState scatter = theme.scatterBlock(random);
|
|
if (scatter != null) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + rx, floorY + 1, baseZ + rz),
|
|
scatter,
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Place ceiling cobwebs and extra hanging chains. */
|
|
static void placeSharedCeilingDecor(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
// Cobwebs along walls at ceiling level
|
|
int[][] cobwebCandidates = {
|
|
{ 2, 1 },
|
|
{ 4, 1 },
|
|
{ 8, 1 },
|
|
{ 10, 1 },
|
|
{ 2, 11 },
|
|
{ 4, 11 },
|
|
{ 8, 11 },
|
|
{ 10, 11 },
|
|
{ 1, 4 },
|
|
{ 1, 8 },
|
|
{ 11, 4 },
|
|
{ 11, 8 },
|
|
};
|
|
for (int[] pos : cobwebCandidates) {
|
|
if (
|
|
layout.isInShape(pos[0], pos[1]) &&
|
|
!layout.isWall(pos[0], pos[1]) &&
|
|
random.nextFloat() < 0.45f
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 10, baseZ + pos[1]),
|
|
Blocks.COBWEB.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Extra hanging chains at random interior positions
|
|
int[][] chainCandidates = { { 5, 3 }, { 7, 9 }, { 3, 7 } };
|
|
for (int[] pos : chainCandidates) {
|
|
if (
|
|
layout.isInShape(pos[0], pos[1]) &&
|
|
!layout.isWall(pos[0], pos[1]) &&
|
|
random.nextFloat() < 0.6f
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 10, baseZ + pos[1]),
|
|
Blocks.CHAIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 9, baseZ + pos[1]),
|
|
Blocks.CHAIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Place additional wall-mounted lighting. */
|
|
static void placeSharedWallLighting(
|
|
WorldGenLevel level,
|
|
RandomSource random,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
BoundingBox chunkBB
|
|
) {
|
|
// Lanterns on pillar sides (facing center) at ry=1 (on the floor)
|
|
int[][] pillarLanternPositions = {
|
|
{ 5, 4 },
|
|
{ 4, 7 },
|
|
{ 8, 5 },
|
|
{ 7, 8 },
|
|
};
|
|
for (int[] pos : pillarLanternPositions) {
|
|
if (
|
|
layout.isInShape(pos[0], pos[1]) &&
|
|
!layout.isWall(pos[0], pos[1])
|
|
) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 1, baseZ + pos[1]),
|
|
Blocks.LANTERN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
// Extra wall sconces at quarter-points
|
|
int[][] wallSconces = {
|
|
{ 4, 0 },
|
|
{ 8, 0 },
|
|
{ 4, 12 },
|
|
{ 8, 12 },
|
|
{ 0, 4 },
|
|
{ 0, 8 },
|
|
{ 12, 4 },
|
|
{ 12, 8 },
|
|
};
|
|
for (int[] pos : wallSconces) {
|
|
if (layout.isWall(pos[0], pos[1]) && random.nextFloat() < 0.5f) {
|
|
Direction torchDir = getTorchDirection(pos[0], pos[1]);
|
|
if (torchDir != null) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + pos[0],
|
|
floorY + 3,
|
|
baseZ + pos[1]
|
|
),
|
|
Blocks.WALL_TORCH.defaultBlockState().setValue(
|
|
net.minecraft.world.level.block.WallTorchBlock.FACING,
|
|
torchDir
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Place wall accent bands at ry=5 and ry=8. */
|
|
static void placeSharedWallBands(
|
|
WorldGenLevel level,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
RoomLayout layout,
|
|
RoomTheme theme,
|
|
BoundingBox chunkBB
|
|
) {
|
|
int[][] bandPositions = {
|
|
{ 6, 1 },
|
|
{ 6, 11 },
|
|
{ 1, 6 },
|
|
{ 11, 6 },
|
|
{ 4, 1 },
|
|
{ 8, 1 },
|
|
{ 4, 11 },
|
|
{ 8, 11 },
|
|
{ 1, 4 },
|
|
{ 1, 8 },
|
|
{ 11, 4 },
|
|
{ 11, 8 },
|
|
};
|
|
for (int[] pos : bandPositions) {
|
|
if (layout.isWall(pos[0], pos[1])) {
|
|
// Band at ry=5
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 5, baseZ + pos[1]),
|
|
theme.wallAccentBlock(),
|
|
chunkBB
|
|
);
|
|
// Optional band at ry=8
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 8, baseZ + pos[1]),
|
|
theme.wallAccentBlock(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Chains on cage flanks and ceiling corners -- shared by all themes. */
|
|
static void placeSharedChains(
|
|
WorldGenLevel level,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
BoundingBox chunkBB
|
|
) {
|
|
for (int[] chainPos : new int[][] { { 3, 6 }, { 9, 6 } }) {
|
|
for (int ry = 5; ry <= 10; ry++) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + chainPos[0],
|
|
floorY + ry,
|
|
baseZ + chainPos[1]
|
|
),
|
|
Blocks.CHAIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
for (int[] chainPos : new int[][] {
|
|
{ 3, 3 },
|
|
{ 3, 9 },
|
|
{ 9, 3 },
|
|
{ 9, 9 },
|
|
}) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(
|
|
baseX + chainPos[0],
|
|
floorY + 10,
|
|
baseZ + chainPos[1]
|
|
),
|
|
Blocks.CHAIN.defaultBlockState(),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
|
|
/** Determine torch facing direction for a wall position (torch faces inward). */
|
|
static Direction getTorchDirection(int rx, int rz) {
|
|
if (rz == 0) return Direction.SOUTH;
|
|
if (rz == 12) return Direction.NORTH;
|
|
if (rx == 0) return Direction.EAST;
|
|
if (rx == 12) return Direction.WEST;
|
|
return null;
|
|
}
|
|
|
|
/** Hanging lanterns -- shared by all themes. */
|
|
static void placeSharedHangingLanterns(
|
|
WorldGenLevel level,
|
|
int baseX,
|
|
int baseZ,
|
|
int floorY,
|
|
BoundingBox chunkBB
|
|
) {
|
|
for (int[] pos : new int[][] { { 3, 3 }, { 9, 9 } }) {
|
|
HangingCagePiece.safeSetBlock(
|
|
level,
|
|
new BlockPos(baseX + pos[0], floorY + 9, baseZ + pos[1]),
|
|
Blocks.LANTERN.defaultBlockState().setValue(
|
|
LanternBlock.HANGING,
|
|
true
|
|
),
|
|
chunkBB
|
|
);
|
|
}
|
|
}
|
|
}
|