@@ -116,6 +116,9 @@ struct RoomscaleDebugBody {
116116 float groundProbeDown = 0 .75f ;
117117};
118118
119+ static RoomscaleDebugBody s_roomscaleResolveBody = {};
120+ static bool s_roomscaleShouldShowPhysicsDebug = false ;
121+
119122struct RoomscaleDebugPalette {
120123 uint32_t pathColor = 0 ;
121124 uint32_t pathSecondaryColor = 0 ;
@@ -181,14 +184,9 @@ static RoomscaleDebugPalette GetRoomscaleDebugPalette(bool isGroundProbe, bool i
181184 };
182185}
183186
184- static RoomscaleDebugBody GetRoomscaleDebugBody ( ) {
187+ static RoomscaleDebugBody BuildRoomscaleDebugBody ( const PlayerBase& player ) {
185188 RoomscaleDebugBody body = {};
186189
187- PlayerBase player = {};
188- if (!GameUtils::TryReadPlayerBase (player)) {
189- return body;
190- }
191-
192190 const glm::fvec3 localMin = player.aabb .min .getLE ();
193191 const glm::fvec3 localMax = player.aabb .max .getLE ();
194192 const glm::fvec3 localHalfExtents = (localMax - localMin) * 0 .5f ;
@@ -208,6 +206,11 @@ static RoomscaleDebugBody GetRoomscaleDebugBody() {
208206 return body;
209207}
210208
209+ static void CacheRoomscaleResolveContext (const PlayerBase& player) {
210+ s_roomscaleResolveBody = BuildRoomscaleDebugBody (player);
211+ s_roomscaleShouldShowPhysicsDebug = GetSettings ().ShouldShowRoomPhysics ();
212+ }
213+
211214static bool IsRoomscaleSweepPhase (RoomscaleResolvePhase phase) {
212215 return phase == RoomscaleResolvePhase_ForwardSweep || phase == RoomscaleResolvePhase_StepUpSweep || phase == RoomscaleResolvePhase_StepForwardSweep;
213216}
@@ -409,12 +412,11 @@ static bool IsRoomscaleGroundProbe(const RoomscaleRaycastScratch& scratch) {
409412 return scratch.queryType .getLE () != RoomscaleQueryType_Sweep;
410413}
411414
412- static void DrawRoomscaleDebugCast (const RoomscaleRaycastScratch& scratch, bool isProbeOnly) {
413- if (!GetSettings (). ShouldShowRoomPhysics () || IsRoomscaleGroundProbe (scratch)) {
415+ static void DrawRoomscaleDebugCast (const RoomscaleRaycastScratch& scratch, const RoomscaleDebugBody& body, bool isProbeOnly, bool shouldShowRoomPhysics ) {
416+ if (!shouldShowRoomPhysics || IsRoomscaleGroundProbe (scratch)) {
414417 return ;
415418 }
416419
417- const RoomscaleDebugBody body = GetRoomscaleDebugBody ();
418420 const RoomscaleDebugPalette palette = GetRoomscaleDebugPalette (false , isProbeOnly);
419421 const glm::fvec3 castFrom = scratch.castFrom .getLE ();
420422 const glm::fvec3 castTo = castFrom + scratch.castDelta .getLE ();
@@ -426,8 +428,8 @@ static void DrawRoomscaleDebugCast(const RoomscaleRaycastScratch& scratch, bool
426428 DrawRoomscaleDebugPositionMarker (castTo, 0 .04f , palette.pathSecondaryColor , true );
427429}
428430
429- static void DrawRoomscaleDebugCastResult (const RoomscaleRaycastScratch& scratch, bool isProbeOnly, bool hadHit, bool acceptedHit) {
430- if (!GetSettings (). ShouldShowRoomPhysics () ) {
431+ static void DrawRoomscaleDebugCastResult (const RoomscaleRaycastScratch& scratch, bool isProbeOnly, bool hadHit, bool acceptedHit, bool shouldShowRoomPhysics ) {
432+ if (!shouldShowRoomPhysics ) {
431433 return ;
432434 }
433435
@@ -505,6 +507,8 @@ static void ClearRoomscaleResolveState() {
505507 s_roomscaleState.remainingWorldDelta = glm::fvec3 (0 .0f );
506508 s_roomscaleState.attemptIndex = 0 ;
507509 s_roomscaleState.maxAttempts = 0 ;
510+ s_roomscaleResolveBody = {};
511+ s_roomscaleShouldShowPhysicsDebug = false ;
508512 ResetRoomscaleActiveStep ();
509513}
510514
@@ -625,7 +629,7 @@ static void PrimeRoomscaleBaseline(const glm::fvec3& headPos) {
625629 UpdateRoomscaleFade ();
626630}
627631
628- static bool ShouldDrivePlayerBodyWithVR (const glm::fvec3& currentHeadPos, PlayerBase& player) {
632+ static bool ShouldDrivePlayerBodyWithVR (const glm::fvec3& currentHeadPos, const PlayerBase& player) {
629633 if (!CemuHooks::IsFirstPerson ()) {
630634 SetRoomscaleBodyDriveMode (RoomscaleBodyDriveMode::DisabledNotFirstPerson);
631635 PrimeRoomscaleBaseline (currentHeadPos);
@@ -644,25 +648,12 @@ static bool ShouldDrivePlayerBodyWithVR(const glm::fvec3& currentHeadPos, Player
644648 return false ;
645649 }
646650
647- auto * renderer = VRManager::instance ().XR ->GetRenderer ();
648- if (renderer == nullptr ) {
649- SetRoomscaleBodyDriveMode (RoomscaleBodyDriveMode::DisabledNoRenderer);
650- PrimeRoomscaleBaseline (currentHeadPos);
651- return false ;
652- }
653-
654651 if (!VRManager::instance ().XR ->m_capabilities .supportsPositional ) {
655652 SetRoomscaleBodyDriveMode (RoomscaleBodyDriveMode::DisabledNoPositional);
656653 PrimeRoomscaleBaseline (currentHeadPos);
657654 return false ;
658655 }
659656
660- if (!GameUtils::TryReadPlayerBase (player)) {
661- SetRoomscaleBodyDriveMode (RoomscaleBodyDriveMode::DisabledNoPlayer);
662- PrimeRoomscaleBaseline (currentHeadPos);
663- return false ;
664- }
665-
666657 PlayerMoveBitFlags moveBits = player.moveBitFlags .getLE ();
667658 OpenXR::GameState gameState = VRManager::instance ().XR ->m_gameState .load ();
668659 bool shouldDisablePlayerBodyDrive = gameState.is_climbing || gameState.is_paragliding || gameState.is_riding_mount || HAS_FLAG (moveBits, PlayerMoveBitFlags::IS_SWIMMING_OR_CLIMBING | PlayerMoveBitFlags::IS_SWIMMING );
@@ -676,16 +667,11 @@ static bool ShouldDrivePlayerBodyWithVR(const glm::fvec3& currentHeadPos, Player
676667 return true ;
677668}
678669
679- static bool TryGetRoomscaleMoveDelta (uint32_t controller , glm::fvec3& currentHeadPos, glm::fvec3& roomDelta, glm::fvec3& worldDelta) {
670+ static bool TryGetRoomscaleMoveDelta (const PlayerBase& player , glm::fvec3& currentHeadPos, glm::fvec3& roomDelta, glm::fvec3& worldDelta) {
680671 currentHeadPos = glm::fvec3 (0 .0f );
681672 roomDelta = glm::fvec3 (0 .0f );
682673 worldDelta = glm::fvec3 (0 .0f );
683674
684- uint32_t playerController = 0 ;
685- if (!GameUtils::TryGetPlayerCharacterController (playerController) || controller != playerController) {
686- return false ;
687- }
688-
689675 std::optional<glm::fvec3> currentHeadPosOpt = TryGetCurrentHeadPos ();
690676 if (!currentHeadPosOpt.has_value ()) {
691677 ResetRoomscaleState ();
@@ -695,7 +681,6 @@ static bool TryGetRoomscaleMoveDelta(uint32_t controller, glm::fvec3& currentHea
695681 currentHeadPos = currentHeadPosOpt.value ();
696682 s_roomscaleState.trackedHeadPos = currentHeadPos;
697683
698- PlayerBase player = {};
699684 if (!ShouldDrivePlayerBodyWithVR (currentHeadPos, player)) {
700685 return false ;
701686 }
@@ -762,21 +747,23 @@ void CemuHooks::hook_BeginRoomscaleMovement(PPCInterpreter_t* hCPU) {
762747 hCPU->instructionPointer = hCPU->sprNew .LR ;
763748
764749 uint32_t controller = hCPU->gpr [3 ];
765- uint32_t scratchPtr = hCPU->gpr [4 ];
766- RoomscaleRaycastScratch scratch = {};
767- writeMemory (scratchPtr, &scratch);
768750 hCPU->gpr [3 ] = RoomscaleHookResult_Skip;
769751 ClearRoomscaleResolveState ();
770752
771- uint32_t playerController = 0 ;
772- if (!GameUtils::TryGetPlayerCharacterController (playerController) || controller != playerController) {
753+ PlayerBase player = {};
754+ if (!GameUtils::TryReadPlayerBase (player)) {
755+ return ;
756+ }
757+
758+ uint32_t playerController = GameUtils::ResolveActorPhysicsController (player);
759+ if (playerController == 0 || controller != playerController) {
773760 return ;
774761 }
775762
776763 glm::fvec3 currentHeadPos = {};
777764 glm::fvec3 roomDelta = {};
778765 glm::fvec3 worldDelta = {};
779- if (!TryGetRoomscaleMoveDelta (controller , currentHeadPos, roomDelta, worldDelta)) {
766+ if (!TryGetRoomscaleMoveDelta (player , currentHeadPos, roomDelta, worldDelta)) {
780767 glm::fvec3 residual = GetRoomscaleResidual ();
781768 glm::fvec3 residualWorldDelta = GetRoomscaleRoomToWorldRotation () * residual;
782769 residualWorldDelta.y = 0 .0f ;
@@ -796,6 +783,7 @@ void CemuHooks::hook_BeginRoomscaleMovement(PPCInterpreter_t* hCPU) {
796783 s_roomscaleState.maxAttempts = maxAttempts;
797784 s_roomscaleState.isResolving = true ;
798785 s_roomscaleState.isProbeOnly = true ;
786+ CacheRoomscaleResolveContext (player);
799787 hCPU->gpr [3 ] = RoomscaleHookResult_Cast;
800788 BetterVRProfiler::BeginSpan (BetterVRProfiler::Section::RoomscaleResolve);
801789 return ;
@@ -811,6 +799,7 @@ void CemuHooks::hook_BeginRoomscaleMovement(PPCInterpreter_t* hCPU) {
811799 s_roomscaleState.maxAttempts = maxAttempts;
812800 s_roomscaleState.isResolving = true ;
813801 s_roomscaleState.isProbeOnly = false ;
802+ CacheRoomscaleResolveContext (player);
814803 hCPU->gpr [3 ] = RoomscaleHookResult_Cast;
815804 BetterVRProfiler::BeginSpan (BetterVRProfiler::Section::RoomscaleResolve);
816805}
@@ -850,7 +839,7 @@ void CemuHooks::hook_PrepareRoomscaleRaycast(PPCInterpreter_t* hCPU) {
850839 return ;
851840 }
852841
853- const RoomscaleDebugBody body = GetRoomscaleDebugBody () ;
842+ const RoomscaleDebugBody& body = s_roomscaleResolveBody ;
854843 const glm::fvec3 currentWorldPos = scratch.currentPos .getLE ();
855844 const RoomscaleResolvePhase phase = s_roomscaleState.resolvePhase ;
856845
@@ -885,7 +874,7 @@ void CemuHooks::hook_PrepareRoomscaleRaycast(PPCInterpreter_t* hCPU) {
885874 PrepareRoomscaleSupportProbe (scratch, body, probeBodyPos);
886875 }
887876
888- DrawRoomscaleDebugCast (scratch, s_roomscaleState.isProbeOnly );
877+ DrawRoomscaleDebugCast (scratch, body, s_roomscaleState.isProbeOnly , s_roomscaleShouldShowPhysicsDebug );
889878 writeMemory (scratchPtr, &scratch);
890879 hCPU->gpr [3 ] = RoomscaleHookResult_Cast;
891880}
@@ -915,8 +904,6 @@ void CemuHooks::hook_ConsumeRoomscaleRaycast(PPCInterpreter_t* hCPU) {
915904 return ;
916905 }
917906
918- RoomscaleRaycastScratch scratch = {};
919- readMemory (scratchPtr, &scratch);
920907 uint32_t remainingSteps = s_roomscaleState.maxAttempts - s_roomscaleState.attemptIndex ;
921908 if (remainingSteps == 0 ) {
922909 ClearRoomscaleResolveState ();
@@ -925,7 +912,12 @@ void CemuHooks::hook_ConsumeRoomscaleRaycast(PPCInterpreter_t* hCPU) {
925912 }
926913
927914 if (IsRoomscaleSweepPhase (s_roomscaleState.resolvePhase )) {
928- DrawRoomscaleDebugCastResult (scratch, s_roomscaleState.isProbeOnly , hadHit, false );
915+ if (s_roomscaleShouldShowPhysicsDebug) {
916+ RoomscaleRaycastScratch scratch = {};
917+ readMemory (scratchPtr, &scratch);
918+ DrawRoomscaleDebugCastResult (scratch, s_roomscaleState.isProbeOnly , hadHit, false , s_roomscaleShouldShowPhysicsDebug);
919+ }
920+
929921 if (hadHit) {
930922 s_roomscaleState.currentStepBlockedByCollision = true ;
931923 if (s_roomscaleState.resolvePhase == RoomscaleResolvePhase_ForwardSweep) {
@@ -952,12 +944,14 @@ void CemuHooks::hook_ConsumeRoomscaleRaycast(PPCInterpreter_t* hCPU) {
952944 return ;
953945 }
954946
955- const RoomscaleDebugBody body = GetRoomscaleDebugBody ();
947+ RoomscaleRaycastScratch scratch = {};
948+ readMemory (scratchPtr, &scratch);
949+ const RoomscaleDebugBody& body = s_roomscaleResolveBody;
956950 const bool isStepProbe = s_roomscaleState.resolvePhase == RoomscaleResolvePhase_StepDownSupportProbe;
957951 const float maxGroundRise = isStepProbe ? (kRoomscaleStepUpHeight + kRoomscaleGroundSnapMaxRise ) : kRoomscaleGroundSnapMaxRise ;
958952 RoomscaleSupportState support = {};
959953 const bool hasSupport = hadHit && TryBuildRoomscaleSupportState (body, scratch.currentPos .getLE (), maxGroundRise, scratch, support);
960- DrawRoomscaleDebugCastResult (scratch, s_roomscaleState.isProbeOnly , hadHit, hasSupport);
954+ DrawRoomscaleDebugCastResult (scratch, s_roomscaleState.isProbeOnly , hadHit, hasSupport, s_roomscaleShouldShowPhysicsDebug );
961955
962956 if (!hasSupport) {
963957 if (!isStepProbe) {
0 commit comments