diff --git a/config/arm9/overlays/ov002/delinks.txt b/config/arm9/overlays/ov002/delinks.txt index 436eb8c61..aed4b0857 100644 --- a/config/arm9/overlays/ov002/delinks.txt +++ b/config/arm9/overlays/ov002/delinks.txt @@ -115,11 +115,11 @@ src/_ZN5EnemyD2Ev.c: complete .text start:0x020aed18 end:0x020aed3c -src/_ZN5EnemyD0Ev.c: +src/_ZN5EnemyD0Ev.cpp: complete .text start:0x020aed3c end:0x020aed74 -src/_ZN5EnemyD1Ev.c: +src/_ZN5EnemyD1Ev.cpp: complete .text start:0x020aed74 end:0x020aed98 @@ -3248,6 +3248,7 @@ src/func_ov002_020d6998.cpp: .text start:0x020d6998 end:0x020d6c60 src/func_ov002_020d6c60.cpp: + complete .text start:0x020d6c60 end:0x020d6dac src/func_ov002_020d6dac.c: @@ -4651,7 +4652,7 @@ src/_ZN8PlatformD1Ev.cpp: complete .text start:0x020ee42c end:0x020ee464 -src/_ZN8PlatformD0Ev.c: +src/_ZN8PlatformD0Ev.cpp: complete .text start:0x020ee464 end:0x020ee4b0 diff --git a/config/arm9/overlays/ov002/symbols.txt b/config/arm9/overlays/ov002/symbols.txt index 4e9c25de3..ab0dd3816 100644 --- a/config/arm9/overlays/ov002/symbols.txt +++ b/config/arm9/overlays/ov002/symbols.txt @@ -1667,6 +1667,7 @@ data_ov002_021081b8 kind:data(any) addr:0x021081b8 _ZTI12dEnemyBase_c kind:data(any) addr:0x021081c0 _ZTS12dEnemyBase_c kind:data(any) addr:0x021081cc data_ov002_021081e4 kind:data(any) addr:0x021081e4 +_ZTV5Enemy kind:data(any) addr:0x021081e4 _ZTI11dCapEnemy_c kind:data(any) addr:0x02108260 _ZTS11dCapEnemy_c kind:data(any) addr:0x0210826c data_ov002_02108284 kind:data(any) addr:0x02108284 diff --git a/config/arm9/overlays/ov091/delinks.txt b/config/arm9/overlays/ov091/delinks.txt index 9427c9af1..27678018b 100644 --- a/config/arm9/overlays/ov091/delinks.txt +++ b/config/arm9/overlays/ov091/delinks.txt @@ -294,9 +294,6 @@ src/_ZN5StumpD0Ev.c: complete .text start:0x021339a8 end:0x021339fc -src/func_ov091_021339fc.c: - .text start:0x021339fc end:0x02133c6c - src/func_ov091_02133c6c.cpp: complete .text start:0x02133c6c end:0x02133d1c diff --git a/include/Actor.h b/include/Actor.h index 75d36f6f4..e3af15149 100644 --- a/include/Actor.h +++ b/include/Actor.h @@ -112,9 +112,14 @@ struct Actor : ActorDerived { s32 mHorzSpeed; /* 0x098 */ s32 mVertAccel; /* 0x09c -- fix12, negative (gravity) */ s32 mTerminalVelocity; /* 0x0a0 -- fix12, negative */ - u8 pad_0a4[0x4]; /* likely the same physics block; unproven */ + /* 0x0a4 and 0x0ac were padding "likely the same physics block; unproven". + They are real, and Enemy is the evidence: its generated header declared + both as s32 and its sources read them, so once `Enemy : Actor` they have + to exist here. Still unnamed -- what they mean is not evidenced, only + that they are Actor's and four bytes wide. */ + s32 unk_0a4; /* 0x0a4 */ s32 mVertSpeed; /* 0x0a8 */ - u8 pad_0ac[0x4]; /* likely the same physics block; unproven */ + s32 unk_0ac; /* 0x0ac */ u32 mFlags; /* 0x0b0 -- bit 0x10000 suppresses behaviour */ s32 unk_0b4; /* 0x0b4 */ s32 unk_0b8; /* 0x0b8 -- clip radius; 0 skips the camera transform */ diff --git a/include/Animation.h b/include/Animation.h index 4f38d9f1c..acfef8257 100644 --- a/include/Animation.h +++ b/include/Animation.h @@ -43,6 +43,8 @@ struct BCA_File; struct SharedFilePtr; +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct Animation { /* 0x00 is the vptr, placed implicitly by the first virtual declaration. */ u32 numFramesAndFlags; /* 0x04 - count in bits 0..29, loop flags in 30..31 */ @@ -66,6 +68,23 @@ struct Animation { /* --- static --- */ static char *LoadFile(SharedFilePtr &ptr); static void UpdateFileOffsets(BCA_File &file); + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char Animation_size_must_be_0x10[sizeof(Animation) == 0x10 ? 1 : -1]; diff --git a/include/ArrowSignRight.h b/include/ArrowSignRight.h index 944447b95..fb80ef10d 100644 --- a/include/ArrowSignRight.h +++ b/include/ArrowSignRight.h @@ -1,13 +1,44 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class ArrowSignRight: 6 matched functions, 7 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ARROWSIGNRIGHT_H #define ARROWSIGNRIGHT_H + #include "types.h" -#include "Model.h" +#include "Platform.h" #include "ShadowModel.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct ArrowSignRight : Platform { + u8 pad_31e[0x2]; + ShadowModel mShadowModel; /* 0x320 */ + u8 unk_348; /* 0x348 */ + u8 pad_349[0x33]; + u8 unk_37c; /* 0x37c */ + + /* --- vtable --- */ + virtual ~ArrowSignRight(); + + int Behavior(); + int CleanupResources(); + int Render(); +}; + +typedef char ArrowSignRight_size_must_be_0x380[sizeof(ArrowSignRight) == 0x380 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct ArrowSignRight { u8 pad_000[0xc]; u16 unk_00c; /* 0x00c */ @@ -26,12 +57,8 @@ struct ArrowSignRight { u8 unk_348; /* 0x348 */ u8 pad_349[0x33]; u8 unk_37c; /* 0x37c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ARROWSIGNRIGHT_H */ diff --git a/include/BigBrickBlock.h b/include/BigBrickBlock.h index 223e48e73..1eb6c638b 100644 --- a/include/BigBrickBlock.h +++ b/include/BigBrickBlock.h @@ -6,14 +6,9 @@ /* Derives from Platform: the destructor stores this class's vtable, then * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and - * the Model at 0xd4 before chaining to Actor. All three are Platform's. + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. * Everything this header used to restate below 0x31e was Actor's and - * Platform's. - * - * THE FIELDS AT 0x31e/0x31f ARE IN PLATFORM'S TAIL PADDING. Platform's last - * field ends at 0x31e and its size rounds to 0x320; the Itanium ABI lets a - * derived class use a non-POD base's tail padding, and the ROM does. The bytes - * settle it -- code here reads this+0x31e and reproduces. + * Platform's, and is inherited now. * * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it * is not independent evidence about the ROM. @@ -22,9 +17,9 @@ #ifdef __cplusplus struct BigBrickBlock : Platform { - u8 unk_31e; /* 0x31e - in Platform's tail padding */ - u8 unk_31f; /* 0x31f */ - u8 mEventID; /* 0x320 */ + u8 unk_31e; /* 0x31e */ + u8 unk_31f; /* 0x31f */ + u8 mEventID; /* 0x320 */ u8 pad_321[0x3]; Actor *mSwitch; /* 0x324 */ @@ -39,6 +34,32 @@ struct BigBrickBlock : Platform { typedef char BigBrickBlock_size_must_be_0x328[sizeof(BigBrickBlock) == 0x328 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +struct BigBrickBlock { + u8 pad_000[0xc]; + u16 mActorId; /* 0x00c */ + u8 pad_00e[0xc6]; + /* Model member, named by the class's own destructor calling + Model's D1 at +0x0d4 -- a relocation the ROM build + checks. Was a u8 marker. [_ZN13BigBrickBlockD1Ev.c] */ + Model mModel; /* 0x0d4 */ + u8 mMeshCollider; /* 0x124 */ + u8 pad_125[0x1f9]; + u8 unk_31e; /* 0x31e */ + u8 unk_31f; /* 0x31f */ + u8 mEventID; /* 0x320 */ + u8 pad_321[0x3]; + /* Actor * -- the ROM loads this WORD and passes it to _ZN5Actor15FindWithActorIDEjPS_ + as that function's `this`, which is an object address, so the word is a Actor *. It + says nothing about the rest of the marker's span, which stays explicit padding. Was + a u8 marker. */ + Actor *mSwitch; /* 0x324 */ +}; + #endif /* __cplusplus */ #endif /* BIGBRICKBLOCK_H */ diff --git a/include/BlendModelAnim.h b/include/BlendModelAnim.h index 4d4046eb2..9e3cf0d6e 100644 --- a/include/BlendModelAnim.h +++ b/include/BlendModelAnim.h @@ -24,6 +24,8 @@ #ifdef __cplusplus +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct BlendModelAnim : ModelAnim { Fix12i blendWeight; /* 0x64 - 0x1000 is 1.0 */ Fix12i blendStep; /* 0x68 - per-frame increment */ @@ -41,6 +43,16 @@ struct BlendModelAnim : ModelAnim { void Advance(); void SetAnim(BCA_File &animFile, int numBlendFrames, int flags, Fix12 speed, u16 startFrame); /* free function, wall 6az */ + + /* ITS OWN, TO RESOLVE AN AMBIGUITY MULTIPLE INHERITANCE CREATES. ModelAnim + derives from Model (so ModelBase) and from Animation, and both bases + declare operator delete, so an inherited one is "ambiguous access to + name found: ModelBase::operator delete and Animation::operator delete". + Declaring it here picks the same deallocator both bases name, and also + satisfies the rule in include/Actor.h that mwcc only inlines the member + when it is in the class or its immediate base. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char BlendModelAnim_size_must_be_0x70[sizeof(BlendModelAnim) == 0x70 ? 1 : -1]; diff --git a/include/BlueCoinSwitch.h b/include/BlueCoinSwitch.h index e54b4e5e1..2853bb448 100644 --- a/include/BlueCoinSwitch.h +++ b/include/BlueCoinSwitch.h @@ -1,24 +1,47 @@ -/* Hand-written from matched-function evidence: - * class BlueCoinSwitch, ov002 0x020f11b0-0x020f15fc (9 functions, no other - * class in the TU -- tu_map.py). - * - * Two names again, as with CastleWater. The symbols mangle from - * `BlueCoinSwitch`, so the struct is spelled that way; the RTTI record calls it - * `daObjBC_Switch_c` and include/daObjBC_Switch_c.h is the generated view under - * that name. Same object, and this is the header methods are defined against. - * - * It is a Platform -- Behavior and InitResources both call - * Platform::UpdateModelPosAndRotY and Platform::UpdateClsnPosAndRot on it -- so - * mPos and mAngleY sit at Actor's offsets. Written FLAT with the inherited - * slots restated, as every other generated header here is. - * - * Field NAMES are placeholders - renaming cannot change codegen. - */ #ifndef BLUECOINSWITCH_H #define BLUECOINSWITCH_H + #include "types.h" -#include "math/Matrix.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct BlueCoinSwitch : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + u16 unk_328; /* 0x328 */ + u16 unk_32a; /* 0x32a */ + u8 unk_32c; /* 0x32c */ + u8 unk_32d; /* 0x32d */ + u8 unk_32e; /* 0x32e */ + + /* --- vtable --- */ + virtual ~BlueCoinSwitch(); + + s32 Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char BlueCoinSwitch_size_must_be_0x330[sizeof(BlueCoinSwitch) == 0x330 ? 1 : -1]; + +#else +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct BlueCoinSwitch { u8 pad_000[0x8]; /* Spawn word, unpacked into two fields by InitResources: bits 0-3 become @@ -63,13 +86,8 @@ struct BlueCoinSwitch { u8 unk_32c; /* 0x32c */ u8 unk_32d; /* 0x32d */ u8 unk_32e; /* 0x32e */ -#ifdef __cplusplus - /* methods */ - s32 Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* BLUECOINSWITCH_H */ diff --git a/include/BowserFireSeaArena.h b/include/BowserFireSeaArena.h index 7dac25a5a..610aa6898 100644 --- a/include/BowserFireSeaArena.h +++ b/include/BowserFireSeaArena.h @@ -11,8 +11,7 @@ * * Two sub-objects of its own, on top of Platform's two: * - * Platform data ends 0x31e -> unk_31e - * three s16 = 0x324 -> mModel2 + * Platform 0x000 + 0x324 = 0x324 -> mModel2 * Model 0x324 + 0x050 = 0x374 -> mMovingMeshCollider2 * MovingMeshCollider 0x374 + 0x1c8 = 0x53c -> padding, then unk_56c * @@ -34,10 +33,9 @@ #include "Platform.h" struct BowserFireSeaArena : Platform { - /* Platform's data ends at 0x31e, so this class's own fields start there -- - these three, and only then mModel2 at 0x324. They were briefly declared as - Platform's; that reproduced this class either way and made StarSwitch, whose - own first s32 sits at 0x320, impossible. */ + /* THIS CLASS'S OWN, not Platform's -- Platform ends at 0x31e. They are what + push mModel2 from 0x320 to 0x324, and the first two sit in the base's + tail padding. */ s16 unk_31e; /* 0x31e */ s16 unk_320; /* 0x320 */ s16 unk_322; /* 0x322 */ diff --git a/include/CannonHatch.h b/include/CannonHatch.h index f51eada2c..17fcacdf3 100644 --- a/include/CannonHatch.h +++ b/include/CannonHatch.h @@ -1,13 +1,46 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class CannonHatch: 6 matched functions, 14 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef CANNONHATCH_H #define CANNONHATCH_H + #include "types.h" -#include "Model.h" -#include "MovingMeshCollider.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct CannonHatch : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + s32 unk_328; /* 0x328 */ + u8 unk_32c; /* 0x32c */ + u8 unk_32d; /* 0x32d */ + u8 unk_32e; /* 0x32e */ + + /* --- vtable --- */ + virtual ~CannonHatch(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char CannonHatch_size_must_be_0x330[sizeof(CannonHatch) == 0x330 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct CannonHatch { u8 pad_000[0x8]; /* 0x008..0x05c is ActorBase's, and ActorBase.h is de-bannered -- hand-reconstructed, not generated. Was one u8 @@ -45,13 +78,8 @@ struct CannonHatch { u8 unk_32c; /* 0x32c */ u8 unk_32d; /* 0x32d */ u8 unk_32e; /* 0x32e */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* CANNONHATCH_H */ diff --git a/include/ChainChompFence.h b/include/ChainChompFence.h index 6a668a4c0..9db74509c 100644 --- a/include/ChainChompFence.h +++ b/include/ChainChompFence.h @@ -1,12 +1,40 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class ChainChompFence: 6 matched functions, 4 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef CHAINCHOMPFENCE_H #define CHAINCHOMPFENCE_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct ChainChompFence : Platform { + u8 unk_31e; /* 0x31e */ + + /* --- vtable --- */ + virtual ~ChainChompFence(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char ChainChompFence_size_must_be_0x320[sizeof(ChainChompFence) == 0x320 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct ChainChompFence { u8 pad_000[0x8e]; s16 unk_08e; /* 0x08e */ @@ -17,13 +45,8 @@ struct ChainChompFence { u8 mMovingMeshCollider; /* 0x124 */ u8 pad_125[0x1f9]; u8 unk_31e; /* 0x31e */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* CHAINCHOMPFENCE_H */ diff --git a/include/CheepCheep.h b/include/CheepCheep.h index 13d099e52..32eef6a68 100644 --- a/include/CheepCheep.h +++ b/include/CheepCheep.h @@ -1,13 +1,47 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class CheepCheep: 5 matched functions, 12 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef CHEEPCHEEP_H #define CHEEPCHEEP_H + #include "types.h" +#include "Enemy.h" +#include "ModelAnim.h" #include "MovingCylinderClsnWithPos.h" #include "WithMeshClsn.h" +/* Derives from Enemy: the destructor stores this class's vtable, then the + * base's, then destroys whatever the base owns before chaining further up. + * Everything this header used to restate below 0x110 belonged to the + * chain above and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct CheepCheep : Enemy { + MovingCylinderClsnWithPos mMovingCylinderClsnWithPos;/* 0x110 */ + WithMeshClsn mWithMeshClsn; /* 0x150 */ + ModelAnim mModelAnim; /* 0x30c */ + u8 pad_370[0x4]; + s32 unk_374; /* 0x374 */ + s32 unk_378; /* 0x378 */ + s32 unk_37c; /* 0x37c */ + + /* --- vtable --- */ + virtual ~CheepCheep(); + + int Behavior(); + int InitResources(); + int Render(); +}; + +typedef char CheepCheep_size_must_be_0x380[sizeof(CheepCheep) == 0x380 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct CheepCheep { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -33,12 +67,8 @@ struct CheepCheep { s32 unk_374; /* 0x374 */ s32 unk_378; /* 0x378 */ s32 unk_37c; /* 0x37c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* CHEEPCHEEP_H */ diff --git a/include/CylinderClsn.h b/include/CylinderClsn.h index 0de68894c..0b9eca0ac 100644 --- a/include/CylinderClsn.h +++ b/include/CylinderClsn.h @@ -50,6 +50,8 @@ #ifdef __cplusplus +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct CylinderClsn { /* 0x00 is the vptr, placed implicitly by the first virtual declaration. */ Fix12i radius; /* 0x04 - Init arg 1 */ @@ -72,6 +74,23 @@ struct CylinderClsn { void Clear(); void Update(); static void Process(); + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char CylinderClsn_size_must_be_0x30[sizeof(CylinderClsn) == 0x30 ? 1 : -1]; diff --git a/include/DonutBlock.h b/include/DonutBlock.h index 64d92eb69..084839375 100644 --- a/include/DonutBlock.h +++ b/include/DonutBlock.h @@ -4,25 +4,24 @@ #include "types.h" #include "Platform.h" -/* Derives from Platform: the destructor stores this class's vtable, then - * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and - * the Model at 0xd4 before chaining to Actor. All three are Platform's. - * Everything this header used to restate below 0x31e was Actor's and - * Platform's. +/* A donut lift: stands still until ridden, then shakes, falls and respawns. * - * THE FIELDS AT 0x31e/0x31f ARE IN PLATFORM'S TAIL PADDING. Platform's last - * field ends at 0x31e and its size rounds to 0x320; the Itanium ABI lets a - * derived class use a non-POD base's tail padding, and the ROM does. The bytes - * settle it -- code here reads this+0x31e and reproduces. + * Everything this header used to declare below 0x31e was Actor's and + * Platform's, restated. It derives from Platform now, which the destructor + * evidences the usual way -- it stores DonutBlock's vtable, then Platform's, + * then destroys the MovingMeshCollider at 0x124 and the Model at 0xd4 and + * chains to Actor. Those three are Platform's own. * - * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it - * is not independent evidence about the ROM. + * unk_31e sits at 0x31e, in Platform's TAIL PADDING: Platform's last field + * ends at 0x31e and its size rounds to 0x320, and the Itanium ABI lets a + * derived class place members in a non-POD base's tail padding. Behavior reads + * this+0x31e and reproduces the ROM, which is what confirms the placement. */ #ifdef __cplusplus struct DonutBlock : Platform { - s16 unk_31e; /* 0x31e - in Platform's tail padding */ + s16 unk_31e; /* 0x31e - per-frame yaw step; see InitResources */ /* --- vtable --- */ virtual ~DonutBlock(); diff --git a/include/Enemy.h b/include/Enemy.h index a64e32f9b..62866a940 100644 --- a/include/Enemy.h +++ b/include/Enemy.h @@ -5,6 +5,7 @@ #ifndef ENEMY_H #define ENEMY_H #include "types.h" +#include "Actor.h" /* fwd */ struct CylinderClsn; @@ -24,87 +25,44 @@ struct ww_; extern "C" void _ZN6Memory10DeallocateEPvP4Heap(void *, void *); extern "C" void *data_020a0eac; -struct Enemy { - /* 0x00 is the vptr, placed implicitly by the virtual destructor declared - below. The 0x5c of padding that used to start at 0x00 therefore starts - at 0x04 and is four bytes shorter -- Enemy's 0x110 span always counted - the vptr, it just was not declared. Adding a virtual WITHOUT taking the - four bytes back pushes every field, and every member of every derived - class, four bytes late. +struct Enemy : Actor { + /* DERIVES FROM Actor, at last -- this header used to restate Actor's whole + layout, and its own note said `Enemy : Actor` was "the real fix and is + its own slice". Everything below 0x0d0 is Actor's and is inherited now; + the thirteen fields that were duplicated here resolve through Actor.h, + two of which (0x0a4, 0x0ac) were padding there until this class proved + they are real. - Enemy really inherits this vptr from ActorBase via Actor -- the fields - below 0x0d0 duplicate Actor's, as the notes in this file already say. - Declaring the destructor here is true but incomplete; `Enemy : Actor` - is the real fix and is its own slice. */ - u8 pad_004[0x4]; - s32 mParam; /* 0x008 */ - u8 pad_00c[0x50]; - s32 mPosX; /* 0x05c */ - s32 mPosY; /* 0x060 */ - s32 mPosZ; /* 0x064 */ - u8 pad_068[0x24]; - /* 0x08c-0x090 are Actor.h:91-93 mAngleX/Y/Z, the rotation triple. - Enemy::UpdateKillByInvincibleChar adds the spin rates at 0x0ec-0x0f0 to - these three in ascending order and hands the same three, in the same - order, to Matrix4x3_ApplyInPlaceToRotationZXYExt -- consistent with - Actor.h's assignment, which is the primary evidence. */ - s16 mAngleX; /* 0x08c */ - s16 mAngleY; /* 0x08e */ - s16 mAngleZ; /* 0x090 */ - u8 pad_092[0x2]; - /* 0x094 is Actor.h:95 mPrevAngleY. The ROM loads it with a signed halfword - load, which is the one thing no source pass can settle -- and 27 derived - headers already declare it s16. Was a bare u8 marker. */ - s16 mPrevAngleY; /* 0x094 */ - u8 pad_096[0x6]; - s32 unk_09c; /* 0x09c */ - s32 unk_0a0; /* 0x0a0 */ - s32 unk_0a4; /* 0x0a4 */ - /* 0x0a8 is Actor.h:99 mVertSpeed; 10 derived headers agree, both evidence - passes see 4-byte accesses. */ - s32 mVertSpeed; /* 0x0a8 */ - /* 0x0ac: no Actor field, but 6 derived headers agree and both passes see - 4-byte accesses. The marker's span ran to 0x0d4; only its first word is - evidenced, so the rest stays padding. */ - s32 unk_0ac; /* 0x0ac */ - u8 pad_0b0[0x24]; - /* Two surface normals, written a Vector3 at a time by - SurfaceInfo::CopyNormalTo in Enemy::UpdateWMClsn -- the floor result's - normal into 0x0d4, the wall result's into 0x0e0. The wall triple was - declared u8 + pad + u8, which made any natural access an ldrb; - Enemy::AngleAwayFromWallOrCliff reads X and Z of it as four-byte values - and hands them to Actor::ReflectAngle, which is what a wall normal is - for. Same shape and same names as Player.h's mFloorNormalX/Y/Z. */ + Actor is 0xd0, so Enemy's own fields start there and its 0x110 closes + exactly on the subclasses that follow it. */ + /* FIVE FIELDS BELOW WERE PADDING HERE and are named on the same kind of + evidence that took Actor's 0x0a4/0x0ac: the subclasses declare them and + read them, and `X : Enemy` cannot compile unless they exist. The counts + are how many of Enemy's 51 subclasses declare each -- 0x100 is in + twenty-eight of them, which is not a coincidence. The names stay unk_ + where the meaning is unevidenced. */ + s32 mEatingPlayer; /* 0x0d0 -- 4 subclasses */ s32 mFloorNormalX; /* 0x0d4 */ s32 mFloorNormalY; /* 0x0d8 */ s32 mFloorNormalZ; /* 0x0dc */ - s32 mWallNormalX; /* 0x0e0 */ - s32 mWallNormalY; /* 0x0e4 */ - s32 mWallNormalZ; /* 0x0e8 */ - /* Per-frame spin applied while the enemy is dying. KillByInvincibleChar - (ov002 0x020ada40) copies the three s16 of its `const Vector3_16 &` - argument straight into these slots; UpdateKillByInvincibleChar then adds - them to mAngleX/Y/Z once a frame. Named from that behaviour -- the ROM - evidences the widths and the copy, not the intent. */ - s16 mSpinRateX; /* 0x0ec */ - s16 mSpinRateY; /* 0x0ee */ - s16 mSpinRateZ; /* 0x0f0 */ - u8 pad_0f2[0x10]; - /* Death timer, counted down a frame at a time. Was s16: every read in the - tree is unsigned -- two ldrh in UpdateKillByInvincibleChar, and - UpdateDeath's DecIfAbove0_Short is `unsigned short*` in both its source - and its ROM bytes (ldrh at 0x0203adbc). No reference reads it signed, - so the declared sign was wrong rather than locally over-ridden. */ - u16 mDeathTimer; /* 0x102 */ - u8 pad_104[0x2]; - u8 unk_106; /* 0x106 */ - u8 unk_107; /* 0x107 */ - u8 pad_108[0x4]; - /* 0x10c: 4 derived headers agree, history sees 4 four-byte accesses and the - ROM two. This is the last field, so widening it grows sizeof(Enemy) by 3 -- - the only site here that is not offset-neutral. */ - s32 mDeathState; /* 0x10c */ - /* --- vtable, in ROM order. Do not reorder. --- */ + s32 mWallNormalX; /* 0x0e0 */ + s32 mWallNormalY; /* 0x0e4 */ + s32 mWallNormalZ; /* 0x0e8 */ + s16 mSpinRateX; /* 0x0ec */ + s16 mSpinRateY; /* 0x0ee */ + s16 mSpinRateZ; /* 0x0f0 */ + u8 pad_0f2[0xe]; + s16 unk_100; /* 0x100 -- 28 subclasses */ + u16 mDeathTimer; /* 0x102 */ + u16 unk_104; /* 0x104 -- 5 subclasses */ + u8 unk_106; /* 0x106 */ + u8 unk_107; /* 0x107 */ + u8 unk_108; /* 0x108 -- 10 subclasses */ + u8 pad_109[0x1]; + u8 unk_10a; /* 0x10a -- 5 subclasses */ + u8 pad_10b[0x1]; + s32 mDeathState; /* 0x10c */ + virtual ~Enemy(); /* slots 0 (D1), 1 (D0) */ /* Enemy's own copy of Actor's inline operator delete, and it has to be its diff --git a/include/FireSeaElevator.h b/include/FireSeaElevator.h index bb47ab1a6..75f065743 100644 --- a/include/FireSeaElevator.h +++ b/include/FireSeaElevator.h @@ -1,13 +1,43 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class FireSeaElevator: 6 matched functions, 6 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef FIRESEAELEVATOR_H #define FIRESEAELEVATOR_H + #include "types.h" -#include "Model.h" +#include "Platform.h" #include "MovingCylinderClsn.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct FireSeaElevator : Platform { + u8 pad_31e[0x2]; + MovingCylinderClsn mMovingCylinderClsn;/* 0x320 */ + u16 unk_354; /* 0x354 */ + + /* --- vtable --- */ + virtual ~FireSeaElevator(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char FireSeaElevator_size_must_be_0x358[sizeof(FireSeaElevator) == 0x358 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct FireSeaElevator { u8 pad_000[0x8]; s32 unk_008; /* 0x008 */ @@ -24,13 +54,8 @@ struct FireSeaElevator { checks. Was a u8 marker. [_ZN15FireSeaElevatorD1Ev.c] */ MovingCylinderClsn mMovingCylinderClsn; /* 0x320 */ u16 unk_354; /* 0x354 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* FIRESEAELEVATOR_H */ diff --git a/include/FloatingFloorLllBig.h b/include/FloatingFloorLllBig.h index fd298fc4f..deaca3d03 100644 --- a/include/FloatingFloorLllBig.h +++ b/include/FloatingFloorLllBig.h @@ -5,22 +5,19 @@ #include "Platform.h" /* Derives from Platform: the destructor stores this class's vtable, then - * Platform's -- inlined -- and then destroys the MovingMeshCollider at 0x124 - * and the Model at 0xd4 before chaining to Actor. Those three are Platform's - * and are declared there; everything this header used to restate below 0x31e - * was Actor's and Platform's. + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. * - * Any field at 0x31e or 0x31f sits in Platform's tail padding, which the - * Itanium ABI lets a derived class use because Platform is non-POD: its last - * field ends at 0x31e and its size rounds to 0x320. - * - * SIZE IS THE OBSERVED FIELD SPAN, rounded up -- not independent evidence. It - * is a regression guard on this declaration, not a claim about the ROM. + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. */ #ifdef __cplusplus struct FloatingFloorLllBig : Platform { + u8 pad_31e[0x2]; s32 unk_320; /* 0x320 */ s16 unk_324; /* 0x324 */ @@ -34,6 +31,27 @@ struct FloatingFloorLllBig : Platform { typedef char FloatingFloorLllBig_size_must_be_0x328[sizeof(FloatingFloorLllBig) == 0x328 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +struct FloatingFloorLllBig { + u8 pad_000[0x60]; + s32 mPosY; /* 0x060 */ + u8 pad_064[0x28]; + s16 mAngleX; /* 0x08c */ + s16 mAngleY; /* 0x08e */ + u8 pad_090[0x44]; + /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. + D1 and not D2, so it is this type and not an inlined base. Was a u8 marker. */ + Model mModel; /* 0x0d4 */ + u8 mMeshCollider; /* 0x124 */ + u8 pad_125[0x1fb]; + s32 unk_320; /* 0x320 */ + s16 unk_324; /* 0x324 */ +}; + #endif /* __cplusplus */ #endif /* FLOATINGFLOORLLLBIG_H */ diff --git a/include/FortressTower.h b/include/FortressTower.h index 56b6d21c4..f3df2cfbd 100644 --- a/include/FortressTower.h +++ b/include/FortressTower.h @@ -1,12 +1,40 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class FortressTower: 6 matched functions, 3 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef FORTRESSTOWER_H #define FORTRESSTOWER_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct FortressTower : Platform { + /* no fields of its own */ + + /* --- vtable --- */ + virtual ~FortressTower(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char FortressTower_size_must_be_0x320[sizeof(FortressTower) == 0x320 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct FortressTower { u8 pad_000[0xc]; u16 unk_00c; /* 0x00c */ @@ -15,13 +43,8 @@ struct FortressTower { D1 and not D2, so it is this type and not an inlined base. Was a u8 marker. */ Model mModel; /* 0x0d4 */ u8 mMovingMeshCollider; /* 0x124 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* FORTRESSTOWER_H */ diff --git a/include/FortressWall.h b/include/FortressWall.h index 8dad08bf5..9107c6982 100644 --- a/include/FortressWall.h +++ b/include/FortressWall.h @@ -6,14 +6,9 @@ /* Derives from Platform: the destructor stores this class's vtable, then * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and - * the Model at 0xd4 before chaining to Actor. All three are Platform's. + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. * Everything this header used to restate below 0x31e was Actor's and - * Platform's. - * - * THE FIELDS AT 0x31e/0x31f ARE IN PLATFORM'S TAIL PADDING. Platform's last - * field ends at 0x31e and its size rounds to 0x320; the Itanium ABI lets a - * derived class use a non-POD base's tail padding, and the ROM does. The bytes - * settle it -- code here reads this+0x31e and reproduces. + * Platform's, and is inherited now. * * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it * is not independent evidence about the ROM. @@ -22,11 +17,11 @@ #ifdef __cplusplus struct FortressWall : Platform { - u8 unk_31e; /* 0x31e - in Platform's tail padding */ - u8 unk_31f; /* 0x31f */ + u8 unk_31e; /* 0x31e */ + u8 unk_31f; /* 0x31f */ u8 pad_320[0x1]; - u8 unk_321; /* 0x321 */ - u8 unk_322; /* 0x322 */ + u8 unk_321; /* 0x321 */ + u8 unk_322; /* 0x322 */ /* --- vtable --- */ virtual ~FortressWall(); @@ -39,6 +34,49 @@ struct FortressWall : Platform { typedef char FortressWall_size_must_be_0x324[sizeof(FortressWall) == 0x324 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +struct FortressWall { + u8 pad_000[0x8]; + s32 mParam; /* 0x008 */ + u16 mActorID; /* 0x00c */ + u8 pad_00e[0x4e]; + /* Actor::mPosX -- Actor.h declares s32 here, and it is de-bannered (hand-reconstructed). */ + s32 unk_05c; /* 0x05c */ + /* Actor::mPosY -- Actor.h declares s32 here, and it is de-bannered (hand-reconstructed). */ + s32 unk_060; /* 0x060 */ + /* 0x064..0x08e is Actor's, and Actor.h is de-bannered -- hand-reconstructed, not generated. Was one u8 + marker over the whole range. */ + s32 unk_064; /* 0x064 */ + s32 unk_068; /* 0x068 */ + s32 unk_06c; /* 0x06c */ + s32 unk_070; /* 0x070 */ + s32 mCamSpacePosX; /* 0x074 */ + s32 mCamSpacePosY; /* 0x078 */ + s32 mCamSpacePosZ; /* 0x07c */ + s32 mScaleX; /* 0x080 */ + s32 mScaleY; /* 0x084 */ + s32 mScaleZ; /* 0x088 */ + s16 mAngleX; /* 0x08c */ + s16 mAngleY; /* 0x08e */ + u8 pad_090[0x3c]; + u8 mAreaId; /* 0x0cc */ + u8 pad_0cd[0x7]; + /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. + D1 and not D2, so it is this type and not an inlined base. Was a u8 marker. */ + Model mModel; /* 0x0d4 */ + u8 mMeshCollider; /* 0x124 */ + u8 pad_125[0x1f9]; + u8 unk_31e; /* 0x31e */ + u8 unk_31f; /* 0x31f */ + u8 pad_320[0x1]; + u8 unk_321; /* 0x321 */ + u8 unk_322; /* 0x322 */ +}; + #endif /* __cplusplus */ #endif /* FORTRESSWALL_H */ diff --git a/include/Heap.h b/include/Heap.h index 249fad0b8..2eddbfed0 100644 --- a/include/Heap.h +++ b/include/Heap.h @@ -138,6 +138,8 @@ struct Heap { u32 flags; /* 0x10 */ }; #else +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct Heap { void* heapStart; /* 0x04 -- first byte of the arena this heap hands out; for a root heap it is the heap @@ -250,6 +252,20 @@ struct Heap { 0x30 bytes for the solid one, 0x4c for the expanding one. */ static struct SolidHeapAllocator* CreateSolidHeapAllocator(void* address, u32 size, u32 flags); static struct ExpandingHeapAllocator* CreateExpandingHeapAllocator(void* address, u32 size, u32 flags); + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + Without it the compiler emits the global `_ZdlPv`, which exists nowhere + in this image, and D0 comes out one relocated word different from the + ROM -- a difference build_pin.verify CANNOT SEE, because it wildcards + relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2; Actor's copy of + this member calls Memory::Deallocate instead, which is why each family + needs its own. Inline and in the IMMEDIATE base: mwcc inlines it only + when it finds it in the class or one level up (see include/Actor.h). + No layout effect. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; #endif diff --git a/include/HugeCover.h b/include/HugeCover.h index 25b9e9c0d..40f1551e2 100644 --- a/include/HugeCover.h +++ b/include/HugeCover.h @@ -1,12 +1,42 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class HugeCover: 6 matched functions, 5 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef HUGECOVER_H #define HUGECOVER_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "TextureTransformer.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct HugeCover : Platform { + u8 pad_31e[0x2]; + TextureTransformer mTextureTransformer;/* 0x320 */ + + /* --- vtable --- */ + virtual ~HugeCover(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char HugeCover_size_must_be_0x334[sizeof(HugeCover) == 0x334 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct HugeCover { u8 pad_000[0xd4]; /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. @@ -19,13 +49,8 @@ struct HugeCover { u8 mTextureTransformer; /* 0x320 */ u8 pad_321[0xb]; s32 unk_32c; /* 0x32c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* HUGECOVER_H */ diff --git a/include/IceBlock.h b/include/IceBlock.h index bde680c8a..afcfdd1e0 100644 --- a/include/IceBlock.h +++ b/include/IceBlock.h @@ -1,12 +1,48 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class IceBlock: 6 matched functions, 14 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ICEBLOCK_H #define ICEBLOCK_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "MovingCylinderClsn.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct IceBlock : Platform { + u8 pad_31e[0x2]; + MovingCylinderClsn mMovingCylinderClsn;/* 0x320 */ + u8 unk_354; /* 0x354 */ + u8 pad_355[0x3]; + s32 mScale; /* 0x358 */ + u32 unk_35c; /* 0x35c */ + u32 unk_360; /* 0x360 */ + u8 unk_364; /* 0x364 */ + /* --- vtable --- */ + virtual ~IceBlock(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char IceBlock_size_must_be_0x368[sizeof(IceBlock) == 0x368 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct IceBlock { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -32,13 +68,8 @@ struct IceBlock { u32 unk_35c; /* 0x35c */ u32 unk_360; /* 0x360 */ u8 unk_364; /* 0x364 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ICEBLOCK_H */ diff --git a/include/IceSheet.h b/include/IceSheet.h index 86defc7d9..c90d7927c 100644 --- a/include/IceSheet.h +++ b/include/IceSheet.h @@ -1,12 +1,40 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class IceSheet: 6 matched functions, 3 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ICESHEET_H #define ICESHEET_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct IceSheet : Platform { + /* no fields of its own */ + + /* --- vtable --- */ + virtual ~IceSheet(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char IceSheet_size_must_be_0x320[sizeof(IceSheet) == 0x320 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct IceSheet { u8 pad_000[0x8e]; s16 unk_08e; /* 0x08e */ @@ -15,13 +43,8 @@ struct IceSheet { D1 and not D2, so it is this type and not an inlined base. Was a u8 marker. */ Model mModel; /* 0x0d4 */ u8 mMovingMeshCollider; /* 0x124 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ICESHEET_H */ diff --git a/include/KingBobOmb.h b/include/KingBobOmb.h index e26400118..a91c161b3 100644 --- a/include/KingBobOmb.h +++ b/include/KingBobOmb.h @@ -1,15 +1,67 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class KingBobOmb: 5 matched functions, 27 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef KINGBOBOMB_H #define KINGBOBOMB_H + #include "types.h" +#include "Enemy.h" #include "BlendModelAnim.h" -#include "WithMeshClsn.h" -#include "MovingCylinderClsnWithPos.h" #include "CommonModel.h" +#include "MovingCylinderClsnWithPos.h" +#include "ShadowModel.h" +#include "WithMeshClsn.h" + +/* Derives from Enemy: the destructor stores this class's vtable, then the + * base's, then destroys whatever the base owns before chaining further up. + * Everything this header used to restate below 0x110 belonged to the + * chain above and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct KingBobOmb : Enemy { + WithMeshClsn mWithMeshClsn; /* 0x110 */ + BlendModelAnim mBlendModelAnim; /* 0x2cc */ + MovingCylinderClsnWithPos mMovingCylinderClsnWithPos;/* 0x33c */ + MovingCylinderClsnWithPos mMovingCylinderClsnWithPos_37c;/* 0x37c */ + CommonModel mCommonModel; /* 0x3bc */ + ShadowModel mShadowModel; /* 0x3f8 */ + u8 pad_420[0x74]; + s32 unk_494; /* 0x494 */ + u8 unk_498; /* 0x498 */ + u8 pad_499[0x7]; + s32 unk_4a0; /* 0x4a0 */ + u8 pad_4a4[0x30]; + s32 unk_4d4; /* 0x4d4 */ + s32 unk_4d8; /* 0x4d8 */ + s32 unk_4dc; /* 0x4dc */ + s32 unk_4e0; /* 0x4e0 */ + s32 unk_4e4; /* 0x4e4 */ + s32 unk_4e8; /* 0x4e8 */ + u8 pad_4ec[0x10]; + s32 unk_4fc; /* 0x4fc */ + s32 unk_500; /* 0x500 */ + u8 pad_504[0x3]; + u8 unk_507; /* 0x507 */ + u8 pad_508[0x1]; + u8 unk_509; /* 0x509 */ + /* --- vtable --- */ + virtual ~KingBobOmb(); + + int Behavior(); + int InitResources(); + int Render(); +}; + +typedef char KingBobOmb_size_must_be_0x50c[sizeof(KingBobOmb) == 0x50c ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct KingBobOmb { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -75,12 +127,8 @@ struct KingBobOmb { u8 unk_507; /* 0x507 */ u8 pad_508[0x1]; u8 unk_509; /* 0x509 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* KINGBOBOMB_H */ diff --git a/include/KnockDownPlank.h b/include/KnockDownPlank.h index c1d8534e5..1edfe3bed 100644 --- a/include/KnockDownPlank.h +++ b/include/KnockDownPlank.h @@ -1,12 +1,44 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class KnockDownPlank: 6 matched functions, 11 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef KNOCKDOWNPLANK_H #define KNOCKDOWNPLANK_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct KnockDownPlank : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + s32 unk_328; /* 0x328 */ + s32 mVariant; /* 0x32c */ + + /* --- vtable --- */ + virtual ~KnockDownPlank(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char KnockDownPlank_size_must_be_0x330[sizeof(KnockDownPlank) == 0x330 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct KnockDownPlank { u8 pad_000[0xc]; /* 0x00c..0x05c is ActorBase's, and ActorBase.h is de-bannered -- hand-reconstructed, not generated. Was one u8 @@ -50,13 +82,8 @@ struct KnockDownPlank { s32 unk_324; /* 0x324 */ s32 unk_328; /* 0x328 */ s32 mVariant; /* 0x32c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* KNOCKDOWNPLANK_H */ diff --git a/include/MeshCollider.h b/include/MeshCollider.h index 22afa018d..ac0b47272 100644 --- a/include/MeshCollider.h +++ b/include/MeshCollider.h @@ -70,6 +70,8 @@ struct KCL_File { u32 zShift; /* 0x34 */ }; +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct MeshCollider : MeshColliderBase { KCL_File *kclFile; /* 0x20 */ u32 clps; /* 0x24 - set via func_0203821c, released via func_02038224 */ @@ -123,6 +125,23 @@ struct MeshCollider : MeshColliderBase { /* --- static --- */ static char *LoadFile(SharedFilePtr &ptr); static void UpdateFileOffsets(KCL_File &file); + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char MeshCollider_size_must_be_0x50[sizeof(MeshCollider) == 0x50 ? 1 : -1]; diff --git a/include/MetalNet.h b/include/MetalNet.h index 742c5d6c9..189fbf7fd 100644 --- a/include/MetalNet.h +++ b/include/MetalNet.h @@ -1,13 +1,40 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class MetalNet: 6 matched functions, 5 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef METALNET_H #define METALNET_H + #include "types.h" -#include "Model.h" -#include "MovingMeshCollider.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct MetalNet : Platform { + /* no fields of its own */ + + /* --- vtable --- */ + virtual ~MetalNet(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char MetalNet_size_must_be_0x320[sizeof(MetalNet) == 0x320 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct MetalNet { u8 pad_000[0x8]; s32 unk_008; /* 0x008 */ @@ -22,13 +49,8 @@ struct MetalNet { checks. Was a u8 marker. [_ZN8MetalNetD1Ev.c] */ MovingMeshCollider mMovingMeshCollider; /* 0x124 */ u8 unk_2ec; /* 0x2ec */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* METALNET_H */ diff --git a/include/ModelAnim.h b/include/ModelAnim.h index e4592beb1..b6ad7df5a 100644 --- a/include/ModelAnim.h +++ b/include/ModelAnim.h @@ -64,6 +64,8 @@ #ifdef __cplusplus +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct ModelAnim : Model, Animation { BCA_File *file; /* 0x60 */ @@ -78,6 +80,16 @@ struct ModelAnim : Model, Animation { void SetAnim(BCA_File *animFile, int flags, Fix12 speed, u32 startFrame); /* defined as a free function, wall 6az */ void Copy(const ModelAnim &src, char *newFile); + + /* ITS OWN, TO RESOLVE AN AMBIGUITY MULTIPLE INHERITANCE CREATES. ModelAnim + derives from Model (so ModelBase) and from Animation, and both bases + declare operator delete, so an inherited one is "ambiguous access to + name found: ModelBase::operator delete and Animation::operator delete". + Declaring it here picks the same deallocator both bases name, and also + satisfies the rule in include/Actor.h that mwcc only inlines the member + when it is in the class or its immediate base. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char ModelAnim_size_must_be_0x64[sizeof(ModelAnim) == 0x64 ? 1 : -1]; diff --git a/include/ModelAnim2.h b/include/ModelAnim2.h index e49ed0568..d0e31b9a0 100644 --- a/include/ModelAnim2.h +++ b/include/ModelAnim2.h @@ -21,6 +21,8 @@ #ifdef __cplusplus +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct ModelAnim2 : ModelAnim { u32 otherFile; /* 0x64 - the second animation's BCA, stored as a word */ Animation otherAnim; /* 0x68 - a member, built with Animation::C1 */ @@ -32,6 +34,16 @@ struct ModelAnim2 : ModelAnim { void Copy(const ModelAnim2 &src, char *newFile, u32 newOtherFile); void Func_020162C4(u32 animFile, int flags, Fix12 speed, u16 startFrame); /* free function, wall 6az */ + + /* ITS OWN, TO RESOLVE AN AMBIGUITY MULTIPLE INHERITANCE CREATES. ModelAnim + derives from Model (so ModelBase) and from Animation, and both bases + declare operator delete, so an inherited one is "ambiguous access to + name found: ModelBase::operator delete and Animation::operator delete". + Declaring it here picks the same deallocator both bases name, and also + satisfies the rule in include/Actor.h that mwcc only inlines the member + when it is in the class or its immediate base. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char ModelAnim2_size_must_be_0x78[sizeof(ModelAnim2) == 0x78 ? 1 : -1]; diff --git a/include/ModelBase.h b/include/ModelBase.h index c7a32dcd5..8e970b204 100644 --- a/include/ModelBase.h +++ b/include/ModelBase.h @@ -78,6 +78,8 @@ struct ModelComponents { void Render(Matrix4x3 *mat, Vector3 *scale); /* 0x020443c8 */ }; +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct ModelBase { /* 0x00 is the vptr, placed implicitly by the first virtual declaration. */ BMD_File *modelFile; /* 0x04 - owned; the destructors Deallocate it */ @@ -89,6 +91,23 @@ struct ModelBase { /* --- non-virtual --- */ void SetFile(BMD_File *file, int a, int b); /* dispatches DoSetFile */ void ApplyOpacity(u32 a); + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char ModelComponents_size_must_be_0x14[sizeof(ModelComponents) == 0x14 ? 1 : -1]; diff --git a/include/MovingBarSmall.h b/include/MovingBarSmall.h index 102670f3a..9715af52b 100644 --- a/include/MovingBarSmall.h +++ b/include/MovingBarSmall.h @@ -1,12 +1,50 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class MovingBarSmall: 6 matched functions, 21 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef MOVINGBARSMALL_H #define MOVINGBARSMALL_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "ShadowModel.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct MovingBarSmall : Platform { + u8 pad_31e[0x2]; + ShadowModel mShadowModel; /* 0x320 */ + u8 pad_348[0x30]; + s32 unk_378; /* 0x378 */ + s32 unk_37c; /* 0x37c */ + s32 unk_380; /* 0x380 */ + s32 unk_384; /* 0x384 */ + s32 unk_388; /* 0x388 */ + s32 unk_38c; /* 0x38c */ + u8 unk_390; /* 0x390 */ + u8 unk_391; /* 0x391 */ + u8 unk_392; /* 0x392 */ + + /* --- vtable --- */ + virtual ~MovingBarSmall(); + + int CleanupResources(); + int Render(); +}; + +typedef char MovingBarSmall_size_must_be_0x394[sizeof(MovingBarSmall) == 0x394 ? 1 : -1]; + +#else +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct MovingBarSmall { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -41,11 +79,8 @@ struct MovingBarSmall { u8 unk_390; /* 0x390 */ u8 unk_391; /* 0x391 */ u8 unk_392; /* 0x392 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* MOVINGBARSMALL_H */ diff --git a/include/MovingCylinderClsn.h b/include/MovingCylinderClsn.h index 8cfc572d4..ce5092920 100644 --- a/include/MovingCylinderClsn.h +++ b/include/MovingCylinderClsn.h @@ -36,6 +36,8 @@ struct Actor; +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct MovingCylinderClsn : CylinderClsn { Actor *owner; /* 0x30 - nulled by C2 */ @@ -43,6 +45,23 @@ struct MovingCylinderClsn : CylinderClsn { virtual ~MovingCylinderClsn(); /* slots 0 (D1), 1 (D0) */ virtual Vector3 &GetPos(); /* slot 2 - the owner's pos, not ours */ virtual u32 GetOwnerID(); /* slot 3 - owner->uniqueID */ + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char MovingCylinderClsn_size_must_be_0x34[ diff --git a/include/MovingMeshCollider.h b/include/MovingMeshCollider.h index 7af21e595..c0e787784 100644 --- a/include/MovingMeshCollider.h +++ b/include/MovingMeshCollider.h @@ -27,6 +27,8 @@ #include "math/Fix12.h" +extern "C" void _ZN6Memory16operator_delete2EPv(void *); + struct MovingMeshCollider : MeshCollider { Fix12i scale; /* 0x50 */ Matrix4x3 mat; /* 0x54 */ @@ -62,6 +64,23 @@ struct MovingMeshCollider : MeshCollider { void SetFile(KCL_File *file, const Matrix4x3 &mat, Fix12 scale, s16 angY, CLPS_Block &clps); /* free def, wall 6az */ void Transform(const Matrix4x3 &mat, s16 angY); /* free def for now */ + + /* WHAT LETS A REAL `~Class()` REPRODUCE THE ROM'S DELETING DESTRUCTOR. + The compiler generates D0 as "run the destructor body, then call operator + delete on the class". Without this it emits the global `_ZdlPv`, which + exists nowhere in this image, and the D0 comes out one relocated word + different from the ROM -- a difference build_pin.verify CANNOT SEE, + because it wildcards relocated words. Only the link catches it. + + This family deallocates through Memory::operator_delete2, not the actor + heap: every D0 below ends with a call to 0x0203cbcc. Actor's copy of this + member calls Memory::Deallocate instead, which is why each needs its own. + + Inline, and in the IMMEDIATE base -- mwcc inlines it only when it finds it + in the class or one level up, as include/Actor.h records. No layout + effect: a non-virtual inline member adds no field and no vtable slot. */ + void operator delete(void *ptr) { _ZN6Memory16operator_delete2EPv(ptr); } + }; typedef char MovingMeshCollider_size_must_be_0x1c8[sizeof(MovingMeshCollider) == 0x1c8 ? 1 : -1]; diff --git a/include/MrBlizzard.h b/include/MrBlizzard.h index d27678cfb..738a6eabc 100644 --- a/include/MrBlizzard.h +++ b/include/MrBlizzard.h @@ -1,14 +1,59 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class MrBlizzard: 5 matched functions, 29 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef MRBLIZZARD_H #define MRBLIZZARD_H + #include "types.h" +#include "Enemy.h" +#include "ModelAnim.h" #include "MovingCylinderClsnWithPos.h" +#include "ShadowModel.h" #include "WithMeshClsn.h" -#include "ModelAnim.h" +/* Derives from Enemy: the destructor stores this class's vtable, then the + * base's, then destroys whatever the base owns before chaining further up. + * Everything this header used to restate below 0x110 belonged to the + * chain above and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct MrBlizzard : Enemy { + MovingCylinderClsnWithPos mMovingCylinderClsnWithPos;/* 0x110 */ + WithMeshClsn mWithMeshClsn; /* 0x150 */ + ModelAnim mModelAnim; /* 0x30c */ + ShadowModel mShadowModel; /* 0x370 */ + u8 pad_398[0x64]; + s32 unk_3fc; /* 0x3fc */ + s32 unk_400; /* 0x400 */ + u8 pad_404[0x10]; + s16 unk_414; /* 0x414 */ + u8 pad_416[0x2]; + s32 mPathId; /* 0x418 */ + s32 mType; /* 0x41c */ + s32 unk_420; /* 0x420 */ + s32 unk_424; /* 0x424 */ + u8 pad_428[0x24]; + s32 unk_44c; /* 0x44c */ + s32 unk_450; /* 0x450 */ + s32 unk_454; /* 0x454 */ + + /* --- vtable --- */ + virtual ~MrBlizzard(); + + int Behavior(); + int InitResources(); + int Render(); +}; + +typedef char MrBlizzard_size_must_be_0x458[sizeof(MrBlizzard) == 0x458 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct MrBlizzard { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -63,12 +108,8 @@ struct MrBlizzard { s32 unk_44c; /* 0x44c */ s32 unk_450; /* 0x450 */ s32 unk_454; /* 0x454 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* MRBLIZZARD_H */ diff --git a/include/Platform.h b/include/Platform.h index 5589d4ac1..a1beff6a7 100644 --- a/include/Platform.h +++ b/include/Platform.h @@ -18,12 +18,27 @@ * (0x0d4 + 0x40 / +0x44 / +0x48). They were declared as siblings of a `u8 mModel` * marker whose pad stopped short of the real object. * - * The class's DATA ends at 0x31e, and that is not the same as its sizeof. A - * derived class's fields start at the base's data size rounded to their own - * alignment, so StarSwitch's first s32 lands at 0x320 and BowserFireSeaArena's - * first s16 lands at 0x31e. Claiming 0x31e..0x324 for Platform reproduces - * BowserFireSeaArena (its three s16 sit at the same addresses either way) and - * makes StarSwitch impossible, which is how the error was caught. + * SIZEOF IS 0x320, and it takes more than one derived class to see why. + * BowserFireSeaArena starts its own Model at 0x324, which alone reads like the + * class ending there. But FOUR classes derive from Platform DIRECTLY -- one + * non-Platform vtable store each, so no intermediate -- and each places a + * 4-byte-aligned CLASS member at 0x320, impossible if this class occupied + * 0x320..0x323: + * + * PyramidTop daObjDlPyramid_c Model @ 0x320 + * SwitchPillar daObjC0Water_c TextureTransformer @ 0x320 + * MovingBarSmall daObjBk_Lift_c ShadowModel @ 0x320 + * WallSign daObjKanban_c MovingCylinderClsnWithPos @ 0x320 + * + * Each is read straight off that class's destructor, which destroys its own + * member at 0x320 before storing _ZTV8Platform and running the base. + * + * One layout satisfies all five: data ends 0x31e, sizeof 0x320. The four above + * align up from 0x31e to 0x320; BowserFireSeaArena puts its OWN three s16 at + * 0x31e/0x320/0x322 so its Model lands at 0x324; DonutBlock puts a single s16 + * at 0x31e, in this class's tail padding, and its Behavior reads this+0x31e + * and reproduces. Ending at 0x324 satisfies BowserFireSeaArena and contradicts + * the other four. * * Field NAMES for the unk_ entries are placeholders. */ #ifndef PLATFORM_H @@ -66,6 +81,8 @@ struct Platform : Actor { Matrix4x3 mClsnMat; /* 0x2ec */ u8 unk_31c; /* 0x31c */ u8 unk_31d; /* 0x31d */ + /* THE CLASS ENDS HERE, at 0x31e; sizeof rounds to 0x320. See the header + comment: three s16 used to sit here, and they are BowserFireSeaArena's. */ /* --- vtable, in ROM order. Do not reorder. --- */ /* INLINE ON PURPOSE. Every Platform subclass's destructor inlines this body @@ -82,9 +99,6 @@ struct Platform : Actor { void UpdateModelPosAndRotY(); }; -/* 0x320, not 0x324: the last field ends at 0x31e and the class rounds up to its - 4-byte alignment. The DATA size is 0x31e, and that is what a derived class's - fields start from -- see the note above. */ typedef char Platform_size_must_be_0x320[sizeof(Platform) == 0x320 ? 1 : -1]; #else @@ -133,11 +147,7 @@ struct Platform { struct Matrix4x3 mClsnMat; /* 0x2ec */ u8 unk_31c; /* 0x31c */ u8 unk_31d; /* 0x31d */ - /* 0x31e..0x324: evidenced from BowserFireSeaArena, which reads all three and - whose own first member starts at 0x324. They are Platform's, not its. */ - s16 unk_31e; /* 0x31e */ - s16 unk_320; /* 0x320 */ - s16 unk_322; /* 0x322 */ + /* Ends at 0x31e; sizeof rounds to 0x320. See the C++ half. */ }; #endif /* __cplusplus */ diff --git a/include/PoleBillboard.h b/include/PoleBillboard.h index fd1fc5306..2370b13eb 100644 --- a/include/PoleBillboard.h +++ b/include/PoleBillboard.h @@ -1,12 +1,52 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class PoleBillboard: 6 matched functions, 19 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef POLEBILLBOARD_H #define POLEBILLBOARD_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "ShadowModel.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct PoleBillboard : Platform { + u8 pad_31e[0x2]; + ShadowModel mShadowModel; /* 0x320 */ + u8 pad_348[0x30]; + s32 unk_378; /* 0x378 */ + s32 unk_37c; /* 0x37c */ + s32 unk_380; /* 0x380 */ + s32 unk_384; /* 0x384 */ + s32 unk_388; /* 0x388 */ + s32 unk_38c; /* 0x38c */ + u16 unk_390; /* 0x390 */ + s16 unk_392; /* 0x392 */ + s16 unk_394; /* 0x394 */ + s8 unk_396; /* 0x396 */ + u8 unk_397; /* 0x397 */ + + /* --- vtable --- */ + virtual ~PoleBillboard(); + + int CleanupResources(); + int Render(); +}; + +typedef char PoleBillboard_size_must_be_0x398[sizeof(PoleBillboard) == 0x398 ? 1 : -1]; + +#else +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct PoleBillboard { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -34,11 +74,8 @@ struct PoleBillboard { s16 unk_394; /* 0x394 */ s8 unk_396; /* 0x396 */ u8 unk_397; /* 0x397 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* POLEBILLBOARD_H */ diff --git a/include/PyramidStep.h b/include/PyramidStep.h index 8342aa7f4..f771fb32f 100644 --- a/include/PyramidStep.h +++ b/include/PyramidStep.h @@ -1,12 +1,46 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class PyramidStep: 6 matched functions, 9 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef PYRAMIDSTEP_H #define PYRAMIDSTEP_H + #include "types.h" +#include "Platform.h" #include "Model.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct PyramidStep : Platform { + u8 pad_31e[0x2]; + Model mModel; /* 0x320 */ + s16 unk_370; /* 0x370 */ + u8 unk_372; /* 0x372 */ + u8 pad_373[0x1]; + u8 unk_374; /* 0x374 */ + + /* --- vtable --- */ + virtual ~PyramidStep(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char PyramidStep_size_must_be_0x378[sizeof(PyramidStep) == 0x378 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct PyramidStep { u8 pad_000[0x8]; s32 unk_008; /* 0x008 */ @@ -28,13 +62,8 @@ struct PyramidStep { u8 unk_372; /* 0x372 */ u8 pad_373[0x1]; u8 unk_374; /* 0x374 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* PYRAMIDSTEP_H */ diff --git a/include/PyramidTop.h b/include/PyramidTop.h index 836c4237d..c037deaee 100644 --- a/include/PyramidTop.h +++ b/include/PyramidTop.h @@ -1,12 +1,52 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class PyramidTop: 6 matched functions, 17 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef PYRAMIDTOP_H #define PYRAMIDTOP_H + #include "types.h" +#include "Platform.h" #include "Model.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct PyramidTop : Platform { + u8 pad_31e[0x2]; + Model mModel; /* 0x320 */ + u8 pad_370[0x30]; + s32 unk_3a0; /* 0x3a0 */ + s32 unk_3a4; /* 0x3a4 */ + s32 unk_3a8; /* 0x3a8 */ + s32 unk_3ac; /* 0x3ac */ + s16 unk_3b0; /* 0x3b0 */ + u16 unk_3b2; /* 0x3b2 */ + s16 unk_3b4; /* 0x3b4 */ + u8 unk_3b6; /* 0x3b6 */ + u8 unk_3b7; /* 0x3b7 */ + + /* --- vtable --- */ + virtual ~PyramidTop(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char PyramidTop_size_must_be_0x3b8[sizeof(PyramidTop) == 0x3b8 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct PyramidTop { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -45,13 +85,8 @@ struct PyramidTop { s16 unk_3b4; /* 0x3b4 */ u8 unk_3b6; /* 0x3b6 */ u8 unk_3b7; /* 0x3b7 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* PYRAMIDTOP_H */ diff --git a/include/QuestionBlock.h b/include/QuestionBlock.h index 7b9dc2186..fff319d46 100644 --- a/include/QuestionBlock.h +++ b/include/QuestionBlock.h @@ -1,13 +1,53 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class QuestionBlock: 6 matched functions, 20 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef QUESTIONBLOCK_H #define QUESTIONBLOCK_H + #include "types.h" +#include "Platform.h" #include "ModelAnim.h" #include "ShadowModel.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct QuestionBlock : Platform { + u8 pad_31e[0x2]; + ModelAnim mModelAnim; /* 0x320 */ + ShadowModel mShadowModel; /* 0x384 */ + u8 unk_3ac; /* 0x3ac */ + u8 pad_3ad[0x33]; + s32 unk_3e0; /* 0x3e0 */ + u8 pad_3e4[0x4]; + s32 unk_3e8; /* 0x3e8 */ + u8 pad_3ec[0x4]; + u8 unk_3f0; /* 0x3f0 */ + u8 unk_3f1; /* 0x3f1 */ + u8 pad_3f2[0x1]; + u8 unk_3f3; /* 0x3f3 */ + + /* --- vtable --- */ + virtual ~QuestionBlock(); + + int Behavior(); + int CleanupResources(); + int Render(); +}; + +typedef char QuestionBlock_size_must_be_0x3f4[sizeof(QuestionBlock) == 0x3f4 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct QuestionBlock { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -48,12 +88,8 @@ struct QuestionBlock { u8 unk_3f1; /* 0x3f1 */ u8 pad_3f2[0x1]; u8 unk_3f3; /* 0x3f3 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* QUESTIONBLOCK_H */ diff --git a/include/RotatingCogSmall.h b/include/RotatingCogSmall.h index 969c0d234..44875c3ed 100644 --- a/include/RotatingCogSmall.h +++ b/include/RotatingCogSmall.h @@ -1,12 +1,45 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class RotatingCogSmall: 6 matched functions, 9 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ROTATINGCOGSMALL_H #define ROTATINGCOGSMALL_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct RotatingCogSmall : Platform { + s16 unk_31e; /* 0x31e */ + s16 unk_320; /* 0x320 */ + s16 unk_322; /* 0x322 */ + s16 unk_324; /* 0x324 */ + u8 pad_326[0x6]; + s32 mRotationState; /* 0x32c */ + /* --- vtable --- */ + virtual ~RotatingCogSmall(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char RotatingCogSmall_size_must_be_0x330[sizeof(RotatingCogSmall) == 0x330 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct RotatingCogSmall { u8 pad_000[0xc]; u16 unk_00c; /* 0x00c */ @@ -24,13 +57,8 @@ struct RotatingCogSmall { s16 unk_324; /* 0x324 */ u8 pad_326[0x6]; s32 mRotationState; /* 0x32c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ROTATINGCOGSMALL_H */ diff --git a/include/RotatingPlatformLll.h b/include/RotatingPlatformLll.h index 1d6df78de..b7063381a 100644 --- a/include/RotatingPlatformLll.h +++ b/include/RotatingPlatformLll.h @@ -1,12 +1,42 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class RotatingPlatformLll: 6 matched functions, 6 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ROTATINGPLATFORMLLL_H #define ROTATINGPLATFORMLLL_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct RotatingPlatformLll : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + u8 unk_324; /* 0x324 */ + + /* --- vtable --- */ + virtual ~RotatingPlatformLll(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char RotatingPlatformLll_size_must_be_0x328[sizeof(RotatingPlatformLll) == 0x328 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct RotatingPlatformLll { u8 pad_000[0x60]; s32 mPosY; /* 0x060 */ @@ -20,13 +50,8 @@ struct RotatingPlatformLll { u8 pad_125[0x1fb]; s32 unk_320; /* 0x320 */ u8 unk_324; /* 0x324 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ROTATINGPLATFORMLLL_H */ diff --git a/include/RotatingPlatformWdw.h b/include/RotatingPlatformWdw.h index 0a50a259d..5d6e90ce3 100644 --- a/include/RotatingPlatformWdw.h +++ b/include/RotatingPlatformWdw.h @@ -1,12 +1,49 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class RotatingPlatformWdw: 6 matched functions, 15 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef ROTATINGPLATFORMWDW_H #define ROTATINGPLATFORMWDW_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "TextureTransformer.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct RotatingPlatformWdw : Platform { + u8 pad_31e[0x2]; + TextureTransformer mTextureTransformer;/* 0x320 */ + s32 mTargetPosY; /* 0x334 */ + u8 unk_338; /* 0x338 */ + u8 pad_339[0x3]; + s32 unk_33c; /* 0x33c */ + u8 unk_340; /* 0x340 */ + u8 pad_341[0x3]; + s32 unk_344; /* 0x344 */ + + /* --- vtable --- */ + virtual ~RotatingPlatformWdw(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; +typedef char RotatingPlatformWdw_size_must_be_0x348[sizeof(RotatingPlatformWdw) == 0x348 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct RotatingPlatformWdw { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -37,13 +74,8 @@ struct RotatingPlatformWdw { u8 unk_340; /* 0x340 */ u8 pad_341[0x3]; s32 unk_344; /* 0x344 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* ROTATINGPLATFORMWDW_H */ diff --git a/include/SeesawBob.h b/include/SeesawBob.h index 5175032e2..1af1bbc39 100644 --- a/include/SeesawBob.h +++ b/include/SeesawBob.h @@ -1,12 +1,43 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class SeesawBob: 6 matched functions, 9 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SEESAWBOB_H #define SEESAWBOB_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct SeesawBob : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s16 unk_324; /* 0x324 */ + u8 unk_326; /* 0x326 */ + + /* --- vtable --- */ + virtual ~SeesawBob(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char SeesawBob_size_must_be_0x328[sizeof(SeesawBob) == 0x328 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct SeesawBob { u8 pad_000[0xc]; u16 unk_00c; /* 0x00c */ @@ -24,13 +55,8 @@ struct SeesawBob { s32 unk_320; /* 0x320 */ s16 unk_324; /* 0x324 */ u8 unk_326; /* 0x326 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SEESAWBOB_H */ diff --git a/include/ShipWater.h b/include/ShipWater.h index 5cfa4c8c3..5b9aabb7c 100644 --- a/include/ShipWater.h +++ b/include/ShipWater.h @@ -1,12 +1,46 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class ShipWater: 6 matched functions, 10 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SHIPWATER_H #define SHIPWATER_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "TextureTransformer.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct ShipWater : Platform { + u8 pad_31e[0x2]; + TextureTransformer mTextureTransformer;/* 0x320 */ + s32 unk_334; /* 0x334 */ + u8 unk_338; /* 0x338 */ + u8 pad_339[0x3]; + s32 unk_33c; /* 0x33c */ + /* --- vtable --- */ + virtual ~ShipWater(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char ShipWater_size_must_be_0x340[sizeof(ShipWater) == 0x340 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct ShipWater { u8 pad_000[0x60]; s32 mPosY; /* 0x060 */ @@ -50,13 +84,8 @@ struct ShipWater { u8 unk_338; /* 0x338 */ u8 pad_339[0x3]; s32 unk_33c; /* 0x33c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SHIPWATER_H */ diff --git a/include/ShipWing.h b/include/ShipWing.h index 6cc3306cb..de1338541 100644 --- a/include/ShipWing.h +++ b/include/ShipWing.h @@ -1,13 +1,48 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class ShipWing: 6 matched functions, 16 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SHIPWING_H #define SHIPWING_H + #include "types.h" -#include "Model.h" +#include "Platform.h" #include "WithMeshClsn.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct ShipWing : Platform { + u8 pad_31e[0x2]; + WithMeshClsn mWithMeshClsn; /* 0x320 */ + s32 unk_4dc; /* 0x4dc */ + s32 unk_4e0; /* 0x4e0 */ + s32 unk_4e4; /* 0x4e4 */ + u8 unk_4e8; /* 0x4e8 */ + u8 unk_4e9; /* 0x4e9 */ + u8 mState; /* 0x4ea */ + + /* --- vtable --- */ + virtual ~ShipWing(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char ShipWing_size_must_be_0x4ec[sizeof(ShipWing) == 0x4ec ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct ShipWing { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -36,13 +71,8 @@ struct ShipWing { u8 unk_4e8; /* 0x4e8 */ u8 unk_4e9; /* 0x4e9 */ u8 mState; /* 0x4ea */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SHIPWING_H */ diff --git a/include/SlidingIce.h b/include/SlidingIce.h index c17a9914a..f24f25bb0 100644 --- a/include/SlidingIce.h +++ b/include/SlidingIce.h @@ -1,12 +1,43 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class SlidingIce: 6 matched functions, 15 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SLIDINGICE_H #define SLIDINGICE_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct SlidingIce : Platform { + s16 unk_31e; /* 0x31e */ + s8 unk_320; /* 0x320 */ + u8 pad_321[0x3]; + s32 unk_324; /* 0x324 */ + s32 unk_328; /* 0x328 */ + + /* --- vtable --- */ + virtual ~SlidingIce(); + int Behavior(); + int CleanupResources(); + int Render(); +}; + +typedef char SlidingIce_size_must_be_0x32c[sizeof(SlidingIce) == 0x32c ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct SlidingIce { u8 pad_000[0xc]; u16 mActorID; /* 0x00c */ @@ -35,12 +66,8 @@ struct SlidingIce { u8 pad_321[0x3]; s32 unk_324; /* 0x324 */ s32 unk_328; /* 0x328 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SLIDINGICE_H */ diff --git a/include/SlidingPlatformWf.h b/include/SlidingPlatformWf.h index 2ec09c977..9e86cfa61 100644 --- a/include/SlidingPlatformWf.h +++ b/include/SlidingPlatformWf.h @@ -1,12 +1,43 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class SlidingPlatformWf: 6 matched functions, 5 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SLIDINGPLATFORMWF_H #define SLIDINGPLATFORMWF_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct SlidingPlatformWf : Platform { + u8 unk_31e; /* 0x31e */ + u8 pad_31f[0x1]; + s16 unk_320; /* 0x320 */ + u8 unk_322; /* 0x322 */ + /* --- vtable --- */ + virtual ~SlidingPlatformWf(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char SlidingPlatformWf_size_must_be_0x324[sizeof(SlidingPlatformWf) == 0x324 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct SlidingPlatformWf { u8 pad_000[0xd4]; /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. @@ -18,13 +49,8 @@ struct SlidingPlatformWf { u8 pad_31f[0x1]; s16 unk_320; /* 0x320 */ u8 unk_322; /* 0x322 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SLIDINGPLATFORMWF_H */ diff --git a/include/SquarePathLift.h b/include/SquarePathLift.h index c4b62fb91..f47d541ae 100644 --- a/include/SquarePathLift.h +++ b/include/SquarePathLift.h @@ -1,12 +1,44 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class SquarePathLift: 6 matched functions, 11 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SQUAREPATHLIFT_H #define SQUAREPATHLIFT_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct SquarePathLift : Platform { + u8 pad_31e[0x2]; + u8 mPath; /* 0x320 */ + u8 pad_321[0x7]; + s32 mNodeIndex; /* 0x328 */ + s32 mPathDir; /* 0x32c */ + /* --- vtable --- */ + virtual ~SquarePathLift(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char SquarePathLift_size_must_be_0x330[sizeof(SquarePathLift) == 0x330 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct SquarePathLift { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -28,13 +60,8 @@ struct SquarePathLift { u8 pad_321[0x7]; s32 mNodeIndex; /* 0x328 */ s32 mPathDir; /* 0x32c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SQUAREPATHLIFT_H */ diff --git a/include/Squasher.h b/include/Squasher.h index bc0113ae2..d87be02ba 100644 --- a/include/Squasher.h +++ b/include/Squasher.h @@ -1,13 +1,44 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class Squasher: 6 matched functions, 13 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SQUASHER_H #define SQUASHER_H + #include "types.h" -#include "Model.h" -#include "MovingMeshCollider.h" +#include "Platform.h" +#include "ShadowModel.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct Squasher : Platform { + s16 unk_31e; /* 0x31e */ + s16 unk_320; /* 0x320 */ + u8 unk_322; /* 0x322 */ + u8 pad_323[0x1]; + ShadowModel mShadowModel; /* 0x324 */ + + /* --- vtable --- */ + virtual ~Squasher(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char Squasher_size_must_be_0x34c[sizeof(Squasher) == 0x34c ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct Squasher { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -39,12 +70,8 @@ struct Squasher { u8 unk_322; /* 0x322 */ u8 pad_323[0x1]; u8 mShadowModel; /* 0x324 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SQUASHER_H */ diff --git a/include/StarSwitch.h b/include/StarSwitch.h index d1c54ba6d..c1ad7833a 100644 --- a/include/StarSwitch.h +++ b/include/StarSwitch.h @@ -5,22 +5,19 @@ #include "Platform.h" /* Derives from Platform: the destructor stores this class's vtable, then - * Platform's -- inlined -- and then destroys the MovingMeshCollider at 0x124 - * and the Model at 0xd4 before chaining to Actor. Those three are Platform's - * and are declared there; everything this header used to restate below 0x31e - * was Actor's and Platform's. + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. * - * Any field at 0x31e or 0x31f sits in Platform's tail padding, which the - * Itanium ABI lets a derived class use because Platform is non-POD: its last - * field ends at 0x31e and its size rounds to 0x320. - * - * SIZE IS THE OBSERVED FIELD SPAN, rounded up -- not independent evidence. It - * is a regression guard on this declaration, not a claim about the ROM. + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. */ #ifdef __cplusplus struct StarSwitch : Platform { + u8 pad_31e[0x2]; s32 unk_320; /* 0x320 */ s32 unk_324; /* 0x324 */ s32 unk_328; /* 0x328 */ @@ -51,6 +48,69 @@ struct StarSwitch : Platform { typedef char StarSwitch_size_must_be_0x354[sizeof(StarSwitch) == 0x354 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +struct StarSwitch { + u8 pad_000[0x8]; + u32 mParam; /* 0x008 */ + u16 mActorID; /* 0x00c */ + u8 pad_00e[0x52]; + /* 0x060..0x08e is Actor's, and Actor.h is de-bannered -- hand-reconstructed, not generated. Was one u8 + marker over the whole range. */ + s32 unk_060; /* 0x060 */ + s32 mPosZ; /* 0x064 */ + s32 unk_068; /* 0x068 */ + s32 unk_06c; /* 0x06c */ + s32 unk_070; /* 0x070 */ + s32 mCamSpacePosX; /* 0x074 */ + s32 mCamSpacePosY; /* 0x078 */ + s32 mCamSpacePosZ; /* 0x07c */ + s32 mScaleX; /* 0x080 */ + s32 mScaleY; /* 0x084 */ + s32 mScaleZ; /* 0x088 */ + s16 mAngleX; /* 0x08c */ + s16 mAngleY; /* 0x08e */ + u8 pad_090[0x20]; + /* 0x0b0..0x0cc is Actor's, and Actor.h is de-bannered -- hand-reconstructed, not generated. Was one u8 + marker over the whole range. */ + u32 unk_0b0; /* 0x0b0 */ + s32 unk_0b4; /* 0x0b4 */ + s32 unk_0b8; /* 0x0b8 */ + s32 unk_0bc; /* 0x0bc */ + s32 unk_0c0; /* 0x0c0 */ + u8 unk_0c4; /* 0x0c4 */ + u8 pad_0c5[0x7]; + u8 mAreaId; /* 0x0cc */ + u8 pad_0cd[0x7]; + /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. + D1 and not D2, so it is this type and not an inlined base. Was a u8 marker. */ + Model mModel; /* 0x0d4 */ + u8 mMeshCollider; /* 0x124 */ + u8 pad_125[0x1fb]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + s32 unk_328; /* 0x328 */ + u8 pad_32c[0x8]; + s32 unk_334; /* 0x334 */ + s16 unk_338; /* 0x338 */ + u16 unk_33a; /* 0x33a */ + s32 unk_33c; /* 0x33c */ + u8 pad_340[0x4]; + u32 mTargetActorID; /* 0x344 */ + s32 unk_348; /* 0x348 */ + u8 unk_34c; /* 0x34c */ + u8 unk_34d; /* 0x34d */ + u8 unk_34e; /* 0x34e */ + u8 unk_34f; /* 0x34f */ + u8 unk_350; /* 0x350 */ + u8 unk_351; /* 0x351 */ + u8 pad_352[0x1]; + s8 unk_353; /* 0x353 */ +}; + #endif /* __cplusplus */ #endif /* STARSWITCH_H */ diff --git a/include/Stump.h b/include/Stump.h index 5f23d4149..0ae70313b 100644 --- a/include/Stump.h +++ b/include/Stump.h @@ -1,13 +1,46 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class Stump: 6 matched functions, 8 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef STUMP_H #define STUMP_H + #include "types.h" +#include "Enemy.h" +#include "ModelAnim.h" #include "MovingCylinderClsn.h" #include "WithMeshClsn.h" +/* Derives from Enemy: the destructor stores this class's vtable, then the + * base's, then destroys whatever the base owns before chaining further up. + * Everything this header used to restate below 0x110 belonged to the + * chain above and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct Stump : Enemy { + MovingCylinderClsn mMovingCylinderClsn;/* 0x110 */ + WithMeshClsn mWithMeshClsn; /* 0x144 */ + ModelAnim mModelAnim; /* 0x300 */ + u8 pad_364[0x10]; + s32 mVariant; /* 0x374 */ + + /* --- vtable --- */ + virtual ~Stump(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char Stump_size_must_be_0x378[sizeof(Stump) == 0x378 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct Stump { u8 pad_000[0x8]; s32 unk_008; /* 0x008 */ @@ -29,13 +62,8 @@ struct Stump { s32 unk_35c; /* 0x35c */ u8 pad_360[0x14]; s32 mVariant; /* 0x374 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* STUMP_H */ diff --git a/include/SwitchPillar.h b/include/SwitchPillar.h index 27d3a253f..a1d50501f 100644 --- a/include/SwitchPillar.h +++ b/include/SwitchPillar.h @@ -1,12 +1,47 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class SwitchPillar: 6 matched functions, 12 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef SWITCHPILLAR_H #define SWITCHPILLAR_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "TextureTransformer.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct SwitchPillar : Platform { + u8 pad_31e[0x2]; + TextureTransformer mTextureTransformer;/* 0x320 */ + s32 mLoweredY; /* 0x334 */ + u32 unk_338; /* 0x338 */ + u8 unk_33c; /* 0x33c */ + u8 pad_33d[0x1]; + u8 unk_33e; /* 0x33e */ + /* --- vtable --- */ + virtual ~SwitchPillar(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char SwitchPillar_size_must_be_0x340[sizeof(SwitchPillar) == 0x340 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct SwitchPillar { u8 pad_000[0x60]; s32 mPosY; /* 0x060 */ @@ -38,13 +73,8 @@ struct SwitchPillar { u8 unk_33c; /* 0x33c */ u8 pad_33d[0x1]; u8 unk_33e; /* 0x33e */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* SWITCHPILLAR_H */ diff --git a/include/TTC_MovingBar.h b/include/TTC_MovingBar.h index 487931599..5381e1995 100644 --- a/include/TTC_MovingBar.h +++ b/include/TTC_MovingBar.h @@ -1,12 +1,43 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class TTC_MovingBar: 5 matched functions, 10 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef TTC_MOVINGBAR_H #define TTC_MOVINGBAR_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "ShadowModel.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct TTC_MovingBar : Platform { + u8 unk_31e; /* 0x31e */ + u8 pad_31f[0x1]; + s32 unk_320; /* 0x320 */ + ShadowModel mShadowModel; /* 0x324 */ + + /* --- vtable --- */ + virtual ~TTC_MovingBar(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char TTC_MovingBar_size_must_be_0x34c[sizeof(TTC_MovingBar) == 0x34c ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct TTC_MovingBar { u8 pad_000[0xc]; u16 mActorID; /* 0x00c */ @@ -26,12 +57,8 @@ struct TTC_MovingBar { u8 pad_31f[0x1]; s32 unk_320; /* 0x320 */ u8 mShadowModel; /* 0x324 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* TTC_MOVINGBAR_H */ diff --git a/include/TinyCover.h b/include/TinyCover.h index 5ec944b1d..caae8b720 100644 --- a/include/TinyCover.h +++ b/include/TinyCover.h @@ -1,13 +1,45 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class TinyCover: 6 matched functions, 8 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef TINYCOVER_H #define TINYCOVER_H + #include "types.h" -#include "Model.h" +#include "Platform.h" #include "TextureTransformer.h" +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct TinyCover : Platform { + u8 pad_31e[0x2]; + TextureTransformer mTextureTransformer;/* 0x320 */ + s32 unk_334; /* 0x334 */ + u8 pad_338[0x4]; + u8 unk_33c; /* 0x33c */ + + /* --- vtable --- */ + virtual ~TinyCover(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char TinyCover_size_must_be_0x340[sizeof(TinyCover) == 0x340 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct TinyCover { u8 pad_000[0x60]; s32 mPosY; /* 0x060 */ @@ -28,13 +60,8 @@ struct TinyCover { s32 unk_334; /* 0x334 */ u8 pad_338[0x4]; u8 unk_33c; /* 0x33c */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* TINYCOVER_H */ diff --git a/include/TowerStep.h b/include/TowerStep.h index a2eec2a8a..c148bd74d 100644 --- a/include/TowerStep.h +++ b/include/TowerStep.h @@ -1,12 +1,42 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class TowerStep: 6 matched functions, 7 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef TOWERSTEP_H #define TOWERSTEP_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct TowerStep : Platform { + s8 unk_31e; /* 0x31e */ + u8 pad_31f[0x1]; + s32 unk_320; /* 0x320 */ + /* --- vtable --- */ + virtual ~TowerStep(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char TowerStep_size_must_be_0x324[sizeof(TowerStep) == 0x324 ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct TowerStep { u8 pad_000[0x74]; /* 0x074..0x08e is Actor's, and Actor.h is de-bannered -- hand-reconstructed, not generated. Was one u8 @@ -30,13 +60,8 @@ struct TowerStep { s8 unk_31e; /* 0x31e */ u8 pad_31f[0x1]; s32 unk_320; /* 0x320 */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* TOWERSTEP_H */ diff --git a/include/TtcMovingCubeA.h b/include/TtcMovingCubeA.h index e79ca7c1d..7f4fe32df 100644 --- a/include/TtcMovingCubeA.h +++ b/include/TtcMovingCubeA.h @@ -1,13 +1,46 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class TtcMovingCubeA: 5 matched functions, 15 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef TTCMOVINGCUBEA_H #define TTCMOVINGCUBEA_H + #include "types.h" -#include "Model.h" -#include "MovingMeshCollider.h" +#include "Platform.h" +#include "ShadowModel.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct TtcMovingCubeA : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + u8 unk_328; /* 0x328 */ + u8 pad_329[0x7]; + s32 unk_330; /* 0x330 */ + ShadowModel mShadowModel; /* 0x334 */ + + /* --- vtable --- */ + virtual ~TtcMovingCubeA(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char TtcMovingCubeA_size_must_be_0x35c[sizeof(TtcMovingCubeA) == 0x35c ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct TtcMovingCubeA { u8 pad_000[0x8]; s32 mParam; /* 0x008 */ @@ -37,12 +70,8 @@ struct TtcMovingCubeA { u8 pad_329[0x7]; s32 unk_330; /* 0x330 */ u8 mShadowModel; /* 0x334 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* TTCMOVINGCUBEA_H */ diff --git a/include/TtcRotatingGear.h b/include/TtcRotatingGear.h index 43582243e..9c59a37ed 100644 --- a/include/TtcRotatingGear.h +++ b/include/TtcRotatingGear.h @@ -1,12 +1,45 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class TtcRotatingGear: 6 matched functions, 13 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef TTCROTATINGGEAR_H #define TTCROTATINGGEAR_H + #include "types.h" -#include "Model.h" +#include "Platform.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct TtcRotatingGear : Platform { + u8 pad_31e[0x2]; + s32 unk_320; /* 0x320 */ + s32 unk_324; /* 0x324 */ + s32 unk_328; /* 0x328 */ + u16 unk_32c; /* 0x32c */ + u8 mMoveDir; /* 0x32e */ + + /* --- vtable --- */ + virtual ~TtcRotatingGear(); + + int Behavior(); + int CleanupResources(); + int InitResources(); + int Render(); +}; + +typedef char TtcRotatingGear_size_must_be_0x330[sizeof(TtcRotatingGear) == 0x330 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct TtcRotatingGear { u8 pad_000[0x5c]; s32 mPosX; /* 0x05c */ @@ -29,13 +62,8 @@ struct TtcRotatingGear { s32 unk_328; /* 0x328 */ u16 unk_32c; /* 0x32c */ u8 mMoveDir; /* 0x32e */ -#ifdef __cplusplus - /* methods */ - int Behavior(); - int CleanupResources(); - int InitResources(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* TTCROTATINGGEAR_H */ diff --git a/include/WallSign.h b/include/WallSign.h index dea63ac06..ebf8ec171 100644 --- a/include/WallSign.h +++ b/include/WallSign.h @@ -1,12 +1,42 @@ -/* AUTO-GENERATED from matched-function evidence by tools/gen_header.py - * class WallSign: 4 matched functions, 3 evidenced fields. - * Offsets/widths are observed, not guessed. Gaps are explicit padding. - * Field NAMES are placeholders - renaming cannot change codegen. */ #ifndef WALLSIGN_H #define WALLSIGN_H + #include "types.h" -#include "Model.h" +#include "Platform.h" +#include "MovingCylinderClsnWithPos.h" + +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct WallSign : Platform { + u8 pad_31e[0x2]; + MovingCylinderClsnWithPos mMovingCylinderClsnWithPos;/* 0x320 */ + + /* --- vtable --- */ + virtual ~WallSign(); + + int CleanupResources(); + int InitResources(); + int Behavior(); + int Render(); +}; + +typedef char WallSign_size_must_be_0x360[sizeof(WallSign) == 0x360 ? 1 : -1]; +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ struct WallSign { u8 pad_000[0xd4]; /* Model member, named by _ZN5ModelD1Ev at +0xd4 -- a relocation the ROM build checks. @@ -15,13 +45,8 @@ struct WallSign { u8 mMovingMeshCollider; /* 0x124 */ u8 pad_125[0x1fb]; u8 mMovingCylinderClsnWithPos; /* 0x320 */ -#ifdef __cplusplus - /* methods */ - int CleanupResources(); - int InitResources(); - int Behavior(); - int Render(); -#endif }; -#endif +#endif /* __cplusplus */ + +#endif /* WALLSIGN_H */ diff --git a/notes/handoff-class-skeleton.md b/notes/handoff-class-skeleton.md new file mode 100644 index 000000000..99971dbf2 --- /dev/null +++ b/notes/handoff-class-skeleton.md @@ -0,0 +1,202 @@ +# Handoff: the class skeleton, and how much of it is proven + +**Written 2026-08-07.** Branch `docs/class-reference-confidence`, five commits, pushed to +`origin`. Everything below is checkable; every number appears with the command that +produces it. Where an earlier answer was wrong, it is recorded rather than quietly fixed. + +--- + +## 0. Read this first if you are picking it up cold + +The question this answers is *"can this ROM be turned into matchable C++, or is that +impossible?"* The short version: + +**The interface is solved. The fields are not.** Those are different problems with +different oracles, and conflating them is the mistake this work exists to prevent. + +* **Fields are a weak oracle.** `notes/runbook-type-reconstruction.md` §2: a retype that + nothing reads emits identical bytes. 71 retypes across 119 TUs came out byte-identical + under `s32/s16` *and* `u32/u16`. The ROM cannot adjudicate most type questions. +* **The skeleton is a strong oracle.** Inheritance and virtual dispatch are not inferred + from code -- the compiler emits them as **data**, and that data is in the ROM. So a + C++ declaration can be compiled and byte-compared against retail. + +```sh +python tools/rtti_extract.py --report --check # -> build/rtti.json +python tools/rtti_vtables.py # -> build/rtti_vtables.json +python tools/rtti_reference.py # -> docs/class-reference.html +python tools/skeleton_conform.py --report # -> build/skeleton_conform.json +``` + +## 1. What is proven, with numbers + +`python tools/rtti_reference.py` prints these and writes the browsable page: + +| claim | count | of | | what makes it true | +|---|---:|---:|---|---| +| class exists and is named | 429 | 429 | 100% | the ROM stores the name string | +| base class known | 413 | 413 | 100% | a pointer in the typeinfo record | +| vtable located | 426 | 429 | 99.3% | bound to the record | +| slot resolves to a named function | 10984 | 11021 | 99.7% | slot → `config/**/symbols.txt` | +| …and that function has a source file | 10973 | 11021 | 99.6% | `tools/srcpath.py` | +| …and that file is **enrolled** | 10324 | 11021 | 93.7% | linked; rebuilt ROM byte-identical to retail | + +`python tools/skeleton_conform.py --report`: + +``` +checked 423: conform=420, bases_only=3 +skipped 6: no vtable slots (dBgPc, dM3dGLin, dMg3DHeyhoObjAdapter_c, daDemo_c::param_c) +``` + +**420 of 429 classes reproduce their vtable shape, offset-to-top, pure-virtual slots and +mangled name string from a compiled C++ declaration.** Zero mismatches. + +### What "conform" does and does not claim + +Compared **exactly**: the `_ZTS` name string, vtable offset-to-top, table length, which +slots are null, and for multiple inheritance the flags, base count and every base's +`offset_flags`. Those are literals. + +**Wildcarded**: every pointer word. In an object file it is an addend against an +undefined symbol; in the ROM it is a resolved address. `tools/match.py` has the identical +problem for code and solves it the same way. Whether the pointer words hold the *right* +functions is answered by a different join -- the 99.7%/93.7% rows above. + +Not claimed at all: field names, types, offsets, or method names. A named slot is not a +named method: where the symbol is a `func_*` placeholder the *position* is right and the +name is still unknown, and a vtable never carries a signature. + +## 2. The multiple-inheritance payload -- the ROM's only direct `sizeof` + +A `__vmi_class_type_info` record stores where each base **subobject** starts, as a +literal. Under Itanium a non-virtual base sits at the next available offset, so +consecutive starts state how much room the earlier base occupies. This is the one place +the ROM states layout outright. + +``` +dBgCh_SphCrr (SphereClsn) dBgCh@0 dBgPi@16 dM3dGSph@56 +dBgCh_Lin (RaycastLine) dBgCh@0 dBgPi@16 dM3dGLin@56 +dBgCh_Gnd dBgCh@0 dBgPi@16 +dExtAnmModel_c dExtSimpleModel_c@0 dExtFrameCtrl_c@80 +daDemo_c::anmModel_c dExtAnmModel_c@0 daDemo_c::param_c@100 +daDemo_c::simpleModel_c dExtSimpleModel_c@0 daDemo_c::param_c@80 + +implied: sizeof(dBgCh) 16 dBgPi 40 dExtSimpleModel_c 80 dExtAnmModel_c 100 +``` + +Each is corroborated by two or three independent records; none conflicts. + +**Two confirmations that were not inputs.** `include/BgCh.h`, hand-reconstructed from the +constructor's stores, says *"LAYOUT is 0x10 bytes"* -- 16, derived here from a different +structure entirely. And `include/SphereClsn.h`, a generated flat header, declares fields +starting at `0x010` and `0x038`; the record puts dBgPi at 16 and dM3dGSph at 56, and +16 + 40 = 56. **Both subobject boundaries land exactly on a field that generator already +found**, knowing nothing about any of this. + +> **If you are matching `DetectClsn(SphereClsn&)`:** everything below `0x38` in +> `include/SphereClsn.h` belongs to a base, not to SphereClsn. The ROM says that class +> has three bases; `include/` models one. See `notes/rtti-reconciliation.md` §4. + +**Honest about the circularity.** Taking offsets from the ROM and checking they come back +is close to vacuous. Two things make it not: the compiler gets a vote (declaration order, +alignment and the primary-base choice can each refuse), and the useful output is a +*restatement* -- "dBgPi starts at 16" becomes "sizeof(dBgCh) == 16", which is the form a +matcher can use. + +## 3. Two defects this found in `build/rtti_vtables.json` + +Both are fixed. Both were found by **using** the data rather than inspecting it, which is +the transferable part. + +**Over-read, 62 classes, 1128 slots.** The end-of-table rule only fired on a null whose +successor is a *known typeinfo record*. Where a `{0, handler}` table follows instead, the +successor is a code pointer, nothing fires, and the walk reads that table as slots. +`daPeach_c` ran to 62 slots against a real 31. + +The fix trims the longest strictly-alternating null/pointer suffix. Orientation is not the +signal -- `daPeach_c`'s tail reads `{fn, 0}` and `daObjSwdoor_c`'s reads `{0, fn}` -- the +*run* is. Both then land on their base's count exactly, which nobody put in by hand. + +**Under-read, 124 classes.** "Is this word code" was asked of the vtable's own module plus +arm9. Too narrow twice: ITCM is its own module and was never loaded (`dBgW_Kc` slots 3-7 +are `0x01ffd920`…), and a slot may point into a **different overlay** (`dScMgAmida_c`'s +table is in ov006 while slot 1 is ov004's code). Asking *every* module fails the other way +-- `dScStage_c` ran to 70 slots against a base of 18. The bound is residency +(`overlay_residency.conflict`, rule E2, the game's own `LoadOverlay` panic), applied +**one-directionally**: arm9 conflicts with nothing, so an arm9-hosted table gets no +cross-overlay allowance or the rule bounds nothing. + +**The invariant is now a gate.** A derived table is never shorter than its base's -- every +base slot is inherited or overridden and neither removes one. `rtti_vtables.py` fails the +run if it is violated. That invariant is what made both bugs findable. + +### The correction that followed + +`include/daObjSwdoor_c.h` declared four fields read from twelve "own" methods. Nine of the +twelve were the over-read tail. §8's attribution argument -- *a method can reach its own +members and its ancestors', never a descendant's* -- only licenses a field if the method +really is the class's, so **all four fields fell**: 3 own methods, 0 own fields. The header +is retracted, and `--emit-headers` now deletes a header it previously wrote for a class +with no remaining evidence. + +**The other four headers regenerate byte-identically** (4, 6, 4, 4 methods; same offsets, +same widths). A trim eating real data would have moved them too. That is the reason to +believe the fix and not merely the finding. + +## 4. What is still open, in the order I would take it + +1. **The 37 unnamed slots** are addresses hosted by two co-resident modules. The join + reports a genuine tie as unresolved rather than picking one. `tools/overlay_residency.py` + `settle()` may narrow some; the rest want a human. Low value, listed for completeness. +2. **`daDemo_c::anmModel_c` / `simpleModel_c`** report `bases_only`: they declare their + offset-100 / offset-80 base first and the primary second, which happens when the + first-declared base is not the one the compiler makes primary. A probe needs the + empty-base and primary-base rules modelled. Their offsets are already recorded. +3. **`dBgCh_Lin` needs `dM3dGLin`'s vtable.** It is one of three records with no vtable + bound (`dBgPc`, `dM3dGLin`, `daDemo_c::param_c`); `rtti_vtables.py` refuses to guess. + Settling any of them unblocks a probe and would confirm `dBgPi`'s size a third time. +4. **Surface conformance on `docs/class-reference.html`.** The data is in + `build/skeleton_conform.json` and the page does not read it yet. Cheap; it would let + the page state both "the code is byte-verified" and "the declaration is byte-verified". +5. **The real blocker for migration is unchanged and is not a codegen problem.** + `eligible.py` rejects any object with a `.data` section (85 files) and any with + multiple `.text` sections (13). A `~Class()` definition always emits D2/D0/D1, so + **enrolled destructor migrations in this tree: zero.** The prerequisite is a delink + model that can bind one source file to a multi-function address range. mwccarm emits + the group in D2, D0, D1 order, which is exactly the ROM's per-class layout -- one TU + already reproduces the contiguous range; nothing can bind it. See + `notes/dtor-variant-audit.md` §7. + +## 5. Wrong answers recorded, so they are not re-derived + +* **"9351 / 9351 slots named, 100.0%"** was an artifact, not an achievement. The walk + stopped early at precisely the slots it could not classify, so they were never in the + denominator. The corrected figure is 10984 / 11021 -- a lower percentage over 1670 more + slots. **A suspiciously perfect number is a reason to check the denominator.** +* **Trimming the over-read tail** was tried before refusing it, and the two orientations + disagree about which slot is last. Refusing was what dropped mismatches 43 → 0, which is + itself the evidence that the mismatches were bad slot data rather than a bad model. +* **`content-visibility: auto`** on the class page makes the browser guess card heights, + so a jump from the tree lands in blank space and the card never paints. Removed. The + weight it was there to fix is handled by building slot tables lazily (9351 rows as + markup is 2.8 MB and froze the renderer) and shipping groups collapsed (69,000px → 8,201px). +* **`skeleton_conform` reported "the probe emitted no `_ZTS`" for 57 classes** when the + probe was fine and its own ROM reader was the broken half -- a fixed 256-byte read + overran the end of the module. Always say *which side* of a comparison is missing. +* **Symbol lookups by prefix/suffix.** A probe object defines every ancestor's RTTI + symbols too, so a scan can return an ancestor's record and compare it against the leaf's + ROM bytes. Index by exact mangled name. + +## 6. Caveats on the artifacts + +`docs/class-reference.html` is generated and committed. It was generated from a working +tree on `d2/renames-small`, so its enrolled counts reflect that branch's `config/` and +`src/`, not `main`'s. Regenerate after merging; `--check` refuses to emit if its inputs +are stale, and warns if any slot resolves to no symbol. + +`build/*.json` are gitignored artifacts. `tools/skeleton_conform.py` needs +`tools/mwccarm/**` and `extracted/**`, neither of which a fresh clone has -- see +`notes/rom-build.md`. + +No `include/`, `config/` or `src/` file is touched by any of this except the retraction of +`include/daObjSwdoor_c.h`, which had zero consumers, so codegen cannot move. diff --git a/src/_ZN10BowserFire13InitResourcesEv.cpp b/src/_ZN10BowserFire13InitResourcesEv.cpp index 721e126a5..8ca795026 100644 --- a/src/_ZN10BowserFire13InitResourcesEv.cpp +++ b/src/_ZN10BowserFire13InitResourcesEv.cpp @@ -63,16 +63,16 @@ int BowserFire::InitResources() _ZN12WithMeshClsn4InitEP5Actor5Fix12IiES3_P10Vector3_16S5_( &this->mWithMeshClsn, this, 0x32000, 0x32000, 0, 0); - this->unk_09c = -0x4000; - this->unk_0a0 = -0x1e000; - this->unk_35c = this->mParam & 7; + this->mVertAccel = -0x4000; + this->mTerminalVelocity = -0x1e000; + this->unk_35c = this->param1 & 7; this->unk_374 = 0; if (this->unk_35c == 0) this->unk_379 = 0; else this->unk_379 = 1; this->unk_36c = 0; - this->unk_378 = ((unsigned int)this->mParam >> 4) & 3; + this->unk_378 = ((unsigned int)this->param1 >> 4) & 3; if (this->unk_35c == 0) this->mMovingCylinderClsn.flags |= 1; this->unk_360 = 0x2000; diff --git a/src/_ZN10BowserFire8BehaviorEv.cpp b/src/_ZN10BowserFire8BehaviorEv.cpp index 0cb65ff00..77aa727cb 100644 --- a/src/_ZN10BowserFire8BehaviorEv.cpp +++ b/src/_ZN10BowserFire8BehaviorEv.cpp @@ -17,12 +17,12 @@ int BowserFire::Behavior() *(int*)(((int)((char *)this) + 0x370)) += 1; (self->*data_ov060_0211afb4[unk_35c].pmf)(); *(unsigned short*)(((int)((char *)this) + 0x374)) += 1; - if (unk_09c != 0) { + if (mVertAccel != 0) { WithMeshClsn_UpdateDiscreteNoLava_veneer((char *)&mWithMeshClsn); if (unk_35c != 4) { if (_ZNK12WithMeshClsn10IsOnGroundEv((char *)&mWithMeshClsn) != 0) { mVertSpeed = 0; - unk_09c = 0; + mVertAccel = 0; } } } diff --git a/src/_ZN10CheepCheep13InitResourcesEv.cpp b/src/_ZN10CheepCheep13InitResourcesEv.cpp index 4330111a9..530246ffa 100644 --- a/src/_ZN10CheepCheep13InitResourcesEv.cpp +++ b/src/_ZN10CheepCheep13InitResourcesEv.cpp @@ -34,23 +34,23 @@ int CheepCheep::InitResources() struct Vector3 v; bmd = _ZN5Model8LoadFileER13SharedFilePtr(data_ov090_02134564); - _ZN9ModelBase7SetFileEP8BMD_Fileii((void *)((char *)&mModelAnim), bmd, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii((void *)((char *)&(*(u8 *)&mModelAnim)), bmd, 1, -1); _ZN9Animation8LoadFileER13SharedFilePtr(*(struct SharedFilePtr *)&data_ov090_0213455c); v = data_ov090_021342d8; _ZN25MovingCylinderClsnWithPos4InitEP5ActorRK7Vector35Fix12IiES6_jj( - (void *)((char *)&mMovingCylinderClsnWithPos), (struct Actor *)((char *)this), v, 0x32000, 0x3c000, 0x200004, 0x8000); + (void *)((char *)&(*(MovingCylinderClsnWithPos *)&mMovingCylinderClsnWithPos)), (struct Actor *)((char *)this), v, 0x32000, 0x3c000, 0x200004, 0x8000); unk_374 = mPosX; unk_378 = mPosY; unk_37c = mPosZ; mAngleY = mPrevAngleY; _ZN12WithMeshClsn4InitEP5Actor5Fix12IiES3_P10Vector3_16S5_( - (void *)((char *)&mWithMeshClsn), (struct Actor *)((char *)this), 0x1e000, 0x1e000, 0, 0); + (void *)((char *)&(*(WithMeshClsn *)&mWithMeshClsn)), (struct Actor *)((char *)this), 0x1e000, 0x1e000, 0, 0); _ZN9ModelAnim7SetAnimEP8BCA_Filei5Fix12IiEj( - (void *)((char *)&mModelAnim), data_ov090_0213455c.file, 0, 0x1000, 0); + (void *)((char *)&(*(u8 *)&mModelAnim)), data_ov090_0213455c.file, 0, 0x1000, 0); func_ov090_021332e8(((char *)this), &data_ov090_02134594); return 1; diff --git a/src/_ZN10CheepCheep6RenderEv.cpp b/src/_ZN10CheepCheep6RenderEv.cpp index 8955c1789..08be78e4b 100644 --- a/src/_ZN10CheepCheep6RenderEv.cpp +++ b/src/_ZN10CheepCheep6RenderEv.cpp @@ -13,9 +13,9 @@ struct Obj { int CheepCheep::Render() { - int b = ((unk_0b0 & 0x40000) != 0); + int b = ((mFlags & 0x40000) != 0); if (b) return 1; - Obj *o = (Obj*)((char *)&mModelAnim); + Obj *o = (Obj*)((char *)&(*(u8 *)&mModelAnim)); o->Target(0); return 1; } diff --git a/src/_ZN10CheepCheep8BehaviorEv.cpp b/src/_ZN10CheepCheep8BehaviorEv.cpp index 9a6a9225f..0e16564a3 100644 --- a/src/_ZN10CheepCheep8BehaviorEv.cpp +++ b/src/_ZN10CheepCheep8BehaviorEv.cpp @@ -21,7 +21,6 @@ extern void _ZN9Animation7AdvanceEv(void *thiz); extern char *_ZN5Actor13ClosestPlayerEv(Enemy *thiz); } -struct Enemy { char pad[0x800]; }; int CheepCheep::Behavior() { diff --git a/src/_ZN10DonutBlock13InitResourcesEv.cpp b/src/_ZN10DonutBlock13InitResourcesEv.cpp index 1203051b4..d24751fb3 100644 --- a/src/_ZN10DonutBlock13InitResourcesEv.cpp +++ b/src/_ZN10DonutBlock13InitResourcesEv.cpp @@ -1,55 +1,33 @@ //cpp // @symbol _ZN10DonutBlock13InitResourcesEv -/* recovered: named members + shared header, real C++ method - * - * Load the model and the collision mesh out of this overlay's file table, put - * both where the actor is, and pick the spin rate. - * - * The three raw offsets are gone: `this + 0xd4` is Platform::mModel, - * `this + 0x124` is Platform::mMeshCollider, and the `this + 0x2ec` handed to - * SetFile as its matrix is Platform::mClsnMat -- which UpdateClsnPosAndRot - * filled in on the line above. A local `typedef int Fix12` went with them; the - * real Fix12 is a template. - * - * unk_31e is the per-frame yaw step. It defaults to -0x80 and takes mAngleZ - * instead when the level author set one, so the field is reused as a - * placement parameter at load time. - * - * The calls keep their mangled spellings: SetFile's name carries Fix12 by - * value (wall 6az), and func_020393d4 and the callback it is handed are still - * unnamed. - */ +/* recovered: named members + shared header, real C++ method */ #include "DonutBlock.h" - extern "C" { -extern void *_ZN5Model8LoadFileER13SharedFilePtr(void *ptr); -extern int _ZN9ModelBase7SetFileEP8BMD_Fileii(void *self, void *file, int a, int b); -extern int _ZN8Platform21UpdateModelPosAndRotYEv(void *self); -extern int _ZN8Platform19UpdateClsnPosAndRotEv(void *self); -extern void *_ZN12MeshCollider8LoadFileER13SharedFilePtr(void *ptr); -extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - void *self, void *file, void *mat, int scale, short angY, void *clps); -extern int func_020393d4(void *self, void *callback); +extern void* _ZN5Model8LoadFileER13SharedFilePtr(void*); +extern int _ZN9ModelBase7SetFileEP8BMD_Fileii(void*, void*, int, int); +extern int _ZN8Platform21UpdateModelPosAndRotYEv(void*); +extern int _ZN8Platform19UpdateClsnPosAndRotEv(void*); +extern void* _ZN12MeshCollider8LoadFileER13SharedFilePtr(void*); +extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(void*, void*, void*, int, short, void*); +extern int func_020393d4(void*, void*); +} +extern void* data_ov036_02113d78[]; +extern "C" { extern int _ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_(void); } -extern void *data_ov036_02113d78[]; - int DonutBlock::InitResources() { - void *mdl = _ZN5Model8LoadFileER13SharedFilePtr(data_ov036_02113d78[0]); - _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, mdl, 1, -1); - _ZN8Platform21UpdateModelPosAndRotYEv(this); - _ZN8Platform19UpdateClsnPosAndRotEv(this); - - void *kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov036_02113d78[1]); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - &mMeshCollider, kcl, &mClsnMat, 0x1000, mAngleY, data_ov036_02113d78[2]); - func_020393d4(&mMeshCollider, - &_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - - unk_31e = -0x80; - if (mAngleZ != 0) - unk_31e = mAngleZ; - return 1; + void* mdl; + void* kcl; + mdl = _ZN5Model8LoadFileER13SharedFilePtr(data_ov036_02113d78[0]); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, mdl, 1, -1); + _ZN8Platform21UpdateModelPosAndRotYEv(this); + _ZN8Platform19UpdateClsnPosAndRotEv(this); + kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov036_02113d78[1]); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, kcl, &mClsnMat, 0x1000, mAngleY, data_ov036_02113d78[2]); + func_020393d4(&mMeshCollider, &_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + unk_31e = -0x80; + if (mAngleZ != 0) unk_31e = mAngleZ; + return 1; } diff --git a/src/_ZN10DonutBlock8BehaviorEv.cpp b/src/_ZN10DonutBlock8BehaviorEv.cpp index 0edbcf844..af305c15b 100644 --- a/src/_ZN10DonutBlock8BehaviorEv.cpp +++ b/src/_ZN10DonutBlock8BehaviorEv.cpp @@ -7,9 +7,9 @@ * matter, the collision mesh too. * * Three shadow declarations are gone -- a `typedef int Fix12` and stand-in - * `MeshColliderBase` and `Platform` structs -- with the raw offsets they + * `MeshColliderBase` and `Platform` structs -- along with the raw offsets they * served. `this + 0x8e` is Actor::mAngleY, and the `t[0x1e/2]` read off - * `this + 0x300` is this class's own unk_31e reached the long way round. + * `this + 0x300` was this class's own unk_31e reached the long way round. * * IsClsnInRange keeps its mangled spelling: the name carries Fix12 by * value, wall 6az, so a real call would not reproduce the call site. @@ -22,7 +22,7 @@ int DonutBlock::Behavior() { /* `+=`, not `mAngleY = mAngleY + ...`: the compound form CSEs the field address into a register and reuses it for the load and the store, which - is what the ROM does here. That is a per-SITE fact -- the opposite + is what the ROM does here. That is a per-SITE fact -- the expanded spelling is the matching one in Player::St_WallJump_Init. */ mAngleY += unk_31e; diff --git a/src/_ZN10DonutBlockD1Ev.cpp b/src/_ZN10DonutBlockD1Ev.cpp index e1ebdef00..f630cd574 100644 --- a/src/_ZN10DonutBlockD1Ev.cpp +++ b/src/_ZN10DonutBlockD1Ev.cpp @@ -5,8 +5,8 @@ * Two vtable stores and three destructor calls, every one a consequence of * `struct DonutBlock : Platform`: its own vptr, then Platform's -- inlined, * because Platform's destructor is defined in its class body -- then - * Platform's Model and MovingMeshCollider, then Actor. This class adds no - * member with a destructor. + * Platform's Model and MovingMeshCollider, then Actor. DonutBlock adds one + * s16, which has no destructor. */ #include "DonutBlock.h" diff --git a/src/_ZN10KingBobOmb13InitResourcesEv.cpp b/src/_ZN10KingBobOmb13InitResourcesEv.cpp index 159d77a66..759d7855d 100644 --- a/src/_ZN10KingBobOmb13InitResourcesEv.cpp +++ b/src/_ZN10KingBobOmb13InitResourcesEv.cpp @@ -46,7 +46,7 @@ int KingBobOmb::InitResources() int i; f = _ZN5Model8LoadFileER13SharedFilePtr(&data_ov078_02126f38); _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0x2cc, f, 1, 1); - _ZN11ShadowModel12InitCylinderEv((char*)&mShadowModel); + _ZN11ShadowModel12InitCylinderEv((char*)&(*(u8 *)&mShadowModel)); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126f00); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126f20); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126f10); @@ -59,8 +59,8 @@ int KingBobOmb::InitResources() _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126ee8); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126f28); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov078_02126ef8); - unk_09c = -0x2000; - unk_0a0 = -0x3c000; + mVertAccel = -0x2000; + mTerminalVelocity = -0x3c000; v0.x = data_ov078_02126e00.x; v0.y = data_ov078_02126e00.y; v0.z = data_ov078_02126e00.z; @@ -77,10 +77,10 @@ int KingBobOmb::InitResources() unk_4d8 = 0x1060000; unk_4dc = 0xfee15000; _ZN12WithMeshClsn4InitEP5Actor5Fix12IiES3_P10Vector3_16S5_(((char*)this)+0x110, (Actor*)((char*)this), 0x190000, 0x190000, 0, 0); - func_02035550((char*)&mWithMeshClsn); + func_02035550((char*)&(*(WithMeshClsn *)&mWithMeshClsn)); unk_4fc = 1; unk_500 = 3; - unk_509 = mParam & 0xf; + unk_509 = (*(s32 *)¶m1) & 0xf; unk_507 = _ZN5Actor9TrackStarEjj(((char*)this), unk_509, 2); #pragma opt_strength_reduction off { diff --git a/src/_ZN10KingBobOmb6RenderEv.cpp b/src/_ZN10KingBobOmb6RenderEv.cpp index 550c5cedb..f22f65d41 100644 --- a/src/_ZN10KingBobOmb6RenderEv.cpp +++ b/src/_ZN10KingBobOmb6RenderEv.cpp @@ -12,7 +12,7 @@ int KingBobOmb::Render() { void *r1 = (void*)*(int*)((char*)&unk_494); if (r1 != 0) { - int r0 = *(int*)((char*)&unk_0b0); + int r0 = *(int*)((char*)&mFlags); int flag = (r0 & 0x4000) ? 1 : 0; if (flag != 0) { if (*(int*)((char*)r1 + 0xc8) != 0) { diff --git a/src/_ZN10MrBlizzard13InitResourcesEv.cpp b/src/_ZN10MrBlizzard13InitResourcesEv.cpp index 710b55530..527caa63e 100644 --- a/src/_ZN10MrBlizzard13InitResourcesEv.cpp +++ b/src/_ZN10MrBlizzard13InitResourcesEv.cpp @@ -43,15 +43,15 @@ int MrBlizzard::InitResources() _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0x30c, _ZN5Model8LoadFileER13SharedFilePtr(&data_ov081_02128db0), 1, -1); _ZN5Model8LoadFileER13SharedFilePtr(&data_ov081_02128d90); - _ZN11ShadowModel12InitCylinderEv((char *)&mShadowModel); + _ZN11ShadowModel12InitCylinderEv((char *)&(*(u8 *)&mShadowModel)); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov081_02128d98); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov081_02128db8); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov081_02128da8); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov081_02128d88); _ZN9Animation8LoadFileER13SharedFilePtr(&data_ov081_02128da0); - mPathId = mParam & 0xff; - mType = (mParam & 0xff00) >> 8; + mPathId = (*(s32 *)¶m1) & 0xff; + mType = ((*(s32 *)¶m1) & 0xff00) >> 8; if (mPathId == 0xff) mPathId = 0; if (mType == 0xff) @@ -88,7 +88,7 @@ int MrBlizzard::InitResources() mScaleX = 0x1000; mScaleY = 0x1000; mScaleZ = 0x1000; - unk_0a0 = -0xc8000; + mTerminalVelocity = -0xc8000; v.x = data_ov081_02128998.x; v.y = data_ov081_02128998.y; @@ -110,8 +110,8 @@ int MrBlizzard::InitResources() _ZN7PathPtr6FromIDEj(pp, mPathId); _ZNK7PathPtr7GetNodeER7Vector3j(pp, ((char *)this) + 0x5c, unk_424); unk_424 = 1; - unk_09c = -0x2000; - unk_0b0 = 0x10000000; + mVertAccel = -0x2000; + (*(s32 *)&mFlags) = 0x10000000; func_ov081_02125488(((char *)this), &data_ov081_02128e54); } else { *(s32 *)(((int)((char *)this) + 0x60)) -= 0x118000; @@ -119,12 +119,12 @@ int MrBlizzard::InitResources() if (mType == 3) { unk_108 = 0; unk_10a = 0; - unk_0b0 = 2; + (*(s32 *)&mFlags) = 2; } if (mType == 2) - unk_0b0 = 0x8000002; + (*(s32 *)&mFlags) = 0x8000002; else - unk_0b0 = 3; + (*(s32 *)&mFlags) = 3; } return 1; diff --git a/src/_ZN10PyramidTop16CleanupResourcesEv.cpp b/src/_ZN10PyramidTop16CleanupResourcesEv.cpp index 227981d62..dc89bd40e 100644 --- a/src/_ZN10PyramidTop16CleanupResourcesEv.cpp +++ b/src/_ZN10PyramidTop16CleanupResourcesEv.cpp @@ -10,7 +10,7 @@ extern int data_ov024_02113968[]; int PyramidTop::CleanupResources() { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(data_ov024_02113968))->Release(); ((SharedFilePtr *)(data_ov024_02113960))->Release(); return 1; diff --git a/src/_ZN10PyramidTop8BehaviorEv.cpp b/src/_ZN10PyramidTop8BehaviorEv.cpp index fb5ce15fe..8618b6a6a 100644 --- a/src/_ZN10PyramidTop8BehaviorEv.cpp +++ b/src/_ZN10PyramidTop8BehaviorEv.cpp @@ -22,13 +22,13 @@ int PyramidTop::Behavior() case 1: _ZN5Sound15PlaySecretSoundEP5ActorPt(((char*)this), (void*)((char*)&unk_3b4)); if (unk_3b2 == 0) { - _ZN5Sound9PlayBank3EjRK7Vector3(0x4b, (void*)((char*)&unk_074)); + _ZN5Sound9PlayBank3EjRK7Vector3(0x4b, (void*)((char*)&mCamSpacePosX)); } func_ov024_02111350(((char*)this)); break; case 2: if (_ZN5Sound15PlaySecretSoundEP5ActorPt(((char*)this), (void*)((char*)&unk_3b4))) { - _ZN5Sound9PlayBank3EjRK7Vector3(0x4c, (void*)((char*)&unk_074)); + _ZN5Sound9PlayBank3EjRK7Vector3(0x4c, (void*)((char*)&mCamSpacePosX)); func_ov024_021112c0(((char*)this)); } else { func_ov024_02111350(((char*)this)); diff --git a/src/_ZN10SlidingIce16CleanupResourcesEv.cpp b/src/_ZN10SlidingIce16CleanupResourcesEv.cpp index 4bb8584fb..69ab155e9 100644 --- a/src/_ZN10SlidingIce16CleanupResourcesEv.cpp +++ b/src/_ZN10SlidingIce16CleanupResourcesEv.cpp @@ -9,8 +9,8 @@ extern char data_ov027_02113be0[]; int SlidingIce::CleanupResources() { - unsigned char ok = (mActorID==0x5d); - if(ok){ ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); } + unsigned char ok = (actorID==0x5d); + if(ok){ ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov027_02113be8))->Release(); ((SharedFilePtr *)(data_ov027_02113be0))->Release(); return 1; diff --git a/src/_ZN10SlidingIce6RenderEv.cpp b/src/_ZN10SlidingIce6RenderEv.cpp index 758358867..d6479bdfe 100644 --- a/src/_ZN10SlidingIce6RenderEv.cpp +++ b/src/_ZN10SlidingIce6RenderEv.cpp @@ -17,7 +17,7 @@ void _ZN8Platform19UpdateClsnPosAndRotEv(void*); int SlidingIce::Render() { - int x = mActorID==0x5d; + int x = actorID==0x5d; if(x){ _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); diff --git a/src/_ZN10SlidingIce8BehaviorEv.cpp b/src/_ZN10SlidingIce8BehaviorEv.cpp index 08d9ad460..081a1d4ae 100644 --- a/src/_ZN10SlidingIce8BehaviorEv.cpp +++ b/src/_ZN10SlidingIce8BehaviorEv.cpp @@ -16,10 +16,10 @@ extern int _ZN5Actor5SpawnEjjRK7Vector3PK10Vector3_16as(unsigned int, unsigned i int SlidingIce::Behavior() { - int isType = (mActorID == 0x5d); + int isType = (actorID == 0x5d); if(isType){ if(DecIfAbove0_Short((char *)&unk_31e) == 0){ - _Z14ApproachLinearRiii((int*)((char *)&unk_098), 0, 0x3000); + _Z14ApproachLinearRiii((int*)((char *)&mHorzSpeed), 0, 0x3000); if(_Z14ApproachLinearRiii((int*)((char *)&mPosY), unk_324, 0xa000) != 0){ _ZN9ActorBase18MarkForDestructionEv(((char *)this)); } diff --git a/src/_ZN10StarSwitch16CleanupResourcesEv.cpp b/src/_ZN10StarSwitch16CleanupResourcesEv.cpp index f5c5c995b..b0595dc30 100644 --- a/src/_ZN10StarSwitch16CleanupResourcesEv.cpp +++ b/src/_ZN10StarSwitch16CleanupResourcesEv.cpp @@ -17,8 +17,8 @@ extern char data_ov002_0211092c; int StarSwitch::CleanupResources() { int t; - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(*(void**)(&data_ov002_021098e8 + unk_34c * 0xc)))->Release(); ((SharedFilePtr *)(*(void**)(&data_ov002_021098ec + unk_34c * 0xc)))->Release(); diff --git a/src/_ZN10StarSwitch8BehaviorEv.cpp b/src/_ZN10StarSwitch8BehaviorEv.cpp index f95861edc..2897a3c47 100644 --- a/src/_ZN10StarSwitch8BehaviorEv.cpp +++ b/src/_ZN10StarSwitch8BehaviorEv.cpp @@ -23,7 +23,7 @@ int StarSwitch::Behavior() int v; if (IsAreaShowing(unk_353) == 0) { - mAreaId = unk_353; + (*(u8 *)&mAreaId) = unk_353; unk_338 = 1; func_ov002_020ba01c(((char *)this), 2, 1, 0x333, 0x1000); func_ov002_020ba4d8(((char *)this), 0); @@ -57,7 +57,7 @@ int StarSwitch::Behavior() } if (_ZN5Actor10FindWithIDEj(id344) == 0) { mTargetActorID = 0; - mAreaId = unk_353; + (*(u8 *)&mAreaId) = unk_353; return 1; } } diff --git a/src/_ZN10StarSwitchD1Ev.cpp b/src/_ZN10StarSwitchD1Ev.cpp index aa9a51b8d..dde1988f1 100644 --- a/src/_ZN10StarSwitchD1Ev.cpp +++ b/src/_ZN10StarSwitchD1Ev.cpp @@ -2,12 +2,11 @@ // @symbol _ZN10StarSwitchD1Ev /* recovered: real C++ destructor -- the compiler emits the whole body * - * Two vtable stores and three destructor calls, all of them consequences of + * Two vtable stores and three destructor calls, every one a consequence of * `struct StarSwitch : Platform`: its own vptr, then Platform's -- inlined, * because Platform's destructor is defined in its class body -- then - * Platform's Model and MovingMeshCollider, then Actor. - * - * This class adds no member with a destructor, so it contributes nothing. + * Platform's Model and MovingMeshCollider, then Actor. This class adds no + * member with a destructor of its own. */ #include "StarSwitch.h" diff --git a/src/_ZN11CannonHatch13InitResourcesEv.cpp b/src/_ZN11CannonHatch13InitResourcesEv.cpp index 20c47af05..bfb9434ab 100644 --- a/src/_ZN11CannonHatch13InitResourcesEv.cpp +++ b/src/_ZN11CannonHatch13InitResourcesEv.cpp @@ -27,7 +27,7 @@ int CannonHatch::InitResources() { struct KCL_File *kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov002_0210e124); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((unsigned char *)this) + 0x124, kcl, *(struct Matrix4x3 *)((unsigned char *)&unk_2ec), 0x199, + ((unsigned char *)this) + 0x124, kcl, *(struct Matrix4x3 *)((unsigned char *)&(*(u8 *)&mClsnMat)), 0x199, mAngleY, data_ov002_0210d7f4); } unk_320 = mPosX; diff --git a/src/_ZN11CannonHatch6RenderEv.cpp b/src/_ZN11CannonHatch6RenderEv.cpp index db1478230..53c9013e6 100644 --- a/src/_ZN11CannonHatch6RenderEv.cpp +++ b/src/_ZN11CannonHatch6RenderEv.cpp @@ -15,7 +15,7 @@ struct Obj { int CannonHatch::Render() { - if (data_0209f2f8 == 6 && data_0209f220 == 1 && (*(int*)((char*)&mParam) & 0xff) == 1) + if (data_0209f2f8 == 6 && data_0209f220 == 1 && (*(int*)((char*)¶m1) & 0xff) == 1) return 1; if (*(unsigned char*)((char*)&unk_32e) != 0) return 1; diff --git a/src/_ZN11PyramidStep13InitResourcesEv.cpp b/src/_ZN11PyramidStep13InitResourcesEv.cpp index 181dae1a0..602e05a2f 100644 --- a/src/_ZN11PyramidStep13InitResourcesEv.cpp +++ b/src/_ZN11PyramidStep13InitResourcesEv.cpp @@ -28,14 +28,14 @@ int PyramidStep::InitResources() { struct KCL_File *kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov025_02113ab0); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char *)this) + 0x124, kcl, *(struct Matrix4x3 *)((char *)&unk_374), 0x1000, - unk_08e, data_ov025_02112ce8); + &mMeshCollider, kcl, *(struct Matrix4x3 *)((char *)&unk_374), 0x1000, + mAngleY, data_ov025_02112ce8); } - func_020393d4((int *)((char *)&mMovingMeshCollider), (int)&_ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + func_020393d4((int *)((char *)&(*(u8 *)&mMeshCollider)), (int)&_ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); { int v = 0x5000; - int k = unk_008 & 3; - unk_0a8 = -v; + int k = (*(s32 *)¶m1) & 3; + mVertSpeed = -v; unk_372 = 0; unk_370 = 0; switch (k) { @@ -48,7 +48,7 @@ int PyramidStep::InitResources() case 2: *(int*)(((int)((char *)this) + 0x60)) -= 0x1f4000; unk_372 = 1; - unk_0a8 = v; + mVertSpeed = v; break; } } diff --git a/src/_ZN11PyramidStep16CleanupResourcesEv.cpp b/src/_ZN11PyramidStep16CleanupResourcesEv.cpp index 61829d733..b13376578 100644 --- a/src/_ZN11PyramidStep16CleanupResourcesEv.cpp +++ b/src/_ZN11PyramidStep16CleanupResourcesEv.cpp @@ -11,7 +11,7 @@ extern int data_ov025_02113ab8[]; int PyramidStep::CleanupResources() { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(data_ov025_02113ab8))->Release(); ((SharedFilePtr *)(data_ov025_02113ab0))->Release(); return 1; diff --git a/src/_ZN12FortressWall13InitResourcesEv.cpp b/src/_ZN12FortressWall13InitResourcesEv.cpp index e460a7847..85e15abe1 100644 --- a/src/_ZN12FortressWall13InitResourcesEv.cpp +++ b/src/_ZN12FortressWall13InitResourcesEv.cpp @@ -20,7 +20,7 @@ int FortressWall::InitResources() int b = (int)(actorID == 0x30); if (b != 0) { unk_31e = 0; - unk_31f = (unsigned char)param1; + unk_31f = (unsigned char)(*(s32 *)¶m1); if (unk_31f == 0xff) unk_31f = 0; } else { diff --git a/src/_ZN12FortressWall16CleanupResourcesEv.cpp b/src/_ZN12FortressWall16CleanupResourcesEv.cpp index 075517cb1..66dc1696e 100644 --- a/src/_ZN12FortressWall16CleanupResourcesEv.cpp +++ b/src/_ZN12FortressWall16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern char data_ov079_0212805c[]; int FortressWall::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov079_02128058 + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov079_0212805c + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); return 1; diff --git a/src/_ZN12FortressWallD1Ev.cpp b/src/_ZN12FortressWallD1Ev.cpp index 5f7b9eec1..69cd68f09 100644 --- a/src/_ZN12FortressWallD1Ev.cpp +++ b/src/_ZN12FortressWallD1Ev.cpp @@ -6,7 +6,7 @@ * `struct FortressWall : Platform`: its own vptr, then Platform's -- inlined, * because Platform's destructor is defined in its class body -- then * Platform's Model and MovingMeshCollider, then Actor. This class adds no - * member with a destructor. + * member with a destructor of its own. */ #include "FortressWall.h" diff --git a/src/_ZN12SwitchPillar13InitResourcesEv.cpp b/src/_ZN12SwitchPillar13InitResourcesEv.cpp index 255b80e3b..f77e53033 100644 --- a/src/_ZN12SwitchPillar13InitResourcesEv.cpp +++ b/src/_ZN12SwitchPillar13InitResourcesEv.cpp @@ -21,13 +21,13 @@ int SwitchPillar::InitResources() { _ZN5Model8LoadFileER13SharedFilePtr(data_ov012_021124d0); _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov012_021124c8); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, data_ov012_021124d0[1], 1, 0x14); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, data_ov012_021124d0[1], 1, 0x14); _ZN18TextureTransformer7PrepareER8BMD_FileR8BTA_File(data_ov012_021124d0[1], data_ov012_02111c24); _ZN18TextureTransformer7SetFileER8BTA_Filei5Fix12IiEj(((char*)this)+0x320, data_ov012_02111c24, 0, 0x1000, 0); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, data_ov012_021124c8[1], ((char*)this)+0x2ec, 0x1000, mAngleY, data_ov012_02111c90); - ((MeshColliderBase *)(((char*)this)+0x124))->Enable((Actor *)(((char*)this))); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, data_ov012_021124c8[1], &mClsnMat, 0x1000, mAngleY, data_ov012_02111c90); + ((MeshColliderBase *)(&mMeshCollider))->Enable((Actor *)(((char*)this))); int v = mPosY - 0x4b0000; mLoweredY = v; if(data_0209caa0[2] & 0x80000){ diff --git a/src/_ZN12SwitchPillar16CleanupResourcesEv.cpp b/src/_ZN12SwitchPillar16CleanupResourcesEv.cpp index 64b728297..33ed1d766 100644 --- a/src/_ZN12SwitchPillar16CleanupResourcesEv.cpp +++ b/src/_ZN12SwitchPillar16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern int data_ov012_021124d0[]; int SwitchPillar::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov012_021124d0))->Release(); ((SharedFilePtr *)(data_ov012_021124c8))->Release(); diff --git a/src/_ZN12SwitchPillar8BehaviorEv.cpp b/src/_ZN12SwitchPillar8BehaviorEv.cpp index b7ec48e5a..4fa6fb697 100644 --- a/src/_ZN12SwitchPillar8BehaviorEv.cpp +++ b/src/_ZN12SwitchPillar8BehaviorEv.cpp @@ -21,7 +21,7 @@ int SwitchPillar::Behavior() mPosY = mLoweredY; } else if (*(int*)((char*)data_0209caa0 + 8) & 0x80000) { unk_338 = _ZN5Sound8PlayLongEjjjRK7Vector3s( - unk_338, 3, 0x96, (void*)((char*)&unk_074), 0); + unk_338, 3, 0x96, (void*)((char*)&mCamSpacePosX), 0); *(int*)((char*)&mPosY) -= 0x5000; unk_33e = 1; if (mPosY <= mLoweredY) { @@ -32,7 +32,7 @@ int SwitchPillar::Behavior() *(int*)&data_0209f32c = mPosY; _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); - unk_32c = 0x1000; - _ZN9Animation7AdvanceEv((char*)&mTextureTransformer); + (*(s32 *)((char *)&mTextureTransformer + 0xc)) = 0x1000; + _ZN9Animation7AdvanceEv((char*)&(*(u8 *)&mTextureTransformer)); return 1; } diff --git a/src/_ZN13BigBrickBlock16CleanupResourcesEv.cpp b/src/_ZN13BigBrickBlock16CleanupResourcesEv.cpp index 55f8fc0be..9c2bbb06a 100644 --- a/src/_ZN13BigBrickBlock16CleanupResourcesEv.cpp +++ b/src/_ZN13BigBrickBlock16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern char data_ov002_02108ab4[]; int BigBrickBlock::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov002_02108ab0 + (unsigned char)((char *)this)[0x32c]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov002_02108ab4 + (unsigned char)((char *)this)[0x32c]*0xc)))->Release(); return 1; diff --git a/src/_ZN13BigBrickBlock8BehaviorEv.cpp b/src/_ZN13BigBrickBlock8BehaviorEv.cpp index a676b69e9..81b4f1349 100644 --- a/src/_ZN13BigBrickBlock8BehaviorEv.cpp +++ b/src/_ZN13BigBrickBlock8BehaviorEv.cpp @@ -29,11 +29,11 @@ int BigBrickBlock::Behavior() } if (_ZN5Event6GetBitEj(mEventID) == 0 || unk_31e != 0) { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled() != 0) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled() != 0) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } else { - func_020393a4((int *)((char *)&mMeshCollider), 0x15e000); - func_02039394((int *)((char *)&mMeshCollider), 0x64000); + func_020393a4((int *)((char *)&(*(u8 *)&mMeshCollider)), 0x15e000); + func_02039394((int *)((char *)&(*(u8 *)&mMeshCollider)), 0x64000); _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(((char *)this), 0x150000, 0); } @@ -48,8 +48,8 @@ int BigBrickBlock::Behavior() v1 = 0x1c2000; v5 = 0x96000; } - func_020393a4((int *)((char *)&mMeshCollider), v1); - func_02039394((int *)((char *)&mMeshCollider), v5); + func_020393a4((int *)((char *)&(*(u8 *)&mMeshCollider)), v1); + func_02039394((int *)((char *)&(*(u8 *)&mMeshCollider)), v5); _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(((char *)this), 0x600000, 0); } return 1; diff --git a/src/_ZN13BigBrickBlockD1Ev.cpp b/src/_ZN13BigBrickBlockD1Ev.cpp index b3119a509..4c8fb3d4c 100644 --- a/src/_ZN13BigBrickBlockD1Ev.cpp +++ b/src/_ZN13BigBrickBlockD1Ev.cpp @@ -6,7 +6,7 @@ * `struct BigBrickBlock : Platform`: its own vptr, then Platform's -- inlined, * because Platform's destructor is defined in its class body -- then * Platform's Model and MovingMeshCollider, then Actor. This class adds no - * member with a destructor. + * member with a destructor of its own. */ #include "BigBrickBlock.h" diff --git a/src/_ZN13FortressTower16CleanupResourcesEv.cpp b/src/_ZN13FortressTower16CleanupResourcesEv.cpp index 6b76d9c66..68ddd5f99 100644 --- a/src/_ZN13FortressTower16CleanupResourcesEv.cpp +++ b/src/_ZN13FortressTower16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern char data_ov102_0214e18c[]; int FortressTower::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov102_0214e188 + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov102_0214e18c + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); return 1; diff --git a/src/_ZN13FortressTower8BehaviorEv.cpp b/src/_ZN13FortressTower8BehaviorEv.cpp index ffe008328..4f1a2ab79 100644 --- a/src/_ZN13FortressTower8BehaviorEv.cpp +++ b/src/_ZN13FortressTower8BehaviorEv.cpp @@ -10,7 +10,7 @@ extern unsigned char data_0209f2d8[]; int FortressTower::Behavior() { - unsigned short id = unk_00c; + unsigned short id = actorID; int r1 = 0; switch (id) { case 0x31: r1 = 0x900000; break; @@ -22,8 +22,8 @@ int FortressTower::Behavior() } int on = (data_0209f2d8[0] == 1); if (on) { - if (!((MeshColliderBase *)((char*)&mMovingMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char*)((char*)this)+0x124))->Enable((Actor *)(((char*)this))); + if (!((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char*)&mMeshCollider))->Enable((Actor *)(((char*)this))); } else { _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(((char*)this), r1, 0); } diff --git a/src/_ZN13PoleBillboard16CleanupResourcesEv.cpp b/src/_ZN13PoleBillboard16CleanupResourcesEv.cpp index ff38f41a7..7d026688c 100644 --- a/src/_ZN13PoleBillboard16CleanupResourcesEv.cpp +++ b/src/_ZN13PoleBillboard16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int PoleBillboard_ModelFile[]; int PoleBillboard::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(PoleBillboard_ModelFile))->Release(); ((SharedFilePtr *)(PoleBillboard_ClsnFile))->Release(); diff --git a/src/_ZN13QuestionBlock16CleanupResourcesEv.cpp b/src/_ZN13QuestionBlock16CleanupResourcesEv.cpp index f30101cad..a9be84741 100644 --- a/src/_ZN13QuestionBlock16CleanupResourcesEv.cpp +++ b/src/_ZN13QuestionBlock16CleanupResourcesEv.cpp @@ -26,17 +26,17 @@ extern char data_ov102_0214e7d0[]; int QuestionBlock::CleanupResources() { int b, b2, b3; - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); - b = (int)(mActorId == 0x16); + b = (int)(actorID == 0x16); if (b) ((SharedFilePtr *)(data_ov002_0210da58))->Release(); - b2 = (int)(mActorId == 0x14); + b2 = (int)(actorID == 0x14); if (b2) goto dosw; - b3 = (int)(mActorId == 0x15); + b3 = (int)(actorID == 0x15); if (b3) { dosw: switch (unk_3f3) { @@ -69,7 +69,7 @@ int QuestionBlock::CleanupResources() } } - switch (mActorId - 0x14) { + switch (actorID - 0x14) { case 0: ((SharedFilePtr *)(data_ov102_0214e7e8))->Release(); ((SharedFilePtr *)(data_ov102_0214e808))->Release(); diff --git a/src/_ZN13QuestionBlock6RenderEv.cpp b/src/_ZN13QuestionBlock6RenderEv.cpp index 6ef35aa69..b8ce2050e 100644 --- a/src/_ZN13QuestionBlock6RenderEv.cpp +++ b/src/_ZN13QuestionBlock6RenderEv.cpp @@ -20,7 +20,7 @@ int QuestionBlock::Render() if (unk_3e8 == 2) goto done; if ((*(int*)((char*)&data_0209caa0 + 4) & 0x80000000) == 0) { - int b = (mActorId == 0x14); + int b = (actorID == 0x14); if (b != 0) { Sub* s = (Sub*)((char*)&mModelAnim); s->m(0); @@ -28,7 +28,7 @@ int QuestionBlock::Render() } } { - Sub* s2 = (Sub*)((char*)&mModel); + Sub* s2 = (Sub*)((char*)&(*(u8 *)&mModel)); s2->m((int)((char*)&mScaleX)); } done: diff --git a/src/_ZN13QuestionBlock8BehaviorEv.cpp b/src/_ZN13QuestionBlock8BehaviorEv.cpp index fc58af02a..4197d9b27 100644 --- a/src/_ZN13QuestionBlock8BehaviorEv.cpp +++ b/src/_ZN13QuestionBlock8BehaviorEv.cpp @@ -25,20 +25,20 @@ int QuestionBlock::Behavior() func_ov102_02149ff0(((char*)this)); func_ov102_02149ea4(((char*)this)); } - func_020393a4((int*)((char*)&mMeshCollider), 0x8c000); - func_02039394((int*)((char*)&mMeshCollider), 0x46000); + func_020393a4((int*)((char*)&(*(u8 *)&mMeshCollider)), 0x8c000); + func_02039394((int*)((char*)&(*(u8 *)&mMeshCollider)), 0x46000); if (unk_3e8 != 0) { - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled() != 0) { - ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled() != 0) { + ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); } goto end; } if ((data_0209caa0[1] & 0x80000000) == 0) { - int b = (int)(mActorId == 0x14); + int b = (int)(actorID == 0x14); if (b != 0) { _ZN9Animation7AdvanceEv((char*)(Animation *)&mModelAnim); - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled() != 0) { - ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled() != 0) { + ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); } goto end; } @@ -46,8 +46,8 @@ int QuestionBlock::Behavior() { int b = (int)(data_0209f2d8 == 1); if (b != 0) { - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled() == 0) { - ((MeshColliderBase *)(((char*)this)+0x124))->Enable((Actor *)(((char*)this))); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled() == 0) { + ((MeshColliderBase *)(&mMeshCollider))->Enable((Actor *)(((char*)this))); } goto end; } diff --git a/src/_ZN13TTC_MovingBar13InitResourcesEv.cpp b/src/_ZN13TTC_MovingBar13InitResourcesEv.cpp index 87c6f9b21..e07be1397 100644 --- a/src/_ZN13TTC_MovingBar13InitResourcesEv.cpp +++ b/src/_ZN13TTC_MovingBar13InitResourcesEv.cpp @@ -32,8 +32,8 @@ int TTC_MovingBar::InitResources() char raycast[0x50]; int i; - if (mActorID != 0x72) { - if (mActorID == 0x73) + if (actorID != 0x72) { + if (actorID == 0x73) unk_31e = 1; } else { unk_31e = 0; @@ -41,7 +41,7 @@ int TTC_MovingBar::InitResources() i = unk_31e; _ZN9ModelBase7SetFileEP8BMD_Fileii( - ((char *)this) + 0xd4, + &mModel, _ZN5Model8LoadFileER13SharedFilePtr(*(void **)(data_ov065_0211d35c + i * 0xc)), 1, -1); @@ -51,14 +51,14 @@ int TTC_MovingBar::InitResources() i = unk_31e; _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char *)this) + 0x124, + &mMeshCollider, _ZN12MeshCollider8LoadFileER13SharedFilePtr(*(void **)(data_ov065_0211d360 + i * 0xc)), - ((char *)this) + 0x2ec, + &mClsnMat, 0x199, mAngleY, *(void **)(data_ov065_0211d364 + i * 0xc)); - func_020393d4((int *)((char *)&mMeshCollider), (int)&_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + func_020393d4((int *)((char *)&(*(u8 *)&mMeshCollider)), (int)&_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); pos.x = mPosX; pos.y = mPosY; diff --git a/src/_ZN13TTC_MovingBar16CleanupResourcesEv.cpp b/src/_ZN13TTC_MovingBar16CleanupResourcesEv.cpp index 27a8c9cba..00fb30b93 100644 --- a/src/_ZN13TTC_MovingBar16CleanupResourcesEv.cpp +++ b/src/_ZN13TTC_MovingBar16CleanupResourcesEv.cpp @@ -9,8 +9,8 @@ int TTC_MovingBar::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov065_0211d35c + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov065_0211d360 + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); return 1; diff --git a/src/_ZN14ArrowSignRight16CleanupResourcesEv.cpp b/src/_ZN14ArrowSignRight16CleanupResourcesEv.cpp index d92b1314b..a0e4bc7dd 100644 --- a/src/_ZN14ArrowSignRight16CleanupResourcesEv.cpp +++ b/src/_ZN14ArrowSignRight16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern char data_ov098_0213c380[]; int ArrowSignRight::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov098_0213c380 + (unsigned char)((char *)this)[0x37c]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov098_0213c384 + (unsigned char)((char *)this)[0x37c]*0xc)))->Release(); return 1; diff --git a/src/_ZN14ArrowSignRight8BehaviorEv.cpp b/src/_ZN14ArrowSignRight8BehaviorEv.cpp index 0b634d367..ad194544c 100644 --- a/src/_ZN14ArrowSignRight8BehaviorEv.cpp +++ b/src/_ZN14ArrowSignRight8BehaviorEv.cpp @@ -14,8 +14,8 @@ int ArrowSignRight::Behavior() { if (_ZN8Platform20UpdateKillByMegaCharEsss5Fix12IiE(((char*)this), -0x2000, 0, 0, 0x96000)) return 1; - func_02039394((int*)((char*)&mMeshCollider), 0xc0000); - func_020393a4((int*)((char*)&mMeshCollider), 0xe0000); + func_02039394((int*)((char*)&(*(u8 *)&mMeshCollider)), 0xc0000); + func_020393a4((int*)((char*)&(*(u8 *)&mMeshCollider)), 0xe0000); _ZN5Actor18DropShadowScaleXYZER11ShadowModelR9Matrix4x35Fix12IiES5_S5_j( ((char*)this), (void*)((char*)&mShadowModel), (void*)((char*)&unk_348), 0x10e000, 0x64000, 0x46000, 0xf); _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(((char*)this), 0x600000, 0); diff --git a/src/_ZN14BlueCoinSwitch13InitResourcesEv.cpp b/src/_ZN14BlueCoinSwitch13InitResourcesEv.cpp index 88f8d8507..363d22002 100644 --- a/src/_ZN14BlueCoinSwitch13InitResourcesEv.cpp +++ b/src/_ZN14BlueCoinSwitch13InitResourcesEv.cpp @@ -7,7 +7,7 @@ * Loads the model and collision mesh, unpacks the spawn word, and computes how * far the switch will sink. * - * mParam carries two fields: bits 0-3 are the event bit to set when the switch + * param1 carries two fields: bits 0-3 are the event bit to set when the switch * bottoms out, bits 8-15 are the countdown seed. That seed is stored in TENTHS * -- it is multiplied by 10 here -- and a byte of 0 or 0xff means "use the * default 0xfa" instead. @@ -63,18 +63,18 @@ int BlueCoinSwitch::InitResources() unsigned short* p; bmd = _ZN5Model8LoadFileER13SharedFilePtr(&data_ov002_02110acc); - _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, bmd, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&(*(u8 *)&mModel), bmd, 1, -1); - unk_32d = (int)mParam & 0xf; + unk_32d = (int)param1 & 0xf; _ZN8Platform21UpdateModelPosAndRotYEv(c); _ZN8Platform19UpdateClsnPosAndRotEv(c); kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(&data_ov002_02110ac4); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - &mMeshCollider, kcl, &mMatrix, 0x199, mAngleY, + &(*(u8 *)&mMeshCollider), kcl, &mClsnMat, 0x199, mAngleY, &data_ov002_0210d6f4); - func_020393c4(&mMeshCollider, (void*)&func_ov002_020f15b8); + func_020393c4(&(*(u8 *)&mMeshCollider), (void*)&func_ov002_020f15b8); unk_32c = 0; @@ -82,7 +82,7 @@ int BlueCoinSwitch::InitResources() and so set_fa rematerializes add r0,r4,#0x300 after ldrh clobbers r0. */ y = mPosY; unk_320 = y - 0x64000; - x = mParam; + x = param1; unk_32a = (x >> 8) & 0xff; unk_32e = mAreaId; val = unk_32a; diff --git a/src/_ZN14BlueCoinSwitch16CleanupResourcesEv.cpp b/src/_ZN14BlueCoinSwitch16CleanupResourcesEv.cpp index aa5037dfe..9e652c058 100644 --- a/src/_ZN14BlueCoinSwitch16CleanupResourcesEv.cpp +++ b/src/_ZN14BlueCoinSwitch16CleanupResourcesEv.cpp @@ -16,8 +16,8 @@ extern void _ZN13SharedFilePtr7ReleaseEv(void *); int BlueCoinSwitch::CleanupResources() { - if (_ZN16MeshColliderBase9IsEnabledEv(&mMeshCollider)) { - _ZN16MeshColliderBase7DisableEv(&mMeshCollider); + if (_ZN16MeshColliderBase9IsEnabledEv(&(*(u8 *)&mMeshCollider))) { + _ZN16MeshColliderBase7DisableEv(&(*(u8 *)&mMeshCollider)); } _ZN13SharedFilePtr7ReleaseEv(BlueCoinSwitch_ModelFile); _ZN13SharedFilePtr7ReleaseEv(BlueCoinSwitch_ClsnFile); diff --git a/src/_ZN14BlueCoinSwitch6RenderEv.cpp b/src/_ZN14BlueCoinSwitch6RenderEv.cpp index 70bc44161..db72fbbe5 100644 --- a/src/_ZN14BlueCoinSwitch6RenderEv.cpp +++ b/src/_ZN14BlueCoinSwitch6RenderEv.cpp @@ -20,7 +20,7 @@ struct Base { int BlueCoinSwitch::Render() { if (mPosY > unk_320) { - Base *bp = (Base *)&mModel; + Base *bp = (Base *)&(*(u8 *)&mModel); bp->m(0); } return 1; diff --git a/src/_ZN14BlueCoinSwitch8BehaviorEv.cpp b/src/_ZN14BlueCoinSwitch8BehaviorEv.cpp index 25d08daa3..cc960e206 100644 --- a/src/_ZN14BlueCoinSwitch8BehaviorEv.cpp +++ b/src/_ZN14BlueCoinSwitch8BehaviorEv.cpp @@ -68,7 +68,7 @@ s32 BlueCoinSwitch::Behavior() mPosY = unk_320; _ZN5Event6SetBitEj(unk_32d); unk_328 = unk_32a; - _ZN16MeshColliderBase7DisableEv(&mMeshCollider); + _ZN16MeshColliderBase7DisableEv(&(*(u8 *)&mMeshCollider)); _ZN5Actor8PoofDustEv(c); } } diff --git a/src/_ZN14KnockDownPlank13InitResourcesEv.cpp b/src/_ZN14KnockDownPlank13InitResourcesEv.cpp index eebfb0d05..395d35bc4 100644 --- a/src/_ZN14KnockDownPlank13InitResourcesEv.cpp +++ b/src/_ZN14KnockDownPlank13InitResourcesEv.cpp @@ -19,25 +19,25 @@ extern int _ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR int KnockDownPlank::InitResources() { - int b = (*(unsigned short*)((char*)&unk_00c) == 0x35) ? 1 : 0; + int b = (*(unsigned short*)((char*)&actorID) == 0x35) ? 1 : 0; if(b) *(int*)((char*)&mVariant) = 1; else *(int*)((char*)&mVariant) = 0; int j0 = *(int*)((char*)&mVariant) * 0xc; int m = _ZN5Model8LoadFileER13SharedFilePtr(*(void**)((char*)data_ov015_02114534 + j0)); - _ZN9ModelBase7SetFileEP8BMD_Fileii((char*)((char*)this)+0xd4, m, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii((char*)&mModel, m, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); int j = *(int*)((char*)&mVariant) * 0xc; int k = _ZN12MeshCollider8LoadFileER13SharedFilePtr(*(void**)((char*)data_ov015_02114538 + j)); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block((char*)((char*)this)+0x124, k, (char*)((char*)this)+0x2ec, 0x1000, mAngleY, *(void**)((char*)data_ov015_0211453c + j)); - func_020393d4((int*)((char*)&mMeshCollider), (int)&_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block((char*)&mMeshCollider, k, (char*)&mClsnMat, 0x1000, mAngleY, *(void**)((char*)data_ov015_0211453c + j)); + func_020393d4((int*)((char*)&(*(u8 *)&mMeshCollider)), (int)&_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); int tmp[3]; tmp[0] = 0x1000; tmp[1] = 0; tmp[2] = 0; - func_01ffb0a4((char*)&mMeshCollider); - func_01ffb07c((char*)((char*)this)+0x124, tmp); - func_020396d0((int*)((char*)&mMeshCollider), 0xccd); - *(int*)((char*)&unk_320) = *(int*)((char*)&unk_05c); - *(int*)((char*)&unk_324) = *(int*)((char*)&unk_060); - *(int*)((char*)&unk_328) = *(int*)((char*)&unk_064); + func_01ffb0a4((char*)&(*(u8 *)&mMeshCollider)); + func_01ffb07c((char*)&mMeshCollider, tmp); + func_020396d0((int*)((char*)&(*(u8 *)&mMeshCollider)), 0xccd); + *(int*)((char*)&unk_320) = *(int*)((char*)&mPosX); + *(int*)((char*)&unk_324) = *(int*)((char*)&mPosY); + *(int*)((char*)&unk_328) = *(int*)((char*)&mPosZ); func_ov015_02111fb8(((char*)this), 5); return 1; } diff --git a/src/_ZN14KnockDownPlank16CleanupResourcesEv.cpp b/src/_ZN14KnockDownPlank16CleanupResourcesEv.cpp index 7f5f3ae92..49535a6ef 100644 --- a/src/_ZN14KnockDownPlank16CleanupResourcesEv.cpp +++ b/src/_ZN14KnockDownPlank16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern char data_ov015_02114534[]; int KnockDownPlank::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void **)(data_ov015_02114534 + mVariant * 0xc)))->Release(); ((SharedFilePtr *)(*(void **)(data_ov015_02114538 + mVariant * 0xc)))->Release(); return 1; diff --git a/src/_ZN14MovingBarSmall16CleanupResourcesEv.cpp b/src/_ZN14MovingBarSmall16CleanupResourcesEv.cpp index ec9b141ce..716b8ae94 100644 --- a/src/_ZN14MovingBarSmall16CleanupResourcesEv.cpp +++ b/src/_ZN14MovingBarSmall16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int MovingBarSmall_ModelFile[]; int MovingBarSmall::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(MovingBarSmall_ModelFile))->Release(); ((SharedFilePtr *)(MovingBarSmall_ClsnFile))->Release(); diff --git a/src/_ZN14SquarePathLift13InitResourcesEv.cpp b/src/_ZN14SquarePathLift13InitResourcesEv.cpp index 1597ee2d8..2ecf8edf0 100644 --- a/src/_ZN14SquarePathLift13InitResourcesEv.cpp +++ b/src/_ZN14SquarePathLift13InitResourcesEv.cpp @@ -19,14 +19,14 @@ extern struct SFP data_ov052_021125a0; int SquarePathLift::InitResources() { void* f = _ZN5Model8LoadFileER13SharedFilePtr(data_ov052_021125a0.a); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, f, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, f, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); void* f2 = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov052_021125a0.b); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, f2, ((char*)this)+0x2ec, 0x199, mAngleY, data_ov052_021125a0.c); - func_020393d4((int*)((char*)&mMeshCollider), &_ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - _ZN7PathPtr6FromIDEj(((char*)this)+0x320, mParam&0xff); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, f2, &mClsnMat, 0x199, mAngleY, data_ov052_021125a0.c); + func_020393d4((int*)((char*)&(*(u8 *)&mMeshCollider)), &_ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + _ZN7PathPtr6FromIDEj(((char*)this)+0x320, (*(s32 *)¶m1)&0xff); mPathDir = 1; - mMoveSpeed = 0xa000; + mHorzSpeed = 0xa000; return 1; } diff --git a/src/_ZN14SquarePathLift16CleanupResourcesEv.cpp b/src/_ZN14SquarePathLift16CleanupResourcesEv.cpp index 92f803a70..38cd8a6d6 100644 --- a/src/_ZN14SquarePathLift16CleanupResourcesEv.cpp +++ b/src/_ZN14SquarePathLift16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern SFP data_ov052_021125a0[2]; int SquarePathLift::CleanupResources() { - if(((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)((void*)data_ov052_021125a0[0].x))->Release(); ((SharedFilePtr *)((void*)data_ov052_021125a0[1].x))->Release(); return 1; diff --git a/src/_ZN14SquarePathLift8BehaviorEv.cpp b/src/_ZN14SquarePathLift8BehaviorEv.cpp index e34f063de..515aa2ddf 100644 --- a/src/_ZN14SquarePathLift8BehaviorEv.cpp +++ b/src/_ZN14SquarePathLift8BehaviorEv.cpp @@ -4,7 +4,6 @@ #include "decl_PathPtr.h" /* recovered: named members + shared header, real C++ method */ #include "SquarePathLift.h" -typedef int Fix12; extern "C" { extern void _ZNK7PathPtr7GetNodeER7Vector3j(void *p, void *out, unsigned idx); extern void Vec3_Sub(void *out, void *a, void *b); @@ -14,7 +13,7 @@ extern void Vec3_MulScalar(void *out, void *v, int s); extern void SubVec3(void *a, void *b, void *c); extern void _ZN8Platform21UpdateModelPosAndRotYEv(void *p); extern void _ZN8Platform19UpdateClsnPosAndRotEv(void *p); -extern int _ZN8Platform13IsClsnInRangeE5Fix12IiES1_(void *p, Fix12 a, int b); +extern int _ZN8Platform13IsClsnInRangeE5Fix12IiES1_(void *p, int a, int b); } struct V3 { int x, y, z; }; @@ -22,7 +21,7 @@ int SquarePathLift::Behavior() { struct V3 prev, node, diff, scaled1, scaled2; int looped, delta, len; - mMoveSpeed = 0xa000; + mHorzSpeed = 0xa000; delta = mNodeIndex - mPathDir; looped = 0; if (_ZNK7PathPtr5LoopsEv((char *)&mPath)) { @@ -37,12 +36,12 @@ int SquarePathLift::Behavior() _ZNK7PathPtr7GetNodeER7Vector3j(((char *)this) + 0x320, &prev, mNodeIndex); Vec3_Sub(&diff, ((char *)this) + 0x5c, &prev); len = LenVec3(&diff); - if (len == 0 || len <= mMoveSpeed) { - Vec3_MulScalar(&scaled1, &diff, _ZN4cstd4fdivEii(mMoveSpeed, len)); + if (len == 0 || len <= mHorzSpeed) { + Vec3_MulScalar(&scaled1, &diff, _ZN4cstd4fdivEii(mHorzSpeed, len)); SubVec3(((char *)this) + 0x5c, &scaled1, ((char *)this) + 0x5c); looped = 1; } else { - Vec3_MulScalar(&scaled2, &diff, _ZN4cstd4fdivEii(mMoveSpeed, len)); + Vec3_MulScalar(&scaled2, &diff, _ZN4cstd4fdivEii(mHorzSpeed, len)); SubVec3(((char *)this) + 0x5c, &scaled2, ((char *)this) + 0x5c); } if (looped) { diff --git a/src/_ZN15ChainChompFence13InitResourcesEv.cpp b/src/_ZN15ChainChompFence13InitResourcesEv.cpp index 646aef474..1f3285356 100644 --- a/src/_ZN15ChainChompFence13InitResourcesEv.cpp +++ b/src/_ZN15ChainChompFence13InitResourcesEv.cpp @@ -23,10 +23,10 @@ extern int data_ov014_021149c0[]; int ChainChompFence::InitResources() { int m = _ZN5Model8LoadFileER13SharedFilePtr(data_ov014_021149c0); - _ZN9ModelBase7SetFileEP8BMD_Fileii((char*)((char*)this)+0xd4, m, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii((char*)&mModel, m, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); int k = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov014_021149b8); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block((char*)((char*)this)+0x124, k, (char*)((char*)this)+0x2ec, 0x1000, unk_08e, (void*)data_ov014_02114558); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block((char*)&mMeshCollider, k, (char*)&mClsnMat, 0x1000, mAngleY, (void*)data_ov014_02114558); return 1; } diff --git a/src/_ZN15ChainChompFence16CleanupResourcesEv.cpp b/src/_ZN15ChainChompFence16CleanupResourcesEv.cpp index 3fee05e1a..843334d94 100644 --- a/src/_ZN15ChainChompFence16CleanupResourcesEv.cpp +++ b/src/_ZN15ChainChompFence16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int data_ov014_021149c0[]; int ChainChompFence::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov014_021149c0))->Release(); ((SharedFilePtr *)(data_ov014_021149b8))->Release(); diff --git a/src/_ZN15FireSeaElevator13InitResourcesEv.cpp b/src/_ZN15FireSeaElevator13InitResourcesEv.cpp index 75d38988a..889bfa2fe 100644 --- a/src/_ZN15FireSeaElevator13InitResourcesEv.cpp +++ b/src/_ZN15FireSeaElevator13InitResourcesEv.cpp @@ -18,7 +18,7 @@ int FireSeaElevator::InitResources() { void* m = _ZN5Model8LoadFileER13SharedFilePtr(data_ov045_021131b0); _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this) + 0xd4, m, 1, -1); - if (unk_008 != 0xffff) { + if ((*(s32 *)¶m1) != 0xffff) { int* p = (int*)(((int)((char*)this) + 0x60)); *p -= 0x12c000; } @@ -26,7 +26,7 @@ int FireSeaElevator::InitResources() _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); void* mc = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov045_021131a8); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char*)this) + 0x124, mc, ((char*)this) + 0x2ec, 0x199, unk_08e, data_ov045_02112510); + ((char*)this) + 0x124, mc, ((char*)this) + 0x2ec, 0x199, mAngleY, data_ov045_02112510); _ZN18MovingCylinderClsn4InitEP5Actor5Fix12IiES3_jj( ((char*)this) + 0x320, ((char*)this), 0x35555, 0x258000, 0x280000c, 0); return 1; diff --git a/src/_ZN15FireSeaElevator16CleanupResourcesEv.cpp b/src/_ZN15FireSeaElevator16CleanupResourcesEv.cpp index b042f9f03..eda3a5d5e 100644 --- a/src/_ZN15FireSeaElevator16CleanupResourcesEv.cpp +++ b/src/_ZN15FireSeaElevator16CleanupResourcesEv.cpp @@ -10,7 +10,7 @@ extern int data_ov045_021131b0[]; int FireSeaElevator::CleanupResources() { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(data_ov045_021131b0))->Release(); ((SharedFilePtr *)(data_ov045_021131a8))->Release(); return 1; diff --git a/src/_ZN15FireSeaElevator8BehaviorEv.cpp b/src/_ZN15FireSeaElevator8BehaviorEv.cpp index 20764c9e6..c97e2f557 100644 --- a/src/_ZN15FireSeaElevator8BehaviorEv.cpp +++ b/src/_ZN15FireSeaElevator8BehaviorEv.cpp @@ -2,12 +2,11 @@ // @symbol _ZN15FireSeaElevator8BehaviorEv /* recovered: named members + shared header, real C++ method */ #include "FireSeaElevator.h" -typedef int Fix12; extern "C" { extern void _ZN12CylinderClsn5ClearEv(void *self); extern void _ZN12CylinderClsn6UpdateEv(void *self); extern void _ZN8Platform21UpdateModelPosAndRotYEv(void *self); -extern int _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(void *self, Fix12 a, int b); +extern int _ZN8Platform21IsClsnInRangeOnScreenE5Fix12IiES1_(void *self, int a, int b); extern void _ZN8Platform19UpdateClsnPosAndRotEv(void *self); } extern short data_02082214[]; @@ -16,7 +15,7 @@ int FireSeaElevator::Behavior() { _ZN12CylinderClsn5ClearEv((char *)&mMovingCylinderClsn); _ZN12CylinderClsn6UpdateEv((char *)&mMovingCylinderClsn); - if (unk_008 != 0xffff) { + if ((*(s32 *)¶m1) != 0xffff) { int idx = unk_354 >> 4; int s = *(short*)((char*)data_02082214 + (idx << 2)); *(int*)(((int)((char *)this) + 0x60)) = diff --git a/src/_ZN15TtcRotatingGear13InitResourcesEv.cpp b/src/_ZN15TtcRotatingGear13InitResourcesEv.cpp index cc31276b4..e20914e3d 100644 --- a/src/_ZN15TtcRotatingGear13InitResourcesEv.cpp +++ b/src/_ZN15TtcRotatingGear13InitResourcesEv.cpp @@ -4,14 +4,13 @@ #include "decl_common.h" /* recovered: named members + shared header, real C++ method */ #include "TtcRotatingGear.h" -typedef int Fix12; extern void* _ZN5Model8LoadFileER13SharedFilePtr(void*); extern void _ZN9ModelBase7SetFileEP8BMD_Fileii(void*, void*, int, int); extern void _ZN8Platform21UpdateModelPosAndRotYEv(void*); extern void _ZN8Platform19UpdateClsnPosAndRotEv(void*); extern void* _ZN12MeshCollider8LoadFileER13SharedFilePtr(void*); extern void _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - void*, void*, void*, Fix12, short, void*); + void*, void*, void*, int, short, void*); extern unsigned char data_0209f2c0[]; extern char data_ov065_0211c0d4[]; @@ -38,7 +37,7 @@ int TtcRotatingGear::InitResources() b = mMoveDir; unk_32c = *(unsigned short*)(data_ov065_0211c0d4 + (ip << 4) + (b << 3)); b = mMoveDir; - unk_0a8 = *(int*)(data_ov065_0211c0d0 + (ip << 4) + (b << 3)); - unk_0a0 = -0x3c000; + mVertSpeed = *(int*)(data_ov065_0211c0d0 + (ip << 4) + (b << 3)); + mTerminalVelocity = -0x3c000; return 1; } diff --git a/src/_ZN15TtcRotatingGear16CleanupResourcesEv.cpp b/src/_ZN15TtcRotatingGear16CleanupResourcesEv.cpp index 554193451..d77a98949 100644 --- a/src/_ZN15TtcRotatingGear16CleanupResourcesEv.cpp +++ b/src/_ZN15TtcRotatingGear16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int TtcRotatingGear_ModelFile[]; int TtcRotatingGear::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(TtcRotatingGear_ModelFile))->Release(); ((SharedFilePtr *)(TtcRotatingGear_ClsnFile))->Release(); diff --git a/src/_ZN16RotatingCogSmall13InitResourcesEv.cpp b/src/_ZN16RotatingCogSmall13InitResourcesEv.cpp index 50ad2869d..142676094 100644 --- a/src/_ZN16RotatingCogSmall13InitResourcesEv.cpp +++ b/src/_ZN16RotatingCogSmall13InitResourcesEv.cpp @@ -29,26 +29,26 @@ int RotatingCogSmall::InitResources() { int b; - b = (int)(unk_00c == 0x77); + b = (int)(actorID == 0x77); if (b != 0) { - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0xd4, + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, _ZN5Model8LoadFileER13SharedFilePtr(data_ov035_02112c78), 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char *)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char *)this)); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char *)this) + 0x124, + &mMeshCollider, _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov035_02112c68), - ((char *)this) + 0x2ec, 0x1000, unk_08e, data_ov035_021121d8); - func_020396c0(((char *)this) + 0x124, 0); - func_020393d4(((char *)this) + 0x124, &_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + &mClsnMat, 0x1000, mAngleY, data_ov035_021121d8); + func_020396c0(&mMeshCollider, 0); + func_020393d4(&mMeshCollider, &_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); mRotationState = 0; } else { - b = (int)(unk_00c == 0x79); + b = (int)(actorID == 0x79); if (b != 0) { - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0xd4, + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, _ZN5Model8LoadFileER13SharedFilePtr(data_ov035_02112c70), 1, -1); } else { - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0xd4, + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, _ZN5Model8LoadFileER13SharedFilePtr(data_ov035_02112c60), 1, -1); } _ZN8Platform21UpdateModelPosAndRotYEv(((char *)this)); diff --git a/src/_ZN16RotatingCogSmall16CleanupResourcesEv.cpp b/src/_ZN16RotatingCogSmall16CleanupResourcesEv.cpp index ca74a072e..d85d79ffd 100644 --- a/src/_ZN16RotatingCogSmall16CleanupResourcesEv.cpp +++ b/src/_ZN16RotatingCogSmall16CleanupResourcesEv.cpp @@ -15,12 +15,12 @@ extern char data_ov035_02112c60[]; int RotatingCogSmall::CleanupResources() { if(mRotationState==0){ - if(((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(data_ov035_02112c78))->Release(); ((SharedFilePtr *)(data_ov035_02112c68))->Release(); } else { - int on = (unk_00c==0x79); + int on = (actorID==0x79); if(on) ((SharedFilePtr *)(data_ov035_02112c70))->Release(); else diff --git a/src/_ZN16RotatingCogSmall8BehaviorEv.cpp b/src/_ZN16RotatingCogSmall8BehaviorEv.cpp index eb9694fe2..0d613d0ec 100644 --- a/src/_ZN16RotatingCogSmall8BehaviorEv.cpp +++ b/src/_ZN16RotatingCogSmall8BehaviorEv.cpp @@ -24,7 +24,7 @@ int RotatingCogSmall::Behavior() return 1; } - if (_Z14ApproachLinearRsss((short*)((char*)&unk_08e), unk_322, 0xc8) != 0 && + if (_Z14ApproachLinearRsss((short*)((char*)&mAngleY), unk_322, 0xc8) != 0 && DecIfAbove0_Short((unsigned short*)((char*)&unk_31e)) == 0) { short* p = (short*)(((int)((char*)this) + 0x322)); *p = *p + unk_324; diff --git a/src/_ZN17SlidingPlatformWf16CleanupResourcesEv.cpp b/src/_ZN17SlidingPlatformWf16CleanupResourcesEv.cpp index f24563c9e..29e50ac6c 100644 --- a/src/_ZN17SlidingPlatformWf16CleanupResourcesEv.cpp +++ b/src/_ZN17SlidingPlatformWf16CleanupResourcesEv.cpp @@ -9,8 +9,8 @@ int SlidingPlatformWf::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov091_02135024 + (unsigned char)((char *)this)[0x322]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov091_02135028 + (unsigned char)((char *)this)[0x322]*0xc)))->Release(); return 1; diff --git a/src/_ZN19FloatingFloorLllBig16CleanupResourcesEv.cpp b/src/_ZN19FloatingFloorLllBig16CleanupResourcesEv.cpp index d8cb88524..c5ef03701 100644 --- a/src/_ZN19FloatingFloorLllBig16CleanupResourcesEv.cpp +++ b/src/_ZN19FloatingFloorLllBig16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int FloatingFloorLllBig_ModelFile[]; int FloatingFloorLllBig::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(FloatingFloorLllBig_ModelFile))->Release(); ((SharedFilePtr *)(FloatingFloorLllBig_ClsnFile))->Release(); diff --git a/src/_ZN19FloatingFloorLllBigD1Ev.cpp b/src/_ZN19FloatingFloorLllBigD1Ev.cpp index d89c13a2b..d2640a117 100644 --- a/src/_ZN19FloatingFloorLllBigD1Ev.cpp +++ b/src/_ZN19FloatingFloorLllBigD1Ev.cpp @@ -2,12 +2,11 @@ // @symbol _ZN19FloatingFloorLllBigD1Ev /* recovered: real C++ destructor -- the compiler emits the whole body * - * Two vtable stores and three destructor calls, all of them consequences of + * Two vtable stores and three destructor calls, every one a consequence of * `struct FloatingFloorLllBig : Platform`: its own vptr, then Platform's -- inlined, * because Platform's destructor is defined in its class body -- then - * Platform's Model and MovingMeshCollider, then Actor. - * - * This class adds no member with a destructor, so it contributes nothing. + * Platform's Model and MovingMeshCollider, then Actor. This class adds no + * member with a destructor of its own. */ #include "FloatingFloorLllBig.h" diff --git a/src/_ZN19RotatingPlatformLll13InitResourcesEv.cpp b/src/_ZN19RotatingPlatformLll13InitResourcesEv.cpp index d4595e704..4489bc39d 100644 --- a/src/_ZN19RotatingPlatformLll13InitResourcesEv.cpp +++ b/src/_ZN19RotatingPlatformLll13InitResourcesEv.cpp @@ -4,14 +4,13 @@ #include "decl_common.h" /* recovered: named members + shared header, real C++ method */ #include "RotatingPlatformLll.h" -typedef int Fix12; extern "C" { extern void* _ZN5Model8LoadFileER13SharedFilePtr(void*); extern int _ZN9ModelBase7SetFileEP8BMD_Fileii(void*, void*, int, int); extern int _ZN8Platform21UpdateModelPosAndRotYEv(void*); extern int _ZN8Platform19UpdateClsnPosAndRotEv(void*); extern void* _ZN12MeshCollider8LoadFileER13SharedFilePtr(void*); -extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(void*, void*, void*, Fix12, short, void*); +extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(void*, void*, void*, int, short, void*); extern int func_020393d4(void*, void*); extern int func_020393c4(void*, void*); } @@ -25,13 +24,13 @@ int RotatingPlatformLll::InitResources() void* mdl; void* kcl; mdl = _ZN5Model8LoadFileER13SharedFilePtr(data_ov022_02114558); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, mdl, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, mdl, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov022_02114550); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, kcl, ((char*)this)+0x2ec, 0x199, mAngleY, data_ov064_0211bb0c); - func_020393d4(((char*)this)+0x124, &_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - func_020393c4(((char*)this)+0x124, &func_ov022_0211193c); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, kcl, &mClsnMat, 0x199, mAngleY, data_ov064_0211bb0c); + func_020393d4(&mMeshCollider, &_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + func_020393c4(&mMeshCollider, &func_ov022_0211193c); unk_320 = mPosY; return 1; } diff --git a/src/_ZN19RotatingPlatformLll16CleanupResourcesEv.cpp b/src/_ZN19RotatingPlatformLll16CleanupResourcesEv.cpp index 9dad5d7ae..115fd65c5 100644 --- a/src/_ZN19RotatingPlatformLll16CleanupResourcesEv.cpp +++ b/src/_ZN19RotatingPlatformLll16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern int data_ov022_02114558[]; int RotatingPlatformLll::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov022_02114558))->Release(); ((SharedFilePtr *)(data_ov022_02114550))->Release(); diff --git a/src/_ZN19RotatingPlatformLll8BehaviorEv.cpp b/src/_ZN19RotatingPlatformLll8BehaviorEv.cpp index 92b7228f6..9fddc56f4 100644 --- a/src/_ZN19RotatingPlatformLll8BehaviorEv.cpp +++ b/src/_ZN19RotatingPlatformLll8BehaviorEv.cpp @@ -8,7 +8,7 @@ extern void func_020393a4(int* p, int v); int RotatingPlatformLll::Behavior() { - func_020393a4((int*)((char*)&mMeshCollider), 0x150000); + func_020393a4((int*)((char*)&(*(u8 *)&mMeshCollider)), 0x150000); if (unk_324) { int* py = (int*)(((int)((char*)this) + 0x60)); *py = *py - 0x2000; diff --git a/src/_ZN19RotatingPlatformWdw13InitResourcesEv.cpp b/src/_ZN19RotatingPlatformWdw13InitResourcesEv.cpp index f5fe9a5dc..b8955706a 100644 --- a/src/_ZN19RotatingPlatformWdw13InitResourcesEv.cpp +++ b/src/_ZN19RotatingPlatformWdw13InitResourcesEv.cpp @@ -27,11 +27,11 @@ int RotatingPlatformWdw::InitResources() void *k; m = _ZN5Model8LoadFileER13SharedFilePtr(data_ov029_021142fc); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0xd4, m, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, m, 1, -1); _ZN18TextureTransformer7PrepareER8BMD_FileR8BTA_File(data_ov029_021142fc[1], &data_ov029_02112fb8); _ZN18TextureTransformer7SetFileER8BTA_Filei5Fix12IiEj(((char *)this) + 0x320, &data_ov029_02112fb8, 0, 0x1000, 0); - unk_338 = (u8)(mParam & 1); + unk_338 = (u8)((*(s32 *)¶m1) & 1); if (unk_338 == 0) { unsigned int idx = data_0209f2c0[0]; if (idx >= 3) idx = 2; @@ -45,8 +45,8 @@ int RotatingPlatformWdw::InitResources() k = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov029_02114304); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char *)this) + 0x124, k, ((char *)this) + 0x2ec, 0x1000, mAngleY, &data_ov029_02112fec); - ((MeshColliderBase *)(((char *)this) + 0x124))->Enable((Actor *)(((char *)this))); + &mMeshCollider, k, &mClsnMat, 0x1000, mAngleY, &data_ov029_02112fec); + ((MeshColliderBase *)(&mMeshCollider))->Enable((Actor *)(((char *)this))); unk_340 = (u8)mAreaId; mAreaId = -1; diff --git a/src/_ZN19RotatingPlatformWdw16CleanupResourcesEv.cpp b/src/_ZN19RotatingPlatformWdw16CleanupResourcesEv.cpp index 284adf21a..d267f6443 100644 --- a/src/_ZN19RotatingPlatformWdw16CleanupResourcesEv.cpp +++ b/src/_ZN19RotatingPlatformWdw16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int RotatingPlatformWdw_ModelFile[]; int RotatingPlatformWdw::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(RotatingPlatformWdw_ModelFile))->Release(); ((SharedFilePtr *)(RotatingPlatformWdw_ClsnFile))->Release(); diff --git a/src/_ZN19RotatingPlatformWdw8BehaviorEv.cpp b/src/_ZN19RotatingPlatformWdw8BehaviorEv.cpp index 404658a93..61e2a0b37 100644 --- a/src/_ZN19RotatingPlatformWdw8BehaviorEv.cpp +++ b/src/_ZN19RotatingPlatformWdw8BehaviorEv.cpp @@ -25,11 +25,11 @@ int RotatingPlatformWdw::Behavior() /* area id at 0x340: ROM does add r0,r4,#0x300; ldrsb r0,[r0,#0x40] */ if (IsAreaShowing(*(s8 *)((u8 *)(((int)((u8 *)this) + 0x300)) + 0x40)) == 0) { mAreaId = *(s8 *)((u8 *)(((unsigned)((u8 *)this) + 0x300)) + 0x40); - if (((MeshColliderBase *)((u8 *)&mMeshCollider))->IsEnabled() != 0) { - ((MeshColliderBase *)((u8 *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((u8 *)&(*(u8 *)&mMeshCollider)))->IsEnabled() != 0) { + ((MeshColliderBase *)((u8 *)&(*(u8 *)&mMeshCollider)))->Disable(); } } else { - if (((MeshColliderBase *)((u8 *)&mMeshCollider))->IsEnabled() == 0) { + if (((MeshColliderBase *)((u8 *)&(*(u8 *)&mMeshCollider)))->IsEnabled() == 0) { ((MeshColliderBase *)(((u8 *)this) + 0x124))->Enable((Actor *)(((u8 *)this))); } } @@ -65,7 +65,7 @@ int RotatingPlatformWdw::Behavior() data_0209f32c = unk_344; func_ov029_021122b4(((u8 *)this)); func_ov029_02112250(((u8 *)this)); - unk_32c = 0x1000; - _ZN9Animation7AdvanceEv((u8 *)&mTextureTransformer); + (*(s32 *)((char *)&mTextureTransformer + 0xc)) = 0x1000; + _ZN9Animation7AdvanceEv((u8 *)&(*(u8 *)&mTextureTransformer)); return 1; } diff --git a/src/_ZN5EnemyD0Ev.c b/src/_ZN5EnemyD0Ev.c deleted file mode 100644 index cc732468e..000000000 --- a/src/_ZN5EnemyD0Ev.c +++ /dev/null @@ -1,28 +0,0 @@ -// @symbol _ZN5EnemyD0Ev -/* recovered: named members + shared header, declarations from a shared header */ -#include "decl_Actor.h" -#include "decl_common.h" -/* This file does NOT include Enemy.h, and that is deliberate. - * - * Enemy.h now declares a virtual destructor, so in C++ Enemy carries a vptr at - * 0x00 that a C translation unit does not model -- the two languages would - * disagree about every field offset by four bytes. This file was Enemy.h's - * only C reader, and it never touched a field: it uses t[0] and passes t - * along, nothing more. Dropping the include removes the disagreement without - * pretending the file has been migrated. - * - * Renaming it .cpp would be the other way to remove the C reader, and it is - * the WRONG way: D0 is the deleting destructor, which is compiler-generated - * and cannot be written by hand, so the file would stay hand-spelt and merely - * change extension -- `cpp_still_handspelled` 155 -> 156. That is the "renamed, - * never migrated" debt of issue #821, and the ratchet correctly rejects it. - */ -extern void* data_020a0eac; -extern int data_ov002_021081e4[]; -int *_ZN5EnemyD0Ev(int *t) -{ - t[0] = (int)data_ov002_021081e4; - _ZN5ActorD2Ev(t); - _ZN6Memory10DeallocateEPvP4Heap(t, data_020a0eac); - return t; -} diff --git a/src/_ZN5EnemyD0Ev.cpp b/src/_ZN5EnemyD0Ev.cpp new file mode 100644 index 000000000..5574dc11a --- /dev/null +++ b/src/_ZN5EnemyD0Ev.cpp @@ -0,0 +1,18 @@ +//cpp +// @symbol _ZN5EnemyD0Ev +/* recovered: real C++ deleting destructor -- the compiler emits the whole body + * + * D0 is the DELETING destructor: destroy through this class and its bases -- + * which is why more than one vptr store appears -- then return the object to + * its heap. Nobody writes that; declaring `~Enemy()` is enough, because mwcc + * emits D2, D0 and D1 together and objisolate keeps the one this file is bound + * to. + * + * The deallocation is an inline operator delete, which is why nothing below + * mentions a heap. + */ +#include "Enemy.h" + +Enemy::~Enemy() +{ +} diff --git a/src/_ZN5EnemyD1Ev.c b/src/_ZN5EnemyD1Ev.c deleted file mode 100644 index a09da167c..000000000 --- a/src/_ZN5EnemyD1Ev.c +++ /dev/null @@ -1,22 +0,0 @@ -/* Enemy::~Enemy() at 0x020aed74 (ov002) -- complete-object destructor (D1). - * Sets the vptr to Enemy's vtable, then delegates to the Actor base-object - * destructor and returns this. Enemy (0x110) : Actor (0xd4) : ActorBase. - * - * It occupies slot 16 of dEnemyBase_c's vtable, and a D2 is never in a vtable; - * it was named D2 until notes/dtor-variant-audit.md. The Actor call below is a - * genuine D2 -- that is what a D1 delegates to. - */ - -extern void *data_ov002_021081e4; /* Enemy vtable (wildcard reloc) */ -extern void *_ZN5ActorD2Ev(void *self); /* Actor::~Actor (already named) */ - -struct Enemy { - void *vtable; -}; - -void *_ZN5EnemyD1Ev(struct Enemy *self) -{ - self->vtable = &data_ov002_021081e4; - _ZN5ActorD2Ev(self); - return self; -} diff --git a/src/_ZN5EnemyD1Ev.cpp b/src/_ZN5EnemyD1Ev.cpp new file mode 100644 index 000000000..e8c818a46 --- /dev/null +++ b/src/_ZN5EnemyD1Ev.cpp @@ -0,0 +1,22 @@ +//cpp +// @symbol _ZN5EnemyD1Ev +/* recovered: real C++ destructor -- the compiler emits the whole body + * + * Store this class's vtable over the one Actor's constructor left, then run + * the Actor subobject destructor. Both follow from `struct Enemy : Actor` and + * `virtual ~Enemy()`; Enemy owns nothing with a destructor of its own. + * + * This needed the vtable to have a NAME. A real destructor stores _ZTV5Enemy, + * and the tree only knew 0x021081e4 as data_ov002_021081e4, so the link failed + * on an undefined symbol while the bytes matched perfectly. The alias is now in + * ov002's symbols.txt -- see the note there. + * + * The destructor stays OUT-OF-LINE, unlike Platform's: the 51 classes derived + * from Enemy call _ZN5EnemyD2Ev rather than inlining its vptr store, so a + * visible body would make each of them emit code the ROM does not have. + */ +#include "Enemy.h" + +Enemy::~Enemy() +{ +} diff --git a/src/_ZN5Stump13InitResourcesEv.cpp b/src/_ZN5Stump13InitResourcesEv.cpp index 6a7324d7d..541e0a5c7 100644 --- a/src/_ZN5Stump13InitResourcesEv.cpp +++ b/src/_ZN5Stump13InitResourcesEv.cpp @@ -22,26 +22,26 @@ extern char data_ov091_021356d0[]; int Stump::InitResources() { - mVariant = unk_008 & 0xff; - unk_0a0 = -0x1e000; + mVariant = (*(s32 *)¶m1) & 0xff; + mTerminalVelocity = -0x1e000; if (mVariant == 0xff) mVariant = 0; if (mVariant == 1) { _ZN18MovingCylinderClsn4InitEP5Actor5Fix12IiES3_jj(((char *)this) + 0x110, ((char *)this), 0x3c000, 0x14000, 0x200002, 0); func_ov091_02134044(((char *)this), data_ov091_021356c0); _ZN12WithMeshClsn4InitEP5Actor5Fix12IiES3_P10Vector3_16S5_(((char *)this) + 0x144, ((char *)this), 0x14000, 0, 0, 0); - unk_0b0 = 0; + (*(s32 *)&mFlags) = 0; return 1; } _ZN18MovingCylinderClsn4InitEP5Actor5Fix12IiES3_jj(((char *)this) + 0x110, ((char *)this), 0x64000, 0x64000, 0x200002, 0x4a010); - unk_0b0 = 0x10000000; + (*(s32 *)&mFlags) = 0x10000000; _ZN5Model8LoadFileER13SharedFilePtr(data_ov002_0210da40); _ZN5Model8LoadFileER13SharedFilePtr(data_ov002_0210d9a0); _ZN5Model8LoadFileER13SharedFilePtr(data_ov002_0210d9c0); _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0x300, _ZN5Model8LoadFileER13SharedFilePtr(data_ov091_02135674), 1, -1); _ZN9Animation8LoadFileER13SharedFilePtr(data_ov091_0213567c); _ZN9Animation8LoadFileER13SharedFilePtr(data_ov091_02135684); - unk_35c = 0x1000; + (*(s32 *)((char *)&mModelAnim + 0x5c)) = 0x1000; func_ov091_02134044(((char *)this), data_ov091_021356d0); return 1; } diff --git a/src/_ZN5Stump16CleanupResourcesEv.cpp b/src/_ZN5Stump16CleanupResourcesEv.cpp index c514cca85..f2d5c12c7 100644 --- a/src/_ZN5Stump16CleanupResourcesEv.cpp +++ b/src/_ZN5Stump16CleanupResourcesEv.cpp @@ -2,7 +2,6 @@ // @symbol _ZN5Stump16CleanupResourcesEv /* recovered: named members + shared header, real C++ method */ #include "Stump.h" -struct SharedFilePtr { unsigned int data[4]; }; extern "C" { extern void _ZN13SharedFilePtr7ReleaseEv(struct SharedFilePtr *self); } diff --git a/src/_ZN5Stump6RenderEv.cpp b/src/_ZN5Stump6RenderEv.cpp index c9b9fb724..03a761d0a 100644 --- a/src/_ZN5Stump6RenderEv.cpp +++ b/src/_ZN5Stump6RenderEv.cpp @@ -9,8 +9,8 @@ struct V { virtual void m0(); virtual void m1(); virtual void m2(); virtual void int Stump::Render() { if (mVariant == 1) return 1; - int b = (unk_0b0 & 0x40000) != 0; + int b = ((*(s32 *)&mFlags) & 0x40000) != 0; if (b) return 1; - ((V*)((char *)&mModelAnim))->m5(0); + ((V*)((char *)&(*(u8 *)&mModelAnim)))->m5(0); return 1; } diff --git a/src/_ZN5Stump8BehaviorEv.cpp b/src/_ZN5Stump8BehaviorEv.cpp index 58ee6f040..21b63d5d8 100644 --- a/src/_ZN5Stump8BehaviorEv.cpp +++ b/src/_ZN5Stump8BehaviorEv.cpp @@ -20,7 +20,6 @@ extern void _ZN5Enemy12UpdateWMClsnER12WithMeshClsnj(Enemy *thiz, WithMeshClsn * extern void _ZN9Animation7AdvanceEv(void *thiz); } -struct Enemy { char pad[0x800]; }; int Stump::Behavior() { diff --git a/src/_ZN8IceBlock13InitResourcesEv.cpp b/src/_ZN8IceBlock13InitResourcesEv.cpp index b0a8f794d..3f1ad9d89 100644 --- a/src/_ZN8IceBlock13InitResourcesEv.cpp +++ b/src/_ZN8IceBlock13InitResourcesEv.cpp @@ -16,12 +16,12 @@ extern "C" void _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEs int IceBlock::InitResources() { void* m = _ZN5Model8LoadFileER13SharedFilePtr(data_ov081_02128fd8); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, m, 1, 0x17); + _ZN9ModelBase7SetFileEP8BMD_Fileii((char *)&mModel, m, 1, 0x17); _ZN18MovingCylinderClsn4InitEP5Actor5Fix12IiES3_jj(((char*)this)+0x320, ((char*)this), 0xc8000, 0x12c000, 0x800002, 0x44000); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); void* k = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov081_02128fd0); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, k, ((char*)this)+0x2ec, 0x1000, mAngleY, data_ov002_0210d8d4); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block((char *)&mMeshCollider, k, (char *)&mClsnMat, 0x1000, mAngleY, data_ov002_0210d8d4); mScale = 0x1000; return 1; } diff --git a/src/_ZN8IceBlock16CleanupResourcesEv.cpp b/src/_ZN8IceBlock16CleanupResourcesEv.cpp index 4af06f0c9..efd2e5063 100644 --- a/src/_ZN8IceBlock16CleanupResourcesEv.cpp +++ b/src/_ZN8IceBlock16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern int data_ov081_02128fd8[]; int IceBlock::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov081_02128fd8))->Release(); ((SharedFilePtr *)(data_ov081_02128fd0))->Release(); diff --git a/src/_ZN8IceBlock8BehaviorEv.cpp b/src/_ZN8IceBlock8BehaviorEv.cpp index fa3220786..f49c26463 100644 --- a/src/_ZN8IceBlock8BehaviorEv.cpp +++ b/src/_ZN8IceBlock8BehaviorEv.cpp @@ -78,18 +78,18 @@ int IceBlock::Behavior() return 1; } - if (unk_344 != 0) { - if ((unk_340 & 0x40000) != 0) { + if ((*(s32 *)((char *)&mMovingCylinderClsn + 0x24)) != 0) { + if (((*(s32 *)((char *)&mMovingCylinderClsn + 0x20)) & 0x40000) != 0) { unk_354 = 0x1e; func_02012694(0x7a, ((char*)this) + 0x74); func_ov081_02127be0(((char*)this)); } - if ((unk_340 & 0x4000) != 0) { + if (((*(s32 *)((char *)&mMovingCylinderClsn + 0x20)) & 0x4000) != 0) { ((VObj*)((char*)this))->OnHit(); } } - _ZN12CylinderClsn5ClearEv((char*)&mMovingCylinderClsn); - _ZN12CylinderClsn6UpdateEv((char*)&mMovingCylinderClsn); + _ZN12CylinderClsn5ClearEv((char*)&(*(u8 *)&mMovingCylinderClsn)); + _ZN12CylinderClsn6UpdateEv((char*)&(*(u8 *)&mMovingCylinderClsn)); return 1; } diff --git a/src/_ZN8IceSheet13InitResourcesEv.cpp b/src/_ZN8IceSheet13InitResourcesEv.cpp index 69c78f572..dd3e93e43 100644 --- a/src/_ZN8IceSheet13InitResourcesEv.cpp +++ b/src/_ZN8IceSheet13InitResourcesEv.cpp @@ -4,23 +4,22 @@ #include "decl_common.h" /* recovered: named members + shared header, real C++ method */ #include "IceSheet.h" -typedef int Fix12; extern "C" { extern void* _ZN5Model8LoadFileER13SharedFilePtr(void*); extern int _ZN9ModelBase7SetFileEP8BMD_Fileii(void*, void*, int, int); extern int _ZN8Platform21UpdateModelPosAndRotYEv(void*); extern int _ZN8Platform19UpdateClsnPosAndRotEv(void*); extern void* _ZN12MeshCollider8LoadFileER13SharedFilePtr(void*); -extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(void*, void*, void*, Fix12, short, void*); +extern int _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(void*, void*, void*, int, short, void*); } int IceSheet::InitResources() { void *mdl = _ZN5Model8LoadFileER13SharedFilePtr(&data_ov018_02113c84); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this) + 0xd4, mdl, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, mdl, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char *)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char *)this)); void *kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(&data_ov018_02113c7c); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char *)this) + 0x124, kcl, ((char *)this) + 0x2ec, 0x199, unk_08e, (void *)&data_ov002_0210d754); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, kcl, &mClsnMat, 0x199, mAngleY, (void *)&data_ov002_0210d754); return 1; } diff --git a/src/_ZN8IceSheet16CleanupResourcesEv.cpp b/src/_ZN8IceSheet16CleanupResourcesEv.cpp index 3f72adc47..bee43a19a 100644 --- a/src/_ZN8IceSheet16CleanupResourcesEv.cpp +++ b/src/_ZN8IceSheet16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int IceSheet_ModelFile[]; int IceSheet::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(IceSheet_ModelFile))->Release(); ((SharedFilePtr *)(IceSheet_ClsnFile))->Release(); diff --git a/src/_ZN8IceSheet8BehaviorEv.cpp b/src/_ZN8IceSheet8BehaviorEv.cpp index 2a2baf372..244be3693 100644 --- a/src/_ZN8IceSheet8BehaviorEv.cpp +++ b/src/_ZN8IceSheet8BehaviorEv.cpp @@ -8,7 +8,7 @@ extern "C" { int IceSheet::Behavior() { - if (!((MeshColliderBase *)((char*)&mMovingMeshCollider))->IsEnabled()) - ((MeshColliderBase *)(((char*)this)+0x124))->Enable((Actor *)(((char*)this))); + if (!((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)(&mMeshCollider))->Enable((Actor *)(((char*)this))); return 1; } diff --git a/src/_ZN8MetalNet13InitResourcesEv.cpp b/src/_ZN8MetalNet13InitResourcesEv.cpp index 5e0737ca3..295af9189 100644 --- a/src/_ZN8MetalNet13InitResourcesEv.cpp +++ b/src/_ZN8MetalNet13InitResourcesEv.cpp @@ -29,10 +29,10 @@ int MetalNet::InitResources() { struct KCL_File *kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov009_02113e88); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((unsigned char *)this) + 0x124, kcl, *(struct Matrix4x3 *)((unsigned char *)&unk_2ec), 0x1000, - unk_08e, data_ov009_02112bf8); + ((unsigned char *)this) + 0x124, kcl, *(struct Matrix4x3 *)((unsigned char *)&(*(u8 *)&mClsnMat)), 0x1000, + mAngleY, data_ov009_02112bf8); } - if ((unk_008 & 0xff) == 0xff) { + if (((*(s32 *)¶m1) & 0xff) == 0xff) { int b = (int)(data_0209f2d8 == 1); if (b != 0) goto ret1; if ((*(int*)((char*)&data_0209caa0 + 8) & 0x80000) == 0) goto ret1; diff --git a/src/_ZN8MetalNet16CleanupResourcesEv.cpp b/src/_ZN8MetalNet16CleanupResourcesEv.cpp index 375e774a1..991bac7a1 100644 --- a/src/_ZN8MetalNet16CleanupResourcesEv.cpp +++ b/src/_ZN8MetalNet16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int data_ov009_02113e90[]; int MetalNet::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { + ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); } ((SharedFilePtr *)(data_ov009_02113e90))->Release(); ((SharedFilePtr *)(data_ov009_02113e88))->Release(); diff --git a/src/_ZN8MetalNet8BehaviorEv.cpp b/src/_ZN8MetalNet8BehaviorEv.cpp index 6201e624b..3a32aaf96 100644 --- a/src/_ZN8MetalNet8BehaviorEv.cpp +++ b/src/_ZN8MetalNet8BehaviorEv.cpp @@ -19,7 +19,7 @@ int MetalNet::Behavior() _ZN8Platform19UpdateClsnPosAndRotEv(((void*)this)); b = (int)(data_0209f2d8 == 1); if (b != 0) { - if (((MeshColliderBase *)((char*)&mMovingMeshCollider))->IsEnabled() == 0) + if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled() == 0) ((MeshColliderBase *)((char*)((void*)this)+0x124))->Enable((Actor *)(((void*)this))); } else { _ZN8Platform13IsClsnInRangeE5Fix12IiES1_(((void*)this), 0, 0); diff --git a/src/_ZN8PlatformD0Ev.c b/src/_ZN8PlatformD0Ev.c deleted file mode 100644 index b70d992a6..000000000 --- a/src/_ZN8PlatformD0Ev.c +++ /dev/null @@ -1,19 +0,0 @@ -// @symbol _ZN8PlatformD0Ev -/* recovered: named members + shared header, vtable identified, declarations from a shared header */ -#include "decl_Actor.h" -#include "decl_Model.h" -#include "decl_MovingMeshCollider.h" -#include "decl_common.h" -extern int _ZTV8Platform[]; -/* recovered: named members + shared header, vtable identified */ -/* vtable identified: VT0 = _ZTV8Platform */ -extern void *data_020a0eac; -int *_ZN8PlatformD0Ev(int *t) -{ - t[0] = (int)_ZTV8Platform; - _ZN18MovingMeshColliderD1Ev((char *)t + 0x124); - _ZN5ModelD1Ev((char *)t + 0xd4); - _ZN5ActorD2Ev(t); - _ZN6Memory10DeallocateEPvP4Heap(t, data_020a0eac); - return t; -} diff --git a/src/_ZN8PlatformD0Ev.cpp b/src/_ZN8PlatformD0Ev.cpp new file mode 100644 index 000000000..2d705aaae --- /dev/null +++ b/src/_ZN8PlatformD0Ev.cpp @@ -0,0 +1,22 @@ +//cpp +// @symbol _ZN8PlatformD0Ev +/* recovered: real C++ deleting destructor, defined inline in the header + * + * ~Platform is defined in the class body -- the seventy-odd classes derived + * from it inline its vptr store rather than calling it, which the compiler can + * only do from a visible body. So this file cannot define it, and a TU that + * merely includes the header emits nothing. The explicit destructor call below + * forces the whole group into existence; objisolate keeps the one this file is + * bound to and drops the rest. + * + * D0 is the deleting half: destroy through Platform and Actor, then hand the + * object back through Actor's inline operator delete, which is why nothing + * here mentions a heap. + */ +#include "Platform.h" + +/* Not called. Forces the out-of-line copy of the inline destructor group. */ +void Platform_EmitDeletingDestructor(Platform *p) +{ + p->~Platform(); +} diff --git a/src/_ZN8PlatformD1Ev.cpp b/src/_ZN8PlatformD1Ev.cpp index 8527271ec..71f530c9f 100644 --- a/src/_ZN8PlatformD1Ev.cpp +++ b/src/_ZN8PlatformD1Ev.cpp @@ -3,18 +3,19 @@ /* recovered: real C++ destructor, defined inline in the header * * ~Platform is defined in the class body, not here, and that is load-bearing: - * the 72 classes derived from Platform inline this destructor's vptr store - * rather than calling it, which the compiler can only do from a visible body. - * include/ActorDerived.h records the measurement behind that. + * the seventy-odd classes derived from Platform inline this destructor's vptr + * store rather than calling it, which the compiler can only do from a visible + * body. include/Platform.h records the measurement. * * So this file cannot define it -- that would be a redefinition -- and a TU - * that merely includes the header emits nothing. The explicit destructor call - * below forces the out-of-line copy the vtable points at into existence. It is - * never called, and objisolate drops it. + * that merely includes the header emits nothing at all. The explicit + * destructor call below is what forces the out-of-line copy the vtable points + * at into existence. It is never called; objisolate keeps the function this + * file declares and drops the rest. * - * The body it forces is the layout evidence for the whole class: the ROM - * destroys a MovingMeshCollider at 0x124 and a Model at 0xd4, and both of - * those offsets are where those classes' own asserted sizes put them. + * The body it forces is the class's own layout evidence: the ROM destroys a + * MovingMeshCollider at 0x124 and a Model at 0xd4, and both offsets are where + * those classes' asserted sizes put them. */ #include "Platform.h" diff --git a/src/_ZN8ShipWing13InitResourcesEv.cpp b/src/_ZN8ShipWing13InitResourcesEv.cpp index 25c74f2da..4e703e10e 100644 --- a/src/_ZN8ShipWing13InitResourcesEv.cpp +++ b/src/_ZN8ShipWing13InitResourcesEv.cpp @@ -20,16 +20,16 @@ extern void _ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResult int ShipWing::InitResources() { int m = _ZN5Model8LoadFileER13SharedFilePtr(data_ov036_0211408c); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, m, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, m, 1, -1); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); int k = _ZN12MeshCollider8LoadFileER13SharedFilePtr(data_ov036_02114084); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, k, ((char*)this)+0x2ec, 0x1000, mAngleY, data_ov036_02112b48); - func_020393d4(((char*)this)+0x124, (void*)_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - func_020393c4(((char*)this)+0x124, (void*)func_ov036_02111cc4); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, k, &mClsnMat, 0x1000, mAngleY, data_ov036_02112b48); + func_020393d4(&mMeshCollider, (void*)_ZN16MeshColliderBase21UpdatePosWithVelocityERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + func_020393c4(&mMeshCollider, (void*)func_ov036_02111cc4); _ZN12WithMeshClsn4InitEP5Actor5Fix12IiES3_P10Vector3_16S5_(((char*)this)+0x320, ((char*)this), 0x32000, 0x64000, 0, 0); - unk_0a0 = -0x1e000; - unk_09c = ~0x198; + mTerminalVelocity = -0x1e000; + mVertAccel = ~0x198; unk_4dc = mPosX; unk_4e0 = mPosY; unk_4e4 = mPosZ; diff --git a/src/_ZN8ShipWing16CleanupResourcesEv.cpp b/src/_ZN8ShipWing16CleanupResourcesEv.cpp index 7074c1c9a..4301fbd57 100644 --- a/src/_ZN8ShipWing16CleanupResourcesEv.cpp +++ b/src/_ZN8ShipWing16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern int data_ov036_0211408c[]; int ShipWing::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov036_0211408c))->Release(); ((SharedFilePtr *)(data_ov036_02114084))->Release(); diff --git a/src/_ZN8ShipWing8BehaviorEv.cpp b/src/_ZN8ShipWing8BehaviorEv.cpp index 1b43c82fb..369ffb1eb 100644 --- a/src/_ZN8ShipWing8BehaviorEv.cpp +++ b/src/_ZN8ShipWing8BehaviorEv.cpp @@ -34,7 +34,7 @@ int ShipWing::Behavior() if (_ZN5Actor13DistToCPlayerEv(((char*)this)) <= 0x9c4000) break; } _ZN5Actor14TriplePoofDustEv(((char*)this)); - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled() != 0) ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled() != 0) ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); mPosX = unk_4dc; mPosY = unk_4e0; mPosZ = unk_4e4; @@ -44,7 +44,7 @@ int ShipWing::Behavior() int d = _ZN5Actor13DistToCPlayerEv(((char*)this)); if (d <= 0x3e8000) break; if (d < 0x7d0000) { - unk_0a8 = 0; + mVertSpeed = 0; unk_4e9 = 0; unk_4e8 = 0; mState = 0; diff --git a/src/_ZN8Squasher13InitResourcesEv.cpp b/src/_ZN8Squasher13InitResourcesEv.cpp index 3a24b7429..0532c6eda 100644 --- a/src/_ZN8Squasher13InitResourcesEv.cpp +++ b/src/_ZN8Squasher13InitResourcesEv.cpp @@ -20,14 +20,14 @@ extern void _ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResul int Squasher::InitResources() { int bmd = _ZN5Model8LoadFileER13SharedFilePtr(&data_ov023_02112088); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char*)this)+0xd4, bmd, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, bmd, 1, -1); _ZN11ShadowModel10InitCuboidEv((char*)&mShadowModel); func_ov023_02111308(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); int kcl = _ZN12MeshCollider8LoadFileER13SharedFilePtr(&_ZN32FloatOnWaterPlatformWdwRectangleD1Ev); - _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(((char*)this)+0x124, kcl, (struct Matrix4x3*)((char*)&unk_2ec), 0x1000, mAngleY, &data_ov064_0211ba4c); + _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block(&mMeshCollider, kcl, (struct Matrix4x3*)((char*)&(*(u8 *)&mClsnMat)), 0x1000, (*(u16 *)&mAngleY), &data_ov064_0211ba4c); func_020393d4((int*)((char*)&mMeshCollider), (int)&_ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - ((MeshColliderBase *)(((char*)this)+0x124))->Enable((Actor *)(((char*)this))); + ((MeshColliderBase *)(&mMeshCollider))->Enable((Actor *)(((char*)this))); unk_31e = 0; unk_320 = 0; unk_322 = 0; diff --git a/src/_ZN9HugeCover13InitResourcesEv.cpp b/src/_ZN9HugeCover13InitResourcesEv.cpp index 0b15190be..0ce22ab68 100644 --- a/src/_ZN9HugeCover13InitResourcesEv.cpp +++ b/src/_ZN9HugeCover13InitResourcesEv.cpp @@ -6,9 +6,6 @@ typedef int Fix12i; struct SharedFilePtr; struct BMD_File; struct BTA_File; struct KCL_File; struct Matrix4x3; struct CLPS_Block; struct Actor; /* Model and ModelBase are the real classes now, through HugeCover.h. */ -struct TextureTransformer { int d; }; -struct MeshCollider { int d; }; -struct MovingMeshCollider { int d; }; extern "C" BMD_File* _ZN5Model8LoadFileER13SharedFilePtr(SharedFilePtr&); extern "C" void _ZN9ModelBase7SetFileEP8BMD_Fileii(ModelBase*, BMD_File*, int, int); diff --git a/src/_ZN9HugeCover16CleanupResourcesEv.cpp b/src/_ZN9HugeCover16CleanupResourcesEv.cpp index 948c26546..268a0bf4c 100644 --- a/src/_ZN9HugeCover16CleanupResourcesEv.cpp +++ b/src/_ZN9HugeCover16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int data_ov032_02113afc[]; int HugeCover::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMovingMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMovingMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov032_02113afc))->Release(); ((SharedFilePtr *)(data_ov032_02113af4))->Release(); diff --git a/src/_ZN9HugeCover8BehaviorEv.cpp b/src/_ZN9HugeCover8BehaviorEv.cpp index 3126b9b27..47eb4f744 100644 --- a/src/_ZN9HugeCover8BehaviorEv.cpp +++ b/src/_ZN9HugeCover8BehaviorEv.cpp @@ -10,8 +10,8 @@ extern void _ZN8Platform19UpdateClsnPosAndRotEv(void *); int HugeCover::Behavior() { - unk_32c = 4096; - _ZN9Animation7AdvanceEv((char *)&mTextureTransformer); + (*(s32 *)((char *)&mTextureTransformer + 0xc)) = 4096; + _ZN9Animation7AdvanceEv((char *)&(*(u8 *)&mTextureTransformer)); _ZN8Platform21UpdateModelPosAndRotYEv(((char *)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char *)this)); return 1; diff --git a/src/_ZN9SeesawBob13InitResourcesEv.cpp b/src/_ZN9SeesawBob13InitResourcesEv.cpp index 681d2b702..e993ecf40 100644 --- a/src/_ZN9SeesawBob13InitResourcesEv.cpp +++ b/src/_ZN9SeesawBob13InitResourcesEv.cpp @@ -20,7 +20,7 @@ int SeesawBob::InitResources() { unsigned char idx; int f; - switch (unk_00c) { + switch (actorID) { case 0x1c: ((char *)this)[0x31e] = 0; break; case 0x27: ((char *)this)[0x31e] = 1; break; case 0x85: ((char *)this)[0x31e] = 2; break; @@ -31,16 +31,16 @@ int SeesawBob::InitResources() } idx = (unsigned char)((char *)this)[0x31e]; f = _ZN5Model8LoadFileER13SharedFilePtr(*(int*)(data_ov095_021374a0 + idx*0xc)); - _ZN9ModelBase7SetFileEP8BMD_Fileii(((char *)this)+0xd4, f, 1, -1); + _ZN9ModelBase7SetFileEP8BMD_Fileii(&mModel, f, 1, -1); func_ov095_0213597c(((char *)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char *)this)); { unsigned char i = (unsigned char)((char *)this)[0x31e]; f = _ZN12MeshCollider8LoadFileER13SharedFilePtr(*(int*)(data_ov095_021374a4 + i*0xc)); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char *)this)+0x124, f, ((char *)this)+0x2ec, 0x1000, unk_08e, *(int*)(data_ov095_021374a8 + i*0xc)); + &mMeshCollider, f, &mClsnMat, 0x1000, mAngleY, *(int*)(data_ov095_021374a8 + i*0xc)); } - func_020393d4(((char *)this)+0x124, _ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); - func_020393c4(((char *)this)+0x124, func_ov095_02135e90); + func_020393d4(&mMeshCollider, _ZN16MeshColliderBase22UpdatePosWithTransformERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + func_020393c4(&mMeshCollider, func_ov095_02135e90); return 1; } diff --git a/src/_ZN9SeesawBob16CleanupResourcesEv.cpp b/src/_ZN9SeesawBob16CleanupResourcesEv.cpp index 7e137377d..fca4fea8e 100644 --- a/src/_ZN9SeesawBob16CleanupResourcesEv.cpp +++ b/src/_ZN9SeesawBob16CleanupResourcesEv.cpp @@ -9,8 +9,8 @@ int SeesawBob::CleanupResources() { - if(((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if(((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); ((SharedFilePtr *)(*(void**)(data_ov095_021374a0 + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); ((SharedFilePtr *)(*(void**)(data_ov095_021374a4 + (unsigned char)((char *)this)[0x31e]*0xc)))->Release(); return 1; diff --git a/src/_ZN9SeesawBob8BehaviorEv.cpp b/src/_ZN9SeesawBob8BehaviorEv.cpp index 2402e86b2..a7f213d3a 100644 --- a/src/_ZN9SeesawBob8BehaviorEv.cpp +++ b/src/_ZN9SeesawBob8BehaviorEv.cpp @@ -15,10 +15,10 @@ void _ZN8Platform19UpdateClsnPosAndRotEv(void* self); int SeesawBob::Behavior() { - int b = (int)((unk_0b0 & 8) != 0); + int b = (int)(((*(s32 *)&mFlags) & 8) != 0); if (b != 0) { - if (((MeshColliderBase *)((char*)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char*)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char*)&(*(u8 *)&mMeshCollider)))->Disable(); } return 1; } @@ -33,8 +33,8 @@ int SeesawBob::Behavior() unk_320, 3, 0x8b, ((char*)this) + 0x74, 0); } } - if (unk_08c > 0x2000) unk_08c = 0x2000; - if (unk_08c < -0x2000) unk_08c = -0x2000; + if (mAngleX > 0x2000) mAngleX = 0x2000; + if (mAngleX < -0x2000) mAngleX = -0x2000; func_ov095_0213597c(((char*)this)); if (_ZN8Platform13IsClsnInRangeE5Fix12IiES1_(((char*)this), 0, 0)) { _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); diff --git a/src/_ZN9ShipWater16CleanupResourcesEv.cpp b/src/_ZN9ShipWater16CleanupResourcesEv.cpp index d22861b57..fd9284c99 100644 --- a/src/_ZN9ShipWater16CleanupResourcesEv.cpp +++ b/src/_ZN9ShipWater16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int data_ov017_02111c88[]; int ShipWater::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov017_02111c88))->Release(); ((SharedFilePtr *)(data_ov017_02111c80))->Release(); diff --git a/src/_ZN9ShipWater8BehaviorEv.cpp b/src/_ZN9ShipWater8BehaviorEv.cpp index ca81473af..056b7732f 100644 --- a/src/_ZN9ShipWater8BehaviorEv.cpp +++ b/src/_ZN9ShipWater8BehaviorEv.cpp @@ -35,8 +35,8 @@ int ShipWater::Behavior() *q -= 0x5000; } } - unk_32c = 0x1000; - _ZN9Animation7AdvanceEv((char*)&mTextureTransformer); + (*(s32 *)((char *)&mTextureTransformer + 0xc)) = 0x1000; + _ZN9Animation7AdvanceEv((char*)&(*(u8 *)&mTextureTransformer)); _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); return 1; diff --git a/src/_ZN9TinyCover16CleanupResourcesEv.cpp b/src/_ZN9TinyCover16CleanupResourcesEv.cpp index 85c9ab3b4..77ac34ec1 100644 --- a/src/_ZN9TinyCover16CleanupResourcesEv.cpp +++ b/src/_ZN9TinyCover16CleanupResourcesEv.cpp @@ -10,8 +10,8 @@ extern int data_ov033_021124f0[]; int TinyCover::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(data_ov033_021124f0))->Release(); ((SharedFilePtr *)(data_ov033_021124e8))->Release(); diff --git a/src/_ZN9TowerStep13InitResourcesEv.cpp b/src/_ZN9TowerStep13InitResourcesEv.cpp index a5ef121d0..0718aa4ea 100644 --- a/src/_ZN9TowerStep13InitResourcesEv.cpp +++ b/src/_ZN9TowerStep13InitResourcesEv.cpp @@ -24,8 +24,8 @@ int TowerStep::InitResources() _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); f = _ZN12MeshCollider8LoadFileER13SharedFilePtr(&data_ov015_02114a84); _ZN18MovingMeshCollider7SetFileEP8KCL_FileRK9Matrix4x35Fix12IiEsR10CLPS_Block( - ((char*)this) + 0x124, f, ((char*)this) + 0x2ec, 0x199, unk_08e, &data_ov015_02113654); - func_020393d4((int*)((char*)&mMeshCollider), (void*)&_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); + ((char*)this) + 0x124, f, ((char*)this) + 0x2ec, 0x199, mAngleY, &data_ov015_02113654); + func_020393d4((int*)((char*)&(*(u8 *)&mMeshCollider)), (void*)&_ZN16MeshColliderBase16UpdatePosAndAngsERS_P5ActorR10ClsnResultR7Vector3P10Vector3_16S8_); unk_31e = 0x3c; return 1; } diff --git a/src/_ZN9TowerStep16CleanupResourcesEv.cpp b/src/_ZN9TowerStep16CleanupResourcesEv.cpp index 5b9950693..854da9fd1 100644 --- a/src/_ZN9TowerStep16CleanupResourcesEv.cpp +++ b/src/_ZN9TowerStep16CleanupResourcesEv.cpp @@ -11,8 +11,8 @@ extern int TowerStep_ModelFile[]; int TowerStep::CleanupResources() { - if (((MeshColliderBase *)((char *)&mMeshCollider))->IsEnabled()) { - ((MeshColliderBase *)((char *)&mMeshCollider))->Disable(); + if (((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->IsEnabled()) { + ((MeshColliderBase *)((char *)&(*(u8 *)&mMeshCollider)))->Disable(); } ((SharedFilePtr *)(TowerStep_ModelFile))->Release(); ((SharedFilePtr *)(TowerStep_ClsnFile))->Release(); diff --git a/src/_ZN9TowerStep8BehaviorEv.cpp b/src/_ZN9TowerStep8BehaviorEv.cpp index 14e6aef52..9c46fd986 100644 --- a/src/_ZN9TowerStep8BehaviorEv.cpp +++ b/src/_ZN9TowerStep8BehaviorEv.cpp @@ -16,12 +16,12 @@ int TowerStep::Behavior() if (DecIfAbove0_Byte((char*)&unk_31e) == 0) { short* p = (short*)(((int)((char*)this) + 0x94)); *p = *p + 0x100; - unk_08e = unk_094; - unk_320 = _ZN5Sound8PlayLongEjjjRK7Vector3s(unk_320, 3, 0x88, (void*)((char*)&unk_074), 0); - if ((unk_094 & 0x7fff) == 0) unk_31e = 0x3c; + mAngleY = mPrevAngleY; + unk_320 = _ZN5Sound8PlayLongEjjjRK7Vector3s(unk_320, 3, 0x88, (void*)((char*)&mCamSpacePosX), 0); + if ((mPrevAngleY & 0x7fff) == 0) unk_31e = 0x3c; } _ZN8Platform21UpdateModelPosAndRotYEv(((char*)this)); - func_020393a4((int*)((char*)&mMeshCollider), 0x320000); + func_020393a4((int*)((char*)&(*(u8 *)&mMeshCollider)), 0x320000); if (_ZN8Platform13IsClsnInRangeE5Fix12IiES1_(((char*)this), 0x320000, 0)) _ZN8Platform19UpdateClsnPosAndRotEv(((char*)this)); return 1; diff --git a/tools/d0_migrate.py b/tools/d0_migrate.py new file mode 100644 index 000000000..9f53c7107 --- /dev/null +++ b/tools/d0_migrate.py @@ -0,0 +1,133 @@ +"""Turn a hand-spelt D0 destructor file into a real C++ one, or leave it alone. + +D0 is the DELETING destructor -- vtable slot 17 for an actor: destroy through +the class and its bases, then return the object to its heap. Nobody writes that +body; the compiler generates it. That is why `src/_ZN5EnemyD0Ev.c` argues +against renaming these files, and why they were counted out of the backlog. + +Counting them out was wrong. You do not write D0 -- you write `X::~X()`, and +mwcc emits D2, D0 and D1 together, and objisolate keeps whichever one the file +is bound to. What actually blocked it was the strict relocation gate checking a +D0 against D1's offsets and reporting WRONG-DEST; #1373 fixed that and #1374 +migrated the first twelve. + +So a D0 needs exactly what a D1 needs: a header where the class is real. This +walks every D0 still spelt by hand, tries it against its own header, verifies, +and restores the original if the bytes differ. +""" +import argparse +import pathlib +import re +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) +import build_pin as BP # noqa: E402 + +REPO = pathlib.Path(__file__).resolve().parents[1] + +BODY = """//cpp +// @symbol _ZN{n}{cls}D0Ev +/* recovered: real C++ deleting destructor -- the compiler emits the whole body + * + * D0 is the DELETING destructor: destroy through this class and its bases -- + * which is why more than one vptr store appears -- then return the object to + * its heap. Nobody writes that; declaring `~{cls}()` is enough, because mwcc + * emits D2, D0 and D1 together and objisolate keeps the one this file is bound + * to. + * + * The deallocation is an inline operator delete, which is why nothing below + * mentions a heap. + */ +#include "{cls}.h" + +{cls}::~{cls}() +{{ +}} +""" + + +def symbol_index(): + idx = {} + for p in REPO.glob("config/**/symbols.txt"): + lab = p.parent.name + for line in p.read_text(errors="replace").splitlines(): + m = re.match(r"\s*(\S+)\s+kind:function\([^)]*size=(0x[0-9a-f]+)\)\s+addr:(0x[0-9a-f]+)", line) + if m: + idx[m.group(1)] = (int(m.group(3), 16), int(m.group(2), 16), lab) + return idx + + +def candidates(): + """Hand-spelt D0 files whose class has a real C++ header with a real base.""" + out = [] + for f in sorted((REPO / "src").glob("*D0Ev.c")): + m = re.match(r"_ZN(\d+)(\w+?)D0Ev$", f.stem) + if not m: + continue + n = int(m.group(1)) + cls = m.group(2)[:n] + if len(cls) != n: + continue + h = REPO / "include" / f"{cls}.h" + if not h.exists(): + continue + ht = h.read_text(errors="replace") + if not re.search(r"^\s*struct\s+" + re.escape(cls) + r"\s*:\s*\w+\s*\{", ht, re.M): + continue # needs a real base + if not re.search(r"virtual\s+~" + re.escape(cls), ht): + continue # needs a declared virtual destructor + out.append((f, cls)) + return out + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--list", action="store_true", help="show candidates, change nothing") + ap.add_argument("--only", help="comma-separated class names") + ap.add_argument("--limit", type=int, default=0) + args = ap.parse_args() + + idx = symbol_index() + cands = candidates() + if args.only: + want = set(args.only.split(",")) + cands = [c for c in cands if c[1] in want] + if args.limit: + cands = cands[:args.limit] + + if args.list: + for _, cls in cands: + print(cls) + print(f"\n{len(cands)} candidates") + return + + kept, failed = [], [] + for f, cls in cands: + sym = f.stem + if sym not in idx: + continue + addr, size, lab = idx[sym] + original = f.read_text(errors="replace") + new = f.with_suffix(".cpp") + new.write_text(BODY.format(n=len(cls), cls=cls)) + f.unlink() + try: + ok, why = BP.verify(str(new.relative_to(REPO)).replace("\\", "/"), sym, addr, size, lab) + except Exception as e: # noqa: BLE001 + ok, why = False, f"{type(e).__name__}: {e}"[:90] + if ok: + kept.append(cls) + print(f"OK {cls:30s} {lab}") + else: + new.unlink() + f.write_text(original) + failed.append((cls, why)) + print(f"-- {cls:30s} {why[:70]}") + + print(f"\nkept {len(kept)} / tried {len(kept) + len(failed)}") + if kept: + print("kept: " + " ".join(kept)) + + +if __name__ == "__main__": + main() diff --git a/tools/objisolate.py b/tools/objisolate.py index 841255123..99d8bcfb3 100644 --- a/tools/objisolate.py +++ b/tools/objisolate.py @@ -189,10 +189,24 @@ def plan(raw, keep_symbol): return {"error": f"{sym.name}: RTTI reloc is REL, not RELA"} if sym.name in ext: - # Being externalised: only the surveyed vtable shape is correctable. - want = (R_ARM_ABS32, VTABLE_PREAMBLE) if sym.name.startswith("_ZTV") \ - else (R_ARM_ABS32, 0) - if (r["r_info_type"], addend) != want: + # MULTIPLE INHERITANCE puts a SECOND vptr store in the object, + # pointing past the primary slots into the secondary sub-table -- + # addend 44 for ModelAnim, where the primary's is 8. The + # correction is the same subtraction either way, because mwcc's + # _ZTV addresses the vtable object's start while the ROM's IS the + # slot array. The ROM names the destination independently and the + # arithmetic lands on it exactly: + # + # _ZTV9ModelAnim 0x0208e980 + # VTable_Animation_ModelAnimThunk 0x0208e9a4 = +0x24 + # 44 - VTABLE_PREAMBLE = 0x24 + # + # Two symbols this tree recorded separately agreeing with the + # subtraction is the enrolled instance the refusal wanted. + ok_type = r["r_info_type"] == R_ARM_ABS32 + ok_addend = (addend >= VTABLE_PREAMBLE if sym.name.startswith("_ZTV") + else addend == 0) + if not (ok_type and ok_addend): return {"error": f"{sym.name}: unexpected reloc " f"type={r['r_info_type']} addend={addend}"} elif shndx == "SHN_UNDEF" or shndx == SHN_UNDEF: @@ -320,7 +334,9 @@ def ext_or_visible(sym): # Drop the preamble skip from every vtable reference, now that the symbol it # binds to already points at the slot array. Elf32_Rela is 12 bytes: # r_offset(4) r_info(4) r_addend(4). `plan` has already refused anything whose - # type/addend is not the surveyed shape, so this only ever rewrites 8 -> 0. + # type/addend is not the surveyed shape. Usually 8 -> 0; a multiple- + # inheritance secondary vptr store subtracts the same 8 from a larger + # addend and lands on the sub-table (44 -> 36 for ModelAnim). # # Two kinds reach here and both need the same correction. A vtable this object # DEFINED and is now externalising, and one it never defined at all -- the @@ -338,7 +354,7 @@ def ext_or_visible(sym): if not sym.name.startswith("_ZTV"): continue undef = sym["st_shndx"] in ("SHN_UNDEF", SHN_UNDEF) - if (sym.name in ext or undef) and r["r_addend"] == VTABLE_PREAMBLE: + if (sym.name in ext or undef) and r["r_addend"] >= VTABLE_PREAMBLE: struct.pack_into(endian + "i", raw, roff + i * 12 + 8, r["r_addend"] - VTABLE_PREAMBLE) diff --git a/tools/platform_subclass.py b/tools/platform_subclass.py new file mode 100644 index 000000000..25817b2bd --- /dev/null +++ b/tools/platform_subclass.py @@ -0,0 +1,351 @@ +"""Rewrite a Platform subclass as real C++, or leave it exactly as it was. + +The generated headers restate all of Actor and Platform. This turns one into +`struct X : Platform` keeping only its own fields, makes its destructor a real +method, and repoints its sources at the inherited names -- then verifies every +source the header reaches and REVERTS THE WHOLE CLASS if any one of them fails. +A class is migrated completely or not at all; nothing half-done is left behind. + +The reverts are the point. Of the first nine tried by hand, seven came back out +for four different reasons, and each reason is a fact about the ROM worth +having. See notes/dtor-migration.md. +""" +import argparse +import pathlib +import re +import subprocess +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) +import build_pin as BP # noqa: E402 + +REPO = pathlib.Path(__file__).resolve().parents[1] +W = {"u8": 1, "s8": 1, "char": 1, "bool": 1, "u16": 2, "s16": 2, "short": 2, + "u32": 4, "s32": 4, "int": 4, "Fix12i": 4, "PathPtr": 8} +FIELD = re.compile(r"^\s*([A-Za-z_][\w:<>]*)\s+(\**)(\w+)(\[[^\]]*\])?\s*;\s*/\*\s*(0x[0-9a-fA-F]+)", re.M) + +# Platform's DATA size: its last field (unk_31d) ends here, and sizeof rounds to +# 0x320. So a subclass field can sit at 0x31e/0x31f in the base's tail padding, +# which the Itanium ABI allows for a non-POD base. include/Platform.h records +# the four classes that rule out reading the class as 0x324. +PLATFORM_DSIZE = 0x31e + +# build_header fills this: marker name -> (member, byte offset into it, type). +SWALLOWED = {} + +# Set by main() for the second attempt: emit `(char *)&mModel` rather than +# `&mModel`, for sources whose externs were declared against the raw offset. +CAST_MEMBERS = [False] + + +def inherited_names(): + """offset -> (name, type) Actor.h / Platform.h gives that offset.""" + out, ty_out = {}, {} + for h, lo, hi in (("include/Actor.h", 0, 0xd0), ("include/Platform.h", 0xd0, 0x31e)): + for ty, star, name, arr, off in FIELD.findall((REPO / h).read_text(errors="replace")): + o = int(off, 16) + if lo <= o < hi and not name.startswith("pad_"): + if o not in out: + out[o] = name + ty_out[name] = ty + ("*" if star else "") + return out, ty_out + + +def symbol_index(): + idx = {} + for p in REPO.glob("config/**/symbols.txt"): + lab = p.parent.name + for line in p.read_text(errors="replace").splitlines(): + m = re.match(r"\s*(\S+)\s+kind:function\([^)]*size=(0x[0-9a-f]+)\)\s+addr:(0x[0-9a-f]+)", line) + if m: + idx[m.group(1)] = (int(m.group(3), 16), int(m.group(2), 16), lab) + return idx + + +def class_sizes(): + """Class -> sizeof, from the tree's own compile-time assertions.""" + out = {} + for h in (REPO / "include").rglob("*.h"): + for m in re.finditer(r"(\w+)_size_must_be_(0x[0-9a-fA-F]+)", h.read_text(errors="replace")): + out[m.group(1)] = int(m.group(2), 16) + return out + + +def members_from_destructor(cls, sizes): + """offset -> (type, sizeof) for the members the ROM's own D1 destroys. + + THE DESTRUCTOR NAMES ITS VICTIMS AND THEIR TYPES. A generated header calls + the thing at 0x320 `u8 mModel2` and the compiler emits nothing for it, so an + empty destructor body comes out short. The ROM's destructor calls + `_ZN5ModelD1Ev(this + 0x320)`, which says the member is a Model; declaring + it as one is what makes the empty body reproduce. That type's own size + assertion then has to close on the next field, which is a second and + independent check on the offset. + + Platform's two (0xd4, 0x124) are skipped -- they belong to the base. + """ + out = {} + for suffix in (".c", ".cpp"): + p = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev{suffix}" + if not p.exists(): + continue + for mangled, off in re.findall( + r"_ZN(\d+\w+?)D[12]Ev\s*\(\s*\(?\s*char\s*\*\s*\)?\s*(?:t|self|thiz|this)\s*\+\s*(0x[0-9a-fA-F]+)", + p.read_text(errors="replace")): + m = re.match(r"(\d+)(\w+)$", mangled) + if not m: + continue + n, o = int(m.group(1)), int(off, 16) + name = m.group(2)[:n] + if len(name) != n or o in (0xd4, 0x124) or name not in sizes: + continue + out[o] = (name, sizes[name]) + return out + + +def build_header(cls, old, sizes=None): + """(text, size, own-field-count) for the rewritten header.""" + sizes = sizes or {} + dtor_members = members_from_destructor(cls, sizes) + own = sorted((int(o, 16), ty, star, nm) + for ty, star, nm, arr, o in FIELD.findall(old) + if int(o, 16) >= PLATFORM_DSIZE and not nm.startswith("pad_")) + covered = set() + for o, (ty, sz) in dtor_members.items(): + covered.update(range(o, o + sz)) + SWALLOWED.clear() + for o, ty, star, nm in own: + if o in covered: + base_off = max(b for b in dtor_members if b <= o) + SWALLOWED[nm] = (f"m{dtor_members[base_off][0]}", o - base_off, ty) + own = [f for f in own if f[0] not in covered] + seen = set() + for o, (ty, sz) in sorted(dtor_members.items()): + own.append((o, ty, "", f"m{ty}" if ty not in seen else f"m{ty}_{o:03x}")) + seen.add(ty) + own.sort() + lines, cur = [], PLATFORM_DSIZE + for o, ty, star, nm in own: + if o > cur: + lines.append(f" u8 pad_{cur:03x}[0x{o - cur:x}];") + lines.append(f" {ty} {star}{nm};".ljust(38) + f"/* 0x{o:03x} */") + cur = o + (4 if star else sizes.get(ty) or W.get(ty, 4)) + size = max(0x320, (cur + 3) & ~3) + meths = re.findall(r"^\s{4}([A-Za-z_][\w:<>]*\s+\**\w+\([^)]*\));", old, re.M) + guard = cls.upper() + "_H" + incs = "".join('#include "%s.h"\n' % ty + for ty in sorted({t2 for _, (t2, _) in dtor_members.items()}) + if (REPO / "include" / f"{ty}.h").exists()) + body = "\n".join(lines) if lines else " /* no fields of its own */" + tail = "".join(f"\n {m};" for m in meths) + + # The C side keeps the flat struct verbatim -- same arrangement as + # include/ShadowModel.h and include/Fader.h. A C translation unit gets no + # base sub-object and no implicit vptr, so it needs every offset spelled + # out, and the generated declaration this replaces already is exactly that. + # The D0 files are why it has to stay: they are C, they read fields, and + # they cannot be migrated (D0 is compiler-generated). + cbody = old[old.index(f"struct {cls} {{"):] + cbody = cbody[:cbody.index("\n};") + 3] + cbody = re.sub(r"#ifdef __cplusplus.*?#endif\n", "", cbody, flags=re.S) + cbody = re.sub(r"\n\s*/\* methods \*/\n", "\n", cbody) + + return f"""#ifndef {guard} +#define {guard} + +#include "types.h" +#include "Platform.h" +{incs} +/* Derives from Platform: the destructor stores this class's vtable, then + * Platform's -- inlined -- then destroys the MovingMeshCollider at 0x124 and + * the Model at 0xd4 before chaining to Actor. All three belong to Platform. + * Everything this header used to restate below 0x31e was Actor's and + * Platform's, and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct {cls} : Platform {{ +{body} + + /* --- vtable --- */ + virtual ~{cls}(); +{tail} +}}; + +typedef char {cls}_size_must_be_0x{size:x}[sizeof({cls}) == 0x{size:x} ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +{cbody} + +#endif /* __cplusplus */ + +#endif /* {guard} */ +""" + + +def patch_source(text, oldmap, names, types=None, itypes=None): + """Repoint one source at the names Actor and Platform already give it. + + The width-cast branch below is a leftover safety net. It fired when Platform + was briefly read as ending at 0x324 and subclass fields at 0x31e..0x323 + looked inherited; with the base ending at 0x31e those are the subclass's own + fields again and nothing should reach it. + """ + types, itypes = types or {}, itypes or {} + # A marker the generated header declared INSIDE a member the destructor + # typed is not a field of its own -- it is bytes of that member. The header + # no longer declares it, so its uses have to reach into the member instead. + # SwitchPillar's unk_32c is twelve bytes into the TextureTransformer at + # 0x320; ShipWater and RotatingPlatformWdw have the same shape. + for nm, (member, delta, ty) in sorted(SWALLOWED.items(), key=lambda kv: -len(kv[0])): + repl = (f"(*({ty} *)((char *)&{member} + 0x{delta:x}))" if delta + else f"(*({ty} *)&{member})") + text = re.sub(r"\b" + re.escape(nm) + r"\b", repl, text) + for nm, o in sorted(oldmap.items(), key=lambda kv: -len(kv[0])): + if nm in SWALLOWED or o >= PLATFORM_DSIZE or o not in names: + continue + base = names[o] + mine, theirs = types.get(nm), itypes.get(base) + if mine and theirs and mine != theirs: + text = re.sub(r"\b" + re.escape(nm) + r"\b", f"(*({mine} *)&{base})", text) + continue + if base != nm: + text = re.sub(r"\b" + re.escape(nm) + r"\b", names[o], text) + # STAND-IN STRUCTS COLLIDE WITH THE REAL TYPES. A source that predates the + # real header often carries its own one-line placeholder -- + # `struct MeshCollider { int d; };` -- purely so an offset cast has a type + # to name. Once Platform.h drags the real class in, that is a redefinition, + # and mwcc answers some of them with an internal compiler error rather than + # a diagnostic. Drop any single-line placeholder whose name the tree really + # declares; anything it does NOT declare is a genuine local type and stays. + def _drop_placeholder(m): + name = m.group(1) + return "" if (REPO / "include" / f"{name}.h").exists() else m.group(0) + + text = re.sub(r"^struct (\w+) \{[^{}]*\};[ \t]*\n", _drop_placeholder, text, flags=re.M) + + # A local `typedef int Fix12` shadows the real Fix12 template the moment + # Platform.h makes it visible. + text = text.replace("typedef int Fix12;\n", "") + text = re.sub(r"\bFix12\s+(\w+)(?=\s*[,)])", r"int \1", text) + text = re.sub(r"\bFix12(?=\s*[,)])", "int", text) + # `&mModel` reads better than `(char *)&mModel` and is what most sources + # want. But plenty of the extern declarations these files carry were written + # against the raw offset and take `char *`, and C++ will not convert a + # `Model *` to one -- IceBlock hands `&mModel` to + # `_ZN9ModelBase7SetFileEP8BMD_Fileii(char *, ...)` and does not compile. + # So the caller retries the whole class with CAST=True, and whichever form + # verifies is the one kept. See main(). + for off, member in (("0x124", "&mMeshCollider"), ("0x2ec", "&mClsnMat"), ("0xd4", "&mModel")): + repl = f"(char *){member}" if CAST_MEMBERS[0] else member + for lhs in (f"((char *)this) + {off}", f"((char*)this)+{off}", f"((char *)this)+{off}"): + text = text.replace(lhs, repl) + return text + + +def sources_for(cls): + inc = f'#include "{cls}.h"' + return sorted(p for p in list((REPO / "src").glob("*.c")) + list((REPO / "src").glob("*.cpp")) + if inc in p.read_text(errors="replace")) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("classes", nargs="+") + ap.add_argument("--cast-members", action="store_true", + help="pass member addresses as (char *)&m -- for sources whose " + "externs were declared against the raw offset") + args = ap.parse_args() + CAST_MEMBERS[0] = args.cast_members + (names, itypes), idx, sizes = inherited_names(), symbol_index(), class_sizes() + kept, dropped = [], [] + + for cls in args.classes: + hpath = REPO / "include" / f"{cls}.h" + if not hpath.exists(): + dropped.append((cls, "no header")) + print(f"-- {cls:30s} no header") + continue + old = hpath.read_text(errors="replace") + oldmap = {nm: int(o, 16) for ty, star, nm, arr, o in FIELD.findall(old)} + oldtypes = {nm: ty + ('*' if star else '') for ty, star, nm, arr, o in FIELD.findall(old)} + srcs = sources_for(cls) + saved = {p: p.read_text(errors="replace") for p in srcs} + saved[hpath] = old + + hpath.write_text(build_header(cls, old, sizes)) + for p in srcs: + if p.suffix == ".cpp": + p.write_text(patch_source(saved[p], oldmap, names, oldtypes, itypes)) + + d1 = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev.cpp" + d1c = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev.c" + had_c = d1c.exists() + if had_c: + saved[d1c] = d1c.read_text(errors="replace") + d1c.unlink() + d1.write_text(f"""//cpp +// @symbol _ZN{len(cls)}{cls}D1Ev +/* recovered: real C++ destructor -- the compiler emits the whole body + * + * Two vtable stores and three destructor calls, every one a consequence of + * `struct {cls} : Platform`: its own vptr, then Platform's -- inlined, + * because Platform's destructor is defined in its class body -- then + * Platform's Model and MovingMeshCollider, then Actor. This class adds no + * member with a destructor of its own. + */ +#include "{cls}.h" + +{cls}::~{cls}() +{{ +}} +""") + + fails = [] + for p in sorted(set(srcs) | {d1}): + if not p.exists(): + continue + sym = p.stem + if sym not in idx: + continue + addr, size, lab = idx[sym] + try: + ok, why = BP.verify(str(p.relative_to(REPO)).replace("\\", "/"), sym, addr, size, lab) + except Exception as e: # noqa: BLE001 + ok, why = False, f"{type(e).__name__}: {e}"[:90] + if not ok: + fails.append((sym, why)) + hdr = subprocess.run([sys.executable, str(REPO / "tools" / "check_header_offsets.py"), str(hpath)], + capture_output=True, text=True) + if hdr.returncode != 0: + last = hdr.stdout.strip().splitlines()[-1] if hdr.stdout.strip() else "exit 1" + fails.append(("check_header_offsets", last)) + + if fails: + for p, t in saved.items(): + p.write_text(t) + if had_c and d1.exists(): + d1.unlink() + dropped.append((cls, f"{fails[0][0]}: {fails[0][1][:60]}")) + print(f"-- {cls:30s} reverted, {len(fails)} fail -- {fails[0][0]}: {fails[0][1][:55]}") + else: + kept.append(cls) + print(f"OK {cls:30s} {len(srcs) + 1} files") + + print(f"\nkept {len(kept)} / dropped {len(dropped)}") + if kept: + print("kept: " + " ".join(kept)) + for c, why in dropped: + print(f" dropped {c}: {why}") + + +if __name__ == "__main__": + main() diff --git a/tools/subclass_migrate.py b/tools/subclass_migrate.py new file mode 100644 index 000000000..b00ef2ab2 --- /dev/null +++ b/tools/subclass_migrate.py @@ -0,0 +1,414 @@ +"""Rewrite a subclass of a reconstructed actor base as real C++, or leave it be. + +The generated headers restate the whole inheritance chain. This turns one into +`struct X : Platform` keeping only its own fields, makes its destructor a real +method, and repoints its sources at the inherited names -- then verifies every +source the header reaches and REVERTS THE WHOLE CLASS if any one of them fails. +A class is migrated completely or not at all; nothing half-done is left behind. + +The reverts are the point. Of the first nine tried by hand, seven came back out +for four different reasons, and each reason is a fact about the ROM worth +having. See notes/dtor-migration.md. +""" +import argparse +import pathlib +import re +import subprocess +import sys + +sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) +import build_pin as BP # noqa: E402 + +REPO = pathlib.Path(__file__).resolve().parents[1] +W = {"u8": 1, "s8": 1, "char": 1, "bool": 1, "u16": 2, "s16": 2, "short": 2, + "u32": 4, "s32": 4, "int": 4, "Fix12i": 4, "PathPtr": 8} +FIELD = re.compile(r"^\s*([A-Za-z_][\w:<>]*)\s+(\**)(\w+)(\[[^\]]*\])?\s*;\s*/\*\s*(0x[0-9a-fA-F]+)", re.M) + +# The base class this run is migrating subclasses of, and its DATA size -- the +# end of its last declared field, which is where a derived class's own fields +# start. That is NOT its sizeof: the Itanium ABI lets a derived class use a +# non-POD base's tail padding, and Platform's subclasses do (its data ends at +# 0x31e and it rounds to 0x320). Both are read off the base's header. +BASE = ["Platform"] +BASE_DSIZE = [0x31e] + +# build_header fills this: marker name -> (member, byte offset into it, type). +SWALLOWED = {} + +# Set by main() for the second attempt: emit `(char *)&mModel` rather than +# `&mModel`, for sources whose externs were declared against the raw offset. +CAST_MEMBERS = [False] + + +def chain_ranges(): + """(header, lo, hi) for each class in the base's chain, ROOT FIRST. + + Each class owns the offsets between where its parent ends and where its own + last field ends -- Actor.h covers 0x00..0xd0 and Enemy.h 0xd0..0x110, not + both covering everything. Getting this wrong drops the fields a level does + not declare instead of repointing them, which shows up as a pile of + "undefined identifier" on names the chain really does provide. + """ + chain, cls = [], BASE[0] + while cls: + h = REPO / "include" / f"{cls}.h" + if not h.exists(): + break + chain.append((cls, h)) + m = re.search(r"^\s*struct\s+" + re.escape(cls) + r"\s*:\s*(\w+)", + h.read_text(errors="replace"), re.M) + cls = m.group(1) if m else None + sizes = class_sizes() + out, lo = [], 0 + for cls, h in reversed(chain): + hi = base_data_size(cls) or sizes.get(cls, lo) + if hi > lo: + out.append((str(h.relative_to(REPO)).replace("\\", "/"), lo, hi)) + lo = sizes.get(cls, hi) + return out + + +def base_data_size(base): + """End of the base's last declared field -- where a subclass's own start.""" + h = REPO / "include" / f"{base}.h" + last = 0 + for ty, star, nm, arr, off in FIELD.findall(h.read_text(errors="replace")): + if nm.startswith("pad_"): + continue + w = 4 if star else W.get(ty, 4) + n = int(arr.strip("[]"), 0) if arr else 1 + last = max(last, int(off, 16) + w * n) + return last + + +def base_member_offsets(base): + """Offsets of members the BASE destroys -- a subclass must not claim them.""" + out = set() + h = REPO / "include" / f"{base}.h" + sizes = class_sizes() + for ty, star, nm, arr, off in FIELD.findall(h.read_text(errors="replace")): + if ty in sizes and not star: + out.add(int(off, 16)) + return out + + +BASE_MEMBER_OFFSETS = [set()] + + +def inherited_names(): + """offset -> (name, type) Actor.h / Platform.h gives that offset.""" + out, ty_out = {}, {} + for h, lo, hi in chain_ranges(): + for ty, star, name, arr, off in FIELD.findall((REPO / h).read_text(errors="replace")): + o = int(off, 16) + if lo <= o < hi and not name.startswith("pad_"): + if o not in out: + out[o] = name + ty_out[name] = ty + ("*" if star else "") + return out, ty_out + + +def symbol_index(): + idx = {} + for p in REPO.glob("config/**/symbols.txt"): + lab = p.parent.name + for line in p.read_text(errors="replace").splitlines(): + m = re.match(r"\s*(\S+)\s+kind:function\([^)]*size=(0x[0-9a-f]+)\)\s+addr:(0x[0-9a-f]+)", line) + if m: + idx[m.group(1)] = (int(m.group(3), 16), int(m.group(2), 16), lab) + return idx + + +def class_sizes(): + """Class -> sizeof, from the tree's own compile-time assertions.""" + out = {} + for h in (REPO / "include").rglob("*.h"): + for m in re.finditer(r"(\w+)_size_must_be_(0x[0-9a-fA-F]+)", h.read_text(errors="replace")): + out[m.group(1)] = int(m.group(2), 16) + return out + + +def members_from_destructor(cls, sizes): + """offset -> (type, sizeof) for the members the ROM's own D1 destroys. + + THE DESTRUCTOR NAMES ITS VICTIMS AND THEIR TYPES. A generated header calls + the thing at 0x320 `u8 mModel2` and the compiler emits nothing for it, so an + empty destructor body comes out short. The ROM's destructor calls + `_ZN5ModelD1Ev(this + 0x320)`, which says the member is a Model; declaring + it as one is what makes the empty body reproduce. That type's own size + assertion then has to close on the next field, which is a second and + independent check on the offset. + + Members the BASE owns are skipped -- they are not this class's. + """ + out = {} + for suffix in (".c", ".cpp"): + p = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev{suffix}" + if not p.exists(): + continue + for mangled, off in re.findall( + r"_ZN(\d+\w+?)D[12]Ev\s*\(\s*\(?\s*char\s*\*\s*\)?\s*(?:t|self|thiz|this)\s*\+\s*(0x[0-9a-fA-F]+)", + p.read_text(errors="replace")): + m = re.match(r"(\d+)(\w+)$", mangled) + if not m: + continue + n, o = int(m.group(1)), int(off, 16) + name = m.group(2)[:n] + if len(name) != n or o in BASE_MEMBER_OFFSETS[0] or name not in sizes: + continue + out[o] = (name, sizes[name]) + return out + + +def build_header(cls, old, sizes=None): + """(text, size, own-field-count) for the rewritten header.""" + sizes = sizes or {} + dtor_members = members_from_destructor(cls, sizes) + own = sorted((int(o, 16), ty, star, nm) + for ty, star, nm, arr, o in FIELD.findall(old) + if int(o, 16) >= BASE_DSIZE[0] and not nm.startswith("pad_")) + covered = set() + for o, (ty, sz) in dtor_members.items(): + covered.update(range(o, o + sz)) + SWALLOWED.clear() + for o, ty, star, nm in own: + if o in covered: + base_off = max(b for b in dtor_members if b <= o) + SWALLOWED[nm] = (f"m{dtor_members[base_off][0]}", o - base_off, ty) + own = [f for f in own if f[0] not in covered] + seen = set() + for o, (ty, sz) in sorted(dtor_members.items()): + own.append((o, ty, "", f"m{ty}" if ty not in seen else f"m{ty}_{o:03x}")) + seen.add(ty) + own.sort() + lines, cur = [], BASE_DSIZE[0] + for o, ty, star, nm in own: + if o > cur: + lines.append(f" u8 pad_{cur:03x}[0x{o - cur:x}];") + lines.append(f" {ty} {star}{nm};".ljust(38) + f"/* 0x{o:03x} */") + cur = o + (4 if star else sizes.get(ty) or W.get(ty, 4)) + size = max(0x320, (cur + 3) & ~3) + meths = re.findall(r"^\s{4}([A-Za-z_][\w:<>]*\s+\**\w+\([^)]*\));", old, re.M) + guard = cls.upper() + "_H" + incs = "".join('#include "%s.h"\n' % ty + for ty in sorted({t2 for _, (t2, _) in dtor_members.items()}) + if (REPO / "include" / f"{ty}.h").exists()) + body = "\n".join(lines) if lines else " /* no fields of its own */" + tail = "".join(f"\n {m};" for m in meths) + + # The C side keeps the flat struct verbatim -- same arrangement as + # include/ShadowModel.h and include/Fader.h. A C translation unit gets no + # base sub-object and no implicit vptr, so it needs every offset spelled + # out, and the generated declaration this replaces already is exactly that. + # The D0 files are why it has to stay: they are C, they read fields, and + # they cannot be migrated (D0 is compiler-generated). + cbody = old[old.index(f"struct {cls} {{"):] + cbody = cbody[:cbody.index("\n};") + 3] + cbody = re.sub(r"#ifdef __cplusplus.*?#endif\n", "", cbody, flags=re.S) + cbody = re.sub(r"\n\s*/\* methods \*/\n", "\n", cbody) + + base = BASE[0] + bdsize = BASE_DSIZE[0] + return f"""#ifndef {guard} +#define {guard} + +#include "types.h" +#include "{base}.h" +{incs} +/* Derives from {base}: the destructor stores this class's vtable, then the + * base's, then destroys whatever the base owns before chaining further up. + * Everything this header used to restate below 0x{bdsize:x} belonged to the + * chain above and is inherited now. + * + * SIZE IS THE OBSERVED FIELD SPAN, rounded up. It guards this declaration; it + * is not independent evidence about the ROM. + */ + +#ifdef __cplusplus + +struct {cls} : {base} {{ +{body} + + /* --- vtable --- */ + virtual ~{cls}(); +{tail} +}}; + +typedef char {cls}_size_must_be_0x{size:x}[sizeof({cls}) == 0x{size:x} ? 1 : -1]; + +#else + +/* The C spelling of the same object, flat. Kept because the D0 file is a C + translation unit that reads these fields, and D0 is compiler-generated so it + can never be migrated. Same arrangement as include/ShadowModel.h. */ +{cbody} + +#endif /* __cplusplus */ + +#endif /* {guard} */ +""" + + +def patch_source(text, oldmap, names, types=None, itypes=None): + """Repoint one source at the names Actor and Platform already give it. + + The width-cast branch below is a leftover safety net. It fired when Platform + was briefly read as ending at 0x324 and subclass fields at 0x31e..0x323 + looked inherited; with the base ending at 0x31e those are the subclass's own + fields again and nothing should reach it. + """ + types, itypes = types or {}, itypes or {} + # A marker the generated header declared INSIDE a member the destructor + # typed is not a field of its own -- it is bytes of that member. The header + # no longer declares it, so its uses have to reach into the member instead. + # SwitchPillar's unk_32c is twelve bytes into the TextureTransformer at + # 0x320; ShipWater and RotatingPlatformWdw have the same shape. + for nm, (member, delta, ty) in sorted(SWALLOWED.items(), key=lambda kv: -len(kv[0])): + repl = (f"(*({ty} *)((char *)&{member} + 0x{delta:x}))" if delta + else f"(*({ty} *)&{member})") + text = re.sub(r"\b" + re.escape(nm) + r"\b", repl, text) + for nm, o in sorted(oldmap.items(), key=lambda kv: -len(kv[0])): + if nm in SWALLOWED or o >= BASE_DSIZE[0] or o not in names: + continue + base = names[o] + mine, theirs = types.get(nm), itypes.get(base) + if mine and theirs and mine != theirs: + text = re.sub(r"\b" + re.escape(nm) + r"\b", f"(*({mine} *)&{base})", text) + continue + if base != nm: + text = re.sub(r"\b" + re.escape(nm) + r"\b", names[o], text) + # STAND-IN STRUCTS COLLIDE WITH THE REAL TYPES. A source that predates the + # real header often carries its own one-line placeholder -- + # `struct MeshCollider { int d; };` -- purely so an offset cast has a type + # to name. Once Platform.h drags the real class in, that is a redefinition, + # and mwcc answers some of them with an internal compiler error rather than + # a diagnostic. Drop any single-line placeholder whose name the tree really + # declares; anything it does NOT declare is a genuine local type and stays. + def _drop_placeholder(m): + name = m.group(1) + return "" if (REPO / "include" / f"{name}.h").exists() else m.group(0) + + text = re.sub(r"^struct (\w+) \{[^{}]*\};[ \t]*\n", _drop_placeholder, text, flags=re.M) + + # A local `typedef int Fix12` shadows the real Fix12 template the moment + # Platform.h makes it visible. + text = text.replace("typedef int Fix12;\n", "") + text = re.sub(r"\bFix12\s+(\w+)(?=\s*[,)])", r"int \1", text) + text = re.sub(r"\bFix12(?=\s*[,)])", "int", text) + # `&mModel` reads better than `(char *)&mModel` and is what most sources + # want. But plenty of the extern declarations these files carry were written + # against the raw offset and take `char *`, and C++ will not convert a + # `Model *` to one -- IceBlock hands `&mModel` to + # `_ZN9ModelBase7SetFileEP8BMD_Fileii(char *, ...)` and does not compile. + # So the caller retries the whole class with CAST=True, and whichever form + # verifies is the one kept. See main(). + for off, member in (("0x124", "&mMeshCollider"), ("0x2ec", "&mClsnMat"), ("0xd4", "&mModel")): + repl = f"(char *){member}" if CAST_MEMBERS[0] else member + for lhs in (f"((char *)this) + {off}", f"((char*)this)+{off}", f"((char *)this)+{off}"): + text = text.replace(lhs, repl) + return text + + +def sources_for(cls): + inc = f'#include "{cls}.h"' + return sorted(p for p in list((REPO / "src").glob("*.c")) + list((REPO / "src").glob("*.cpp")) + if inc in p.read_text(errors="replace")) + + +def main(): + ap = argparse.ArgumentParser() + ap.add_argument("--base", default="Platform", + help="the reconstructed base whose subclasses to migrate") + ap.add_argument("classes", nargs="+") + ap.add_argument("--cast-members", action="store_true", + help="pass member addresses as (char *)&m -- for sources whose " + "externs were declared against the raw offset") + args = ap.parse_args() + CAST_MEMBERS[0] = args.cast_members + BASE[0] = args.base + BASE_DSIZE[0] = base_data_size(args.base) + BASE_MEMBER_OFFSETS[0] = base_member_offsets(args.base) + (names, itypes), idx, sizes = inherited_names(), symbol_index(), class_sizes() + kept, dropped = [], [] + + for cls in args.classes: + hpath = REPO / "include" / f"{cls}.h" + if not hpath.exists(): + dropped.append((cls, "no header")) + print(f"-- {cls:30s} no header") + continue + old = hpath.read_text(errors="replace") + oldmap = {nm: int(o, 16) for ty, star, nm, arr, o in FIELD.findall(old)} + oldtypes = {nm: ty + ('*' if star else '') for ty, star, nm, arr, o in FIELD.findall(old)} + srcs = sources_for(cls) + saved = {p: p.read_text(errors="replace") for p in srcs} + saved[hpath] = old + + hpath.write_text(build_header(cls, old, sizes)) + for p in srcs: + if p.suffix == ".cpp": + p.write_text(patch_source(saved[p], oldmap, names, oldtypes, itypes)) + + d1 = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev.cpp" + d1c = REPO / "src" / f"_ZN{len(cls)}{cls}D1Ev.c" + had_c = d1c.exists() + if had_c: + saved[d1c] = d1c.read_text(errors="replace") + d1c.unlink() + d1.write_text(f"""//cpp +// @symbol _ZN{len(cls)}{cls}D1Ev +/* recovered: real C++ destructor -- the compiler emits the whole body + * + * Two vtable stores and three destructor calls, every one a consequence of + * `struct {cls} : Platform`: its own vptr, then Platform's -- inlined, + * because Platform's destructor is defined in its class body -- then + * Platform's Model and MovingMeshCollider, then Actor. This class adds no + * member with a destructor of its own. + */ +#include "{cls}.h" + +{cls}::~{cls}() +{{ +}} +""") + + fails = [] + for p in sorted(set(srcs) | {d1}): + if not p.exists(): + continue + sym = p.stem + if sym not in idx: + continue + addr, size, lab = idx[sym] + try: + ok, why = BP.verify(str(p.relative_to(REPO)).replace("\\", "/"), sym, addr, size, lab) + except Exception as e: # noqa: BLE001 + ok, why = False, f"{type(e).__name__}: {e}"[:90] + if not ok: + fails.append((sym, why)) + hdr = subprocess.run([sys.executable, str(REPO / "tools" / "check_header_offsets.py"), str(hpath)], + capture_output=True, text=True) + if hdr.returncode != 0: + last = hdr.stdout.strip().splitlines()[-1] if hdr.stdout.strip() else "exit 1" + fails.append(("check_header_offsets", last)) + + if fails: + for p, t in saved.items(): + p.write_text(t) + if had_c and d1.exists(): + d1.unlink() + dropped.append((cls, f"{fails[0][0]}: {fails[0][1][:60]}")) + print(f"-- {cls:30s} reverted, {len(fails)} fail -- {fails[0][0]}: {fails[0][1][:55]}") + else: + kept.append(cls) + print(f"OK {cls:30s} {len(srcs) + 1} files") + + print(f"\nkept {len(kept)} / dropped {len(dropped)}") + if kept: + print("kept: " + " ".join(kept)) + for c, why in dropped: + print(f" dropped {c}: {why}") + + +if __name__ == "__main__": + main() diff --git a/tools/test_objisolate.py b/tools/test_objisolate.py index 7197939df..c5467f04a 100644 --- a/tools/test_objisolate.py +++ b/tools/test_objisolate.py @@ -135,20 +135,41 @@ def test_corrects_inlined_base_vtable_store(self): OI.isolate(obj, "_ZN1DD1Ev") self.assertEqual(sorted(set(self._vtable_addends(obj, "_ZN1DD1Ev"))), [0]) - def test_still_refuses_an_unsurveyed_vtable_addend(self): - """Only the preamble skip of 8 is correctable; anything else is refused. - - Multiple inheritance produces a secondary vptr store pointing into the - middle of the vtable object -- addend 44 for `ModelAnim` -- and there is no - enrolled instance to verify that correction against. Fail-closed costs one - function; fail-open corrupts a module.""" + def test_corrects_a_multiple_inheritance_secondary_vptr(self): + """A second base means a second vptr store, further into the vtable. + + Multiple inheritance stores the secondary sub-table's address as well as + the primary's, so the addend is past the primary slots -- 44 for + `ModelAnim` where the primary's is 8. The correction is the same + subtraction, because mwcc's `_ZTV` addresses the vtable object's start + while the ROM's IS the slot array, and the ROM names the destination + independently: `_ZTV9ModelAnim` 0x0208e980 and + `VTable_Animation_ModelAnimThunk` 0x0208e9a4 differ by 0x24, which is + exactly 44 - 8. + + This was refused while no enrolled instance existed to check the + arithmetic against. Both stores now drop by the preamble.""" obj = self.build("struct B1 { int p[4]; virtual ~B1(){} virtual void f(); };\n" "struct B2 { int q[4]; virtual ~B2(){} virtual void g(); };\n" "struct M : B1, B2 { virtual ~M(); };\n" "M::~M(){}\n") - err = OI.plan(obj.read_bytes(), "_ZN1MD1Ev")["error"] - self.assertIsNotNone(err) - self.assertIn("_ZTV", err) + self.assertIsNone(OI.plan(obj.read_bytes(), "_ZN1MD1Ev")["error"]) + before = sorted(set(self._vtable_addends(obj, "_ZN1MD1Ev"))) + OI.isolate(obj, "_ZN1MD1Ev") + after = sorted(set(self._vtable_addends(obj, "_ZN1MD1Ev"))) + self.assertEqual(after, [a - 8 for a in before]) + self.assertIn(0, after) # the primary landed on the slot array + + def test_still_refuses_a_vtable_addend_below_the_preamble(self): + """Correctable means "past the preamble". An addend under it is not. + + Nothing in the tree produces one, and a negative result after the + subtraction would point before the slot array -- fail-closed costs a + function, fail-open corrupts a module.""" + obj = self.build("struct V { int p[4]; virtual ~V(); virtual void f(); };\n" + "V::~V(){}\n") + raw = bytearray(obj.read_bytes()) + self.assertIsNone(OI.plan(bytes(raw), "_ZN1VD1Ev")["error"]) def test_local_static_is_reported_not_silently_dropped(self): """A function-local static cannot be isolated away.