File size: 2,315 Bytes
61c0834 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #!/usr/bin/env python3
"""Inventory every extracted MD3 occurrence, preserving archive/case variants."""
import hashlib
from collections import defaultdict
from pathlib import Path
from md3 import MD3
from analyze_qvm import write_json
def paths():return sorted(p for p in Path('assets/extracted').rglob('*') if p.is_file() and p.suffix.lower()=='.md3')
def virtual(p):
parts=p.parts;j=parts.index('members');return '/'.join(parts[j+2:])
def main():
rows=[];groups=defaultdict(list)
for p in paths():
raw=p.read_bytes();r={'path':str(p),'virtual_path':virtual(p),'sha256':hashlib.sha256(raw).hexdigest(),'bytes':len(raw)}
try:
m=MD3(raw);surfaces=[];changes=[];first=[m.tag(0,j)['name'] for j in range(m.tags)] if m.frames else []
for frame in range(m.frames):
m.frame(frame)
for j in range(m.tags):
tag=m.tag(frame,j)
if tag['name']!=first[j]:changes.append([frame,j,tag['name']])
for s in m.surfaces:
uv=[m.uv(s,j) for j in range(s.vertices)];surfaces.append({'name':s.name,'frames':s.frames,'vertices':s.vertices,'triangles':s.triangles,'uv_bounds':[[min(v[j] for v in uv),max(v[j] for v in uv)] for j in range(2)] if uv else None,'shaders':[m.shader(s,j) for j in range(s.shaders)]})
r.update({'frames':m.frames,'tag_names':first,'tag_name_changes':changes,'surfaces':surfaces,'status':'validated'})
except (ValueError,IndexError) as e:r.update({'status':'rejected','error':str(e)})
rows.append(r);groups[r['virtual_path'].casefold()].append({'path':str(p),'sha256':r['sha256'],'stored_virtual_path':r['virtual_path']})
duplicates={k:v for k,v in groups.items() if len(v)>1};write_json(Path('docs/research/md3-inventory.json'),{'models':rows,'totals':{'occurrences':len(rows),'validated':sum(r['status']=='validated' for r in rows),'bytes':sum(r['bytes'] for r in rows),'casefold_paths':len(groups)},'path_variants':duplicates,'limits':'Every extracted occurrence retained; casefold groups are comparisons, not VFS precedence or asset renames. Frames/tags/UVs validated finite, triangle bounds and packed regions validated. Normal interpretation/rendering/runtime resolution remain separate.'})
if __name__=='__main__':main()
|