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.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Compare every live map column to the planned visible result and inspect hidden water."""
|
||||
import argparse
|
||||
from collections import defaultdict
|
||||
import importlib.util
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
|
||||
def main():
|
||||
p=argparse.ArgumentParser(description=__doc__)
|
||||
p.add_argument('--before',type=Path,required=True);p.add_argument('--after',type=Path,required=True)
|
||||
p.add_argument('--layout',type=Path,action='append',required=True);p.add_argument('--report',type=Path,required=True)
|
||||
args=p.parse_args();before=json.loads(args.before.read_text());after=json.loads(args.after.read_text())
|
||||
for key in ('world_uuid','min_x','max_x','min_z','max_z','width','length'):
|
||||
if before[key]!=after[key]:raise ValueError('Map scopes differ: '+key)
|
||||
w=before['width'];expected_y=before['surface_y'].copy()
|
||||
expected_m=[before['palette'][i] for i in before['material_index']]
|
||||
original_m=expected_m.copy();targets=set();planned_blocks=0
|
||||
for path in args.layout:
|
||||
layout=json.loads(path.read_text())
|
||||
if layout['scope']['world_id']!=before['world_uuid']:raise ValueError('Layout world differs')
|
||||
for b in sorted(layout['blocks'],key=lambda b:b['y']):
|
||||
i=(b['z']-before['min_z'])*w+b['x']-before['min_x'];targets.add((b['x'],b['y'],b['z']));planned_blocks+=1
|
||||
if b['y']>=expected_y[i]:expected_y[i]=b['y'];expected_m[i]=b['block']
|
||||
observed=[after['palette'][i] for i in after['material_index']]
|
||||
mismatches=[i for i in range(len(expected_y)) if expected_y[i]!=after['surface_y'][i] or expected_m[i]!=observed[i]]
|
||||
if mismatches:raise ValueError(f'{len(mismatches)} unexpected surface columns; first indices {mismatches[:8]}')
|
||||
hidden_water=defaultdict(list)
|
||||
for i,material in enumerate(original_m):
|
||||
if material=='minecraft:water' and observed[i]!='minecraft:water':
|
||||
x=i%w+before['min_x'];z=i//w+before['min_z'];y=before['surface_y'][i]
|
||||
hidden_water[(x//16,z//16,y)].append((x,y,z))
|
||||
spec=importlib.util.spec_from_file_location('terrain',ROOT/'scripts/terrain.py')
|
||||
terrain=importlib.util.module_from_spec(spec);spec.loader.exec_module(terrain)
|
||||
backend=terrain.Backend(ROOT/'.runtime/server/plugins/MinecraftBuilderMCP/config.yml')
|
||||
context=backend.call('project_context')
|
||||
if context['world_id']!=before['world_uuid']:raise ValueError('Live verification world differs')
|
||||
verified_water=0
|
||||
for points in hidden_water.values():
|
||||
lo={axis:min(point[j] for point in points) for j,axis in enumerate(('x','y','z'))}
|
||||
hi={axis:max(point[j] for point in points) for j,axis in enumerate(('x','y','z'))}
|
||||
read=backend.call('region_inspect',min=lo,max=hi,detail='blocks')
|
||||
states={tuple(b['pos'][axis] for axis in ('x','y','z')):b['state'] for b in read['blocks']}
|
||||
for point in points:
|
||||
if not states[point].startswith('minecraft:water['):raise ValueError('Water changed beneath a marker: '+str(point))
|
||||
verified_water+=1
|
||||
report={'world':before['world'],'source':'live Paper surface maps + bounded RPC water reads',
|
||||
'verified_surface_columns':len(expected_y),'surface_mismatches':0,
|
||||
'unique_marker_blocks':len(targets),'planned_writes':planned_blocks,
|
||||
'original_water_columns':original_m.count('minecraft:water'),'water_columns_obscured_by_markers':verified_water,
|
||||
'water_obscured_by_markers_verified_intact':True,
|
||||
'height_unchanged_columns':sum(a==b for a,b in zip(before['surface_y'],after['surface_y'])),
|
||||
'capture_started_at':after['capture_started_at'],'capture_finished_at':after['capture_finished_at'],
|
||||
'atomic_snapshot':False,'note':'World edits were idle during each capture. Terrain follows its original heights; raised markers represent future structures, not finished traversable paths.'}
|
||||
args.report.parent.mkdir(parents=True,exist_ok=True);args.report.write_text(json.dumps(report,indent=2)+'\n')
|
||||
print(json.dumps(report))
|
||||
|
||||
if __name__=='__main__':main()
|
||||
Reference in New Issue
Block a user