#!/usr/bin/env python3 """Parse original player LOD3 model layout against the recovered QVM offsets.""" import hashlib from dataclasses import asdict from pathlib import Path from md3 import MD3 from analyze_qvm import write_json def selected():return sorted(p for p in Path('assets/extracted').rglob('*') if p.is_file() and '/models/players/' in str(p) and p.parent.name in ['athena','orion'] and p.name.lower() in ['lower_3.md3','upper_3.md3','head_3.md3','helmet_3.md3']) def main(): rows=[] for p in selected(): raw=p.read_bytes();m=MD3(raw);rows.append({'path':str(p),'sha256':hashlib.sha256(raw).hexdigest(),'bytes':len(raw),'name':m.name,'frames':m.frames,'tags':m.tags,'surfaces':[asdict(s) for s in m.surfaces],'offsets':{'frames':m.frames_offset,'tags':m.tags_offset,'surfaces':m.surfaces_offset,'end':m.end},'first_frame':m.frame(0),'first_tags':[m.tag(0,j) for j in range(m.tags)]}) write_json(Path('docs/research/md3-contract.json'),{'models':rows,'limits':'Original bytes parsed only; version15/declared ranges/surface chain/frame counts/triangle indices checked. No renderer/full runtime. Coordinate scale and fields are cross-linked to recovered QVM offsets, not external format assumptions.'}) if __name__=='__main__':main()