Session multiplexer and more (#3167)
This commit is contained in:
parent
0393c5d391
commit
c180694199
@ -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 ""
|
||||
|
46
src/backend/looped/session/block_ceo_creation.cpp
Normal file
46
src/backend/looped/session/block_ceo_creation.cpp
Normal 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);
|
||||
}
|
32
src/backend/looped/session/increase_player_limit.cpp
Normal file
32
src/backend/looped/session/increase_player_limit.cpp
Normal 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);
|
||||
}
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
16
src/hooks/matchmaking/advertise_session.cpp
Normal file
16
src/hooks/matchmaking/advertise_session.cpp
Normal 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);
|
||||
}
|
||||
}
|
13
src/hooks/matchmaking/create_session_detail_response.cpp
Normal file
13
src/hooks/matchmaking/create_session_detail_response.cpp
Normal 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);
|
||||
}
|
||||
}
|
21
src/hooks/matchmaking/unadvertise_session.cpp
Normal file
21
src/hooks/matchmaking/unadvertise_session.cpp
Normal 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);
|
||||
}
|
||||
}
|
21
src/hooks/matchmaking/update_session_advertisement.cpp
Normal file
21
src/hooks/matchmaking/update_session_advertisement.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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">();
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user