"""Generate missing enemy actions sequentially on the recipe's SAME rig.""" import argparse import hashlib import json from pathlib import Path import subprocess import sys REPO=Path(__file__).resolve().parents[1] def seal_generated_motion(folder): """Attach output hashes after the backend has completed its own manifest.""" receipt=folder/'motion_request.json' record=json.loads(receipt.read_text(encoding='utf-8-sig')) result=json.loads((folder/'unimate_manifest.json').read_text(encoding='utf-8-sig')) if result['prompt']!=record['prompt']: raise ValueError('Generated output caption differs from request') record.update(status='generated',remote_job=result['remote_job'], source_fbx_sha256=hashlib.sha256((folder/'animated.fbx').read_bytes()).hexdigest()) temporary=receipt.with_suffix('.pending.json') temporary.write_text(json.dumps(record,indent=2),encoding='utf-8') temporary.replace(receipt) def main(): parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--recipe',type=Path,required=True) parser.add_argument('--motions',nargs='+',choices=('Idle','Walk','Attack'),default=['Idle','Walk','Attack']) parser.add_argument('--device',choices=('cuda','cpu'),default='cuda') args=parser.parse_args() recipe=json.loads(args.recipe.read_text(encoding='utf-8-sig')) for motion in recipe['motions']: if motion['name'] not in args.motions: continue command=[sys.executable,str(REPO/'Tools/generate_animal_walk.py'), '--rig',str(REPO/recipe['rigSource']),'--out',str(REPO/motion['sourceDir']), '--motion',motion['name'],'--duration',str(motion['duration']), '--device',args.device, '--face-right',recipe['faceRight'],'--face-left',recipe['faceLeft'], '--prompt',motion['prompt']] print('GENERATE',recipe['id'],motion['name'],flush=True) subprocess.run(command,cwd=REPO,check=True) seal_generated_motion(REPO/motion['sourceDir']) if __name__=='__main__': main()