mirror of
https://github.com/hedge-dev/UnleashedRecomp.git
synced 2025-12-18 14:02:34 +00:00
Implemented free camera (WIP)
Patch "Enable Free Camera" id "EnableFreeCamera" in "Debug" by "Hyper" does /* Enables the replay mode camera with controls similar to Generations Free Camera. Controls: - Start - toggle pause (use after enabling free camera). - Back (Select) - toggle free camera. - Left Stick - move camera. - Left Stick Button (L3) - teleport player to camera. - Right Stick - rotate camera. - Right Stick Button (R3) - teleport camera to player. - Left Bumper (L1) - move camera down. - Right Bumper (R1) - move camera up. - Left Trigger (L2) - move camera at slow speed. - Right Trigger (R2) - move camera at fast speed. - Left Trigger (L2) + Right Trigger (R2) - move camera at moderate speed. - A (Cross) - reset camera speed. - B (Circle) - decrease base camera speed. - X (Square) - increase base camera speed. - Y (Triangle) - reset field of view. - D-Pad Up - increase field of view. - D-Pad Down - decrease field of view. - D-Pad Left - toggle camera position lock. - D-Pad Right - toggle depth of field. */
This commit is contained in:
parent
df8234ab3b
commit
0aa1a256dd
11 changed files with 306 additions and 6 deletions
|
|
@ -137,6 +137,7 @@ set(UNLEASHED_RECOMP_PATCHES_CXX_SOURCES
|
|||
"patches/CTitleStateIntro_patches.cpp"
|
||||
"patches/CTitleStateMenu_patches.cpp"
|
||||
"patches/fps_patches.cpp"
|
||||
"patches/free_camera_patches.cpp"
|
||||
"patches/frontend_listener.cpp"
|
||||
"patches/input_patches.cpp"
|
||||
"patches/inspire_patches.cpp"
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@
|
|||
#include "SWA/Player/Character/EvilSonic/EvilSonic.h"
|
||||
#include "SWA/Player/Character/EvilSonic/EvilSonicContext.h"
|
||||
#include "SWA/Player/Character/EvilSonic/Hud/EvilHudGuide.h"
|
||||
#include "SWA/Replay/Camera/ReplayFreeCamera.h"
|
||||
#include "SWA/Sequence/Unit/SequenceUnitBase.h"
|
||||
#include "SWA/Sequence/Unit/SequenceUnitPlayMovie.h"
|
||||
#include "SWA/Sequence/Utility/SequencePlayMovieWrapper.h"
|
||||
|
|
|
|||
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
namespace SWA
|
||||
{
|
||||
class CCameraController : public Hedgehog::Universe::CStateMachineBase::CStateBase
|
||||
class CCameraController
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0x04);
|
||||
SWA_INSERT_PADDING(0x64);
|
||||
be<float> m_FieldOfView;
|
||||
SWA_INSERT_PADDING(0x68);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -33,6 +33,9 @@ namespace SWA
|
|||
// ms_IsRenderDebugPositionDraw: デバッグ位置描画
|
||||
static inline bool* ms_IsRenderDebugPositionDraw;
|
||||
|
||||
// N/A
|
||||
static inline bool* ms_IsRenderDepthOfField;
|
||||
|
||||
// ms_IsRenderGameMainHud: ゲームメインHUD 描画
|
||||
static inline bool* ms_IsRenderGameMainHud;
|
||||
|
||||
|
|
@ -65,6 +68,7 @@ namespace SWA
|
|||
ms_IsRenderDebugDraw = (bool*)MmGetHostAddress(0x8328BB23);
|
||||
ms_IsRenderDebugDrawText = (bool*)MmGetHostAddress(0x8328BB25);
|
||||
ms_IsRenderDebugPositionDraw = (bool*)MmGetHostAddress(0x8328BB24);
|
||||
ms_IsRenderDepthOfField = (bool*)MmGetHostAddress(0x83302720);
|
||||
ms_IsRenderGameMainHud = (bool*)MmGetHostAddress(0x8328BB27);
|
||||
ms_IsRenderHud = (bool*)MmGetHostAddress(0x8328BB26);
|
||||
ms_IsRenderHudPause = (bool*)MmGetHostAddress(0x8328BB28);
|
||||
|
|
|
|||
16
UnleashedRecomp/api/SWA/Replay/Camera/ReplayFreeCamera.h
Normal file
16
UnleashedRecomp/api/SWA/Replay/Camera/ReplayFreeCamera.h
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#pragma once
|
||||
|
||||
#include <SWA.inl>
|
||||
#include "SWA/Camera/CameraController.h"
|
||||
|
||||
namespace SWA
|
||||
{
|
||||
class CReplayFreeCamera : public CCameraController
|
||||
{
|
||||
public:
|
||||
SWA_INSERT_PADDING(0x90);
|
||||
be<float> m_Speed;
|
||||
};
|
||||
|
||||
SWA_ASSERT_OFFSETOF(CReplayFreeCamera, m_Speed, 0x160);
|
||||
}
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
#include <kernel/function.h>
|
||||
#include <api/SWA.h>
|
||||
#include <patches/free_camera_patches.h>
|
||||
#include <ui/achievement_menu.h>
|
||||
#include <ui/button_guide.h>
|
||||
#include <ui/options_menu.h>
|
||||
|
|
@ -119,6 +120,9 @@ bool CHudPauseMiscInjectOptionsMidAsmHook(PPCRegister& pThis)
|
|||
PPC_FUNC_IMPL(__imp__sub_824B0930);
|
||||
PPC_FUNC(sub_824B0930)
|
||||
{
|
||||
if (FreeCameraPatches::s_isActive)
|
||||
return;
|
||||
|
||||
if (App::s_isLoading)
|
||||
{
|
||||
__imp__sub_824B0930(ctx, base);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
#include "camera_patches.h"
|
||||
#include <api/SWA.h>
|
||||
#include <gpu/video.h>
|
||||
#include <patches/aspect_ratio_patches.h>
|
||||
#include <patches/free_camera_patches.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
#include <gpu/video.h>
|
||||
#include "camera_patches.h"
|
||||
#include "aspect_ratio_patches.h"
|
||||
|
||||
void CameraAspectRatioMidAsmHook(PPCRegister& r30, PPCRegister& r31)
|
||||
{
|
||||
|
|
@ -35,7 +36,9 @@ void CameraFieldOfViewMidAsmHook(PPCRegister& r31, PPCRegister& f31)
|
|||
{
|
||||
auto camera = (SWA::CCamera*)g_memory.Translate(r31.u32);
|
||||
|
||||
f31.f64 = AdjustFieldOfView(f31.f64, camera->m_HorzAspectRatio);
|
||||
f31.f64 = FreeCameraPatches::s_isActive
|
||||
? FreeCameraPatches::s_fieldOfView
|
||||
: AdjustFieldOfView(f31.f64, camera->m_HorzAspectRatio);
|
||||
}
|
||||
|
||||
PPC_FUNC_IMPL(__imp__sub_824697B0);
|
||||
|
|
|
|||
222
UnleashedRecomp/patches/free_camera_patches.cpp
Normal file
222
UnleashedRecomp/patches/free_camera_patches.cpp
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
#include "free_camera_patches.h"
|
||||
#include <api/SWA.h>
|
||||
#include <os/logger.h>
|
||||
#include <ui/game_window.h>
|
||||
#include <user/config.h>
|
||||
#include <app.h>
|
||||
|
||||
#define DEGREES_TO_RADIANS(x) (float)(x / 180.0f * M_PI)
|
||||
#define RADIANS_TO_DEGREES(x) (float)(x / M_PI * 180.0f)
|
||||
|
||||
constexpr float DEFAULT_SPEED = 0.5f;
|
||||
constexpr float DEFAULT_FOV = 45.0f;
|
||||
constexpr float MOVE_SPEED_SLOW = 0.075f;
|
||||
constexpr float MOVE_SPEED_FAST = 8.0f;
|
||||
constexpr float MOVE_SPEED_MODIFIER_RATIO = 0.02f;
|
||||
constexpr float FOV_MODIFIER_RATIO = 1.0f;
|
||||
|
||||
static float g_baseSpeed = DEFAULT_SPEED;
|
||||
static float g_baseFOV = DEFAULT_FOV;
|
||||
|
||||
static bool g_isCameraLocked;
|
||||
static float g_speed;
|
||||
static float g_fov;
|
||||
|
||||
static void ResetParameters()
|
||||
{
|
||||
g_isCameraLocked = false;
|
||||
g_speed = g_baseSpeed = DEFAULT_SPEED;
|
||||
|
||||
*SWA::SGlobals::ms_IsRenderDepthOfField = true;
|
||||
FreeCameraPatches::s_fieldOfView = g_fov = g_baseFOV = DEFAULT_FOV;
|
||||
}
|
||||
|
||||
bool EnableFreeCameraMidAsmHook()
|
||||
{
|
||||
return Config::EnableFreeCamera;
|
||||
}
|
||||
|
||||
bool FreeCameraNullInputMidAsmHook()
|
||||
{
|
||||
return Config::EnableFreeCamera;
|
||||
}
|
||||
|
||||
// Original input: D-Pad Up
|
||||
bool FreeCameraActivationInputMidAsmHook(PPCRegister& r11, PPCRegister& r27, PPCRegister& r28)
|
||||
{
|
||||
if (!Config::EnableFreeCamera)
|
||||
return false;
|
||||
|
||||
static auto isChangedCameraMode = false;
|
||||
|
||||
if ((r11.u32 & SWA::eKeyState_Select) != 0)
|
||||
{
|
||||
if (++r28.u32 >= 2)
|
||||
r28.u32 = 0;
|
||||
|
||||
isChangedCameraMode = true;
|
||||
}
|
||||
|
||||
FreeCameraPatches::s_isActive = r28.u32 > 0;
|
||||
|
||||
if (isChangedCameraMode)
|
||||
{
|
||||
ResetParameters();
|
||||
|
||||
switch (r28.u32)
|
||||
{
|
||||
case 0:
|
||||
LOGN("[Free Camera] Disabled");
|
||||
break;
|
||||
|
||||
case 1:
|
||||
LOGN("[Free Camera] Enabled");
|
||||
break;
|
||||
}
|
||||
|
||||
isChangedCameraMode = false;
|
||||
|
||||
if (FreeCameraPatches::s_isActive && *SWA::SGlobals::ms_IsRenderHud)
|
||||
{
|
||||
*SWA::SGlobals::ms_IsRenderHud = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*SWA::SGlobals::ms_IsRenderHud = true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Original input: D-Pad Left
|
||||
void FreeCameraTeleportToPlayerInputMidAsmHook(PPCRegister& r4)
|
||||
{
|
||||
if (Config::EnableFreeCamera)
|
||||
r4.u32 = SWA::eKeyState_RightStick;
|
||||
}
|
||||
|
||||
// Original inputs: X (Square) / Y (Triangle)
|
||||
bool FreeCameraSpeedInputMidAsmHook(PPCRegister& r31)
|
||||
{
|
||||
if (!Config::EnableFreeCamera)
|
||||
return false;
|
||||
|
||||
auto pCamera = (SWA::CReplayFreeCamera*)g_memory.Translate(r31.u32);
|
||||
auto pInputState = SWA::CInputState::GetInstance();
|
||||
|
||||
if (!pInputState)
|
||||
return false;
|
||||
|
||||
auto& rPadState = pInputState->GetPadState();
|
||||
|
||||
auto factor = App::s_deltaTime / (1.0f / 60.0f);
|
||||
auto aspectRatio = (float)GameWindow::s_width / (float)GameWindow::s_height;
|
||||
|
||||
if (g_isCameraLocked)
|
||||
{
|
||||
g_speed = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
static auto isLeftTriggerSpeedModifier = false;
|
||||
static auto isRightTriggerSpeedModifier = false;
|
||||
|
||||
if (rPadState.IsDown(SWA::eKeyState_LeftTrigger))
|
||||
{
|
||||
g_speed = MOVE_SPEED_SLOW;
|
||||
isLeftTriggerSpeedModifier = true;
|
||||
}
|
||||
else if (isLeftTriggerSpeedModifier)
|
||||
{
|
||||
g_speed = g_baseSpeed;
|
||||
isLeftTriggerSpeedModifier = false;
|
||||
}
|
||||
|
||||
if (rPadState.IsDown(SWA::eKeyState_RightTrigger))
|
||||
{
|
||||
g_speed = MOVE_SPEED_FAST;
|
||||
isRightTriggerSpeedModifier = true;
|
||||
}
|
||||
else if (isRightTriggerSpeedModifier)
|
||||
{
|
||||
g_speed = g_baseSpeed;
|
||||
isRightTriggerSpeedModifier = false;
|
||||
}
|
||||
|
||||
if (isLeftTriggerSpeedModifier && isRightTriggerSpeedModifier)
|
||||
g_speed = MOVE_SPEED_FAST / 3;
|
||||
|
||||
if (rPadState.IsDown(SWA::eKeyState_A))
|
||||
g_speed = g_baseSpeed = DEFAULT_SPEED;
|
||||
|
||||
if (rPadState.IsDown(SWA::eKeyState_B))
|
||||
{
|
||||
g_baseSpeed -= MOVE_SPEED_MODIFIER_RATIO * factor;
|
||||
g_speed = g_baseSpeed;
|
||||
|
||||
LOGFN("[Free Camera] Speed: {}", g_speed);
|
||||
}
|
||||
|
||||
if (rPadState.IsDown(SWA::eKeyState_X))
|
||||
{
|
||||
g_baseSpeed += MOVE_SPEED_MODIFIER_RATIO * factor;
|
||||
g_speed = g_baseSpeed;
|
||||
|
||||
LOGFN("[Free Camera] Speed: {}", g_speed);
|
||||
}
|
||||
|
||||
auto isResetFOV = rPadState.IsDown(SWA::eKeyState_Y);
|
||||
auto isIncreaseFOV = rPadState.IsDown(SWA::eKeyState_DpadUp);
|
||||
auto isDecreaseFOV = rPadState.IsDown(SWA::eKeyState_DpadDown);
|
||||
|
||||
auto fovScaleFactor = 0.0f;
|
||||
|
||||
if (isIncreaseFOV)
|
||||
{
|
||||
fovScaleFactor = FOV_MODIFIER_RATIO;
|
||||
}
|
||||
else if (isDecreaseFOV)
|
||||
{
|
||||
fovScaleFactor = -FOV_MODIFIER_RATIO;
|
||||
}
|
||||
|
||||
g_speed = std::clamp(g_speed, 0.01f, 20.0f);
|
||||
g_fov = fmodf(isResetFOV ? DEFAULT_FOV : g_fov + fovScaleFactor * App::s_deltaTime * 60.0f, 180.0f);
|
||||
}
|
||||
|
||||
if (rPadState.IsTapped(SWA::eKeyState_DpadLeft))
|
||||
{
|
||||
g_isCameraLocked = !g_isCameraLocked;
|
||||
g_speed = g_baseSpeed;
|
||||
|
||||
if (g_isCameraLocked)
|
||||
{
|
||||
LOGN("[Free Camera] Locked");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGN("[Free Camera] Unlocked");
|
||||
}
|
||||
}
|
||||
|
||||
if (rPadState.IsTapped(SWA::eKeyState_DpadRight))
|
||||
{
|
||||
*SWA::SGlobals::ms_IsRenderDepthOfField = !*SWA::SGlobals::ms_IsRenderDepthOfField;
|
||||
|
||||
if (*SWA::SGlobals::ms_IsRenderDepthOfField)
|
||||
{
|
||||
LOGN("[Free Camera] Depth of Field ON");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGN("[Free Camera] Depth of Field OFF");
|
||||
}
|
||||
}
|
||||
|
||||
pCamera->m_Speed = g_speed;
|
||||
|
||||
FreeCameraPatches::s_fieldOfView = 2.0f * atan(tan(DEGREES_TO_RADIANS(g_fov / 2.0f) * (16.0f / 9.0f / std::min(aspectRatio, 16.0f / 9.0f))));
|
||||
|
||||
return true;
|
||||
}
|
||||
9
UnleashedRecomp/patches/free_camera_patches.h
Normal file
9
UnleashedRecomp/patches/free_camera_patches.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
class FreeCameraPatches
|
||||
{
|
||||
public:
|
||||
static inline bool s_isActive;
|
||||
|
||||
static inline float s_fieldOfView;
|
||||
};
|
||||
|
|
@ -80,6 +80,7 @@ CONFIG_DEFINE_HIDDEN("Codes", bool, DisableAutoSaveWarning, false);
|
|||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDLCIcon, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, DisableDWMRoundedCorners, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableEventCollisionDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableFreeCamera, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableGIMipLevelDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableObjectCollisionDebugView, false);
|
||||
CONFIG_DEFINE_HIDDEN("Codes", bool, EnableStageCollisionDebugView, false);
|
||||
|
|
|
|||
|
|
@ -1086,3 +1086,42 @@ registers = ["r4"]
|
|||
name = "AnimationDataMakeMidAsmHook"
|
||||
address = 0x82BB38E4
|
||||
registers = ["r31", "r29", "r28"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "EnableFreeCameraMidAsmHook"
|
||||
address = 0x825389F0
|
||||
jump_address_on_true = 0x825389F4
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "EnableFreeCameraMidAsmHook"
|
||||
address = 0x82538A18
|
||||
jump_address_on_true = 0x82538A1C
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "FreeCameraActivationInputMidAsmHook"
|
||||
address = 0x824569BC
|
||||
registers = ["r11", "r27", "r28"]
|
||||
jump_address_on_true = 0x824569D4
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "FreeCameraTeleportToPlayerInputMidAsmHook"
|
||||
address = 0x8245C21C
|
||||
registers = ["r4"]
|
||||
|
||||
[[midasm_hook]]
|
||||
name = "FreeCameraSpeedInputMidAsmHook"
|
||||
address = 0x8245C318
|
||||
registers = ["r31"]
|
||||
jump_address_on_true = 0x8245C38C
|
||||
|
||||
# Disable "change to free camera" input.
|
||||
[[midasm_hook]]
|
||||
name = "FreeCameraNullInputMidAsmHook"
|
||||
address = 0x8245BCE4
|
||||
jump_address_on_true = 0x8245BDB4
|
||||
|
||||
# Disable "change to pan camera" input.
|
||||
[[midasm_hook]]
|
||||
name = "FreeCameraNullInputMidAsmHook"
|
||||
address = 0x8245BDC4
|
||||
jump_address_on_true = 0x8245BEAC
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue