Files
Emil 89c53d7058 Expand material support and checkpoint the completed building toolkit
Expose the runtime block/item registry through compact material search and
single-material descriptions. Preserve private block-entity data through
checked edits and durable undo without sending payloads to model context.

Include the completed terrain tools, isolated world/map plugin, station lift,
ACP streaming and guidance fixes, local camera auto-connect, construction
scripts, and their public documentation, references and verification records.
Active station decoration and private runtime data remain outside this commit.

Validation: 145 Maven tests, 47 Bridge tests, successful camera Gradle build,
and isolated Paper verification of all 1,196 block defaults plus 5,392
independent property cases for placement, same-material edits and restoration.
2026-09-13 16:59:13 +03:00

390 lines
22 KiB
Python

#!/usr/bin/env python3
"""Read-only candidate/live station block, public-floor and containment QA.
Recipes use the checked layout contract {version:1,scope,blocks:[x,y,z,block,
expected]}. Metadata declares public_floors, air-only clear_regions and optional
containment bounds/seeds/authorized_caps. Flooding treats partial/unknown shapes
as passable, so a successful result does not rely on decorative collision shapes.
"""
import argparse
from collections import Counter, deque
import hashlib
import importlib.util
import json
import math
from pathlib import Path
import unittest
ROOT = Path(__file__).resolve().parents[1]
SPEC = importlib.util.spec_from_file_location('station_base', ROOT / 'scripts/verify-balustrade.py')
base = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(base)
survey, plaza = base.survey, base.plaza
FULL = plaza.STATIC_CUBES | {'barrier'}
N2 = ((1, 0), (-1, 0), (0, 1), (0, -1))
N3 = ((1, 0, 0), (-1, 0, 0), (0, 1, 0), (0, -1, 0), (0, 0, 1), (0, 0, -1))
def full_cube(state):
return plaza.parse(state)[0] in FULL
def bounded_box(document):
box = survey.box_of(document['min'], document['max'])
if survey.volume(box) > survey.MAX_VOXELS:
raise ValueError('Verification box exceeds the snapshot voxel limit')
return box
def positions(box):
return ((x, y, z) for x in range(box['min']['x'], box['max']['x'] + 1)
for y in range(box['min']['y'], box['max']['y'] + 1)
for z in range(box['min']['z'], box['max']['z'] + 1))
def inside(at, box):
return all(box['min'][axis] <= value <= box['max'][axis]
for axis, value in zip(('x', 'y', 'z'), at))
def surface_shape(state):
if full_cube(state):
return [(0., 1.)]
name, props = plaza.parse(state)
if name in {'smooth_sandstone_slab', 'cut_sandstone_slab', 'waxed_oxidized_cut_copper_slab'}:
if props.get('waterlogged') != 'false':
return None
return {'bottom': [(0., .5)], 'top': [(.5, 1.)], 'double': [(0., 1.)]}.get(props.get('type'))
return survey.vertical_shape(state)
def public_floors(reader, floors):
reports = []
for floor in floors:
name, feet, raw = floor['id'], floor['standing_y'], floor['clear_columns']
if feet not in (99, 113):
raise ValueError('This station stage declares public feet at Y99 or Y113')
if (not isinstance(raw, list) or not raw or any(not isinstance(p, list) or len(p) != 2
or any(type(v) is not int for v in p) for p in raw)):
raise ValueError('Each public floor requires integer clear_columns [x,z]')
clear = set(map(tuple, raw))
if len(clear) != len(raw):
raise ValueError('Duplicate public floor column')
source = floor['source']['x'], floor['source']['z']
if source not in clear:
raise ValueError('Floor source is not a declared clear column')
height = floor.get('min_headroom', 4)
if type(height) not in (int, float) or not math.isfinite(height) or height < 1.8:
raise ValueError('Headroom must be finite and at least 1.8 blocks')
failures, valid = [], set()
for x, z in sorted(clear):
support = surface_shape(reader.state(x, feet - 1, z))
reason = None
if support is None or not any(abs(high - 1.) < 1e-8 for low, high in support):
reason = 'missing_or_unknown_support_at_public_feet'
else:
for y in range(feet, math.ceil(feet + height)):
shape = surface_shape(reader.state(x, y, z))
if shape is None:
reason = 'unknown_shape_in_required_clearance'
break
if any(y + lo < feet + height and y + hi > feet for lo, hi in shape):
reason = 'occupied_required_clearance'
break
if reason:
failures.append({'x': x, 'z': z, 'standing_y': feet, 'reason': reason})
else:
valid.add((x, z))
reached, queue = set(), deque([source])
while queue:
p = queue.popleft()
if p in reached or p not in valid:
continue
reached.add(p)
queue.extend((p[0] + dx, p[1] + dz) for dx, dz in N2)
unreachable = sorted(clear - reached)
reports.append({'id': name, 'standing_y': feet, 'required_headroom': height,
'declared_columns': len(clear), 'physically_clear_columns': len(valid),
'reachable_clear_columns': len(reached), 'failed_samples': len(failures),
'sample_failure_examples': failures[:30], 'unreachable_columns': len(unreachable),
'unreachable_examples': unreachable[:30], 'passed': not failures and not unreachable})
return {'status': 'checked' if reports else 'not_provided', 'passed': bool(reports) and all(r['passed'] for r in reports),
'floors': reports, 'method': 'Observed center supports and declared vertical headroom, then cardinal traversal across valid level-floor columns. No lift transitions are inferred.'}
def clear_regions(reader, regions):
reports = []
for region in regions:
box, failures, checked = bounded_box(region), [], 0
for at in positions(box):
checked += 1
state = reader.state(*at)
if state not in survey.AIR:
failures.append({'at': list(at), 'actual': state})
reports.append({'id': region['id'], 'bounds': box, 'checked_voxels': checked,
'nonair_voxels': len(failures), 'examples': failures[:30], 'passed': not failures})
return {'status': 'checked' if reports else 'not_provided', 'passed': bool(reports) and all(r['passed'] for r in reports),
'regions': reports, 'method': 'Every declared doorway/cabin/aisle clearance voxel must be observed air.'}
def named_access(reader, metadata):
"""Ensure furnishing targets are not silently filtered out of public topology."""
interior = metadata.get('interior')
if interior is None:
return {'status': 'not_provided', 'passed': True}
failures, targets_by_floor, lift_reports = [], {}, []
floors = {f['standing_y']: set(map(tuple, f['clear_columns'])) for f in metadata['public_floors']}
for raw_feet, navigation in interior['navigation'].items():
feet = int(raw_feet)
targets = navigation['named_targets']
targets_by_floor[raw_feet] = len(targets)
if feet not in floors or not targets:
failures.append({'reason': 'missing_floor_or_named_targets', 'standing_y': feet})
for target in targets:
x, z = target['x'], target['z']
if target['y'] != feet or (x, z) not in floors.get(feet, set()):
failures.append({'reason': 'named_target_missing_from_public_topology', 'target': target})
if not full_cube(reader.state(x, feet - 1, z)) or any(
reader.state(x, y, z) not in survey.AIR for y in range(feet, feet + 4)):
failures.append({'reason': 'named_target_missing_full_support_or_four_air', 'target': target})
for level, lift in interior['lift'].items():
selector = tuple(lift['selector_block'])
landing = tuple(lift['landing_block'])
selector_state = reader.state(*selector)
x, feet, z = landing
passed = selector_state == 'minecraft:gold_block' and full_cube(reader.state(x, feet - 1, z)) and all(
reader.state(x, y, z) in survey.AIR for y in range(feet, feet + 4))
lift_reports.append({'floor': level, 'selector': selector, 'observed_selector': selector_state,
'landing': landing, 'passed': passed})
if not passed:
failures.append({'reason': 'lift_selector_or_landing_obstructed', 'floor': level})
return {'status': 'checked', 'passed': not failures, 'named_targets_per_floor': targets_by_floor,
'lift_landings': lift_reports, 'failures': failures,
'method': 'Named furnishing targets must remain in the independently verified public-floor topology with full support and four air blocks. Gold selector and landing voxels are checked; runtime lift operation is not inferred.'}
def fixture_stability(reader, desired):
fixtures = {p: s for p, s in desired.items() if plaza.parse(s)[0] in {'lantern', 'spruce_leaves'}}
report = plaza.check_fixtures(reader, fixtures, {'fixtures': []})
report['checked'].pop('root_connected_logs', None)
logs = {p: s for p, s in desired.items() if plaza.parse(s)[0] == 'spruce_log'}
roots = [p for p in logs if (p[0], p[1] - 1, p[2]) not in logs]
for x, y, z in roots:
below = reader.state(x, y - 1, z)
if plaza.parse(below)[0] not in {'dirt', 'moss_block'}:
report['failures'].append({'reason': 'station_topiary_or_diorama_root_without_soil',
'at': [x, y, z], 'below': below})
report['checked'].update({'spruce_logs': len(logs), 'topiary_or_diorama_roots': len(roots)})
report['passed'] = not report['failures']
report['status'] = 'checked'
report['method'] = 'Planned lantern support, persistent leaf distances against the full observed neighborhood, and station topiary/diorama roots on stable dirt or moss.'
return report
def conservative_containment(reader, metadata):
if metadata is None:
return {'status': 'not_proven', 'passed': False, 'reason': 'No containment bounds, seeds and authorized entrance caps were supplied.'}
box = bounded_box(metadata['bounds'])
caps, cap_reports = set(), []
for region in metadata.get('authorized_caps', []):
cap_box = bounded_box(region)
points = set(positions(cap_box))
if not points or not all(inside(p, box) for p in points):
raise ValueError('Authorized virtual cap lies outside surveyed containment bounds')
caps |= points
cap_reports.append({'id': region['id'], 'bounds': cap_box, 'voxels': len(points)})
blocked, passable, unknown = set(), set(), Counter()
for at in positions(box):
state = reader.state(*at)
if full_cube(state) or at in caps:
blocked.add(at)
else:
passable.add(at)
if state not in survey.AIR:
unknown[plaza.parse(state)[0]] += 1
regions = [(r['id'], bounded_box(r)) for r in metadata.get('forbidden_regions', [])]
roof_y = metadata.get('forbidden_y_at_or_above', 126)
if type(roof_y) is not int:
raise ValueError('Forbidden roof threshold must be an integer Y')
seeds = metadata.get('seeds')
if not isinstance(seeds, list) or not seeds:
raise ValueError('Containment requires explicit public aisle/cabin seeds')
reports = []
for seed in seeds:
coordinates = [seed[axis] for axis in ('x', 'y', 'z')]
if any(type(v) not in (int, float) or not math.isfinite(v) for v in coordinates):
raise ValueError('Seed coordinates must be finite')
source = tuple(math.floor(v) for v in coordinates)
if not inside(source, box) or source in caps:
raise ValueError('Containment source is outside its observed box or inside a virtual cap')
low, high = seed.get('min_y'), seed.get('max_y')
if any(v is not None and type(v) is not int for v in (low, high)):
raise ValueError('Per-floor minimum/maximum reachable Y must be integers')
reached, queue, violations, examples = set(), deque([source]), Counter(), []
while queue:
p = queue.popleft()
if p in reached or p not in passable:
continue
reached.add(p)
reasons = []
if any(value in (box['min'][axis], box['max'][axis]) for axis, value in zip(('x', 'y', 'z'), p)):
reasons.append('survey_boundary_reachable')
if p[1] >= roof_y:
reasons.append('roof_space_reachable')
if low is not None and p[1] < low:
reasons.append('below_public_floor_reachable')
if high is not None and p[1] > high:
reasons.append('above_public_room_reachable')
reasons.extend('forbidden_region:' + name for name, bounds in regions if inside(p, bounds))
for reason in reasons:
violations[reason] += 1
if len(examples) < 30:
examples.append({'at': list(p), 'reason': reason})
queue.extend((p[0] + dx, p[1] + dy, p[2] + dz) for dx, dy, dz in N3)
source_air = reader.state(*source) in survey.AIR
reports.append({'id': seed['id'], 'source': list(source), 'source_observed_air': source_air,
'reachable_voxels': len(reached), 'minimum_reached_y': min((p[1] for p in reached), default=None),
'maximum_reached_y': max((p[1] for p in reached), default=None),
'violation_counts': dict(violations), 'examples': examples,
'passed': source_air and bool(reached) and not violations})
return {'status': 'checked', 'passed': all(r['passed'] for r in reports), 'bounds': box,
'observed_voxels': len(blocked) + len(passable), 'authorized_virtual_caps': cap_reports,
'partial_or_unknown_materials_treated_as_passable': dict(unknown), 'seeds': reports,
'method': 'Independent 6-neighbor floods from each public room/cabin seed. Known full cubes including glass block movement; partial/unknown shapes are treated as empty. Authorized entrance caps are virtual audit boundaries only.',
'limits': 'This overestimates continuous player movement and does not simulate teleportation, spectator, block removal or lift operation. Failed floods through partial shapes require review; they are not automatically proven playable escape paths.'}
def audit(before, recipe, metadata, after=None):
scope = survey.scope_of(recipe['scope'])
if scope != before.scope or scope != metadata['scope'] or (after and after.scope != scope):
raise ValueError('Recipe, metadata and snapshots differ in project/world/epoch')
desired = base.coordinates(recipe)
for row in recipe['blocks']:
at = tuple(row[axis] for axis in ('x', 'y', 'z'))
if before.state(*at) != row['expected']:
raise ValueError(f'Recipe expected state differs from observed baseline at {at}')
reader = plaza.Reader(after or before, None if after else desired)
floor_report = public_floors(reader, metadata.get('public_floors', []))
clearance = clear_regions(reader, metadata.get('clear_regions', []))
access = named_access(reader, metadata)
fixtures = fixture_stability(reader, desired)
containment = conservative_containment(reader, metadata.get('containment'))
volume = base.compare_volume(before, after, desired) if after else None
unproven = []
if floor_report['status'] == 'not_provided':
unproven.append('Public floor support/headroom/reachability: no clear-column topology supplied.')
if clearance['status'] == 'not_provided':
unproven.append('Doorway and lift cabin clearances: no explicit clearance regions supplied.')
if containment['status'] == 'not_proven':
unproven.append('Windows, floor separation and roof/private-space containment: no flood contract supplied.')
provided = [r for r in (floor_report, clearance, access, fixtures, containment) if r['status'] == 'checked']
supported_passed = all(r['passed'] for r in provided) and (volume is None or volume['passed'])
return {'version': 1, 'scope': scope, 'world_edits': 0,
'mode': 'actual_after_snapshot' if after else 'candidate_overlay', 'desired_blocks': len(desired),
'expected_states_verified_against_baseline': len(desired), 'public_floors': floor_report,
'clear_regions': clearance, 'named_access': access, 'fixtures': fixtures,
'containment': containment, 'volume': volume,
'supported_checks_passed': supported_passed, 'unproven_checks': unproven,
'passed': supported_passed and not unproven,
'limits': 'Only observed block states are verified. Block entity text, display entities, gameplay/sign destinations and operational lift transitions require separate runtime checks. Actual snapshots are sequential, not atomic.'}
class FakeReader:
def __init__(self, states):
self.states = states
def state(self, x, y, z):
return self.states.get((x, y, z), 'minecraft:air')
class StationTests(unittest.TestCase):
def room(self):
box = {'min': {'x': -1, 'y': 98, 'z': -1}, 'max': {'x': 5, 'y': 127, 'z': 5}}
states = {(x, y, z): 'minecraft:glass' for x in range(5) for y in range(99, 104) for z in range(5)
if x in (0, 4) or z in (0, 4) or y in (99, 103)}
meta = {'bounds': box, 'seeds': [{'id': 'room', 'x': 2, 'y': 100, 'z': 2, 'min_y': 100, 'max_y': 102}]}
return FakeReader(states), meta
def test_closed_glass_room_is_contained_and_window_hole_is_detected(self):
reader, metadata = self.room()
self.assertTrue(conservative_containment(reader, metadata)['passed'])
del reader.states[0, 101, 2]
result = conservative_containment(reader, metadata)
self.assertFalse(result['passed'])
self.assertIn('survey_boundary_reachable', result['seeds'][0]['violation_counts'])
def test_authorized_entrance_can_be_virtually_capped_without_changing_world(self):
reader, metadata = self.room()
del reader.states[0, 101, 2]
metadata['authorized_caps'] = [{'id': 'entry', 'min': {'x': 0, 'y': 101, 'z': 2}, 'max': {'x': 0, 'y': 101, 'z': 2}}]
self.assertTrue(conservative_containment(reader, metadata)['passed'])
self.assertEqual(reader.state(0, 101, 2), 'minecraft:air')
def test_partial_window_is_treated_as_open_and_upper_floor_hole_is_detected(self):
reader, metadata = self.room()
reader.states[0, 101, 2] = 'minecraft:iron_bars[east=false,north=true,south=true,waterlogged=false,west=false]'
self.assertFalse(conservative_containment(reader, metadata)['passed'])
reader, metadata = self.room()
del reader.states[2, 99, 2]
result = conservative_containment(reader, metadata)
self.assertIn('below_public_floor_reachable', result['seeds'][0]['violation_counts'])
def test_public_headroom_is_four_blocks_and_obstacle_disconnects_floor(self):
reader = FakeReader({(x, 98, 0): 'minecraft:stone' for x in range(3)})
floor = {'id': 'vestibule', 'standing_y': 99, 'source': {'x': 0, 'z': 0}, 'clear_columns': [[0, 0], [1, 0], [2, 0]]}
self.assertTrue(public_floors(reader, [floor])['passed'])
reader.states[1, 102, 0] = 'minecraft:lantern[hanging=true,waterlogged=false]'
result = public_floors(reader, [floor])
self.assertFalse(result['passed'])
self.assertEqual(result['floors'][0]['unreachable_columns'], 2)
def test_clearance_region_reports_real_door_obstruction(self):
reader = FakeReader({(0, 99, 0): 'minecraft:stone'})
region = {'id': 'door', 'min': {'x': 0, 'y': 99, 'z': 0}, 'max': {'x': 0, 'y': 102, 'z': 0}}
self.assertEqual(clear_regions(reader, [region])['regions'][0]['nonair_voxels'], 1)
def test_named_target_cannot_be_hidden_by_filtering_the_public_mask(self):
reader = FakeReader({(x, 98, 0): 'minecraft:stone' for x in range(2)})
metadata = {'public_floors': [{'standing_y': 99, 'clear_columns': [[0, 0]]}],
'interior': {'navigation': {'99': {'named_targets': [
{'name': 'bench-front', 'x': 1, 'y': 99, 'z': 0}]}}, 'lift': {}}}
self.assertFalse(named_access(reader, metadata)['passed'])
metadata['public_floors'][0]['clear_columns'].append([1, 0])
self.assertTrue(named_access(reader, metadata)['passed'])
def test_fixture_leaf_distance_and_lantern_support_use_actual_states(self):
desired = {(0, 100, 0): 'minecraft:lantern[hanging=true,waterlogged=false]',
(2, 100, 0): 'minecraft:spruce_leaves[distance=1,persistent=true,waterlogged=false]'}
reader = FakeReader(desired | {(0, 101, 0): 'minecraft:stone',
(2, 99, 0): 'minecraft:spruce_log[axis=y]'})
self.assertTrue(fixture_stability(reader, desired)['passed'])
del reader.states[0, 101, 0]
del reader.states[2, 99, 0]
self.assertEqual(len(fixture_stability(reader, desired)['failures']), 2)
def main():
parser = argparse.ArgumentParser(description=__doc__)
for name in ('before', 'after', 'recipe', 'metadata', 'report'):
parser.add_argument('--' + name, type=Path)
parser.add_argument('--self-test', action='store_true')
args = parser.parse_args()
if args.self_test:
result = unittest.TextTestRunner().run(unittest.defaultTestLoader.loadTestsFromTestCase(StationTests))
raise SystemExit(0 if result.wasSuccessful() else 1)
if any(getattr(args, name) is None for name in ('before', 'recipe', 'metadata', 'report')):
parser.error('--before, --recipe, --metadata and --report are required')
before = survey.load_snapshot(args.before)
after = survey.load_snapshot(args.after, before.scope) if args.after else None
report = audit(before, json.loads(args.recipe.read_text()), json.loads(args.metadata.read_text()), after)
paths = {name: getattr(args, name) for name in ('before', 'after', 'recipe', 'metadata') if getattr(args, name)}
report['input_sha256'] = {key: hashlib.sha256(path.read_bytes()).hexdigest() for key, path in paths.items()}
args.report.parent.mkdir(parents=True, exist_ok=True)
survey.terrain.save(args.report, report)
print(json.dumps(report, indent=2))
raise SystemExit(0 if report['passed'] else 2 if report['supported_checks_passed'] and report['unproven_checks'] else 1)
if __name__ == '__main__':
main()