Player matching notes
August 26, 2026 ยท View on GitHub
Reusable VC7 source-shape evidence from the TH08 Player option/shot callback family.
- Reusing the shared
PlayerOptionStatestate-1/state-2/state-3 lexical skeleton is more reliable than reconstructing each option callback independently. - Under
/Od, do not introduce a C++ reference alias when the target repeatedly reloads a scalar member. InUpdateHomingShot,f32 &speedadded a 4-byte local home; repeating the directslot->speedmember expression restored the target frame. - Aggregate assignment and component assignment are not interchangeable.
FUN_00450AD0needs three separatevm.pos.x/y/z = vectors[i].x/y/zstores so VC7 recomputesi*0xCthree times; aggregate copy shortened the body by 34 bytes. - Preserve branch-local lifetime for non-trivial
Float3work.FUN_00450EE0constructs its effect position only inside the every-eighth-frame branch; function-scope declaration hoisted the constructor and changed 52 bytes. - The target sometimes writes
vm.pendingInterrupt = 1directly instead of callingSetInterrupt(1).UpdatePersistentShotandUpdateShotTrailrequire the direct field owner. - Avoid chained assignments when target store order matters.
FUN_00450C50needshitboxSize.x = value; hitboxSize.y = value;;x = y = valuereverses the stores under VC7. - Keep associated tables out of authored progress:
FUN_0044F5E0is 0x32A authored / 0x34E compared, andFUN_00450C50is 0x263 authored / 0x287 compared. - The SHT callback ABI is consistently
__fastcall(Player *player, PlayerShot *slot, ...): ECX owns Player, EDX owns the shot, and extra SHT arguments are stack parameters. An isolated free-function probe reproduces this without perturbing the production Player TU.