Include the current addon, terrain integrations, tools, regression tests and recorded development evidence.
33 lines
3.1 KiB
Plaintext
33 lines
3.1 KiB
Plaintext
from pathlib import Path
|
|
import re,json,math,shutil,hashlib
|
|
out=Path('/home/jakub/devel/escapistsrereintroduced/docs/evidence/convoy-hq-coordination-2026-10-04')
|
|
base=Path('/tmp/erri-convoy-scene-native')
|
|
metrics={}
|
|
for label,name in [('baseline','baseline-combat'),('combat','final-combat'),('arrival-stall','qualified'),('final','arrival-fixed')]:
|
|
run=base/name;session=next((run/'profile/logs').glob('logs_*'))
|
|
text=(session/'console.log').read_text(errors='replace');events=(session/'rereintroduced-hq.log').read_text(errors='replace')
|
|
cars={};teams={}
|
|
for m in re.finditer(r'ERR CONVOY SCENE CAR: t=([\d.]+) id=(\d+) pos=<([^>]+)> goal=<([^>]+)> released=(\d)',text):
|
|
t,i,xyz,goal,released=m.groups();x,y,z=map(float,xyz.split(','));cars.setdefault(int(i),[]).append((float(t),x,z,int(released)))
|
|
for m in re.finditer(r'ERR CONVOY SCENE MAN: t=([\d.]+) team=(\d+) man=(\d+) pos=<([^>]+)> mounted=(\d)',text):
|
|
t,i,n,xyz,mounted=m.groups();x,y,z=map(float,xyz.split(','));teams.setdefault(int(i),{}).setdefault(int(n),[]).append((float(t),x,z,int(mounted)))
|
|
summary={}
|
|
for i,members in teams.items():
|
|
detail={}
|
|
for n,samples in members.items():
|
|
foot=[p for p in samples if p[0]>=(180 if label in ('final','arrival-stall') else 90) and not p[3]]
|
|
detail[n]={'seen_on_foot':bool(foot),'first_on_foot_seconds':foot[0][0] if foot else None,'max_displacement_after_dismount_m':round(max((math.hypot(p[1]-foot[0][1],p[2]-foot[0][2]) for p in foot),default=0),1),'mounted_at_end':bool(samples[-1][3])}
|
|
summary[i]=detail
|
|
travel={}
|
|
for i,samples in cars.items():
|
|
before=[p for p in samples if p[0]<(180 if label in ('final','arrival-stall') else 90)];first=samples[0]
|
|
travel[i]={'travel_max_displacement_m':round(max((math.hypot(p[1]-first[1],p[2]-first[2]) for p in before),default=0),1),'released_at_end':bool(samples[-1][3])}
|
|
metrics[label]={'complete':'ERR SCENE COMPLETE' in text,'synthetic_initial_contact':True,'cars':travel,'teams':summary,'script_errors':[l for l in text.splitlines() if 'SCRIPT (E)' in l],'stranded_events':[l for l in events.splitlines() if 'CONVOY STRANDED' in l]}
|
|
shutil.copy2(session/'console.log',out/(label+'-console.log'))
|
|
(out/(label+'-events.log')).write_text('\n'.join(l for l in events.splitlines() if any(w in l for w in ['CONVOY','flanking search','ORDER DELIVERED','ORDER QUEUED']))+'\n')
|
|
if (run/'result.json').exists():shutil.copy2(run/'result.json',out/(label+'-result.json'))
|
|
scripts={str(p.relative_to(run/'source')):hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted((run/'source/Scripts').rglob('*.c'))}
|
|
(out/(label+'-script-sha256.json')).write_text(json.dumps(scripts,indent=2)+'\n')
|
|
(out/'metrics.json').write_text(json.dumps(metrics,indent=2)+'\n')
|
|
print(json.dumps({k:{'complete':v['complete'],'cars':v['cars'],'teams':{i:{'off':sum(m['seen_on_foot'] for m in members.values()),'max_displacement_m':max(m['max_displacement_after_dismount_m'] for m in members.values()),'end_aboard':sum(m['mounted_at_end'] for m in members.values())} for i,members in v['teams'].items()},'script_errors':len(v['script_errors'])} for k,v in metrics.items()},indent=2))
|