Files
RustRaptor/tools/hd_dark_terrain_six.py

117 lines
10 KiB
Python

"""Finite DERIVED terrain; Source broad colour + genuine parent fine/mid luminance.
No generator, registry, World or original-data writes. Source-only regions and
retained pale-tip/lavender cells receive zero HD detail credit. Independent ART required.
"""
from pathlib import Path
import argparse, hashlib, io, json, os, re, shutil, stat, types
import numpy as np
from PIL import Image
METHOD='six-dark-Source-gray-lavender-generated-fine-mid-buffered-v1'
DEPENDENCIES={'hd_terrain_retexture':'0e4d7d5a4f7a7ddf6e396e757691156dfc74d231d9925744c342078532b89a98','hd_terrain_group_retexture':'24e3751d26090699f2d8d317ed98f73e05f51f3caa6dc2bf21fc40a109068a27'}
PARAMETERS={'output_side':512,'source_sigma':3.0,'residual_sigma_fine':0.65,'residual_sigma_coarse':10.0,'residual_percentile':80.0}
GROUPS=[{'name': 'pale', 'indices': [1], 'texture_log_gain': 0.06, 'quiet_from_source_variance': True}, {'name': 'gray', 'indices': [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27], 'texture_log_gain': 0.38, 'quiet_from_source_variance': True}, {'name': 'floor', 'indices': [28, 29, 30, 31], 'texture_log_gain': 0.38, 'quiet_from_source_variance': True}, {'name': 'lavender', 'indices': [113], 'texture_log_gain': 0.06, 'quiet_from_source_variance': True}]
COHORTS=[['301c3','301c8','301cc'],['301d1','301d4','301d7']]
PALETTE='1cf6adb926d1dee1888b3e3d33b51a7049b3e5eb5f90a3067ef71c8970547204'
PINS={'301c3': ['9c370900214a601e40200cb67e959f042323d001f7a2e6de3627e5044a2078b5', 'dc4244108b9e760f324f4279e530ef2e02a799b087fe21570668c345fbe37b43'], '301c8': ['4d87a0251b8b064c6ab5835ae31f5eaabfec405f56b0408980f93484b70470d1', '8b6d719ecd4762156a81e9f0173ccea0dcfd9d1967b3fae6f04f82d6aba9297d'], '301cc': ['be151484d73ebe4461115391c3fcea20f109a14b0f2eee1ce13f1cbb34014355', 'e2cf0453dfc61b5729ef9c968bf48dc6dc3deb42e1fa6e1e520904ebf4f6e502'], '301d1': ['c9acde36a4eba021ede70d02f13a63be869b8403636d0d8e61b2647484b26aa7', 'b35415096e86ef4e3e7b73994f1f2ab7e7ef44109b7a339bf8325e3189aa69cc'], '301d4': ['ca09a82a3379d6bdf15360a3469e7d7f0a278c1edfaab835c4b7d3e80ebff239', 'b4cf5cfde22ea1ab889cea70a905d3320ec7395a20e8657f69716251c4a9f166'], '301d7': ['4d39e7d667501dca5941243b5f371e4e783663faaf5f69c64385a98c41e015af', '569ecfbae3dc723f1bc2c2dca2f0aa3d452f94e3c68d11bb21ca48b02537d4e7']}
def sha(payload):return hashlib.sha256(payload).hexdigest()
def binding(value):
if type(value)is not dict or set(value)!={'path','sha256'} or type(value['path'])is not str or type(value['sha256'])is not str or re.fullmatch('[0-9a-f]{64}',value['sha256'])is None:raise ValueError('exact path/hash binding required')
return value
def read_contained(root,relative,limit=32*1024*1024):
if type(relative)is not str or relative.startswith('/') or '\\'in relative or any(x in ('','.','..')for x in relative.split('/')):raise ValueError('strict contained relative path required')
root=Path(root).absolute()
if '..'in root.parts:raise ValueError('noncanonical root path')
flags=os.O_RDONLY|os.O_CLOEXEC|os.O_NOFOLLOW|os.O_NONBLOCK
fd=os.open('/',flags|os.O_DIRECTORY)
try:
for part in root.parts[1:]+tuple(relative.split('/')[:-1]):
following=os.open(part,flags|os.O_DIRECTORY,dir_fd=fd);os.close(fd);fd=following
source=os.open(relative.split('/')[-1],flags,dir_fd=fd)
try:
before=os.fstat(source)
if not stat.S_ISREG(before.st_mode)or not 0<=before.st_size<=limit:raise ValueError('bounded regular input required')
chunks=[];size=0
while True:
chunk=os.read(source,min(65536,limit+1-size))
if not chunk:break
chunks.append(chunk);size+=len(chunk)
if size>limit:raise ValueError('EOF limit exceeded')
after=os.fstat(source)
identity=lambda x:(x.st_dev,x.st_ino,x.st_size,x.st_mtime_ns,x.st_mode)
if identity(before)!=identity(after)or size!=before.st_size:raise ValueError('input changed/non-EOF read')
return b''.join(chunks)
finally:os.close(source)
finally:os.close(fd)
class BufferedInputs:
def __init__(self,root):self.root=root;self.cache={};self.physical_reads=0
def read(self,value,limit=32*1024*1024):
binding(value);relative=value['path']
if relative not in self.cache:self.cache[relative]=read_contained(self.root,relative,limit);self.physical_reads+=1
payload=self.cache[relative]
if len(payload)>limit or sha(payload)!=value['sha256']:raise ValueError('input hash/limit mismatch')
return payload
def modules(payloads):
if set(payloads)!=set(DEPENDENCIES)or any(sha(payloads[k])!=v for k,v in DEPENDENCIES.items()):raise ValueError('dependency buffer pins differ')
loaded={}
for name,payload in payloads.items():
m=types.ModuleType('verified_'+name);m.__file__='/authenticated-buffered/'+name+'.py';exec(compile(payload,m.__file__,'exec'),m.__dict__);loaded[name]=m
return loaded
def decode_png(payload):
with Image.open(io.BytesIO(payload))as im:
if im.format!='PNG'or im.size!=(1254,1254)or getattr(im,'n_frames',1)!=1 or im.mode not in('RGB','RGBA'):raise ValueError('exact bounded single full provider PNG required')
if im.mode=='RGBA'and im.getchannel('A').getextrema()!=(255,255):raise ValueError('opaque parent required; never fill holes')
return np.array(im.convert('RGB'))
def validate_recipe(recipe):
if type(recipe)is not dict or set(recipe)!={'format_version','method','dependencies','palette','frames','parameters','material_groups'}or type(recipe['format_version'])is not int or recipe['format_version']!=1 or recipe['method']!=METHOD:raise ValueError('exact versioned recipe required')
if recipe['parameters']!=PARAMETERS or recipe['material_groups']!=GROUPS:raise ValueError('fixed math only')
if type(recipe['frames'])is not list or any(type(f)is not dict for f in recipe['frames'])or [f.get('asset')for f in recipe['frames']]not in COHORTS:raise ValueError('exact complete3 distinct-tile cohort required')
if type(recipe['dependencies'])is not dict or set(recipe['dependencies'])!=set(DEPENDENCIES):raise ValueError('exact dependencies required')
for k,pin in DEPENDENCIES.items():
if binding(recipe['dependencies'][k])['sha256']!=pin:raise ValueError('dependency pin differs')
if binding(recipe['palette'])['sha256']!=PALETTE:raise ValueError('palette pin differs')
for f in recipe['frames']:
if type(f)is not dict or set(f)!={'asset','Source','parent_raw','origin','crop'}or f['asset']not in PINS:raise ValueError('exact frame fields required')
if f['origin']!=[0,0]or f['crop']!=[0,0,1254,1254]or any(type(v)is not int for v in f['origin']+f['crop']):raise ValueError('exact whole canvas required')
for key,pin in zip(('Source','parent_raw'),PINS[f['asset']]):
if binding(f[key])['sha256']!=pin:raise ValueError('Source/provider binding differs')
def derive(recipe,root):
validate_recipe(recipe);inputs=BufferedInputs(root);deps=modules({k:inputs.read(v,1024*1024)for k,v in recipe['dependencies'].items()});kernel=deps['hd_terrain_retexture'];group=deps['hd_terrain_group_retexture']
palette=kernel.palette_rgb(inputs.read(recipe['palette'],768));outputs=[];reports=[]
for f in recipe['frames']:
source=kernel.decode_source(inputs.read(f['Source'],1044))
if source.shape!=(32,32)or not set(map(int,np.unique(source)))<={i for group in GROUPS for i in group['indices']}:raise ValueError('exact supported Source shape/indices required')
raw=decode_png(inputs.read(f['parent_raw']))
result,base,labels,metrics=group.reconstruct(source,palette,raw,PARAMETERS,GROUPS,kernel)
marker_owners=set()
for factor in range(1,5):
ys,xs=np.where(np.isin(kernel.scale_nx(source,factor),[1,113]))
marker_owners.update((int(x)//factor,int(y)//factor)for x,y in zip(xs,ys))
marker_cells=[list(xy)for xy in sorted(marker_owners)]
# Runtime retains these literal logical cells using its own exact SourceNx.
# The derived physical PNG remains honestly as returned by reconstruct().
outputs.append((f['asset'],result));reports.append(dict(asset=f['asset'],Source_sha256=f['Source']['sha256'],parent_raw_sha256=f['parent_raw']['sha256'],original_detail_cells=marker_cells,retained_Source_cells_HD_credit=0,metrics=metrics))
return outputs,dict(method=METHOD,assets=reports,physical_authenticated_input_reads=inputs.physical_reads,dependencies=DEPENDENCIES,scope='DERIVED Source broad RGB/Scale4x material geometry plus genuine generated monochrome fine/mid log-luminance; not untouched provider RGB. Source-backed structure and runtime pale-tip/lavender retentions receive zero new HD detail credit. Separate intrinsic/context ART approval required.')
def main(recipe_relative,recipe_sha,project_root,output):
root=Path(project_root).absolute();payload=read_contained(root,recipe_relative,1024*1024)
if sha(payload)!=recipe_sha:raise ValueError('recipe hash mismatch')
recipe=json.loads(payload);validate_recipe(recipe);out=Path(output).absolute()
if '..'in out.parts or not out.parent.is_dir()or any(p.is_symlink()for p in(out.parent,*out.parent.parents))or os.path.lexists(out):raise ValueError('fresh nonsymlink output required')
if shutil.disk_usage(out.parent).free<1_932_735_284+32*1024*1024:raise ValueError('disk floor/reserve required')
results,report=derive(recipe,root);prepared=[]
for asset,result in results:
buf=io.BytesIO();Image.fromarray(result).save(buf,format='PNG',compress_level=9);prepared.append((asset,buf.getvalue()))
report['execution']=dict(status='success',tool_sha256=sha(read_contained(Path(__file__).parent,Path(__file__).name,1024*1024)),recipe_sha256=sha(payload),source_sha256={f['asset']:f['Source']['sha256']for f in recipe['frames']},parent_raw_sha256={f['asset']:f['parent_raw']['sha256']for f in recipe['frames']},outputs=[dict(asset=a,file=a+'-derived.png',sha256=sha(b))for a,b in prepared])
out.mkdir()
for asset,b in prepared:(out/(asset+'-derived.png')).write_bytes(b)
(out/'ACTUAL-DERIVATION-RECEIPT.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(report['execution']))
if __name__=='__main__':
ap=argparse.ArgumentParser();ap.add_argument('recipe_relative');ap.add_argument('recipe_sha');ap.add_argument('project_root');ap.add_argument('output');a=ap.parse_args();main(a.recipe_relative,a.recipe_sha,a.project_root,a.output)