D131: restore truncated module ptr in seg_addr (Jungle -level_37)
explosionRenderPropSmoke passes a compiled .bss matrix symbol
(&dword_CODE_bss_8007A100) through osVirtualToPhysical() -- a u32-returning
shim -- into gSPMatrix, truncating the 0x1_00000000 module high word. w1
lands as 0x40xxxxxx and seg_addr() returns it raw -> wild deref in
gfx_sp_matrix when the first explosion draws (~frame 300).
Fix: seg_addr() restores the module high word for any fallthrough w1 in
[0x40000000, 0x70000000) (module fixed-based at 0x140000000, no ASLR;
DRAM/KSEG0/segmented/phys are all handled in earlier branches). Covers the
~30 latent osVirtualToPhysical(<compiled matrix/vtx symbol>) sites in
explosion/glass/blood/bondview2.
Verified: Jungle renders to frame 1500-2400+ crash-free at 91.7% content;
-level_20/-level_24 unregressed. Sweep 18->19/21 (note: -level_09 has a
separate pre-existing boot crash regressed since M-18 -- see HANDOFF).
@
romdataFixupFont re-lays out the N64 24B fontchar array into the PC 32B
array in place; for glyphs 0/1/2 dst overlaps src by less than the 24B
read span, so a forward field write clobbered a later field's source
mid-loop (glyph 1 width = bswap(index), glyph 2 pixeldata -> wild ptr).
Facility's level title 'Chemical Warfare Facility #2' rendered '#' with
the wild pixeldata -> gDPLoadTextureBlock -> fast3d AV in import_texture_i8.
Fix: stage all six N64 fields in a local f[6] before writing any.
Not the model-GDL relocation the D124-Facility addendum suspected
(disproved; D124 entry + BRIEF-C2gdl-model-reloc premise corrected).
Verified: -level_34 0/~14 runs, -level_35 0/4 (was ~3/4);
-level_09/20/24 unregressed. Sweep 18 -> 20/21 PASS; only Jungle C2m
(gfx_sp_matrix explosion-DL G_MTX) remains.
Docs: D130 in PCPortResearch §F/§H, LEVEL-STATUS 20/21, HANDOFF M-18,
PORT-LEARNINGS §A (in-place relayout aliasing + negative glyph index).
LEVEL-STATUS: Bunker2/Depot/Surface2 (D126), Surface1 (D127), Control
(D128) now PASS. Only C2/C2-GDL remains (Runway intermittent, Facility,
Jungle). Cuba loads+renders but bare-boot end-credits path still faults
(D76/D129). HANDOFF next task = C2-GDL model relocation (own session).
PORT-LEARNINGS: D126 corollary (trailing runtime list ptr in ROM record),
D128 (raw hardcoded N64 struct stride bites the same as Gfx/Vtx sizing).
criteria_picture (30) / criteria_roomentered (32) / criteria_deposit (33)
/ setup_objective_text (35) each end in a T*next list pointer that the
setup walk writes unconditionally (set_parent_cur_obj_* /
setup_briefing_text_entry_parent). On x86-64 the pointer widens 4->8B and
8-aligns at offset 16, making the struct 24B/6w (N64 16/20). d88_propdefs.py
emitted N64 size -> the runtime 8-byte ->next store clobbered the next
propdef record's header -> walk desync -> command indices drifted ~100 ->
setupDoor linkedDoor resolution landed on the wrong record -> crash.
Fixes C3r (Bunker2 -level_27), C4 (Depot -level_30), C6 (Surface2 -level_43)
in one change. Sweep 13 -> 16/21. Bunker1/Silo/Aztec/Archives/Egypt/Train
unregressed; d125_check.py 21/21 MATCH.
- tools_pc/d88_propdefs.py: PROPDEF_PC_BYTES[30/32/33/35]=24 + typed handler
- src/game/loadobjectmodel.c: sizepropdef PORT returns 6 for those types
emit_pad()'s widened-stan zero-fill assigned a 4-byte literal to an
8-byte bytearray slice. Python slice-assign with a short RHS silently
deletes the surplus bytes, so `out` shrank 4 B per pad+boundpad; once
len(out) dropped below a later leaf write's target offset, the write
clamped to empty-at-end and inserted there, drifting/truncating the
boundpad plink-name blob (Aztec pad33 "p138d2" -> "8d2") -> stanPackId
reject -> NULL stan -> door model=NULL -> crash propobj.c:13601.
Fix: 8 NUL bytes (only width-mismatched out[ write in the file).
All 21 Usetup*Z sidecars regenerated. Aztec (-level_28) now PASSES
(was C3 CRASH); Bunker1/Silo unregressed; d125_check.py 21/21 MATCH.
Sweep 12 -> 13/21.
Bunker2 (-level_27) still crashes: separate DOOR-tail linkedDoor
layout bug in d88_propdefs.py (C3r) -- linkedDoor is resolved from
linkedDoorOffset (read-before-write int id, D123 pattern). Folded
into the converter write-audit.
M-16 probes reverted; d125_check.py kept as the offline regression guard.
Generalisable quirk added to PORT-LEARNINGS.md §C.
WS4 level sweep driven to completion: 12/21 solo levels PASS
(load + render + no-crash). Full matrix in docs/LEVEL-STATUS.md,
reusable runner tools_pc/level_sweep.sh, WS6 checklist docs/LEVEL-PLAYTEST.md.
Fixes:
- D123 (tools_pc/d88_propdefs.py): crash class C1 on 6 levels
(Dam/Runway/Frigate/Statue/Streets/Cradle). D122 fallout - the widened
Vehichle/AircraftRecord.ailist slot was zeroed instead of carrying its
read-before-write integer AI-list id, so prop.c -> ailistFindById(0) ->
GAILIST_AIM_AT_BOND -> ai() ran a CHR aim list with a NULL chr ->
chrIsNotDeadOrShot(NULL). New OBJ_ID_WORDS arm. 4 levels -> PASS,
Runway falls through to C2. BUNKER1/Silo unregressed.
- D124 (port/src/gimgfixup.c): crash class C2 on Jungle. Compiled
explosion-DL pointer-sync keyed on an IMAGESEG marker that texLoad()
had already erased -> compiled globalDL_0xNNN arrays kept link-time
IMAGESEG words -> 0xABCDxxxx into fast3d on first explosion draw.
Latent on every level. Detect the slot from the compiled array instead.
Diagnosed, NOT fixed (write-ups in PCPortResearch.md SF):
- C2-GDL (D124-Facility addendum): Facility/Runway - model texture-pool
path yields a garbage tex->data; every model file loads at an odd
bank base (mempAllocBytesInBank does no alignment). Suspect
d43_emit.py/pcmodels sidecar texture-blob offsets (N64 8B vs PC 16B Gfx).
- C3/C6 (D125): Aztec/Bunker2/Surface2 - converted propDefs blob in RAM
doesn't match d88_propdefs.py offline output (garbage after record 0);
runtime sizepropdef() walk drifts ~100 records -> wrong door/modelid.
d88_propdefs.py convert_stream + sizepropdef() PORT strides verified
correct; suspect a dest-offset/pd_end bug in d88_emit.py propdefs emit.
Remaining: 9 crashes / 6 classes (C2-GDL, C3/C6, C2m Jungle G_MTX,
C5 Control BG portal, C4 Depot BG tile/room, C7 Surface1 sndSetupSound).
Priority order in docs/LEVEL-STATUS.md.
Also folds in the in-progress docs restructure (HANDOFF/AGENTS/CLAUDE,
PCPortResearch D121/D122 SF/SH entries, PLAN-linear-level-sweep,
HANDOFF-ARCHIVE, BACKLOG).