feat: add some player options

This commit is contained in:
maybegreat48 committed 2025-06-22 15:37:59 -04:00
1 parent b65f1ba302
commit cc9c426957
21 files changed
+806 -5

No files matched your search

+5
View File
@@ -41,6 +41,11 @@ namespace YimMenu
BaseHook::Add<Hooks::Network::GetPoolType>(new DetourHook("GetPoolType", Pointers.GetPoolType, Hooks::Network::GetPoolType));
BaseHook::Add<Hooks::Matchmaking::MatchmakingAdvertise>(new DetourHook("MatchmakingAdvertise", Pointers.MatchmakingAdvertise, Hooks::Matchmaking::MatchmakingAdvertise));
BaseHook::Add<Hooks::Matchmaking::MatchmakingSessionDetailSendResponse>(new DetourHook("MatchmakingSessionDetailSendResponse", Pointers.MatchmakingSessionDetailSendResponse, Hooks::Matchmaking::MatchmakingSessionDetailSendResponse));
BaseHook::Add<Hooks::Matchmaking::MatchmakingUnadvertise>(new DetourHook("MatchmakingUnadvertise", Pointers.MatchmakingUnadvertise, Hooks::Matchmaking::MatchmakingUnadvertise));
BaseHook::Add<Hooks::Matchmaking::MatchmakingUpdate>(new DetourHook("MatchmakingUpdate", Pointers.MatchmakingUpdate, Hooks::Matchmaking::MatchmakingUpdate));
BaseHook::Add<Hooks::Misc::AssistedAimShouldReleaseEntity>(new DetourHook("AssistedAimShouldReleaseEntity", Pointers.AssistedAimShouldReleaseEntity, Hooks::Misc::AssistedAimShouldReleaseEntity));
}
+251
View File
@@ -0,0 +1,251 @@
#include "CustomMatchmaking.hpp"
#include "core/util/Joaat.hpp"
#include "types/network/MatchmakingId.hpp"
#include "types/network/rlSessionDetail.hpp"
#include "core/commands/BoolCommand.hpp"
#include "core/commands/IntCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "game/hooks/Hooks.hpp"
#include "core/hooking/DetourHook.hpp"
#include "core/backend/FiberPool.hpp"
#include "core/backend/ScriptMgr.hpp"
namespace YimMenu::Features
{
static std::vector<std::pair<int, const char*>> g_RegionCodes = {
{0, "CIS"},
{1, "South America"},
{2, "US East"},
{3, "Europe"},
{4, "China"},
{5, "Australia"},
{6, "US West"},
{7, "Japan"},
{8, "Unknown"},
};
static std::vector<std::pair<int, const char*>> g_LanguageTypes = {
{0, "English"},
{1, "French"},
{2, "German"},
{3, "Italian"},
{4, "Spanish (Spain)"},
{5, "Portuguese (Brazil)"},
{6, "Polish"},
{7, "Russian"},
{8, "Korean"},
{9, "Chinese (Traditional)"},
{10, "Japanese"},
{11, "Spanish (Mexico)"},
{12, "Chinese (Simplified)"},
};
BoolCommand _SpoofRegionType{
"mmspoofregiontype",
"Spoof Region Type",
"Spoofs the region type of the session"};
ListCommand _RegionType{
"mmregiontype",
"Region Type",
"The region to spoof the session to",
g_RegionCodes};
BoolCommand _SpoofLanguage{
"mmspooflanguage",
"Spoof Language",
"Spoofs the session language"};
ListCommand _Language{
"mmlanguage",
"Language",
"The language to spoof the session to",
g_LanguageTypes};
BoolCommand _SpoofPlayerCount{
"mmspoofplayercount",
"Spoof Player Count",
"Spoofs the session player count"};
IntCommand _PlayerCount{
"mmplayercount",
"Player Count",
"The player count to spoof the session to",
1,
32,
25};
BoolCommand _MultiplexSession{
"mmmultiplexsession",
"Multiplex Session",
"Makes your session much more visible to other players by hosting multiple instances of it. High values may fill your session in seconds. Use at your own risk"};
IntCommand _MultiplexCount{
"mmmultiplexsessioncount",
"Multiplex Session Count",
"The number of sessions to advertise for matchmaking",
2,
7,
5};
}
namespace YimMenu
{
static std::uint32_t GetIdHash(MatchmakingId* id)
{
return Joaat(id->m_data1);
}
static void PatchMatchmakingAttrs(MatchmakingAttributes* attrs)
{
if (Features::_SpoofRegionType.GetState())
{
attrs->m_ParamValues[4] = Features::_RegionType.GetState();
}
if (Features::_SpoofLanguage.GetState())
{
attrs->m_ParamValues[3] = Features::_Language.GetState();
}
if (Features::_SpoofPlayerCount.GetState())
{
attrs->m_ParamValues[2] = Features::_PlayerCount.GetState();
}
}
CustomMatchmaking::CustomMatchmaking()
{
}
bool CustomMatchmaking::OnAdvertiseImpl(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id, rage::rlTaskStatus* status)
{
PatchMatchmakingAttrs(attrs);
if (!Features::_MultiplexSession.GetState())
return true; // let the default game code run
if (status->m_Status)
return false;
status->m_Status = 1; // set task in progress
auto num_slots_copy = num_slots;
auto available_slots_copy = available_slots;
FiberPool::Push([this, num_slots_copy, available_slots_copy, info, attrs, id, status] {
rage::rlTaskStatus first_advert_status;
if (!BaseHook::Get<Hooks::Matchmaking::MatchmakingAdvertise, DetourHook<decltype(&Hooks::Matchmaking::MatchmakingAdvertise)>>()->Original()(0, num_slots_copy, available_slots_copy, attrs, -1, info, id, &first_advert_status))
{
LOGF(WARNING, "OnAdvertiseImpl(): MatchmakingAdvertise returned false for the initial advertisement");
status->m_Status = 2;
return;
}
while (first_advert_status.m_Status == 1)
ScriptMgr::Yield();
if (first_advert_status.m_Status == 2)
{
LOGF(WARNING, "OnAdvertiseImpl(): MatchmakingAdvertise failed for the initial advertisement with code {}", status->m_ErrorCode);
status->m_Status = 2;
return;
}
auto id_hash = GetIdHash(id);
m_MultiplexedSessions.emplace(id_hash, std::vector<MatchmakingId>{});
// create the multiplexed sessions
for (int i = 0; i < Features::_MultiplexCount.GetState() - 1; i++)
{
FiberPool::Push([this, num_slots_copy, available_slots_copy, info, attrs, status, id_hash, i] {
rage::rlTaskStatus additional_advert_status;
MatchmakingId additional_id;
if (!BaseHook::Get<Hooks::Matchmaking::MatchmakingAdvertise, DetourHook<decltype(&Hooks::Matchmaking::MatchmakingAdvertise)>>()->Original()(0, num_slots_copy, available_slots_copy, attrs, -1, info, &additional_id, &additional_advert_status))
{
LOGF(WARNING, "OnAdvertiseImpl(): MatchmakingAdvertise returned false for additional advertisement {}", i);
return;
}
while (additional_advert_status.m_Status == 1)
ScriptMgr::Yield();
if (additional_advert_status.m_Status == 2)
{
LOGF(WARNING, "OnAdvertiseImpl(): MatchmakingAdvertise failed for the additional advertisement {} with code {}", i, status->m_ErrorCode);
return;
}
if (auto it = m_MultiplexedSessions.find(id_hash); it != m_MultiplexedSessions.end())
it->second.push_back(additional_id);
});
}
status->m_Status = 3; // signal success to game
});
return false; // we're handling the request now
}
void CustomMatchmaking::OnUpdateImpl(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id)
{
PatchMatchmakingAttrs(attrs);
auto hash = GetIdHash(id);
// check if the game is trying to update a session we've multiplexed
if (auto it = m_MultiplexedSessions.find(hash); it != m_MultiplexedSessions.end())
{
for (auto& session : it->second)
{
auto num_slots_copy = num_slots;
auto available_slots_copy = available_slots;
FiberPool::Push([session, num_slots_copy, available_slots_copy, info, attrs]() {
auto session_copy = session; // the compiler doesn't like it if I use session directly
BaseHook::Get<Hooks::Matchmaking::MatchmakingUpdate, DetourHook<decltype(&Hooks::Matchmaking::MatchmakingUpdate)>>()->Original()(0, &session_copy, num_slots_copy, available_slots_copy, info, attrs, nullptr); // life's too short to check the task result
});
}
}
}
bool CustomMatchmaking::OnUnadvertiseImpl(MatchmakingId* id)
{
auto hash = GetIdHash(id);
// 1) destroying host session
if (auto it = m_MultiplexedSessions.find(hash); it != m_MultiplexedSessions.end())
{
for (auto& session : it->second)
{
FiberPool::Push([session]() {
auto session_copy = session; // the compiler doesn't like it if I use session directly
BaseHook::Get<Hooks::Matchmaking::MatchmakingUnadvertise, DetourHook<decltype(&Hooks::Matchmaking::MatchmakingUnadvertise)>>()->Original()(0, &session_copy, nullptr);
});
}
return true; // we've destroyed the multiplexed sessions, let the game destroy the main session
}
// or 2) game tries to unadvertise multiplexed sessions every few seconds
for (auto& [_, multiplex] : m_MultiplexedSessions)
{
for (auto& session : multiplex)
{
if (GetIdHash(&session) == hash)
{
return false; // don't let the game destroy our sessions
}
}
}
return true;
}
void CustomMatchmaking::OnSendSessionDetailResponseImpl(rage::rlSessionDetailMsg* message)
{
PatchMatchmakingAttrs(&message->m_Detail.m_SessionConfig.m_MatchmakingAttributes);
if (Features::_SpoofPlayerCount.GetState())
{
message->m_Detail.m_PlayerCount = Features::_PlayerCount.GetState();
message->m_Detail.m_SpectatorCount = 0;
}
}
}
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include "types/network/rlTaskStatus.hpp"
#include "types/network/MatchmakingId.hpp"
namespace rage
{
class rlSessionInfo;
class rlSessionDetailMsg;
}
class MatchmakingAttributes;
class MatchmakingId;
namespace YimMenu
{
class CustomMatchmaking
{
bool OnAdvertiseImpl(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id, rage::rlTaskStatus* status);
void OnUpdateImpl(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id);
bool OnUnadvertiseImpl(MatchmakingId* id);
void OnSendSessionDetailResponseImpl(rage::rlSessionDetailMsg* message);
CustomMatchmaking();
static CustomMatchmaking& GetInstance()
{
static CustomMatchmaking instance;
return instance;
}
std::unordered_map<std::uint32_t, std::vector<MatchmakingId>> m_MultiplexedSessions;
public:
static bool OnAdvertise(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id, rage::rlTaskStatus* status)
{
return GetInstance().OnAdvertiseImpl(num_slots, available_slots, info, attrs, id, status);
}
static void OnUpdate(int& num_slots, int& available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attrs, MatchmakingId* id)
{
return GetInstance().OnUpdateImpl(num_slots, available_slots, info, attrs, id);
}
static bool OnUnadvertise(MatchmakingId* id)
{
return GetInstance().OnUnadvertiseImpl(id);
}
static void OnSendSessionDetailResponse(rage::rlSessionDetailMsg* message)
{
return GetInstance().OnSendSessionDetailResponseImpl(message);
}
};
}
@@ -0,0 +1,79 @@
#include "game/backend/Self.hpp"
#include "game/commands/PlayerCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "types/script/globals/GlobalPlayerBD.hpp"
#include "types/script/ScriptEvent.hpp"
namespace YimMenu::Features
{
static std::vector<std::pair<int, const char*>> g_Interiors = {
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARMORY_TRUCK_1, "MOC"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_CASINO, "Casino"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_CASINO_APT, "Casino Penthouse"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_DAVIS, "Arcade (Davis)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_GRAPESEED, "Arcade (Grapeseed)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_LA_MESA, "Arcade (La Mesa)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_PALETO_BAY, "Arcade (Paleto Bay)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_ROCKFORD_HILLS, "Arcade (Rockford Hills)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARCADE_WEST_VINEWOOD, "Arcade (West Vinewood)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_CASINO_NIGHTCLUB, "Music Locker"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_AUTO_SHOP_BURTON, "Auto Shop (Burton)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_AUTO_SHOP_LA_MESA, "Auto Shop (La Mesa)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_AUTO_SHOP_MISSION_ROW, "Auto Shop (Mission Row)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_AUTO_SHOP_RANCHO, "Auto Shop (Rancho)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_AUTO_SHOP_STRAWBERRY, "Auto Shop (Strawberry)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_CAR_MEET, "Car Meet"}, // requires players to have been there at least once on their own
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_FIXER_HQ_HAWICK, "Agency (Hawick)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_FIXER_HQ_ROCKFORD, "Agency (Rockford)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_FIXER_HQ_SEOUL, "Agency (Little Seoul)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_FIXER_HQ_VESPUCCI, "Agency (Vespucci)"},
// {(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ACID_LAB, "Acid Lab"}, stuck in black screen
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_JUGGALO_HIDEOUT, "Freakhouse"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SALVAGE_YARD_LA_PUERTA, "Salvage Yard (La Puerta)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SALVAGE_YARD_MURIETTA_HEIGHTS, "Salvage Yard (Murietta Heights)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SALVAGE_YARD_PALETO_BAY, "Salvage Yard (Paleto Bay)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SALVAGE_YARD_SANDY_SHORES, "Salvage Yard (Sandy Shores)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SALVAGE_YARD_STRAWBERRY, "Salvage Yard (Strawberry)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_BAIL_OFFICE_DAVIS, "Bail Office (Davis)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_BAIL_OFFICE_DEL_PERRO, "Bail Office (Del Perro)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_BAIL_OFFICE_MISSION_ROW, "Bail Office (Mission Row)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_BAIL_OFFICE_PALETO_BAY, "Bail Office (Paleto Bay)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_BAIL_OFFICE_WEST_VINEWOOD, "Bail Office (West Vinewood)"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_HACKER_DEN, "Garment Factory"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_FIELD_HANGAR, "Field Hangar"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SMALL_BUSINESS_CAR_WASH, "Car Wash"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SMALL_BUSINESS_WEED_SHOP, "Weed Shop"},
{(int)eSimpleInteriorIndex::SIMPLE_INTERIOR_SMALL_BUSINESS_HELI_TOURS, "Heli Tours"},
};
static ListCommand _SelectedInterior{"sendtointeriorindex", "Send to Interior Index", "The interior index to send the player(s) to", g_Interiors, (int)eSimpleInteriorIndex::SIMPLE_INTERIOR_ARMORY_TRUCK_1};
class SendToInterior : public PlayerCommand
{
using PlayerCommand::PlayerCommand;
virtual void OnCall(Player player) override
{
OnCall(std::vector{player});
}
virtual void OnCall(const std::vector<Player>& players) override
{
SCRIPT_EVENT_SEND_TO_INTERIOR message;
message.Interior = _SelectedInterior.GetState();
message.EnterOwnerInterior = true;
message.GoonsOnly = false;
message.InstanceId = 0;
message.SubInstanceId = -1;
message.Owner = Self::GetPlayer().GetId();
message.Distance = 99999;
message.Position = {0, 0, 0};
for (auto& player : players)
message.SetPlayer(player.GetId());
message.Send();
}
};
static SendToInterior _SendToInterior{"sendtointerior", "Send to Interior", "Sends the player to the selected interior"};
}
@@ -0,0 +1,145 @@
#include "game/backend/Self.hpp"
#include "game/commands/PlayerCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "types/script/ScriptEvent.hpp"
namespace YimMenu::Features
{
static std::vector<std::pair<int, const char*>> g_Properties = {
{1, "Eclipse Towers, Apt 31"},
{2, "Eclipse Towers, Apt 9"},
{3, "Eclipse Towers, Apt 40"},
{4, "Eclipse Towers, Apt 5"},
{5, "3 Alta St, Apt 10"},
{6, "3 Alta St, Apt 57"},
{7, "Del Perro Heights, Apt 20"},
{8, "1162 Power St, Apt 3"},
{9, "0605 Spanish Ave, Apt 1"},
{10, "0604 Las Lagunas Blvd, Apt 4"},
{11, "0184 Milton Rd, Apt 13"},
{12, "The Royale, Apt 19"},
{13, "0504 S Mo Milton Dr"},
{14, "0115 Bay City Ave, Apt 45"},
{15, "0325 South Rockford Dr"},
{16, "Dream Tower, Apt 15"},
{17, "2143 Las Lagunas Blvd, Apt 9"},
{18, "1561 San Vitas St, Apt 2"},
{19, "0112 S Rockford Dr, Apt 13"},
{20, "2057 Vespucci Blvd, Apt 1"},
{21, "0069 Cougar Ave, Apt 19"},
{22, "1237 Prosperity St, Apt 21"},
{23, "1115 Blvd Del Perro, Apt 18"},
{24, "0120 Murrieta Heights"},
{25, "Unit 14 Popular St"},
{26, "Unit 2 Popular St"},
{27, "331 Supply St"},
{28, "Unit 1 Olympic Fwy"},
{29, "0754 Roy Lowenstein Blvd"},
{30, "12 Little Bighorn Ave"},
{31, "Unit 124 Popular St"},
{32, "0552 Roy Lowenstein Blvd"},
{33, "0432 Davis Ave"},
{34, "Del Perro Heights, Apt 7"},
{35, "Weazel Plaza, Apt 101"},
{36, "Weazel Plaza, Apt 70"},
{37, "Weazel Plaza, Apt 26"},
{38, "4 Integrity Way, Apt 30"},
{39, "4 Integrity Way, Apt 35"},
{40, "Richards Majestic, Apt 4"},
{41, "Richards Majestic, Apt 51"},
{42, "Tinsel Towers, Apt 45"},
{43, "Tinsel Towers, Apt 29"},
{44, "142 Paleto Blvd"},
{45, "1 Strawberry Ave"},
{46, "1932 Grapeseed Ave"},
{47, "1920 Senora Way"},
{48, "2000 Great Ocean Highway"},
{49, "197 Route 68"},
{50, "870 Route 68 Approach"},
{51, "1200 Route 68"},
{52, "8754 Route 68"},
{53, "1905 Davis Ave"},
{54, "1623 South Shambles St"},
{55, "4531 Dry Dock St"},
{56, "1337 Exceptionalists Way"},
{57, "Unit 76 Greenwich Parkway"},
{58, "Garage Innocence Blvd"},
{59, "634 Blvd Del Perro"},
{60, "0897 Mirror Park Blvd"},
{61, "Eclipse Towers, Apt 3"},
{62, "Del Perro Heights, Apt 4"},
{63, "Richards Majestic, Apt 2"},
{64, "Tinsel Towers, Apt 42"},
{65, "4 Integrity Way, Apt 28"},
{66, "4 Hangman Ave"},
{67, "12 Sustancia Rd"},
{68, "4584 Procopio Dr"},
{69, "4401 Procopio Dr"},
{70, "0232 Paleto Blvd"},
{71, "140 Zancudo Ave"},
{72, "1893 Grapeseed Ave"},
{73, "3655 Wild Oats Drive"},
{74, "2044 North Conker Avenue"},
{75, "2868 Hillcrest Avenue"},
{76, "2862 Hillcrest Avenue"},
{77, "3677 Whispymound Drive"},
{78, "2117 Milton Road"},
{79, "2866 Hillcrest Avenue"},
{80, "2874 Hillcrest Avenue"},
{81, "2113 Mad Wayne Thunder Drive"},
{82, "2045 North Conker Avenue"},
{83, "Eclipse Towers, Penthouse Suite 1"},
{84, "Eclipse Towers, Penthouse Suite 2"},
{85, "Eclipse Towers, Penthouse Suite 3"},
{86, "Private Yacht"},
{87, "Lombank West"},
{88, "Maze Bank West"},
{89, "Arcadius Business Center"},
{90, "Maze Bank Tower"},
{91, "Rancho Clubhouse"},
{92, "Del Perro Beach Clubhouse"},
{93, "Pillbox Hill Clubhouse"},
{94, "Great Chaparral Clubhouse"},
{95, "Paleto Bay Clubhouse"},
{96, "Sandy Shores Clubhouse"},
{97, "La Mesa Clubhouse"},
{98, "Downtown Vinewood Clubhouse"},
{99, "Hawick Clubhouse"},
{100, "Grapeseed Clubhouse"},
{101, "Paleto Bay Clubhouse"},
{102, "Vespucci Beach Clubhouse"},
{103, "Office Garage 1"},
{104, "Office Garage 2"},
{105, "Office Garage 3"},
{115, "Vehicle Warehouse"},
};
static ListCommand _SelectedProperty{"sendtopropertyindex", "Send to Property Index", "The property index to send the player(s) to", g_Properties, 1};
class SendToProperty : public PlayerCommand
{
using PlayerCommand::PlayerCommand;
virtual void OnCall(Player player) override
{
OnCall(std::vector{player});
}
virtual void OnCall(const std::vector<Player>& players) override
{
SCRIPT_EVENT_SEND_TO_PROPERTY message;
message.Owner = Self::GetPlayer().GetId();
message.PropertyIndex = _SelectedProperty.GetState();
message.SubProperyIndex = 1;
message.MissionPassNotify1 = true; // skips some checks
message.PAD_0004 = -1;
message.Variation = 1;
message.Flags = 2; // skips some more checks
for (auto& player : players)
message.SetPlayer(player.GetId());
message.Send();
}
};
static SendToProperty _SendToProperty{"sendtoproperty", "Send to Property", "Sends the player to the selected property"};
}
+26
View File
@@ -6,6 +6,8 @@
#include "core/backend/FiberPool.hpp"
#include "game/gta/ScriptFunction.hpp"
#include "game/gta/Natives.hpp"
#include "types/script/globals/GlobalPlayerBD.hpp"
#include "types/script/ScriptEvent.hpp"
namespace YimMenu::Submenus
{
@@ -21,6 +23,30 @@ namespace YimMenu::Submenus
});
}
static int interiorIndex = 0;
ImGui::InputInt("interiorIndex", &interiorIndex);
static bool enterOwnerInterior = false;
ImGui::Checkbox("enterOwnerInterior", &enterOwnerInterior);
if (ImGui::Button("DoTeleport"))
{
FiberPool::Push([] {
SCRIPT_EVENT_SEND_TO_INTERIOR message;
message.Interior = interiorIndex;
message.EnterOwnerInterior = enterOwnerInterior;
message.GoonsOnly = false;
message.InstanceId = 0;
message.SubInstanceId = -1;
message.Owner = Self::GetPlayer().GetId();
message.Distance = 99999;
message.Position = {0, 0, 0};
message.SetAllPlayers();
message.Send();
});
}
static int team;
ImGui::InputInt("Team", &team);
if (ImGui::Button("fm_mission_controller DoTeamSwap"))
+30 -2
View File
@@ -59,10 +59,18 @@ namespace YimMenu::Submenus
bountyGroup->AddItem(std::make_shared<BoolCommandItem>("anonymousbounty"_J, "Anonymous"));
bountyGroup->AddItem(std::make_shared<CommandItem>("setbountyall"_J, "Set Bounties"));
teleportGroup->AddItem(std::make_shared<CommandItem>("bringall"_J, "Bring All"));
auto customPlayerTp = std::make_shared<Group>("", 1);
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, ""));
customPlayerTp->AddItem(std::make_shared<CommandItem>("tpplayertocoordall"_J, "Teleport Everyone"));
auto tpToProperty = std::make_shared<Group>("", 1);
tpToProperty->AddItem(std::make_shared<ListCommandItem>("sendtopropertyindex"_J, "##selproperty"));
tpToProperty->AddItem(std::make_shared<CommandItem>("sendtopropertyall"_J, "Send All to Property"));
auto tpToInterior = std::make_shared<Group>("", 1);
tpToInterior->AddItem(std::make_shared<ListCommandItem>("sendtointeriorindex"_J, "##selinterior"));
tpToInterior->AddItem(std::make_shared<CommandItem>("sendtointeriorall"_J, "Send All to Interior"));
teleportGroup->AddItem(tpToProperty);
teleportGroup->AddItem(tpToInterior);
teleportGroup->AddItem(std::make_shared<CommandItem>("bringall"_J, "Bring All"));
teleportGroup->AddItem(customPlayerTp);
trollGroup->AddItem(std::make_shared<CommandItem>("sendsextall"_J, "Send Sexts"));
@@ -75,6 +83,7 @@ namespace YimMenu::Submenus
toxicGroup->AddItem(std::make_shared<CommandItem>("explodeall"_J, "Explode All"));
toxicGroup->AddItem(std::make_shared<CommandItem>("ceokickall"_J, "CEO Kick All"));
enhancements->AddItem(std::make_shared<BoolCommandItem>("notifyonplayerjoin"_J));
enhancements->AddItem(std::make_shared<BoolCommandItem>("fastjoin"_J));
enhancements->AddItem(std::make_shared<BoolCommandItem>("disabledeathbarriers"_J));
enhancements->AddItem(std::make_shared<BoolCommandItem>("despawnbypass"_J));
@@ -91,7 +100,7 @@ namespace YimMenu::Submenus
session->AddItem(enhancements);
auto spoofing = std::make_shared<Category>("Spoofing");
auto matchmakingGroup = std::make_shared<Group>("Matchmaking");
auto matchmakingGroup = std::make_shared<Group>("Matchmaking (Client)");
matchmakingGroup->AddItem(std::make_shared<BoolCommandItem>("cheaterpool"_J));
auto spoofMMRegion = std::make_shared<Group>("", 1);
spoofMMRegion->AddItem(std::make_shared<BoolCommandItem>("spoofmmregion"_J, "Spoof Region"));
@@ -99,6 +108,25 @@ namespace YimMenu::Submenus
matchmakingGroup->AddItem(std::make_shared<ConditionalItem>("cheaterpool"_J, spoofMMRegion, true));
spoofing->AddItem(matchmakingGroup);
auto matchmakingSrvGroup = std::make_shared<Group>("Matchmaking (Server)");
auto srvSpoofRegion = std::make_shared<Group>("", 1);
srvSpoofRegion->AddItem(std::make_shared<BoolCommandItem>("mmspoofregiontype"_J));
srvSpoofRegion->AddItem(std::make_shared<ConditionalItem>("mmspoofregiontype"_J, std::make_shared<ListCommandItem>("mmregiontype"_J, "##mmregiontype")));
auto srvSpoofLanguage = std::make_shared<Group>("", 1);
srvSpoofLanguage->AddItem(std::make_shared<BoolCommandItem>("mmspooflanguage"_J));
srvSpoofLanguage->AddItem(std::make_shared<ConditionalItem>("mmspooflanguage"_J, std::make_shared<ListCommandItem>("mmlanguage"_J, "##mmlanguage")));
auto srvSpoofPlayerCount = std::make_shared<Group>("", 1);
srvSpoofPlayerCount->AddItem(std::make_shared<BoolCommandItem>("mmspoofplayercount"_J));
srvSpoofPlayerCount->AddItem(std::make_shared<ConditionalItem>("mmspoofplayercount"_J, std::make_shared<IntCommandItem>("mmplayercount"_J, "##mmplayercount")));
auto srvMultiplex = std::make_shared<Group>("", 1);
srvMultiplex->AddItem(std::make_shared<BoolCommandItem>("mmmultiplexsession"_J));
srvMultiplex->AddItem(std::make_shared<ConditionalItem>("mmmultiplexsession"_J, std::make_shared<IntCommandItem>("mmmultiplexsessioncount"_J, "##mmmultiplexsessioncount")));
matchmakingSrvGroup->AddItem(std::move(srvSpoofRegion));
matchmakingSrvGroup->AddItem(std::move(srvSpoofLanguage));
matchmakingSrvGroup->AddItem(std::move(srvSpoofPlayerCount));
matchmakingSrvGroup->AddItem(std::move(srvMultiplex));
spoofing->AddItem(matchmakingSrvGroup);
AddCategory(std::move(session));
AddCategory(std::move(spoofing));
AddCategory(std::move(BuildSavedPlayersMenu()));
+12 -2
View File
@@ -120,12 +120,22 @@ namespace YimMenu::Submenus
menu->AddItem(playerOptionsGroup);
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tptoplayer"_J, "Teleport To"));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("bring"_J));
auto customPlayerTp = std::make_shared<Group>("", 1);
customPlayerTp->AddItem(std::make_shared<Vector3CommandItem>("playertpcoord"_J, ""));
customPlayerTp->AddItem(std::make_shared<PlayerCommandItem>("tpplayertocoord"_J, "Teleport"));
auto tpToProperty = std::make_shared<Group>("", 1);
tpToProperty->AddItem(std::make_shared<ListCommandItem>("sendtopropertyindex"_J, "##selproperty"));
tpToProperty->AddItem(std::make_shared<PlayerCommandItem>("sendtoproperty"_J));
auto tpToInterior = std::make_shared<Group>("", 1);
tpToInterior->AddItem(std::make_shared<ListCommandItem>("sendtointeriorindex"_J, "##selinterior"));
tpToInterior->AddItem(std::make_shared<PlayerCommandItem>("sendtointerior"_J));
teleportGroup->AddItem(tpToProperty);
teleportGroup->AddItem(tpToInterior);
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("tptoplayer"_J, "Teleport To"));
teleportGroup->AddItem(std::make_shared<PlayerCommandItem>("bring"_J));
teleportGroup->AddItem(customPlayerTp);
menu->AddItem(teleportGroup);
return menu;
+14
View File
@@ -18,8 +18,14 @@ namespace rage
class datBitBuffer;
class JsonSerializer;
class rlMetric;
class rlSessionDetailMsg;
class rlSessionInfo;
struct rlTaskStatus;
}
class MatchmakingAttributes;
class MatchmakingId;
namespace YimMenu
{
class Player;
@@ -46,6 +52,14 @@ namespace YimMenu::Hooks
extern std::uint32_t GetAnticheatInitializedHash2(void* ac_var, std::uint32_t seed);
}
namespace Matchmaking
{
extern bool MatchmakingAdvertise(int profile_index, int num_slots, int available_slots, MatchmakingAttributes* data, std::uint64_t session_id, rage::rlSessionInfo* info, MatchmakingId* out_id, rage::rlTaskStatus* status);
extern bool MatchmakingUpdate(int profile_index, MatchmakingId* id, int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* data, rage::rlTaskStatus* status);
extern bool MatchmakingUnadvertise(int profile_index, MatchmakingId* id, rage::rlTaskStatus* status);
extern bool MatchmakingSessionDetailSendResponse(rage::netConnectionManager* mgr, void* request_frame, rage::rlSessionDetailMsg* msg);
}
namespace Info
{
extern void AssignPhysicalIndex(CNetworkPlayerMgr* mgr, CNetGamePlayer* player, std::uint8_t index);
@@ -2,6 +2,18 @@
#include "game/hooks/Hooks.hpp"
#include "game/backend/Players.hpp"
#include "types/network/CNetGamePlayer.hpp"
#include "core/commands/BoolCommand.hpp"
#include "game/gta/Natives.hpp"
#include "core/backend/FiberPool.hpp"
namespace YimMenu::Features
{
static BoolCommand _NotifyOnPlayerJoin{
"notifyonplayerjoin",
"Notify on Player Join",
"Notifies you when a player joins above the map",
true};
}
namespace YimMenu::Hooks
{
@@ -16,6 +28,13 @@ namespace YimMenu::Hooks
LOGF(WARNING, "Player {} changed their player index from {} to {}", player->GetName(), player->m_PlayerIndex, index);
BaseHook::Get<Info::AssignPhysicalIndex, DetourHook<decltype(&Info::AssignPhysicalIndex)>>()->Original()(mgr, player, index);
Players::OnPlayerJoin(player);
std::string name = player->GetName();
FiberPool::Push([name] {
HUD::SET_TEXT_OUTLINE();
HUD::BEGIN_TEXT_COMMAND_THEFEED_POST("STRING");
HUD::ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(std::format("<C>{}</C> joined.", name).data());
HUD::END_TEXT_COMMAND_THEFEED_POST_TICKER(false, false);
});
}
else
{
@@ -0,0 +1,14 @@
#include "game/hooks/Hooks.hpp"
#include "core/hooking/DetourHook.hpp"
#include "game/backend/CustomMatchmaking.hpp"
namespace YimMenu::Hooks
{
bool Matchmaking::MatchmakingAdvertise(int profile_index, int num_slots, int available_slots, MatchmakingAttributes* data, std::uint64_t session_id, rage::rlSessionInfo* info, MatchmakingId* out_id, rage::rlTaskStatus* status)
{
if (!CustomMatchmaking::OnAdvertise(num_slots, available_slots, info, data, out_id, status))
return true;
return BaseHook::Get<Matchmaking::MatchmakingAdvertise, DetourHook<decltype(&Matchmaking::MatchmakingAdvertise)>>()->Original()(profile_index, num_slots, available_slots, data, session_id, info, out_id, status);
}
}
@@ -0,0 +1,12 @@
#include "game/hooks/Hooks.hpp"
#include "core/hooking/DetourHook.hpp"
#include "game/backend/CustomMatchmaking.hpp"
namespace YimMenu::Hooks
{
bool Matchmaking::MatchmakingSessionDetailSendResponse(rage::netConnectionManager* mgr, void* request_frame, rage::rlSessionDetailMsg* msg)
{
CustomMatchmaking::OnSendSessionDetailResponse(msg);
return BaseHook::Get<Matchmaking::MatchmakingSessionDetailSendResponse, DetourHook<decltype(&Matchmaking::MatchmakingSessionDetailSendResponse)>>()->Original()(mgr, request_frame, msg);
}
}
@@ -0,0 +1,16 @@
#include "game/hooks/Hooks.hpp"
#include "core/hooking/DetourHook.hpp"
#include "game/backend/CustomMatchmaking.hpp"
namespace YimMenu::Hooks
{
bool Matchmaking::MatchmakingUnadvertise(int profile_index, MatchmakingId* id, rage::rlTaskStatus* status)
{
if (!CustomMatchmaking::OnUnadvertise(id))
{
status->m_Status = 2;
return true;
}
return BaseHook::Get<Matchmaking::MatchmakingUnadvertise, DetourHook<decltype(&Matchmaking::MatchmakingUnadvertise)>>()->Original()(profile_index, id, status);
}
}
@@ -0,0 +1,12 @@
#include "game/hooks/Hooks.hpp"
#include "core/hooking/DetourHook.hpp"
#include "game/backend/CustomMatchmaking.hpp"
namespace YimMenu::Hooks
{
bool Matchmaking::MatchmakingUpdate(int profile_index, MatchmakingId* id, int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* data, rage::rlTaskStatus* status)
{
CustomMatchmaking::OnUpdate(num_slots, available_slots, info, data, id);
return BaseHook::Get<Matchmaking::MatchmakingUpdate, DetourHook<decltype(&Matchmaking::MatchmakingUpdate)>>()->Original()(profile_index, id, num_slots, available_slots, info, data, status);
}
}
+20
View File
@@ -425,6 +425,26 @@ namespace YimMenu
AbilityBarPatch = BytePatches::Add(ptr.As<std::uint16_t*>(), 0x9090);
});
static constexpr auto doMatchmakingAdvertisePtrn = Pattern<"C7 47 30 01 00 00 00 E9 92">("MatchmakingAdvertise");
scanner.Add(doMatchmakingAdvertisePtrn, [this](PointerCalculator addr) {
MatchmakingAdvertise = addr.Sub(0xC).Rip().As<PVOID>();
});
static constexpr auto doMatchmakingUpdatePtrn = Pattern<"C7 47 30 02 00 00 00 EB 7A">("MatchmakingUpdate");
scanner.Add(doMatchmakingUpdatePtrn, [this](PointerCalculator addr) {
MatchmakingUpdate = addr.Sub(0x8).Rip().As<PVOID>();
});
static constexpr auto doMatchmakingUnadvertisePtrn = Pattern<"C7 86 C8 01 00 00 04 00 00 00">("MatchmakingUnadvertise");
scanner.Add(doMatchmakingUnadvertisePtrn, [this](PointerCalculator addr) {
MatchmakingUnadvertise = addr.Sub(0xC).Rip().As<PVOID>();
});
static constexpr auto matchmakingSessionDetailSendResponsePtrn = Pattern<"48 B8 01 00 00 00 0D 00 00 00">("SessionDetailSendResponse");
scanner.Add(matchmakingSessionDetailSendResponsePtrn, [this](PointerCalculator addr) {
MatchmakingSessionDetailSendResponse = addr.Add(0x2F).Rip().As<PVOID>();
});
if (!scanner.Scan())
{
LOG(FATAL) << "Some patterns could not be found, unloading.";
+5 -1
View File
@@ -23,7 +23,7 @@ namespace rage
class fwVehiclePool;
class rlSessionInfo;
class rlGamerHandle;
class rlTaskStatus;
struct rlTaskStatus;
class rlScTaskStatus;
class rlSessionByGamerTaskResult;
class rlQueryPresenceAttributesContext;
@@ -163,6 +163,10 @@ namespace YimMenu
PVOID GetAnticheatInitializedHash2;
CAnticheatContext** AnticheatContext;
BytePatch AbilityBarPatch;
PVOID MatchmakingAdvertise;
PVOID MatchmakingUpdate;
PVOID MatchmakingUnadvertise;
PVOID MatchmakingSessionDetailSendResponse;
};
struct Pointers : PointerData
@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
class MatchmakingAttributes
{
public:
uint32_t m_GameMode; //0x0000
uint32_t m_NumParams; //0x0004
uint32_t m_ParamUnk[8]; //0x0008
char m_ParamNames[8][24]; //0x0028
uint32_t m_ParamValues[8]; //0x00E8
uint32_t m_ParamBitset; //0x0108
}; //Size: 0x010C
static_assert(sizeof(MatchmakingAttributes) == 0x10C);
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include <cstdint>
#include <cstddef>
class MatchmakingId
{
public:
char m_data1[0x26];
std::uint64_t m_data2;
std::uint64_t m_data3;
};
+16
View File
@@ -0,0 +1,16 @@
#pragma once
#include "MatchmakingAttributes.hpp"
namespace rage
{
class rlSessionConfig
{
public:
char m_pad[0x4]; // 0x00
int m_PublicSlots; // 0x04
int m_PrivateSlots; // 0x08
MatchmakingAttributes m_MatchmakingAttributes; // 0x0C
char m_pad2[0x18]; // 0x10C
};
static_assert(sizeof(rage::rlSessionConfig) == 0x130);
}
+36
View File
@@ -0,0 +1,36 @@
#pragma once
#include "rlSessionConfig.hpp"
#include "rlGamerInfoBase.hpp"
#include "rlSessionInfo.hpp"
namespace rage
{
class rlSessionDetail
{
public:
class rage::rlGamerInfoBase m_BaseGamerInfo; // 0x00
std::uint64_t m_HostToken; // 0xC0
class rage::rlSessionInfo m_SessionInfo; // 0xC8
class rage::rlSessionConfig m_SessionConfig; // 0x198
rage::rlGamerHandle m_Handle; // 0x2C8
char m_Name[0x14]; // 0x2D8
uint32_t m_PlayerCount; // 0x2EC
uint32_t m_SpectatorCount; // 0x2F0
uint16_t m_SessionDataStructSize; // 0x2F4
char m_SessionDataStruct[0x100]; // 0x2F6 likely a union of two structs, sizes 0x44 and 0x28
uint16_t m_MatchmakingDataStructSize; // 0x3F6
char m_MatchmakingDataStruct[0x80]; // 0x3F8 stores matchmaking tunable data?
}; //Size: 0x03CA
static_assert(sizeof(rlSessionDetail) == 0x478);
class rlSessionDetailMsg
{
public:
int m_Status;
int m_RequiredVersion;
int m_RequestToken;
int m_Unk;
rlSessionDetail m_Detail;
};
static_assert(sizeof(rlSessionDetailMsg) == 0x488);
}
+15
View File
@@ -174,6 +174,21 @@ struct SCRIPT_EVENT_SEND_TO_INTERIOR : public SCRIPT_EVENT
};
static_assert(sizeof(SCRIPT_EVENT_SEND_TO_INTERIOR) == 16 * 8);
struct SCRIPT_EVENT_SEND_TO_PROPERTY : public SCRIPT_EVENT
{
REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_SEND_TO_PROPERTY, Teleport);
PLAYER_INDEX Owner;
SCR_INT PAD_0004;
SCR_INT Variation;
SCR_INT PropertyIndex;
SCR_INT SubProperyIndex;
SCR_BOOL MissionPassNotify1;
SCR_BOOL MissionPassNotify2;
SCR_INT Flags;
};
static_assert(sizeof(SCRIPT_EVENT_SEND_TO_PROPERTY) == 11 * 8);
struct SCRIPT_EVENT_REQUEST_RANDOM_EVENT : public SCRIPT_EVENT
{
REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_REQUEST_RANDOM_EVENT, RequestRandomEvent);