From 0c1b2719e28811bf60d9877efef2c311fd21f8fb Mon Sep 17 00:00:00 2001 From: vagnertxr Date: Tue, 8 Sep 2026 18:38:00 -0300 Subject: [PATCH] Match cmMenuFixedController::init and update Completes and links sora/cm/cm_controller_menu_fixed.cpp. init was at 23%. Three things were wrong: - unkFA.m_flag2 is actually m_rotate; the target ORs 0x40, not 0x04. - The camera has to be held in a local. Indexing m_cameraManager->m_cameras[0] per statement reloads the manager every time. - m_rot is written through an 8-byte temporary, not a Vec3f. A Vec3f temporary forces a 32-byte frame in every position it can occupy, while the target's frame is 16. The flag writes are split deliberately: setting m_flag7 through the mask keeps the original read live, so the following two writes chain off it. With all three written through the mask, mwcc folds (flags|0x82)|0x40 into flags|0xC2 and hoists it above the first store. update was never written. It is storeDefault() behind the unk8 guard, then init(), then m_transformFlag and the call. Caching m_cameraManager in a local is what keeps the manager in one register across the inlined bodies. fn_800A69AC is renamed to its mangled name, which follows from the existing virtual void update(float) declaration. Requires Sammi-Husky/BrawlHeaders#66: init only matches with gfCamera::TransformFlag's bitfields declared over u16, so that the flag accesses are halfword-wide. Verified: `ninja` reports 127 files OK. Co-Authored-By: Claude Opus 5 --- config/RSBE01_02/symbols.txt | 2 +- configure.py | 2 +- src/sora/cm/cm_controller_menu_fixed.cpp | 40 ++++++++++++++++-------- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/config/RSBE01_02/symbols.txt b/config/RSBE01_02/symbols.txt index fedea1b01..062007555 100644 --- a/config/RSBE01_02/symbols.txt +++ b/config/RSBE01_02/symbols.txt @@ -4281,7 +4281,7 @@ fn_800A6668 = .text:0x800A6668; // type:function size:0x258 __ct__21cmMenuFixedControllerFv = .text:0x800A68C0; // type:function size:0x44 storeDefault__21cmMenuFixedControllerFv = .text:0x800A6904; // type:function size:0x3C init__21cmMenuFixedControllerFv = .text:0x800A6940; // type:function size:0x6C -fn_800A69AC = .text:0x800A69AC; // type:function size:0xCC +update__21cmMenuFixedControllerFf = .text:0x800A69AC; // type:function size:0xCC fn_800A6A78 = .text:0x800A6A78; // type:function size:0x1C fn_800A6A94 = .text:0x800A6A94; // type:function size:0x40 fn_800A6AD4 = .text:0x800A6AD4; // type:function size:0xA4 diff --git a/configure.py b/configure.py index d44984a5b..3bfb6e6c9 100755 --- a/configure.py +++ b/configure.py @@ -334,7 +334,7 @@ def MatchingFor(*versions): Object(Matching, "sora/mv/mv_THPAudioDecode.cpp"), Object(Matching, "sora/mv/mv_THPRead.cpp"), Object(Matching, "sora/cm/cm_controller_default.cpp", extra_cflags=["-RTTI off"]), - Object(NonMatching, "sora/cm/cm_controller_menu_fixed.cpp"), + Object(Matching, "sora/cm/cm_controller_menu_fixed.cpp"), Object(Matching, "sora/cm/cm_controller_melee_fixed.cpp"), Object(Matching, "sora/cm/cm_stage_param.cpp"), Object(NonMatching, "sora/ty/ty_fig_listmng.cpp"), diff --git a/src/sora/cm/cm_controller_menu_fixed.cpp b/src/sora/cm/cm_controller_menu_fixed.cpp index e2d3f9c93..04d6cae5b 100644 --- a/src/sora/cm/cm_controller_menu_fixed.cpp +++ b/src/sora/cm/cm_controller_menu_fixed.cpp @@ -34,19 +34,33 @@ void cmMenuFixedController::storeDefault() { unk8 = true; } -// NONMATCHING void cmMenuFixedController::init() { - m_cameraManager->m_cameras[0].unkCC = unkC; - m_cameraManager->m_cameras[0].unkFA.m_flag7 = true; - m_cameraManager->m_cameras[0].m_targetPos.m_x = unk10.m_x; - m_cameraManager->m_cameras[0].m_targetPos.m_y = unk10.m_y; - m_cameraManager->m_cameras[0].m_targetPos.m_z = unk10.m_z; - m_cameraManager->m_cameras[0].unkFA.m_flag1 = true; - m_cameraManager->m_cameras[0].unkD0 = unk1C; - m_cameraManager->m_cameras[0].m_rot.m_x = 0.0f; - m_cameraManager->m_cameras[0].m_rot.m_y = 0.0f; - m_cameraManager->m_cameras[0].m_rot.m_z = 0.0f; - m_cameraManager->m_cameras[0].unkFA.m_flag2 = true; + gfCamera& cam = m_cameraManager->m_cameras[0]; + cam.unkCC = unkC; + // Setting m_flag7 through the mask keeps the original read live, which is + // what lets the later two writes chain off it. + u16 flags = cam.unkFA.m_mask; + cam.unkFA.m_mask = flags | 0x80; + cam.m_targetPos.m_x = unk10.m_x; + cam.m_targetPos.m_y = unk10.m_y; + cam.m_targetPos.m_z = unk10.m_z; + cam.unkFA.m_flag1 = true; + cam.unkD0 = unk1C; + Vec2f xy(0.0f, 0.0f); + cam.m_rot.m_x = xy.m_x; + cam.m_rot.m_y = xy.m_y; + cam.m_rot.m_z = 0.0f; + cam.unkFA.m_rotate = true; } -// TODO: cmMenuFixedController::update +extern "C" void fn_80018778(gfCameraManager*); + +void cmMenuFixedController::update(float) { + gfCameraManager* mgr = m_cameraManager; + if (!unk8) { + storeDefault(); + } + init(); + mgr->m_cameras[0].m_transformFlag.m_mask = 0xE1; + fn_80018778(mgr); +}