fix(UC-02): arch review — furniture x/z offsets + ceiling chain fidelity
- Add x_offset/z_offset to PositionedBlock for multi-block furniture clusters - Furniture items now spread across 2-3 positions (matching original Java code) - Offsets multiplied by inward direction for correct corner orientation - Fix has_ceiling_chain: only oubliette has ceiling chains (was true for all 6) - Fix firstCornerSpecial: oubliette cauldron uses x/z offset +1 (inward diagonal) - Update parser to read x_offset/z_offset (defaults to 0)
This commit is contained in:
@@ -27,10 +27,17 @@ public record DecorationConfig(
|
|||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A block state with an associated Y offset for positioned placement.
|
* A block state with positional offsets for placement.
|
||||||
*
|
*
|
||||||
* @param state the block state to place
|
* @param state the block state to place
|
||||||
|
* @param xOffset horizontal X offset from base position (0 = no offset)
|
||||||
* @param yOffset vertical offset from the base position
|
* @param yOffset vertical offset from the base position
|
||||||
|
* @param zOffset horizontal Z offset from base position (0 = no offset)
|
||||||
*/
|
*/
|
||||||
public record PositionedBlock(BlockState state, int yOffset) {}
|
public record PositionedBlock(BlockState state, int xOffset, int yOffset, int zOffset) {
|
||||||
|
/** Convenience constructor for Y-offset-only blocks (most common case). */
|
||||||
|
public PositionedBlock(BlockState state, int yOffset) {
|
||||||
|
this(state, 0, yOffset, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -660,24 +660,35 @@ public class HangingCagePiece extends StructurePiece {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// First corner special (e.g. water cauldron, skull, TNT, sculk catalyst)
|
// First corner special (e.g. water cauldron, skull, TNT, sculk catalyst)
|
||||||
|
// x/z offsets are multiplied by inward direction (toward room center)
|
||||||
if (deco.firstCornerSpecial() != null && corners.length > 0) {
|
if (deco.firstCornerSpecial() != null && corners.length > 0) {
|
||||||
int[] sc = corners[0];
|
int[] sc = corners[0];
|
||||||
if (layout.isInShape(sc[0], sc[1]) && !layout.isWall(sc[0], sc[1])) {
|
int dirX = sc[0] < 6 ? 1 : -1;
|
||||||
|
int dirZ = sc[1] < 6 ? 1 : -1;
|
||||||
|
int scx = sc[0] + deco.firstCornerSpecial().xOffset() * dirX;
|
||||||
|
int scz = sc[1] + deco.firstCornerSpecial().zOffset() * dirZ;
|
||||||
|
if (layout.isInShape(scx, scz) && !layout.isWall(scx, scz)) {
|
||||||
safeSetBlock(level,
|
safeSetBlock(level,
|
||||||
new BlockPos(baseX + sc[0], floorY + deco.firstCornerSpecial().yOffset(), baseZ + sc[1]),
|
new BlockPos(baseX + scx, floorY + deco.firstCornerSpecial().yOffset(), baseZ + scz),
|
||||||
deco.firstCornerSpecial().state(), chunkBB);
|
deco.firstCornerSpecial().state(), chunkBB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Furniture cluster at corners[1] (e.g. barrel+brewing_stand, soul_campfire+cauldron)
|
// Furniture cluster at corners[1] — each item has x/z offsets relative to the
|
||||||
|
// base furniture position. x_offset/z_offset values are multiplied by the
|
||||||
|
// inward direction (toward room center) to handle all 4 corner orientations.
|
||||||
if (corners.length > 1) {
|
if (corners.length > 1) {
|
||||||
int[] fc = corners[1];
|
int[] fc = corners[1];
|
||||||
int fcx = fc[0] + (fc[0] < 6 ? 1 : -1);
|
int dirX = fc[0] < 6 ? 1 : -1;
|
||||||
int fcz = fc[1] + (fc[1] < 6 ? 1 : -1);
|
int dirZ = fc[1] < 6 ? 1 : -1;
|
||||||
if (layout.isInShape(fcx, fcz) && !layout.isWall(fcx, fcz)) {
|
int fcx = fc[0] + dirX;
|
||||||
for (DecorationConfig.PositionedBlock pb : deco.furnitureCluster()) {
|
int fcz = fc[1] + dirZ;
|
||||||
|
for (DecorationConfig.PositionedBlock pb : deco.furnitureCluster()) {
|
||||||
|
int px = fcx + pb.xOffset() * dirX;
|
||||||
|
int pz = fcz + pb.zOffset() * dirZ;
|
||||||
|
if (layout.isInShape(px, pz) && !layout.isWall(px, pz)) {
|
||||||
safeSetBlock(level,
|
safeSetBlock(level,
|
||||||
new BlockPos(baseX + fcx, floorY + pb.yOffset(), baseZ + fcz),
|
new BlockPos(baseX + px, floorY + pb.yOffset(), baseZ + pz),
|
||||||
pb.state(), chunkBB);
|
pb.state(), chunkBB);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -433,7 +433,7 @@ public final class RoomThemeParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse a single positioned block: { "block": "...", "y_offset": 0 }
|
* Parse a single positioned block: { "block": "...", "x_offset": 0, "y_offset": 0, "z_offset": 0 }
|
||||||
*/
|
*/
|
||||||
@Nullable
|
@Nullable
|
||||||
private static DecorationConfig.PositionedBlock parsePositionedBlock(
|
private static DecorationConfig.PositionedBlock parsePositionedBlock(
|
||||||
@@ -445,8 +445,10 @@ public final class RoomThemeParser {
|
|||||||
BlockState state = parseBlockState(blockStr, fileId);
|
BlockState state = parseBlockState(blockStr, fileId);
|
||||||
if (state == null) return null;
|
if (state == null) return null;
|
||||||
|
|
||||||
|
int xOffset = getIntOrDefault(obj, "x_offset", 0);
|
||||||
int yOffset = getIntOrDefault(obj, "y_offset", 0);
|
int yOffset = getIntOrDefault(obj, "y_offset", 0);
|
||||||
return new DecorationConfig.PositionedBlock(state, yOffset);
|
int zOffset = getIntOrDefault(obj, "z_offset", 0);
|
||||||
|
return new DecorationConfig.PositionedBlock(state, xOffset, yOffset, zOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== Primitive Helpers =====
|
// ===== Primitive Helpers =====
|
||||||
|
|||||||
@@ -52,9 +52,9 @@
|
|||||||
"first_corner_special": { "block": "minecraft:skeleton_skull", "y_offset": 1 },
|
"first_corner_special": { "block": "minecraft:skeleton_skull", "y_offset": 1 },
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:lectern", "y_offset": 1 },
|
{ "block": "minecraft:lectern", "y_offset": 1 },
|
||||||
{ "block": "minecraft:candle[lit=true,candles=4]", "y_offset": 1 }
|
{ "block": "minecraft:candle[lit=true,candles=4]", "x_offset": 1, "y_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": true,
|
"use_torch_lighting": true,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,10 +50,10 @@
|
|||||||
],
|
],
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:powder_snow_cauldron[level=3]", "y_offset": 1 },
|
{ "block": "minecraft:powder_snow_cauldron[level=3]", "y_offset": 1 },
|
||||||
{ "block": "minecraft:blue_ice", "y_offset": 1 },
|
{ "block": "minecraft:blue_ice", "x_offset": 1, "y_offset": 1 },
|
||||||
{ "block": "minecraft:lantern", "y_offset": 2 }
|
{ "block": "minecraft:lantern", "y_offset": 2, "z_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": false,
|
"use_torch_lighting": false,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,10 @@
|
|||||||
],
|
],
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:soul_campfire", "y_offset": 1 },
|
{ "block": "minecraft:soul_campfire", "y_offset": 1 },
|
||||||
{ "block": "minecraft:lava_cauldron", "y_offset": 1 },
|
{ "block": "minecraft:lava_cauldron", "x_offset": 1, "y_offset": 1 },
|
||||||
{ "block": "minecraft:gilded_blackstone", "y_offset": 1 }
|
{ "block": "minecraft:gilded_blackstone", "y_offset": 1, "z_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": false,
|
"use_torch_lighting": false,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,10 +51,10 @@
|
|||||||
"wall_midpoint_blocks": [
|
"wall_midpoint_blocks": [
|
||||||
{ "block": "minecraft:soul_lantern", "y_offset": 3 }
|
{ "block": "minecraft:soul_lantern", "y_offset": 3 }
|
||||||
],
|
],
|
||||||
"first_corner_special": { "block": "minecraft:water_cauldron[level=3]", "y_offset": 1 },
|
"first_corner_special": { "block": "minecraft:water_cauldron[level=3]", "x_offset": 1, "y_offset": 1, "z_offset": 1 },
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:barrel", "y_offset": 1 },
|
{ "block": "minecraft:barrel", "y_offset": 1 },
|
||||||
{ "block": "minecraft:brewing_stand", "y_offset": 1 }
|
{ "block": "minecraft:brewing_stand", "x_offset": 1, "y_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": false,
|
"use_torch_lighting": false,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": true
|
||||||
|
|||||||
@@ -43,10 +43,10 @@
|
|||||||
"first_corner_special": { "block": "minecraft:tnt", "y_offset": 1 },
|
"first_corner_special": { "block": "minecraft:tnt", "y_offset": 1 },
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:barrel", "y_offset": 1 },
|
{ "block": "minecraft:barrel", "y_offset": 1 },
|
||||||
{ "block": "minecraft:flower_pot", "y_offset": 1 },
|
{ "block": "minecraft:flower_pot", "x_offset": 1, "y_offset": 1 },
|
||||||
{ "block": "minecraft:orange_terracotta", "y_offset": 1 }
|
{ "block": "minecraft:orange_terracotta", "y_offset": 1, "z_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": true,
|
"use_torch_lighting": true,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,10 @@
|
|||||||
"first_corner_special": { "block": "minecraft:sculk_catalyst", "y_offset": 1 },
|
"first_corner_special": { "block": "minecraft:sculk_catalyst", "y_offset": 1 },
|
||||||
"furniture_cluster": [
|
"furniture_cluster": [
|
||||||
{ "block": "minecraft:sculk_shrieker", "y_offset": 1 },
|
{ "block": "minecraft:sculk_shrieker", "y_offset": 1 },
|
||||||
{ "block": "minecraft:sculk_sensor", "y_offset": 1 },
|
{ "block": "minecraft:sculk_sensor", "x_offset": 1, "y_offset": 1 },
|
||||||
{ "block": "minecraft:candle[lit=true,candles=3]", "y_offset": 1 }
|
{ "block": "minecraft:candle[lit=true,candles=3]", "y_offset": 1, "z_offset": 1 }
|
||||||
],
|
],
|
||||||
"use_torch_lighting": false,
|
"use_torch_lighting": false,
|
||||||
"has_ceiling_chain": true
|
"has_ceiling_chain": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user