mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-10-03 00:05:11 -04:00
17 KiB
17 KiB
Struct-map decisions — the head types (P38 T3)
Canonical file set
- One file,
include/struct_types.h, included frominclude/common.h(the header splat gives every TU; precedent:gte_inline.h, P36 T5).CANON_HEADERS = (src/shared/engine_types.h, include/struct_types.h); engine_types.h stays the ov-only canonical file, struct_types.h holds layouts whose cluster spans spaces. - Evidence (body_base_type.json, census at
42a9cd7f5):Unkstruct_80126B58bodies ov 16,773 · md 311 · main 0;Unkstruct_800B5CB8bodies ov 15,245 · md 502 · main 22 (src/800.c) · boot.c 1. Each is ONE union-find cluster (one id, one layout) across spaces, so a per-space file would duplicate the definition: identity by cluster, never by name. - No per-space files (
src/shared/main/types.h, the slots'): main's shared types stay insrc/800_shared.h(not canonical yet, T5); slot headers are reached through the prelude already. - Tool fix that this needed: the restruct/delever include graph (
tools/delever.py includers) now follows the build's-Iinclude; before,type_visiblewas false for every header under include/.
Resolution rule
- Per head: candidates = the map's layout entries plus every conflict alternative; misaligned candidates dropped; the non-overlapping set with the most sites wins (weighted-interval DP; ties: lower offset, wider, sign s<u<p). Every overlap resolves as SPLIT: loser sites keep their casts and the byte oracle judges them later. A union is recorded as a candidate (loser >= 50 sites and >= 20 % of the winner) but never emitted: the rewriter spells flat members only (
restruct.py member_spelling). - binding: head-type overlaps resolve by max-site split; unions wait until the rewriter spells union members.
- Field names: unkHEX throughout;
docs/actor-struct.mddoes not describe these layouts (next section), so no field has cited evidence. Unkstruct_800B5CB8issuspectin the map (20+ AT globals, 4,724 params, 50 conflict offsets, 25,393 of 101,110 candidate sites dropped): a merge of several real types through argument conduits; its split is provisional until the cluster is separated (T5 candidate).
Unkstruct_80078E00 (the player block)
- Not defined: no such layout exists.
D_80078E00has 0 occurrences in src/; the struct map has no cluster anchored at 0x80078E00 (only scalar clusters:AT:D_80078EB4u16 x270,AT:D_80078EB0s16 x152, ...); both heads have s32 at +0xB4 (1,744 / 404 sites) where the player's hp_current is a u16 at 0x80078EB4, so the player block is an instance of neither (9 scalar globals compared: 1 agrees with 80126B58, 0 with 800B5CB8;.run/P38/T3/player_vs_heads.py).docs/actor-struct.md's "0x24C at 0x80078E00" was a Phase-17 m2c inference matched by the coincidence of +0xB4. - What the code has: a 0x98-byte record at 0x80078E78:
Blk98_80029274(src/800.c,s32 words[38], struct-copied into the save slot in func_80029774), the block-scopeBlk80078E78(src/resident/resident_jr_800D00E4.c:546), andu8 D_80078E78[]indexed [0]/[0x1A]/[0x37]/[0x49] in 880 TUs. - Defined instead:
Unkstruct_80078E78(0x98) in include/struct_types.h; widths = the type each USING TU declares for the scalar global (.run/P38/T3/player_use_widths.py, boilerplate externs excluded); names only for rows memory-map 3.4 / actor-struct.md mark verified (gold, tiredness_raw, dayCounter, hour, hp_max, hp_current, bp_max, bp_current, dayOfWeek, posX, posZ). Code-width overlaps recorded in the field comments (+0x38 s16 over hour: the verified name wins; +0x1C/+0x20/+0x24/+0x2C wide over narrow: the wide majority wins). Reported-only names stay in comments. Blk98_80029274folded onto it (typedef Unkstruct_80078E78 Blk98_80029274;, src/800.c), R22-judged. No typed body exists for this record in the map, so the--try-fileproof does not apply; R22 is its byte proof.Blk80078E78(block scope) is rung-L work.
Unkstruct_800B5CB8: split or union (P38 T5.1)
- Call: the max-site SPLIT stands (include/struct_types.h:6-117); no union members are emitted. The locals the fold refused keep their own types.
- Evidence, T4's kept units (logs/T4.md, rung-L head fold, byte judge):
- DIFFERS 29.
Ent_8017FD58family (20 names, one layout; base def src/shared/engine_types.h:2128-2144 at T5.1 start):u16at +0x02/+0x04 where the split hass16 unk2/unk4(lhu vs lh: a sign, not a width, so a union would not reconcile it; the sites differ per access, i.e. a different type).Ent_801202A0(:1883-1890), 6 md_MAIN_011 player copies (0x98 record, not this head),Ent_8017D898,Ent@func_8014D820: same verdict. - pad3C 3 (
Ent_8018D3A4/Ent_8018D654, engine_types.h:5060-5109):s16 f38, s16 f3A, s32 f3C, s16 f40, s16 f42("home" record, commented field meanings) against the split'ss16 unk38, u16 unk3A, pad3C, u16 unk3E, pad40, u16 unk42. The 0x3C loser (4s n=125 vs 2u@0x3E n=352) is a union candidate by count, but the same bodies disagree at 0x3A and 0x40 too: a coherent second record, not one field with two spellings.
- DIFFERS 29.
- Why split, not union: the head is
suspect(a merge of real types through argument conduits, line 15); every refused unit is a whole coherent layout disagreeing at several offsets, which is the signature of a separate type (G62 "per type"), and a union would give one name two types. The byte judge refusing the fold is the evidence that these sites belong to another type. - Consequence:
Ent_8017FD58andEnt_8018D3A4stay distinct canonical types (their own same-layout copies fold onto them in T5.1); unions stay deferred (binding line 13) until a unit is found whose single field is read at two widths in one body.
Per-offset records
Written by tools/head_types.py (max-site split). Losers' sites keep their casts; the byte oracle judges them later.
Summary fields: overlaps = candidates dropped because a heavier non-overlapping set won; misaligned = candidates dropped
for off % min(w,4) != 0 (or an 8-byte field off 8-alignment); union_candidates = offsets whose resolution is
union-candidate (deferred).
Source: .run/P37/census/struct_map.json head 42a9cd7f5.
Unkstruct_800B5CB8
fields=101 kept_sites=75717 dropped_sites=25393 conflict_offsets=50 overlaps=167 misaligned=4 union_candidates=27
0x000: chosen 2u n=367; losers: 4s n=25@0x000, 4p n=10@0x000, 2s n=38@0x000, 1u n=24@0x000, 1u n=11@0x001; resolution: split0x001: chosen none (inside 2u@0x000); losers listed there; resolution: split0x002: chosen 2s n=3260; losers: 2u n=2271@0x002, 1u n=7@0x002, 1u n=9@0x003; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x004: chosen 2s n=61; losers: 4s n=1376@0x004, 4u n=538@0x004, 2u n=26@0x004, 1s n=2@0x004; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x006: chosen 2u n=1597; losers: 2s n=696@0x006; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x008: chosen 2u n=480; losers: 4s n=466@0x008, 4u n=9@0x008, 2s n=36@0x008; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x00C: chosen 2u n=470; losers: 4s n=399@0x00C, 4u n=6@0x00C, 2s n=22@0x00C, 1u n=16@0x00C, 1u n=12@0x00D; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x010: chosen 2u n=1925; losers: 4s n=2139@0x010, 4u n=8@0x010, 4p n=3@0x010, 2s n=935@0x010; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x012: chosen 2u n=4483; losers: 2s n=2789@0x012; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x014: chosen 4s n=1156; losers: 4u n=13@0x014, 2s n=416@0x014, 2u n=310@0x014, 2s n=280@0x016; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x018: chosen 2u n=1062; losers: 4s n=2122@0x018, 4u n=13@0x018, 2s n=778@0x018; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x01C: chosen 4s n=7913; losers: 4u n=59@0x01C, 2s n=306@0x01C, 2u n=160@0x01C, 1u n=5@0x01C, 2s n=133@0x01E, 1s n=1@0x01F; resolution: split0x020: chosen 4s n=13163; losers: 4u n=73@0x020, 4p n=389@0x020, 1u n=6@0x020, 1u n=8@0x021, 1u n=12@0x022, 1u n=5@0x023; resolution: split0x024: chosen 1u n=10; losers: 4s n=111@0x024, 4u n=1@0x024, 4p n=7@0x024, 2s n=5@0x024, 2u n=1@0x024; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x026: chosen 1u n=11; losers: 2s n=5@0x026, 2u n=3@0x026; resolution: split0x028: chosen 2s n=26; losers: 4s n=31@0x028, 4u n=3@0x028, 2u n=20@0x028, 1u n=1@0x028; resolution: split0x02C: chosen 2u n=728; losers: 4s n=141@0x02C, 4u n=5@0x02C, 4p n=15@0x02C, 2s n=87@0x02C; resolution: split0x030: chosen 4s n=31; losers: 2s n=7@0x030, 2u n=18@0x030, 2s n=11@0x032; resolution: split0x034: chosen 2u n=2952; losers: 4s n=46@0x034, 4u n=8@0x034, 4p n=4@0x034, 2s n=804@0x034; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x038: chosen 2s n=1; losers: 4s n=175@0x038, 2u n=1@0x038; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x03E: chosen 2u n=352; losers: 4s n=125@0x03C; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x042: chosen 2u n=352; losers: 4s n=176@0x040; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x044: chosen 4s n=46; losers: 2u n=8@0x044; resolution: split0x048: chosen 4s n=418; losers: 2u n=13@0x04A; resolution: split0x050: chosen 4s n=126; losers: 2s n=7@0x050, 2u n=13@0x050, 2s n=48@0x052; resolution: split0x05C: chosen 2u n=947; losers: 4s n=1@0x05C, 2s n=531@0x05C; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x05E: chosen 1u n=295; losers: 2s n=138@0x05E, 2u n=234@0x05E; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x070: chosen 2s n=1813; losers: 4s n=1@0x070, 2u n=938@0x070, 1s n=4@0x070, 1u n=12@0x070; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x080: chosen 2s n=292; losers: 4s n=94@0x080, 4u n=3@0x080, 4p n=22@0x080, 2u n=26@0x080; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0CC: chosen 4s n=1172; losers: 4u n=23@0x0CC, 4p n=269@0x0CC, 2s n=2@0x0CC, 2u n=5@0x0CC, 2u n=5@0x0CE; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0D0: chosen 4s n=464; losers: 4p n=75@0x0D0, 2s n=2@0x0D0, 2u n=7@0x0D0, 2s n=3@0x0D2; resolution: split0x0D4: chosen 4s n=184; losers: 4p n=24@0x0D4, 2u n=5@0x0D4, 2u n=5@0x0D6; resolution: split0x0D8: chosen 4s n=93; losers: 4p n=12@0x0D8, 2s n=2@0x0D8, 2u n=5@0x0D8; resolution: split0x0DC: chosen 4s n=487; losers: 4u n=7@0x0DC, 4p n=79@0x0DC, 2s n=155@0x0DC, 2u n=76@0x0DC, 2s n=105@0x0DE; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0E0: chosen 4s n=511; losers: 4u n=283@0x0E0, 2s n=69@0x0E0, 2u n=52@0x0E0, 2u n=74@0x0E2; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0E4: chosen 4s n=282; losers: 4u n=6@0x0E4, 2s n=46@0x0E4, 2u n=55@0x0E4, 2u n=40@0x0E6; resolution: split0x0E8: chosen 4s n=313; losers: 4u n=58@0x0E8, 2s n=65@0x0E8, 2u n=10@0x0E8, 2s n=58@0x0EA; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0EC: chosen 2s n=36; losers: 4s n=43@0x0EC, 4u n=1@0x0EC, 4p n=1@0x0EC, 2u n=6@0x0EC, 1u n=5@0x0EC, 1u n=5@0x0ED; resolution: split0x0EE: chosen 2s n=17; losers: 2u n=5@0x0EE, 1u n=5@0x0EE; resolution: split0x0F0: chosen 1u n=5; losers: 4s n=22@0x0F0, 2s n=5@0x0F0; resolution: split0x0F2: chosen 2u n=16; losers: 2s n=6@0x0F2, 1u n=5@0x0F2; resolution: split0x0F4: chosen 4s n=35; losers: 4p n=1@0x0F4, 2s n=26@0x0F4, 2u n=17@0x0F4, 1u n=5@0x0F4, 1u n=5@0x0F5, 2s n=8@0x0F6, 2u n=7@0x0F6, 1u n=6@0x0F6; resolution: split0x0F6: chosen none (inside 4s@0x0F4); losers listed there; resolution: split0x0F8: chosen 4s n=21; losers: 4p n=5@0x0F8, 2s n=9@0x0F8, 2u n=8@0x0F8, 1u n=5@0x0F8, 1u n=5@0x0F9, 2s n=5@0x0FA, 2u n=3@0x0FA, 1u n=5@0x0FA; resolution: split0x0FA: chosen none (inside 4s@0x0F8); losers listed there; resolution: split0x0FC: chosen 2s n=1922; losers: 4s n=5@0x0FC, 2u n=740@0x0FC, 1u n=31@0x0FC, 1u n=4@0x0FD; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x0FE: chosen 2s n=1470; losers: 2u n=690@0x0FE, 1u n=7@0x0FE, 1u n=4@0x0FF; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x100: chosen 2s n=691; losers: 4u n=8@0x100, 2u n=588@0x100, 1u n=5@0x100, 1u n=2@0x101; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x102: chosen 2s n=364; losers: 2u n=280@0x102, 1s n=4@0x102, 1u n=17@0x102, 1u n=2@0x103; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x104: chosen 2s n=311; losers: 1u n=6@0x105; resolution: split0x108: chosen 2u n=173; losers: 2s n=166@0x108, 1u n=36@0x108, 1u n=21@0x109; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split
Unkstruct_80126B58
fields=152 kept_sites=61599 dropped_sites=1713 conflict_offsets=50 overlaps=71 misaligned=5 union_candidates=4
0x004: chosen 2u n=5; losers: 4s n=12@0x004; resolution: split0x006: chosen 2s n=237; losers: 2u n=178@0x006; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x008: chosen 2u n=5; losers: 4s n=15@0x008; resolution: split0x00C: chosen 2u n=5; losers: 4s n=13@0x00C; resolution: split0x010: chosen 4s n=464; losers: 4p n=2@0x010, 2s n=10@0x010, 2u n=283@0x010, 2u n=22@0x012; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x014: chosen 4s n=440; losers: 4u n=2@0x014, 2u n=6@0x014, 2u n=6@0x016; resolution: split0x018: chosen 4s n=438; losers: 4u n=2@0x018, 2u n=8@0x018, 2u n=8@0x01A; resolution: split0x024: chosen 2s n=20; losers: 4s n=142@0x024, 2u n=2@0x024; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split0x028: chosen 4s n=12; losers: 2s n=11@0x028, 2u n=1@0x028, 1u n=2@0x028; resolution: split0x02C: chosen 4s n=4448; losers: 4u n=8@0x02C, 2s n=3@0x02C, 2s n=135@0x02E; resolution: split0x030: chosen 4s n=171; losers: 4u n=4@0x030, 1u n=2@0x030; resolution: split0x044: chosen 4u n=1744; losers: 4s n=331@0x044, 2s n=1@0x044, 2s n=1@0x046; resolution: split0x04D: chosen 1u n=13; losers: 4s n=49@0x04C; resolution: split0x054: chosen 4s n=2151; losers: 1u n=4@0x054; resolution: split0x058: chosen 4s n=2145; losers: 4u n=1@0x058, 4p n=6@0x058, 2s n=6@0x058, 2u n=4@0x058, 1u n=3@0x058, 1u n=3@0x059, 2s n=7@0x05A, 2u n=5@0x05A, 1u n=3@0x05A, 1u n=1@0x05B; resolution: split0x05A: chosen none (inside 4s@0x058); losers listed there; resolution: split0x05C: chosen 4s n=404; losers: 2s n=3@0x05C, 2u n=1@0x05C, 1u n=3@0x05C, 1u n=3@0x05D, 2s n=2@0x05E, 2u n=1@0x05E, 1u n=3@0x05E, 1u n=1@0x05F; resolution: split0x05E: chosen none (inside 4s@0x05C); losers listed there; resolution: split0x060: chosen 2u n=72; losers: 4s n=1@0x060, 2s n=38@0x060; resolution: split0x066: chosen 2u n=10; losers: 1u n=2@0x067; resolution: split0x0AE: chosen 2u n=14; losers: 2s n=1@0x0AE, 1u n=4@0x0AE; resolution: split0x0FC: chosen 2s n=3; losers: 4u n=2@0x0FC; resolution: split0x204: chosen 4s n=26; losers: 2s n=3@0x206; resolution: split0x208: chosen 4s n=4; losers: 2u n=1@0x20A; resolution: split0x20C: chosen 2s n=28; losers: 2u n=21@0x20C, 1s n=1@0x20C, 1u n=11@0x20C, 1s n=4@0x20D; resolution: split0x218: chosen 1u n=3; losers: 4s n=1@0x218; resolution: split0x234: chosen 4s n=5937; losers: 4u n=1@0x234, 2u n=6@0x234, 2u n=138@0x236; resolution: split0x238: chosen 4s n=1475; losers: 4u n=2@0x238, 2u n=2@0x238, 2u n=2@0x23A; resolution: split0x240: chosen 4s n=274; losers: 2u n=4@0x240; resolution: split0x244: chosen 2u n=409; losers: 2s n=142@0x244, 1s n=1@0x244, 1u n=5@0x244, 1s n=1@0x245; resolution: union-candidate (deferred: rewriter spells flat members only, restruct.py member_spelling) -> split