mirror of
https://github.com/jkdansereau/goldeneye-pc-port.git
synced 2026-10-23 15:52:42 +02:00
PC port: phase 2 — D48 review: re-plan D43 as offline pre-conversion (Plan B)
- D48 finding in PCPortResearch.md §F: d43_convert.py does not emit bytes (layout+remap validation only); Plan B = Python emit pass -> data/pcmodels-<region>/ RZ sidecars served via port-layer hw_address/rom_size table patch (no C converter); Plan A kept as fallback with corrected staging guard (D_N64+D_PC<=avail) - Moved all 23 d43_*.py investigation scripts from gitignored build-pc/ to tracked tools_pc/ (spec is now versioned); d43_cover.py path ref updated; converter re-run from new location: ALL CLEAN - HANDOFF.md rewritten as two-session prompt: Session A = independent review of Plan B (8 claims, each with falsification criterion -> finding D49), Session B = execute (emit pass + round-trip validator, romdata plumbing, one-line hook, pixel-assert soak); verified-facts converter spec preserved - AGENTS.md phase status updated to D48 re-plan
This commit is contained in:
1 parent
181f6db07d
commit
73ea03734d
26 files changed
+2839
-216
No files matched your search
@@ -0,0 +1,106 @@
|
||||
# D43: full layout analysis of all model files with CORRECT N64 sizes.
|
||||
# node = 24B; records per opcode; vertex/coll arrays; GDLs. Report gaps/overlaps.
|
||||
import csv, struct, zlib, os, re
|
||||
from collections import Counter
|
||||
|
||||
ROM = r"data/ge007.ntsc-final.z64"
|
||||
rom = open(ROM, "rb").read()
|
||||
rows = list(csv.reader(open(r"scripts/filelist.u.csv")))
|
||||
RSZ = {1:0x10, 2:0x1C, 4:0x14, 8:0x10, 9:0x24, 10:0x1C, 12:0x28, 13:0x20, 15:0x1C, 17:0x20, 18:0x8, 21:0x14, 22:0x10, 23:0x2, 24:0x20}
|
||||
hdrfiles = set()
|
||||
for root, dirs, files in os.walk("assets"):
|
||||
for fn in files:
|
||||
if fn.lower().endswith("modelfileheader.inc.c"): hdrfiles.add(os.path.join(root, fn))
|
||||
nsnt = {}
|
||||
for f in sorted(hdrfiles):
|
||||
for line in open(f):
|
||||
m = re.search(r"MODELFILEHEADER\((.*)\)\s*;?\s*$", line)
|
||||
if not m: continue
|
||||
a = [x.strip() for x in m.group(1).split(",")]
|
||||
if len(a) < 9: continue
|
||||
try: nsnt[a[0]] = (int(a[4], 0), int(a[8], 0))
|
||||
except ValueError: pass
|
||||
|
||||
def be32(b, o): return struct.unpack_from(">I", b, o)[0] & 0xFFFFFF
|
||||
def be16(b, o): return struct.unpack_from(">H", b, o)[0]
|
||||
def be32raw(b, o): return struct.unpack_from(">I", b, o)[0]
|
||||
|
||||
gapstats = Counter(); problems = []
|
||||
nfiles = 0; totalnodes = 0; opcodes = Counter()
|
||||
for r in rows:
|
||||
if len(r) < 3 or not r[2]: continue
|
||||
base = r[2].rsplit("/",1)[-1]
|
||||
if base.endswith(".bin"): base = base[:-4]
|
||||
if not (base[0] in "CGP" and base.endswith("Z") and "_stan" not in base): continue
|
||||
try: addr,size = int(r[0]),int(r[1])
|
||||
except ValueError: continue
|
||||
key=None
|
||||
for cand in (base, base[1:], base[:-1], base[1:-1]):
|
||||
if cand in nsnt: key=cand; break
|
||||
if not key: problems.append((base,"nohdr")); continue
|
||||
NS,NT = nsnt[key]
|
||||
try: out = zlib.decompress(rom[addr:addr+size][2:], -15)
|
||||
except Exception: problems.append((base,"decomp")); continue
|
||||
D = len(out); R0 = 4*NS + 12*NT; nfiles += 1
|
||||
stack=[R0]; seen=set(); objs=[]
|
||||
while stack:
|
||||
o=stack.pop()
|
||||
if o in seen or o>=D-23: problems.append((base,"badnode %X"%o)); break
|
||||
seen.add(o)
|
||||
op=struct.unpack_from(">H",out,o)[0]&0xff
|
||||
opcodes[op]+=1
|
||||
data=be32(out,o+4)
|
||||
objs.append((o,o+24,"node"))
|
||||
if op in RSZ:
|
||||
rsz = RSZ[op]
|
||||
if data + rsz > D: problems.append((base,"rec %X+%X>D"%(data,rsz)))
|
||||
else: objs.append((data,data+rsz,"rec%d"%op))
|
||||
if op==22:
|
||||
nv=struct.unpack_from(">i",out,data)[0]
|
||||
v=be32(out,data+4)
|
||||
p=be32(out,data+8)
|
||||
if p: objs.append((p,None,"gdl"))
|
||||
if v and nv>0: objs.append((v,v+16*nv,"vtx22"))
|
||||
if op==4:
|
||||
p=be32(out,data); s=be32(out,data+4)
|
||||
v=be32(out,data+0xC)
|
||||
if p: objs.append((p,None,"gdl"))
|
||||
if s: objs.append((s,None,"gdl"))
|
||||
if v: objs.append((v,None,"vtx?")) # size unknown (numVertices may be 0)
|
||||
elif op==24:
|
||||
p=be32(out,data); s=be32(out,data+4)
|
||||
v=be32(out,data+8); nv=be16(out,data+0xC)
|
||||
cv=be32(out,data+0x10); nc=be16(out,data+0xE)
|
||||
pu=be32(out,data+0x14)
|
||||
if p: objs.append((p,None,"gdl"))
|
||||
if s: objs.append((s,None,"gdl"))
|
||||
if v and nv: objs.append((v,v+16*nv,"vtx"))
|
||||
if cv and nc: objs.append((cv,cv+16*nc,"coll"))
|
||||
if pu: objs.append((pu,None,"pointusage?"))
|
||||
for q in (be32(out,o+0x14), be32(out,o+0xC)):
|
||||
if q: stack.append(q)
|
||||
totalnodes += len(seen)
|
||||
# resolve open-ended objects using sorted starts
|
||||
known = sorted(set(s for s,e,k in objs if e is not None))
|
||||
for i,(s,e,k) in enumerate(objs):
|
||||
if e is None:
|
||||
nxt = [x for x in known if x > s]
|
||||
objs[i] = (s, min(nxt) if nxt else D, k)
|
||||
ivs = sorted((s,e) for s,e,k in [(0,R0,"hdr")]+objs)
|
||||
pos = 0
|
||||
for s,e in ivs:
|
||||
if s < pos: problems.append((base,"overlap %X<%X"%(s,pos))); break
|
||||
if s > pos:
|
||||
gapstats[(s-pos)] += 1
|
||||
if len(problems) < 40:
|
||||
problems.append((base, "gap %X..%X (%d B)" % (pos, s, s - pos)))
|
||||
break
|
||||
pos = e
|
||||
else:
|
||||
if pos != D: problems.append((base,"tail gap %X!=D=%X"%(pos,D)))
|
||||
|
||||
print("files:",nfiles,"nodes:",totalnodes)
|
||||
print("opcodes:",dict(sorted(opcodes.items())))
|
||||
print("gap-size histogram (first gap per file):",dict(sorted(gapstats.items())[:20]))
|
||||
print("problems:",len(problems))
|
||||
for p in problems[:40]: print(" ",p)
|
||||
Reference in new issue
Block a user