fix(camping): half-slab hammock geometry + smarter tent grounding
All checks were successful
Deploy Addons / deploy (push) Successful in 15s

- Hammock now uses a custom geometry.silverlabs.hammock_slab (8-voxel
  tall half-slab instead of a full cube), matching its thin collision
  box so the block reads visually as a hammock cradle, not a brick.

- Tent placement now projects the player's feet down to the nearest
  solid block (up to 3 blocks) before picking the base Y, so mid-jump
  fractional positions or standing-on-slab cases don't mis-place the
  footprint one block too high.

- Failure messages now include the exact failing cell coordinates and
  the block type that's in the way, so we can diagnose live pitch
  attempts without guesswork.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-24 15:08:34 +01:00
parent 5c1af25468
commit 7e3432d868
3 changed files with 60 additions and 12 deletions

View File

@@ -26,7 +26,7 @@
"origin": [-8, 0, -8], "origin": [-8, 0, -8],
"size": [16, 4, 16] "size": [16, 4, 16]
}, },
"minecraft:geometry": "minecraft:geometry.full_block", "minecraft:geometry": "geometry.silverlabs.hammock_slab",
"minecraft:light_dampening": 0 "minecraft:light_dampening": 0
} }
} }

View File

@@ -96,14 +96,26 @@ function tryPlaceTent(player) {
const dim = player.dimension; const dim = player.dimension;
const facing = cardinalFacing(player.getRotation().y); const facing = cardinalFacing(player.getRotation().y);
const { fx, fz, rx, rz } = vecsForFacing(facing); const { fx, fz, rx, rz } = vecsForFacing(facing);
const feet = { // Use precise player position; floor X/Z but scan Y downward to find the actual
x: Math.floor(player.location.x), // standing surface. player.location.y may be fractionally above the block you're
y: Math.floor(player.location.y), // on (e.g. 87.01), so floor() alone is reliable, but if the player is in the
z: Math.floor(player.location.z), // air (jumping / on a slab / flying) we want to project them down to solid ground
}; // so the tent doesn't try to sit on empty space.
const ox = feet.x + fx; const feetX = Math.floor(player.location.x);
const oy = feet.y; const feetZ = Math.floor(player.location.z);
const oz = feet.z + fz; let feetY = Math.floor(player.location.y);
// If the block at feet level is air (player's mid-jump or location rounded up),
// scan downward up to 3 blocks to find the ground.
for (let probe = 0; probe < 4; probe++) {
const here = dim.getBlock({ x: feetX, y: feetY - 1, z: feetZ });
if (here && here.isSolid) break;
const onSolid = dim.getBlock({ x: feetX, y: feetY, z: feetZ });
if (onSolid && onSolid.isSolid) { feetY += 1; break; }
feetY -= 1;
}
const ox = feetX + fx;
const oy = feetY;
const oz = feetZ + fz;
const groundCells = []; const groundCells = [];
const clearCells = []; const clearCells = [];
@@ -119,18 +131,19 @@ function tryPlaceTent(player) {
for (const g of groundCells) { for (const g of groundCells) {
const b = dim.getBlock(g); const b = dim.getBlock(g);
if (!b || !b.isSolid) { if (!b || !b.isSolid) {
player.sendMessage("§c[Camping] §7Need a flat 2×3 patch of solid ground in front of you."); const seen = b ? b.typeId : "unloaded";
player.sendMessage(`§c[Camping] §7Ground at §f${g.x},${g.y},${g.z}§7 is §f${seen}§7 — need solid ground there.`);
return false; return false;
} }
} }
for (const c of clearCells) { for (const c of clearCells) {
const b = dim.getBlock(c); const b = dim.getBlock(c);
if (!b) { if (!b) {
player.sendMessage("§c[Camping] §7Can't reach that area (chunk unloaded)."); player.sendMessage(`§c[Camping] §7Can't reach §f${c.x},${c.y},${c.z}§7 (chunk unloaded).`);
return false; return false;
} }
if (!b.isAir && !b.isLiquid) { if (!b.isAir && !b.isLiquid) {
player.sendMessage("§c[Camping] §7The space above the tent footprint isn't clear."); player.sendMessage(`§c[Camping] §7Space at §f${c.x},${c.y},${c.z}§7 is blocked by §f${b.typeId}§7.`);
return false; return false;
} }
} }

View File

@@ -0,0 +1,35 @@
{
"format_version": "1.21.0",
"minecraft:geometry": [
{
"description": {
"identifier": "geometry.silverlabs.hammock_slab",
"texture_width": 16,
"texture_height": 16,
"visible_bounds_width": 2,
"visible_bounds_height": 1,
"visible_bounds_offset": [0, 0.25, 0]
},
"bones": [
{
"name": "root",
"pivot": [0, 0, 0],
"cubes": [
{
"origin": [-8, 0, -8],
"size": [16, 4, 16],
"uv": {
"north": { "uv": [0, 12], "uv_size": [16, 4] },
"south": { "uv": [0, 12], "uv_size": [16, 4] },
"east": { "uv": [0, 12], "uv_size": [16, 4] },
"west": { "uv": [0, 12], "uv_size": [16, 4] },
"up": { "uv": [0, 0], "uv_size": [16, 16] },
"down": { "uv": [0, 0], "uv_size": [16, 16] }
}
}
]
}
]
}
]
}