45 lines
3.5 KiB
Python
45 lines
3.5 KiB
Python
"""Validate actual packaged process evidence. Does not drive the game or infer screenshots."""
|
|
import argparse
|
|
import json
|
|
import struct
|
|
from pathlib import Path
|
|
|
|
|
|
def total(items,item):return sum(i['count'] for i in items if i['itemId']==item)
|
|
def verify(folder):
|
|
launch=json.loads((folder/'launch.json').read_text(encoding='utf-8-sig'))
|
|
checks=[]
|
|
def check(name,value):checks.append({'name':name,'passed':bool(value)})
|
|
images=[]
|
|
for path in sorted(folder.glob('*.png')):
|
|
data=path.read_bytes()
|
|
if not data.startswith(b'\x89PNG\r\n\x1a\n'):raise ValueError('Not PNG: '+str(path))
|
|
width,height=struct.unpack('>II',data[16:24]);images.append({'file':path.name,'width':width,'height':height,'environment':launch['environment']})
|
|
check('Captured real images',len(images)>=5)
|
|
expected=tuple(map(int,launch['requestedResolution'].split('x')))
|
|
check('Actual captures match requested resolution',all((i['width'],i['height'])==expected for i in images))
|
|
def load(name):return json.loads((folder/(name+'.json')).read_text(encoding='utf-8-sig'))
|
|
if launch['scenario']=='cycle':
|
|
before,deploy,pod,ready,returned,dead,final=[load(n) for n in ('before','deployed','pod-recovered','ready-still-active','returned','destroyed','final')]
|
|
check('V1 unchanged',all(p['version']==1 for p in (before,deploy,pod,ready,returned,dead,final)))
|
|
check('Deployment consumed owned starter UID once',deploy['sorties']==1 and len(deploy['run']['installed'])==4 and len(deploy['warehouse'])==0)
|
|
check('Pod bank and exact receipt',pod['run']['active'] and pod['run']['podUsed'] and total(pod['warehouse'],'alloy')==4 and pod['receipts']==[deploy['run']['id']+':cargo'])
|
|
check('Ready transport did not auto-extract',ready['run']['active'] and ready['extractions']==0 and len(ready['receipts'])==1)
|
|
check('Explicit boarding returned equipment and protected cargo',not returned['run']['active'] and returned['extractions']==1 and total(returned['warehouse'],'cells')==2 and len(returned['warehouse'])==6)
|
|
check('Death retains only safe cargo; loss cargo not banked',dead['sorties']==2 and dead['extractions']==1 and total(dead['warehouse'],'alloy')==4 and total(dead['warehouse'],'cells')==5 and len(dead['warehouse'])==2 and not dead['run']['active'])
|
|
check('Recovery receipts unique',len(final['receipts'])==len(set(final['receipts']))==4)
|
|
uids=[i['uid'] for key in ('warehouse','recoveryInbox') for i in final[key]]+[i['uid'] for key in ('cargo','safeCase','installed') for i in final['run'][key]]
|
|
check('Unique physical ownership',len(uids)==len(set(uids)))
|
|
else:
|
|
profile=load('ui-profile');check('UI sweep did not deploy or change save version',profile['version']==1 and profile['sorties']==0 and not profile['run']['active'])
|
|
check('Both languages captured',any(i['file'].startswith('hangar-zh') for i in images) and any(i['file'].startswith('hangar-en') for i in images))
|
|
result={'passed':all(c['passed'] for c in checks),'checks':checks,'screenshots':images}
|
|
(folder/'verification.json').write_text(json.dumps(result,ensure_ascii=False,indent=2)+'\n',encoding='utf-8')
|
|
print(json.dumps({'folder':str(folder),'passed':result['passed'],'checks':len(checks),'failed':[c['name'] for c in checks if not c['passed']],'images':len(images)},ensure_ascii=False))
|
|
return result['passed']
|
|
|
|
|
|
if __name__=='__main__':
|
|
parser=argparse.ArgumentParser();parser.add_argument('folder',type=Path);args=parser.parse_args()
|
|
raise SystemExit(0 if verify(args.folder.resolve()) else 1)
|