From f130c126e67efea8c57f8a4ea5f55369ba8a49a9 Mon Sep 17 00:00:00 2001 From: maybegreat48 <96936658+maybegreat48@users.noreply.github.com> Date: Fri, 11 Apr 2025 14:35:15 -0400 Subject: [PATCH] general fixes --- src/game/backend/SavedPlayers.cpp | 8 +- src/game/backend/SavedPlayers.hpp | 2 +- .../features/recovery/ForceLaunchHeist.cpp | 20 +++++ .../features/recovery/PlayAllMissionsSolo.cpp | 82 ++++++++++++++++--- src/game/frontend/submenus/Debug.cpp | 2 + src/game/frontend/submenus/Debug/Misc.cpp | 29 +++++++ src/game/frontend/submenus/Debug/Misc.hpp | 8 ++ src/game/frontend/submenus/Recovery.cpp | 3 +- src/game/hooks/Network/HandleNetGameEvent.cpp | 15 +++- src/types/network/netGameEvent.cpp | 2 +- src/types/script/ScriptEvent.hpp | 14 ++++ 11 files changed, 167 insertions(+), 18 deletions(-) create mode 100644 src/game/features/recovery/ForceLaunchHeist.cpp create mode 100644 src/game/frontend/submenus/Debug/Misc.cpp create mode 100644 src/game/frontend/submenus/Debug/Misc.hpp diff --git a/src/game/backend/SavedPlayers.cpp b/src/game/backend/SavedPlayers.cpp index fae47e7..391c5cc 100644 --- a/src/game/backend/SavedPlayers.cpp +++ b/src/game/backend/SavedPlayers.cpp @@ -55,7 +55,6 @@ namespace YimMenu SavedPlayers::~SavedPlayers() { - m_FetchPlayerInfoMutex.unlock(); } void SavedPlayers::UpdateFetchedData(SavedPlayerData& saved_data, const FetchedPlayerData& fetched_data) @@ -141,7 +140,8 @@ namespace YimMenu void SavedPlayers::FetchPlayerInfoImpl(bool tracked_only) { - std::lock_guard guard(m_FetchPlayerInfoMutex); + if (m_FetchingPlayerInfo) + return; if (!Pointers.GetPresenceAttributes) { @@ -149,6 +149,8 @@ namespace YimMenu return; } + m_FetchingPlayerInfo = true; + std::vector> player_buckets; int current_bucket_idx = 0; @@ -241,6 +243,8 @@ namespace YimMenu // failed, do something here? LOG(WARNING) << "Failed to start get presence attributes task"; } + + m_FetchingPlayerInfo = false; } } diff --git a/src/game/backend/SavedPlayers.hpp b/src/game/backend/SavedPlayers.hpp index 020eefe..bbf02f9 100644 --- a/src/game/backend/SavedPlayers.hpp +++ b/src/game/backend/SavedPlayers.hpp @@ -10,7 +10,7 @@ namespace YimMenu static constexpr auto AUTO_REFRESH_TIME = 3min; std::unordered_map m_SavedPlayers; - std::mutex m_FetchPlayerInfoMutex; + bool m_FetchingPlayerInfo; std::filesystem::path m_PlayersFile; std::chrono::system_clock::time_point m_LastPlayerInfoFetch; diff --git a/src/game/features/recovery/ForceLaunchHeist.cpp b/src/game/features/recovery/ForceLaunchHeist.cpp new file mode 100644 index 0000000..b0a82bf --- /dev/null +++ b/src/game/features/recovery/ForceLaunchHeist.cpp @@ -0,0 +1,20 @@ +#include "core/commands/Command.hpp" +#include "types/script/ScriptEvent.hpp" + +namespace YimMenu::Features +{ + class ForceLaunchHeist : public Command + { + using Command::Command; + + virtual void OnCall() override + { + SCRIPT_EVENT_COMMAND event; + event.Command = SCRIPT_EVENT_COMMAND::eCommand::LaunchHeist; + event.SetAllPlayers(); + event.Send(); + } + }; + + static ForceLaunchHeist _ForceLaunchHeist{"forcelaunchheist", "Force Launch Heist", "Forces the heist to launch from the setup screen"}; +} \ No newline at end of file diff --git a/src/game/features/recovery/PlayAllMissionsSolo.cpp b/src/game/features/recovery/PlayAllMissionsSolo.cpp index 436d7c4..f092f7e 100644 --- a/src/game/features/recovery/PlayAllMissionsSolo.cpp +++ b/src/game/features/recovery/PlayAllMissionsSolo.cpp @@ -1,11 +1,12 @@ -#include "core/commands/BoolCommand.hpp" +#include "core/commands/LoopedCommand.hpp" #include "game/backend/ScriptPatches.hpp" +#include "game/gta/Natives.hpp" namespace YimMenu::Features { - class PlayAllMissionsSolo : public BoolCommand + class PlayAllMissionsSolo : public LoopedCommand { - using BoolCommand::BoolCommand; + using LoopedCommand::LoopedCommand; ScriptPatch m_CanLaunchJobPatch{}; ScriptPatch m_MissionRequestPatch1{}; // TODO: do we need these patches? @@ -19,16 +20,21 @@ namespace YimMenu::Features ScriptPatch m_ShouldFailMissionPatch1{}; // god I hate this function std::vector m_ShouldFailMissionPatches{}; ScriptPatch m_ShouldFailMissionPatch2{}; - ScriptPatch m_EnsureMissionPassedPatch{}; + ScriptPatch m_ShouldFailMissionPatch3{}; + ScriptPatch m_NotEnoughTeamsPatch{}; + ScriptPatch m_IsTeamValidPatch{}; // TODO: probably has many unintended side effects + ScriptPatch m_EnsureMissionPassedPatch{}; + ScriptPatch m_ProcessPhoneHackingPatch{}; virtual void OnEnable() override { if (!m_CanLaunchJobPatch) { - m_CanLaunchJobPatch = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 05 0C 00 00 71", 5, {0x72, 0x2E, 0x05, 0x01}); + m_CanLaunchJobPatch = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 05 0C 00 00 71", 5, {0x72, 0x2E, 0x05, 0x01}); // the main patch that bypasses the not enough players alert } m_CanLaunchJobPatch->Enable(); + // these patches allow the mission request system to launch fm_mission_controller with insufficent players if (!m_MissionRequestPatch1) { m_MissionRequestPatch1 = ScriptPatches::AddPatch("freemode"_J, "38 00 72 5D ? ? ? 38 00 5D ? ? ? 2E 02 00 38 00 38 01", 0, std::vector(14, 0x0)); @@ -55,7 +61,7 @@ namespace YimMenu::Features if (!m_PlayerCountWatchdogPatch1) { - m_PlayerCountWatchdogPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 02 09 00 00 25 A4", 5, {0x71, 0x2E, 0x02, 0x01}); + m_PlayerCountWatchdogPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 02 09 00 00 25 A4", 5, {0x71, 0x2E, 0x02, 0x01}); // instant kick if this check fails } m_PlayerCountWatchdogPatch1->Enable(); @@ -67,10 +73,10 @@ namespace YimMenu::Features if (!m_HeistTeamsPatch1) { - m_HeistTeamsPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "47 ? ? 5B 7B 00 38 04", 0, {0x2B, 0x2B, 0x00, 0x55}); + m_HeistTeamsPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "47 ? ? 5B 7B 00 38 04", 0, {0x2B, 0x2B, 0x00, 0x55}); // TODO: doesn't work for doomsday heist } m_HeistTeamsPatch1->Enable(); - + if (!m_HeistTeamsPatch2) { m_HeistTeamsPatch2 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 01 05 00 00 25 5D", 5, {0x72, 0x2E, 0x01, 0x01}); @@ -86,6 +92,7 @@ namespace YimMenu::Features if (m_ShouldFailMissionPatches.empty()) { // TODO: this is a very bad idea that can break anytime + // for some reason, Rockstar thought it's a good idea to copy-paste the same failure check in four different branches, "just in case" for (int i = 0; i < 4; i++) m_ShouldFailMissionPatches.push_back(ScriptPatches::AddPatch("fm_mission_controller"_J, "38 02 5D ? ? ? 71 09 2A 56 07 00 71 5D ? ? ? 06 1F 56", 0, {0x71, 0x00, 0x00, 0x00, 0x00, 0x00})); } @@ -95,15 +102,50 @@ namespace YimMenu::Features if (!m_ShouldFailMissionPatch2) { - m_ShouldFailMissionPatch2 = ScriptPatches::AddPatch("fm_mission_controller"_J, "56 07 00 38 02 5D ? ? ? 20 56 BC 01", 0, {0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x71}); + m_ShouldFailMissionPatch2 = ScriptPatches::AddPatch("fm_mission_controller"_J, "56 07 00 38 02 5D ? ? ? 20 56 BC 01", 0, {0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x71}); // some heist check, more or less same as above } m_ShouldFailMissionPatch2->Enable(); + + if (!m_ShouldFailMissionPatch3) + { + m_ShouldFailMissionPatch3 = ScriptPatches::AddPatch("fm_mission_controller"_J, "50 ? ? 78 82 06 1F 56 2E 01", 0, {0x00, 0x00, 0x00, 0x00, 0x72}); + } + m_ShouldFailMissionPatch3->Enable(); + + if (!m_NotEnoughTeamsPatch) + { + m_NotEnoughTeamsPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "2D 00 02 00 00 61 ? ? ? 47 ? ? 72 57 04 00 72 2E 00 01 4F", 5, {0x71, 0x2E, 0x00, 0x01}); + } + m_NotEnoughTeamsPatch->Enable(); + + if (!m_IsTeamValidPatch) + { + m_IsTeamValidPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "2D 01 03 00 00 38 00 71 57 1D 00", 5, {0x72, 0x2E, 0x01, 0x01}); + } + m_IsTeamValidPatch->Enable(); if (!m_EnsureMissionPassedPatch) { - m_EnsureMissionPassedPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "55 C8 FF 61", 3, {0x2E, 0x00, 0x00}); + m_EnsureMissionPassedPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "55 C8 FF 61", 3, {0x2E, 0x00, 0x00}); // the game does one final check to ensure all players exist before the mission is passed } m_EnsureMissionPassedPatch->Enable(); + + if (!m_ProcessPhoneHackingPatch) + { + m_ProcessPhoneHackingPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "58 13 00 38 00 4F ? ? 48", 0, {0x2B, 0x00, 0x00}); + } + } + + virtual void OnTick() override + { + if (m_ProcessPhoneHackingPatch) + { + // the patch transfers the hacking minigame from the passenger to the driver, so we only want it applied when we're playing solo + if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("fm_mission_controller"_J) && NETWORK::NETWORK_GET_TOTAL_NUM_PLAYERS() == 1) + m_ProcessPhoneHackingPatch->Enable(); + else + m_ProcessPhoneHackingPatch->Disable(); + } } virtual void OnDisable() override @@ -166,10 +208,30 @@ namespace YimMenu::Features m_ShouldFailMissionPatch2->Disable(); } + if (m_ShouldFailMissionPatch3) + { + m_ShouldFailMissionPatch3->Disable(); + } + + if (m_NotEnoughTeamsPatch) + { + m_NotEnoughTeamsPatch->Disable(); + } + + if (m_IsTeamValidPatch) + { + m_IsTeamValidPatch->Disable(); + } + if (m_EnsureMissionPassedPatch) { m_EnsureMissionPassedPatch->Disable(); } + + if (m_ProcessPhoneHackingPatch) + { + m_ProcessPhoneHackingPatch->Disable(); + } } }; diff --git a/src/game/frontend/submenus/Debug.cpp b/src/game/frontend/submenus/Debug.cpp index 1e5713b..2f325d8 100644 --- a/src/game/frontend/submenus/Debug.cpp +++ b/src/game/frontend/submenus/Debug.cpp @@ -3,6 +3,7 @@ #include "Debug/Globals.hpp" #include "Debug/Locals.hpp" //#include "Debug/Scripts.hpp" +#include "Debug/Misc.hpp" #include "game/frontend/items/Items.hpp" @@ -15,5 +16,6 @@ namespace YimMenu::Submenus { AddCategory(BuildGlobalsMenu()); AddCategory(BuildLocalsMenu()); + AddCategory(BuildMiscMenu()); } } \ No newline at end of file diff --git a/src/game/frontend/submenus/Debug/Misc.cpp b/src/game/frontend/submenus/Debug/Misc.cpp new file mode 100644 index 0000000..9a1c118 --- /dev/null +++ b/src/game/frontend/submenus/Debug/Misc.cpp @@ -0,0 +1,29 @@ +#include "DrawVariable.hpp" +#include "Locals.hpp" +#include "core/filemgr/FileMgr.hpp" +#include "game/backend/Self.hpp" +#include "game/pointers/Pointers.hpp" +#include "core/backend/FiberPool.hpp" +#include "game/gta/ScriptFunction.hpp" + +namespace YimMenu::Submenus +{ + std::shared_ptr BuildMiscMenu() + { + auto misc = std::make_unique("Misc"); + + misc->AddItem(std::make_unique([] { + static int team; + ImGui::InputInt("Team", &team); + if (ImGui::Button("fm_mission_controller DoTeamSwap")) + { + FiberPool::Push([] { + static ScriptFunction DoTeamSwap("DoTeamSwap", "fm_mission_controller"_J, "2D 02 04 00 00 38 00 50"); + DoTeamSwap.Call(team, true); + }); + } + })); + + return misc; + } +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Debug/Misc.hpp b/src/game/frontend/submenus/Debug/Misc.hpp new file mode 100644 index 0000000..22316a2 --- /dev/null +++ b/src/game/frontend/submenus/Debug/Misc.hpp @@ -0,0 +1,8 @@ +#pragma once +#include "core/frontend/manager/Category.hpp" +#include "game/frontend/items/Items.hpp" + +namespace YimMenu::Submenus +{ + std::shared_ptr BuildMiscMenu(); +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Recovery.cpp b/src/game/frontend/submenus/Recovery.cpp index 9e3ee23..481b90e 100644 --- a/src/game/frontend/submenus/Recovery.cpp +++ b/src/game/frontend/submenus/Recovery.cpp @@ -27,7 +27,8 @@ namespace YimMenu::Submenus } })); - generalGroup->AddItem(std::make_shared("playallmissionssolo"_J)); + generalGroup->AddItem(std::make_shared("playallmissionssolo"_J)); + generalGroup->AddItem(std::make_shared("forcelaunchheist"_J)); cayoPericoGroup->AddItem(std::make_shared("skipcayosetup"_J)); cayoPericoGroup->AddItem(std::make_shared("skipcayocooldown"_J)); diff --git a/src/game/hooks/Network/HandleNetGameEvent.cpp b/src/game/hooks/Network/HandleNetGameEvent.cpp index 215f236..b1a3c80 100644 --- a/src/game/hooks/Network/HandleNetGameEvent.cpp +++ b/src/game/hooks/Network/HandleNetGameEvent.cpp @@ -36,12 +36,14 @@ namespace YimMenu::Hooks if (event.m_CameraShake > 0.0f && dist <= 30.0f) { // Camera shake + LOGF(WARNING, "Blocked EXPLOSION_EVENT from {} since m_CameraShake > 0.0f", player.GetName()); return true; } if (event.m_DamageScale > 0.0f && dist <= 10.0f) { // Ragdoll + LOGF(WARNING, "Blocked EXPLOSION_EVENT from {} since m_DamageScale > 0.0f", player.GetName()); return true; } } @@ -134,8 +136,7 @@ namespace YimMenu::Hooks if (event.m_WeaponType == "WEAPON_TRANQUILIZER"_J) { - LOG(INFO) << "blocked this thing from " << player.GetName(); - //player.AddDetection(); + LOGF(WARNING, "Blocked WEAPON_DAMAGE_EVENT from {} with m_WeaponType == WEAPON_TRANQUILIZER", player.GetName()); return false; } @@ -163,6 +164,7 @@ namespace YimMenu::Hooks if (self_veh && self_veh.GetNetworkObjectId() == veh_id && sender_veh && sender_veh.GetNetworkObjectId() != veh_id) { // Vehicle takeover + LOGF(WARNING, "Blocked CHANGE_RADIO_STATION_EVENT on our local vehicle from {}", player.GetName()); return false; } @@ -171,7 +173,7 @@ namespace YimMenu::Hooks case rage::netGameEvent::Type::DOOR_BREAK_EVENT: { // never used for legitimate reasons - + LOGF(WARNING, "Blocked DOOR_BREAK_EVENT from {}", player.GetName()); return false; } case rage::netGameEvent::Type::SCRIPTED_GAME_EVENT: @@ -202,12 +204,14 @@ namespace YimMenu::Hooks if (pop_group == 0 && (percentage == 0 || percentage == 103)) { // pop group override crash + LOGF(WARNING, "Blocked SCRIPT_WORLD_STATE_EVENT of type PopGroupOverride with invalid params from {}", player.GetName()); return false; } } else if (type == CScriptWorldStateEvent::Type::PopMultiplierArea && !NETWORK::NETWORK_IS_ACTIVITY_SESSION()) { // Stop traffic + LOGF(WARNING, "Blocked SCRIPT_WORLD_STATE_EVENT of type PopMultiplierArea from {}", player.GetName()); return false; } @@ -227,12 +231,14 @@ namespace YimMenu::Hooks if (action >= 15 && action <= 18) { // vehicle temp action crash + LOGF(WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SettingOfTaskVehicleTempAction with invalid params from {}", player.GetName()); return false; } if (Self::GetPed().GetNetworkObjectId() == entity) { // Ped takeover + LOGF(WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SettingOfTaskVehicleTempAction on our local ped from {}", player.GetName()); return false; } @@ -240,6 +246,7 @@ namespace YimMenu::Hooks if (self_veh && self_veh.GetNetworkObjectId() == veh_id) { // Vehicle takeover + LOGF(WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SettingOfTaskVehicleTempAction on our local vehicle from {}", player.GetName()); return false; } } @@ -311,6 +318,7 @@ namespace YimMenu::Hooks if (Self::GetPed().GetVehicleObjectId() == event.m_VehicleId && !Self::GetVehicle().IsRemote()) { // Vehicle takeover + LOGF(WARNING, "Blocked ACTIVATE_VEHICLE_SPECIAL_ABILITY_EVENT on our local vehicle from {}", player.GetName()); return false; } @@ -324,6 +332,7 @@ namespace YimMenu::Hooks if (Self::GetPed().GetNetworkObjectId() == event.m_PedToRagdoll) { // is sometimes used legit, beware + LOGF(WARNING, "Blocked RAGDOLL_REQUEST_EVENT on our local ped from {}", player.GetName()); return false; } diff --git a/src/types/network/netGameEvent.cpp b/src/types/network/netGameEvent.cpp index a2ac3f9..f5773a2 100644 --- a/src/types/network/netGameEvent.cpp +++ b/src/types/network/netGameEvent.cpp @@ -9,7 +9,7 @@ bool CScriptedGameEvent::Deserialize(rage::datBitBuffer& buffer) if (m_ArgsSize > sizeof(m_Args)) return false; - buffer.ReadArray(m_Args, 8 * m_ArgsSize); + buffer.ReadArrayBytes(m_Args, m_ArgsSize); return true; } diff --git a/src/types/script/ScriptEvent.hpp b/src/types/script/ScriptEvent.hpp index b888c18..97b130a 100644 --- a/src/types/script/ScriptEvent.hpp +++ b/src/types/script/ScriptEvent.hpp @@ -64,6 +64,7 @@ enum class ScriptEventIndex TSECommand = 800157557, // CnCTG_IN_BF TSECommandRotateCam = 225624744, // != 29) && f TSECommandSound = 385726943, + TSECommandLaunchHeist = 1733306780, // HEIST_NOTE_3 in fmmc_launcher Notification = -642704387, NotificationMoneyBanked = 94410750, // TICK_TC_BANK @@ -182,4 +183,17 @@ struct SCRIPT_EVENT_REQUEST_RANDOM_EVENT : public SCRIPT_EVENT }; static_assert(sizeof(SCRIPT_EVENT_REQUEST_RANDOM_EVENT) == 7 * 8); +struct SCRIPT_EVENT_COMMAND : public SCRIPT_EVENT +{ + enum class eCommand + { + LaunchHeist = 1733306780 + }; + + REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_COMMAND, TSECommand); + + eCommand Command; + SCR_INT RandomNumber; // it's fine if we don't set this +}; + #undef REGISTER_SCRIPT_EVENT \ No newline at end of file