Polish Gothic hall with lanterns, landscaping and checked edits

This commit is contained in:
Emil
2026-09-12 23:45:14 +03:00
parent 54af124a6d
commit f50fce2e55
13 changed files with 662 additions and 4 deletions
@@ -0,0 +1,120 @@
"""Add the architecture polish layer to the finished v1 scene, without I/O.
The input is scene.Voxels after the eighteen finishing corrections. V1 modules
remain immutable; removed blocks disappear from this sparse voxel composition.
"""
def build(v):
"""Restore the roof silhouette and add restrained Gothic stone/iron detail."""
stone = "minecraft:stone_bricks"
trim = "minecraft:polished_andesite"
dark = "minecraft:deepslate_tiles"
glass = "minecraft:gray_stained_glass"
wall = ("minecraft:stone_brick_wall[east=none,north=none,south=none,"
"up=true,waterlogged=false,west=none]")
def stair(material, facing, half="bottom"):
return (f"minecraft:{material}_stairs[facing={facing},half={half},"
"shape=straight,waterlogged=false]")
def bars(north=False, south=False, east=False, west=False):
flags = {"east": east, "north": north, "south": south, "west": west}
return "minecraft:iron_bars[" + ",".join(
f"{name}={str(value).lower()}" for name, value in flags.items()
) + ",waterlogged=false]"
def roof_height(x):
return 43 - (abs(x - 19) * 16 + 13) // 14
# Use the actual input mask so a material replacement cannot fill an opening.
# Preserve the six pale blocks of the heraldic cross on the north facade.
crest = {(19, y, 10) for y in range(23, 27)} | {
(x, 25, 10) for x in range(18, 21)
}
timber = {
p: block for p, block in v.blocks.items()
if 9 <= p[0] <= 29 and 28 <= p[1] <= 40 and 15 <= p[2] <= 54
and (block.startswith("minecraft:dark_oak_log[")
or block == "minecraft:dark_oak_planks")
}
for p, block in tuple(v.blocks.items()):
if block == "minecraft:polished_diorite" and p not in crest:
v.set(*p, trim)
elif block == "minecraft:tinted_glass":
v.set(*p, glass)
elif (block == "minecraft:cut_sandstone"
and 39 <= p[0] <= 41 and 34 <= p[1] <= 37 and 48 <= p[2] <= 50):
v.set(*p, "minecraft:gold_block")
# Remove only the ten old dormer envelopes, then reconstruct the same
# two-cell roof section. These envelopes exclude both gables and all trusses.
for z in (18, 26, 34, 42, 50):
for x1, x2 in ((10, 14), (24, 28)):
v.clear(x1, 32, z - 2, x2, 40, z + 2)
for x in range(x1, x2 + 1):
high = roof_height(x)
for y in (high - 1, high):
if 32 <= y <= 40:
block = dark if y < high else stair(
"deepslate_tile", "east" if x < 19 else "west")
v.box(x, y, z - 2, x, y, z + 2, block)
# Three narrow, low dormers per slope: a one-by-two recessed light, three
# blocks of facade width, and a short roof merging into the original slope.
for z in (22, 34, 46):
for face, inner, back in ((10, 11, 13), (28, 27, 25)):
x1, x2 = sorted((face, back))
near = back - 1 if face < back else back + 1
v.clear(min(face, near), 33, z, max(face, near), 34, z)
for dz in (-1, 1):
v.box(x1, 32, z + dz, x2, 34, z + dz, dark)
facing = "south" if dz < 0 else "north"
v.box(x1, 35, z + dz, x2, 35, z + dz,
stair("deepslate_tile", facing))
v.box(face, 33, z + dz, face, 34, z + dz, trim)
v.set(face, 35, z + dz, stair("stone_brick", facing))
v.box(x1, 36, z, x2, 36, z, dark)
v.box(face, 32, z - 1, face, 32, z + 1, trim)
v.box(inner, 33, z, inner, 34, z, glass)
v.set(face, 35, z, stone)
v.set(face, 36, z, wall)
# The old bright, chunky ridge is now a dark backing for one thin iron rail.
v.box(19, 43, 14, 19, 43, 55, dark)
for z in range(14, 56):
v.set(19, 44, z, bars(north=z > 14, south=z < 55))
# Replace full-block mullions with slender rods in their original glazing
# plane. Connected horizontal bars provide a clear transom without a grille.
for center in (18, 26, 34, 42, 50):
for inner, outside in ((8, 6), (30, 32)):
for y in range(10, 21):
v.set(inner, y, center, bars())
for dz in range(-2, 3):
v.set(inner, 15, center + dz,
bars(north=dz > -2, south=dz < 2))
# A bevel on the underside of each stepped arch reduces square caps.
for dz, top in ((-2, 19), (-1, 21), (1, 21), (2, 19)):
v.set(outside, top + 1, center + dz,
stair("stone_brick", "north" if dz < 0 else "south", "top"))
for x in (18, 20):
for y in range(29, 37):
v.set(x, y, 14, bars())
for x in range(16, 23):
v.set(x, 33, 14, bars(east=x < 22, west=x > 16))
# Taper the tips, retaining the full support blocks installed by finish v1.
for x in (6, 32):
for z in (14, 22, 30, 38, 46, 54):
v.box(x, 32, z, x, 33, z, wall)
for x in (7, 31):
v.box(x, 36, 12, x, 37, 12, wall)
for x in (35, 45):
for z in (43, 55):
v.box(x, 49, z, x, 50, z, wall)
# Two new dormer centers cross truss planes. Keep every original timber
# voxel, including the inclined members, instead of cutting a frame for glass.
for p, block in timber.items():
v.set(*p, block)
+159
View File
@@ -0,0 +1,159 @@
"""Reference-driven finishing layer; the original scene and its ledgers stay immutable."""
from .scene import build_scene as original_scene
from .polish_architecture import build as architecture
STONE = 'minecraft:stone_bricks'
TRIM = 'minecraft:polished_andesite'
LEAVES = 'minecraft:oak_leaves[distance=7,persistent=true,waterlogged=false]'
CHAIN = 'minecraft:iron_chain[axis=y,waterlogged=false]'
SLAB = 'minecraft:stone_brick_slab[type=bottom,waterlogged=false]'
def stair(facing, half='top'):
return f'minecraft:stone_brick_stairs[facing={facing},half={half},shape=straight,waterlogged=false]'
def bars(north=False, east=False, south=False, west=False):
return ('minecraft:iron_bars[' + ','.join(f'{key}={str(value).lower()}' for key, value in
[('north', north), ('east', east), ('south', south), ('west', west)]) + ',waterlogged=false]')
def finished_scene():
v = original_scene()
for x in (6, 32):
for z in (14, 22, 30, 38, 46, 54):
v.set(x, 30, z, STONE)
for x in (7, 31):
v.set(x, 34, 12, STONE)
for z in range(36, 40):
v.set(35, 8, z, stair('east', 'bottom'))
return v
def lamp(v, x, y, z, hanging=True):
v.set(x, y, z, f'minecraft:lantern[hanging={str(hanging).lower()},waterlogged=false]')
def lighting(v):
v.stage = 'lanterns and interior lighting'
# Portal fixtures attach to the existing masonry jambs.
for x in (13, 25):
v.set(x, 14, 9, stair('south'))
v.set(x, 13, 9, CHAIN)
lamp(v, x, 12, 9)
for x, facing, bays in ((4, 'east', (14, 22, 30, 38, 46, 54)),
(34, 'west', (14, 22, 30))):
for z in bays:
v.set(x, 16, z, stair(facing))
v.set(x, 15, z, CHAIN)
lamp(v, x, 14, z)
for x in (43, 52):
v.set(x, 8, 14, stair('south'))
v.set(x, 7, 14, CHAIN)
lamp(v, x, 6, 14)
for z in (21, 29, 37):
v.set(59, 14, z, TRIM)
v.set(60, 14, z, stair('west'))
v.set(60, 13, z, CHAIN)
lamp(v, 60, 12, z)
# Existing low piers become courtyard lamps, with a full supporting cap.
for x in (8, 30, 35, 61):
for z in (6, 59):
v.set(x, 4, z, TRIM)
lamp(v, x, 5, z, False)
# Three chandeliers hang in the clear nave, below the preserved timber ties.
for z in (22, 38, 46):
v.box(19, 19, z, 19, 27, z, CHAIN)
for dx in range(-2, 3):
v.set(19 + dx, 18, z, bars(dx == 0, dx < 2, dx == 0, dx > -2))
for dz in (-2, -1, 1, 2):
v.set(19, 18, z + dz, bars(dz > -2, False, dz < 2, False))
for x, zz in ((17, z), (21, z), (19, z - 2), (19, z + 2)):
lamp(v, x, 17, zz)
for x, facing in ((13, 'west'), (25, 'east')):
for z in (22, 38, 46):
v.set(x, 12, z, stair(facing))
v.set(x, 11, z, CHAIN)
lamp(v, x, 10, z)
# Wing ground floor: lights hang from the existing floor beams.
for x in (43, 50):
for z in (23, 31):
v.set(x, 6, z, CHAIN)
lamp(v, x, 5, z)
for z in (23, 35):
v.box(38, 17, z, 57, 17, z, 'minecraft:spruce_log[axis=x]')
v.box(47, 14, z, 47, 16, z, CHAIN)
lamp(v, 47, 13, z)
# Tower landings and the block-built bell receive a restrained warm light.
for y in (7, 16, 25):
v.box(40, y + 1, 46, 40, y + 2, 46, CHAIN)
lamp(v, 40, y, 46)
for x in (37, 43):
v.box(x, 39, 49, x, 40, 49, CHAIN)
lamp(v, x, 38, 49)
def landscape(v):
v.stage = 'planted stone terrace'
def bed(x1, z1, x2, z2, high=3):
# Soil replaces only the known terrace surface, with a low dressed rim.
for x in range(x1, x2 + 1):
for z in range(z1, z2 + 1):
edge = x in (x1, x2) or z in (z1, z2)
if edge:
if (x, 1, z) not in v.blocks:
v.set(x, 1, z, SLAB)
else:
v.set(x, 0, z, 'minecraft:dirt')
height = high - int((x * 7 + z * 11) % 5 == 0)
for y in range(1, height + 1):
if (x, y, z) not in v.blocks:
v.set(x, y, z, LEAVES)
for z in (18, 26, 34, 42, 50):
bed(1, z - 2, 5, z + 2, 2)
for z in (21, 29, 37):
bed(60, z - 2, 64, z + 2, 2)
bed(5, 9, 12, 11, 2)
bed(26, 9, 32, 11, 2)
bed(39, 11, 43, 13, 2)
bed(52, 11, 56, 13, 2)
bed(9, 59, 28, 61, 2)
bed(48, 45, 59, 47, 2)
def narrow_tree(x, z, height):
# Persistent leaves cannot decay; every addition respects existing masonry.
if (x, 0, z) not in v.blocks or v.blocks[(x, 0, z)].split('[')[0] in (
'minecraft:smooth_stone', 'minecraft:polished_andesite', 'minecraft:stone_bricks'):
v.set(x, 0, z, 'minecraft:moss_block')
for y in range(1, height - 1):
if (x, y, z) not in v.blocks or v.blocks[(x, y, z)] == LEAVES:
v.set(x, y, z, 'minecraft:spruce_log[axis=y]')
for y in range(2, height + 1):
radius = 2 if y <= height - 4 else 1 if y <= height - 1 else 0
for dx in range(-radius, radius + 1):
for dz in range(-radius, radius + 1):
if abs(dx) + abs(dz) > radius + 1:
continue
p = x + dx, y, z + dz
if p not in v.blocks or v.blocks[p] == LEAVES:
v.set(*p, LEAVES)
for x, z, h in ((10, 9, 8), (28, 9, 8), (62, 16, 7), (62, 44, 7),
(6, 60, 8), (32, 60, 7)):
narrow_tree(x, z, h)
# Slight wear follows the edges, leaving the main approach calm and readable.
for (x, y, z), block in list(v.blocks.items()):
if y == 0 and block == 'minecraft:smooth_stone' and (x < 6 or x > 59 or z > 57):
if (x * 31 + z * 17) % 29 == 0:
v.set(x, y, z, 'minecraft:andesite')
if y in (1, 2, 3) and block == STONE and (x < 8 or x > 56) and (x * 13 + y * 7 + z * 19) % 31 == 0:
v.set(x, y, z, 'minecraft:mossy_stone_bricks')
def build_scene():
v = finished_scene()
architecture(v)
lighting(v)
landscape(v)
return v