Session multiplexer and more (#3167)

This commit is contained in:
maybegreat48 2024-05-24 21:17:54 +00:00 committed by GitHub
parent 8ddba7de27
commit a6e7eb54b6
21 changed files with 460 additions and 100 deletions

View File

@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
gtav_classes
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
GIT_TAG 46c1c63396cf40b206b9f5dd612f293809eefcd1
GIT_TAG c741a3031de7981d12c97f55569f930a82556d63
GIT_PROGRESS TRUE
CONFIGURE_COMMAND ""
BUILD_COMMAND ""

View File

@ -0,0 +1,46 @@
#include "backend/looped_command.hpp"
#include "natives.hpp"
#include "services/players/player_service.hpp"
#include "services/script_patcher/script_patcher_service.hpp"
#include "pointers.hpp"
#include "core/scr_globals.hpp"
#include "gta_util.hpp"
#include "gta/script_handler.hpp"
namespace big
{
class block_ceo_creation : looped_command
{
using looped_command::looped_command;
virtual void on_enable() override
{
g_script_patcher_service->update();
}
virtual void on_tick() override
{
if (!STREAMING::IS_PLAYER_SWITCH_IN_PROGRESS()) [[likely]]
{
if (*g_pointers->m_gta.m_is_session_started && SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) == 0)
{
if (auto freemode = gta_util::find_script_thread("freemode"_J); freemode && freemode->m_net_component
&& ((CGameScriptHandlerNetComponent*)freemode->m_net_component)->is_local_player_host())
{
for (int i = 0; i < 10; i++)
{
*scr_globals::gsbd_fm_events.at(11).at(132).at(i, 1).as<Player*>() = self::id;
}
}
}
}
}
virtual void on_disable() override
{
g_script_patcher_service->update();
}
};
block_ceo_creation g_block_ceo_creation("blockceos", "BLOCK_CEO_CREATION", "BLOCK_CEO_CREATION_DESC", g.session.block_ceo_creation);
}

View File

@ -0,0 +1,32 @@
#include "backend/looped_command.hpp"
#include "pointers.hpp"
#include "natives.hpp"
namespace big
{
class increase_player_limit : looped_command
{
using looped_command::looped_command;
memory::byte_patch* m_join_request_patch;
virtual void on_enable() override
{
if (!m_join_request_patch)
m_join_request_patch = memory::byte_patch::make(g_pointers->m_gta.m_session_request_patch, std::to_array({0x90, 0x90, 0x90, 0x90, 0x90, 0x90})).get();
m_join_request_patch->apply();
}
virtual void on_tick() override
{
if (*g_pointers->m_gta.m_is_session_started && !NETWORK::NETWORK_IS_ACTIVITY_SESSION())
NETWORK::NETWORK_SESSION_CHANGE_SLOTS(32, 0);
}
virtual void on_disable() override
{
m_join_request_patch->restore();
}
};
increase_player_limit g_increase_player_limit("32players", "INCREASE_PLAYER_LIMIT", "INCREASE_PLAYER_LIMIT_DESC", g.spoofing.increase_player_limit);
}

View File

@ -8,69 +8,28 @@ namespace big
{
void register_script_patches()
{
g_script_patcher_service->add_patch(
{"freemode"_J, "freemode1", "2D 01 08 00 ? 38 00 5D ? ? ? 2A 06", 5, {0x71, 0x2E, 0x01, 0x01}, &g.session.decloak_players});
g_script_patcher_service->add_patch({"freemode"_J, "freemode1", "2D 01 08 00 ? 38 00 5D ? ? ? 2A 06", 5, {0x71, 0x2E, 0x01, 0x01}, &g.session.decloak_players});
g_script_patcher_service->add_patch({"freemode"_J, "script host kick", "2D 01 04 00 ? 2C ? ? ? 5D ? ? ? 71 57 ? ? 2C", 5, {0x2E, 0x01, 0x00}, nullptr}); // script host kick
g_script_patcher_service->add_patch({"freemode"_J, "end session kick protection", "5D ? ? ? 76 57 ? ? 5D ? ? ? 76", 0, {0x2E, 0x00, 0x00}, nullptr}); // end session kick protection
g_script_patcher_service->add_patch({"freemode"_J, "disable death when undermap/spectating", "2D 01 09 00 00 5D ? ? ? 56 ? ? 3A", 5, {0x2E, 0x01, 0x00}, nullptr}); // disable death when undermap/spectating
g_script_patcher_service->add_patch({"freemode"_J, "load island even if stranded animal IPL choice is not set", "71 2E ? ? 55 ? ? 61 ? ? ? 47 ? ? 63", 0, {0x72}, nullptr}); // load island even if stranded animal IPL choice is not set
g_script_patcher_service->add_patch({"freemode"_J, "disable population load balancing", "2D 00 07 00 00 7B", 5, {0x2E, 0x00, 0x00}, nullptr}); // disable population load balancing
g_script_patcher_service->add_patch(
{"freemode"_J, "freemode7", "2D 02 08 00 00 38 01 56", 5, {0x2E, 0x02, 0x00}, &g.session.block_muggers});
g_script_patcher_service->add_patch(
{"freemode"_J, "freemode8", "2D 00 CF 00 00", 5, {0x2E, 0x00, 0x00}, &g.session.block_ceo_raids});
g_script_patcher_service->add_patch(
{"freemode"_J, "prevent normal blip update", "06 56 ? ? 38 02 2C ? ? ? 71 71", 0, {0x2B, 0x55}, &g.spoofing.spoof_blip}); // prevent normal blip update
g_script_patcher_service->add_patch({"freemode"_J,
"prevent normal blip update 2",
"2C ? ? ? 55 ? ? 71 2C ? ? ? 61",
7,
std::vector<uint8_t>(16, 0x0),
&g.spoofing.spoof_blip}); // prevent normal blip update 2
g_script_patcher_service->add_patch({"freemode"_J, "freemode7", "2D 02 08 00 00 38 01 56", 5, {0x2E, 0x02, 0x00}, &g.session.block_muggers});
g_script_patcher_service->add_patch({"freemode"_J, "freemode8", "2D 00 CF 00 00", 5, {0x2E, 0x00, 0x00}, &g.session.block_ceo_raids});
g_script_patcher_service->add_patch({"freemode"_J, "prevent normal blip update", "06 56 ? ? 38 02 2C ? ? ? 71 71", 0, {0x2B, 0x55}, &g.spoofing.spoof_blip}); // prevent normal blip update
g_script_patcher_service->add_patch({"freemode"_J, "prevent normal blip update 2", "2C ? ? ? 55 ? ? 71 2C ? ? ? 61", 7, std::vector<uint8_t>(16, 0x0), &g.spoofing.spoof_blip}); // prevent normal blip update 2
g_script_patcher_service->add_patch({"freemode"_J, "stop relinquishing invalid CEO slots", "2D 01 05 00 00 38 00 2C ? ? ? 39 03 38 03 2C ? ? ? 56", 5, {0x2E, 0x01, 0x00}, &g.session.block_ceo_creation}); // stop relinquishing invalid CEO slots
g_script_patcher_service->add_patch({"shop_controller"_J, "despawn bypass", "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, {0x71, 0x2E, 0x01, 0x01}, nullptr}); // despawn bypass
g_script_patcher_service->add_patch({"shop_controller"_J, "godmode/invisibility detection bypass", "2D 01 03 00 00 5D ? ? ? 06 56 ? ? 2E ? ? 2C", 5, {0x2E, 0x01, 0x00}, nullptr}); // godmode/invisibility detection bypass
g_script_patcher_service->add_patch({"am_mp_nightclub"_J,
"am_mp_nightclub1",
"2D 01 03 00 00 2C ? ? ? 56 ? ? 72 2E ? ? 38 00",
5,
{0x72, 0x2E, 0x01, 0x01},
&g.self.dance_mode});
g_script_patcher_service->add_patch({"am_mp_nightclub"_J,
"am_mp_nightclub2",
"20 56 ? ? 4F ? ? 46 ? ? 41 ? 71",
0,
{0x2B, 0x55},
&g.self.dance_mode});
g_script_patcher_service->add_patch({"freemode"_J,
"freemode9",
"5D ? ? ? 56 ? ? 72 39 05 38 04 2C ? ? ? 58",
0,
{0x2B, 0x2B, 0x2B, 0x00, 0x55},
&g.self.invisibility});
g_script_patcher_service->add_patch({"freemode"_J,
"freemode10",
"2D 01 03 00 00 38 00 71 72 5D ? ? ? 06 56 ? ? 71 2E ? ? 2C ? ? ? 71",
5,
{0x72, 0x2E, 0x01, 0x01},
&g.session.unhide_players_from_player_list});
g_script_patcher_service->add_patch({"carmod_shop"_J,
"disable camera",
"2D 01 0A 00 00 4F ? ? 40 ? 41 ? 39 03",
5,
{0x2E, 0x01, 0x00},
&g.vehicle.ls_customs}); // disable camera
g_script_patcher_service->add_patch(
{"carmod_shop"_J, "carmod_shop1", "2D 02 10 00 00 2C", 5, {0x71, 0x2E, 0x02, 0x01}, &g.vehicle.ls_customs});
g_script_patcher_service->add_patch(
{"carmod_shop"_J, "carmod_shop2", "2D 00 B8 00 00", 5, {0x2E, 0x00, 0x00}, &g.vehicle.ls_customs});
g_script_patcher_service->add_patch({"am_mp_nightclub"_J, "am_mp_nightclub1", "2D 01 03 00 00 2C ? ? ? 56 ? ? 72 2E ? ? 38 00", 5, {0x72, 0x2E, 0x01, 0x01}, &g.self.dance_mode});
g_script_patcher_service->add_patch({"am_mp_nightclub"_J, "am_mp_nightclub2", "20 56 ? ? 4F ? ? 46 ? ? 41 ? 71", 0, {0x2B, 0x55}, &g.self.dance_mode});
g_script_patcher_service->add_patch({"freemode"_J, "freemode9", "5D ? ? ? 56 ? ? 72 39 05 38 04 2C ? ? ? 58", 0, {0x2B, 0x2B, 0x2B, 0x00, 0x55}, &g.self.invisibility});
g_script_patcher_service->add_patch({"freemode"_J, "freemode10", "2D 01 03 00 00 38 00 71 72 5D ? ? ? 06 56 ? ? 71 2E ? ? 2C ? ? ? 71", 5, {0x72, 0x2E, 0x01, 0x01}, &g.session.unhide_players_from_player_list});
g_script_patcher_service->add_patch({"carmod_shop"_J, "disable camera", "2D 01 0A 00 00 4F ? ? 40 ? 41 ? 39 03", 5, {0x2E, 0x01, 0x00}, &g.vehicle.ls_customs}); // disable camera
g_script_patcher_service->add_patch({"carmod_shop"_J, "carmod_shop1", "2D 02 10 00 00 2C", 5, {0x71, 0x2E, 0x02, 0x01}, &g.vehicle.ls_customs});
g_script_patcher_service->add_patch({"carmod_shop"_J, "carmod_shop2", "2D 00 B8 00 00", 5, {0x2E, 0x00, 0x00}, &g.vehicle.ls_customs});
g_script_patcher_service->add_patch({"carmod_shop"_J, "allow all vehicles", "2D 03 16 00 00 5D", 5, {0x72, 0x2E, 0x03, 0x01}, nullptr}); // allow all vehicles
g_script_patcher_service->add_patch({"carmod_shop"_J,
"allow all vehicles 2",
"2D 03 07 00 00 71 38 02",
5,
{0x72, 0x2E, 0x03, 0x01},
nullptr}); // allow all vehicles 2
g_script_patcher_service->add_patch({"carmod_shop"_J, "allow all vehicles 2", "2D 03 07 00 00 71 38 02", 5, {0x72, 0x2E, 0x03, 0x01}, nullptr}); // allow all vehicles 2
for (auto& entry : *g_pointers->m_gta.m_script_program_table)
{

View File

@ -436,6 +436,7 @@ namespace big
bool block_jobs = false;
bool block_muggers = false;
bool block_ceo_raids = false;
bool block_ceo_creation = false;
int send_to_apartment_idx = 1;
int send_to_warehouse_idx = 1;
@ -468,7 +469,7 @@ namespace big
NLOHMANN_DEFINE_TYPE_INTRUSIVE(chat_translator, enabled, print_result, draw_result, bypass_same_language, target_language, endpoint);
} chat_translator{};
NLOHMANN_DEFINE_TYPE_INTRUSIVE(session, log_chat_messages, log_text_messages, decloak_players, force_session_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, join_in_sctv_slots, kick_chat_spammers, kick_host_when_forcing_host, explosion_karma, damage_karma, disable_traffic, disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, block_jobs, block_muggers, block_ceo_raids, send_to_apartment_idx, send_to_warehouse_idx, chat_commands, chat_command_default_access_level, show_cheating_message, anonymous_bounty, lock_session, fast_join, unhide_players_from_player_list, allow_friends_into_locked_session, trust_friends, use_spam_timer, spam_timer, spam_length, chat_translator)
NLOHMANN_DEFINE_TYPE_INTRUSIVE(session, log_chat_messages, log_text_messages, decloak_players, force_session_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, join_in_sctv_slots, kick_chat_spammers, kick_host_when_forcing_host, explosion_karma, damage_karma, disable_traffic, disable_peds, force_thunder, block_ceo_money, randomize_ceo_colors, block_jobs, block_muggers, block_ceo_raids, block_ceo_creation, send_to_apartment_idx, send_to_warehouse_idx, chat_commands, chat_command_default_access_level, show_cheating_message, anonymous_bounty, lock_session, fast_join, unhide_players_from_player_list, allow_friends_into_locked_session, trust_friends, use_spam_timer, spam_timer, spam_length, chat_translator)
} session{};
struct settings
@ -709,10 +710,13 @@ namespace big
bool spoof_session_player_count = false;
int session_player_count = 25;
int spoof_session_bad_sport_status = 0;
bool multiplex_session = false;
int multiplex_count = 2;
bool increase_player_limit = false;
bool voice_chat_audio = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(spoofing, hide_from_player_list, spoof_blip, blip_type, spoof_rank, rank, spoof_job_points, job_points, spoof_kd_ratio, kd_ratio, spoof_bad_sport, badsport_type, spoof_player_model, player_model, spoof_cheater, spoof_hide_god, spoof_hide_veh_god, spoof_hide_spectate, spoof_crew_data, crew_tag, rockstar_crew, square_crew_tag, spoof_session_region_type, session_region_type, spoof_session_language, session_language, spoof_session_player_count, session_player_count, spoof_session_bad_sport_status, voice_chat_audio)
NLOHMANN_DEFINE_TYPE_INTRUSIVE(spoofing, hide_from_player_list, spoof_blip, blip_type, spoof_rank, rank, spoof_job_points, job_points, spoof_kd_ratio, kd_ratio, spoof_bad_sport, badsport_type, spoof_player_model, player_model, spoof_cheater, spoof_hide_god, spoof_hide_veh_god, spoof_hide_spectate, spoof_crew_data, crew_tag, rockstar_crew, square_crew_tag, spoof_session_region_type, session_region_type, spoof_session_language, session_language, spoof_session_player_count, session_player_count, spoof_session_bad_sport_status, multiplex_session, multiplex_count, increase_player_limit, voice_chat_audio)
} spoofing{};
struct vehicle

View File

@ -232,8 +232,6 @@ namespace big
PVOID m_http_start_request;
PVOID m_send_session_matchmaking_attributes;
PVOID m_serialize_take_off_ped_variation_task;
PVOID m_serialize_parachute_task;
@ -374,6 +372,13 @@ namespace big
PVOID m_can_send_node_to_player;
PVOID m_write_node;
functions::get_sector_data m_get_sector_data;
PVOID m_advertise_session;
PVOID m_update_session_advertisement;
PVOID m_unadvertise_session;
PVOID m_send_session_detail_msg;
PVOID m_session_request_patch;
};
#pragma pack(pop)
static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned");

View File

@ -84,8 +84,6 @@ namespace big
detour_hook_helper::add<hooks::broadcast_net_array>("BNA", g_pointers->m_gta.m_broadcast_net_array);
detour_hook_helper::add<hooks::send_session_matchmaking_attributes>("SSMA", g_pointers->m_gta.m_send_session_matchmaking_attributes);
detour_hook_helper::add<hooks::serialize_take_off_ped_variation_task>("STOPVT", g_pointers->m_gta.m_serialize_take_off_ped_variation_task);
detour_hook_helper::add<hooks::serialize_parachute_task>("SPT", g_pointers->m_gta.m_serialize_parachute_task);
@ -137,6 +135,12 @@ namespace big
detour_hook_helper::add<hooks::format_int>("FI", g_pointers->m_gta.m_format_int);
detour_hook_helper::add<hooks::searchlight_crash>("SLC", g_pointers->m_gta.m_searchlight_crash);
detour_hook_helper::add<hooks::advertise_session>("AS", g_pointers->m_gta.m_advertise_session);
detour_hook_helper::add<hooks::update_session_advertisement>("USA", g_pointers->m_gta.m_update_session_advertisement);
detour_hook_helper::add<hooks::unadvertise_session>("US", g_pointers->m_gta.m_unadvertise_session);
detour_hook_helper::add<hooks::send_session_detail_msg>("SSDM", g_pointers->m_gta.m_send_session_detail_msg);
detour_hook_helper::add<hooks::write_node_data>("WND", g_pointers->m_gta.m_write_node_data);
detour_hook_helper::add<hooks::can_send_node_to_player>("CSNTP", g_pointers->m_gta.m_can_send_node_to_player);

View File

@ -39,6 +39,7 @@ class GtaThread;
class CNetworkPlayerMgr;
class CNetworkObjectMgr;
class CPhysicalScriptGameStateDataNode;
class MatchmakingId;
enum class eAckCode : uint32_t;
@ -58,6 +59,7 @@ namespace rage
class json_serializer;
class netGameEvent;
class netSyncDataNode;
class rlSessionDetailMsg;
}
namespace big
@ -125,8 +127,6 @@ namespace big
static unsigned int broadcast_net_array(rage::netArrayHandlerBase* _this, CNetGamePlayer* target, rage::datBitBuffer* bit_buffer, uint16_t counter, uint32_t* elem_start, bool silent);
static bool send_session_matchmaking_attributes(void* a1, rage::rlSessionInfo* info, uint64_t session_id, bool use_session_id, MatchmakingAttributes* attributes);
static void serialize_take_off_ped_variation_task(ClonedTakeOffPedVariationInfo* info, rage::CSyncDataBase* serializer);
static void serialize_parachute_task(__int64 info, rage::CSyncDataBase* serializer);
@ -195,6 +195,11 @@ namespace big
static bool can_send_node_to_player(void* node, rage::netObject* object, std::uint8_t player, int sync_type, int a5, int a6);
static bool write_node(rage::netSyncDataNode* node, int sync_type, int a3, rage::netObject* object, rage::datBitBuffer* buffer, int a6, void* log, std::uint8_t player, int* a9, int* a10);
static void searchlight_crash(void* a1, CPed* ped);
static bool advertise_session(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);
static bool update_session_advertisement(int profile_index, MatchmakingId* id, int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* data, rage::rlTaskStatus* status);
static bool unadvertise_session(int profile_index, MatchmakingId* id, rage::rlTaskStatus* status);
static void send_session_detail_msg(rage::netConnectionManager* mgr, rage::netConnection::InFrame* request_frame, rage::rlSessionDetailMsg* msg);
};
class minhook_keepalive

View File

@ -0,0 +1,16 @@
#include "hooking/hooking.hpp"
#include "services/matchmaking/matchmaking_service.hpp"
#include <network/MatchmakingId.hpp>
namespace big
{
bool hooks::advertise_session(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 (g_matchmaking_service) [[likely]]
if (g_matchmaking_service->handle_advertise(num_slots, available_slots, info, data, out_id, status))
return true;
return g_hooking->get_original<hooks::advertise_session>()(profile_index, num_slots, available_slots, data, session_id, info, out_id, status);
}
}

View File

@ -0,0 +1,13 @@
#include "hooking/hooking.hpp"
#include "services/matchmaking/matchmaking_service.hpp"
namespace big
{
void hooks::send_session_detail_msg(rage::netConnectionManager* mgr, rage::netConnection::InFrame* request_frame, rage::rlSessionDetailMsg* msg)
{
if (g_matchmaking_service) [[likely]]
g_matchmaking_service->handle_session_detail_send_response(msg);
g_hooking->get_original<hooks::send_session_detail_msg>()(mgr, request_frame, msg);
}
}

View File

@ -0,0 +1,21 @@
#include "hooking/hooking.hpp"
#include "services/matchmaking/matchmaking_service.hpp"
#include <network/MatchmakingId.hpp>
namespace big
{
bool hooks::unadvertise_session(int profile_index, MatchmakingId* id, rage::rlTaskStatus* status)
{
if (g_matchmaking_service) [[likely]]
{
if (g_matchmaking_service->handle_unadvertise(id))
{
status->status = 2; // nope
return true;
}
}
return g_hooking->get_original<hooks::unadvertise_session>()(profile_index, id, status);
}
}

View File

@ -0,0 +1,21 @@
#include "hooking/hooking.hpp"
#include "services/matchmaking/matchmaking_service.hpp"
#include <network/MatchmakingId.hpp>
namespace big
{
bool hooks::update_session_advertisement(int profile_index, MatchmakingId* id, int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* data, rage::rlTaskStatus* status)
{
if (g_matchmaking_service) [[likely]]
g_matchmaking_service->handle_update(num_slots, available_slots, info, data, id);
if (g.spoofing.increase_player_limit)
{
num_slots = 30;
available_slots = std::max(1, available_slots);
}
return g_hooking->get_original<hooks::update_session_advertisement>()(profile_index, id, num_slots, available_slots, info, data, status);
}
}

View File

@ -125,8 +125,9 @@ namespace big
break;
case eRemoteEvent::Crash3:
{
if (isnan(*(float*)&args[4]) || isnan(*(float*)&args[5]))
if (isnan(*(float*)&args[3]) || isnan(*(float*)&args[4]) || isnan(*(float*)&args[5]))
{
session::add_infraction(plyr, Infraction::TRIED_CRASH_PLAYER);
g.reactions.crash.process(plyr);
return true;
}

View File

@ -1,25 +0,0 @@
#include "hooking/hooking.hpp"
#include "network/Network.hpp"
namespace big
{
bool hooks::send_session_matchmaking_attributes(void* a1, rage::rlSessionInfo* info, uint64_t session_id, bool use_session_id, MatchmakingAttributes* attributes)
{
if (g.spoofing.spoof_session_region_type)
attributes->m_param_values[4] = g.spoofing.session_region_type;
if (g.spoofing.spoof_session_language)
attributes->m_param_values[3] = g.spoofing.session_language;
if (g.spoofing.spoof_session_player_count)
attributes->m_param_values[7] = g.spoofing.session_player_count;
if (g.spoofing.spoof_session_bad_sport_status == 1)
attributes->m_param_values[0] |= (1 << 14); // Bad Sport
if (g.spoofing.spoof_session_bad_sport_status == 2)
attributes->m_param_values[0] &= ~(1 << 14); // Good Sport
return g_hooking->get_original<hooks::send_session_matchmaking_attributes>()(a1, info, session_id, use_session_id, attributes);
}
}

View File

@ -27,7 +27,7 @@ namespace big
"48 83 EC 28 83 3D ? ? ? ? ? 75 10",
[](memory::handle ptr)
{
g_pointers->m_gta.m_region_code = ptr.add(16).rip().add(1).as<uint32_t*>();
g_pointers->m_gta.m_region_code = ptr.add(16).rip().as<uint32_t*>();
}
},
// Ocean Quads
@ -806,15 +806,6 @@ namespace big
g_pointers->m_gta.m_broadcast_net_array = ptr.as<PVOID>();
}
},
// Send Session Matchmaking Attributes
{
"SSMA",
"48 8B C4 48 89 58 08 48 89 68 10 48 89 70 18 48 89 78 20 41 56 48 81 EC D0 00 00 00 49 8B",
[](memory::handle ptr)
{
g_pointers->m_gta.m_send_session_matchmaking_attributes = ptr.as<PVOID>();
}
},
// Serialize Take Off Ped Variation Task
{
"STOPVT",
@ -1776,6 +1767,51 @@ namespace big
{
g_pointers->m_gta.m_get_sector_data = ptr.as<functions::get_sector_data>();
}
},
// Advertise Session
{
"AS",
"F6 D8 1B C9 83 C1 05 EB 43",
[](memory::handle ptr)
{
g_pointers->m_gta.m_advertise_session = ptr.sub(4).rip().as<PVOID>();
}
},
// Update Session Advertisement
{
"USA",
"84 C0 74 0A 44 89 43 30",
[](memory::handle ptr)
{
g_pointers->m_gta.m_update_session_advertisement = ptr.sub(0xA).rip().as<PVOID>();
}
},
// Unadvertise Session
{
"US",
"EB 21 B9 01 00 00 00 87 4B 28",
[](memory::handle ptr)
{
g_pointers->m_gta.m_unadvertise_session = ptr.sub(4).rip().as<PVOID>();
}
},
// Send Session Detail Msg
{
"SSDM",
"4C 8D 85 F0 01 00 00 49 8B D5", // unstable
[](memory::handle ptr)
{
g_pointers->m_gta.m_send_session_detail_msg = ptr.add(0xE).rip().as<PVOID>();
}
},
// Session Request Patch
{
"SRP",
"48 8B 9D 60 01 00 00 E9 FF 00 00 00",
[](memory::handle ptr)
{
g_pointers->m_gta.m_session_request_patch = ptr.add(0x13).as<PVOID>();
}
}
>(); // don't leave a trailing comma at the end

View File

@ -3,6 +3,7 @@
#include "hooking/hooking.hpp"
#include "pointers.hpp"
#include "script.hpp"
#include "fiber_pool.hpp"
#include <network/Network.hpp>
@ -18,6 +19,30 @@ namespace big
g_matchmaking_service = nullptr;
}
void matchmaking_service::patch_matchmaking_attributes(MatchmakingAttributes* attributes)
{
if (g.spoofing.spoof_session_region_type)
attributes->m_param_values[4] = g.spoofing.session_region_type;
if (g.spoofing.spoof_session_language)
attributes->m_param_values[3] = g.spoofing.session_language;
if (g.spoofing.spoof_session_player_count && g.spoofing.increase_player_limit)
attributes->m_param_values[2] = std::min(29, g.spoofing.session_player_count);
else if (g.spoofing.spoof_session_player_count)
attributes->m_param_values[2] = g.spoofing.session_player_count;
else if (g.spoofing.increase_player_limit)
attributes->m_param_values[2] = std::min(29u, attributes->m_param_values[2]);
// TODO: the logic is incorrect
if (g.spoofing.spoof_session_bad_sport_status == 1)
attributes->m_param_values[0] |= (1 << 14); // Bad Sport
if (g.spoofing.spoof_session_bad_sport_status == 2)
attributes->m_param_values[0] &= ~(1 << 14); // Good Sport
}
bool matchmaking_service::matchmake(std::optional<int> constraint)
{
for (auto& session : m_found_sessions)
@ -113,4 +138,170 @@ namespace big
m_active = false;
return false;
}
bool matchmaking_service::handle_advertise(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* out_id, rage::rlTaskStatus* status)
{
patch_matchmaking_attributes(attributes);
if (!g.spoofing.multiplex_session)
return false;
if (status->status)
return true;
status->status = 1; // set in progress
// create the first advertisement
g_fiber_pool->queue_job([this, num_slots, available_slots, info, attributes, out_id, status] {
rage::rlTaskStatus our_status{};
if (!g_hooking->get_original<hooks::advertise_session>()(0, num_slots, available_slots, attributes, -1, info, out_id, &our_status))
{
LOG(WARNING) << __FUNCTION__ ": advertise_session returned false for first advertisement";
status->status = 2;
return;
}
while (our_status.status == 1)
script::get_current()->yield();
if (our_status.status == 2)
{
LOG(WARNING) << __FUNCTION__ ": advertise_session failed for first advertisement";
status->status = 2;
return;
}
MatchmakingId primary_id = *out_id; // create a copy if the original memory gets deallocated
std::uint32_t id_hash = rage::joaat(primary_id.m_data1);
// m_data1 is generated from m_data2 and m_data3
m_multiplexed_sessions.emplace(id_hash, std::vector<MatchmakingId>{ });
// create multiplex advertisements
for (int i = 0; i < (g.spoofing.multiplex_count - 1); i++)
{
g_fiber_pool->queue_job([this, num_slots, available_slots, info, attributes, id_hash, i] {
rage::rlTaskStatus status;
MatchmakingId multiplexed_id;
if (!g_hooking->get_original<hooks::advertise_session>()(0, num_slots, available_slots, attributes, -1, info, &multiplexed_id, &status))
{
LOG(WARNING) << __FUNCTION__ ": advertise_session returned false for multiplex task " << i;
return;
}
while (status.status == 1)
script::get_current()->yield();
if (status.status == 2)
{
LOG(WARNING) << __FUNCTION__ ": advertise_session failed for multiplex task " << i;
return;
}
if (auto it = m_multiplexed_sessions.find(id_hash); it != m_multiplexed_sessions.end())
{
it->second.push_back(multiplexed_id);
}
else
{
LOG(WARNING) << __FUNCTION__ ": created a multiplexed session advertisement, but the primary advertisement no longer exists";
}
});
}
status->status = 3; // return success for original caller
});
return true;
}
void matchmaking_service::handle_update(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* id)
{
patch_matchmaking_attributes(attributes);
// this can be fire and forget, but it's probably a good idea to be notified if something goes wrong
if (auto it = m_multiplexed_sessions.find(rage::joaat(id->m_data1)); it != m_multiplexed_sessions.end())
{
if (!g.spoofing.multiplex_session)
{
// option disabled mid-session
return;
}
int i = 0;
for (auto& multiplex_session : it->second)
{
g_fiber_pool->queue_job([&multiplex_session, num_slots, available_slots, info, attributes, i] {
rage::rlTaskStatus status;
if (!g_hooking->get_original<hooks::update_session_advertisement>()(0, &multiplex_session, num_slots, available_slots, info, attributes, &status))
{
LOG(WARNING) << __FUNCTION__ ": update_session_advertisement returned false for multiplex task " << i;
return;
}
while (status.status == 1)
script::get_current()->yield();
if (status.status == 2)
{
LOG(WARNING) << __FUNCTION__ ": update_session_advertisement failed for multiplex task " << i;
return;
}
});
i++;
}
}
}
bool matchmaking_service::handle_unadvertise(MatchmakingId* id)
{
if (auto it = m_multiplexed_sessions.find(rage::joaat(id->m_data1)); it != m_multiplexed_sessions.end())
{
for (auto& multiplex_session : it->second)
{
g_hooking->get_original<hooks::unadvertise_session>()(0, &multiplex_session, nullptr);
}
m_multiplexed_sessions.erase(it);
return false;
}
else
{
if (g.spoofing.multiplex_session)
{
for (auto& [_, children] : m_multiplexed_sessions)
{
for (auto& session : children)
{
if (session.m_data2 == id->m_data2 && session.m_data3 == id->m_data3)
{
return true; // prevent auto cleanup
}
}
}
}
}
return false;
}
void matchmaking_service::handle_session_detail_send_response(rage::rlSessionDetailMsg* msg)
{
if (msg->m_status == 5)
{
if (g.spoofing.increase_player_limit)
{
msg->m_detail.m_player_count = std::min(29,
g.spoofing.spoof_session_player_count ? g.spoofing.session_player_count : (int)msg->m_detail.m_player_count);
msg->m_detail.m_spectator_count = 0;
msg->m_detail.m_session_config.m_public_slots = 30;
msg->m_detail.m_session_config.m_private_slots = 2;
}
patch_matchmaking_attributes(&msg->m_detail.m_session_config.m_matchmaking_attributes);
}
else
{
LOG(WARNING) << __FUNCTION__ ": sending fail code " << msg->m_status;
}
}
}

View File

@ -1,5 +1,16 @@
#pragma once
#include <network/MatchmakingId.hpp>
#include <rage/rlTaskStatus.hpp>
namespace rage
{
class rlSessionInfo;
class rlSessionDetailMsg;
}
class MatchmakingAttributes;
namespace big
{
class matchmaking_service
@ -26,12 +37,20 @@ namespace big
int m_num_sessions_found = 0;
bool m_active = false;
session m_found_sessions[MAX_SESSIONS_TO_FIND];
std::unordered_map<std::uint32_t, std::vector<MatchmakingId>> m_multiplexed_sessions;
void patch_matchmaking_attributes(MatchmakingAttributes* attributes);
public:
matchmaking_service();
~matchmaking_service();
bool matchmake(std::optional<int> constraint = std::nullopt);
bool handle_advertise(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* out_id, rage::rlTaskStatus* status);
void handle_update(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* id);
bool handle_unadvertise(MatchmakingId* id);
void handle_session_detail_send_response(rage::rlSessionDetailMsg* msg);
inline int get_num_found_sessions()
{
return m_num_sessions_found;

View File

@ -603,6 +603,8 @@ namespace big
components::script_patch_checkbox("BLOCK_MUGGERS"_T, &g.session.block_muggers, "BLOCK_MUGGERS_DESC"_T.data());
components::script_patch_checkbox("BLOCK_CEO_RAIDS"_T, &g.session.block_ceo_raids, "BLOCK_CEO_RAIDS_DESC"_T);
ImGui::SameLine();
components::command_checkbox<"blockceos">();
ImGui::EndGroup();
}

View File

@ -156,5 +156,15 @@ namespace big
ImGui::RadioButton("VIEW_SPOOFING_SPORT_GOOD"_T.data(), &g.spoofing.spoof_session_bad_sport_status, 1);
ImGui::SameLine();
ImGui::RadioButton("VIEW_SPOOFING_SPORT_BAD"_T.data(), &g.spoofing.spoof_session_bad_sport_status, 2);
ImGui::Checkbox("MULTIPLEX_SESSION"_T.data(), &g.spoofing.multiplex_session);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("MULTIPLEX_SESSION_DESC"_T.data());
if (g.spoofing.multiplex_session)
{
ImGui::SameLine();
ImGui::SliderInt("###multiplex_cnt", &g.spoofing.multiplex_count, 2, 5);
}
components::command_checkbox<"32players">();
}
}