Skip to content

Convert the four intact-TU minigame classes to real members - #2116

Merged
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-methods-3
Sep 1, 2026
Merged

Convert the four intact-TU minigame classes to real members#2116
andrewboudreau merged 1 commit into
mainfrom
cpp/minigame-methods-3

Conversation

@andrewboudreau

Copy link
Copy Markdown
Collaborator

dScMgBSC_c, dScMgCard_c, dScMgMCarlo_c, dScMgMCarlo2_c are intact-object TUs — each carries a whole class in one file and includes its own header — but their virtuals were still free functions with hand-written mangled names, sitting right next to the class they belong to.

25 members converted: InitResources, Behavior, Render, CleanupResources, OnYoshiTryEat, OnTurnIntoEgg, OnGroundPounded.

Six bodies were missing their parameter entirely. Card, MCarlo and MCarlo2 each declared OnYoshiTryEat and OnTurnIntoEgg taking only this. The class declares (int) — measured from the ROM's vtables during the slots-18-35 campaign — and an unread trailing argument costs no instruction, which is exactly why the disagreement was invisible. Header wins; the parameter is spelled and left unnamed.

The risk this batch carried, and why I checked rather than assumed

A real member definition can make its TU the class's key function, at which point mwcc emits _ZTV<class> there — bytes the config does not own. 106/106 module fidelity is blind to vtables, so a green build would not have caught it. Checked the objects directly:

dScMgBSC_c       build/src/actors/dScMgBSC_c.o        no vtable/RTTI emitted
dScMgCard_c      build/src/actors/dScMgCard_c.o       no vtable/RTTI emitted
dScMgMCarlo_c    build/src/actors/dScMgMCarlo_c.o     no vtable/RTTI emitted
dScMgMCarlo2_c   build/src/actors/dScMgMCarlo2_c.o    no vtable/RTTI emitted

None of the four classes' key functions — the first virtual declared in each header — lives in these TUs, so nothing moved. ROM data from source is unchanged at 496 verified / 223 partial / 5 differ.

No delinks.txt change: these files were already .cpp and already enrolled.

Flagged, not fixed

src/actors/dScMgBSC_c.cpp carries a comment above OnYoshiTryEat claiming the body is "The DELETING DESTRUCTOR, vtable slot 17 … the old comment here called it OnYoshiTryEat, which is slot 18 — off by one". The body it sits above stores no vtable and calls no deallocator; it sets two flags and calls func_ov004_020b66d4. The ROM reproduces it at the OnYoshiTryEat address, so the symbol is right and the prose is stale. Left for a follow-up rather than silently deleted — someone measured something to write that, and I would rather it be re-measured than dropped.

Verified

rombuild.py -j 16 --no-rom → 11,088/11,088 reproducing, 0 mismatching, 106/106 exact, 100.000000%. Nine static gates green, re-run after line-ending normalization.

With this, every free-function body in the minigame family is now a real C++ member. Stacked on #2115. attribution-override.

dScMgBSC_c, dScMgCard_c, dScMgMCarlo_c and dScMgMCarlo2_c are intact-object
TUs: they include their own class header and carry the whole class in one
file, but their virtuals were still spelled as free functions with
hand-written mangled names next to the class they belong to.

  void _ZN13dScMgMCarlo_c13OnYoshiTryEatEi(char* c)   ->
  void dScMgMCarlo_c::OnYoshiTryEat(int)

Twenty-five members across the four files: InitResources, Behavior, Render,
CleanupResources, OnYoshiTryEat, OnTurnIntoEgg, OnGroundPounded.

Six bodies were missing their slot-18/slot-19 parameter entirely -- Card,
MCarlo and MCarlo2 each declared OnYoshiTryEat and OnTurnIntoEgg taking only
`this`. The class declares `(int)`, measured from the ROM's vtables, and an
unread trailing argument costs no instruction, which is why the disagreement
was invisible. The header wins; the parameter is spelled and unnamed.

THE RISK THIS BATCH CARRIED, and it did not fire: a real member definition
can make its TU the class's key function, and mwcc would then emit
_ZTV<class> there -- bytes the config does not own. Checked directly rather
than inferred, because 106/106 module fidelity is blind to vtables:

  dScMgBSC_c       build/src/actors/dScMgBSC_c.o        no vtable/RTTI emitted
  dScMgCard_c      build/src/actors/dScMgCard_c.o       no vtable/RTTI emitted
  dScMgMCarlo_c    build/src/actors/dScMgMCarlo_c.o     no vtable/RTTI emitted
  dScMgMCarlo2_c   build/src/actors/dScMgMCarlo2_c.o    no vtable/RTTI emitted

None of the four classes' key functions -- the first virtual DECLARED in
each header -- lives in these TUs, so no vtable moved.

No delinks change: these files were already .cpp and already enrolled.

NOT FIXED, flagged for a follow-up: src/actors/dScMgBSC_c.cpp carries a
comment above OnYoshiTryEat claiming the body is "The DELETING DESTRUCTOR,
vtable slot 17 ... the old comment here called it OnYoshiTryEat, which is
slot 18 -- off by one". The body it sits above stores no vtable and calls no
deallocator; it sets two flags and calls func_ov004_020b66d4. The ROM
reproduces it at the OnYoshiTryEat address, so the symbol is right and the
prose is stale.

VERIFIED: python tools/rombuild.py -j 16 --no-rom
  11,088 / 11,088 functions reproducing, 0 mismatching
  106/106 modules exact, 100.000000% of compared bytes
  ROM data from source unchanged: 496 verified, 223 partial, 5 differ
Nine static gates green, re-run after line-ending normalization.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QhhAeJwXBnfPp7B5DNjCwh
@tangos-validator

tangos-validator Bot commented Aug 31, 2026

Copy link
Copy Markdown

✅ PR validation — Passed

Committed merge introduces no reconstruction or attribution regression.

Full merge validation

Check Result
Committed test merge yes
Byte-verified functions 10,781 / 11,347 (95.01%, +0)
Byte-verified code bytes 2,004,460 / 2,211,124 (90.65%, +0)
Claimed, not byte-verified 436 functions, 101,220 bytes (+0)
Perfect source moves 0 R100
Enrolled ranges (delinks complete) 11,059 functions, 2,053,148 bytes (92.86%, +0) -- differs from byte-verified by +278
Contributor credit 0 added, 0 changed, 0 lost
Relocation check 99 checked; 99 VERIFIED
Port reference check 405 checked; 0 stale
Module fidelity 106/106 exact; 100.000000% compared bytes
Code linked from verified source 11,088 functions, 2,067,148 bytes (93.49%)
Module bytes from source 2,067,148 / 3,049,600 (67.8%); 811,492 (26.6%) are data no delink entry reaches
ROM data reproduced from source 496 symbol(s) exact, 223 partial, 5 differ

Byte-verified means the range carries complete in a delinks.txt, so the ROM build compiled it and compared it to the cartridge. The 436 claimed functions have a src/ file named after the symbol with no NONMATCHING banner, and nothing compiles them -- dsd fills their addresses with the ROM's own bytes. Both together are the 11,217 this project calls matched.

Per-file link-check detail

All 4 changed file(s) compile to the ROM byte-for-byte with correct relocation targets.

File Symbol Result Slots checked
src/actors/dScMgBSC_c.cpp _ZN10dScMgBSC_cD1Ev + _ZN10dScMgBSC_cD0Ev + func_ov006_02124a04 + func_ov006_02124a08 + func_ov006_02124ae4 + func_ov006_02124b58 + func_ov006_02124bb4 + func_ov006_02124cb4 + func_ov006_02124dc0 + func_ov006_02124e1c + func_ov006_02124ec4 + func_ov006_02124fd8 + func_ov006_021250e4 + _ZN10dScMgBSC_c15OnGroundPoundedEv + _ZN10dScMgBSC_c13OnTurnIntoEggEi + _ZN10dScMgBSC_c13OnYoshiTryEatEi + _ZN10dScMgBSC_c6RenderEv + _ZN10dScMgBSC_c8BehaviorEv + _ZN10dScMgBSC_c13InitResourcesEv ✅ verified 19
src/actors/dScMgCard_c.cpp _ZN11dScMgCard_cD1Ev + _ZN11dScMgCard_cD0Ev + func_ov006_020d96e0 + func_ov006_020d96f0 + func_ov006_020d970c + func_ov006_020d978c + func_ov006_020d9998 + func_ov006_020d99a4 + func_ov006_020d99ec + func_ov006_020d9a14 + func_ov006_020d9bd0 + func_ov006_020d9bdc + func_ov006_020d9c5c + func_ov006_020da00c + func_ov006_020da0ac + func_ov006_020da154 + func_ov006_020da174 + func_ov006_020da420 + func_ov006_020da4ac + func_ov006_020da5e8 + func_ov006_020da834 + func_ov006_020da860 + func_ov006_020da88c + func_ov006_020da8b8 + func_ov006_020da8e4 + func_ov006_020da974 + _ZN11dScMgCard_c16CleanupResourcesEv + _ZN11dScMgCard_c6RenderEv + _ZN11dScMgCard_c8BehaviorEv + func_ov006_020dac34 + _ZN11dScMgCard_c15OnGroundPoundedEv + _ZN11dScMgCard_c13OnTurnIntoEggEi + _ZN11dScMgCard_c13OnYoshiTryEatEi + _ZN11dScMgCard_c13InitResourcesEv ✅ verified 34
src/actors/dScMgMCarlo2_c.cpp _ZN14dScMgMCarlo2_cD1Ev + _ZN14dScMgMCarlo2_cD0Ev + func_ov006_020f8ff0 + func_ov006_020f9000 + func_ov006_020f94f4 + func_ov006_020f9560 + func_ov006_020f95f0 + func_ov006_020f9668 + func_ov006_020f96e0 + func_ov006_020f9760 + func_ov006_020f98dc + func_ov006_020f9994 + func_ov006_020f9bec + func_ov006_020f9cbc + func_ov006_020f9d68 + func_ov006_020f9db8 + func_ov006_020f9f40 + _ZN14dScMgMCarlo2_c16CleanupResourcesEv + _ZN14dScMgMCarlo2_c6RenderEv + _ZN14dScMgMCarlo2_c8BehaviorEv + _ZN14dScMgMCarlo2_c13OnTurnIntoEggEi + _ZN14dScMgMCarlo2_c13OnYoshiTryEatEi + _ZN14dScMgMCarlo2_c13InitResourcesEv ✅ verified 23
src/actors/dScMgMCarlo_c.cpp _ZN13dScMgMCarlo_cD1Ev + _ZN13dScMgMCarlo_cD0Ev + func_ov006_020f7730 + func_ov006_020f7740 + func_ov006_020f7994 + func_ov006_020f7a00 + func_ov006_020f7a90 + func_ov006_020f7b10 + func_ov006_020f7b90 + func_ov006_020f7c10 + func_ov006_020f7e2c + func_ov006_020f7ee4 + func_ov006_020f8154 + func_ov006_020f8224 + func_ov006_020f82d0 + func_ov006_020f8320 + func_ov006_020f84a8 + func_ov006_020f8540 + _ZN13dScMgMCarlo_c6RenderEv + _ZN13dScMgMCarlo_c8BehaviorEv + _ZN13dScMgMCarlo_c13OnTurnIntoEggEi + _ZN13dScMgMCarlo_c13OnYoshiTryEatEi + _ZN13dScMgMCarlo_c13InitResourcesEv ✅ verified 23

The private worker commits a test merge, builds the stock ROM profile, compares every executable module, measures matched and source-built code, checks contributor lineage, and verifies affected relocations. The mod profile is opt-in and is not part of this merge gate.

@andrewboudreau andrewboudreau added the attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings label Aug 31, 2026
Base automatically changed from cpp/minigame-methods-2 to main September 1, 2026 07:26
@andrewboudreau
andrewboudreau merged commit 8c1663a into main Sep 1, 2026
8 checks passed
@andrewboudreau
andrewboudreau deleted the cpp/minigame-methods-3 branch September 1, 2026 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

attribution-override Maintainer accepts this PR's contributor-credit changes; validation reports them as warnings

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant