From dc58696a899b928f56d1f2481ef66b4a1b04b3a5 Mon Sep 17 00:00:00 2001 From: = Date: Mon, 10 Aug 2026 11:31:51 -0500 Subject: [PATCH] Platform is 0x320, Enemy derives from Actor, and the structors that follow The first half of the layout work behind #1377, split so each PR clears the validator's 200-file cap. 172 files; the second half is the header-generation fixes and the Vector3 destructor. PLATFORM'S DATA ENDS AT 0x31e, SIZEOF 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 Platform 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. Ending at 0x324 satisfies BowserFireSeaArena and contradicts the other four. This corrects #1374, which was mine, and which took BowserFireSeaArena's evidence alone. Also here: Enemy derives from Actor -- what 51 subclasses were waiting on -- with five more Enemy fields named by its subclasses and its vtable symbol; the inline base destructors for ActorDerived and Scene; Platform's own destructor forced out of line by a call it never makes, because an inline destructor emits nothing in a TU that only includes the header; the arm9 D0s that were missing an operator delete rather than fakematching; and objisolate learning the multiple-inheritance secondary vptr addend -- `>= VTABLE_PREAMBLE` rather than `==`, so 44 -> 36 for ModelAnim corrects instead of being refused, which the ROM confirms independently (_ZTV9ModelAnim 0x0208e980 against VTable_Animation_ModelAnimThunk 0x0208e9a4, differing by exactly 44 - 8). VERIFIED rombuild -j16, full ROM: 106/106 exact, 0 mismatching, 10,813 source-built, 87.88%. eligible.py against cbd57a83: name list IDENTICAL -- nothing lost, nothing gained. langmode ratchet PASS. pr_linkcheck: no new WRONG or NO-REPRO. Original work is by the author of #1377; this split preserves the content, not the 37-commit history, which remains on that branch. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_015AXm5k53WFPjCYcDHRDX3x --- config/arm9/overlays/ov002/delinks.txt | 7 +- config/arm9/overlays/ov002/symbols.txt | 1 + config/arm9/overlays/ov091/delinks.txt | 3 - include/Actor.h | 9 +- include/Animation.h | 19 + include/ArrowSignRight.h | 51 ++- include/BigBrickBlock.h | 41 +- include/BlendModelAnim.h | 12 + include/BlueCoinSwitch.h | 68 +-- include/BowserFireSeaArena.h | 10 +- include/CannonHatch.h | 56 ++- include/ChainChompFence.h | 49 ++- include/CheepCheep.h | 52 ++- include/CylinderClsn.h | 19 + include/DonutBlock.h | 23 +- include/Enemy.h | 112 ++--- include/FireSeaElevator.h | 51 ++- include/FloatingFloorLllBig.h | 38 +- include/FortressTower.h | 49 ++- include/FortressWall.h | 60 ++- include/Heap.h | 16 + include/HugeCover.h | 51 ++- include/IceBlock.h | 57 ++- include/IceSheet.h | 49 ++- include/KingBobOmb.h | 74 +++- include/KnockDownPlank.h | 53 ++- include/MeshCollider.h | 19 + include/MetalNet.h | 50 ++- include/ModelAnim.h | 12 + include/ModelAnim2.h | 12 + include/ModelBase.h | 19 + include/MovingBarSmall.h | 57 ++- include/MovingCylinderClsn.h | 19 + include/MovingMeshCollider.h | 19 + include/MrBlizzard.h | 65 ++- include/Platform.h | 38 +- include/PoleBillboard.h | 59 ++- include/PyramidStep.h | 53 ++- include/PyramidTop.h | 59 ++- include/QuestionBlock.h | 58 ++- include/RotatingCogSmall.h | 54 ++- include/RotatingPlatformLll.h | 51 ++- include/RotatingPlatformWdw.h | 58 ++- include/SeesawBob.h | 52 ++- include/ShipWater.h | 55 ++- include/ShipWing.h | 56 ++- include/SlidingIce.h | 51 ++- include/SlidingPlatformWf.h | 52 ++- include/SquarePathLift.h | 53 ++- include/Squasher.h | 53 ++- include/StarSwitch.h | 80 +++- include/Stump.h | 52 ++- include/SwitchPillar.h | 56 ++- include/TTC_MovingBar.h | 51 ++- include/TinyCover.h | 53 ++- include/TowerStep.h | 51 ++- include/TtcMovingCubeA.h | 55 ++- include/TtcRotatingGear.h | 54 ++- include/WallSign.h | 51 ++- notes/handoff-class-skeleton.md | 202 +++++++++ src/_ZN10BowserFire13InitResourcesEv.cpp | 8 +- src/_ZN10BowserFire8BehaviorEv.cpp | 4 +- src/_ZN10CheepCheep13InitResourcesEv.cpp | 8 +- src/_ZN10CheepCheep6RenderEv.cpp | 4 +- src/_ZN10CheepCheep8BehaviorEv.cpp | 1 - src/_ZN10DonutBlock13InitResourcesEv.cpp | 68 +-- src/_ZN10DonutBlock8BehaviorEv.cpp | 6 +- src/_ZN10DonutBlockD1Ev.cpp | 4 +- src/_ZN10KingBobOmb13InitResourcesEv.cpp | 10 +- src/_ZN10KingBobOmb6RenderEv.cpp | 2 +- src/_ZN10MrBlizzard13InitResourcesEv.cpp | 18 +- src/_ZN10PyramidTop16CleanupResourcesEv.cpp | 2 +- src/_ZN10PyramidTop8BehaviorEv.cpp | 4 +- src/_ZN10SlidingIce16CleanupResourcesEv.cpp | 4 +- src/_ZN10SlidingIce6RenderEv.cpp | 2 +- src/_ZN10SlidingIce8BehaviorEv.cpp | 4 +- src/_ZN10StarSwitch16CleanupResourcesEv.cpp | 4 +- src/_ZN10StarSwitch8BehaviorEv.cpp | 4 +- src/_ZN10StarSwitchD1Ev.cpp | 7 +- src/_ZN11CannonHatch13InitResourcesEv.cpp | 2 +- src/_ZN11CannonHatch6RenderEv.cpp | 2 +- src/_ZN11PyramidStep13InitResourcesEv.cpp | 12 +- src/_ZN11PyramidStep16CleanupResourcesEv.cpp | 2 +- src/_ZN12FortressWall13InitResourcesEv.cpp | 2 +- src/_ZN12FortressWall16CleanupResourcesEv.cpp | 4 +- src/_ZN12FortressWallD1Ev.cpp | 2 +- src/_ZN12SwitchPillar13InitResourcesEv.cpp | 6 +- src/_ZN12SwitchPillar16CleanupResourcesEv.cpp | 4 +- src/_ZN12SwitchPillar8BehaviorEv.cpp | 6 +- ..._ZN13BigBrickBlock16CleanupResourcesEv.cpp | 4 +- src/_ZN13BigBrickBlock8BehaviorEv.cpp | 12 +- src/_ZN13BigBrickBlockD1Ev.cpp | 2 +- ..._ZN13FortressTower16CleanupResourcesEv.cpp | 4 +- src/_ZN13FortressTower8BehaviorEv.cpp | 6 +- ..._ZN13PoleBillboard16CleanupResourcesEv.cpp | 4 +- ..._ZN13QuestionBlock16CleanupResourcesEv.cpp | 12 +- src/_ZN13QuestionBlock6RenderEv.cpp | 4 +- src/_ZN13QuestionBlock8BehaviorEv.cpp | 18 +- src/_ZN13TTC_MovingBar13InitResourcesEv.cpp | 12 +- ..._ZN13TTC_MovingBar16CleanupResourcesEv.cpp | 4 +- ...ZN14ArrowSignRight16CleanupResourcesEv.cpp | 4 +- src/_ZN14ArrowSignRight8BehaviorEv.cpp | 4 +- src/_ZN14BlueCoinSwitch13InitResourcesEv.cpp | 12 +- ...ZN14BlueCoinSwitch16CleanupResourcesEv.cpp | 4 +- src/_ZN14BlueCoinSwitch6RenderEv.cpp | 2 +- src/_ZN14BlueCoinSwitch8BehaviorEv.cpp | 2 +- src/_ZN14KnockDownPlank13InitResourcesEv.cpp | 20 +- ...ZN14KnockDownPlank16CleanupResourcesEv.cpp | 4 +- ...ZN14MovingBarSmall16CleanupResourcesEv.cpp | 4 +- src/_ZN14SquarePathLift13InitResourcesEv.cpp | 10 +- ...ZN14SquarePathLift16CleanupResourcesEv.cpp | 4 +- src/_ZN14SquarePathLift8BehaviorEv.cpp | 11 +- src/_ZN15ChainChompFence13InitResourcesEv.cpp | 4 +- ...N15ChainChompFence16CleanupResourcesEv.cpp | 4 +- src/_ZN15FireSeaElevator13InitResourcesEv.cpp | 4 +- ...N15FireSeaElevator16CleanupResourcesEv.cpp | 2 +- src/_ZN15FireSeaElevator8BehaviorEv.cpp | 5 +- src/_ZN15TtcRotatingGear13InitResourcesEv.cpp | 7 +- ...N15TtcRotatingGear16CleanupResourcesEv.cpp | 4 +- ..._ZN16RotatingCogSmall13InitResourcesEv.cpp | 18 +- ...16RotatingCogSmall16CleanupResourcesEv.cpp | 6 +- src/_ZN16RotatingCogSmall8BehaviorEv.cpp | 2 +- ...7SlidingPlatformWf16CleanupResourcesEv.cpp | 4 +- ...loatingFloorLllBig16CleanupResourcesEv.cpp | 4 +- src/_ZN19FloatingFloorLllBigD1Ev.cpp | 7 +- ...19RotatingPlatformLll13InitResourcesEv.cpp | 11 +- ...otatingPlatformLll16CleanupResourcesEv.cpp | 4 +- src/_ZN19RotatingPlatformLll8BehaviorEv.cpp | 2 +- ...19RotatingPlatformWdw13InitResourcesEv.cpp | 8 +- ...otatingPlatformWdw16CleanupResourcesEv.cpp | 4 +- src/_ZN19RotatingPlatformWdw8BehaviorEv.cpp | 10 +- src/_ZN5EnemyD0Ev.c | 28 -- src/_ZN5EnemyD0Ev.cpp | 18 + src/_ZN5EnemyD1Ev.c | 22 - src/_ZN5EnemyD1Ev.cpp | 22 + src/_ZN5Stump13InitResourcesEv.cpp | 10 +- src/_ZN5Stump16CleanupResourcesEv.cpp | 1 - src/_ZN5Stump6RenderEv.cpp | 4 +- src/_ZN5Stump8BehaviorEv.cpp | 1 - src/_ZN8IceBlock13InitResourcesEv.cpp | 4 +- src/_ZN8IceBlock16CleanupResourcesEv.cpp | 4 +- src/_ZN8IceBlock8BehaviorEv.cpp | 10 +- src/_ZN8IceSheet13InitResourcesEv.cpp | 7 +- src/_ZN8IceSheet16CleanupResourcesEv.cpp | 4 +- src/_ZN8IceSheet8BehaviorEv.cpp | 4 +- src/_ZN8MetalNet13InitResourcesEv.cpp | 6 +- src/_ZN8MetalNet16CleanupResourcesEv.cpp | 4 +- src/_ZN8MetalNet8BehaviorEv.cpp | 2 +- src/_ZN8PlatformD0Ev.c | 19 - src/_ZN8PlatformD0Ev.cpp | 22 + src/_ZN8PlatformD1Ev.cpp | 19 +- src/_ZN8ShipWing13InitResourcesEv.cpp | 12 +- src/_ZN8ShipWing16CleanupResourcesEv.cpp | 4 +- src/_ZN8ShipWing8BehaviorEv.cpp | 4 +- src/_ZN8Squasher13InitResourcesEv.cpp | 6 +- src/_ZN9HugeCover13InitResourcesEv.cpp | 3 - src/_ZN9HugeCover16CleanupResourcesEv.cpp | 4 +- src/_ZN9HugeCover8BehaviorEv.cpp | 4 +- src/_ZN9SeesawBob13InitResourcesEv.cpp | 10 +- src/_ZN9SeesawBob16CleanupResourcesEv.cpp | 4 +- src/_ZN9SeesawBob8BehaviorEv.cpp | 10 +- src/_ZN9ShipWater16CleanupResourcesEv.cpp | 4 +- src/_ZN9ShipWater8BehaviorEv.cpp | 4 +- src/_ZN9TinyCover16CleanupResourcesEv.cpp | 4 +- src/_ZN9TowerStep13InitResourcesEv.cpp | 4 +- src/_ZN9TowerStep16CleanupResourcesEv.cpp | 4 +- src/_ZN9TowerStep8BehaviorEv.cpp | 8 +- tools/d0_migrate.py | 133 ++++++ tools/objisolate.py | 28 +- tools/platform_subclass.py | 351 +++++++++++++++ tools/subclass_migrate.py | 414 ++++++++++++++++++ tools/test_objisolate.py | 41 +- 172 files changed, 3491 insertions(+), 1064 deletions(-) create mode 100644 notes/handoff-class-skeleton.md delete mode 100644 src/_ZN5EnemyD0Ev.c create mode 100644 src/_ZN5EnemyD0Ev.cpp delete mode 100644 src/_ZN5EnemyD1Ev.c create mode 100644 src/_ZN5EnemyD1Ev.cpp delete mode 100644 src/_ZN8PlatformD0Ev.c create mode 100644 src/_ZN8PlatformD0Ev.cpp create mode 100644 tools/d0_migrate.py create mode 100644 tools/platform_subclass.py create mode 100644 tools/subclass_migrate.py 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.