Files
AIGame/Tools/verify_partner_skills.py
T

60 lines
3.3 KiB
Python

"""Audit the formal partner presentation bank and all nine TangoFlux sound receipts."""
import hashlib
import json
from pathlib import Path
import numpy as np
from scipy.io import wavfile
ROOT=Path(__file__).resolve().parents[1]
DESIGN=ROOT/'Doc/Design/Combat/PartnerSkills'
def load(path):return json.loads(path.read_text(encoding='utf-8-sig'))
def digest(path):return hashlib.sha256(path.read_bytes()).hexdigest()
def main():
plan=load(ROOT/'Config/Combat/partner_presentations_v1.json')
game=load(ROOT/'Config/Gameplay/greenfield.json')
assert len(plan['profiles'])==len(game['pets'])==10
assert [p['pet'] for p in plan['profiles']]==list(range(10))
assert [e['id'] for e in plan['effects']]==list(range(5,15))
assert len(set(e['path'] for e in plan['effects']))==10
for e in plan['effects']:
assert (ROOT/'AIClient'/e['path']).is_file()
assert e['poolSize']==4 and .1<=e['lifetime']<=1
assert e['loop']==(e['id'] in (5,14))
assert e['beam']==(e['id'] in (8,13))
for p in plan['profiles']:
for name,value in p.items():
if name.endswith('Effect'):assert -1<=value<15
if name.endswith('Sound'):assert -1<=value<9
assert p['abilityEffect']==p['pet']+5
manifest=load(ROOT/'Doc/Design/Sound/BattleSkills/manifest.json')
assert manifest['status']=='generated'
assert {i['id'] for i in manifest['items']}=={'Sfx_'+s for s in plan['soundIds']}
rows=[]
for item in manifest['items']:
production=item['production']
receipt=load(ROOT/production['receipt'])
record=next(r for r in receipt['items'] if r['id']==item['id'])
target=ROOT/production['output']
assert digest(target)==production['sha256']==record['outputSha256']
assert digest(ROOT/record['source'])==record['sourceSha256']
assert hashlib.sha256(json.dumps(record['request'],sort_keys=True).encode()).hexdigest()==record['requestHash']
assert record['job']['status']=='succeeded'
assert record['job']['seed']==record['request']['seed']
if item['id'] in ('Sfx_Heal','Sfx_Slow','Sfx_Lightning','Sfx_EnemyHit'):assert item['seed']==record['request']['seed']
rate,samples=wavfile.read(target);x=samples.astype(float)/32768
assert rate==44100 and samples.dtype==np.int16 and x.ndim==2 and x.shape[1]==2
assert .1<len(x)/rate<1 and np.isfinite(x).all()
peak=float(np.abs(x).max());rms=float(20*np.log10(np.sqrt(np.mean(x*x))))
assert peak<.95 and np.abs(x[:4410]).max()>.05 and np.abs(x[-10:]).max()<.003 and rms>-36
rows.append(dict(id=item['id'],seconds=len(x)/rate,peakDb=20*np.log10(peak),rmsDb=rms,
clippedSamples=int(np.sum(np.abs(x)>=.999)),sha256=digest(target),actualSeed=record['request']['seed']))
assert len(rows)==9
result=dict(status='pass',profiles=10,signaturePrefabs=10,poolRoots=76,voices=8,audio=rows,
subjectiveListening='not_asserted',releaseLicenseReview=manifest['releaseLicenseReview'])
DESIGN.mkdir(parents=True,exist_ok=True)
(DESIGN/'audio_config_validation.json').write_text(json.dumps(result,indent=2)+'\n',encoding='utf-8')
print('PASS ten partner profiles and prefabs; nine PCM sounds, source/request/output hashes, onset, fades, level, zero clipping')
if __name__=='__main__':main()