Add FreecamCheat

- Added ModMenuModule::FreecamCheat
- Added an option to toggle FreecamCheat in ModMenuModule::CameraMenu
This commit is contained in:
izawartka 2026-05-18 12:46:24 +02:00
parent 92cce963ec
commit 4a7a74d8f4
7 changed files with 190 additions and 1 deletions

View File

@ -637,6 +637,7 @@ echo Created $(ProjectDir)src\git.h with commit %GIT_HASH% (dirty=%GIT_DIRTY%)
<ClInclude Include="src\modules\modmenu\cheats\camera\clear-screen.h" />
<ClInclude Include="src\modules\modmenu\cheats\camera\disable-antialiasing.h" />
<ClInclude Include="src\modules\modmenu\cheats\camera\disable-culling.h" />
<ClInclude Include="src\modules\modmenu\cheats\camera\freecam.h" />
<ClInclude Include="src\modules\modmenu\cheats\camera\shadows-fix.h" />
<ClInclude Include="src\modules\modmenu\cheats\cheats.h" />
<ClInclude Include="src\modules\modmenu\cheats\cop-value.h" />
@ -880,6 +881,7 @@ echo Created $(ProjectDir)src\git.h with commit %GIT_HASH% (dirty=%GIT_DIRTY%)
<ClCompile Include="src\modules\modmenu\cheats\camera\clear-screen.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\camera\disable-antialiasing.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\camera\disable-culling.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\camera\freecam.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\camera\shadows-fix.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\cop-value.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\disable-steering-assist.cpp" />

View File

@ -171,6 +171,7 @@
<ClCompile Include="src\modules\modmenu\cheats\disable-steering-assist.cpp" />
<ClCompile Include="src\modules\modmenu\utils\get-selectable-car-lock-states.cpp" />
<ClCompile Include="src\modules\modmenu\quick-actions\toggle-steering-assist.cpp" />
<ClCompile Include="src\modules\modmenu\cheats\camera\freecam.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\converters\ammo.h" />
@ -458,6 +459,7 @@
<ClInclude Include="src\converters\car-lock-state.h" />
<ClInclude Include="src\modules\modmenu\utils\get-selectable-car-lock-states.h" />
<ClInclude Include="src\modules\modmenu\quick-actions\toggle-steering-assist.h" />
<ClInclude Include="src\modules\modmenu\cheats\camera\freecam.h" />
</ItemGroup>
<ItemGroup>
<None Include="GTA2.props" />

View File

@ -0,0 +1,101 @@
#include "freecam.h"
#include "../../../../events/game-tick.h"
#include "../../cheat-registry.h"
ModMenuModule::FreecamCheat* ModMenuModule::FreecamCheat::m_instance = nullptr;
ModMenuModule::FreecamCheat::FreecamCheat() : ModMenuModule::CheatBase("Cheat_Freecam_IsEnabled") {
assert(m_instance == nullptr && "FreecamCheat instance already exists");
m_instance = this;
}
ModMenuModule::FreecamCheat::~FreecamCheat()
{
m_instance = nullptr;
}
ModMenuModule::FreecamCheat* ModMenuModule::FreecamCheat::GetInstance()
{
assert(m_instance && "FreecamCheat not initialized!");
return m_instance;
}
void ModMenuModule::FreecamCheat::ResetAndDisable()
{
if (!IsEnabled()) {
spdlog::error("FreecamCheat::ResetAndDisable: Cheat is not enabled, cannot reset and disable");
return;
}
m_watchedControlState->RequestUpdate();
m_isDisabling = true;
}
void ModMenuModule::FreecamCheat::OnFirstEnable()
{
m_controlStateResolver = Core::MakeResolver(Game::Utils::GetPlayer, mem(&Game::Player::controlState));
}
void ModMenuModule::FreecamCheat::OnEnable()
{
Core::WatchManager* watchManager = Core::WatchManager::GetInstance();
/// TODO: check GameTickEvent?
m_watchedControlState = watchManager->Watch<GameTickEvent>(
m_controlStateResolver,
this,
&ModMenuModule::FreecamCheat::OnControlStateChange
);
AddEventListener<GameEndEvent>(&ModMenuModule::FreecamCheat::OnGameEnd);
}
void ModMenuModule::FreecamCheat::OnDisable()
{
RemoveEventListener<GameEndEvent>();
Core::WatchManager* watchManager = Core::WatchManager::GetInstance();
watchManager->Unwatch(m_watchedControlState);
m_watchedControlState = nullptr;
m_originalControlState = std::nullopt;
m_resetAndDisableDone = false;
m_isDisabling = false;
}
void ModMenuModule::FreecamCheat::OnControlStateChange(const std::optional<Game::PLAYER_CONTROL_STATE>& oldValue, const std::optional<Game::PLAYER_CONTROL_STATE>& newValue)
{
if (m_isDisabling) {
if (m_originalControlState.has_value()) {
m_watchedControlState->SetValueNow(m_originalControlState.value(), false);
}
m_resetAndDisableDone = true;
ResetAndDisableCheckAndProceed();
return;
}
m_originalControlState = newValue;
if (newValue.has_value()) {
m_watchedControlState->SetValueNow(Game::PLAYER_CONTROL_STATE_FREECAM, false);
}
}
void ModMenuModule::FreecamCheat::OnGameEnd(GameEndEvent& event)
{
if (m_isDisabling) {
SetEnabled(false);
}
}
void ModMenuModule::FreecamCheat::ResetAndDisableCheckAndProceed()
{
if (!m_isDisabling || !m_resetAndDisableDone) {
return;
}
SetEnabled(false);
}
REGISTER_CHEAT(FreecamCheat)

View File

@ -0,0 +1,34 @@
#pragma once
#include "../../common.h"
#include "../../../../events/game-end.h"
#include "../../cheat-base.h"
namespace ModMenuModule {
class FreecamCheat : public CheatBase, public Core::EventListenerSupport {
public:
FreecamCheat();
virtual ~FreecamCheat() override;
static FreecamCheat* GetInstance();
void ResetAndDisable();
private:
virtual void OnFirstEnable() override;
virtual void OnEnable() override;
virtual void OnDisable() override;
void OnControlStateChange(const std::optional<Game::PLAYER_CONTROL_STATE>& oldValue, const std::optional<Game::PLAYER_CONTROL_STATE>& newValue);
void OnGameEnd(GameEndEvent& event);
void ResetAndDisableCheckAndProceed();
static FreecamCheat* m_instance;
Core::Resolver<Game::PLAYER_CONTROL_STATE*> m_controlStateResolver = nullptr;
std::optional<Game::PLAYER_CONTROL_STATE> m_originalControlState = std::nullopt;
Core::Watched<Game::PLAYER_CONTROL_STATE>* m_watchedControlState = nullptr;
bool m_isDisabling = false;
bool m_resetAndDisableDone = false;
};
}

View File

@ -12,6 +12,7 @@
#include "camera/clear-screen.h"
#include "camera/disable-antialiasing.h"
#include "camera/disable-culling.h"
#include "camera/freecam.h"
#include "camera/camera-pos.h"
#include "camera/shadows-fix.h"
#include "player-appearance.h"

View File

@ -4,6 +4,8 @@
#include "camera-pos-menu.h"
#include "camera-rendering-menu.h"
#include "camera-advanced-menu.h"
#include "../cheats/camera/freecam.h"
#include "../../../converters/enabled-disabled.h"
#include "../root.h"
ModMenuModule::CameraMenu::CameraMenu()
@ -43,12 +45,38 @@ bool ModMenuModule::CameraMenu::Attach()
);
modeController->SetConverter<CameraEasyModeConverter>();
modeController->SetCustomSaveCallback(Utils::CameraEasyMode::SetCurrentMode);
// freecam
FreecamCheat* freecamCheat = FreecamCheat::GetInstance();
UiModule::Text* freecamText = m_menuController->CreateItem<UiModule::Text>(vertCont, L"", options.textSize);
m_freecamCheatController = m_menuController->CreateLatestItemController<UiModule::SelectController<bool>>(
freecamText,
UiModule::SelectOptionList<bool>{ false, true },
std::nullopt,
UiModule::SelectControllerOptions{ L"Freecam: #", L"#" }
);
m_freecamCheatController->SetConverter<EnabledDisabledConverter>();
m_freecamCheatController->SetSaveCallback([freecamCheat](bool newValue) {
if (newValue) freecamCheat->SetEnabled(true);
else freecamCheat->ResetAndDisable();
});
SetPreviousSelectedIndex();
return true;
}
void ModMenuModule::CameraMenu::OnShow()
{
AddEventListener<ModMenuModule::CheatStateEvent>(&CameraMenu::OnCheatStateChange);
UpdateCheatStates();
}
void ModMenuModule::CameraMenu::OnHide()
{
RemoveEventListener<ModMenuModule::CheatStateEvent>();
}
void ModMenuModule::CameraMenu::OnMenuAction(UiModule::Selectable* item, UiModule::MenuItemId id)
{
switch (id) {
@ -68,3 +96,15 @@ void ModMenuModule::CameraMenu::OnMenuAction(UiModule::Selectable* item, UiModul
break;
}
}
void ModMenuModule::CameraMenu::OnCheatStateChange(CheatStateEvent& event)
{
if (event.GetCheatType() == typeid(FreecamCheat)) {
m_freecamCheatController->SetValue(event.IsEnabled());
}
}
void ModMenuModule::CameraMenu::UpdateCheatStates()
{
m_freecamCheatController->SetValue(FreecamCheat::GetInstance()->IsEnabled());
}

View File

@ -1,9 +1,10 @@
#pragma once
#include "../common.h"
#include "../menu-base.h"
#include "../events/cheat-state.h"
namespace ModMenuModule {
class CameraMenu : public MenuBase {
class CameraMenu : public MenuBase, public Core::EventListenerSupport {
public:
CameraMenu();
virtual ~CameraMenu();
@ -11,6 +12,14 @@ namespace ModMenuModule {
private:
virtual bool Attach() override;
virtual void OnShow() override;
virtual void OnHide() override;
void OnMenuAction(UiModule::Selectable* item, UiModule::MenuItemId id) override;
void OnCheatStateChange(CheatStateEvent& event);
void UpdateCheatStates();
UiModule::SelectController<bool>* m_freecamCheatController = nullptr;
};
}