diff --git a/src/game/backend/NativeHooks.cpp b/src/game/backend/NativeHooks.cpp index 9002202..5f4b3ad 100644 --- a/src/game/backend/NativeHooks.cpp +++ b/src/game/backend/NativeHooks.cpp @@ -12,7 +12,7 @@ namespace YimMenu m_Program(program), m_Hook(std::make_unique("rage::scrProgram", program, 9)) { - m_Hook->Hook(6, ScrProgram_Dtor); + m_Hook->Hook(6, reinterpret_cast(&ScrProgram_Dtor)); m_Hook->Enable(); m_OrigHandlers = new rage::scrNativeHandler[program->m_NativeCount]; memcpy(m_OrigHandlers, program->m_NativeEntrypoints, program->m_NativeCount * sizeof(rage::scrNativeHandler)); @@ -36,7 +36,9 @@ namespace YimMenu void NativeHooks::Program::ScrProgram_Dtor(rage::scrProgram* _this, bool free_mem) { NativeHooks::UnregisterProgram(_this); - (**reinterpret_cast(_this))(_this, free_mem); + auto vtable = *reinterpret_cast(_this); + auto destructor = *(vtable + 6); + reinterpret_cast(destructor)(_this, free_mem); } NativeHooks::NativeHooks() : diff --git a/src/game/commands/PlayerCommand.cpp b/src/game/commands/PlayerCommand.cpp index c7afaa3..547d5ce 100644 --- a/src/game/commands/PlayerCommand.cpp +++ b/src/game/commands/PlayerCommand.cpp @@ -13,9 +13,20 @@ namespace YimMenu void PlayerAllCommand::OnCall() { + std::vector validPlayers; + validPlayers.reserve(Players::GetPlayers().size() - 1); for (auto& p : Players::GetPlayers()) + { if (p.second.IsValid() && (!Self::GetPlayer().IsValid() || p.second.GetId() != Self::GetPlayer().GetId())) - m_PlayerCommand->Call(p.second); + validPlayers.push_back(p.second); + } + m_PlayerCommand->Call(validPlayers); + } + + void PlayerCommand::OnCall(const std::vector& players) + { + for (auto& p : players) + Call(p); } PlayerCommand::PlayerCommand(std::string name, std::string label, std::string description, int num_args, bool all_version) : @@ -34,4 +45,9 @@ namespace YimMenu { OnCall(target); } + + void PlayerCommand::Call(const std::vector& targets) + { + OnCall(targets); + } } \ No newline at end of file diff --git a/src/game/commands/PlayerCommand.hpp b/src/game/commands/PlayerCommand.hpp index 3cbff0a..566862d 100644 --- a/src/game/commands/PlayerCommand.hpp +++ b/src/game/commands/PlayerCommand.hpp @@ -21,9 +21,11 @@ namespace YimMenu protected: virtual void OnCall(Player) = 0; + virtual void OnCall(const std::vector&); public: PlayerCommand(std::string name, std::string label, std::string description, int num_args = 0, bool all_version = true); - void Call(Player target); // TODO + void Call(Player target); + void Call(const std::vector& targets); }; } \ No newline at end of file diff --git a/src/game/features/network/FastJoin.cpp b/src/game/features/network/FastJoin.cpp index 02c6ed4..af7e623 100644 --- a/src/game/features/network/FastJoin.cpp +++ b/src/game/features/network/FastJoin.cpp @@ -37,7 +37,7 @@ namespace YimMenu::Features if (SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME() == "freemode"_J) { GSBD::Get()->FreemodeState = eFreemodeState::RUNNING; - GSBD::Get()->CayoPericoStrandedAnimalChoice = 0; // unbrick cayo just in case if the script host never responds + GSBD::Get()->CayoPericoStrandedAnimalChoice = 1; // unbrick cayo just in case if the script host never responds } return ctx->SetReturnValue(TRUE); } diff --git a/src/game/features/players/info/Spectate.cpp b/src/game/features/players/info/Spectate.cpp index 1dcdef3..fd10a30 100644 --- a/src/game/features/players/info/Spectate.cpp +++ b/src/game/features/players/info/Spectate.cpp @@ -17,13 +17,15 @@ namespace YimMenu::Features { NETWORK::NETWORK_SET_IN_SPECTATOR_MODE(false, 0); HUD::SET_MINIMAP_IN_SPECTATOR_MODE(false, 0); - if (selected) - { - NETWORK::NETWORK_SET_IN_SPECTATOR_MODE(true, selected.GetPed().GetHandle()); - HUD::SET_MINIMAP_IN_SPECTATOR_MODE(true, selected.GetPed().GetHandle()); - } + m_SpectatingPlayer = selected; } + + if (m_SpectatingPlayer) + { + NETWORK::NETWORK_SET_IN_SPECTATOR_MODE(true, m_SpectatingPlayer.GetPed().GetHandle()); + HUD::SET_MINIMAP_IN_SPECTATOR_MODE(true, m_SpectatingPlayer.GetPed().GetHandle()); + } } virtual void OnDisable() override diff --git a/src/game/features/players/troll/SendSext.cpp b/src/game/features/players/troll/SendSext.cpp new file mode 100644 index 0000000..04f6878 --- /dev/null +++ b/src/game/features/players/troll/SendSext.cpp @@ -0,0 +1,29 @@ +#include "game/commands/PlayerCommand.hpp" +#include "types/script/ScriptEvent.hpp" + +namespace YimMenu::Features +{ + class SendSext : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + + static constexpr auto sm_Strippers = std::to_array({"HCH", "INF", "JUL", "NIK", "SAP", "TXI"}); + static constexpr auto sm_SextTypes = std::to_array({"1ST", "2ND", "NEED"}); + + virtual void OnCall(Player player) override + { + OnCall(std::vector{player}); + } + + virtual void OnCall(const std::vector& players) override + { + SCRIPT_EVENT_SEND_TEXT_LABEL_MESSAGE message; + strncpy(message.Label.Data, std::format("SXT_{}_{}", sm_Strippers[rand() % sm_Strippers.size()], sm_SextTypes[rand() % sm_SextTypes.size()]).c_str(), 24); + for (auto& player : players) + message.SetPlayer(player.GetId()); + message.Send(); + } + }; + + static SendSext _SendSext{"sendsext", "Send Sext", "Sends a random sext to the specified player"}; +} \ No newline at end of file diff --git a/src/game/features/players/troll/SetBounty.cpp b/src/game/features/players/troll/SetBounty.cpp new file mode 100644 index 0000000..69674aa --- /dev/null +++ b/src/game/features/players/troll/SetBounty.cpp @@ -0,0 +1,31 @@ +#include "core/commands/BoolCommand.hpp" +#include "core/commands/IntCommand.hpp" +#include "game/commands/PlayerCommand.hpp" +#include "types/script/ScriptEvent.hpp" +#include "types/script/globals/GSBD_FM_Events.hpp" + +namespace YimMenu::Features +{ + static IntCommand _BountyAmount{"bountyamount", "Bounty Amount", "The bounty amount to set", 1, 10000, 9000}; + static BoolCommand _AnonymousBounty{"anonymousbounty", "Anonymous Bounty", "Sets the bounty as anonymous"}; + + class SetBounty : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + + virtual void OnCall(Player player) override + { + SCRIPT_EVENT_BOUNTY bounty; + bounty.Target = player.GetId(); + bounty.FromPed = _AnonymousBounty.GetState(); + bounty.Amount = _BountyAmount.GetState(); + bounty.BountyFlags = 1; + bounty.AntiReplayValue1 = GSBD_FM_Events::Get()->AntiReplayValue1; + bounty.AntiReplayValue2 = GSBD_FM_Events::Get()->AntiReplayValue2; + bounty.SetAllPlayers(); + bounty.Send(); + } + }; + + static SetBounty _SetBounty{"setbounty", "Set Bounty", "Sets the specified bounty to the player"}; +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Network.cpp b/src/game/frontend/submenus/Network.cpp index c14061c..68a2a3c 100644 --- a/src/game/frontend/submenus/Network.cpp +++ b/src/game/frontend/submenus/Network.cpp @@ -8,14 +8,24 @@ namespace YimMenu::Submenus { // TODO: this needs a rework auto session = std::make_shared("Session"); + auto bountyGroup = std::make_shared("Bounty", 1); auto toxicGroup = std::make_shared("Toxic"); + auto trollGroup = std::make_shared("Troll"); auto enhancements = std::make_shared("Enhancements"); + bountyGroup->AddItem(std::make_shared("bountyamount"_J, "Amount")); + bountyGroup->AddItem(std::make_shared("anonymousbounty"_J, "Anonymous")); + bountyGroup->AddItem(std::make_shared("setbountyall"_J, "Set Bounties")); + + trollGroup->AddItem(std::make_shared("sendsextall"_J, "Send Sexts")); + toxicGroup->AddItem(std::make_shared("killall"_J, "Kill All")); toxicGroup->AddItem(std::make_shared("explodeall"_J, "Explode All")); - + enhancements->AddItem(std::make_shared("fastjoin"_J)); + session->AddItem(bountyGroup); + session->AddItem(trollGroup); session->AddItem(toxicGroup); session->AddItem(enhancements); diff --git a/src/game/frontend/submenus/Player/Troll.cpp b/src/game/frontend/submenus/Player/Troll.cpp new file mode 100644 index 0000000..e2403f4 --- /dev/null +++ b/src/game/frontend/submenus/Player/Troll.cpp @@ -0,0 +1,23 @@ +#include "Troll.hpp" + +namespace YimMenu::Submenus +{ + std::shared_ptr BuildTrollMenu() + { + auto menu = std::make_shared("Troll"); + + auto general = std::make_shared("General"); + auto bounty = std::make_shared("Bounty", 1); + + general->AddItem(std::make_shared("sendsext"_J)); + + bounty->AddItem(std::make_shared("bountyamount"_J, "Amount")); + bounty->AddItem(std::make_shared("anonymousbounty"_J, "Anonymous")); + bounty->AddItem(std::make_shared("setbounty"_J)); + + menu->AddItem(general); + menu->AddItem(bounty); + + return menu; + } +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Player/Troll.hpp b/src/game/frontend/submenus/Player/Troll.hpp new file mode 100644 index 0000000..6207560 --- /dev/null +++ b/src/game/frontend/submenus/Player/Troll.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 BuildTrollMenu(); +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Players.cpp b/src/game/frontend/submenus/Players.cpp index 00216d5..5fa742c 100644 --- a/src/game/frontend/submenus/Players.cpp +++ b/src/game/frontend/submenus/Players.cpp @@ -2,6 +2,7 @@ #include "Player/Info.hpp" #include "Player/Toxic.hpp" +#include "Player/Troll.hpp" #include "core/frontend/widgets/imgui_colors.h" #include "game/backend/PlayerData.hpp" #include "game/backend/Players.hpp" @@ -115,6 +116,7 @@ namespace YimMenu::Submenus Submenu::Submenu("Players") { AddCategory(std::move(BuildInfoMenu())); + AddCategory(std::move(BuildTrollMenu())); AddCategory(std::move(BuildToxicMenu())); for (auto& category : m_Categories) diff --git a/src/game/frontend/submenus/Self.cpp b/src/game/frontend/submenus/Self.cpp index 00cdaee..e216fd4 100644 --- a/src/game/frontend/submenus/Self.cpp +++ b/src/game/frontend/submenus/Self.cpp @@ -1,14 +1,8 @@ #include "Self.hpp" #include "core/util/Joaat.hpp" -#include "core/commands/BoolCommand.hpp" -#include "core/commands/Commands.hpp" -#include "core/commands/IntCommand.hpp" #include "game/frontend/items/Items.hpp" -#include - - namespace YimMenu::Features { // BoolCommand _RecoveryEnabled("recoveryenabled", "Recovery Enabled", "Is the recovery feature enabled"); diff --git a/src/game/gta/Player.cpp b/src/game/gta/Player.cpp index 7ba07db..bedaa58 100644 --- a/src/game/gta/Player.cpp +++ b/src/game/gta/Player.cpp @@ -19,7 +19,7 @@ namespace YimMenu return m_Handle && m_Handle->IsPhysical() && m_Handle->m_PlayerInfo; } - int Player::GetId() + int Player::GetId() const { if (!IsValid()) { diff --git a/src/game/gta/Player.hpp b/src/game/gta/Player.hpp index ab4d3b5..c84ce2e 100644 --- a/src/game/gta/Player.hpp +++ b/src/game/gta/Player.hpp @@ -35,7 +35,7 @@ namespace YimMenu // object bool IsValid() const; - int GetId(); + int GetId() const; const char* GetName(); CNetGamePlayer* GetHandle(); rage::rlGamerInfo* GetGamerInfo(); diff --git a/src/types/script/ScriptEvent.cpp b/src/types/script/ScriptEvent.cpp new file mode 100644 index 0000000..d2e190c --- /dev/null +++ b/src/types/script/ScriptEvent.cpp @@ -0,0 +1,10 @@ +#include "ScriptEvent.hpp" +#include "game/gta/Natives.hpp" + +void SCRIPT_EVENT::Send() +{ + auto size = __SizeOfEvent; + __SizeOfEvent = 0; + SCRIPT::_SEND_TU_SCRIPT_EVENT_NEW(1, this, size / sizeof(std::uint32_t), PlayerBits, EventIndex); + __SizeOfEvent = size; +} diff --git a/src/types/script/ScriptEvent.hpp b/src/types/script/ScriptEvent.hpp new file mode 100644 index 0000000..9f6317a --- /dev/null +++ b/src/types/script/ScriptEvent.hpp @@ -0,0 +1,143 @@ +#pragma once +#include "types.hpp" + +#define REGISTER_SCRIPT_EVENT(classType, indexType) \ + constexpr static auto EVENT_INDEX = ScriptEventIndex::indexType; \ + classType() \ + { \ + memset(this, 0, sizeof(classType)); EventIndex = static_cast(EVENT_INDEX); \ + __SizeOfEvent = sizeof(classType); \ + } \ + classType(const classType& other) \ + { \ + memcpy(this, &other, sizeof(classType)); \ + EventIndex = static_cast(EVENT_INDEX); \ + __SizeOfEvent = sizeof(classType); \ + } + +// I doubt rockstar would cycle this again, but best to keep this, just in case +enum class ScriptEventIndex +{ + Bounty = 1517551547, // (137, "FM_TXT_BNTY0", iVar1, PLAYER::GET_PLAYER_NAME(Var2.f_1), "", 5000, Var2.f_6); + CeoBan = 1531565154, // mpply_vipgameplaydisabledtimer + CeoKick = -11681548, + CeoMoney = -337848027, // Goon_Paid_Large + ClearWantedLevel = -1704545346, + ForceMission = 259469385, // ), Var0.f_2, 1)) + GiveCollectible = 968269233, // DLC_SUM20_HIDDEN_COLLECTIBLES xref + GtaBanner = -330501227, // NETWORK::NETWORK_IS_SCRIPT_ACTIVE("BUSINESS_BATTLES", -1, true, 0) second one + NetworkBail = -901348601, // NETWORK::NETWORK_BAIL(16, 0, 0); xref func + PersonalVehicleDestroyed = 1655503526, // PLYVEH_INS_DES1 + RemoteOffradar = 57493695, // NETWORK::GET_TIME_DIFFERENCE(NETWORK::GET_NETWORK_TIME(), Var0.f_2) + SendToCutscene = -1951335381, // (bVar3, bVar4, 125f, 1) + SendToCayoPerico = 373376135, // CELL_HI_INV + SendToLocation = 1669592503, // &Var222, 11); + SoundSpam = 996099702, // CELL_APTINVYACHT + Spectate = 1840946429, // SPEC_TCK1 + Teleport = -1321657966, // Mission_Pass_Notify + TeleportToWarehouse = -1253241415, // .f_4 == 50 + TransactionError = -830063381, // NETWORK_RECEIVE_PLAYER_JOBSHARE_CASH + VehicleKick = -503325966, // PIM_RFMOC + MCTeleport = 1103127469, // NETWORK::NETWORK_HASH_FROM_PLAYER_HANDLE(PLAYER::PLAYER_ID()) == (first one) + StartActivity = 1450115979, // (Var0.f_2, -1); first match + MarkPlayerAsBeast = 1649541577, // GB_BOSSBST xref == PLAYER... global (sadly doesn't actually turn people into the beast) + KickFromInterior = -1496371358, // ENTITY::SET_ENTITY_HEALTH(PLAYER::PLAYER_PED_ID(), PED::GET_PED_MAX_HEALTH(PLAYER::PLAYER_PED_ID()), false) + InteriorControl = -1638522928, // eventData.f_3 != _INVALID_PLAYER_INDEX_0() + SendTextLabelSMS = -1773335296, + + Crash = -1604421397, // SET_NO_LOADING_SCREEN, xref it + Crash2 = -375628860, + Crash3 = 323285304, + + TSECommand = 800157557, // CnCTG_IN_BF + TSECommandRotateCam = 225624744, // != 29) && f + TSECommandSound = 385726943, + + Notification = -642704387, + NotificationMoneyBanked = 94410750, // TICK_TC_BANK + NotificationMoneyRemoved = -242911964, // TICK_TC_REMO + NotificationMoneyStolen = -295926414, // TICK_TC_STOL + NotificationCrash1 = -994541138, // AMCH_ATTEMPT2 + NotificationCrash2 = 782258655, // GBSAL_COLL + + DestroyPersonalVehicle = 109434679, // CnC_PV_THEFT + TriggerCEORaid = -1906536929, + + StartScriptBegin = -366707054, + StartScriptProceed = 1757622014 +}; + +struct SCRIPT_EVENT +{ +protected: + SCR_HASH EventIndex; // 0x00 + Player SenderIndex; // 0x08 + int __SizeOfEvent; // 0x0C + SCR_INT PlayerBits; // 0x10 + +public: + int GetSender() const + { + return SenderIndex; + } + + Hash GetEventIndex() const + { + return EventIndex; + } + + bool ShouldReceiveEvent(int player) const + { + return PlayerBits & (1 << player); + } + + void SetAllPlayers() + { + PlayerBits = -1; + } + + void SetAllPlayersExcept(int player_to_exclude) + { + PlayerBits = -1 & ~(1 << player_to_exclude); + } + + void SetPlayer(int player) + { + PlayerBits |= (1 << player); + } + + // must be called in script context + void Send(); + + inline void Send(int player) + { + SetPlayer(player); + Send(); + } +}; +static_assert(sizeof(SCRIPT_EVENT) == 3 * 8); + +struct SCRIPT_EVENT_BOUNTY : public SCRIPT_EVENT +{ + REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_BOUNTY, Bounty); + + PLAYER_INDEX Target; + SCR_INT BountyFlags; + SCR_INT Amount; + SCR_INT PAD_0006; + SCR_BOOL FromPed; + uint64_t PAD_0008[13]; + SCR_INT AntiReplayValue1; + SCR_INT AntiReplayValue2; +}; +static_assert(sizeof(SCRIPT_EVENT_BOUNTY) == 23 * 8); + +struct SCRIPT_EVENT_SEND_TEXT_LABEL_MESSAGE : public SCRIPT_EVENT +{ + REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_SEND_TEXT_LABEL_MESSAGE, SendTextLabelSMS); + + TEXT_LABEL_23 Label; +}; +static_assert(sizeof(SCRIPT_EVENT_SEND_TEXT_LABEL_MESSAGE) == 9 * 8); + +#undef REGISTER_SCRIPT_EVENT \ No newline at end of file diff --git a/src/types/script/globals/GSBD_FM_Events.hpp b/src/types/script/globals/GSBD_FM_Events.hpp new file mode 100644 index 0000000..13f995a --- /dev/null +++ b/src/types/script/globals/GSBD_FM_Events.hpp @@ -0,0 +1,13 @@ +#pragma once +#include "../types.hpp" + +// TODO +struct GSBD_FM_Events +{ + uint64_t PAD_0000[8]; + SCR_INT AntiReplayValue1; + SCR_INT AntiReplayValue2; + + static GSBD_FM_Events* Get(); +}; +//static_assert(sizeof(GSBD) == 1498 * 8); \ No newline at end of file diff --git a/src/types/script/globals/Globals.cpp b/src/types/script/globals/Globals.cpp index 1060093..1e9469e 100644 --- a/src/types/script/globals/Globals.cpp +++ b/src/types/script/globals/Globals.cpp @@ -6,6 +6,7 @@ #include "GSBD.hpp" #include "GSBD_BlockB.hpp" #include "GSBD_FM.hpp" +#include "GSBD_FM_Events.hpp" #include "GSBD_Kicking.hpp" #include "GSBD_PropertyInstances.hpp" #include "g_AMC_playerBD.hpp" @@ -27,6 +28,7 @@ DEFINE_GLOBAL_ACCESSOR(GPBD_MissionName, 1873815); DEFINE_GLOBAL_ACCESSOR(GSBD, 2648917); DEFINE_GLOBAL_ACCESSOR(GSBD_BlockB, 2650415); DEFINE_GLOBAL_ACCESSOR(GSBD_FM, 1835557); +DEFINE_GLOBAL_ACCESSOR(GSBD_FM_Events, 1917230); DEFINE_GLOBAL_ACCESSOR(GSBD_Kicking, 1877529); DEFINE_GLOBAL_ACCESSOR(GSBD_PropertyInstances, 1937699); DEFINE_GLOBAL_ACCESSOR(g_AMC_playerBD, 2699624); \ No newline at end of file