Decompile 42 functions in world.c and type the chunk/triangle records - #134
Conversation
Xeeynamo
left a comment
There was a problem hiding this comment.
Most changes are required based on the new style guide:
https://github.com/Xeeynamo/ff7-decomp/blob/main/STYLE.md
| s32 col; | ||
| s16 idx; | ||
|
|
||
| if (D_800E5814 == 0 && D_800E5810 != NULL) { |
There was a problem hiding this comment.
| if (D_800E5814 == 0 && D_800E5810 != NULL) { | |
| if (D_800E5814 == 0 && D_800E5810 != NULL) { | |
| return; | |
| } |
early return?
| s16 idx; | ||
|
|
||
| if (D_800E5814 == 0 && D_800E5810 != NULL) { | ||
| if (TryAcquireLoadSlot(0) != 0) { |
| if (c != NULL) { | ||
| do { | ||
| if ((((c->z >> 2) * 9) + (c->x >> 2)) == arg0->unk4) { | ||
| func_800A5AD8(c); | ||
| } | ||
| c = c->next; | ||
| } while (c != NULL); | ||
| } |
There was a problem hiding this comment.
| if (c != NULL) { | |
| do { | |
| if ((((c->z >> 2) * 9) + (c->x >> 2)) == arg0->unk4) { | |
| func_800A5AD8(c); | |
| } | |
| c = c->next; | |
| } while (c != NULL); | |
| } | |
| while (c != NULL) { | |
| if ((((c->z >> 2) * 9) + (c->x >> 2)) == arg0->unk4) { | |
| func_800A5AD8(c); | |
| } | |
| c = c->next; | |
| } |
| if (chunk != NULL) { | ||
| do { |
There was a problem hiding this comment.
| if (chunk != NULL) { | |
| do { | |
| while (chunk != NULL) { |
this is also a while loop
| WorldChunkHeader* chunk; | ||
|
|
||
| chunk = D_80109D3C; | ||
| if (chunk != NULL) { |
There was a problem hiding this comment.
| if (chunk != NULL) { |
isn't this if unnecessary for the match?
| WorldChunkHeader* chunk; | ||
| SVECTOR* verts; | ||
|
|
||
| if (arg1 != NULL) { |
| i++; | ||
| } while (i < 0x2B); |
|
|
||
| INCLUDE_ASM("asm/us/world/nonmatchings/world", func_800B6C84); | ||
| void StartStreamRead(void) { | ||
| if (D_80115A60 == 0) { |
| extern u8 D_8010CB24[]; | ||
| extern s32 D_8010D930; | ||
| extern u8* D_8010D9A4; | ||
| extern s32 D_8010D9A8; | ||
| extern s32 D_8010D9AC; | ||
| extern s32 D_8010D9B0; | ||
| extern s32 D_8010D9B4; | ||
| extern s32 D_80115A44; | ||
| extern s32 D_80115A4C; | ||
| extern s32 D_80115A54; | ||
| extern u8 D_80115A6C[]; | ||
| extern u8* D_800C80BC; | ||
| extern u32 D_8014A608; | ||
| extern s32 D_8014A610; | ||
| extern s32 D_800C74C4[][2]; | ||
| extern s32 D_80115A48; | ||
| extern s32 D_80115A5C; | ||
| void func_800B6AEC(void); | ||
| extern u8 D_800C6940; | ||
| extern u8 D_800C6A10[]; | ||
| extern MATRIX D_800C6808; | ||
| extern MATRIX D_800C6828; | ||
| extern MATRIX D_800C6848; | ||
| extern s32 D_8010CB20; | ||
| extern u8 D_800C6748[]; | ||
| extern s32 D_8010AD50; | ||
| extern u8 D_8010D9BA[]; | ||
| extern u16 D_8009D2A6; |
| extern s32 D_800C74C4[][2]; | ||
| extern s32 D_80115A48; | ||
| extern s32 D_80115A5C; | ||
| void func_800B6AEC(void); |
|
all applied, pushed as 52473e2, 15 overlays match. the D_8010B434 one was a good catch. 0x8010B47C - 0x8010B434 = 0x48, so exactly two 0x24 entries, DR_MODE at 0x0 and 0x18 unidentified after it. matched first try with two things that would not take the rewrite as-is: the triangle flag loop at 2848 is a plain the range condition at 2881 is half done. the outer test reads |
52473e2 to
973c5b2
Compare
Three list initialisers: func_800A59A0 and func_800A60D8 thread the 0x40 WorldListNode entries at D_800E582C and the 0x20 WorldChunkHeader entries at D_80109A38, and func_800B392C threads the 32 0x74-byte records at D_8010CB24 backwards from its last element. func_800A0BE4 is the bump allocator over the buffer D_800D05DC points at, taking the panic path when the 0x20800-byte arena would overflow. func_800A7EA4, func_800B5274 and func_800B667C are subsystem resets. The rest: func_800A5B88 walks the loaded chunks for the one whose 9-column grid index matches, func_800AD928 reports whether any actor still has a script running, func_800AD970 packs an actor's position, type and direction into a two-word display record, func_800AF110 picks the light and colour matrices for the current mode, func_800B65E0 drives the AKAO fade commands, func_800B6C84 and func_800B7620 handle the streamed read for slot 2 and report its timing, and func_800B7AC0 copies a name out of the table func_800A40F0 indexes. D_8009A000, D_800E582C and D_80109A38 gain real types; the two ascending free-list loops derive their &array[1] base from the array itself, so the symbols splat named there need no declaration. func_800B6AEC, func_800B6DCC and func_800BBA34 gain prototypes because their addresses are taken.
No func_ADDR left in the file's decompiled half. Most are clear from the code -- the fog ranges, the two bounded layer scrolls, the AKAO track and ambient calls, the stream state and its read. UpdateWorldMode, ResetEffectState and GetSavedParams describe what the code does rather than claim a purpose I could not pin down.
…order Rewrite the hand-expanded do/while loops as plain for and while, invert the guard conditions into early returns, drop the redundant chunk-search guard, give D_8010B434 a real struct so the draw-mode setup indexes it, and put the added externs in address order with the stray prototypes back in the prototype block.
Xeeynamo#142 named 13 of the same functions this branch did, and named 27 more that it calls; take upstream's names for all of them rather than renaming merged work. Xeeynamo#141 renamed DS_read to SysCdromStartLoadLzs.
973c5b2 to
adee19b
Compare
|
@Xeeynamo ready to merge |
… from parkedfuncs Three of the four functions parkedfuncs had beyond what PR Xeeynamo#134 shipped: InitSpritePrims needed plain array indexing over a hand-rolled byte offset, the skybox quad setup needed explicit address bindings for two new CVECTOR globals nothing had referenced before, and the shadow quad setup matched as-is. The fourth, WmLoadTxzFile (parkedfuncs called it ReadFileRetry), was a bad parked claim -- retail branches on useDsRead before calling a specifically-named SysCdromStartLoadLzs, not a function-pointer dispatch between two generic readers -- so it stays INCLUDE_ASM.
| a = &D_800C6768; | ||
| b = &D_800C676C; | ||
| do { | ||
| p = (POLY_G4*)((i * 0x24) + (s32)D_800C6770); |
There was a problem hiding this comment.
| p = (POLY_G4*)((i * 0x24) + (s32)D_800C6770); | |
| p = &D_800C6770[i]; |
with the real D_800C6770 type, the code can be simplified
| if (WmGetWmId() == mode) { | ||
| r = 0x20; | ||
| g = 0x20; | ||
| b = 0x30; | ||
| } else { | ||
| r = 0x40; | ||
| g = 0x40; | ||
| b = 0x40; | ||
| } | ||
| SetBackColor(r, g, b); |
There was a problem hiding this comment.
| if (WmGetWmId() == mode) { | |
| r = 0x20; | |
| g = 0x20; | |
| b = 0x30; | |
| } else { | |
| r = 0x40; | |
| g = 0x40; | |
| b = 0x40; | |
| } | |
| SetBackColor(r, g, b); | |
| if (WmGetWmId() == mode) { | |
| SetBackColor(0x30, 0x30, 0x30); | |
| } else { | |
| SetBackColor(0x40, 0x40, 0x40); | |
| } |
can be simplified, which also allows the removal of s32 r, g, b
| s32 inside; | ||
| s32 zoff; | ||
|
|
||
| if (D_8010CA8C == 0 || D_8010CA8C == 2 || D_8010CA8C == 3) { |
There was a problem hiding this comment.
Early return, as per https://github.com/Xeeynamo/ff7-decomp/blob/main/STYLE.md
| void WmCreateShadowPacket(u8* prims, RECT* rect) { | ||
| POLY_FT4* p; |
There was a problem hiding this comment.
| void WmCreateShadowPacket(u8* prims, RECT* rect) { | |
| POLY_FT4* p; | |
| void WmCreateShadowPacket(POLY_FT4* prims, RECT* rect) { |
can you change the type and get rid of POLY_FT4* p;?
| if (D_8010CB20 < arg0) { | ||
| D_8009A000[0] = 0x20; | ||
| D_8010CB20 = arg0; | ||
| D_8009A004[0] = 0x40; | ||
| D_8009A008[0] = arg0; | ||
| } else if (arg0 == -D_8010CB20) { | ||
| D_8010CB20 = 0; | ||
| D_8009A000[0] = 0xF1; | ||
| SystemAkaoExecute(); | ||
| D_8009A000[0] = 0xBC; | ||
| D_8009A004[0] = 0; | ||
| } else { | ||
| return; | ||
| } | ||
| SystemAkaoExecute(); |
There was a problem hiding this comment.
| if (D_8010CB20 < arg0) { | |
| D_8009A000[0] = 0x20; | |
| D_8010CB20 = arg0; | |
| D_8009A004[0] = 0x40; | |
| D_8009A008[0] = arg0; | |
| } else if (arg0 == -D_8010CB20) { | |
| D_8010CB20 = 0; | |
| D_8009A000[0] = 0xF1; | |
| SystemAkaoExecute(); | |
| D_8009A000[0] = 0xBC; | |
| D_8009A004[0] = 0; | |
| } else { | |
| return; | |
| } | |
| SystemAkaoExecute(); | |
| if (D_8010CB20 < arg0) { | |
| D_8009A000[0] = 0x20; | |
| D_8010CB20 = arg0; | |
| D_8009A004[0] = 0x40; | |
| D_8009A008[0] = arg0; | |
| SystemAkaoExecute(); | |
| } else if (arg0 == -D_8010CB20) { | |
| D_8010CB20 = 0; | |
| D_8009A000[0] = 0xF1; | |
| SystemAkaoExecute(); | |
| D_8009A000[0] = 0xBC; | |
| D_8009A004[0] = 0; | |
| SystemAkaoExecute(); | |
| } |
did you try this?
InitSpritePrims and the walk-to-tail loops become plain for/while, the tpage vsync window check drops the unsigned-subtract trick for a readable range, and func_800AA640 drops a redundant cast. Kept the (s16) cast on ExpireChunks' age compare; removing it (as asked, with a question mark) breaks the match, verified by rebuild.
|
applied the rest, pushed as a248107. InitSpritePrims and the walk to tail loops (AllocRegionNode, UpdateRegionLoad, WmGetElementWithBlockIdAndSetItFirst, IsRegionLoading, ExpireChunks, AllocChunk, WmAbortMapLoading) are plain for/while now, dropped the redundant if (x != NULL) { while (x != NULL) guards. the fade overlay vsync check lost the unsigned subtract trick for a readable range test. func_800AA640 dropped a redundant cast. kept the (s16) cast on ExpireChunks' age compare though, tried removing it and it breaks the match on rebuild. figured you meant it as a question rather than a firm ask given the wording. |
Xeeynamo
left a comment
There was a problem hiding this comment.
The comments regarding D_800C6770 have not been addressed yet.
|
D_800C6770 typed as POLY_G4, both call sites simplified. also went back through the rest of the review and found four more that hadn't actually landed: WmRestoreEntityPosAndDirFromSavemap and SetCurrentTriangle are early returns now, WmSetGteColourSettings drops r/g/b for direct SetBackColor calls, WmCreateShadowPacket takes POLY_FT4* directly, ToggleAmbientSound duplicates the SystemAkaoExecute call into each branch instead of a shared tail call. pushed as c1ffd83 and 2ebfc7d, 17 overlays match. |
42 functions in world.c, 144 down to 102.
two types came out of it. WorldTriangleRef {WorldChunkHeader* chunk;
WorldTriangle* tri; s8 unk8} lives at D_8010C83C and is what D_8010CA1C points
at, and WorldChunkNode {next; WorldChunkHeader* chunk} is the D_800E582C pool.
D_8010CA24 is a WorldChunkHeader*[20] with D_8010CA74 as the bump pointer over
it, so the bound that shows up as &D_8010CA74 in the asm is just
&D_8010CA24[20].
some existing declarations were wrong rather than missing:
sign-extends. they had only ever been written before, so nothing caught it.
WorldListNode*.
three things decided most of these, in case it saves anyone time:
drops the redundant guard, where an explicit do/while gets rotated and costs
a j and a duplicated load.
global's address inside the branch, which is where retail puts it.
reloads, since the first store may alias.
what didn't come out, left as INCLUDE_ASM:
chunk->x and chunk->z as one 32-bit word. that needs a union on
WorldChunkHeader or it's a fake match, so it's out either way.
GetGraphType() == 2 into an extra callee-saved register where retail
materialises it inline.
instructions and differ only in prologue order.
array typing can't produce.
func_800B6348, func_800B5DD8 and func_800B85D4 need structs that their
still-asm callers build, so they are left alone rather than guessed at.