Menu revamp (#3274)

* Complete player and network UI redesign, meant to show all features instead of stuffing them into tiny boxes
* Added option to delete player vehicles
* Better clone player (now clones head blend too)
* Better host token spoofing, with an option to enter your own
* Better host token spoofing detection
* Better desync kick prot detections
* A script blocker for the entire session (per-player options will be added later)
* Added option to spoof data/DLC hashes
* Logging framework that allows developers to easily debug false positives
* Major protection improvements
This commit is contained in:
maybegreat48 2024-06-27 08:32:17 +00:00 committed by GitHub
parent f3cf7b5983
commit 4589b87553
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
98 changed files with 3157 additions and 2042 deletions

View File

@ -6,7 +6,7 @@ message("AsyncLogger")
FetchContent_Declare( FetchContent_Declare(
AsyncLogger AsyncLogger
GIT_REPOSITORY https://github.com/Yimura/AsyncLogger.git GIT_REPOSITORY https://github.com/Yimura/AsyncLogger.git
GIT_TAG 80ce938277acd44767f858099920ae20f1df42ca GIT_TAG 6fcfd90b3f4ca4dae09c4a96e9a506e6aea06472
GIT_PROGRESS TRUE GIT_PROGRESS TRUE
) )
FetchContent_MakeAvailable(AsyncLogger) FetchContent_MakeAvailable(AsyncLogger)

View File

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

View File

@ -124,6 +124,7 @@ namespace big
looped::session_force_thunder(); looped::session_force_thunder();
looped::session_randomize_ceo_colors(); looped::session_randomize_ceo_colors();
looped::session_auto_kick_host(); looped::session_auto_kick_host();
looped::session_force_script_host();
looped::session_block_jobs(); looped::session_block_jobs();
looped::session_chat_translator(); looped::session_chat_translator();
looped::session_modder_detection(); looped::session_modder_detection();

View File

@ -74,7 +74,7 @@ namespace big
{ {
m_toggle = true; m_toggle = true;
m_last_enabled = true; m_last_enabled = true;
g_fiber_pool->queue_job([this] { g_fiber_pool->execute_on_game_thread([this] {
on_enable(); on_enable();
}); });
} }
@ -86,7 +86,7 @@ namespace big
{ {
m_toggle = false; m_toggle = false;
m_last_enabled = false; m_last_enabled = false;
g_fiber_pool->queue_job([this] { g_fiber_pool->execute_on_game_thread([this] {
on_disable(); on_disable();
}); });
} }
@ -97,14 +97,14 @@ namespace big
if (m_toggle && !m_last_enabled) if (m_toggle && !m_last_enabled)
{ {
m_last_enabled = true; m_last_enabled = true;
g_fiber_pool->queue_job([this] { g_fiber_pool->execute_on_game_thread([this] {
on_enable(); on_enable();
}); });
} }
else if (!m_toggle && m_last_enabled) else if (!m_toggle && m_last_enabled)
{ {
m_last_enabled = false; m_last_enabled = false;
g_fiber_pool->queue_job([this] { g_fiber_pool->execute_on_game_thread([this] {
on_disable(); on_disable();
}); });
} }

View File

@ -18,7 +18,8 @@ namespace big
if (!player->get_ped()) if (!player->get_ped())
return; return;
g_pointers->m_gta.m_send_network_damage(g_player_service->get_self()->get_ped(), g_pointers->m_gta.m_send_network_damage(
g_player_service->get_self()->get_ped(),
player->get_ped(), player->get_ped(),
player->get_ped()->m_navigation->get_position(), player->get_ped()->m_navigation->get_position(),
0, 0,
@ -27,7 +28,7 @@ namespace big
10000.0f, 10000.0f,
2, 2,
0, 0,
(1 << 4), (1 << 4) | 0x80000,
0, 0,
0, 0,
0, 0,

View File

@ -24,7 +24,7 @@ namespace big
int64_t args[arg_count] = {(int64_t)eRemoteEvent::StartScriptBegin, (int64_t)self::id, 1 << player->id()}; int64_t args[arg_count] = {(int64_t)eRemoteEvent::StartScriptBegin, (int64_t)self::id, 1 << player->id()};
args[3] = scriptId; args[3] = scriptId;
strcpy((char*)&args[2 + 3], "0"); strcpy((char*)&args[3 + 3], "0");
args[3 + 16] = -1; args[3 + 16] = -1;
args[3 + 17] = 1337; args[3 + 17] = 1337;
args[3 + 19] = arg19; args[3 + 19] = arg19;

View File

@ -118,7 +118,6 @@ namespace big
if (!stack || !net_component) if (!stack || !net_component)
return; return;
((CGameScriptHandlerNetComponent*)thread->m_net_component)->block_host_migration(true);
thread->m_context.m_state = rage::eThreadState::unk_3; thread->m_context.m_state = rage::eThreadState::unk_3;
g.m_hunt_the_beast_thread = thread; g.m_hunt_the_beast_thread = thread;

View File

@ -0,0 +1,27 @@
#include "backend/player_command.hpp"
#include "natives.hpp"
#include "pointers.hpp"
#include "util/entity.hpp"
namespace big
{
class delete_vehicle : player_command
{
using player_command::player_command;
virtual void execute(player_ptr player, const command_arguments& _args, const std::shared_ptr<command_context> ctx) override
{
auto object = player->get_current_vehicle();
if (object)
entity::force_remove_network_entity(object);
else if (player->get_ped())
{
auto net_id = *(int16_t*)(((__int64)player->get_ped()->m_net_object) + 0x3D8); // TODO: extract offset
if (net_id)
entity::force_remove_network_entity(net_id);
}
}
};
delete_vehicle g_delete_vehicle("deleteveh", "BACKEND_DELETE_VEHICLE", "BACKEND_DELETE_VEHICLE_DESC", 0);
}

View File

@ -35,6 +35,7 @@ namespace big
static void session_block_jobs(); static void session_block_jobs();
static void session_randomize_ceo_colors(); static void session_randomize_ceo_colors();
static void session_auto_kick_host(); static void session_auto_kick_host();
static void session_force_script_host();
static void session_chat_translator(); static void session_chat_translator();
static void session_modder_detection(); static void session_modder_detection();

View File

@ -29,8 +29,6 @@ namespace big
g.m_dance_thread = gta_util::find_script_thread_by_id(thread); g.m_dance_thread = gta_util::find_script_thread_by_id(thread);
g.m_dance_program = gta_util::find_script_program("am_mp_nightclub"_J); g.m_dance_program = gta_util::find_script_program("am_mp_nightclub"_J);
(*g_pointers->m_gta.m_script_handler_mgr)->attach_thread(g.m_dance_thread);
g.m_dance_thread->m_context.m_state = rage::eThreadState::unk_3; g.m_dance_thread->m_context.m_state = rage::eThreadState::unk_3;
// perform initial setup // perform initial setup

View File

@ -8,8 +8,8 @@ namespace big
static bool bLastKickHost = false; static bool bLastKickHost = false;
void looped::session_auto_kick_host() void looped::session_auto_kick_host()
{ {
bool kick_host = *g_pointers->m_gta.m_is_session_started && g.session.force_session_host && g.session.kick_host_when_forcing_host; bool kick_host = false; // *g_pointers->m_gta.m_is_session_started && g.session.force_session_host && g.session.kick_host_when_forcing_host;
if (kick_host && !bLastKickHost) if (kick_host && !bLastKickHost) [[unlikely]]
{ {
g_player_service->iterate([](auto& plyr) { g_player_service->iterate([](auto& plyr) {
// Don't kick trusted players // Don't kick trusted players

View File

@ -0,0 +1,63 @@
#include "backend/looped/looped.hpp"
#include "backend/player_command.hpp"
#include "natives.hpp"
#include "pointers.hpp"
#include "gta_util.hpp"
#include "gta/script_handler.hpp"
#include "gta/net_array.hpp"
#include "packet.hpp"
namespace big
{
void looped::session_force_script_host()
{
if (!g.session.force_script_host)
return;
static bool loaded_into_session = false;
if (!*g_pointers->m_gta.m_is_session_started)
{
loaded_into_session = false;
return;
}
if (!loaded_into_session)
{
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) == 0) [[unlikely]]
{
if (auto freemode = gta_util::find_script_thread("freemode"_J); freemode && freemode->m_net_component)
{
auto net_component = reinterpret_cast<CGameScriptHandlerNetComponent*>(freemode->m_net_component);
int num_synced_arrays = 0;
for (int i = 0; i < net_component->m_host_array_count; i++)
{
if ((g_pointers->m_gta.m_get_host_array_handler_by_index(net_component, i)->m_flags & 1) != 0)
num_synced_arrays++;
}
if (num_synced_arrays == net_component->m_host_array_count)
{
net_component->do_host_migration(g_player_service->get_self()->get_net_game_player(), 0xFFFF, true);
packet pack;
pack.write_message(rage::eNetMessage::MsgScriptVerifyHostAck);
net_component->m_script_handler->get_id()->serialize(&pack.m_buffer);
pack.write<bool>(true, 1);
pack.write<bool>(true, 1);
pack.write<std::uint16_t>(0xFFFF, 16);
for (auto& player : g_player_service->players())
{
if (player.second->get_net_game_player())
pack.send(player.second->get_net_game_player()->m_msg_id);
}
loaded_into_session = true;
}
}
}
}
}
}

View File

@ -0,0 +1,104 @@
#include "backend/looped/looped.hpp"
#include "backend/looped_command.hpp"
#include "pointers.hpp"
#include "gta_util.hpp"
#include "util/math.hpp"
#include <network/Network.hpp>
#include <network/CCommunications.hpp>
namespace big
{
void set_peer_id_upper(std::uint64_t upper)
{
*g_pointers->m_gta.m_peer_id &= 0xFFFFFFFF;
*g_pointers->m_gta.m_peer_id |= (upper << 32);
if (gta_util::get_network()->m_game_session_ptr)
gta_util::get_network()->m_game_session_ptr->m_local_player.m_player_data.m_peer_id = *g_pointers->m_gta.m_peer_id;
if (gta_util::get_network()->m_transition_session_ptr)
gta_util::get_network()->m_transition_session_ptr->m_local_player.m_player_data.m_peer_id = *g_pointers->m_gta.m_peer_id;
g_pointers->m_gta.m_profile_gamer_info->m_peer_id = *g_pointers->m_gta.m_peer_id;
g_pointers->m_gta.m_player_info_gamer_info->m_peer_id = *g_pointers->m_gta.m_peer_id;
(*g_pointers->m_gta.m_communications)->m_voice.m_connections[0]->m_gamer_info.m_peer_id = *g_pointers->m_gta.m_peer_id;
if (g_local_player && g_local_player->m_player_info)
g_local_player->m_player_info->m_net_player_data.m_peer_id = *g_pointers->m_gta.m_peer_id;
}
void set_host_token(std::uint64_t token)
{
*g_pointers->m_gta.m_host_token = token;
if (gta_util::get_network()->m_game_session_ptr)
gta_util::get_network()->m_game_session_ptr->m_local_player.m_player_data.m_host_token = token;
if (gta_util::get_network()->m_transition_session_ptr)
gta_util::get_network()->m_transition_session_ptr->m_local_player.m_player_data.m_host_token = token;
g_pointers->m_gta.m_profile_gamer_info->m_host_token = token;
g_pointers->m_gta.m_player_info_gamer_info->m_host_token = token;
(*g_pointers->m_gta.m_communications)->m_voice.m_connections[0]->m_gamer_info.m_host_token = token;
if (g_local_player && g_local_player->m_player_info)
g_local_player->m_player_info->m_net_player_data.m_host_token = token;
set_peer_id_upper(token >> 32);
}
class spoof_host_token_internal : looped_command
{
using looped_command::looped_command;
virtual void on_enable() override
{
g.session.original_host_token = *g_pointers->m_gta.m_host_token;
}
virtual void on_tick() override
{
if (g.session.spoof_host_token_dirty && gta_util::get_network()->m_game_session_state == 0)
{
switch (g.session.spoof_host_token_type)
{
case 0: // Disabled
{
set_host_token(g.session.original_host_token);
break;
}
case 1: // Legit
{
std::uint64_t rand_upper = math::rand(20, 230);
set_host_token(((g.session.original_host_token) & 0xFFFFFFFF) | (rand_upper << 32));
break;
}
case 2: // Aggressive
{
set_host_token(math::rand(10, 1000));
break;
}
case 3: // Very aggressive
{
set_host_token(0);
break;
}
case 4: // Custom
{
set_host_token(g.session.custom_host_token);
break;
}
}
g.session.spoof_host_token_dirty = false;
}
}
virtual void on_disable() override
{
if (g.session.original_host_token)
set_host_token(g.session.original_host_token);
}
};
static bool true_ref = true;
spoof_host_token_internal g_spoof_host_token_internal("$$spoofhosttoken", "", "", true_ref);
}

View File

@ -0,0 +1,20 @@
#include "backend/looped_command.hpp"
#include "pointers.hpp"
#include "hooking/hooking.hpp"
namespace big
{
class copy_current_dlc_hash : command
{
using command::command;
virtual void execute(const command_arguments&, const std::shared_ptr<command_context> ctx) override
{
g.spoofing.dlc_hash = g_hooking->get_original<hooks::get_dlc_hash>()(*g_pointers->m_gta.m_dlc_manager, 0);
}
};
bool_command
g_spoof_dlc_hash("spoofdlchash", "SPOOF_DLC_HASH", "SPOOF_DLC_HASH_DESC", g.spoofing.spoof_dlc_hash);
copy_current_dlc_hash g_copy_current_dlc_hash("storedlchash", "COPY_CURRENT_DLC_HASH", "COPY_CURRENT_DLC_HASH_DESC", 0);
}

View File

@ -0,0 +1,69 @@
#include "backend/looped_command.hpp"
#include "pointers.hpp"
#include <game_files/GameDataHash.hpp>
namespace
{
static std::array<std::uint32_t, 15> orig_hash;
void store_data(std::array<std::uint32_t, 15>& data)
{
for (int i = 0; i < 15; i++)
{
data[i] = (*big::g_pointers->m_gta.m_game_data_hash)->m_data[i];
}
}
void load_data(const std::array<std::uint32_t, 15>& data)
{
for (int i = 0; i < 15; i++)
{
(*big::g_pointers->m_gta.m_game_data_hash)->m_data[i] = data[i];
}
}
}
namespace big
{
class spoof_game_data_hash : looped_command
{
using looped_command::looped_command;
virtual void on_enable() override
{
store_data(orig_hash);
}
virtual void on_tick() override
{
if (g.spoofing.game_data_hash_dirty)
{
load_data(g.spoofing.game_data_hash);
g.spoofing.game_data_hash_dirty = false;
}
}
virtual void on_disable() override
{
load_data(orig_hash);
}
};
class copy_current_game_data_hash : command
{
using command::command;
virtual void execute(const command_arguments&, const std::shared_ptr<command_context> ctx) override
{
if (g.spoofing.spoof_game_data_hash)
g.spoofing.game_data_hash = orig_hash;
else
store_data(g.spoofing.game_data_hash);
g.spoofing.game_data_hash_dirty = true;
}
};
spoof_game_data_hash g_spoof_game_data_hash("spoofdatahash", "SPOOF_GAME_DATA_HASH", "SPOOF_GAME_DATA_HASH_DESC", g.spoofing.spoof_game_data_hash);
copy_current_game_data_hash g_copy_current_game_data_hash("storecurrenthash", "COPY_CURRENT_GAME_DATA_HASH", "COPY_CURRENT_GAME_DATA_HASH_DESC", 0);
}

View File

@ -14,28 +14,6 @@ namespace big
static bool bLastForceHost = false; static bool bLastForceHost = false;
void looped::system_spoofing() void looped::system_spoofing()
{ {
if (bLastForceHost != g.session.force_session_host && gta_util::get_network()->m_game_session_state == 0)
{
uint64_t host_token;
g_pointers->m_gta.m_generate_uuid(&host_token);
host_token = g.session.force_session_host ? math::rand(10000) : host_token;
*g_pointers->m_gta.m_host_token = host_token;
if (gta_util::get_network()->m_game_session_ptr)
gta_util::get_network()->m_game_session_ptr->m_local_player.m_player_data.m_host_token = host_token;
g_pointers->m_gta.m_profile_gamer_info->m_host_token = host_token;
g_pointers->m_gta.m_player_info_gamer_info->m_host_token = host_token;
(*g_pointers->m_gta.m_communications)->m_voice.m_connections[0]->m_gamer_info.m_host_token = host_token;
if (g_local_player && g_local_player->m_player_info)
g_local_player->m_player_info->m_net_player_data.m_host_token = host_token;
bLastForceHost = g.session.force_session_host;
}
if (*g_pointers->m_gta.m_is_session_started) if (*g_pointers->m_gta.m_is_session_started)
{ {
gta_util::execute_as_script("freemode"_J, [] { gta_util::execute_as_script("freemode"_J, [] {

View File

@ -3,6 +3,7 @@
#include "fiber_pool.hpp" #include "fiber_pool.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "script.hpp"
namespace big namespace big
{ {

View File

@ -2,7 +2,9 @@
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "natives.hpp" #include "natives.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "util/math.hpp"
#include <numbers> #include <numbers>
namespace big namespace big
{ {
class aimbot : looped_command class aimbot : looped_command

View File

@ -2,6 +2,7 @@
#include "core/enums.hpp" #include "core/enums.hpp"
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "natives.hpp"
namespace big namespace big
{ {

View File

@ -4,7 +4,9 @@
#include "script.hpp" #include "script.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "util/math.hpp"
#include <numbers> #include <numbers>
namespace big namespace big
{ {
static timer spawning_axe_delay(200ms); static timer spawning_axe_delay(200ms);

View File

@ -2,6 +2,8 @@
#include "core/enums.hpp" #include "core/enums.hpp"
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "util/math.hpp"
#include "natives.hpp"
namespace big namespace big
{ {

View File

@ -2,6 +2,8 @@
#include "core/enums.hpp" #include "core/enums.hpp"
#include "gta/enums.hpp" #include "gta/enums.hpp"
#include "util/entity.hpp" #include "util/entity.hpp"
#include "natives.hpp"
#include "script.hpp"
namespace big namespace big
{ {

View File

@ -24,6 +24,8 @@ namespace big
// Patch blocked explosions // Patch blocked explosions
explosion_anti_cheat_bypass::m_can_blame_others = explosion_anti_cheat_bypass::m_can_blame_others =
memory::byte_patch::make(g_pointers->m_gta.m_blame_explode.as<uint16_t*>(), 0xE990).get(); memory::byte_patch::make(g_pointers->m_gta.m_blame_explode.as<uint16_t*>(), 0xE990).get();
explosion_anti_cheat_bypass::m_set_script_flag =
memory::byte_patch::make(g_pointers->m_gta.m_blame_explode.sub(0x12).as<uint32_t*>(), 0x90909090).get();
explosion_anti_cheat_bypass::m_can_use_blocked_explosions = explosion_anti_cheat_bypass::m_can_use_blocked_explosions =
memory::byte_patch::make(g_pointers->m_gta.m_explosion_patch.sub(12).as<uint16_t*>(), 0x9090).get(); memory::byte_patch::make(g_pointers->m_gta.m_explosion_patch.sub(12).as<uint16_t*>(), 0x9090).get();

File diff suppressed because it is too large Load Diff

View File

@ -26,5 +26,6 @@ namespace big
// So that lua scripts can add a custom runtime reason. // So that lua scripts can add a custom runtime reason.
CUSTOM_REASON, CUSTOM_REASON,
CHAT_SPAM, CHAT_SPAM,
SENT_MODDER_BEACONS
}; };
} }

View File

@ -17,7 +17,7 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
{"MsgConfigResponse", 0x5F}, {"MsgConfigResponse", 0x5F},
{"MsgConfigRequest", 0x48}, {"MsgConfigRequest", 0x48},
{"MsgChangeSessionAttributesCmd", 0x5A}, {"MsgChangeSessionAttributesCmd", 0x5A},
{"MsgAddGamerToSessionCmd", 0x6}, {"MsgAddGamerToSessionCmd", 0x64},
{"MsgReassignResponse", 0x10}, {"MsgReassignResponse", 0x10},
{"MsgReassignNegotiate", 0x01}, {"MsgReassignNegotiate", 0x01},
{"MsgReassignConfirm", 0x26}, {"MsgReassignConfirm", 0x26},
@ -88,8 +88,8 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
{"MsgRoamingInitialBubble", 0x32}, {"MsgRoamingInitialBubble", 0x32},
{"MsgVoiceStatus", 0x03}, {"MsgVoiceStatus", 0x03},
{"MsgTextChatStatus", 0x00}, {"MsgTextChatStatus", 0x00},
{"MsgJoinResponse2", 0x08}, {"MsgSnJoinResponse", 0x08},
{"MsgJoinRequest2", 0x68}, {"MsgSnJoinRequest", 0x68},
{"MsgNetTimeSync", 0x38}, {"MsgNetTimeSync", 0x38},
{"MsgNetComplaint", 0x55}, {"MsgNetComplaint", 0x55},
{"MsgNetLagPing", 0x27}, {"MsgNetLagPing", 0x27},
@ -107,8 +107,15 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
{"Msg_0x88", 0x88}, {"Msg_0x88", 0x88},
{"Msg_0x80", 0x80}, {"Msg_0x80", 0x80},
{"Msg_0x28", 0x28}, {"Msg_0x28", 0x28},
{"Msg_0x11", 0x11}, {"MsgNatTunnelerResponse", 0x11},
{"MsgNatTunnelerRequest", 0x15},
{"MsgNatTunnelerUnk", 0x7F},
{"Msg_0x45", 0x45}, {"Msg_0x45", 0x45},
{"Msg_0x89", 0x89}, {"Msg_0x89", 0x89},
{"Msg_0x86", 0x86}, {"Msg_0x86", 0x86},
{"MsgDtlsCxnCommand", 0x8A},
{"MsgSetKickVote", 0x8E},
{"MsgTransitionHandshake", 0x8D},
{"MsgDidInvitePlayerRequest", 0x8B},
{"MsgDidInvitePlayerResponse", 0x8C},
}; };

View File

@ -10,12 +10,12 @@ namespace big
const RegionType regions[] = { const RegionType regions[] = {
{0, "CIS"}, {0, "CIS"},
{1, "Africa"}, {1, "South America"},
{2, "East"}, {2, "US East"},
{3, "Europe"}, {3, "Europe"},
{4, "China"}, {4, "China"},
{5, "Australia"}, {5, "Australia"},
{6, "West"}, {6, "US West"},
{7, "Japan"}, {7, "Japan"},
{8, "Unknown"}, {8, "Unknown"},
}; };

View File

@ -83,6 +83,30 @@ namespace big
rage::scrThread* m_mission_creator_thread = nullptr; rage::scrThread* m_mission_creator_thread = nullptr;
struct script_block_opts
{
bool lsc = false;
bool atms = false;
bool interiors = false;
bool drones = false;
bool strip_club = false;
bool ammunation = false;
bool stores = false;
bool sitting = false;
bool sleeping = false;
bool casino_games = false;
bool arcade_games = false;
bool prostitutes = false;
bool movies = false;
bool street_dealer = false;
bool impromptu_dm = false;
bool impromptu_race = false;
bool gang_attacks = false;
bool vending_machines = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(script_block_opts, lsc, atms, interiors, drones, strip_club, ammunation, stores, sitting, sleeping, casino_games, arcade_games, prostitutes, movies, street_dealer, impromptu_dm, impromptu_race, gang_attacks, vending_machines);
};
struct cmd_executor struct cmd_executor
{ {
bool enabled = false; bool enabled = false;
@ -126,8 +150,9 @@ namespace big
bool external_console = true; bool external_console = true;
bool window_hook = false; bool window_hook = false;
bool block_all_metrics = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(debug, logs, external_console, window_hook) NLOHMANN_DEFINE_TYPE_INTRUSIVE(debug, logs, external_console, window_hook, block_all_metrics)
} debug{}; } debug{};
struct tunables struct tunables
@ -179,12 +204,13 @@ namespace big
struct reactions struct reactions
{ {
// first constructor param is an internal identifier for the event // first constructor param is an internal identifier for the event
// it's never shown in the UI
reaction bounty{"Bounty", "REACTION_BOUNTY_NOTIFY", "REACTION_BOUNTY_ANNOUNCE"}; reaction bounty{"Bounty", "REACTION_BOUNTY_NOTIFY", "REACTION_BOUNTY_ANNOUNCE"};
reaction break_game{"Break Game", "REACTION_BREAK_GAME_NOTIFY", "REACTION_BREAK_GAME_ANNOUNCE"};
reaction ceo_kick{"CEO Kick", "REACTION_CEO_KICK_NOTIFY", "REACTION_CEO_KICK_ANNOUNCE"}; reaction ceo_kick{"CEO Kick", "REACTION_CEO_KICK_NOTIFY", "REACTION_CEO_KICK_ANNOUNCE"};
reaction ceo_money{"CEO Money", "REACTION_CEO_MONEY_NOTIFY", "REACTION_CEO_MONEY_ANNOUNCE"}; reaction ceo_money{"CEO Money", "REACTION_CEO_MONEY_NOTIFY", "REACTION_CEO_MONEY_ANNOUNCE"};
reaction clear_wanted_level{"Clear Wanted Level", "REACTION_CLEAR_WANTED_LEVEL_NOTIFY", "REACTION_CLEAR_WANTED_LEVEL_ANNOUNCE"}; reaction clear_wanted_level{"Clear Wanted Level", "REACTION_CLEAR_WANTED_LEVEL_NOTIFY", "REACTION_CLEAR_WANTED_LEVEL_ANNOUNCE"};
reaction crash{"Crash", "REACTION_CRASH_NOTIFY", "REACTION_CRASH_ANNOUNCE"}; reaction crash{"Crash", "REACTION_CRASH_NOTIFY", "REACTION_CRASH_ANNOUNCE"};
reaction delete_vehicle{"Delete Vehicle", "REACTION_DELETE_VEHICLE_NOTIFY", "REACTION_DELETE_VEHICLE_ANNOUNCE"};
reaction end_session_kick{"End Session Kick", "REACTION_END_SESSION_KICK_NOTIFY", "REACTION_GENERIC_KICK_ANNOUNCE"}; reaction end_session_kick{"End Session Kick", "REACTION_END_SESSION_KICK_NOTIFY", "REACTION_GENERIC_KICK_ANNOUNCE"};
reaction fake_deposit{"Fake Deposit", "REACTION_FAKE_DEPOSIT_NOTIFY", "REACTION_FAKE_DEPOSIT_ANNOUNCE"}; reaction fake_deposit{"Fake Deposit", "REACTION_FAKE_DEPOSIT_NOTIFY", "REACTION_FAKE_DEPOSIT_ANNOUNCE"};
reaction force_mission{"Force Mission", "REACTION_FORCE_MISSION_NOTIFY", "REACTION_FORCE_MISSION_ANNOUNCE"}; reaction force_mission{"Force Mission", "REACTION_FORCE_MISSION_NOTIFY", "REACTION_FORCE_MISSION_ANNOUNCE"};
@ -224,11 +250,11 @@ namespace big
reaction game_anti_cheat_modder_detection{"Game Anti-Cheat Modder Detection", "REACTION_MODDER_DETECTED_BY_ANTICHEAT_GENERIC", "REACTION_MODDER_DETECTED_BY_ANTICHEAT_GENERIC"}; reaction game_anti_cheat_modder_detection{"Game Anti-Cheat Modder Detection", "REACTION_MODDER_DETECTED_BY_ANTICHEAT_GENERIC", "REACTION_MODDER_DETECTED_BY_ANTICHEAT_GENERIC"};
reaction request_control_event{"Request Control Event", "REACTION_REQUEST_CONTROL_NOTIFY", "REACTION_REQUEST_CONTROL_ANNOUNCE"}; reaction request_control_event{"Request Control Event", "REACTION_REQUEST_CONTROL_NOTIFY", "REACTION_REQUEST_CONTROL_ANNOUNCE"};
reaction report{"Report", "REACTION_REPORT_NOTIFY", "REACTION_REPORT_ANNOUNCE"}; reaction report{"Report", "REACTION_REPORT_NOTIFY", "REACTION_REPORT_ANNOUNCE"};
reaction spectate{"Spectate", "REACTION_SPECTATING_NOTIFY", "REACTION_SPECTATING_ANNOUNCE"};
reaction chat_spam{"Chat Spam", "REACTION_CHAT_SPAM_NOTIFY", "REACTION_CHAT_SPAM_ANNOUNCE"}; reaction chat_spam{"Chat Spam", "REACTION_CHAT_SPAM_NOTIFY", "REACTION_CHAT_SPAM_ANNOUNCE"};
reaction spectate{"Spectate", "REACTION_SPECTATING_NOTIFY", "REACTION_SPECTATING_ANNOUNCE"};
interloper_reaction spectate_others{"Spectate Others", "REACTION_SPECTATING_OTHERS_NOTIFY", "REACTION_SPECTATING_OTHERS_ANNOUNCE", false, false}; interloper_reaction spectate_others{"Spectate Others", "REACTION_SPECTATING_OTHERS_NOTIFY", "REACTION_SPECTATING_OTHERS_ANNOUNCE", false, false};
NLOHMANN_DEFINE_TYPE_INTRUSIVE(reactions, bounty, ceo_money, ceo_kick, clear_wanted_level, crash, end_session_kick, fake_deposit, force_mission, force_teleport, gta_banner, kick_from_interior, mc_teleport, network_bail, personal_vehicle_destroyed, remote_off_radar, rotate_cam, send_to_cutscene, send_to_location, sound_spam, spectate_notification, give_collectible, transaction_error, tse_freeze, tse_sender_mismatch, vehicle_kick, teleport_to_warehouse, trigger_business_raid, start_activity, start_script, null_function_kick, destroy_personal_vehicle, clear_ped_tasks, turn_into_beast, remote_wanted_level, remote_wanted_level_others, remote_ragdoll, kick_vote, report_cash_spawn, modder_detection, game_anti_cheat_modder_detection, request_control_event, report, send_to_interior, spectate, chat_spam, spectate_others) NLOHMANN_DEFINE_TYPE_INTRUSIVE(reactions, bounty, ceo_money, ceo_kick, clear_wanted_level, crash, delete_vehicle, end_session_kick, fake_deposit, force_mission, force_teleport, gta_banner, kick_from_interior, mc_teleport, network_bail, personal_vehicle_destroyed, remote_off_radar, rotate_cam, send_to_cutscene, send_to_location, sound_spam, spectate_notification, give_collectible, transaction_error, tse_freeze, tse_sender_mismatch, vehicle_kick, teleport_to_warehouse, trigger_business_raid, start_activity, start_script, null_function_kick, destroy_personal_vehicle, clear_ped_tasks, turn_into_beast, remote_wanted_level, remote_wanted_level_others, remote_ragdoll, kick_vote, report_cash_spawn, modder_detection, game_anti_cheat_modder_detection, request_control_event, report, send_to_interior, chat_spam, spectate, spectate_others)
} reactions{}; } reactions{};
struct player struct player
@ -402,7 +428,9 @@ namespace big
bool log_text_messages = false; bool log_text_messages = false;
bool decloak_players = false; bool decloak_players = false;
bool unhide_players_from_player_list = true; bool unhide_players_from_player_list = true;
bool force_session_host = false; int spoof_host_token_type = 0;
std::uint64_t custom_host_token = 0x000000200235F2EA;
bool hide_token_spoofing_when_host = true;
bool force_script_host = false; bool force_script_host = false;
bool player_magnet_enabled = false; bool player_magnet_enabled = false;
int player_magnet_count = 32; int player_magnet_count = 32;
@ -441,7 +469,11 @@ namespace big
int send_to_apartment_idx = 1; int send_to_apartment_idx = 1;
int send_to_warehouse_idx = 1; int send_to_warehouse_idx = 1;
script_block_opts script_block_opts;
// not to be saved // not to be saved
std::atomic_bool spoof_host_token_dirty = true;
std::uint64_t original_host_token = 0;
bool join_queued = false; bool join_queued = false;
rage::rlSessionInfo info; rage::rlSessionInfo info;
bool never_wanted_all = false; bool never_wanted_all = false;
@ -469,7 +501,7 @@ namespace big
NLOHMANN_DEFINE_TYPE_INTRUSIVE(chat_translator, enabled, print_result, draw_result, bypass_same_language, target_language, endpoint); NLOHMANN_DEFINE_TYPE_INTRUSIVE(chat_translator, enabled, print_result, draw_result, bypass_same_language, target_language, endpoint);
} chat_translator{}; } 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_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) NLOHMANN_DEFINE_TYPE_INTRUSIVE(session, log_chat_messages, log_text_messages, decloak_players, spoof_host_token_type, custom_host_token, hide_token_spoofing_when_host, force_script_host, player_magnet_enabled, player_magnet_count, is_team, join_in_sctv_slots, 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, script_block_opts)
} session{}; } session{};
struct settings struct settings
@ -605,8 +637,9 @@ namespace big
bool spawn_invincible = false; bool spawn_invincible = false;
bool spawn_invisible = false; bool spawn_invisible = false;
bool spawn_as_attacker = false; bool spawn_as_attacker = false;
bool randomize_outfit = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(spawn_ped, preview_ped, spawn_invincible, spawn_invisible, spawn_as_attacker) NLOHMANN_DEFINE_TYPE_INTRUSIVE(spawn_ped, preview_ped, spawn_invincible, spawn_invisible, spawn_as_attacker, randomize_outfit)
} spawn_ped{}; } spawn_ped{};
struct custom_time struct custom_time
@ -716,7 +749,16 @@ namespace big
bool voice_chat_audio = 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, multiplex_session, multiplex_count, increase_player_limit, voice_chat_audio) bool spoof_game_data_hash = false;
std::array<std::uint32_t, 15> game_data_hash{};
bool spoof_dlc_hash = false;
std::uint32_t dlc_hash;
// do not save
bool game_data_hash_dirty = true;
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, spoof_game_data_hash, game_data_hash, spoof_dlc_hash, dlc_hash)
} spoofing{}; } spoofing{};
struct vehicle struct vehicle
@ -1037,13 +1079,15 @@ namespace big
int player_count_filter_minimum = 0; int player_count_filter_minimum = 0;
int player_count_filter_maximum = 32; int player_count_filter_maximum = 32;
bool filter_multiplexed_sessions = false;
int sort_method = 0; int sort_method = 0;
int sort_direction = 0; int sort_direction = 0;
bool replace_game_matchmaking = false; bool replace_game_matchmaking = false;
bool exclude_modder_sessions = false; bool exclude_modder_sessions = false;
NLOHMANN_DEFINE_TYPE_INTRUSIVE(session_browser, region_filter_enabled, region_filter, language_filter_enabled, language_filter, player_count_filter_enabled, player_count_filter_minimum, player_count_filter_maximum, sort_method, sort_direction, replace_game_matchmaking, pool_filter_enabled, pool_filter, exclude_modder_sessions) NLOHMANN_DEFINE_TYPE_INTRUSIVE(session_browser, region_filter_enabled, region_filter, language_filter_enabled, language_filter, player_count_filter_enabled, player_count_filter_minimum, player_count_filter_maximum, filter_multiplexed_sessions, sort_method, sort_direction, replace_game_matchmaking, pool_filter_enabled, pool_filter, exclude_modder_sessions)
} session_browser{}; } session_browser{};
struct session_protection struct session_protection

View File

@ -3,6 +3,7 @@
#include "common.hpp" #include "common.hpp"
#include "script.hpp" #include "script.hpp"
#include "script_mgr.hpp" #include "script_mgr.hpp"
#include <script/tlsContext.hpp>
namespace big namespace big
{ {
@ -31,6 +32,18 @@ namespace big
} }
} }
void fiber_pool::execute_on_game_thread(std::function<void()> func)
{
if (func)
{
if (rage::tlsContext::get()->m_script_thread && rage::tlsContext::get()->m_is_script_thread_active)
func();
else
queue_job(func);
}
}
void fiber_pool::fiber_tick() void fiber_pool::fiber_tick()
{ {
std::unique_lock lock(m_mutex); std::unique_lock lock(m_mutex);

View File

@ -10,6 +10,7 @@ namespace big
~fiber_pool(); ~fiber_pool();
void queue_job(std::function<void()> func); void queue_job(std::function<void()> func);
void execute_on_game_thread(std::function<void()> func);
void fiber_tick(); void fiber_tick();
static void fiber_func(); static void fiber_func();

View File

@ -16,6 +16,7 @@ enum class PedBones : uint16_t;
class CNetComplaintMgr; class CNetComplaintMgr;
class Network; class Network;
class CNetworkObjectMgr; class CNetworkObjectMgr;
class CHeadBlendData;
namespace rage namespace rage
{ {
@ -44,6 +45,7 @@ namespace rage
class fiPackfile; class fiPackfile;
class scrNativeRegistrationTable; class scrNativeRegistrationTable;
class rlSessionByGamerTaskResult; class rlSessionByGamerTaskResult;
class SecurityPeer;
struct rlScTaskStatus struct rlScTaskStatus
{ {
void* pad = 0; void* pad = 0;
@ -164,7 +166,7 @@ namespace big::functions
using sync_network_time = bool (*)(rage::netConnectionManager* mgr, rage::netPeerAddress* addr, int connection_id, rage::netTimeSyncMsg* msg, int flags); using sync_network_time = bool (*)(rage::netConnectionManager* mgr, rage::netPeerAddress* addr, int connection_id, rage::netTimeSyncMsg* msg, int flags);
using send_packet = bool (*)(rage::netConnectionManager* mgr, rage::netPeerAddress* adde, int connection_id, void* data, int size, int flags); using send_packet = bool (*)(rage::netConnectionManager* mgr, rage::netPeerAddress* adde, int connection_id, void* data, int size, int flags);
using connect_to_peer = bool (*)(rage::netConnectionManager* mgr, rage::rlGamerInfoBase* gamer_info, rage::snConnectToPeerTaskData* data, rage::snConnectToPeerTaskResult* result, rage::rlTaskStatus* status); using connect_to_peer = bool (*)(rage::netConnectionManager* mgr, rage::rlGamerHandle* handle, rage::rlGamerInfoBase* gamer_info, rage::snConnectToPeerTaskData* data, rage::snConnectToPeerTaskResult* result, rage::rlTaskStatus* status);
using clear_ped_tasks_network = void (*)(CPed* ped, bool immediately); using clear_ped_tasks_network = void (*)(CPed* ped, bool immediately);
@ -215,4 +217,8 @@ namespace big::functions
using get_searchlight = void* (*) (CPed*); using get_searchlight = void* (*) (CPed*);
using get_sector_data = void (*) (rage::fvector3* coords, std::uint16_t* x, std::uint16_t* y, std::uint16_t* z, rage::fvector3* sector_pos); using get_sector_data = void (*) (rage::fvector3* coords, std::uint16_t* x, std::uint16_t* y, std::uint16_t* z, rage::fvector3* sector_pos);
using get_peer_by_security_id = rage::SecurityPeer*(*)(int id);
using set_head_blend_data = void(*)(CPed* ped, CHeadBlendData* data);
} }

View File

@ -104,7 +104,7 @@ namespace rage
virtual void _0x80() = 0; // virtual void _0x80() = 0; //
virtual void _0x88() = 0; // virtual void _0x88(int) = 0; //
virtual void* get_identifier() = 0; // 0x90 virtual void* get_identifier() = 0; // 0x90
@ -130,7 +130,7 @@ namespace rage
virtual void verify_array_data() = 0; // 0xE8 virtual void verify_array_data() = 0; // 0xE8
virtual void _0xF0() = 0; // virtual void verify_array_data_ack(CNetGamePlayer* player, int) = 0; //
virtual char* get_name() = 0; // 0xF8 virtual char* get_name() = 0; // 0xF8

View File

@ -73,7 +73,7 @@ namespace rage
{ {
return m_bitsRead; return m_bitsRead;
} }
bool Seek(uint32_t bits) void Seek(uint32_t bits)
{ {
if (bits >= 0) if (bits >= 0)
{ {
@ -81,7 +81,12 @@ namespace rage
if (bits <= length) if (bits <= length)
m_bitsRead = bits; m_bitsRead = bits;
} }
return false; }
void SeekForward(uint32_t bits)
{
m_bitsRead += static_cast<uint32_t>(bits);
if (m_bitsRead > m_highestBitsRead)
m_highestBitsRead = m_bitsRead;
} }
bool WriteBool(bool boolean) bool WriteBool(bool boolean)
{ {
@ -244,10 +249,11 @@ namespace rage
template<typename T> template<typename T>
inline T Read(int length) inline T Read(int length)
{ {
static_assert(sizeof(T) <= 4, "maximum of 32 bit read"); static_assert(sizeof(T) <= 8, "maximum of 64 bit read");
static_assert(!std::is_same_v<T, float>, "use ReadFloat to read floating point values from the bitbuffer");
uint32_t val = 0; uint64_t val = 0;
ReadDword(&val, length); ReadQWord(&val, length);
return T(val); return T(val);
} }
@ -256,6 +262,7 @@ namespace rage
inline T ReadSigned(int length) inline T ReadSigned(int length)
{ {
static_assert(sizeof(T) <= 4, "maximum of 32 bit read"); static_assert(sizeof(T) <= 4, "maximum of 32 bit read");
static_assert(!std::is_same_v<T, float>, "use ReadSignedFloat to read signed floating point values from the bitbuffer");
int val = 0; int val = 0;
ReadInt32(&val, length); ReadInt32(&val, length);

View File

@ -108,8 +108,8 @@ namespace rage
virtual void PackCloneCreate(netObject* object, CNetGamePlayer* player, datBitBuffer* buffer) = 0; virtual void PackCloneCreate(netObject* object, CNetGamePlayer* player, datBitBuffer* buffer) = 0;
virtual bool PackCloneRemove(netObject* object, CNetGamePlayer* player, bool) = 0; virtual bool PackCloneRemove(netObject* object, CNetGamePlayer* player, bool) = 0;
virtual void PackCloneSync(netObject* object, CNetGamePlayer* player) = 0;
virtual void _0x78(netObject* object, void*) = 0;
virtual void _0x80() = 0; virtual void _0x80() = 0;
virtual void _0x88() = 0; virtual void _0x88() = 0;
virtual const char* _0x90(int) = 0; virtual const char* _0x90(int) = 0;

View File

@ -9,10 +9,10 @@ int CGameScriptHandlerNetComponent::get_participant_index(CNetGamePlayer* player
if (player == (*big::g_pointers->m_gta.m_network_player_mgr)->m_local_net_player) if (player == (*big::g_pointers->m_gta.m_network_player_mgr)->m_local_net_player)
return m_local_participant_index; return m_local_participant_index;
if (m_num_participants <= 1) if (m_max_participants <= 1)
return -1; return -1;
for (int i = 0; i < m_num_participants - 1; i++) for (int i = 0; i < m_max_participants - 1; i++)
{ {
if (m_participants[i] && m_participants[i]->m_net_game_player == player) if (m_participants[i] && m_participants[i]->m_net_game_player == player)
return m_participants[i]->m_participant_index; return m_participants[i]->m_participant_index;

View File

@ -4,264 +4,7 @@
#include "script/scriptIdBase.hpp" #include "script/scriptIdBase.hpp"
#include "script/scriptResource.hpp" #include "script/scriptResource.hpp"
#include "script/scriptHandler.hpp" #include "script/scriptHandler.hpp"
#include "script/scriptHandlerMgr.hpp"
#include "script/scriptHandlerNetComponent.hpp" #include "script/scriptHandlerNetComponent.hpp"
#include "script/CGameScriptHandler.hpp"
#include <cstdint> #include "script/CGameScriptHandlerNetComponent.hpp"
#pragma pack(push, 1)
namespace rage
{
class scriptResourceEntry
{
public:
scriptResource* m_data; // 0x00
uint32_t m_unk; // 0x04
char m_padding[0x0C]; // 0x0C
scriptResourceEntry* m_next;// 0x18
};
class scriptHandlerMgr
{
public:
virtual ~scriptHandlerMgr() = default;
// Initializes some scripting-related pools.
virtual bool initialize() = 0;// 1 (0x08)
// Called every tick.
virtual void _0x10() = 0;// 2 (0x10)
// Frees some scripting-related pools.
virtual void shutdown() = 0;// 3 (0x18)
virtual void _0x20() = 0;// 4 (0x20)
virtual void _0x28() = 0;// 5 (0x28)
virtual void _0x30() = 0;// 6 (0x30)
// Generates a rage::scriptId from the thread and copies it over to a global structure.
virtual void _0x38(scrThread*) = 0;// 7 (0x38)
// Allocates and constructs a script handler.
virtual scriptHandler* create_script_handler() = 0;// 8 (0x40)
// Finds the script handler for a given script id.
virtual scriptHandler* get_script_handler(scriptId*) = 0;// 9 (0x48)
// Attaches a script thread.
virtual void attach_thread(scrThread*) = 0;// 10 (0x50)
// Detaches a script thread.
virtual void detach_thread(scrThread*) = 0;// 11 (0x58)
// Called when a player joins.
virtual void on_player_join(netPlayer*) = 0;// 12 (0x60)
// Called when a player leaves.
virtual void on_player_left(netPlayer*) = 0;// 13 (0x68)
virtual std::int32_t _0x70() = 0;// 14 (0x70)
virtual void* _0x78() = 0;// 15 (0x78)
public:
char pad_0008[104];
};
}
class CGameScriptHandler : public rage::scriptHandler
{
public:
CGameScriptId m_script_id;// 0x60
};
class CGameScriptHandlerNetwork : public CGameScriptHandler
{
public:
uint8_t m_0xA0; // 0xA0
uint8_t m_0xA1; // 0xA1
uint8_t m_0xA2; // 0xA2
uint8_t m_0xA3; // 0xA3
uint8_t m_num_players;// 0xA4
uint8_t m_0xA5; // 0xA5
uint8_t m_0xA6; // 0xA6
uint8_t m_0xA7; // 0xA7
uint8_t m_0xA8; // 0xA8
uint8_t m_0xA9; // 0xA9
uint8_t m_0xAA; // 0xAA
uint8_t m_0xAB; // 0xAB
uint8_t m_0xAC; // 0xAC
uint8_t m_0xAD; // 0xAD
uint8_t m_0xAE; // 0xAE
uint8_t m_0xAF; // 0xAF
};
class CScriptParticipant
{
public:
char pad_0000[16]; //0x0000
class CNetGamePlayer* m_net_game_player;//0x0010
char pad_0018[2]; //0x0018
int16_t m_participant_index; //0x001A
char pad_001C[12]; //0x001C
}; //Size: 0x0028
static_assert(sizeof(CScriptParticipant) == 0x28);
class CGameScriptHandlerNetComponent
{
public:
virtual ~CGameScriptHandlerNetComponent() = default;
virtual bool _0x08(void*) = 0;
virtual void _0x10(CNetGamePlayer*) = 0;// creates a scriptId?
virtual void* player_left(CNetGamePlayer* player) = 0;
virtual void* send_host_migration_event(CNetGamePlayer* player) = 0;
virtual void* player_joined(void**, void* msg_ctx) = 0;
virtual void* player_joined_ack(void**, void* msg_ctx) = 0;
virtual bool _0x38(void*, void*) = 0;// join_script?
virtual void* _0x40(void*, void*) = 0;
virtual void* _0x48(void*, void*, void*) = 0;
virtual void* _0x50(void*, void*) = 0;
virtual void* _0x58(void*, void*) = 0;
virtual void* _0x60(void*, void*) = 0;
virtual void* _0x68(void*, void*) = 0;
virtual void _0x70(void*, void*) = 0;
virtual void _0x78(void*, void*) = 0;
virtual short _0x80(void*, void*) = 0;
virtual void* _0x88(void*, void*) = 0;
virtual void* _0x90(void*, void*) = 0;// HOST_MIGRATION_FAILED
virtual bool _0x98(void*, void*) = 0;
virtual void* _0xA0(void*, void*) = 0;
virtual void* _0xA8(void*, void*) = 0;
virtual short _0xB0(void*, void*) = 0;
virtual bool register_host_broadcast_data(void* data, int size, char* a3) = 0;
virtual bool register_player_broadcast_data(int a1, int size, bool a3) = 0;
virtual bool _0xC8() = 0;// something to do to joining session
virtual bool _0xD0() = 0;
virtual bool add_player_to_script(CNetGamePlayer* player, short* outParticipantID, short* outSlot, int* outFailReason) = 0;
virtual bool add_player_to_script_internal(CNetGamePlayer* player, short participantID, short slot) = 0;// player aka participant
virtual bool remove_player_from_script(CNetGamePlayer* player) = 0;
virtual void* player_left_impl(CNetGamePlayer*, bool) = 0;
virtual bool do_host_migration(CNetGamePlayer* player, short host_token, bool unk) = 0;// aka _0xF8
virtual void* leave_from_script() = 0;// calls above function with player = nullptr
virtual bool _0x108() = 0;
virtual void* _0x110() = 0;
virtual bool _0x118() = 0;// related to above function
CGameScriptHandler* m_script_handler; //0x0008
char pad_0010[32]; //0x0010
class CScriptParticipant* m_host; //0x0030
int16_t m_local_participant_index; //0x0038
char pad_003A[6]; //0x003A
uint32_t m_participant_bitset; //0x0040
char pad_0044[36]; //0x0044
class CScriptParticipant* m_participants[32];//0x0068
char pad_0168[12]; //0x0168
int16_t m_num_participants; //0x0174
char pad_0176[28]; //0x0176
uint8_t m_host_migration_flags; //0x0192
char pad_0193[29]; //0x0193
int get_participant_index(CNetGamePlayer* player);
bool is_player_a_participant(CNetGamePlayer* player);
inline bool is_local_player_host()
{
if (!m_host)
return true;// or return false?
return m_host->m_participant_index == m_local_participant_index;
}
inline CNetGamePlayer* get_host()
{
if (!m_host)
return nullptr;
return m_host->m_net_game_player;
}
// not 100% foolproof
inline void block_host_migration(bool toggle)
{
if (toggle)
m_host_migration_flags |= (1 << 7);
else
m_host_migration_flags &= ~(1 << 7);
}
};//Size: 0x01B0
static_assert(sizeof(CGameScriptHandlerNetComponent) == 0x1B0);
class CRemoteScriptInfo : public CGameScriptId
{
public:
uint32_t m_participants; //0x0040
char pad_0044[4]; //0x0044
class CNetGamePlayer* m_host;//0x0048
uint32_t m_timestamp_2; //0x0050
uint16_t m_host_token; //0x0054
uint8_t m_reserved_peds; //0x0056
uint8_t m_reserved_vehicles; //0x0057
uint8_t m_reserved_objects; //0x0058
uint8_t m_reserved_unk1; //0x0059
uint8_t m_reserved_unk2; //0x005A
uint8_t m_reserved_unk3; //0x005B
uint8_t m_reserved_unk4; //0x005C
char pad_005D[3]; //0x005D
}; //Size: 0x0060
static_assert(sizeof(CRemoteScriptInfo) == 0x60);
class CGameScriptHandlerMgr : public rage::scriptHandlerMgr
{
public:
char pad_0070[56]; //0x0070
class CRemoteScriptInfo m_remote_script_infos[320]; //0x00A8
char pad_78A8[4]; //0x78A8
uint32_t m_remote_script_start_idx; //0x78AC
uint32_t m_remote_script_count; //0x78B0
char pad_78B4[4]; //0x78B4
class CRemoteScriptInfo m_detached_remote_script_infos[64];//0x78B8
char pad_90B8[4]; //0x90B8
uint32_t m_detached_remote_script_start_idx; //0x90BC
uint32_t m_detached_remote_script_count; //0x90C0
char pad_90C4[28]; //0x90C4
}; //Size: 0x90E0
static_assert(sizeof(CGameScriptHandlerMgr) == 0x90E0);
static_assert(sizeof(rage::scriptHandler) == 0x60);
static_assert(sizeof(CGameScriptHandler) == 0xA0);
static_assert(sizeof(CGameScriptHandlerNetwork) == 0xB0);
#pragma pack(pop)

View File

@ -20,6 +20,7 @@ class CWeaponInfoManager;
class CGameScriptHandlerMgr; class CGameScriptHandlerMgr;
class CPedFactory; class CPedFactory;
class GtaThread; class GtaThread;
class GameDataHash;
namespace rage namespace rage
{ {
@ -195,6 +196,7 @@ namespace big
functions::generate_uuid m_generate_uuid; functions::generate_uuid m_generate_uuid;
uint64_t* m_host_token; uint64_t* m_host_token;
uint64_t* m_peer_id;
rage::rlGamerInfo* m_profile_gamer_info; // per profile gamer info rage::rlGamerInfo* m_profile_gamer_info; // per profile gamer info
rage::rlGamerInfo* m_player_info_gamer_info; // the gamer info that is applied to CPlayerInfo rage::rlGamerInfo* m_player_info_gamer_info; // the gamer info that is applied to CPlayerInfo
CCommunications** m_communications; CCommunications** m_communications;
@ -377,6 +379,23 @@ namespace big
PVOID m_send_session_detail_msg; PVOID m_send_session_detail_msg;
PVOID m_session_request_patch; PVOID m_session_request_patch;
functions::get_peer_by_security_id m_get_peer_by_security_id;
GameDataHash** m_game_data_hash;
void** m_dlc_manager;
PVOID m_get_dlc_hash;
PVOID m_add_gamer_to_session;
functions::set_head_blend_data m_set_head_blend_data;
std::uint32_t* m_object_ids_offset;
PVOID m_error_packet_memmove;
PVOID m_create_pool_item;
}; };
#pragma pack(pop) #pragma pack(pop)
static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned"); static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned");

View File

@ -7,6 +7,11 @@
#include <ped/CPedFactory.hpp> #include <ped/CPedFactory.hpp>
#include <script/scrProgramTable.hpp> #include <script/scrProgramTable.hpp>
namespace rage
{
class netObjectIds;
}
namespace big::gta_util namespace big::gta_util
{ {
inline CPed* get_local_ped() inline CPed* get_local_ped()
@ -54,6 +59,14 @@ namespace big::gta_util
return *g_pointers->m_gta.m_network; return *g_pointers->m_gta.m_network;
} }
inline rage::netObjectIds* get_net_object_ids()
{
if (!*g_pointers->m_gta.m_network_object_mgr)
return nullptr;
return (rage::netObjectIds*)(((std::uintptr_t)*g_pointers->m_gta.m_network_object_mgr) + *g_pointers->m_gta.m_object_ids_offset); // TODO: map out CNetworkObjectMgr eventually
}
template<typename F, typename... Args> template<typename F, typename... Args>
void execute_as_script(rage::scrThread* thread, F&& callback, Args&&... args) void execute_as_script(rage::scrThread* thread, F&& callback, Args&&... args)
{ {

View File

@ -2,11 +2,15 @@
#include "pointers.hpp" #include "pointers.hpp"
#include <player/CNonPhysicalPlayerData.hpp>
#include <network/CNetGamePlayer.hpp>
namespace big namespace big
{ {
hooking::hooking() : hooking::hooking() :
m_swapchain_hook(*g_pointers->m_gta.m_swapchain, hooks::swapchain_num_funcs), m_swapchain_hook(*g_pointers->m_gta.m_swapchain, hooks::swapchain_num_funcs),
m_sync_data_reader_hook(g_pointers->m_gta.m_sync_data_reader_vtable, 27) m_sync_data_reader_hook(g_pointers->m_gta.m_sync_data_reader_vtable, 27),
m_error_packet_memmove_hook(g_pointers->m_gta.m_error_packet_memmove, hooks::error_packet_memmove)
{ {
m_swapchain_hook.hook(hooks::swapchain_present_index, &hooks::swapchain_present); m_swapchain_hook.hook(hooks::swapchain_present_index, &hooks::swapchain_present);
m_swapchain_hook.hook(hooks::swapchain_resizebuffers_index, &hooks::swapchain_resizebuffers); m_swapchain_hook.hook(hooks::swapchain_resizebuffers_index, &hooks::swapchain_resizebuffers);
@ -140,11 +144,17 @@ namespace big
detour_hook_helper::add<hooks::update_session_advertisement>("USA", g_pointers->m_gta.m_update_session_advertisement); 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::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::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::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); detour_hook_helper::add<hooks::can_send_node_to_player>("CSNTP", g_pointers->m_gta.m_can_send_node_to_player);
detour_hook_helper::add<hooks::write_node>("WN", g_pointers->m_gta.m_write_node); detour_hook_helper::add<hooks::write_node>("WN", g_pointers->m_gta.m_write_node);
detour_hook_helper::add<hooks::get_dlc_hash>("GDLCH", g_pointers->m_gta.m_get_dlc_hash);
detour_hook_helper::add<hooks::add_gamer_to_session>("AGTS", g_pointers->m_gta.m_add_gamer_to_session);
detour_hook_helper::add<hooks::create_pool_item>("CPI", g_pointers->m_gta.m_create_pool_item);
g_hooking = this; g_hooking = this;
} }
@ -162,6 +172,7 @@ namespace big
{ {
m_swapchain_hook.enable(); m_swapchain_hook.enable();
m_sync_data_reader_hook.enable(); m_sync_data_reader_hook.enable();
m_error_packet_memmove_hook.enable();
m_og_wndproc = WNDPROC(SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, LONG_PTR(&hooks::wndproc))); m_og_wndproc = WNDPROC(SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, LONG_PTR(&hooks::wndproc)));
for (auto& detour_hook_helper : m_detour_hook_helpers) for (auto& detour_hook_helper : m_detour_hook_helpers)
@ -184,6 +195,7 @@ namespace big
} }
SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_og_wndproc)); SetWindowLongPtrW(g_pointers->m_hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(m_og_wndproc));
m_error_packet_memmove_hook.disable();
m_sync_data_reader_hook.disable(); m_sync_data_reader_hook.disable();
m_swapchain_hook.disable(); m_swapchain_hook.disable();

View File

@ -3,6 +3,7 @@
#include "detour_hook.hpp" #include "detour_hook.hpp"
#include "vmt_hook.hpp" #include "vmt_hook.hpp"
#include "vtable_hook.hpp" #include "vtable_hook.hpp"
#include "call_hook.hpp"
#include <gta/enums.hpp> #include <gta/enums.hpp>
#include <network/netConnection.hpp> // cannot stub this #include <network/netConnection.hpp> // cannot stub this
@ -40,6 +41,8 @@ class CNetworkPlayerMgr;
class CNetworkObjectMgr; class CNetworkObjectMgr;
class CPhysicalScriptGameStateDataNode; class CPhysicalScriptGameStateDataNode;
class MatchmakingId; class MatchmakingId;
class CMsgJoinRequest;
class GenericPool;
enum class eAckCode : uint32_t; enum class eAckCode : uint32_t;
@ -60,6 +63,7 @@ namespace rage
class netGameEvent; class netGameEvent;
class netSyncDataNode; class netSyncDataNode;
class rlSessionDetailMsg; class rlSessionDetailMsg;
class netEvent;
} }
namespace big namespace big
@ -94,7 +98,7 @@ namespace big
static bool increment_stat_event(CNetworkIncrementStatEvent* net_event_struct, CNetGamePlayer* sender); static bool increment_stat_event(CNetworkIncrementStatEvent* net_event_struct, CNetGamePlayer* sender);
static bool scripted_game_event(CScriptedGameEvent* scripted_game_event, CNetGamePlayer* player); static bool scripted_game_event(CScriptedGameEvent* scripted_game_event, CNetGamePlayer* player);
static bool receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame); static bool receive_net_message(void* a1, rage::netConnectionManager* mgr, rage::netEvent* event);
static rage::CEventNetwork* get_network_event_data(int64_t unk, rage::CEventNetwork* net_event); static rage::CEventNetwork* get_network_event_data(int64_t unk, rage::CEventNetwork* net_event);
static void* assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index); static void* assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index);
@ -121,7 +125,7 @@ namespace big
static bool process_matchmaking_find_response(void* _this, void* unused, rage::JSONNode* node, int* unk); static bool process_matchmaking_find_response(void* _this, void* unused, rage::JSONNode* node, int* unk);
static bool serialize_join_request_message(RemoteGamerInfoMsg* info, void* data, int size, int* bits_serialized); static bool serialize_join_request_message(RemoteGamerInfoMsg* info, void* data, int size, int* bits_serialized);
static bool serialize_join_request_message_2(__int64 msg, void* buf, int size, int* bits_serialized); static bool serialize_join_request_message_2(CMsgJoinRequest* msg, void* buf, int size, int* bits_serialized);
static bool start_matchmaking_find_sessions(int profile_index, int available_slots, NetworkGameFilterMatchmakingComponent* filter, unsigned int max_sessions, rage::rlSessionInfo* results, int* num_sessions_found, rage::rlTaskStatus* status); static bool start_matchmaking_find_sessions(int profile_index, int available_slots, NetworkGameFilterMatchmakingComponent* filter, unsigned int max_sessions, rage::rlSessionInfo* results, int* num_sessions_found, rage::rlTaskStatus* status);
@ -200,6 +204,13 @@ namespace big
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 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 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); static void send_session_detail_msg(rage::netConnectionManager* mgr, rage::netConnection::InFrame* request_frame, rage::rlSessionDetailMsg* msg);
static std::uint32_t get_dlc_hash(void* mgr, std::uint32_t seed);
static bool add_gamer_to_session(rage::netConnectionManager* mgr, std::uint32_t msg_id, int* req_id, RemoteGamerInfoMsg* info, int flags, void* a6);
static void error_packet_memmove(void* dst, void* src, int size);
static void* create_pool_item(GenericPool* pool);
}; };
class minhook_keepalive class minhook_keepalive
@ -290,6 +301,8 @@ namespace big
vmt_hook m_swapchain_hook; vmt_hook m_swapchain_hook;
vtable_hook m_sync_data_reader_hook; vtable_hook m_sync_data_reader_hook;
call_hook m_error_packet_memmove_hook;
WNDPROC m_og_wndproc = nullptr; WNDPROC m_og_wndproc = nullptr;
static inline std::vector<detour_hook_helper> m_detour_hook_helpers; static inline std::vector<detour_hook_helper> m_detour_hook_helpers;

View File

@ -5,51 +5,53 @@
namespace big namespace big
{ {
const auto warn_bad_metrics = std::unordered_set<std::string_view>({ const auto warn_bad_metrics = std::unordered_set<std::string_view>({
"REPORTER", "REPORTER",
"REPORT_INVALIDMODEL", "REPORT_INVALIDMODEL",
"MEM_NEW", "MEM_NEW",
"DEBUGGER_ATTACH", "DEBUGGER_ATTACH",
"XP_LOSS", "XP_LOSS",
"CF", "CF",
"CC", "CC",
"CNR", "CNR",
"SCRIPT", "SCRIPT",
"CHEAT", "CHEAT",
"AUX_DEUX", "AUX_DEUX",
"HARDWARE_OS", "HARDWARE_OS",
"HARDWARE_GPU", "HARDWARE_GPU",
"HARDWARE_MOBO", "HARDWARE_MOBO",
"HARDWARE_MEM", "HARDWARE_MEM",
"HARDWARE_CPU", "HARDWARE_CPU",
"PCSETTINGS", "PCSETTINGS",
"CASH_CREATED", "CASH_CREATED",
"DR_PS", "DR_PS",
"IDLEKICK", "IDLEKICK",
"GSCB", "GSCB",
"GSINV", "GSINV",
"GSCW", "GSCW",
"GSINT", "GSINT",
"GARAGE_TAMPER", "GARAGE_TAMPER",
"DUPE_DETECT", "DUPE_DETECT",
"LAST_VEH", "LAST_VEH",
"FAIL_SERV", "FAIL_SERV",
"CCF_UPDATE", "CCF_UPDATE",
"CODE_CRC", "CODE_CRC",
"MM", "MM",
"RDEV", "RDEV",
"RQA", "RQA",
}); });
const auto filtered_bad_metrics = std::unordered_set<std::string_view>({ const auto filtered_bad_metrics = std::unordered_set<std::string_view>({
"DIG", "DIG",
"AWARD_XP", "AWARD_XP",
"WEATHER", "WEATHER",
"UVC", "UVC",
"W_L", "W_L",
"ESVCS", "ESVCS",
"EARN", "EARN",
"COLLECTIBLE", "COLLECTIBLE",
"FIRST_VEH", "FIRST_VEH",
"RANK_UP", "RANK_UP",
"COMMS_TEXT",
"BLAST",
}); });
std::string hex_encode(std::string_view input) { std::string hex_encode(std::string_view input) {
@ -103,9 +105,9 @@ namespace big
if (g.notifications.warn_metric && is_warn_bad_metrics) if (g.notifications.warn_metric && is_warn_bad_metrics)
{ {
g_notification_service.push_warning("METRIC"_T.data(), g_notification_service.push_warning("METRIC"_T.data(),
std::format("{} {}", "METRIC_WARNING_MESSAGE"_T, metric_name).c_str()); std::format("{} {}", "METRIC_WARNING_MESSAGE"_T, metric_name).c_str());
} }
if (!strcmp(metric_name, "MM")) if (!strcmp(metric_name, "MM") && !g.debug.block_all_metrics)
{ {
std::string data = std::string(reinterpret_cast<char*>(metric) + 0x18); std::string data = std::string(reinterpret_cast<char*>(metric) + 0x18);
char module_name[MAX_PATH]; char module_name[MAX_PATH];
@ -117,13 +119,16 @@ namespace big
strncpy(reinterpret_cast<char*>(metric) + 0x18, result.c_str(), 0x900); strncpy(reinterpret_cast<char*>(metric) + 0x18, result.c_str(), 0x900);
return g_hooking->get_original<prepare_metric_for_sending>()(serializer, unk, time, metric); return g_hooking->get_original<prepare_metric_for_sending>()(serializer, unk, time, metric);
} }
return false; return true;
} }
else if (g.debug.logs.metric_logs == 1) else if (g.debug.logs.metric_logs == 1)
{ {
LOG(INFO) << "METRIC: " << metric_name << "; DATA: " << yim_serializer.get_string(); LOG(INFO) << "METRIC: " << metric_name << "; DATA: " << yim_serializer.get_string();
} }
return g_hooking->get_original<prepare_metric_for_sending>()(serializer, unk, time, metric); if (g.debug.block_all_metrics) [[unlikely]]
return true;
else
return g_hooking->get_original<prepare_metric_for_sending>()(serializer, unk, time, metric);
} }
} }

View File

@ -1,5 +1,6 @@
#include "hooking/hooking.hpp" #include "hooking/hooking.hpp"
#include "services/matchmaking/matchmaking_service.hpp" #include "services/matchmaking/matchmaking_service.hpp"
#include <network/snSession.hpp>
namespace big namespace big
{ {
@ -8,6 +9,9 @@ namespace big
if (g_matchmaking_service) [[likely]] if (g_matchmaking_service) [[likely]]
g_matchmaking_service->handle_session_detail_send_response(msg); g_matchmaking_service->handle_session_detail_send_response(msg);
if (g.session.hide_token_spoofing_when_host)
msg->m_detail.m_host_token = g.session.original_host_token;
g_hooking->get_original<hooks::send_session_detail_msg>()(mgr, request_frame, msg); g_hooking->get_original<hooks::send_session_detail_msg>()(mgr, request_frame, msg);
} }
} }

View File

@ -18,10 +18,7 @@ namespace big
g_fiber_pool->queue_job([max_sessions, results, num_sessions_found, status, discriminator] { g_fiber_pool->queue_job([max_sessions, results, num_sessions_found, status, discriminator] {
bool result = false; bool result = false;
if (g.session.join_in_sctv_slots) result = g_matchmaking_service->matchmake(discriminator, !g.session.join_in_sctv_slots);
result = g_matchmaking_service->matchmake();
else
result = g_matchmaking_service->matchmake(discriminator);
if (result) if (result)
{ {

View File

@ -0,0 +1,22 @@
#include "gta_util.hpp"
#include "hooking/hooking.hpp"
#include "services/players/player_service.hpp"
#include <network/CNetGamePlayerDataMsg.hpp>
#include <network/Network.hpp>
#include <network/RemoteGamerInfoMsg.hpp>
namespace big
{
bool hooks::add_gamer_to_session(rage::netConnectionManager* mgr, std::uint32_t msg_id, int* req_id, RemoteGamerInfoMsg* info, int flags, void* a6)
{
if (g.session.hide_token_spoofing_when_host
&& info->m_gamer_info.m_gamer_handle.m_rockstar_id == g_player_service->get_self()->get_rockstar_id())
{
info->m_gamer_info.m_host_token = g.session.original_host_token;
info->m_gamer_info.m_peer_id = (info->m_gamer_info.m_peer_id & 0xFFFFFFFF) | (g.session.original_host_token << 32); // TODO: P2pSecurity info message
}
return g_hooking->get_original<hooks::add_gamer_to_session>()(mgr, msg_id, req_id, info, flags, a6);
}
}

View File

@ -5,6 +5,7 @@
#include <network/CNetGamePlayerDataMsg.hpp> #include <network/CNetGamePlayerDataMsg.hpp>
#include <network/Network.hpp> #include <network/Network.hpp>
#include <network/RemoteGamerInfoMsg.hpp> #include <network/RemoteGamerInfoMsg.hpp>
#include <network/CMsgJoinRequest.hpp>
namespace big namespace big
{ {
@ -17,12 +18,13 @@ namespace big
info->m_gamer_info.m_nat_type = 0; info->m_gamer_info.m_nat_type = 0;
info->m_num_handles = 0; info->m_num_handles = 0;
return g_hooking->get_original<hooks::serialize_join_request_message>()(info, data, size, bits_serialized); return g_hooking->get_original<hooks::serialize_join_request_message>()(info, data, size, bits_serialized);
} }
bool hooks::serialize_join_request_message_2(__int64 msg, void* buf, int size, int* bits_serialized) bool hooks::serialize_join_request_message_2(CMsgJoinRequest* msg, void* buf, int size, int* bits_serialized)
{ {
auto& data = *(CNetGamePlayerDataMsg*)(msg + 0x128); auto& data = msg->m_player_data_msg;
if (g.session.join_in_sctv_slots) if (g.session.join_in_sctv_slots)
data.m_matchmaking_group = 4; data.m_matchmaking_group = 4;

View File

@ -15,12 +15,12 @@
namespace big namespace big
{ {
inline bool is_spoofed_host_token(uint64_t token) inline bool is_spoofed_host_token(rage::rlGamerInfo* info)
{ {
if (token < 200'000'000) if (info->m_host_token < INT_MAX)
return true; return true;
return false; return (info->m_peer_id >> 32) != (info->m_host_token >> 32);
} }
void* hooks::assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index) void* hooks::assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index)
@ -117,12 +117,12 @@ namespace big
if (plyr->block_join && *g_pointers->m_gta.m_is_session_started) if (plyr->block_join && *g_pointers->m_gta.m_is_session_started)
dynamic_cast<player_command*>(command::get("smartkick"_J))->call(plyr, {}); dynamic_cast<player_command*>(command::get("smartkick"_J))->call(plyr, {});
if (is_spoofed_host_token(plyr->get_net_data()->m_host_token)) if (is_spoofed_host_token(plyr->get_net_data()))
{ {
session::add_infraction(plyr, Infraction::SPOOFED_HOST_TOKEN); session::add_infraction(plyr, Infraction::SPOOFED_HOST_TOKEN);
} }
if (g_player_service->get_self()->is_host() && plyr->get_net_data()->m_nat_type == 0) if (g_player_service->get_self()->is_host() && plyr->get_net_data()->m_nat_type <= 1)
{ {
session::add_infraction(plyr, Infraction::DESYNC_PROTECTION); session::add_infraction(plyr, Infraction::DESYNC_PROTECTION);
} }
@ -131,6 +131,11 @@ namespace big
{ {
session::add_infraction(plyr, Infraction::DESYNC_PROTECTION); // some broken menus may do this session::add_infraction(plyr, Infraction::DESYNC_PROTECTION); // some broken menus may do this
} }
if (g_player_service->did_player_send_modder_beacon(plyr->get_rockstar_id()))
{
session::add_infraction(plyr, Infraction::SENT_MODDER_BEACONS);
}
} }
}); });
} }

View File

@ -1135,6 +1135,8 @@ namespace big
return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_SUBMARINE; return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_SUBMARINE;
case eTaskTypeIndex::CTaskVehicleFleeAirborne: case eTaskTypeIndex::CTaskVehicleFleeAirborne:
return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_HELI && g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_PLANE; return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_HELI && g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_PLANE;
case eTaskTypeIndex::CTaskVehicleGoToPointWithAvoidanceAutomobile:
return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_AUTOMOBILE;
} }
return false; return false;
@ -1261,7 +1263,8 @@ namespace big
return true; return true;
} }
if (attach_node->m_attached && object->m_object_type == (int16_t)eNetObjType::NET_OBJ_TYPE_TRAILER) if (attach_node->m_attached
&& object->m_object_type == (int16_t)eNetObjType::NET_OBJ_TYPE_TRAILER)
{ {
if (auto net_obj = if (auto net_obj =
g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, attach_node->m_attached_to, false)) g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, attach_node->m_attached_to, false))
@ -1270,6 +1273,12 @@ namespace big
{ {
if (entity->m_entity_type != 3) if (entity->m_entity_type != 3)
{ {
LOGF(stream::net_sync,
WARNING,
"Rejecting sync due to a CPhysicalAttachDataNode from {} since it's attaching a {} to a {}, which is known to cause crashes",
sender->get_name(),
net_object_type_strs[(int)g.m_syncing_object_type],
net_object_type_strs[(int)net_obj->m_object_type]);
notify::crash_blocked(sender, "invalid attachment"); notify::crash_blocked(sender, "invalid attachment");
return true; return true;
} }

View File

@ -0,0 +1,18 @@
#include "hooking/hooking.hpp"
#include "gta/pools.hpp"
namespace big
{
void* hooks::create_pool_item(GenericPool* pool)
{
auto item = g_hooking->get_original<hooks::create_pool_item>()(pool);
if (!item)
{
auto caller_offset = (__int64)_ReturnAddress() - (__int64)GetModuleHandleA(0);
LOGF(FATAL, "Pool full! Caller: GTA5.exe+0x{:X}, Size: {}", caller_offset, pool->m_item_count);
}
return item;
}
}

View File

@ -0,0 +1,19 @@
#include "hooking/hooking.hpp"
namespace big
{
void hooks::error_packet_memmove(void* dst, void* src, int size)
{
if (!src || !dst) [[unlikely]]
return;
// remote crash
if (size > 0x80) [[unlikely]]
{
LOG(INFO) << "remote crash blocked";
return;
}
return g_hooking->m_error_packet_memmove_hook.get_original<decltype(&hooks::error_packet_memmove)>()(dst, src, size);
}
}

View File

@ -12,9 +12,12 @@
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "util/chat.hpp" #include "util/chat.hpp"
#include "util/session.hpp" #include "util/session.hpp"
#include "gta/net_object_mgr.hpp"
#include <network/Network.hpp> #include <network/Network.hpp>
#include <network/netTime.hpp> #include <network/netTime.hpp>
#include <network/P2pSecurity.hpp>
#include <network/netObjectIds.hpp>
inline void gamer_handle_deserialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf) inline void gamer_handle_deserialize(rage::rlGamerHandle& hnd, rage::datBitBuffer& buf)
@ -39,6 +42,12 @@ inline bool is_kick_instruction(rage::datBitBuffer& buffer)
namespace big namespace big
{ {
bool try_read_secondary_header(rage::datBitBuffer& buffer)
{
auto data = buffer.Read<std::uint32_t>(20);
return data == 0x8C253 || data == 0x8924F;
}
bool get_msg_type(rage::eNetMessage& msgType, rage::datBitBuffer& buffer) bool get_msg_type(rage::eNetMessage& msgType, rage::datBitBuffer& buffer)
{ {
uint32_t pos; uint32_t pos;
@ -66,30 +75,244 @@ namespace big
if (buffer.Read<bool>(1)) if (buffer.Read<bool>(1))
id.m_position_hash = buffer.Read<uint32_t>(32); id.m_position_hash = buffer.Read<uint32_t>(32);
else
id.m_position_hash = 0;
if (buffer.Read<bool>(1)) if (buffer.Read<bool>(1))
id.m_instance_id = buffer.Read<int32_t>(8); id.m_instance_id = buffer.Read<int32_t>(8);
else
id.m_instance_id = -1;
} }
bool hooks::receive_net_message(void* netConnectionManager, void* a2, rage::netConnection::InFrame* frame) static void script_id_serialize(CGameScriptId& id, rage::datBitBuffer& buffer)
{ {
if (frame->get_event_type() != rage::netConnection::InFrame::EventType::FrameReceived) buffer.Write<uint32_t>(id.m_hash, 32);
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame); buffer.Write<uint32_t>(id.m_timestamp, 32);
if (frame->m_data == nullptr || frame->m_length == 0) if (id.m_position_hash != 0)
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame); {
buffer.Write<bool>(true, 1);
buffer.Write<uint32_t>(id.m_position_hash, 32);
}
else
{
buffer.Write<bool>(false, 1);
}
rage::datBitBuffer buffer(frame->m_data, frame->m_length); if (id.m_instance_id != -1)
{
buffer.Write<bool>(true, 1);
buffer.Write<int32_t>(id.m_instance_id, 8);
}
else
{
buffer.Write<bool>(false, 1);
}
}
void log_net_message(rage::eNetMessage message_type, rage::datBitBuffer& data_buffer, rage::netEvent* event, rage::SecurityPeer* sec_peer)
{
if (g.debug.logs.packet_logs == 1 || //ALL
(g.debug.logs.packet_logs == 2 && message_type != rage::eNetMessage::MsgCloneSync && message_type != rage::eNetMessage::MsgPackedCloneSyncACKs && message_type != rage::eNetMessage::MsgPackedEvents && message_type != rage::eNetMessage::MsgPackedReliables && message_type != rage::eNetMessage::MsgPackedEventReliablesMsgs && message_type != rage::eNetMessage::MsgNetArrayMgrUpdate && message_type != rage::eNetMessage::MsgNetArrayMgrSplitUpdateAck && message_type != rage::eNetMessage::MsgNetArrayMgrUpdateAck && message_type != rage::eNetMessage::MsgScriptHandshakeAck && message_type != rage::eNetMessage::MsgScriptHandshake && message_type != rage::eNetMessage::MsgScriptJoin && message_type != rage::eNetMessage::MsgScriptJoinAck && message_type != rage::eNetMessage::MsgScriptJoinHostAck && message_type != rage::eNetMessage::MsgRequestObjectIds && message_type != rage::eNetMessage::MsgInformObjectIds && message_type != rage::eNetMessage::MsgNetTimeSync)) //FILTERED
{
const char* packet_type = "<UNKNOWN>";
for (const auto& p : packet_types)
{
if (p.second == (int)message_type)
{
packet_type = p.first;
break;
}
}
auto now = std::chrono::system_clock::now();
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
auto timer = std::chrono::system_clock::to_time_t(now);
auto local_time = *std::localtime(&timer);
std::string name = "";
rage::rlGamerHandle rid{};
if (sec_peer)
{
if (sec_peer->m_info.handle.m_platform == 3)
rid = sec_peer->m_info.handle;
else if (sec_peer->m_unverified_handle.m_platform == 3)
rid = sec_peer->m_unverified_handle;
name = sec_peer->m_info.name;
}
if (name.empty())
name = "???";
std::string log_msg = std::format("PKT | {} (0x{:X}) [size=0x{:X}, cxnId={:X}, peerId={}, msgId={}] from {} ({})",
packet_type,
(int)message_type,
data_buffer.GetDataLength(),
event->m_connection_identifier,
event->m_peer_id,
event->m_msg_id,
name,
rid.m_rockstar_id);
static std::ofstream log(g_file_manager.get_project_file("./packets.log").get_path(), std::ios::app);
log << "[" << std::put_time(&local_time, "%m/%d/%Y %I:%M:%S") << ":" << std::setfill('0') << std::setw(3) << ms.count() << " " << std::put_time(&local_time, "%p") << "] " << log_msg << std::endl;
log.flush();
}
}
bool is_host_of_session(rage::snSession* session, std::uint32_t peer_id)
{
if (!session || peer_id == -1)
return false;
if (auto player = session->get_player_by_token(session->m_host_token))
return player->m_player_data.m_peer_id_2 == peer_id;
return false;
}
bool should_block_script(std::uint32_t hash, const menu_settings::script_block_opts& opts)
{
const static std::unordered_set<std::uint32_t> arcade_games = {"am_mp_arcade_claw_crane"_J, "am_mp_arcade_fortune_teller"_J, "am_mp_arcade_love_meter"_J, "am_mp_arcade_strength_test"_J, "grid_arcade_cabine"_J,
"gunslinger_arcade"_J, "road_arcade"_J, "dont_cross_the_line"_J, "camhedz_arcade"_J};
const static std::unordered_set<std::uint32_t> casino_games = {"casinoroulette"_J, "casino_lucky_wheel"_J, "casino_slots"_J, "three_card_poker"_J, "blackjack"_J};
const static std::unordered_set<std::uint32_t> interiors = {"am_mp_property_ext"_J, "am_mp_smpl_interior_ext"_J}; // blocking the actual interior scripts would softlock the game
const static std::unordered_set<std::uint32_t> prostitutes = {"am_prostitute"_J, "pb_prostitute"_J};
const static std::unordered_set<std::uint32_t> sitting = {"am_mp_boardroom_seating"_J, "arcade_seating"_J, "arena_box_bench_seats"_J, "arena_workshop_seats"_J, "auto_shop_seating"_J, "base_corridor_seats"_J,
"base_entrance_seats"_J, "base_heist_seats"_J, "base_lounge_seats"_J, "base_quaters_seats"_J, "base_reception_seats"_J, "beach_exterior_seating"_J,
"business_hub_garage_seats"_J, "car_meet_exterior_seating"_J, "casino_bar_seating"_J, "casino_exterior_seating"_J, "casino_interior_seating"_J,
"casino_main_lounge_seating"_J, "casino_nightclub_seating"_J, "casino_penthouse_seating"_J, "fixer_hq_seating"_J, "fixer_hq_seating_op_floor"_J,
"fixer_hq_seating_pq"_J, "juggalo_hideout_seating"_J, "multistorey_garage_ext_seating"_J, "multistorey_garage_seating"_J, "music_studio_seating"_J,
"music_studio_seating_external"_J, "nightclub_ground_floor_seats"_J, "nightclub_office_seats"_J, "nightclub_vip_seats"_J, "salvage_yard_seating"_J,
"simeon_showroom_seating"_J};
const static std::unordered_set<std::uint32_t> sleeping = {"mp_bed_high"_J, "ob_mp_bed_high"_J, "ob_mp_bed_low"_J, "ob_mp_bed_med"_J};
const static std::unordered_set<std::uint32_t> stores = {"clothes_shop_mp"_J, "hairdo_shop_mp"_J, "tattoo_shop"_J, "am_hold_up"_J, "ob_cashregister"_J};
const static std::unordered_set<std::uint32_t> strip_club = {"stripclub_drinking"_J, "stripclub_mp"_J, "stripperhome"_J, "ob_mp_stripper"_J, "sclub_front_bouncer"_J};
const static std::unordered_set<std::uint32_t> vending_machines = {"ob_vend1"_J, "ob_vend2"_J};
return
(opts.lsc && hash == "carmod_shop"_J) ||
(opts.ammunation && hash == "gunclub_shop"_J) ||
(opts.arcade_games && arcade_games.contains(hash)) ||
(opts.casino_games && casino_games.contains(hash)) ||
(opts.drones && hash == "am_mp_drone"_J) ||
(opts.impromptu_race && hash == "mg_race_to_point"_J) ||
(opts.interiors && interiors.contains(hash)) ||
(opts.movies && hash == "act_cinema"_J) ||
(opts.prostitutes && prostitutes.contains(hash)) ||
(opts.sitting && sitting.contains(hash)) ||
(opts.sleeping && sleeping.contains(hash)) ||
(opts.stores && stores.contains(hash)) ||
(opts.street_dealer && hash == "fm_street_dealer"_J) ||
(opts.strip_club && strip_club.contains(hash)) ||
(opts.atms && hash == "atm_trigger"_J) ||
(opts.impromptu_dm && hash == "fm_impromptu_dm_controler"_J) ||
(opts.gang_attacks && hash == "fm_hideout_controler"_J) ||
(opts.vending_machines && vending_machines.contains(hash));
}
bool handle_block_script(player_ptr player, CGameScriptId& script, int msg_id)
{
if (NETWORK::NETWORK_IS_ACTIVITY_SESSION() || NETWORK::NETWORK_IS_IN_TRANSITION() || NETWORK::NETWORK_IS_TRANSITION_BUSY())
return false;
if (should_block_script(script.m_hash, g.session.script_block_opts) || should_block_script(script.m_hash, player->script_block_opts))
{
packet pkt;
pkt.write_message(rage::eNetMessage::MsgScriptJoinHostAck);
script_id_serialize(script, pkt.m_buffer);
pkt.write<int16_t>(-1, 16);
pkt.write<int16_t>(-1, 16);
pkt.write<bool>(false, 1);
pkt.write<int>(2, 3);
pkt.send(msg_id);
return true;
}
return false;
}
bool hooks::receive_net_message(void* a1, rage::netConnectionManager* net_cxn_mgr, rage::netEvent* event)
{
void* message_data;
int message_size;
rage::netConnection::InFrame* frame = nullptr;
rage::netEventConnectionError* error = nullptr;
if (event->get_event_type() == rage::netEvent::Type::ConnectionRequested || event->get_event_type() == rage::netEvent::Type::FrameReceived)
{
frame = reinterpret_cast<rage::netConnection::InFrame*>(event);
if (frame->m_data == nullptr || frame->m_length == 0 || frame->m_connection_identifier == 2)
return g_hooking->get_original<hooks::receive_net_message>()(a1, net_cxn_mgr, event);
message_data = frame->m_data;
message_size = frame->m_length;
}
else if (event->get_event_type() == rage::netEvent::Type::ConnectionError)
{
error = reinterpret_cast<rage::netEventConnectionError*>(event);
if (error->m_size == 0)
return g_hooking->get_original<hooks::receive_net_message>()(a1, net_cxn_mgr, event);
message_data = error->m_data;
message_size = error->m_size;
}
else
{
return g_hooking->get_original<hooks::receive_net_message>()(a1, net_cxn_mgr, event);
}
rage::datBitBuffer buffer(message_data, message_size);
buffer.m_flagBits = 1; buffer.m_flagBits = 1;
if (try_read_secondary_header(buffer))
{
buffer = rage::datBitBuffer(((char*)message_data) + 7, message_size - 7);
buffer.m_flagBits = 1;
}
else
{
buffer.Seek(0);
}
rage::eNetMessage msgType; rage::eNetMessage msgType;
player_ptr player = nullptr;
if (!get_msg_type(msgType, buffer))
{
LOGF(stream::net_messages, WARNING, "Received message that we cannot parse from cxn id {}", event->m_connection_identifier);
return g_hooking->get_original<hooks::receive_net_message>()(a1, net_cxn_mgr, event);
}
rage::snSession* session = nullptr; // game unless proven otherwise
if (gta_util::get_network()->m_transition_session_ptr
&& gta_util::get_network()->m_transition_session_ptr->m_connection_identifier == event->m_connection_identifier)
{
session = gta_util::get_network()->m_transition_session_ptr;
}
else
{
session = gta_util::get_network()->m_game_session_ptr;
}
player_ptr player = nullptr; // WILL be null until we get their physical
for (uint32_t i = 0; i < gta_util::get_network()->m_game_session_ptr->m_player_count; i++) for (uint32_t i = 0; i < gta_util::get_network()->m_game_session_ptr->m_player_count; i++)
{ {
if (auto player_iter = gta_util::get_network()->m_game_session_ptr->m_players[i]) if (auto player_iter = gta_util::get_network()->m_game_session_ptr->m_players[i])
{ {
if (frame && player_iter->m_player_data.m_peer_id_2 == frame->m_peer_id) if (player_iter->m_player_data.m_peer_id_2 == event->m_peer_id)
{ {
player = g_player_service->get_by_host_token( player = g_player_service->get_by_host_token(
gta_util::get_network()->m_game_session_ptr->m_players[i]->m_player_data.m_host_token); gta_util::get_network()->m_game_session_ptr->m_players[i]->m_player_data.m_host_token);
@ -98,124 +321,80 @@ namespace big
} }
} }
if (!get_msg_type(msgType, buffer)) int sec_id = 0;
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
if (frame)
if (msgType == rage::eNetMessage::MsgRoamingJoinBubbleAck) sec_id = frame->m_security_id;
return true; else
if (player)
{ {
switch (msgType) if (auto cxn = g_pointers->m_gta.m_get_connection_peer(net_cxn_mgr, error->m_peer_id))
sec_id = cxn->m_security_id;
}
auto peer = g_pointers->m_gta.m_get_peer_by_security_id(sec_id); // shouldn't be null in most cases, contains unspoofable data
if (error && msgType != rage::eNetMessage::MsgJoinResponse)
{
if (peer)
LOGF(stream::net_messages, WARNING, "Received an error packet that isn't MsgJoinResponse from {}", peer->m_info.name);
return true;
}
if (g.debug.logs.packet_logs)
{
log_net_message(msgType, buffer, event, peer);
}
switch (msgType)
{
case rage::eNetMessage::MsgScriptJoin:
{
CGameScriptId script;
script_id_deserialize(script, buffer);
if (player && handle_block_script(player, script, event->m_msg_id))
{ {
case rage::eNetMessage::MsgTextMessage: LOGF(stream::net_messages, WARNING, "Denying script request from {} (hash={:X}, instance={})", player->get_name(), script.m_hash, script.m_instance_id);
case rage::eNetMessage::MsgTextMessage2: return true;
{
char message[256];
rage::rlGamerHandle handle{};
bool is_team;
buffer.ReadString(message, sizeof(message));
gamer_handle_deserialize(handle, buffer);
buffer.ReadBool(&is_team);
if (player->is_spammer)
return true;
if (auto spam_reason = chat::is_text_spam(message, player))
{
if (g.session.log_chat_messages)
chat::log_chat(message, player, spam_reason, is_team);
player->is_spammer = true;
if (!(player->is_trusted || (player->is_friend() && g.session.trust_friends) || g.session.trust_session))
{
session::add_infraction(player, Infraction::CHAT_SPAM);
g.reactions.chat_spam.process(player);
}
return true;
}
else
{
if (g.session.log_chat_messages)
chat::log_chat(message, player, SpamReason::NOT_A_SPAMMER, is_team);
if (g.session.chat_translator.enabled)
{
chat_message new_message{player->get_name(), message};
translate_queue.push(new_message);
}
if (g.session.chat_commands && message[0] == g.session.chat_command_prefix)
command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
else
g_lua_manager->trigger_event<menu_event::ChatMessageReceived>(player->id(), message);
if (msgType == rage::eNetMessage::MsgTextMessage && g_pointers->m_gta.m_chat_data && player->get_net_data())
{
buffer.Seek(0);
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame); // Call original function since we can't seem to handle it
}
}
break;
} }
case rage::eNetMessage::MsgScriptMigrateHost:
break;
}
case rage::eNetMessage::MsgScriptHostRequest:
{
CGameScriptId script;
script_id_deserialize(script, buffer);
if (script.m_hash == "freemode"_J && g.session.force_script_host)
return true;
break;
}
case rage::eNetMessage::MsgKickPlayer:
{
KickReason reason = buffer.Read<KickReason>(3);
if (!is_host_of_session(gta_util::get_network()->m_game_session_ptr, event->m_peer_id))
{ {
if (player->m_host_migration_rate_limit.process()) LOGF(stream::net_messages, WARNING, "{} sent MsgKickPlayer, but they are not the host", peer->m_info.name);
{ return true;
if (player->m_host_migration_rate_limit.exceeded_last_process())
{
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
auto p_name = player->get_name();
g_notification_service.push_error("PROTECTIONS"_T.data(), std::vformat("OOM_KICK"_T, std::make_format_args(p_name)));
}
return true;
}
break;
} }
case rage::eNetMessage::MsgScriptHostRequest:
if (reason == KickReason::VOTED_OUT)
{ {
CGameScriptId script; g_notification_service.push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
script_id_deserialize(script, buffer); return true;
if (script.m_hash == "freemode"_J && g.session.force_script_host)
return true;
break;
} }
case rage::eNetMessage::MsgNetTimeSync:
{
int action = buffer.Read<int>(2);
uint32_t counter = buffer.Read<uint32_t>(32);
uint32_t token = buffer.Read<uint32_t>(32);
uint32_t timestamp = buffer.Read<uint32_t>(32);
uint32_t time_diff = (*g_pointers->m_gta.m_network_time)->m_time_offset + frame->m_timestamp;
if (action == 0) LOGF(stream::net_messages, VERBOSE, "{} sent us a MsgKickPlayer, reason = {}", peer->m_info.name, (int)reason);
{ break;
player->player_time_value = timestamp; }
player->player_time_value_received_time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()); case rage::eNetMessage::MsgRadioStationSyncRequest:
if (!player->time_difference || time_diff > player->time_difference.value()) {
player->time_difference = time_diff; if (player && player->block_radio_requests)
} return true;
break;
}
case rage::eNetMessage::MsgKickPlayer:
{
KickReason reason = buffer.Read<KickReason>(3);
if (!player->is_host()) if (player)
return true;
if (reason == KickReason::VOTED_OUT)
{
g_notification_service.push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
return true;
}
break;
}
case rage::eNetMessage::MsgRadioStationSyncRequest:
{ {
if (player->block_radio_requests) if (player->block_radio_requests)
return true; return true;
@ -225,100 +404,357 @@ namespace big
if (player->m_radio_request_rate_limit.exceeded_last_process()) if (player->m_radio_request_rate_limit.exceeded_last_process())
{ {
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER); session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
auto p_name = player->get_name(); g_notification_service.push_error("PROTECTIONS"_T.data(),
std::vformat("OOM_KICK"_T, std::make_format_args(player->get_name())));
g_notification_service.push_error("PROTECTIONS"_T.data(), std::vformat("OOM_KICK"_T, std::make_format_args(p_name)));
player->block_radio_requests = true; player->block_radio_requests = true;
} }
return true; return true;
} }
break;
} }
case rage::eNetMessage::MsgRoamingInitialBubble: else
{ {
LOG(WARNING) << "Shouldn't get this again"; static rate_limiter unk_player_radio_requests{1s, 5};
return true;
}
}
}
else
{
switch (msgType)
{
case rage::eNetMessage::MsgScriptMigrateHost: return true;
case rage::eNetMessage::MsgRadioStationSyncRequest:
{
static rate_limiter unk_player_radio_requests{1s, 6};
if (unk_player_radio_requests.process()) if (unk_player_radio_requests.process())
{ {
if (unk_player_radio_requests.exceeded_last_process()) if (unk_player_radio_requests.exceeded_last_process())
{ {
// Make a translation for this new OOM kick protection g_notification_service.push_error("PROTECTIONS"_T.data(), std::vformat("OOM_KICK"_T.data(), std::make_format_args(peer->m_info.name)));
g_notification_service.push_error("PROTECTIONS"_T.data(), "OOM_KICK_UNK"_T.data());
} }
return true; return true;
} }
break;
} }
case rage::eNetMessage::MsgTextMessage: return true;
case rage::eNetMessage::MsgNonPhysicalData: if (!session || !session->is_host())
{ {
buffer.Read<int>(7); // size LOGF(stream::net_messages, WARNING, "{} sent MsgRadioStationSyncRequest, but we are not the host", peer->m_info.name);
int bubble = buffer.Read<int>(4); return true;
int player = buffer.Read<int>(6);
if (g_player_service->get_self() && g_player_service->get_self()->id() == player)
{
LOG(WARNING) << "We're being replaced";
return true;
}
if (bubble != 0)
{
LOG(WARNING) << "Wrong bubble: " << bubble;
}
break;
}
} }
break;
} }
case rage::eNetMessage::MsgRadioStationSync:
if (g.debug.logs.packet_logs) [[unlikely]]
{ {
if (g.debug.logs.packet_logs == 1 || //ALL if (!session || !is_host_of_session(session, event->m_peer_id))
(g.debug.logs.packet_logs == 2 && msgType != rage::eNetMessage::MsgCloneSync && msgType != rage::eNetMessage::MsgPackedCloneSyncACKs && msgType != rage::eNetMessage::MsgPackedEvents && msgType != rage::eNetMessage::MsgPackedReliables && msgType != rage::eNetMessage::MsgPackedEventReliablesMsgs && msgType != rage::eNetMessage::MsgNetArrayMgrUpdate && msgType != rage::eNetMessage::MsgNetArrayMgrSplitUpdateAck && msgType != rage::eNetMessage::MsgNetArrayMgrUpdateAck && msgType != rage::eNetMessage::MsgScriptHandshakeAck && msgType != rage::eNetMessage::MsgScriptHandshake && msgType != rage::eNetMessage::MsgScriptJoin && msgType != rage::eNetMessage::MsgScriptJoinAck && msgType != rage::eNetMessage::MsgScriptJoinHostAck && msgType != rage::eNetMessage::MsgRequestObjectIds && msgType != rage::eNetMessage::MsgInformObjectIds && msgType != rage::eNetMessage::MsgNetTimeSync)) //FILTERED
{ {
const char* packet_type = "<UNKNOWN>"; LOGF(stream::net_messages, WARNING, "{} sent MsgRadioStationSync, but is not the host", peer->m_info.name);
for (const auto& p : packet_types) return true;
}
break;
}
case rage::eNetMessage::MsgRequestObjectIds:
{
if (!player)
{
break;
}
if (!gta_util::get_net_object_ids())
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRequestObjectIds, but we don't have a valid CNetworkObjectMgr", peer->m_info.name);
return true;
}
if (player->received_object_id_request)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRequestObjectIds, but we've already received a request from them", peer->m_info.name);
return true;
}
player->received_object_id_request = true;
break;
}
case rage::eNetMessage::MsgInformObjectIds:
{
if (!player)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgInformObjectIds, but is not physical yet", peer->m_info.name);
return true;
}
if (!gta_util::get_net_object_ids())
{
LOGF(stream::net_messages, WARNING, "{} sent MsgInformObjectIds, but we don't have a valid CNetworkObjectMgr", peer->m_info.name);
return true;
}
if ((gta_util::get_net_object_ids()->m_object_id_response_pending_players & (1 << player->id())) == 0 && player->received_object_id_response)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgInformObjectIds, but we didn't request them for it", peer->m_info.name);
return true;
}
int num_objects_in_our_range = buffer.Read<int>(13);
if (num_objects_in_our_range > 256)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgInformObjectIds, but they have given us an unusual amount of occupied object IDs in our object range", peer->m_info.name);
gta_util::get_net_object_ids()->m_object_id_response_pending_players &= (1 << player->id());
return true;
}
buffer.SeekForward(num_objects_in_our_range * 13); // we don't really care about this segment
int num_replacement_objects = buffer.Read<int>(13);
for (int i = 0; i < num_replacement_objects; i++)
{
auto object_id = buffer.Read<std::uint16_t>(13);
if ((*g_pointers->m_gta.m_network_object_mgr)->find_object_by_id(object_id, true))
{ {
if (p.second == (int)msgType) LOGF(stream::net_messages, WARNING, "{} sent MsgInformObjectIds, but they have given us an object ID that is not actually free", peer->m_info.name);
{ gta_util::get_net_object_ids()->m_object_id_response_pending_players &= (1 << player->id());
packet_type = p.first; return true;
break; }
} }
player->received_object_id_response = true;
break;
}
case rage::eNetMessage::MsgRoamingJoinBubbleAck:
{
int status = buffer.Read<int>(2);
int bubble = buffer.Read<int>(4);
if (status == 0 && bubble == 10)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingJoinBubbleAck with a null bubble id", peer->m_info.name);
if (player)
g.reactions.break_game.process(player);
return true;
}
else if (status == 0)
{
LOGF(stream::net_messages, WARNING, "{} wants us to join their bubble {}, but this is not a good idea", peer->m_info.name, bubble);
return true;
}
break;
}
case rage::eNetMessage::MsgRoamingInitialBubble:
{
// should not get this after the host has joined
if (player && g_player_service->get_self()->id() != -1)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host has already joined (and so have we)", peer->m_info.name);
return true;
}
int my_bubble = buffer.Read<int>(4);
int my_pid = buffer.Read<int>(6);
int their_bubble = buffer.Read<int>(4);
int their_pid = buffer.Read<int>(6);
if (their_bubble == 10) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host doesn't have a bubble?", peer->m_info.name);
return true;
}
if (my_bubble == 10) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host didn't actually give us a valid bubble", peer->m_info.name);
return true;
}
if (my_bubble > 10 || their_bubble > 10) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host is trying to crash us by giving us an out of bounds bubble id", peer->m_info.name);
return true;
}
if (my_bubble != 0) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble with a non-standard bubble id: {}", peer->m_info.name, my_bubble);
}
if (my_bubble != their_bubble) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host's bubble id doesn't match our bubble id ({} != {})", peer->m_info.name, their_bubble, my_bubble);
return true;
}
if (my_pid >= 32 || their_pid >= 32) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host gave us invalid player ids (or made us pick our own player ids)", peer->m_info.name);
}
if (my_pid == their_pid) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgRoamingInitialBubble, but the host has the same player id as us", peer->m_info.name);
return true;
}
break;
}
case rage::eNetMessage::MsgNonPhysicalData:
{
buffer.Read<int>(7); // size
int bubble_id = buffer.Read<int>(4);
int player_id = buffer.Read<int>(6);
if (player)
{
return true; // we don't need this message anymore
}
if (bubble_id == 10) [[unlikely]]
{
LOGF(stream::net_messages, VERBOSE, "{} sent MsgNonPhysicalData and indicated that they are not in a bubble", peer->m_info.name);
return true; // might as well drop it
}
if (bubble_id > 10) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgNonPhysicalData, but are trying to crash us by giving us an out of bounds bubble id", peer->m_info.name);
return true;
}
if (bubble_id != 0) [[unlikely]]
{
LOGF(stream::net_messages, WARNING, "{} sent MsgNonPhysicalData with a non-standard bubble id: {}. This may cause problems during join", peer->m_info.name, bubble_id);
}
if (player_id >= 32) [[unlikely]]
{
LOG(WARNING) << peer->m_info.name << " sent MsgNonPhysicalData, but has an invalid player id (or is trying to make us pick our own)";
return true;
}
if (g_player_service->get_self() && g_player_service->get_self()->id() != -1
&& g_player_service->get_self()->id() == player_id) [[unlikely]]
{
LOGF(stream::net_messages, VERBOSE, "{} sent MsgNonPhysicalData, but are trying to replace us", peer->m_info.name);
return true;
}
for (auto& player : g_player_service->players())
{
if (player.second->id() == player_id) [[unlikely]]
{
LOGF(stream::net_messages, VERBOSE, "{} sent MsgNonPhysicalData, but are trying to replace {}", peer->m_info.name, player.second->get_name());
return true;
}
}
break;
}
case rage::eNetMessage::MsgRequestKickFromHost:
{
LOGF(stream::net_messages, WARNING, "Denying MsgRequestKickFromHost from {}", peer->m_info.name);
return true;
}
case rage::eNetMessage::MsgConfigRequest:
{
LOGF(stream::net_messages, WARNING, "Denying MsgConfigRequest from {} ({})", peer->m_info.name, peer->m_info.handle.m_rockstar_id);
return true;
}
case rage::eNetMessage::MsgScriptMigrateHost:
{
if (player && player->m_host_migration_rate_limit.process())
{
if (player->m_host_migration_rate_limit.exceeded_last_process())
{
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
g_notification_service.push_error("PROTECTIONS"_T.data(),
std::vformat("OOM_KICK"_T, std::make_format_args(player->get_name())));
}
return true;
}
break;
}
case rage::eNetMessage::MsgNetTimeSync:
{
int action = buffer.Read<int>(2);
uint32_t counter = buffer.Read<uint32_t>(32);
uint32_t token = buffer.Read<uint32_t>(32);
uint32_t timestamp = buffer.Read<uint32_t>(32);
uint32_t time_diff = (*g_pointers->m_gta.m_network_time)->m_time_offset + event->m_timestamp;
if (action == 0 && player)
{
player->player_time_value = timestamp;
player->player_time_value_received_time = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
if (!player->time_difference || time_diff > player->time_difference.value())
player->time_difference = time_diff;
}
break;
}
case rage::eNetMessage::MsgTextMessage:
case rage::eNetMessage::MsgTextMessage2:
{
char message[256];
rage::rlGamerHandle handle{};
bool is_team;
buffer.ReadString(message, sizeof(message));
gamer_handle_deserialize(handle, buffer);
is_team = buffer.Read<bool>(1);
if (!player)
{
LOGF(stream::net_messages, WARNING, "{} sent MsgTextMessage, but is not physical yet. This may indicate chat spam", peer->m_info.name);
return true;
}
if (player->is_spammer)
return true;
if (auto spam_reason = chat::is_text_spam(message, player))
{
if (g.session.log_chat_messages)
chat::log_chat(message, player, spam_reason, is_team);
g_notification_service.push("PROTECTIONS"_T.data(),
std::format("{} {}", player->get_name(), "IS_A_SPAMMER"_T.data()));
player->is_spammer = true;
g.reactions.chat_spam.process(player);
return true;
}
else
{
if (g.session.log_chat_messages)
chat::log_chat(message, player, SpamReason::NOT_A_SPAMMER, is_team);
if (g.session.chat_translator.enabled)
{
chat_message new_message{player->get_name(), message};
translate_queue.push(new_message);
} }
auto now = std::chrono::system_clock::now(); if (g.session.chat_commands && message[0] == g.session.chat_command_prefix)
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000; command::process(std::string(message + 1), std::make_shared<chat_command_context>(player));
auto timer = std::chrono::system_clock::to_time_t(now); else
auto local_time = *std::localtime(&timer); g_lua_manager->trigger_event<menu_event::ChatMessageReceived>(player->id(), message);
static std::ofstream log(g_file_manager.get_project_file("./packets.log").get_path(), std::ios::app); if (msgType == rage::eNetMessage::MsgTextMessage && player->get_net_data())
log << "[" << std::put_time(&local_time, "%m/%d/%Y %I:%M:%S") << ":" << std::setfill('0') << std::setw(3) << ms.count() << " " << std::put_time(&local_time, "%p") << "] " {
<< "RECEIVED PACKET | Type: " << packet_type << " | Length: " << frame->m_length << " | Sender: " g_pointers->m_gta.m_handle_chat_message(*g_pointers->m_gta.m_chat_data, nullptr, &peer->m_info.handle, message, is_team);
<< (player ? player->get_name() : }
std::format("<M:{}>, <C:{:X}>, <P:{}>", }
(int)frame->m_msg_id,
frame->m_connection_identifier, return true;
frame->m_peer_id) }
.c_str()) default:
<< " | " << HEX_TO_UPPER((int)msgType) << std::endl; {
log.flush(); if ((int)msgType > 0x91) [[unlikely]]
{
if (peer)
LOGF(stream::net_messages, WARNING, "{} sent a message that does not exist: {:X}", peer->m_info.name, (int)msgType);
// dumb modders
if (player)
{
session::add_infraction(player, Infraction::SENT_MODDER_BEACONS);
}
else if (peer)
{
g_player_service->mark_player_as_sending_modder_beacons(peer->m_info.handle.m_rockstar_id);
}
} }
} }
}
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame); return g_hooking->get_original<hooks::receive_net_message>()(a1, net_cxn_mgr, event);
} }
} }

View File

@ -2,6 +2,9 @@
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "util/notify.hpp" #include "util/notify.hpp"
#include "gta/pools.hpp" #include "gta/pools.hpp"
#include "gta_util.hpp"
#include <network/netObjectIds.hpp>
namespace big namespace big
{ {
@ -13,6 +16,38 @@ namespace big
return; return;
} }
// can delete objects here too
if (dst && dst->m_player_info && dst->m_player_info->m_ped && dst->m_player_info->m_ped->m_net_object
&& object_id == dst->m_player_info->m_ped->m_net_object->m_object_id) [[unlikely]]
{
notify::crash_blocked(src, "player create");
return;
}
if (g_local_player && g_local_player->m_vehicle && g_local_player->m_vehicle->m_net_object
&& object_id == g_local_player->m_vehicle->m_net_object->m_object_id) [[unlikely]]
{
if (auto plyr = g_player_service->get_by_id(src->m_player_id))
{
g.reactions.delete_vehicle.process(plyr);
}
return;
}
if (auto object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, object_id, true)) [[likely]]
{
if (object->m_object_type == (int)eNetObjType::NET_OBJ_TYPE_PLAYER && object->m_owner_id != src->m_player_id) [[unlikely]]
{
std::string target = "<UNKNOWN>";
if (auto tgt = g_player_service->get_by_id(object->m_owner_id))
target = tgt->get_name();
LOGF(stream::net_sync, WARNING, "Rejecting clone create from {}, who is trying to delete {}'s player ped", src->get_name(), target);
return;
}
}
switch (object_type) switch (object_type)
{ {
case eNetObjType::NET_OBJ_TYPE_AUTOMOBILE: case eNetObjType::NET_OBJ_TYPE_AUTOMOBILE:
@ -31,6 +66,12 @@ namespace big
} }
} }
if (gta_util::get_net_object_ids()->is_object_id_usable(object_id))
{
LOGF(stream::net_sync, WARNING, "{} sent us an object create request with an object ID that is in our usable object ID list. Somebody lied to us...", src->get_name());
gta_util::get_net_object_ids()->remove_object_id(object_id);
}
auto plyr = g_player_service->get_by_id(src->m_player_id); auto plyr = g_player_service->get_by_id(src->m_player_id);
if (plyr && plyr->block_clone_create) [[unlikely]] if (plyr && plyr->block_clone_create) [[unlikely]]

View File

@ -12,6 +12,30 @@ namespace big
return; return;
} }
if (g_local_player && g_local_player->m_vehicle && g_local_player->m_vehicle->m_net_object
&& object_id == g_local_player->m_vehicle->m_net_object->m_object_id) [[unlikely]]
{
if (auto plyr = g_player_service->get_by_id(src->m_player_id))
{
g.reactions.delete_vehicle.process(plyr);
}
return;
}
if (auto object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, object_id, true)) [[likely]]
{
if (object->m_object_type == (int)eNetObjType::NET_OBJ_TYPE_PLAYER && object->m_owner_id != src->m_player_id) [[unlikely]]
{
std::string target = "<UNKNOWN>";
if (auto tgt = g_player_service->get_by_id(object->m_owner_id))
target = tgt->get_name();
LOGF(stream::net_sync, WARNING, "Rejecting clone remove from {}, who is trying to delete {}'s player ped", src->get_name(), target);
return;
}
}
g_hooking->get_original<hooks::received_clone_remove>()(mgr, src, dst, object_id, ownership_token); g_hooking->get_original<hooks::received_clone_remove>()(mgr, src, dst, object_id, ownership_token);
} }
} }

View File

@ -18,6 +18,28 @@ namespace big
return eAckCode::ACKCODE_FAIL; return eAckCode::ACKCODE_FAIL;
} }
// can be used to crash or reverse sync player data
if (dst && dst->m_player_info && dst->m_player_info->m_ped && dst->m_player_info->m_ped->m_net_object
&& object_id == dst->m_player_info->m_ped->m_net_object->m_object_id) [[unlikely]]
{
notify::crash_blocked(src, "player sync");
return eAckCode::ACKCODE_FAIL;
}
if (auto object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, object_id, true)) [[likely]]
{
if (object->m_object_type == (int)eNetObjType::NET_OBJ_TYPE_PLAYER && object->m_owner_id != src->m_player_id) [[unlikely]]
{
std::string target = "<UNKNOWN>";
if (auto tgt = g_player_service->get_by_id(object->m_owner_id))
target = tgt->get_name();
LOGF(stream::net_sync, WARNING, "Rejecting clone sync from {}, who is trying to sync to {}'s player ped", src->get_name(), target);
return eAckCode::ACKCODE_FAIL;
}
}
auto plyr = g_player_service->get_by_id(src->m_player_id); auto plyr = g_player_service->get_by_id(src->m_player_id);
if (plyr && plyr->block_clone_sync) [[unlikely]] if (plyr && plyr->block_clone_sync) [[unlikely]]

View File

@ -104,6 +104,7 @@ namespace big
if (!is_valid_weapon(weaponType)) if (!is_valid_weapon(weaponType))
{ {
notify::crash_blocked(player, "invalid weapon type"); notify::crash_blocked(player, "invalid weapon type");
LOGF(stream::net_events, WARNING, "Blocked WEAPON_DAMAGE_EVENT from {} with invalid weapon hash {:X}", player->get_name(), weaponType);
g_pointers->m_gta.m_send_event_ack(event_manager, player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, player, target_player, event_index, event_handled_bitset);
return true; return true;
} }
@ -258,8 +259,8 @@ namespace big
void scan_explosion_event(CNetGamePlayer* player, rage::datBitBuffer* buffer) void scan_explosion_event(CNetGamePlayer* player, rage::datBitBuffer* buffer)
{ {
uint16_t f186; uint16_t f186;
uint16_t f208; uint16_t targetEntity;
int ownerNetId; uint16_t ownerNetId;
uint16_t f214; uint16_t f214;
eExplosionTag explosionType; eExplosionTag explosionType;
float damageScale; float damageScale;
@ -276,10 +277,10 @@ namespace big
bool f189; bool f189;
bool isInvisible; bool isInvisible;
bool f126; bool f126;
bool f241; bool addOwnedExplosion;
bool f243;
uint16_t f210; bool hasTargetEnt2;
uint16_t targetEnt2;
float unkX; float unkX;
float unkY; float unkY;
@ -301,7 +302,7 @@ namespace big
// clang-format off // clang-format off
f186 = buffer->Read<uint16_t>(16); f186 = buffer->Read<uint16_t>(16);
f208 = buffer->Read<uint16_t>(13); targetEntity = buffer->Read<uint16_t>(13);
ownerNetId = buffer->Read<uint16_t>(13); ownerNetId = buffer->Read<uint16_t>(13);
f214 = buffer->Read<uint16_t>(13); // 1604+ f214 = buffer->Read<uint16_t>(13); // 1604+
explosionType = (eExplosionTag)buffer->ReadSigned<int>(8);// 1604+ bit size explosionType = (eExplosionTag)buffer->ReadSigned<int>(8);// 1604+ bit size
@ -311,7 +312,7 @@ namespace big
posY = buffer->ReadSignedFloat(22, 27648.0f); posY = buffer->ReadSignedFloat(22, 27648.0f);
posZ = buffer->ReadFloat(22, 4416.0f) - 1700.0f; posZ = buffer->ReadFloat(22, 4416.0f) - 1700.0f;
f242 = buffer->Read<uint8_t>(1); f242 = buffer->Read<bool>(1);
f104 = buffer->Read<uint16_t>(16); f104 = buffer->Read<uint16_t>(16);
cameraShake = buffer->Read<int>(8) / 127.0f; cameraShake = buffer->Read<int>(8) / 127.0f;
@ -319,10 +320,11 @@ namespace big
f189 = buffer->Read<uint8_t>(1); f189 = buffer->Read<uint8_t>(1);
isInvisible = buffer->Read<uint8_t>(1); isInvisible = buffer->Read<uint8_t>(1);
f126 = buffer->Read<uint8_t>(1); f126 = buffer->Read<uint8_t>(1);
f241 = buffer->Read<uint8_t>(1); addOwnedExplosion = buffer->Read<uint8_t>(1);
f243 = buffer->Read<uint8_t>(1);// 1604+ buffer->Read<uint8_t>(1);
f210 = buffer->Read<uint16_t>(13); hasTargetEnt2 = buffer->Read<bool>(1);// 1604+
targetEnt2 = buffer->Read<uint16_t>(13);
unkX = buffer->ReadSignedFloat(16, 1.1f); unkX = buffer->ReadSignedFloat(16, 1.1f);
unkY = buffer->ReadSignedFloat(16, 1.1f); unkY = buffer->ReadSignedFloat(16, 1.1f);
@ -364,20 +366,18 @@ namespace big
auto object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, ownerNetId, true); auto object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, ownerNetId, true);
auto entity = object ? object->GetGameObject() : nullptr; auto entity = object ? object->GetGameObject() : nullptr;
auto offset_object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, f210, true); auto offset_object = g_pointers->m_gta.m_get_net_object(*g_pointers->m_gta.m_network_object_mgr, targetEnt2, true);
if (f208 == 0 && entity && entity->m_entity_type == 4 && reinterpret_cast<CPed*>(entity)->m_player_info if (addOwnedExplosion && entity && entity->m_entity_type == 4 && reinterpret_cast<CPed*>(entity)->m_player_info
&& player->m_player_info->m_ped && player->m_player_info->m_ped->m_net_object && player->m_player_info->m_ped && player->m_player_info->m_ped->m_net_object
&& ownerNetId != player->m_player_info->m_ped->m_net_object->m_object_id && !offset_object) && ownerNetId != player->m_player_info->m_ped->m_net_object->m_object_id)
{ {
auto p_name = player->get_name();
auto m_name = reinterpret_cast<CPed*>(entity)->m_player_info->m_net_player_data.m_name;
g_notification_service.push_error("WARNING"_T.data(), g_notification_service.push_error("WARNING"_T.data(),
std::vformat("BLAMED_FOR_EXPLOSION"_T, std::vformat("BLAMED_FOR_EXPLOSION"_T,
std::make_format_args(p_name, m_name))); std::make_format_args(player->get_name(),
// too many false positives, disabling it reinterpret_cast<CPed*>(entity)->m_player_info->m_net_player_data.m_name)));
//session::add_infraction(g_player_service->get_by_id(player->m_player_id), Infraction::BLAME_EXPLOSION_DETECTED); session::add_infraction(g_player_service->get_by_id(player->m_player_id), Infraction::BLAME_EXPLOSION_DETECTED);
LOGF(stream::net_events, WARNING, "{} sent an EXPLOSION_EVENT with addOwnedExplosion enabled and with the wrong owner", player->get_name());
return; return;
} }
@ -420,67 +420,78 @@ namespace big
static const std::unordered_set<uint32_t> blocked_ref_hashes = {"Arena_Vehicle_Mod_Shop_Sounds"_J, "CELEBRATION_SOUNDSET"_J, "DLC_AW_Arena_Office_Planning_Wall_Sounds"_J, "DLC_AW_Arena_Spin_Wheel_Game_Frontend_Sounds"_J, "DLC_Biker_SYG_Sounds"_J, "DLC_BTL_SECURITY_VANS_RADAR_PING_SOUNDS"_J, "DLC_BTL_Target_Pursuit_Sounds"_J, "DLC_GR_Bunker_Door_Sounds"_J, "DLC_GR_CS2_Sounds"_J, "DLC_IO_Warehouse_Mod_Garage_Sounds"_J, "DLC_MPSUM2_HSW_Up_Sounds"_J, "DLC_sum20_Business_Battle_AC_Sounds"_J, "DLC_TG_Running_Back_Sounds"_J, "dlc_vw_table_games_frontend_sounds"_J, "dlc_xm_facility_entry_exit_sounds"_J, "Frontend"_J, "GTAO_Boss_Goons_FM_Soundset"_J, "GTAO_Exec_SecuroServ_Computer_Sounds"_J, "GTAO_Exec_SecuroServ_Warehouse_PC_Sounds"_J, "GTAO_Script_Doors_Faded_Screen_Sounds"_J, "GTAO_SMG_Hangar_Computer_Sounds"_J, "HUD_AMMO_SHOP_SOUNDSET"_J, "HUD_FRONTEND_CUSTOM_SOUNDSET"_J, "HUD_FRONTEND_DEFAULT_SOUNDSET"_J, "HUD_FRONTEND_MP_SOUNDSET"_J, "HUD_FRONTEND_MP_COLLECTABLE_SOUNDS"_J, "HUD_FRONTEND_TATTOO_SHOP_SOUNDSET"_J, "HUD_FRONTEND_CLOTHESSHOP_SOUNDSET"_J, "HUD_FRONTEND_STANDARD_PICKUPS_NPC_SOUNDSET"_J, "HUD_FRONTEND_VEHICLE_PICKUPS_NPC_SOUNDSET"_J, "HUD_FRONTEND_WEAPONS_PICKUPS_NPC_SOUNDSET"_J, "HUD_FREEMODE_SOUNDSET"_J, "HUD_MINI_GAME_SOUNDSET"_J, "HUD_AWARDS"_J, "JA16_Super_Mod_Garage_Sounds"_J, "Low2_Super_Mod_Garage_Sounds"_J, "MissionFailedSounds"_J, "MP_CCTV_SOUNDSET"_J, "MP_LOBBY_SOUNDS"_J, "MP_MISSION_COUNTDOWN_SOUNDSET"_J, "Phone_SoundSet_Default"_J, "Phone_SoundSet_Glasses_Cam"_J, "Phone_SoundSet_Prologue"_J, "Phone_SoundSet_Franklin"_J, "Phone_SoundSet_Michael"_J, "Phone_SoundSet_Trevor"_J, "PLAYER_SWITCH_CUSTOM_SOUNDSET"_J, "RESPAWN_ONLINE_SOUNDSET"_J, "TATTOOIST_SOUNDS"_J, "WastedSounds"_J, "WEB_NAVIGATION_SOUNDS_PHONE"_J}; static const std::unordered_set<uint32_t> blocked_ref_hashes = {"Arena_Vehicle_Mod_Shop_Sounds"_J, "CELEBRATION_SOUNDSET"_J, "DLC_AW_Arena_Office_Planning_Wall_Sounds"_J, "DLC_AW_Arena_Spin_Wheel_Game_Frontend_Sounds"_J, "DLC_Biker_SYG_Sounds"_J, "DLC_BTL_SECURITY_VANS_RADAR_PING_SOUNDS"_J, "DLC_BTL_Target_Pursuit_Sounds"_J, "DLC_GR_Bunker_Door_Sounds"_J, "DLC_GR_CS2_Sounds"_J, "DLC_IO_Warehouse_Mod_Garage_Sounds"_J, "DLC_MPSUM2_HSW_Up_Sounds"_J, "DLC_sum20_Business_Battle_AC_Sounds"_J, "DLC_TG_Running_Back_Sounds"_J, "dlc_vw_table_games_frontend_sounds"_J, "dlc_xm_facility_entry_exit_sounds"_J, "Frontend"_J, "GTAO_Boss_Goons_FM_Soundset"_J, "GTAO_Exec_SecuroServ_Computer_Sounds"_J, "GTAO_Exec_SecuroServ_Warehouse_PC_Sounds"_J, "GTAO_Script_Doors_Faded_Screen_Sounds"_J, "GTAO_SMG_Hangar_Computer_Sounds"_J, "HUD_AMMO_SHOP_SOUNDSET"_J, "HUD_FRONTEND_CUSTOM_SOUNDSET"_J, "HUD_FRONTEND_DEFAULT_SOUNDSET"_J, "HUD_FRONTEND_MP_SOUNDSET"_J, "HUD_FRONTEND_MP_COLLECTABLE_SOUNDS"_J, "HUD_FRONTEND_TATTOO_SHOP_SOUNDSET"_J, "HUD_FRONTEND_CLOTHESSHOP_SOUNDSET"_J, "HUD_FRONTEND_STANDARD_PICKUPS_NPC_SOUNDSET"_J, "HUD_FRONTEND_VEHICLE_PICKUPS_NPC_SOUNDSET"_J, "HUD_FRONTEND_WEAPONS_PICKUPS_NPC_SOUNDSET"_J, "HUD_FREEMODE_SOUNDSET"_J, "HUD_MINI_GAME_SOUNDSET"_J, "HUD_AWARDS"_J, "JA16_Super_Mod_Garage_Sounds"_J, "Low2_Super_Mod_Garage_Sounds"_J, "MissionFailedSounds"_J, "MP_CCTV_SOUNDSET"_J, "MP_LOBBY_SOUNDS"_J, "MP_MISSION_COUNTDOWN_SOUNDSET"_J, "Phone_SoundSet_Default"_J, "Phone_SoundSet_Glasses_Cam"_J, "Phone_SoundSet_Prologue"_J, "Phone_SoundSet_Franklin"_J, "Phone_SoundSet_Michael"_J, "Phone_SoundSet_Trevor"_J, "PLAYER_SWITCH_CUSTOM_SOUNDSET"_J, "RESPAWN_ONLINE_SOUNDSET"_J, "TATTOOIST_SOUNDS"_J, "WastedSounds"_J, "WEB_NAVIGATION_SOUNDS_PHONE"_J};
static const std::unordered_set<uint32_t> blocked_sound_hashes = {"Remote_Ring"_J, "COP_HELI_CAM_ZOOM"_J, "Object_Dropped_Remote"_J}; static const std::unordered_set<uint32_t> blocked_sound_hashes = {"Remote_Ring"_J, "COP_HELI_CAM_ZOOM"_J, "Object_Dropped_Remote"_J};
if (blocked_ref_hashes.contains(ref_hash) || blocked_sound_hashes.contains(sound_hash)) static const std::unordered_set<uint32_t> blocked_script_hashes = {"main_persistent"_J, "shop_controller"_J};
return true;
switch (sound_hash) bool should_block = [&] {
if (blocked_ref_hashes.contains(ref_hash) || blocked_sound_hashes.contains(sound_hash) || blocked_script_hashes.contains(script_hash))
return true;
switch (sound_hash)
{
case "DLC_XM_Explosions_Orbital_Cannon"_J:
{
if (is_entity)
return true;
if (!scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[plyr->id()].OrbitalBitset.IsSet(eOrbitalBitset::kOrbitalCannonActive))
return true;
static const std::unordered_set<uint32_t> valid_script_hashes = {"am_mp_defunct_base"_J, "am_mp_orbital_cannon"_J, "fm_mission_controller_2020"_J, "fm_mission_controller"_J};
if (!valid_script_hashes.contains(script_hash))
return true;
break;
}
}
switch (ref_hash)
{
case "GTAO_Biker_Modes_Soundset"_J:
case "DLC_Biker_Sell_Postman_Sounds"_J:
{
if (is_entity)
return true;
if (script_hash != "gb_biker_contraband_sell"_J)
return true;
break;
}
case "DLC_AW_General_Sounds"_J:
{
if (sound_hash != "Airhorn_Blast_Long"_J)
return true;
if (script_hash != "gb_casino_heist"_J)
return true;
if (!gta_util::find_script_thread("gb_casino_heist"_J))
return true;
break;
}
case "GTAO_FM_Events_Soundset"_J:
{
if (!is_entity)
return true;
if (sound_hash != "Explosion_Countdown"_J)
return true;
break;
}
}
return false;
}();
if (should_block)
{ {
case "DLC_XM_Explosions_Orbital_Cannon"_J: LOGF(stream::net_events, WARNING, "Blocked NETWORK_PLAY_SOUND_EVENT from {} with is_entity: {}, ref_hash: {:X}, sound_hash: {:X}, sound_id: {}, script_hash: {:X}", plyr->get_name(), is_entity ? "T" : "F", ref_hash, sound_hash, sound_id, script_hash);
{
if (is_entity)
return true;
if (!scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[plyr->id()].OrbitalBitset.IsSet(eOrbitalBitset::kOrbitalCannonActive))
return true;
static const std::unordered_set<uint32_t> valid_script_hashes = {"am_mp_defunct_base"_J, "am_mp_orbital_cannon"_J, "fm_mission_controller_2020"_J, "fm_mission_controller"_J};
if (!valid_script_hashes.contains(script_hash))
return true;
break;
}
}
switch (ref_hash)
{
case "GTAO_Biker_Modes_Soundset"_J:
case "DLC_Biker_Sell_Postman_Sounds"_J:
{
if (is_entity)
return true;
if (script_hash != "gb_biker_contraband_sell"_J)
return true;
break;
}
case "DLC_AW_General_Sounds"_J:
{
if (sound_hash != "Airhorn_Blast_Long"_J)
return true;
if (script_hash != "gb_casino_heist"_J)
return true;
if (!gta_util::find_script_thread("gb_casino_heist"_J))
return true;
break;
}
case "GTAO_FM_Events_Soundset"_J:
{
if (!is_entity)
return true;
if (sound_hash != "Explosion_Countdown"_J)
return true;
break;
}
} }
buffer.Seek(0); buffer.Seek(0);
return false; return should_block;
} }
void hooks::received_event(rage::netEventMgr* event_manager, CNetGamePlayer* source_player, CNetGamePlayer* target_player, uint16_t event_id, int event_index, int event_handled_bitset, int buffer_size, rage::datBitBuffer* buffer) void hooks::received_event(rage::netEventMgr* event_manager, CNetGamePlayer* source_player, CNetGamePlayer* target_player, uint16_t event_id, int event_index, int event_handled_bitset, int buffer_size, rage::datBitBuffer* buffer)
@ -545,6 +556,37 @@ namespace big
{ {
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
notify::crash_blocked(source_player, "vehicle temp action"); notify::crash_blocked(source_player, "vehicle temp action");
LOGF(stream::net_events, WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SettingOfTaskVehicleTempAction with action {} that would crash the game", plyr->get_name(), action);
return;
}
}
else if (type == ScriptEntityChangeType::SetVehicleLockState)
{
if (g_local_player && g_local_player->m_vehicle && g_local_player->m_vehicle->m_net_object
&& g_local_player->m_vehicle->m_net_object->m_object_id == entity)
{
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
LOGF(stream::net_events, WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SetVehicleLockState from {} on our local vehicle", plyr->get_name());
return;
}
}
else if (type == ScriptEntityChangeType::SetVehicleExclusiveDriver)
{
if (g_local_player && g_local_player->m_vehicle && g_local_player->m_vehicle->m_net_object
&& g_local_player->m_vehicle->m_net_object->m_object_id == entity)
{
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
LOGF(stream::net_events, WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SetVehicleExclusiveDriver from {} on our local vehicle", plyr->get_name());
g.reactions.vehicle_kick.process(plyr);
return;
}
}
else if (type == ScriptEntityChangeType::SetPedFacialIdleAnimOverride)
{
if (g_local_player && g_local_player->m_net_object && g_local_player->m_net_object->m_object_id)
{
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
LOGF(stream::net_events, WARNING, "Blocked SCRIPT_ENTITY_STATE_CHANGE_EVENT of type SetPedFacialIdleAnimOverride from {} on our local player", plyr->get_name());
return; return;
} }
} }
@ -564,7 +606,6 @@ namespace big
buffer->ReadDword(&scripted_game_event->m_args_size, 32); buffer->ReadDword(&scripted_game_event->m_args_size, 32);
if (scripted_game_event->m_args_size > sizeof(scripted_game_event->m_args)) if (scripted_game_event->m_args_size > sizeof(scripted_game_event->m_args))
{ {
notify::crash_blocked(source_player, "out of bounds tse args size");
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
} }
@ -628,8 +669,12 @@ namespace big
// player sending this event is a modder // player sending this event is a modder
case eNetworkEvents::REPORT_MYSELF_EVENT: case eNetworkEvents::REPORT_MYSELF_EVENT:
{ {
auto p1 = buffer->Read<int>(32);
auto p2 = buffer->Read<int>(32);
LOGF(stream::net_events, VERBOSE, "Received REPORT_MYSELF_EVENT from {} with parameters ({}, {})", plyr->get_name(), p1, p2);
session::add_infraction(plyr, Infraction::TRIGGERED_ANTICHEAT); session::add_infraction(plyr, Infraction::TRIGGERED_ANTICHEAT);
g.reactions.game_anti_cheat_modder_detection.process(plyr); g.reactions.game_anti_cheat_modder_detection.process(plyr);
buffer->Seek(0);
break; break;
} }
case eNetworkEvents::REQUEST_CONTROL_EVENT: case eNetworkEvents::REQUEST_CONTROL_EVENT:
@ -671,20 +716,21 @@ namespace big
if (type == WorldStateDataType::Rope) if (type == WorldStateDataType::Rope)
{ {
buffer->Read<int>(9); // network rope id buffer->Read<int>(9); // network rope id
buffer->Read<float>(19); // pos x buffer->ReadSigned<int>(19); // pos x
buffer->Read<float>(19); // pos y buffer->ReadSigned<int>(19); // pos y
buffer->Read<float>(19); // pos z buffer->Read<int>(19); // pos z
buffer->Read<float>(19); // rot x buffer->ReadSigned<int>(19); // rot x
buffer->Read<float>(19); // rot y buffer->ReadSigned<int>(19); // rot y
buffer->Read<float>(19); // rot z buffer->Read<int>(19); // rot z
buffer->Read<float>(16); // length float max_length = buffer->ReadSignedFloat(16, 100.0f);
int type = buffer->Read<int>(4); int type = buffer->Read<int>(4);
float initial_length = buffer->Read<float>(16); float initial_length = buffer->ReadSignedFloat(16, 100.0f);
float min_length = buffer->Read<float>(16); float min_length = buffer->ReadSignedFloat(16, 100.0f);
if (type == 0 || initial_length < min_length) // https://docs.fivem.net/natives/?_0xE832D760399EB220 if (type == 0 || initial_length < min_length || max_length < min_length || max_length < 0.0f)
{ {
LOGF(stream::net_events, WARNING, "{} sent a SCRIPT_WORLD_STATE_EVENT of type Rope that would crash the game. Script Hash: {:X}, Type: {}, Initial Length: {}, Min Length: {}, Max Length: {}", plyr->get_name(), id.m_hash, type, initial_length, min_length, max_length);
notify::crash_blocked(source_player, "rope"); notify::crash_blocked(source_player, "rope");
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
@ -699,6 +745,7 @@ namespace big
if (pop_group == 0 && (percentage == 0 || percentage == 103)) if (pop_group == 0 && (percentage == 0 || percentage == 103))
{ {
notify::crash_blocked(source_player, "pop group override"); notify::crash_blocked(source_player, "pop group override");
LOGF(stream::net_events, WARNING, "{} sent a SCRIPT_WORLD_STATE_EVENT of type PopGroupOverride that would crash the game. Pop schedule: {}, Pop group: {}, Percentage: {}, Script Hash: {:X}", plyr->get_name(), pop_schedule, pop_group, percentage, id.m_hash);
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
} }
@ -711,6 +758,7 @@ namespace big
} }
else if (type == WorldStateDataType::PopMultiplierArea && g.protections.stop_traffic && !NETWORK::NETWORK_IS_ACTIVITY_SESSION()) else if (type == WorldStateDataType::PopMultiplierArea && g.protections.stop_traffic && !NETWORK::NETWORK_IS_ACTIVITY_SESSION())
{ {
LOGF(stream::net_events, WARNING, "Blocked a SCRIPT_WORLD_STATE_EVENT of type PopMultiplierArea from {}", plyr->get_name());
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
} }
@ -725,6 +773,7 @@ namespace big
if (hash == "WEAPON_UNARMED"_J) if (hash == "WEAPON_UNARMED"_J)
{ {
LOGF(stream::net_events, WARNING, "{} sent a REMOVED_WEAPON_EVENT with weapon hash == WEAPON_UNARMED", plyr->get_name());
notify::crash_blocked(source_player, "remove unarmed"); notify::crash_blocked(source_player, "remove unarmed");
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
@ -811,7 +860,6 @@ namespace big
if (plyr && scan_play_sound_event(plyr, *buffer)) if (plyr && scan_play_sound_event(plyr, *buffer))
{ {
g.reactions.sound_spam.process(plyr); g.reactions.sound_spam.process(plyr);
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset); g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
} }
@ -833,6 +881,7 @@ namespace big
{ {
if (scan_weapon_damage_event(event_manager, source_player, target_player, event_index, event_handled_bitset, buffer)) if (scan_weapon_damage_event(event_manager, source_player, target_player, event_index, event_handled_bitset, buffer))
{ {
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
return; return;
} }
break; break;

View File

@ -21,7 +21,7 @@ namespace big
m_program(program) m_program(program)
{ {
m_orig_bytecode = program->m_code_blocks; m_orig_bytecode = program->m_code_blocks;
if (auto bytecode = g_script_patcher_service->get_script_bytecode(program->m_name_hash)) if (auto bytecode = g_script_patcher_service->get_script_bytecode(program->m_name_hash))
program->m_code_blocks = bytecode; program->m_code_blocks = bytecode;

View File

@ -0,0 +1,12 @@
#include "hooking/hooking.hpp"
namespace big
{
std::uint32_t hooks::get_dlc_hash(void* mgr, std::uint32_t seed)
{
if (g.spoofing.spoof_dlc_hash)
return g.spoofing.dlc_hash;
return g_hooking->get_original<hooks::get_dlc_hash>()(mgr, seed);
}
}

View File

@ -11,6 +11,7 @@
#include <netsync/nodes/ped/CPedTaskTreeDataNode.hpp> #include <netsync/nodes/ped/CPedTaskTreeDataNode.hpp>
#include <netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp> #include <netsync/nodes/physical/CPhysicalScriptGameStateDataNode.hpp>
#include <netsync/nodes/proximity_migrateable/CSectorDataNode.hpp> #include <netsync/nodes/proximity_migrateable/CSectorDataNode.hpp>
#include <netsync/nodes/proximity_migrateable/CGlobalFlagsDataNode.hpp>
#include <netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp> #include <netsync/nodes/dynamic_entity/CDynamicEntityGameStateDataNode.hpp>
#include <netsync/nodes/player/CPlayerAppearanceDataNode.hpp> #include <netsync/nodes/player/CPlayerAppearanceDataNode.hpp>
#include <netsync/nodes/player/CPlayerCameraDataNode.hpp> #include <netsync/nodes/player/CPlayerCameraDataNode.hpp>

View File

@ -132,11 +132,16 @@ namespace big
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp()); const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
const auto& location = msg->Location(); const auto& location = msg->Location();
const auto level = msg->Level(); const auto level = msg->Level();
const auto stream = msg->Stream();
const auto file = std::filesystem::path(location.file_name()).filename().string(); const auto file = std::filesystem::path(location.file_name()).filename().string();
m_console_out << "[" << timestamp << "]" << ADD_COLOR_TO_STREAM(color) << "[" << get_level_string(level) << "/" << file << ":" if (stream)
<< location.line() << "] " << RESET_STREAM_COLOR << msg->Message() << std::flush; m_console_out << "[" << timestamp << "][" << stream->get()->Name() << "]" << ADD_COLOR_TO_STREAM(color) << "[" << get_level_string(level) << "/" << file << ":"
<< location.line() << "] " << RESET_STREAM_COLOR << msg->Message() << std::flush;
else
m_console_out << "[" << timestamp << "]" << ADD_COLOR_TO_STREAM(color) << "[" << get_level_string(level) << "/" << file << ":"
<< location.line() << "] " << RESET_STREAM_COLOR << msg->Message() << std::flush;
} }
void logger::format_console_simple(const LogMessagePtr msg) void logger::format_console_simple(const LogMessagePtr msg)
@ -151,11 +156,16 @@ namespace big
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp()); const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
const auto& location = msg->Location(); const auto& location = msg->Location();
const auto level = msg->Level(); const auto level = msg->Level();
const auto stream = msg->Stream();
const auto file = std::filesystem::path(location.file_name()).filename().string(); const auto file = std::filesystem::path(location.file_name()).filename().string();
m_console_out << "[" << timestamp << "]" if (stream)
<< "[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush; m_console_out << "[" << timestamp << "][" << stream->get()->Name() << "]"
"[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
else
m_console_out << "[" << timestamp << "]"
"[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
} }
void logger::format_file(const LogMessagePtr msg) void logger::format_file(const LogMessagePtr msg)
@ -166,10 +176,15 @@ namespace big
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp()); const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
const auto& location = msg->Location(); const auto& location = msg->Location();
const auto level = msg->Level(); const auto level = msg->Level();
const auto stream = msg->Stream();
const auto file = std::filesystem::path(location.file_name()).filename().string(); const auto file = std::filesystem::path(location.file_name()).filename().string();
m_file_out << "[" << timestamp << "]" if (stream)
<< "[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush; m_file_out << "[" << timestamp << "][" << stream->get()->Name() << "]"
"[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
else
m_file_out << "[" << timestamp << "]"
"[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
} }
} }

View File

@ -1,9 +1,15 @@
#pragma once #pragma once
#include "file_manager.hpp" #include "file_manager.hpp"
#include <AsyncLogger/Logger.hpp> #include <AsyncLogger/Logger.hpp>
using namespace al; using namespace al;
namespace stream
{
inline auto net_events = std::make_shared<LogStream>("net_events");
inline auto net_messages = std::make_shared<LogStream>("net_messages");
inline auto net_sync = std::make_shared<LogStream>("net_sync");
}
namespace big namespace big
{ {
#define ADD_COLOR_TO_STREAM(color) "\x1b[" << int(color) << "m" #define ADD_COLOR_TO_STREAM(color) "\x1b[" << int(color) << "m"

View File

@ -71,16 +71,6 @@ namespace big
} }
else else
{ {
if (g.session.force_script_host && (g.session.fast_join || NETWORK::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA()))
{
auto hash = SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME();
g_fiber_pool->queue_job([hash] {
scripts::force_host(hash);
if (auto script = gta_util::find_script_thread(hash); script && script->m_net_component)
((CGameScriptHandlerNetComponent*)script->m_net_component)->block_host_migration(true);
});
}
if (SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME() == "freemode"_J && g.session.fast_join) if (SCRIPT::GET_HASH_OF_THIS_SCRIPT_NAME() == "freemode"_J && g.session.fast_join)
{ {
scr_functions::set_freemode_session_active({}); scr_functions::set_freemode_session_active({});

View File

@ -11,7 +11,7 @@ namespace big
{ {
if (g.session.join_queued) if (g.session.join_queued)
{ {
g_pointers->m_gta.m_join_session_by_info(*g_pointers->m_gta.m_network, &g.session.info, 1, 1 | 2, nullptr, 0); g_pointers->m_gta.m_join_session_by_info(*g_pointers->m_gta.m_network, &g.session.info, g.session.join_in_sctv_slots ? 1 : 0, 1 | 2, nullptr, 0);
g.session.join_queued = false; g.session.join_queued = false;
src->set_return_value<BOOL>(TRUE); src->set_return_value<BOOL>(TRUE);
} }

View File

@ -653,6 +653,15 @@ namespace big
g_pointers->m_gta.m_host_token = ptr.add(3).rip().as<uint64_t*>(); g_pointers->m_gta.m_host_token = ptr.add(3).rip().as<uint64_t*>();
} }
}, },
// Peer ID
{
"PI",
"48 83 F8 FF 74 0D",
[](memory::handle ptr)
{
g_pointers->m_gta.m_peer_id = ptr.add(9).rip().as<uint64_t*>();
}
},
// Profile Gamer Info // Profile Gamer Info
{ {
"PGI", "PGI",
@ -1803,6 +1812,79 @@ namespace big
{ {
g_pointers->m_gta.m_session_request_patch = ptr.add(0x13).as<PVOID>(); g_pointers->m_gta.m_session_request_patch = ptr.add(0x13).as<PVOID>();
} }
},
// Get Peer By Security Id
{
"GPBSI",
"76 E0 8B 4C 24 30 E8",
[](memory::handle ptr)
{
g_pointers->m_gta.m_get_peer_by_security_id = ptr.add(7).rip().as<functions::get_peer_by_security_id>();
}
},
// Game Data Hash
{
"GDH",
"BA 05 AC 17 D9",
[](memory::handle ptr)
{
g_pointers->m_gta.m_game_data_hash = ptr.add(0x18).rip().as<GameDataHash**>();
}
},
// Get DLC Hash
{
"GDLCH",
"74 0B 41 BC 10",
[](memory::handle ptr)
{
g_pointers->m_gta.m_dlc_manager = ptr.sub(0x11).rip().as<void**>();
g_pointers->m_gta.m_get_dlc_hash = ptr.sub(0xA).rip().as<PVOID>();
}
},
// Add Gamer To Session
{
"AGTS",
"7C E8 EB 23",
[](memory::handle ptr)
{
g_pointers->m_gta.m_add_gamer_to_session = ptr.add(0x23).rip().as<PVOID>();
}
},
// Set Head Blend Data
{
"SHBD",
"44 88 B2 3A 01",
[](memory::handle ptr)
{
g_pointers->m_gta.m_set_head_blend_data = ptr.sub(0x21).as<functions::set_head_blend_data>();
}
},
// Object Ids Offset
{
"OIO",
"FF 50 50 48 83 C7 08",
[](memory::handle ptr)
{
g_pointers->m_gta.m_object_ids_offset = ptr.add(0xF).as<std::uint32_t*>();
}
},
// Error Packet Memmove
{
"EPM",
"49 8D 4C 24 60 44 8B C0 E8",
[](memory::handle ptr)
{
g_pointers->m_gta.m_error_packet_memmove = ptr.add(0x8).as<PVOID>();
}
},
// Create Pool Item
{
"CPI",
"18 83 F9 FF 75",
[](memory::handle ptr)
{
g_pointers->m_gta.m_create_pool_item = ptr.sub(0x6).as<PVOID>();
}
} }
>(); // don't leave a trailing comma at the end >(); // don't leave a trailing comma at the end

View File

@ -163,6 +163,7 @@ namespace big
}}, }},
{"ANIMATION", {"ANIMATION",
[this] { [this] {
// TODO: maybe inform the user of this behavior
if(STREAMING::DOES_ANIM_DICT_EXIST(g_ped_animation_service.current_animation.dict.data())) if(STREAMING::DOES_ANIM_DICT_EXIST(g_ped_animation_service.current_animation.dict.data()))
g_ped_animation_service.play_saved_ped_animation(g_ped_animation_service.current_animation, m_handle); g_ped_animation_service.play_saved_ped_animation(g_ped_animation_service.current_animation, m_handle);
else else

View File

@ -38,6 +38,7 @@ namespace big
XML_MAPS, XML_MAPS,
NETWORK, NETWORK,
CHAT,
MISSIONS, MISSIONS,
SPOOFING, SPOOFING,
PLAYER_DATABASE, PLAYER_DATABASE,
@ -139,8 +140,9 @@ namespace big
TAB_DECL(NETWORK), TAB_DECL(NETWORK),
view::network, view::network,
{ {
{TAB_DECL(SPOOFING), view::spoofing}}, {TAB_DECL(CHAT), view::chat}},
{TAB_DECL(MISSIONS), view::missions}}, {TAB_DECL(MISSIONS), view::missions}},
{TAB_DECL(SPOOFING), view::spoofing}},
{TAB_DECL(PLAYER_DATABASE), view::player_database}}, {TAB_DECL(PLAYER_DATABASE), view::player_database}},
{TAB_DECL(SESSION_BROWSER), view::session_browser}}, {TAB_DECL(SESSION_BROWSER), view::session_browser}},
{TAB_DECL(STAT_EDITOR), view::stat_editor}}, {TAB_DECL(STAT_EDITOR), view::stat_editor}},

View File

@ -7,6 +7,8 @@
#include "renderer/renderer.hpp" #include "renderer/renderer.hpp"
#include "util/teleport.hpp" #include "util/teleport.hpp"
#include <script/GtaThread.hpp>
namespace big namespace big
{ {
hotkey_service::hotkey_service() hotkey_service::hotkey_service()

View File

@ -43,7 +43,7 @@ namespace big
attributes->m_param_values[0] &= ~(1 << 14); // Good Sport attributes->m_param_values[0] &= ~(1 << 14); // Good Sport
} }
bool matchmaking_service::matchmake(std::optional<int> constraint) bool matchmaking_service::matchmake(std::optional<int> constraint, std::optional<bool> enforce_player_limit)
{ {
for (auto& session : m_found_sessions) for (auto& session : m_found_sessions)
{ {
@ -69,6 +69,7 @@ namespace big
static rage::rlSessionInfo result_sessions[MAX_SESSIONS_TO_FIND]; static rage::rlSessionInfo result_sessions[MAX_SESSIONS_TO_FIND];
m_active = true; m_active = true;
m_num_valid_sessions = 0;
if (g_hooking->get_original<hooks::start_matchmaking_find_sessions>()(0, 1, &component, MAX_SESSIONS_TO_FIND, result_sessions, &m_num_sessions_found, &state)) if (g_hooking->get_original<hooks::start_matchmaking_find_sessions>()(0, 1, &component, MAX_SESSIONS_TO_FIND, result_sessions, &m_num_sessions_found, &state))
{ {
@ -77,11 +78,26 @@ namespace big
if (state.status == 3) if (state.status == 3)
{ {
std::unordered_map<std::uint64_t, session*> stok_map = {};
for (int i = 0; i < m_num_sessions_found; i++) for (int i = 0; i < m_num_sessions_found; i++)
{ {
m_found_sessions[i].info = result_sessions[i]; m_found_sessions[i].info = result_sessions[i];
if (constraint && m_found_sessions[i].attributes.player_count >= 30) if (auto it = stok_map.find(m_found_sessions[i].info.m_session_token); it != stok_map.end())
{
if (g.session_browser.filter_multiplexed_sessions)
{
it->second->is_valid = false;
}
it->second->attributes.multiplex_count++;
m_found_sessions[i].is_valid = false;
continue;
}
if (enforce_player_limit.has_value() && enforce_player_limit.value()
&& m_found_sessions[i].attributes.player_count >= 30)
m_found_sessions[i].is_valid = false; m_found_sessions[i].is_valid = false;
if (g.session_browser.language_filter_enabled if (g.session_browser.language_filter_enabled
@ -99,6 +115,8 @@ namespace big
&& ((m_found_sessions[i].attributes.discriminator & (1 << 14)) == (1 << 14)) && ((m_found_sessions[i].attributes.discriminator & (1 << 14)) == (1 << 14))
!= (bool)g.session_browser.pool_filter) != (bool)g.session_browser.pool_filter)
m_found_sessions[i].is_valid = false; m_found_sessions[i].is_valid = false;
stok_map.emplace(m_found_sessions[i].info.m_session_token, &m_found_sessions[i]);
} }
if (g.session_browser.sort_method != 0) if (g.session_browser.sort_method != 0)

View File

@ -24,6 +24,7 @@ namespace big
int player_count; int player_count;
int region; int region;
int language; int language;
int multiplex_count = 1;
}; };
struct session struct session
@ -35,6 +36,7 @@ namespace big
private: private:
int m_num_sessions_found = 0; int m_num_sessions_found = 0;
int m_num_valid_sessions = 0;
bool m_active = false; bool m_active = false;
session m_found_sessions[MAX_SESSIONS_TO_FIND]; session m_found_sessions[MAX_SESSIONS_TO_FIND];
std::unordered_map<std::uint32_t, std::vector<MatchmakingId>> m_multiplexed_sessions; std::unordered_map<std::uint32_t, std::vector<MatchmakingId>> m_multiplexed_sessions;
@ -44,7 +46,7 @@ namespace big
public: public:
matchmaking_service(); matchmaking_service();
~matchmaking_service(); ~matchmaking_service();
bool matchmake(std::optional<int> constraint = std::nullopt); bool matchmake(std::optional<int> constraint = std::nullopt, std::optional<bool> enforce_player_limit = std::nullopt);
bool handle_advertise(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* out_id, rage::rlTaskStatus* status); 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); void handle_update(int num_slots, int available_slots, rage::rlSessionInfo* info, MatchmakingAttributes* attributes, MatchmakingId* id);
@ -56,6 +58,11 @@ namespace big
return m_num_sessions_found; return m_num_sessions_found;
} }
inline int get_num_valid_sessions()
{
return m_num_valid_sessions;
}
inline session* get_found_sessions() inline session* get_found_sessions()
{ {
return m_found_sessions; return m_found_sessions;

View File

@ -24,6 +24,7 @@ namespace big
{Infraction::UNDEAD_OTR, "Had used undead OTR"}, {Infraction::UNDEAD_OTR, "Had used undead OTR"},
{Infraction::CUSTOM_REASON, ""}, {Infraction::CUSTOM_REASON, ""},
{Infraction::CHAT_SPAM, "Chat spammer"}, {Infraction::CHAT_SPAM, "Chat spammer"},
{Infraction::SENT_MODDER_BEACONS, "Sent modder beacons"},
}; };
const char* persistent_player::get_infraction_description(int infraction) const char* persistent_player::get_infraction_description(int infraction)

View File

@ -73,10 +73,8 @@ namespace big
rate_limiter m_radio_station_change_rate_limit{1s, 3}; rate_limiter m_radio_station_change_rate_limit{1s, 3};
bool block_radio_requests = false; bool block_radio_requests = false;
bool received_object_id_request = false;
int m_num_spawned_permanent_vehicles = 0; bool received_object_id_response = false;
bool m_block_permanent_vehicles = false;
bool is_modder = false; bool is_modder = false;
bool is_trusted = false; bool is_trusted = false;
@ -104,6 +102,7 @@ namespace big
int spectating_player = -1; int spectating_player = -1;
menu_settings::script_block_opts script_block_opts{};
protected: protected:
bool equals(const CNetGamePlayer* net_game_player) const; bool equals(const CNetGamePlayer* net_game_player) const;

View File

@ -29,6 +29,7 @@ namespace big
void player_service::do_cleanup() void player_service::do_cleanup()
{ {
m_players_sending_modder_beacons.clear();
m_selected_player = m_dummy; m_selected_player = m_dummy;
m_players.clear(); m_players.clear();
} }
@ -119,6 +120,16 @@ namespace big
} }
} }
void player_service::mark_player_as_sending_modder_beacons(std::uint64_t rid)
{
m_players_sending_modder_beacons.insert(rid);
}
bool player_service::did_player_send_modder_beacon(std::uint64_t rid)
{
return m_players_sending_modder_beacons.contains(rid);
}
void player_service::set_selected(player_ptr plyr) void player_service::set_selected(player_ptr plyr)
{ {
m_selected_player = plyr; m_selected_player = plyr;

View File

@ -20,6 +20,8 @@ namespace big
player_ptr m_dummy = std::make_shared<player>(nullptr); player_ptr m_dummy = std::make_shared<player>(nullptr);
player_ptr m_selected_player; player_ptr m_selected_player;
std::unordered_set<std::uint64_t> m_players_sending_modder_beacons;
public: public:
player_service(); player_service();
~player_service(); ~player_service();
@ -40,6 +42,8 @@ namespace big
void player_join(CNetGamePlayer* net_game_player); void player_join(CNetGamePlayer* net_game_player);
void player_leave(CNetGamePlayer* net_game_player); void player_leave(CNetGamePlayer* net_game_player);
void mark_player_as_sending_modder_beacons(std::uint64_t rid);
bool did_player_send_modder_beacon(std::uint64_t rid);
players& players() players& players()
{ {

View File

@ -178,8 +178,6 @@ namespace big
if (!m_thread->m_stack || !m_thread->m_net_component) if (!m_thread->m_stack || !m_thread->m_net_component)
return false; return false;
} }
((CGameScriptHandlerNetComponent*)m_thread->m_net_component)->block_host_migration(true);
} }
return true; return true;

View File

@ -308,6 +308,14 @@ namespace big
case 12: preferred_lang = "zh_CN"; break; case 12: preferred_lang = "zh_CN"; break;
} }
if (game_lang == 12 || game_lang == 9)
{
// Tweaks to make it easier for people playing in the China region
g.session_browser.filter_multiplexed_sessions = true;
g.reactions.chat_spam.block_joins = true;
g.reactions.chat_spam.block_join_reason = 27;
}
if (does_language_exist(preferred_lang)) if (does_language_exist(preferred_lang))
{ {
m_local_index.selected_language = preferred_lang; m_local_index.selected_language = preferred_lang;

View File

@ -4,6 +4,7 @@
#include "pointers.hpp" #include "pointers.hpp"
#include "util/misc.hpp" #include "util/misc.hpp"
#include "util/vehicle.hpp" #include "util/vehicle.hpp"
#include "util/pools.hpp"
#include "util/world_model.hpp" #include "util/world_model.hpp"
#include "vehicle/CVehicle.hpp" #include "vehicle/CVehicle.hpp"

View File

@ -1,4 +1,29 @@
#include "entity.hpp" #include "entity.hpp"
#include "gta/joaat.hpp"
#include "gta_util.hpp"
#include "math.hpp"
#include "natives.hpp"
#include "pools.hpp"
#include "script.hpp"
#include "services/players/player_service.hpp"
#include "packet.hpp"
#include "gta/net_object_mgr.hpp"
#include <entities/CDynamicEntity.hpp>
namespace
{
int get_next_token_value(int prev_token)
{
for (int i = 0; i < 0x1F; i++)
{
if ((i << 27) - (prev_token << 27) > 0)
return i;
}
return 0;
}
}
namespace big::entity namespace big::entity
{ {
@ -350,4 +375,58 @@ namespace big::entity
return closest_entity; return closest_entity;
} }
void force_remove_network_entity(rage::CDynamicEntity* entity, bool delete_locally)
{
if (!entity->m_net_object)
return;
force_remove_network_entity(entity->m_net_object->m_object_id, entity->m_net_object->m_ownership_token, delete_locally);
}
void force_remove_network_entity(std::uint16_t net_id, int ownership_token, bool delete_locally)
{
char buf[0x200]{};
rage::datBitBuffer remove_buf(buf, sizeof(buf));
int msgs_written = 0;
if (ownership_token != -1)
{
remove_buf.Write<std::uint16_t>(net_id, 13);
remove_buf.Write<int>(get_next_token_value(ownership_token), 5);
msgs_written++;
}
else
{
// try all tokens if we don't know it
for (int i = 0; i < 0x1F; i++)
{
remove_buf.Write<std::uint16_t>(net_id, 13);
remove_buf.Write<int>(i, 5);
msgs_written++;
}
}
packet pack;
pack.write_message(rage::eNetMessage::MsgPackedReliables);
pack.write<int>(4, 4); // remove
pack.write<int>(msgs_written, 5);
pack.write<int>(remove_buf.GetPosition(), 13);
pack.m_buffer.WriteArray(&buf, remove_buf.GetPosition());
for (auto& player : g_player_service->players())
{
if (player.second->get_net_game_player())
{
if (!player.second->get_ped() || player.second->get_ped()->m_net_object->m_object_id != net_id) // would crash the player otherwise
{
pack.send(player.second->get_net_game_player()->m_msg_id);
}
}
}
if (delete_locally)
if (auto object = (*g_pointers->m_gta.m_network_object_mgr)->find_object_by_id(net_id, true))
(*g_pointers->m_gta.m_network_object_mgr)->UnregisterNetworkObject(object, 8, true, true);
}
} }

View File

@ -1,11 +1,12 @@
#pragma once #pragma once
#include "gta/joaat.hpp" #include <script/types.hpp>
#include "gta_util.hpp" #include <rage/vector.hpp>
#include "math.hpp"
#include "natives.hpp" namespace rage
#include "pools.hpp" {
#include "script.hpp" class netObject;
#include "services/players/player_service.hpp" class CEntity;
}
namespace big::entity namespace big::entity
{ {
@ -21,4 +22,6 @@ namespace big::entity
bool request_model(rage::joaat_t hash); bool request_model(rage::joaat_t hash);
double distance_to_middle_of_screen(const rage::fvector2& screen_pos); double distance_to_middle_of_screen(const rage::fvector2& screen_pos);
Entity get_entity_closest_to_middle_of_screen(rage::fwEntity** pointer = nullptr, std::vector<Entity> ignore_entities = {}, bool include_veh = true, bool include_ped = true, bool include_prop = true, bool include_players = true); Entity get_entity_closest_to_middle_of_screen(rage::fwEntity** pointer = nullptr, std::vector<Entity> ignore_entities = {}, bool include_veh = true, bool include_ped = true, bool include_prop = true, bool include_players = true);
void force_remove_network_entity(rage::CDynamicEntity* entity, bool delete_locally = true);
void force_remove_network_entity(std::uint16_t net_id, int ownership_token = -1, bool delete_locally = true);
} }

View File

@ -7,15 +7,18 @@ namespace big
{ {
inline static memory::byte_patch* m_can_blame_others; inline static memory::byte_patch* m_can_blame_others;
inline static memory::byte_patch* m_can_use_blocked_explosions; inline static memory::byte_patch* m_can_use_blocked_explosions;
inline static memory::byte_patch* m_set_script_flag;
inline static void apply() inline static void apply()
{ {
explosion_anti_cheat_bypass::m_can_blame_others->apply(); explosion_anti_cheat_bypass::m_can_blame_others->apply();
explosion_anti_cheat_bypass::m_can_use_blocked_explosions->apply(); explosion_anti_cheat_bypass::m_can_use_blocked_explosions->apply();
explosion_anti_cheat_bypass::m_set_script_flag->apply();
} }
inline static void restore() inline static void restore()
{ {
explosion_anti_cheat_bypass::m_set_script_flag->restore();
explosion_anti_cheat_bypass::m_can_use_blocked_explosions->restore(); explosion_anti_cheat_bypass::m_can_use_blocked_explosions->restore();
explosion_anti_cheat_bypass::m_can_blame_others->restore(); explosion_anti_cheat_bypass::m_can_blame_others->restore();
} }

View File

@ -6,6 +6,7 @@
#include "outfit.hpp" #include "outfit.hpp"
#include "pointers.hpp" #include "pointers.hpp"
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "script.hpp"
namespace big::ped namespace big::ped
{ {
@ -477,15 +478,37 @@ namespace big::ped
return true; return true;
} }
inline void clone_ped(const Ped src, const Ped target)
{
PED::CLONE_PED_TO_TARGET(src, target);
auto src_ptr = g_pointers->m_gta.m_handle_to_ptr(src);
auto dst_ptr = g_pointers->m_gta.m_handle_to_ptr(target);
if (src_ptr && dst_ptr)
{
for (auto container = src_ptr->m_extension_container; container; container = container->m_next)
{
if (container->m_entry && container->m_entry->get_id() == 0xB)
{
g_pointers->m_gta.m_set_head_blend_data(reinterpret_cast<CPed*>(dst_ptr), reinterpret_cast<CHeadBlendData*>(container->m_entry));
break;
}
}
}
}
inline void steal_identity(const Ped target) inline void steal_identity(const Ped target)
{ {
const int max_health = ENTITY::GET_ENTITY_MAX_HEALTH(self::ped); const int max_health = ENTITY::GET_ENTITY_MAX_HEALTH(self::ped);
const int current_health = ENTITY::GET_ENTITY_HEALTH(self::ped); const int current_health = ENTITY::GET_ENTITY_HEALTH(self::ped);
const int current_armor = PED::GET_PED_ARMOUR(self::ped); const int current_armor = PED::GET_PED_ARMOUR(self::ped);
PLAYER::SET_PLAYER_MODEL(self::id, ENTITY::GET_ENTITY_MODEL(target)); if (ENTITY::GET_ENTITY_MODEL(target) != ENTITY::GET_ENTITY_MODEL(self::id))
script::get_current()->yield(); {
PED::CLONE_PED_TO_TARGET(target, self::ped); PLAYER::SET_PLAYER_MODEL(self::id, ENTITY::GET_ENTITY_MODEL(target));
script::get_current()->yield();
}
clone_ped(target, self::ped);
ENTITY::SET_ENTITY_MAX_HEALTH(self::ped, max_health); ENTITY::SET_ENTITY_MAX_HEALTH(self::ped, max_health);
ENTITY::SET_ENTITY_HEALTH(self::ped, current_health, 0, 0); ENTITY::SET_ENTITY_HEALTH(self::ped, current_health, 0, 0);
PED::SET_PED_ARMOUR(self::ped, current_armor); PED::SET_PED_ARMOUR(self::ped, current_armor);
@ -505,7 +528,7 @@ namespace big::ped
} }
} }
inline Ped spawn(ePedType pedType, Hash hash, Hash clone, Vector3 location, float heading, bool is_networked = true) inline Ped spawn(ePedType pedType, Hash hash, Ped clone, Vector3 location, float heading, bool is_networked = true)
{ {
if (entity::request_model(hash)) if (entity::request_model(hash))
{ {
@ -515,7 +538,7 @@ namespace big::ped
if (clone) if (clone)
{ {
PED::CLONE_PED_TO_TARGET(clone, ped); clone_ped(clone, ped);
} }
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash); STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);

View File

@ -5,6 +5,7 @@
#include "pointers.hpp" #include "pointers.hpp"
#include "script_global.hpp" #include "script_global.hpp"
#include "services/players/player_service.hpp" #include "services/players/player_service.hpp"
#include "pools.hpp"
namespace big::train namespace big::train
{ {

View File

@ -1,4 +1,5 @@
#include "vehicle.hpp" #include "vehicle.hpp"
#include "pools.hpp"
namespace big::vehicle namespace big::vehicle
{ {

View File

@ -1,6 +1,7 @@
#include "fiber_pool.hpp" #include "fiber_pool.hpp"
#include "views/view.hpp" #include "views/view.hpp"
#include "script_mgr.hpp" #include "script_mgr.hpp"
#include "pointers.hpp"
namespace big namespace big
{ {
@ -23,6 +24,7 @@ namespace big
{(300.f * g.window.gui_scale) - ImGui::CalcTextSize("UNLOAD"_T.data()).x - ImGui::GetStyle().ItemSpacing.x, {(300.f * g.window.gui_scale) - ImGui::CalcTextSize("UNLOAD"_T.data()).x - ImGui::GetStyle().ItemSpacing.x,
ImGui::GetStyle().WindowPadding.y / 2 + ImGui::GetStyle().ItemSpacing.y + (ImGui::CalcTextSize("W").y / 2)}); ImGui::GetStyle().WindowPadding.y / 2 + ImGui::GetStyle().ItemSpacing.y + (ImGui::CalcTextSize("W").y / 2)});
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.69f, 0.29f, 0.29f, 1.00f)); ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.69f, 0.29f, 0.29f, 1.00f));
ImGui::BeginDisabled(g_pointers && *g_pointers->m_gta.m_is_session_started);
if (components::nav_button("UNLOAD"_T)) if (components::nav_button("UNLOAD"_T))
{ {
// allow to unload in the main title screen. // allow to unload in the main title screen.
@ -45,6 +47,7 @@ namespace big
g_running = false; g_running = false;
} }
} }
ImGui::EndDisabled();
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
ImGui::End(); ImGui::End();

View File

@ -91,11 +91,6 @@ namespace big
{ {
components::button("VIEW_DEBUG_THREADS_TAKE_CONTROL"_T, [net_handler] { components::button("VIEW_DEBUG_THREADS_TAKE_CONTROL"_T, [net_handler] {
net_handler->send_host_migration_event(g_player_service->get_self()->get_net_game_player()); net_handler->send_host_migration_event(g_player_service->get_self()->get_net_game_player());
script::get_current()->yield(10ms);
if (selected_thread->m_stack && selected_thread->m_net_component)
{
net_handler->block_host_migration(true);
}
}); });
} }
} }

View File

@ -0,0 +1,92 @@
#include "core/scr_globals.hpp"
#include "fiber_pool.hpp"
#include "gta_util.hpp"
#include "views/view.hpp"
#include "util/chat.hpp"
#include "core/data/command_access_levels.hpp"
namespace big
{
struct target_language_type
{
const char* type;
const char* name;
};
void view::chat()
{
static char msg[256];
ImGui::Checkbox("USE_SPAM_TIMER"_T.data(), &g.session.use_spam_timer);
if (g.session.use_spam_timer)
{
ImGui::SliderFloat("SPAM_TIMER"_T.data(), &g.session.spam_timer, 0.5f, 5.0f);
ImGui::SliderInt("SPAM_LENGTH"_T.data(), &g.session.spam_length, 1, 256);
}
ImGui::Checkbox("LOG_CHAT_MSG"_T.data(), &g.session.log_chat_messages);
ImGui::Checkbox("LOG_TXT_MSG"_T.data(), &g.session.log_text_messages);
components::input_text_with_hint("##message", "VIEW_NET_CHAT_MESSAGE"_T, msg, sizeof(msg));
ImGui::Checkbox("IS_TEAM"_T.data(), &g.session.is_team);
ImGui::SameLine();
components::button("SEND"_T, [] {
if (const auto net_game_player = gta_util::get_network_player_mgr()->m_local_net_player; net_game_player)
{
chat::send_message(msg, nullptr, true, g.session.is_team);
}
});
ImGui::Separator();
ImGui::Checkbox("CHAT_COMMANDS"_T.data(), &g.session.chat_commands);
if (g.session.chat_commands)
{
components::small_text("DEFAULT_CMD_PERMISSIONS"_T);
if (ImGui::BeginCombo("##defualtchatcommands", COMMAND_ACCESS_LEVELS[g.session.chat_command_default_access_level]))
{
for (const auto& [type, name] : COMMAND_ACCESS_LEVELS)
{
if (ImGui::Selectable(name, type == g.session.chat_command_default_access_level))
{
g.session.chat_command_default_access_level = type;
}
if (type == g.session.chat_command_default_access_level)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
}
components::command_checkbox<"translatechat">();
if (g.session.chat_translator.enabled)
{
ImGui::Checkbox("TRANSLATOR_HIDE_SAME_LANGUAGE"_T.data(), &g.session.chat_translator.bypass_same_language);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("TRANSLATOR_HIDE_SAME_LANGUAGE_DESC"_T.data());
components::small_text("TRANSLATOR_OUTPUT"_T.data());
ImGui::Checkbox("TRANSLATOR_SHOW_ON_CHAT"_T.data(), &g.session.chat_translator.draw_result);
ImGui::Checkbox("TRANSLATOR_PRINT_TO_CONSOLE"_T.data(), &g.session.chat_translator.print_result);
static const auto target_language = std::to_array<target_language_type>({{"sq", "Albanian"}, {"ar", "Arabic"}, {"az", "Azerbaijani"}, {"bn", "Bengali"}, {"bg", "Bulgarian"}, {"ca", "Catalan"}, {"zh", "Chinese"}, {"zt", "Chinese(traditional)"}, {"cs", "Czech"}, {"da", "Danish"}, {"nl", "Dutch"}, {"en", "English"}, {"eo", "Esperanto"}, {"et", "Estonian"}, {"fi", "Finnish"}, {"fr", "French"}, {"de", "German"}, {"el", "Greek"}, {"he", "Hebrew"}, {"hi", "Hindi"}, {"hu", "Hungarian"}, {"id", "Indonesian"}, {"ga", "Irish"}, {"it", "Italian"}, {"ja", "Japanese"}, {"ko", "Korean"}, {"lv", "Latvian"}, {"lt", "Lithuanian"}, {"ms", "Malay"}, {"nb", "Norwegian"}, {"fa", "Persian"}, {"pl", "Polish"}, {"pt", "Portuguese"}, {"ro", "Romanian"}, {"ru", "Russian"}, {"sr", "Serbian"}, {"sk", "Slovak"}, {"sl", "Slovenian"}, {"es", "Spanish"}, {"sv", "Swedish"}, {"tl", "Tagalog"}, {"th", "Thai"}, {"tr", "Turkish"}, {"uk", "Ukrainian"}, {"ur", "Urdu"}, {"vi", "Vietnamese"}});
components::input_text_with_hint("TRANSLATOR_ENDPOINT"_T.data(),
"http://localhost:5000/translate",
g.session.chat_translator.endpoint);
if (ImGui::BeginCombo("TRANSLATOR_TARGET_LANGUAGE"_T.data(), g.session.chat_translator.target_language.c_str()))
{
for (const auto& [type, name] : target_language)
{
components::selectable(name, false, [&type] {
g.session.chat_translator.target_language = type;
});
}
ImGui::EndCombo();
}
}
}
}

View File

@ -1,11 +1,9 @@
#include "core/data/apartment_names.hpp" #include "core/data/apartment_names.hpp"
#include "core/data/command_access_levels.hpp"
#include "core/data/region_codes.hpp" #include "core/data/region_codes.hpp"
#include "core/data/warehouse_names.hpp" #include "core/data/warehouse_names.hpp"
#include "fiber_pool.hpp" #include "fiber_pool.hpp"
#include "gta_util.hpp" #include "gta_util.hpp"
#include "hooking/hooking.hpp" #include "hooking/hooking.hpp"
#include "util/chat.hpp"
#include "util/scripts.hpp" #include "util/scripts.hpp"
#include "util/session.hpp" #include "util/session.hpp"
#include "util/troll.hpp" #include "util/troll.hpp"
@ -26,125 +24,104 @@ namespace big
const char* name; const char* name;
}; };
struct target_language_type void render_join_game()
{ {
const char* type; ImGui::SeparatorText("JOIN_GAME"_T.data());
const char* name;
};
void render_rid_joiner()
{
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("RID_JOINER"_T); static uint64_t rid = 0;
if (ImGui::BeginListBox("##ridjoiner", get_listbox_dimensions())) static char username[20];
static char base64[500]{};
ImGui::SetNextItemWidth(200);
ImGui::InputScalar("##inputrid", ImGuiDataType_U64, &rid);
ImGui::SameLine();
components::button("JOIN_BY_RID"_T, [] {
session::join_by_rockstar_id(rid);
});
ImGui::SetNextItemWidth(200);
components::input_text_with_hint("##usernameinput", "INPUT_USERNAME"_T, username, sizeof(username));
ImGui::SameLine();
if (components::button("JOIN_BY_USERNAME"_T))
{ {
static uint64_t rid = 0; session::join_by_username(username);
static char username[20]; };
static char base64[500]{};
ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.5); ImGui::SetNextItemWidth(200);
components::input_text_with_hint("##sessioninfoinput", "SESSION_INFO"_T, base64, sizeof(base64));
ImGui::SameLine();
components::button("JOIN_SESSION_INFO"_T, [] {
rage::rlSessionInfo info;
if (g_pointers->m_gta.m_decode_session_info(&info, base64, nullptr))
session::join_session(info);
else
g_notification_service.push_error("RID_JOINER"_T.data(), "VIEW_NET_RIDJOINER_SESSION_INFO_INVALID"_T.data());
});
ImGui::InputScalar("##inputrid", ImGuiDataType_U64, &rid); components::button("COPY_SESSION_INFO"_T, [] {
ImGui::SameLine(); char buf[0x100]{};
components::button("JOIN_BY_RID"_T, [] { g_pointers->m_gta.m_encode_session_info(&gta_util::get_network()->m_last_joined_session.m_session_info, buf, 0xA9, nullptr);
session::join_by_rockstar_id(rid); ImGui::SetClipboardText(buf);
}); });
components::input_text_with_hint("##usernameinput", "INPUT_USERNAME"_T, username, sizeof(username)); ImGui::Checkbox("JOIN_IN_SCTV"_T.data(), &g.session.join_in_sctv_slots);
ImGui::SameLine(); if (ImGui::IsItemHovered())
if (components::button("JOIN_BY_USERNAME"_T)) ImGui::SetTooltip("JOIN_IN_SCTV_DESC"_T.data());
{
session::join_by_username(username);
};
components::input_text_with_hint("##sessioninfoinput", "SESSION_INFO"_T, base64, sizeof(base64)); ImGui::Checkbox("PLAYER_MAGNET"_T.data(), &g.session.player_magnet_enabled);
ImGui::SameLine(); if (g.session.player_magnet_enabled)
components::button("JOIN_SESSION_INFO"_T, [] { {
rage::rlSessionInfo info; ImGui::Text("PLAYER_COUNT"_T.data());
if (g_pointers->m_gta.m_decode_session_info(&info, base64, nullptr)) ImGui::InputInt("##playercount", &g.session.player_magnet_count);
session::join_session(info);
else
g_notification_service.push_error("RID_JOINER"_T.data(), "VIEW_NET_RIDJOINER_SESSION_INFO_INVALID"_T.data());
});
components::button("COPY_SESSION_INFO"_T, [] {
char buf[0x100]{};
g_pointers->m_gta.m_encode_session_info(&gta_util::get_network()->m_last_joined_session.m_session_info, buf, 0xA9, nullptr);
ImGui::SetClipboardText(buf);
});
ImGui::PopItemWidth();
ImGui::EndListBox();
} }
ImGui::EndGroup(); ImGui::EndGroup();
}
void render_session_switcher() ImGui::SameLine();
{
if (g_pointers->m_gta.m_region_code == nullptr)
return;
static int selected_region_index = -1;
static bool region_updated = false;
std::string region_str =
(selected_region_index == -1) ? "SESSION_SELECT_COMBO"_T.data() : regions[*g_pointers->m_gta.m_region_code].name;
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("SESSION_SELECT"_T); std::string region_str = regions[*g_pointers->m_gta.m_region_code].name;
if (ImGui::BeginListBox("###session_switch", get_listbox_dimensions()))
ImGui::SetNextItemWidth(250);
if (ImGui::BeginCombo("##regionswitcher", region_str.c_str()))
{ {
if (ImGui::BeginCombo("##regionswitcher", region_str.c_str())) for (const auto& region_type : regions)
{ {
for (const auto& region_type : regions) components::selectable(region_type.name, *g_pointers->m_gta.m_region_code == region_type.id, [&region_type] {
{ *g_pointers->m_gta.m_region_code = region_type.id;
components::selectable(region_type.name, *g_pointers->m_gta.m_region_code == region_type.id, [&region_type] {
*g_pointers->m_gta.m_region_code = region_type.id;
region_updated = true;
});
}
ImGui::EndCombo();
}
if (region_updated)
{
selected_region_index = *g_pointers->m_gta.m_region_code;
region_updated = false;
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("SESSION_SELECT_COMBO_DESC"_T.data());
}
ImGui::Separator();
static const auto sessions = std::to_array<SessionType>({ //This has to be here because if it's generated at compile time, the translations break for some reason.
{eSessionType::JOIN_PUBLIC, "BACKEND_SESSION_TYPE_JOIN_PUBLIC"},
{eSessionType::NEW_PUBLIC, "BACKEND_SESSION_TYPE_NEW_PUBLIC"},
{eSessionType::CLOSED_CREW, "BACKEND_SESSION_TYPE_CLOSED_CREW"},
{eSessionType::CREW, "BACKEND_SESSION_TYPE_CREW"},
{eSessionType::CLOSED_FRIENDS, "BACKEND_SESSION_TYPE_CLOSED_FRIENDS"},
{eSessionType::FIND_FRIEND, "BACKEND_SESSION_TYPE_FIND_FRIEND"},
{eSessionType::SOLO, "BACKEND_SESSION_TYPE_SOLO"},
{eSessionType::INVITE_ONLY, "BACKEND_SESSION_TYPE_INVITE_ONLY"},
{eSessionType::JOIN_CREW, "BACKEND_SESSION_TYPE_JOIN_CREW"},
{eSessionType::SC_TV, "BACKEND_SESSION_TYPE_SC_TV"},
{eSessionType::LEAVE_ONLINE, "BACKEND_SESSION_TYPE_LEAVE_ONLINE"}
});
for (const auto& [id, name] : sessions)
{
if (id == eSessionType::LEAVE_ONLINE && gta_util::get_network_player_mgr()->m_player_count == 0) // Don't show a Leave Online option in single player (it actually sends us INTO online)
continue;
ImGui::BeginDisabled(selected_region_index == -1 && id != eSessionType::LEAVE_ONLINE); // Leave Online is always enabled in online sessions since we don't care about the selected region
components::selectable(g_translation_service.get_translation(name), false, [&id] {
session::join_type(id);
}); });
ImGui::EndDisabled();
} }
ImGui::EndListBox(); ImGui::EndCombo();
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("SESSION_SELECT_COMBO_DESC"_T.data());
}
ImGui::Separator();
static constexpr auto sessions = std::to_array<SessionType>({// This has to be here because if it's generated at compile time, the translations break for some reason.
{eSessionType::JOIN_PUBLIC, "BACKEND_SESSION_TYPE_JOIN_PUBLIC"},
{eSessionType::NEW_PUBLIC, "BACKEND_SESSION_TYPE_NEW_PUBLIC"},
{eSessionType::CLOSED_CREW, "BACKEND_SESSION_TYPE_CLOSED_CREW"},
{eSessionType::CREW, "BACKEND_SESSION_TYPE_CREW"},
{eSessionType::CLOSED_FRIENDS, "BACKEND_SESSION_TYPE_CLOSED_FRIENDS"},
{eSessionType::FIND_FRIEND, "BACKEND_SESSION_TYPE_FIND_FRIEND"},
{eSessionType::SOLO, "BACKEND_SESSION_TYPE_SOLO"},
{eSessionType::INVITE_ONLY, "BACKEND_SESSION_TYPE_INVITE_ONLY"},
{eSessionType::JOIN_CREW, "BACKEND_SESSION_TYPE_JOIN_CREW"},
{eSessionType::SC_TV, "BACKEND_SESSION_TYPE_SC_TV"},
{eSessionType::LEAVE_ONLINE, "BACKEND_SESSION_TYPE_LEAVE_ONLINE"}});
for (const auto& [id, name] : sessions)
{
if (id == eSessionType::LEAVE_ONLINE && !*g_pointers->m_gta.m_is_session_started) // Don't show a Leave Online option in single player (it actually sends us INTO online)
continue;
components::selectable(g_translation_service.get_translation(name), false, [&id] {
session::join_type(id);
});
} }
ImGui::EndGroup(); ImGui::EndGroup();
@ -154,184 +131,331 @@ namespace big
bool_command whitelist_session("trustsession", "TRUST_SESSION", "TRUST_SESSION_DESC", g.session.trust_session); bool_command whitelist_session("trustsession", "TRUST_SESSION", "TRUST_SESSION_DESC", g.session.trust_session);
bool_command chat_translate("translatechat", "TRANSLATOR_TOGGLE", "TRANSLATOR_TOGGLE_DESC", g.session.chat_translator.enabled); bool_command chat_translate("translatechat", "TRANSLATOR_TOGGLE", "TRANSLATOR_TOGGLE_DESC", g.session.chat_translator.enabled);
void render_misc() void render_general_options()
{
ImGui::SeparatorText("PLAYER_TOGGLES"_T.data());
ImGui::BeginGroup();
components::command_checkbox<"trustfriends">();
components::command_checkbox<"trustsession">();
components::script_patch_checkbox("REVEAL_OTR_PLAYERS"_T, &g.session.decloak_players, "REVEAL_OTR_PLAYERS_DESC"_T.data());
components::script_patch_checkbox("REVEAL_HIDDEN_PLAYERS"_T, &g.session.unhide_players_from_player_list,"REVEAL_HIDDEN_PLAYERS_DESC"_T.data());
components::command_button<"sextall">({}, "SEND_SEXT"_T);
components::command_button<"fakebanall">({}, "FAKE_BAN_MESSAGE"_T);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("OFF_THE_RADAR"_T.data(), &g.session.off_radar_all);
ImGui::Checkbox("NEVER_WANTED"_T.data(), &g.session.never_wanted_all);
ImGui::Checkbox("SEMI_GODMODE"_T.data(), &g.session.semi_godmode_all);
ImGui::Checkbox("VIEW_NET_SESSION_FIX_VEHICLE"_T.data(), &g.session.vehicle_fix_all);
components::command_checkbox<"harass">();
ImGui::Checkbox("SPAM_KILLFEED"_T.data(), &g.session.spam_killfeed);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("EXPLOSION_KARMA"_T.data(), &g.session.explosion_karma);
ImGui::Checkbox("DAMAGE_KARMA"_T.data(), &g.session.damage_karma);
ImGui::Checkbox("DISABLE_PEDS"_T.data(), &g.session.disable_peds);
ImGui::Checkbox("DISABLE_TRAFFIC"_T.data(), &g.session.disable_traffic);
ImGui::Checkbox("FORCE_THUNDER"_T.data(), &g.session.force_thunder);
ImGui::Checkbox("LOBBY_LOCK"_T.data(), &g.session.lock_session);
if (g.session.lock_session)
{
ImGui::Checkbox("LOBBY_LOCK_ALLOW_FRIENDS"_T.data(), &g.session.allow_friends_into_locked_session);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("LOBBY_LOCK_ALLOW_FRIENDS_DESC"_T.data());
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("LOBBY_LOCK_DESC"_T.data());
ImGui::EndGroup();
}
void render_force_host_options()
{ {
ImGui::BeginGroup(); ImGui::BeginGroup();
components::small_text("FORCE_HOST"_T);
components::sub_title("DEBUG_TAB_MISC"_T); static constexpr auto token_spoof_types = std::to_array({"SPOOF_HOST_TOKEN_OFF", "SPOOF_HOST_TOKEN_TYPE_LEGIT", "SPOOF_HOST_TOKEN_TYPE_AGGRESSIVE", "SPOOF_HOST_TOKEN_TYPE_EXTRA_AGGRESSIVE", "SPOOF_HOST_TOKEN_TYPE_CUSTOM"});
if (ImGui::BeginListBox("##miscsession", get_listbox_dimensions()))
ImGui::BeginDisabled(gta_util::get_network()->m_game_session_state != 0);
ImGui::SetNextItemWidth(300);
if (ImGui::BeginCombo("HOST_TOKEN_SPOOFING"_T.data(),
g_translation_service.get_translation(token_spoof_types[g.session.spoof_host_token_type]).data()))
{ {
ImGui::Checkbox("JOIN_IN_SCTV"_T.data(), &g.session.join_in_sctv_slots); for (int i = 0; i < token_spoof_types.size(); i++)
if (ImGui::IsItemHovered())
ImGui::SetTooltip("JOIN_IN_SCTV_DESC"_T.data());
ImGui::Checkbox("PLAYER_MAGNET"_T.data(), &g.session.player_magnet_enabled);
if (g.session.player_magnet_enabled)
{ {
ImGui::Text("PLAYER_COUNT"_T.data()); if (ImGui::Selectable(g_translation_service.get_translation(token_spoof_types[i]).data(), i == g.session.spoof_host_token_type))
ImGui::InputInt("##playercount", &g.session.player_magnet_count); {
g.session.spoof_host_token_type = i;
g_fiber_pool->queue_job([] {
g.session.spoof_host_token_dirty = true;
}); // this part gets a bit racy so we're setting it in a fiber pool
}
if (i == g.session.spoof_host_token_type)
{
ImGui::SetItemDefaultFocus();
}
} }
components::command_checkbox<"trustfriends">(); ImGui::EndCombo();
components::command_checkbox<"trustsession">();
ImGui::BeginDisabled(!g_player_service->get_self()->is_host());
ImGui::Checkbox("LOBBY_LOCK"_T.data(), &g.session.lock_session);
if (g.session.lock_session)
{
ImGui::Checkbox("LOBBY_LOCK_ALLOW_FRIENDS"_T.data(), &g.session.allow_friends_into_locked_session);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("LOBBY_LOCK_ALLOW_FRIENDS_DESC"_T.data());
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("LOBBY_LOCK_DESC"_T.data());
ImGui::EndDisabled();
components::script_patch_checkbox("REVEAL_OTR_PLAYERS"_T,
&g.session.decloak_players,
"REVEAL_OTR_PLAYERS_DESC"_T.data());
components::script_patch_checkbox("REVEAL_HIDDEN_PLAYERS"_T,
&g.session.unhide_players_from_player_list,
"REVEAL_HIDDEN_PLAYERS_DESC"_T.data());
components::command_button<"sextall">({}, "SEND_SEXT"_T);
ImGui::SameLine();
components::command_button<"fakebanall">({}, "FAKE_BAN_MESSAGE"_T);
ImGui::EndListBox();
} }
if (g.session.spoof_host_token_type != 0)
{
ImGui::Checkbox("HIDE_TOKEN_SPOOFING_WHEN_HOST"_T.data(), &g.session.hide_token_spoofing_when_host);
}
if (g.session.spoof_host_token_type == 4)
{
ImGui::SetNextItemWidth(200);
if (ImGui::InputScalar("##token_input", ImGuiDataType_U64, &g.session.custom_host_token, nullptr, nullptr, "%p", ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
{
g.session.spoof_host_token_dirty = true;
}
}
ImGui::EndDisabled();
//if (g.session.force_session_host)
//{
// ImGui::SameLine();
// ImGui::Checkbox("KICK_HOST_ON_JOIN"_T.data(), &g.session.kick_host_when_forcing_host);
//}
ImGui::Checkbox("FORCE_SCRIPT_HOST"_T.data(), &g.session.force_script_host);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FORCE_SCRIPT_HOST_DESC"_T.data());
ImGui::SameLine();
ImGui::Checkbox("FAST_JOIN"_T.data(), &g.session.fast_join);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FAST_JOIN_DESC"_T.data());
components::command_button<"emptysession">();
ImGui::EndGroup(); ImGui::EndGroup();
} }
void render_chat() void render_player_options()
{ {
ImGui::SeparatorText("PLAYER_OPTIONS"_T.data());
ImGui::BeginGroup(); ImGui::BeginGroup();
components::command_button<"killall">({}, "KILL_ALL"_T);
components::command_button<"explodeall">({}, "EXPLODE_ALL"_T);
components::command_button<"beastall">({});
if (ImGui::IsItemHovered())
ImGui::SetTooltip("INCLUDING_YOU"_T.data());
components::command_button<"bringall">({});
components::command_button<"giveweapsall">({});
components::command_button<"remweapsall">({});
ImGui::EndGroup();
components::sub_title("CHAT"_T.data()); ImGui::SameLine();
if (ImGui::BeginListBox("##chat", get_listbox_dimensions()))
{
static char msg[256];
ImGui::Checkbox("USE_SPAM_TIMER"_T.data(), &g.session.use_spam_timer);
if (g.session.use_spam_timer)
{
ImGui::SliderFloat("SPAM_TIMER"_T.data(), &g.session.spam_timer, 0.5f, 5.0f);
ImGui::SliderInt("SPAM_LENGTH"_T.data(), &g.session.spam_length, 1, 256);
}
ImGui::Checkbox("LOG_CHAT_MSG"_T.data(), &g.session.log_chat_messages);
ImGui::Checkbox("LOG_TXT_MSG"_T.data(), &g.session.log_text_messages);
components::input_text_with_hint("##message", "VIEW_NET_CHAT_MESSAGE"_T, msg, sizeof(msg));
ImGui::Checkbox("IS_TEAM"_T.data(), &g.session.is_team); ImGui::BeginGroup();
ImGui::SameLine(); components::command_button<"ceokickall">({});
components::button("SEND"_T, [] { components::command_button<"vehkickall">({});
if (const auto net_game_player = gta_util::get_network_player_mgr()->m_local_net_player; net_game_player) components::command_button<"deletevehall">({});
{ components::command_button<"ragdollall">({}, "RAGDOLL_PLAYERS"_T);
chat::send_message(msg, nullptr, true, g.session.is_team); components::command_button<"intkickall">({}, "KICK_ALL_FROM_INTERIORS"_T);
} components::command_button<"missionall">({});
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::command_button<"errorall">({});
components::command_button<"ceoraidall">({});
components::button("TRIGGER_MC_RAID"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::BikerDefend);
}); });
});
components::button("TRIGGER_BUNKER_RAID"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::GunrunningDefend);
});
});
ImGui::EndGroup();
ImGui::Separator(); components::small_text("BOUNTY"_T);
static int value = 10000;
ImGui::SetNextItemWidth(300);
ImGui::SliderInt("##bountyvalue", &value, 0, 10000);
components::command_checkbox<"anonbounty">();
components::button("Bounty All", [] {
g_player_service->iterate([](auto& plyr) {
troll::set_bounty_on_player(plyr.second, value, g.session.anonymous_bounty);
});
});
}
ImGui::Checkbox("CHAT_COMMANDS"_T.data(), &g.session.chat_commands); void render_teleport_options()
if (g.session.chat_commands) {
ImGui::SeparatorText("TELEPORTS"_T.data());
ImGui::SetNextItemWidth(300);
if (ImGui::BeginCombo("##apartment", apartment_names[g.session.send_to_apartment_idx]))
{
for (int i = 1; i < apartment_names.size(); i++)
{ {
components::small_text("DEFAULT_CMD_PERMISSIONS"_T); if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
if (ImGui::BeginCombo("##defualtchatcommands", COMMAND_ACCESS_LEVELS[g.session.chat_command_default_access_level]))
{ {
for (const auto& [type, name] : COMMAND_ACCESS_LEVELS) g.session.send_to_apartment_idx = i;
{ }
if (ImGui::Selectable(name, type == g.session.chat_command_default_access_level))
{
g.session.chat_command_default_access_level = type;
}
if (type == g.session.chat_command_default_access_level) if (i == g.session.send_to_apartment_idx)
{ {
ImGui::SetItemDefaultFocus(); ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
} }
} }
components::command_checkbox<"translatechat">(); ImGui::EndCombo();
if (g.session.chat_translator.enabled)
{
ImGui::Checkbox("TRANSLATOR_HIDE_SAME_LANGUAGE"_T.data(), &g.session.chat_translator.bypass_same_language);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("TRANSLATOR_HIDE_SAME_LANGUAGE_DESC"_T.data());
components::small_text("TRANSLATOR_OUTPUT"_T.data());
ImGui::Checkbox("TRANSLATOR_SHOW_ON_CHAT"_T.data(), &g.session.chat_translator.draw_result);
ImGui::Checkbox("TRANSLATOR_PRINT_TO_CONSOLE"_T.data(), &g.session.chat_translator.print_result);
static const auto target_language = std::to_array<target_language_type>({{"sq", "Albanian"}, {"ar", "Arabic"}, {"az", "Azerbaijani"}, {"bn", "Bengali"}, {"bg", "Bulgarian"}, {"ca", "Catalan"}, {"zh", "Chinese"}, {"zt", "Chinese(traditional)"}, {"cs", "Czech"}, {"da", "Danish"}, {"nl", "Dutch"}, {"en", "English"}, {"eo", "Esperanto"}, {"et", "Estonian"}, {"fi", "Finnish"}, {"fr", "French"}, {"de", "German"}, {"el", "Greek"}, {"he", "Hebrew"}, {"hi", "Hindi"}, {"hu", "Hungarian"}, {"id", "Indonesian"}, {"ga", "Irish"}, {"it", "Italian"}, {"ja", "Japanese"}, {"ko", "Korean"}, {"lv", "Latvian"}, {"lt", "Lithuanian"}, {"ms", "Malay"}, {"nb", "Norwegian"}, {"fa", "Persian"}, {"pl", "Polish"}, {"pt", "Portuguese"}, {"ro", "Romanian"}, {"ru", "Russian"}, {"sr", "Serbian"}, {"sk", "Slovak"}, {"sl", "Slovenian"}, {"es", "Spanish"}, {"sv", "Swedish"}, {"tl", "Tagalog"}, {"th", "Thai"}, {"tr", "Turkish"}, {"uk", "Ukrainian"}, {"ur", "Urdu"}, {"vi", "Vietnamese"}});
components::input_text_with_hint("TRANSLATOR_ENDPOINT"_T.data(), "http://localhost:5000/translate", g.session.chat_translator.endpoint);
if (ImGui::BeginCombo("TRANSLATOR_TARGET_LANGUAGE"_T.data(), g.session.chat_translator.target_language.c_str()))
{
for (const auto& [type, name] : target_language)
{
components::selectable(name, false, [&type] {
g.session.chat_translator.target_language = type;
});
}
ImGui::EndCombo();
}
}
ImGui::EndListBox();
} }
ImGui::SameLine();
components::command_button<"apartmenttpall">({(uint64_t)g.session.send_to_apartment_idx}, "TP_ALL_TO_APARTMENT"_T);
ImGui::SetNextItemWidth(300);
if (ImGui::BeginCombo("##warehouse", warehouse_names[g.session.send_to_warehouse_idx]))
{
for (int i = 1; i < warehouse_names.size(); i++)
{
if (ImGui::Selectable(warehouse_names[i], i == g.session.send_to_warehouse_idx))
{
g.session.send_to_warehouse_idx = i;
}
if (i == g.session.send_to_warehouse_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::command_button<"warehousetpall">({(uint64_t)g.session.send_to_warehouse_idx}, "TP_ALL_TO_WAREHOUSE"_T);
ImGui::BeginGroup();
components::button("TP_ALL_TO_DARTS"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::Darts);
});
});
components::button("TP_ALL_TO_FLIGHT_SCHOOL"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::PilotSchool);
});
});
components::button("TP_ALL_TO_MAP_CENTER"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::ArmWresling);
});
});
components::button("TP_ALL_TO_SKYDIVE"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::Skydive);
});
});
components::command_button<"interiortpall">({81}, "TP_ALL_TO_MOC"_T);
components::command_button<"interiortpall">({123}, "TP_ALL_TO_CASINO"_T);
components::command_button<"interiortpall">({124}, "TP_ALL_TO_PENTHOUSE"_T);
components::command_button<"interiortpall">({128}, "TP_ALL_TO_ARCADE"_T);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::command_button<"interiortpall">({146}, "TP_ALL_TO_MUSIC_LOCKER"_T);
components::command_button<"interiortpall">({148}, "TP_ALL_TO_RECORD_A_STUDIOS"_T);
components::command_button<"interiortpall">({149}, "TP_ALL_TO_CUSTOM_AUTO_SHOP"_T);
components::command_button<"interiortpall">({155}, "TP_ALL_TO_AGENCY"_T);
components::command_button<"interiortpall">({160}, "TP_ALL_TO_FREAKSHOP"_T);
components::command_button<"interiortpall">({161}, "TP_ALL_TO_MULTI_FLOOR_GARAGE"_T);
components::command_button<"tutorialall">();
components::command_button<"golfall">();
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::command_button<"flightschoolall">();
components::command_button<"dartsall">();
components::command_button<"badlandsall">();
components::command_button<"spacemonkeyall">();
components::command_button<"wizardall">();
components::command_button<"qub3dall">();
components::command_button<"camhedzall">();
ImGui::EndGroup();
}
void render_session_control()
{
ImGui::SeparatorText("SESSION_CONTROL"_T.data());
ImGui::BeginGroup();
ImGui::Checkbox("SCRIPT_BLOCK_AMMUNATION"_T.data(), &g.session.script_block_opts.ammunation);
ImGui::Checkbox("SCRIPT_BLOCK_ATMS"_T.data(), &g.session.script_block_opts.atms);
ImGui::Checkbox("SCRIPT_BLOCK_ARCADE_GAMES"_T.data(), &g.session.script_block_opts.arcade_games);
ImGui::Checkbox("SCRIPT_BLOCK_CASINO_GAMES"_T.data(), &g.session.script_block_opts.casino_games);
ImGui::Checkbox("SCRIPT_BLOCK_DRONES"_T.data(), &g.session.script_block_opts.drones);
ImGui::Checkbox("SCRIPT_BLOCK_GANG_ATTACKS"_T.data(), &g.session.script_block_opts.gang_attacks);
ImGui::Checkbox("SCRIPT_BLOCK_IMPROMPTU_DEATHMATCHES"_T.data(), &g.session.script_block_opts.impromptu_dm);
ImGui::Checkbox("SCRIPT_BLOCK_IMPROMPTU_RACES"_T.data(), &g.session.script_block_opts.impromptu_race);
ImGui::Checkbox("SCRIPT_BLOCK_INTERIORS"_T.data(), &g.session.script_block_opts.interiors);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("SCRIPT_BLOCK_INTERIORS_DESC"_T.data());
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Checkbox("SCRIPT_BLOCK_LSC"_T.data(), &g.session.script_block_opts.lsc);
ImGui::Checkbox("SCRIPT_BLOCK_MOVIES"_T.data(), &g.session.script_block_opts.movies);
ImGui::Checkbox("SCRIPT_BLOCK_PROSTITUTES"_T.data(), &g.session.script_block_opts.prostitutes);
ImGui::Checkbox("SCRIPT_BLOCK_SITTING"_T.data(), &g.session.script_block_opts.sitting);
ImGui::Checkbox("SCRIPT_BLOCK_SLEEPING"_T.data(), &g.session.script_block_opts.sleeping);
ImGui::Checkbox("SCRIPT_BLOCK_STORES"_T.data(), &g.session.script_block_opts.stores);
ImGui::Checkbox("SCRIPT_BLOCK_STREET_DEALER"_T.data(), &g.session.script_block_opts.street_dealer);
ImGui::Checkbox("SCRIPT_BLOCK_STRIP_CLUB"_T.data(), &g.session.script_block_opts.strip_club);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("SCRIPT_BLOCK_STRIP_CLUB_DESC"_T.data());
ImGui::Checkbox("SCRIPT_BLOCK_STRIP_CLUB"_T.data(), &g.session.script_block_opts.vending_machines);
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::sub_title("REQUIRES_SCRIPT_HOST"_T);
ImGui::Checkbox("DISABLE_CEO_MONEY"_T.data(), &g.session.block_ceo_money);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("DISABLE_CEO_MONEY_DESC"_T.data());
ImGui::Checkbox("BLOCK_JOBS"_T.data(), &g.session.block_jobs);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("BLOCK_JOBS_DESC"_T.data());
ImGui::Checkbox("RANDOMIZE_CEO_COLORS"_T.data(), &g.session.randomize_ceo_colors);
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);
components::command_checkbox<"blockceos">();
ImGui::EndGroup(); ImGui::EndGroup();
} }
void render_session_globals() void render_session_globals()
{ {
// TODO: what are we doing with this?
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("GLOBALS"_T);
if (ImGui::BeginListBox("##globals", get_listbox_dimensions()))
{
static int global_wanted_level = 0;
ImGui::Checkbox("OFF_THE_RADAR"_T.data(), &g.session.off_radar_all);
ImGui::Checkbox("NEVER_WANTED"_T.data(), &g.session.never_wanted_all);
ImGui::Checkbox("SEMI_GODMODE"_T.data(), &g.session.semi_godmode_all);
ImGui::Checkbox("VIEW_NET_SESSION_FIX_VEHICLE"_T.data(), &g.session.vehicle_fix_all);
components::command_checkbox<"harass">();
ImGui::Checkbox("SPAM_KILLFEED"_T.data(), &g.session.spam_killfeed);
ImGui::Checkbox("EXPLOSION_KARMA"_T.data(), &g.session.explosion_karma);
ImGui::Checkbox("DAMAGE_KARMA"_T.data(), &g.session.damage_karma);
ImGui::Checkbox("DISABLE_PEDS"_T.data(), &g.session.disable_peds);
ImGui::Checkbox("DISABLE_TRAFFIC"_T.data(), &g.session.disable_traffic);
ImGui::Checkbox("FORCE_THUNDER"_T.data(), &g.session.force_thunder);
components::small_text("WANTED_LVL"_T);
ImGui::SetNextItemWidth(150);
if (ImGui::SliderInt("##wantedlevel", &global_wanted_level, 0, 5))
{
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelAmount = global_wanted_level;
}
ImGui::SameLine();
if (ImGui::Checkbox("FORCE"_T.data(), &g.session.wanted_level_all))
{
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelPlayer = __rdtsc() + 32;
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelAmount = global_wanted_level;
}
ImGui::EndListBox();
}
components::small_text("WARP_TIME"_T); components::small_text("WARP_TIME"_T);
components::button("PLUS_1_MINUTE"_T, [] { components::button("PLUS_1_MINUTE"_T, [] {
@ -359,252 +483,37 @@ namespace big
}); });
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("STOP_TIME_DESC"_T.data()); ImGui::SetTooltip("STOP_TIME_DESC"_T.data());
ImGui::EndGroup();
ImGui::SameLine();
static int global_wanted_level = 0;
ImGui::BeginGroup();
components::small_text("WANTED_LVL"_T);
ImGui::SetNextItemWidth(150);
if (ImGui::SliderInt("##wantedlevel", &global_wanted_level, 0, 5))
{
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelAmount = global_wanted_level;
}
ImGui::SameLine();
if (ImGui::Checkbox("FORCE"_T.data(), &g.session.wanted_level_all))
{
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelPlayer = __rdtsc() + 32;
scr_globals::globalplayer_bd.as<GlobalPlayerBD*>()->Entries[self::id].RemoteWantedLevelAmount = global_wanted_level;
}
ImGui::EndGroup(); ImGui::EndGroup();
} }
void view::network() void view::network()
{ {
render_rid_joiner(); render_join_game();
ImGui::SameLine(); render_general_options();
render_session_switcher();
render_misc();
ImGui::SameLine();
render_chat();
render_session_globals(); render_session_globals();
render_force_host_options();
ImGui::SameLine(); render_player_options();
render_teleport_options();
ImGui::BeginGroup(); render_session_control();
components::sub_title("FORCE_HOST"_T);
ImGui::Checkbox("FORCE_SESSION_HOST"_T.data(), &g.session.force_session_host);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FORCE_SESSION_HOST_DESC"_T.data());
if (g.session.force_session_host)
{
ImGui::SameLine();
ImGui::Checkbox("KICK_HOST_ON_JOIN"_T.data(), &g.session.kick_host_when_forcing_host);
}
if (ImGui::Checkbox("FORCE_SCRIPT_HOST"_T.data(), &g.session.force_script_host))
{
if (g.session.force_script_host)
g_fiber_pool->queue_job([] {
scripts::force_host("freemode"_J);
if (auto script = gta_util::find_script_thread("freemode"_J); script && script->m_net_component)
((CGameScriptHandlerNetComponent*)script->m_net_component)->block_host_migration(true);
scripts::force_host("fmmc_launcher"_J);
if (auto script = gta_util::find_script_thread("fmmc_launcher"_J); script && script->m_net_component)
((CGameScriptHandlerNetComponent*)script->m_net_component)->block_host_migration(true);
});
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FORCE_SCRIPT_HOST_DESC"_T.data());
ImGui::SameLine();
ImGui::Checkbox("FAST_JOIN"_T.data(), &g.session.fast_join);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FAST_JOIN_DESC"_T.data());
ImGui::Spacing();
components::sub_title("PLAYERS"_T);
components::options_modal(
"GRIEFING"_T.data(),
[] {
components::command_button<"killall">({}, "KILL_ALL"_T);
ImGui::SameLine();
components::command_button<"explodeall">({}, "EXPLODE_ALL"_T);
ImGui::SameLine();
components::command_button<"beastall">({});
if (ImGui::IsItemHovered())
ImGui::SetTooltip("INCLUDING_YOU"_T.data());
components::command_button<"bringall">({});
ImGui::SameLine();
components::command_button<"giveweapsall">({});
ImGui::SameLine();
components::command_button<"remweapsall">({});
components::command_button<"ceokickall">({});
ImGui::SameLine();
components::command_button<"vehkickall">({});
components::command_button<"ragdollall">({}, "RAGDOLL_PLAYERS"_T);
ImGui::SameLine();
components::command_button<"intkickall">({}, "KICK_ALL_FROM_INTERIORS"_T);
components::command_button<"missionall">({});
ImGui::SameLine();
components::command_button<"errorall">({});
components::command_button<"ceoraidall">({});
ImGui::SameLine();
components::button("TRIGGER_MC_RAID"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::BikerDefend);
});
});
ImGui::SameLine();
components::button("TRIGGER_BUNKER_RAID"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::GunrunningDefend);
});
});
ImGui::SeparatorText("Bounty");
static int value = 10000;
ImGui::SliderInt("##bountyvalue", &value, 0, 10000);
components::command_checkbox<"anonbounty">();
components::button("Bounty All", [] {
g_player_service->iterate([](auto& plyr) {
troll::set_bounty_on_player(plyr.second, value, g.session.anonymous_bounty);
});
});
},
false,
"GRIEFING"_T.data());
components::options_modal(
"TELEPORT"_T.data(),
[] {
if (ImGui::BeginCombo("##apartment", apartment_names[g.session.send_to_apartment_idx]))
{
for (int i = 1; i < apartment_names.size(); i++)
{
if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
{
g.session.send_to_apartment_idx = i;
}
if (i == g.session.send_to_apartment_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::command_button<"apartmenttpall">({(uint64_t)g.session.send_to_apartment_idx}, "TP_ALL_TO_APARTMENT"_T);
if (ImGui::BeginCombo("##warehouse", warehouse_names[g.session.send_to_warehouse_idx]))
{
for (int i = 1; i < warehouse_names.size(); i++)
{
if (ImGui::Selectable(warehouse_names[i], i == g.session.send_to_warehouse_idx))
{
g.session.send_to_warehouse_idx = i;
}
if (i == g.session.send_to_warehouse_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::command_button<"warehousetpall">({(uint64_t)g.session.send_to_warehouse_idx}, "TP_ALL_TO_WAREHOUSE"_T);
components::button("TP_ALL_TO_DARTS"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::Darts);
});
});
ImGui::SameLine();
components::button("TP_ALL_TO_FLIGHT_SCHOOL"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::PilotSchool);
});
});
ImGui::SameLine();
components::button("TP_ALL_TO_MAP_CENTER"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::ArmWresling);
});
});
components::button("TP_ALL_TO_SKYDIVE"_T, [] {
g_player_service->iterate([](auto& plyr) {
toxic::start_activity(plyr.second, eActivityType::Skydive);
});
});
ImGui::SameLine();
components::command_button<"interiortpall">({81}, "TP_ALL_TO_MOC"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({123}, "TP_ALL_TO_CASINO"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({124}, "TP_ALL_TO_PENTHOUSE"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({128}, "TP_ALL_TO_ARCADE"_T);
components::command_button<"interiortpall">({146}, "TP_ALL_TO_MUSIC_LOCKER"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({148}, "TP_ALL_TO_RECORD_A_STUDIOS"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({149}, "TP_ALL_TO_CUSTOM_AUTO_SHOP"_T);
components::command_button<"interiortpall">({155}, "TP_ALL_TO_AGENCY"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({160}, "TP_ALL_TO_FREAKSHOP"_T);
ImGui::SameLine();
components::command_button<"interiortpall">({161}, "TP_ALL_TO_MULTI_FLOOR_GARAGE"_T);
components::command_button<"tutorialall">();
ImGui::SameLine();
components::command_button<"golfall">();
ImGui::SameLine();
components::command_button<"flightschoolall">();
ImGui::SameLine();
components::command_button<"dartsall">();
components::command_button<"badlandsall">();
ImGui::SameLine();
components::command_button<"spacemonkeyall">();
ImGui::SameLine();
components::command_button<"wizardall">();
components::command_button<"qub3dall">();
ImGui::SameLine();
components::command_button<"camhedzall">();
},
true,
"TELEPORT"_T.data());
components::command_button<"emptysession">();
components::sub_title("SCRIPT_HOST_FEATURES"_T);
ImGui::Checkbox("DISABLE_CEO_MONEY"_T.data(), &g.session.block_ceo_money);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("DISABLE_CEO_MONEY_DESC"_T.data());
ImGui::SameLine();
ImGui::Checkbox("BLOCK_JOBS"_T.data(), &g.session.block_jobs);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("BLOCK_JOBS_DESC"_T.data());
ImGui::Checkbox("RANDOMIZE_CEO_COLORS"_T.data(), &g.session.randomize_ceo_colors);
ImGui::SameLine();
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

@ -266,7 +266,7 @@ namespace big
ImGui::Text(std::format("{}: {}", "VIEW_NET_PLAYER_DB_CURRENT_MISSION_TYPE"_T, player_database_service::get_game_mode_str(selected->game_mode)).c_str()); ImGui::Text(std::format("{}: {}", "VIEW_NET_PLAYER_DB_CURRENT_MISSION_TYPE"_T, player_database_service::get_game_mode_str(selected->game_mode)).c_str());
if (selected->game_mode != GameMode::None && player_database_service::can_fetch_name(selected->game_mode)) if (selected->game_mode != GameMode::None && player_database_service::can_fetch_name(selected->game_mode))
{ {
ImGui::Text("VIEW_NET_PLAYER_DB_CURRENT_MISSION_TYPE"_T.data(), selected->game_mode_name.c_str()); ImGui::Text(std::format("{}: {}", "VIEW_NET_PLAYER_DB_CURRENT_MISSION_NAME"_T.data(), selected->game_mode_name.c_str()).c_str());
if ((selected->game_mode_name == "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data() || selected->game_mode_name.empty()) if ((selected->game_mode_name == "VIEW_NET_PLAYER_DB_GAME_MODE_UNKNOWN"_T.data() || selected->game_mode_name.empty())
&& !selected->game_mode_id.empty()) && !selected->game_mode_id.empty())
{ {

View File

@ -34,13 +34,19 @@ namespace big
if (!session.is_valid) if (!session.is_valid)
continue; continue;
std::string session_str;
if (session.attributes.multiplex_count > 1)
session_str = std::format("{:X} (x{})", session.info.m_session_token, session.attributes.multiplex_count);
else
session_str = std::format("{:X}", session.info.m_session_token);
auto host_rid = session.info.m_net_player_data.m_gamer_handle.m_rockstar_id; auto host_rid = session.info.m_net_player_data.m_gamer_handle.m_rockstar_id;
auto player = g_player_database_service->get_player_by_rockstar_id(host_rid); auto player = g_player_database_service->get_player_by_rockstar_id(host_rid);
if (g.session_browser.exclude_modder_sessions && player && player->block_join) if (g.session_browser.exclude_modder_sessions && player && player->block_join)
continue; continue;
if (components::selectable(std::to_string(session.info.m_session_token), i == selected_session_idx)) if (components::selectable(session_str, i == selected_session_idx))
{ {
selected_session_idx = i; selected_session_idx = i;
g_pointers->m_gta.m_encode_session_info(&session.info, session_info, 0xA9, nullptr); g_pointers->m_gta.m_encode_session_info(&session.info, session_info, 0xA9, nullptr);
@ -51,7 +57,7 @@ namespace big
auto tool_tip = std::format("{}: {}\n{}: {}\n{}: {}\n{}: {}\n{}: {:X}", "SESSION_BROWSER_NUM_PLAYERS"_T, session.attributes.player_count, auto tool_tip = std::format("{}: {}\n{}: {}\n{}: {}\n{}: {}\n{}: {:X}", "SESSION_BROWSER_NUM_PLAYERS"_T, session.attributes.player_count,
"REGION"_T, regions[session.attributes.region].name, "REGION"_T, regions[session.attributes.region].name,
"LANGUAGE"_T, languages[session.attributes.language].name, "LANGUAGE"_T, languages[session.attributes.language].name,
"SESSION_BROWSER_HOST_RID"_T, session.info.m_net_player_data.m_gamer_handle.m_rockstar_id, "SESSION_BROWSER_HOST_RID"_T, session.info.m_net_player_data.m_gamer_handle.m_rockstar_id, // TODO: this is not accurate
"SESSION_BROWSER_DISCRIMINATOR"_T, session.attributes.discriminator); "SESSION_BROWSER_DISCRIMINATOR"_T, session.attributes.discriminator);
ImGui::SetTooltip(tool_tip.c_str()); ImGui::SetTooltip(tool_tip.c_str());
} }
@ -165,8 +171,11 @@ namespace big
ImGui::Combo("###pooltype", &g.session_browser.pool_filter, pool_filter_options.c_str()); ImGui::Combo("###pooltype", &g.session_browser.pool_filter, pool_filter_options.c_str());
} }
ImGui::Checkbox("FILTER_MULTIPLEXED_SESSIONS"_T.data(), &g.session_browser.filter_multiplexed_sessions);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("FILTER_MULTIPLEXED_SESSIONS_DESC"_T.data());
ImGui::Checkbox("EXCLUDE_MODDER_SESSIONS"_T.data(), &g.session_browser.exclude_modder_sessions); ImGui::Checkbox("EXCLUDE_MODDER_SESSIONS"_T.data(), &g.session_browser.exclude_modder_sessions);
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("EXCLUDE_MODDER_SESSIONS_DESC"_T.data()); ImGui::SetTooltip("EXCLUDE_MODDER_SESSIONS_DESC"_T.data());
@ -183,9 +192,7 @@ namespace big
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::Checkbox("REPLACE_GAME_MATCHMAKING"_T.data(), &g.session_browser.replace_game_matchmaking)) ImGui::Checkbox("REPLACE_GAME_MATCHMAKING"_T.data(), &g.session_browser.replace_game_matchmaking);
;
if (ImGui::IsItemHovered()) if (ImGui::IsItemHovered())
ImGui::SetTooltip("REPLACE_GAME_MATCHMAKING_DESC"_T.data()); ImGui::SetTooltip("REPLACE_GAME_MATCHMAKING_DESC"_T.data());

View File

@ -166,5 +166,42 @@ namespace big
ImGui::SliderInt("###multiplex_cnt", &g.spoofing.multiplex_count, 2, 5); ImGui::SliderInt("###multiplex_cnt", &g.spoofing.multiplex_count, 2, 5);
} }
components::command_checkbox<"32players">(); components::command_checkbox<"32players">();
ImGui::SeparatorText("SPOOFING_DATA_HASHES"_T.data());
components::command_checkbox<"spoofdatahash">();
if (g.spoofing.spoof_game_data_hash)
{
ImGui::SameLine();
components::command_button<"storecurrenthash">();
if (ImGui::TreeNode("DATA_HASHES"_T.data()))
{
for (int i = 0; i < 15; i++)
{
ImGui::PushID(i);
ImGui::SetNextItemWidth(200);
if (ImGui::InputScalar("##data_hash_value", ImGuiDataType_U32, &g.spoofing.game_data_hash[i], nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
{
g.spoofing.game_data_hash_dirty = true;
}
ImGui::PopID();
if (((i - 1) % 3) != 0 && i != 14)
{
ImGui::SameLine();
}
}
ImGui::TreePop();
}
}
components::command_checkbox<"spoofdlchash">();
if (g.spoofing.spoof_dlc_hash)
{
ImGui::SameLine();
components::command_button<"storedlchash">();
ImGui::InputScalar("Value", ImGuiDataType_U32, &g.spoofing.dlc_hash, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase);
}
} }
} }

View File

@ -41,280 +41,283 @@ namespace big
void view::player_info() void view::player_info()
{ {
ImGui::BeginGroup(); ImGui::SeparatorText("INFO"_T.data());
components::sub_title("INFO"_T);
if (ImGui::BeginListBox("##infobox", get_listbox_dimensions())) uint32_t ped_damage_bits = 0;
uint32_t ped_task_flag = 0;
uint32_t ped_health = 0;
uint32_t ped_maxhealth = 0;
uint32_t veh_damage_bits = 0;
std::string mode_str{};
std::string vehicle_name{};
if (CPed* ped = g_player_service->get_selected()->get_ped(); ped != nullptr)
{ {
uint32_t ped_damage_bits = 0; ped_damage_bits = ped->m_damage_bits;
uint32_t ped_task_flag = 0; ped_task_flag = ped->m_ped_task_flag;
uint32_t ped_health = 0; ped_health = ped->m_health;
uint32_t ped_maxhealth = 0; ped_maxhealth = ped->m_maxhealth;
uint32_t veh_damage_bits = 0; }
std::string mode_str{};
std::string vehicle_name{};
if (CPed* ped = g_player_service->get_selected()->get_ped(); ped != nullptr) components::options_modal(
{ "VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(),
ped_damage_bits = ped->m_damage_bits; [ped_health, ped_maxhealth] {
ped_task_flag = ped->m_ped_task_flag; ImGui::BeginGroup();
ped_health = ped->m_health;
ped_maxhealth = ped->m_maxhealth;
}
components::options_modal( auto id = g_player_service->get_selected()->id();
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(),
[ped_health, ped_maxhealth] {
ImGui::BeginGroup();
auto id = g_player_service->get_selected()->id(); if (id != -1)
if (id != -1)
{
auto& stats = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].PlayerStats;
auto& boss_goon = scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[id].BossGoon;
const auto money = reinterpret_cast<uint64_t&>(stats.Money);
const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance);
if (boss_goon.Language >= 0 && boss_goon.Language < 13)
ImGui::Text("PLAYER_INFO_LANGUAGE"_T.data(), languages[boss_goon.Language].name);
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_CEO_NAME"_T, boss_goon.GangName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MC_NAME"_T, boss_goon.ClubhouseName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_WALLET"_T, wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_BANK"_T, money - wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_TOTAL_MONEY"_T, money).c_str());
ImGui::Text(std::format("{}: {} ({} {})", "PLAYER_INFO_RANK"_T, stats.Rank, "PLAYER_INFO_RANK_RP"_T, stats.RP).c_str());
ImGui::Text(std::format("{}: {} ({} {})", "VIEW_PLAYER_INFO_HEALTH"_T, ped_health, "VIEW_PLAYER_INFO_MAXHEALTH"_T, ped_maxhealth).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KD"_T, stats.KdRatio).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KILLS"_T, stats.KillsOnPlayers).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_DEATHS"_T, stats.DeathsByPlayers).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_PROSTITUTES"_T, stats.ProstitutesFrequented).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_LAP_DANCES"_T, stats.LapDancesBought).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MISSIONS_CREATED"_T, stats.MissionsCreated).c_str());
auto meltdown_completed = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].MeltdownComplete ? "YES"_T : "NO"_T;
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_METLDOWN_COMPLETE"_T, meltdown_completed).c_str());
}
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NAT_TYPE"_T, get_nat_type_str(g_player_service->get_selected()->get_net_data()->m_nat_type)).c_str());
if (auto peer = g_player_service->get_selected()->get_connection_peer())
{
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_CONNECTION_TYPE"_T, get_connection_type_str(peer->m_peer_address.m_connection_type)).c_str());
if (peer->m_peer_address.m_connection_type == 2)
{
auto ip = peer->m_relay_address.m_relay_address;
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str());
}
else if (peer->m_peer_address.m_connection_type == 3)
{
auto ip = peer->m_peer_address.m_relay_address;
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_PEER_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str());
}
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_MESSAGES_SENT"_T, peer->m_num_messages_batched).c_str());
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_SENT"_T, peer->m_num_reliable_messages_batched).c_str());
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_RESENT"_T, peer->m_num_resent_reliable_messages_batched).c_str());
ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_ENCRYPTION_ATTEMPTS"_T, peer->m_num_encryption_attempts).c_str());
}
ImGui::EndGroup();
ImGui::Separator();
if (ImGui::Checkbox("TRUST"_T.data(), &g_player_service->get_selected()->is_trusted))
{
auto entry = g_player_database_service->get_or_create_player(g_player_service->get_selected());
entry->is_trusted = g_player_service->get_selected()->is_trusted;
g_player_database_service->save();
}
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_EXPLOSIONS"_T.data(), &g_player_service->get_selected()->block_explosions);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_CREATE"_T.data(), &g_player_service->get_selected()->block_clone_create);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_SYNC"_T.data(), &g_player_service->get_selected()->block_clone_sync);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_NETWORK_EVENTS"_T.data(), &g_player_service->get_selected()->block_net_events);
ImGui::Checkbox("VIEW_PLAYER_INFO_LOG_CLONES"_T.data(), &g_player_service->get_selected()->log_clones);
ImGui::Separator();
if (ImGui::BeginCombo("CHAT_COMMAND_PERMISSIONS"_T.data(),
COMMAND_ACCESS_LEVELS[g_player_service->get_selected()->command_access_level.value_or(
g.session.chat_command_default_access_level)]))
{
for (const auto& [type, name] : COMMAND_ACCESS_LEVELS)
{
if (ImGui::Selectable(name,
type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level)))
{
g.session.chat_command_default_access_level = type;
g_player_database_service->get_or_create_player(g_player_service->get_selected())->command_access_level = type;
g_player_database_service->save();
}
if (type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level))
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
},
false,
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data());
ImGui::SameLine();
if (ImGui::SmallButton("PLAYER_INFO_ADD_TO_DB"_T.data()))
{
g_player_database_service->get_or_create_player(g_player_service->get_selected());
}
ImGui::SameLine();
if (ImGui::SmallButton("VIEW_PLAYER_INFO_SC_PROFILE"_T.data()))
session::show_profile_by_rockstar_id(g_player_service->get_selected()->get_net_data()->m_gamer_handle.m_rockstar_id);
if (CPlayerInfo* player_info = g_player_service->get_selected()->get_player_info(); player_info != nullptr)
{
ImGui::Text(std::format("{}: {}", "WANTED_LEVEL"_T, player_info->m_wanted_level).c_str());
}
if (ped_damage_bits & (uint32_t)eEntityProofs::GOD)
{
mode_str = "PLAYER_INFO_GOD"_T;
}
else
{
if (ped_damage_bits & (uint32_t)eEntityProofs::BULLET)
{ {
mode_str += "PLAYER_INFO_BULLET"_T; auto& stats = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].PlayerStats;
auto& boss_goon = scr_globals::gpbd_fm_3.as<GPBD_FM_3*>()->Entries[id].BossGoon;
const auto money = reinterpret_cast<uint64_t&>(stats.Money);
const auto wallet = reinterpret_cast<uint64_t&>(stats.WalletBalance);
if (boss_goon.Language >= 0 && boss_goon.Language < 13)
ImGui::Text("PLAYER_INFO_LANGUAGE"_T.data(), languages[boss_goon.Language].name);
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_CEO_NAME"_T, boss_goon.GangName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MC_NAME"_T, boss_goon.ClubhouseName.Data).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_WALLET"_T, wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_BANK"_T, money - wallet).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_TOTAL_MONEY"_T, money).c_str());
ImGui::Text(std::format("{}: {} ({} {})", "PLAYER_INFO_RANK"_T, stats.Rank, "PLAYER_INFO_RANK_RP"_T, stats.RP).c_str());
ImGui::Text(std::format("{}: {} ({} {})", "VIEW_PLAYER_INFO_HEALTH"_T, ped_health, "VIEW_PLAYER_INFO_MAXHEALTH"_T, ped_maxhealth).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KD"_T, stats.KdRatio).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_KILLS"_T, stats.KillsOnPlayers).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_DEATHS"_T, stats.DeathsByPlayers).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_PROSTITUTES"_T, stats.ProstitutesFrequented).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_LAP_DANCES"_T, stats.LapDancesBought).c_str());
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_MISSIONS_CREATED"_T, stats.MissionsCreated).c_str());
auto meltdown_completed = scr_globals::gpbd_fm_1.as<GPBD_FM*>()->Entries[id].MeltdownComplete ? "YES"_T : "NO"_T;
ImGui::Text(std::format("{}: {}", "PLAYER_INFO_METLDOWN_COMPLETE"_T, meltdown_completed).c_str());
} }
if (ped_damage_bits & (uint32_t)eEntityProofs::EXPLOSION)
{
mode_str += "PLAYER_INFO_EXPLOSION"_T;
}
if (ped_health > 328 || ped_maxhealth > 328 && !(uint32_t)eEntityProofs::EXPLOSION && !(uint32_t)eEntityProofs::BULLET)
{
mode_str += "VIEW_PLAYER_INFO_UNNATURAL_HEALTH"_T.data();
}
}
if (mode_str.empty()) ImGui::EndGroup();
{
mode_str = "NO"_T;
}
ImGui::Text("PLAYER_INFO_PROOFS"_T.data(), mode_str.c_str());
mode_str.clear();
if (ped_task_flag & (uint8_t)ePedTask::TASK_DRIVING)
{
if (auto vehicle = g_player_service->get_selected()->get_current_vehicle(); vehicle != nullptr)
{
veh_damage_bits = vehicle->m_damage_bits;
if (CVehicleModelInfo* vehicle_model_info = static_cast<CVehicleModelInfo*>(vehicle->m_model_info))
{
vehicle_name = g_gta_data_service->vehicles()[vehicle_model_info->m_name].m_display_name;
}
if (veh_damage_bits & (uint32_t)eEntityProofs::GOD)
{
mode_str = "PLAYER_INFO_GOD"_T;
}
else
{
if (veh_damage_bits & (uint32_t)eEntityProofs::COLLISION)
{
mode_str += "PLAYER_INFO_COLLISION"_T;
}
if (veh_damage_bits & (uint32_t)eEntityProofs::EXPLOSION)
{
mode_str += "PLAYER_INFO_EXPLOSION"_T;
}
}
if (mode_str.empty())
{
mode_str = "NO"_T;
}
}
}
else
{
vehicle_name = "PLAYER_INFO_NO_VEHICLE"_T;
}
ImGui::Text("PLAYER_INFO_VEHICLE"_T.data(), vehicle_name.c_str(), mode_str.c_str());
if (auto net_player_data = g_player_service->get_selected()->get_net_data())
{
ImGui::Text("PLAYER_INFO_RID"_T.data(), net_player_data->m_gamer_handle.m_rockstar_id);
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushID("##rid"); ImGui::BeginGroup();
if (ImGui::SmallButton("COPY"_T.data()))
ImGui::SetClipboardText(std::to_string(net_player_data->m_gamer_handle.m_rockstar_id).data());
ImGui::PopID();
auto ip = g_player_service->get_selected()->get_ip_address(); ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NAT_TYPE"_T, get_nat_type_str(g_player_service->get_selected()->get_net_data()->m_nat_type)).c_str());
auto port = g_player_service->get_selected()->get_port();
if (ip) if (auto peer = g_player_service->get_selected()->get_connection_peer())
{ {
ImGui::Text("PLAYER_INFO_IP"_T.data(), ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_CONNECTION_TYPE"_T, get_connection_type_str(peer->m_peer_address.m_connection_type)).c_str());
ip.value().m_field1,
ip.value().m_field2,
ip.value().m_field3,
ip.value().m_field4,
port);
ImGui::SameLine(); if (peer->m_peer_address.m_connection_type == 2)
{
auto ip = peer->m_relay_address.m_relay_address;
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str());
}
else if (peer->m_peer_address.m_connection_type == 3)
{
auto ip = peer->m_peer_address.m_relay_address;
ImGui::Text(std::format("{}: {}.{}.{}.{}", "VIEW_PLAYER_INFO_PEER_RELAY_IP"_T, ip.m_field1, ip.m_field2, ip.m_field3, ip.m_field4).c_str());
}
// clang-format off ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_MESSAGES_SENT"_T, peer->m_num_messages_batched).c_str());
ImGui::PushID("##ip"); ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_SENT"_T, peer->m_num_reliable_messages_batched).c_str());
if (ImGui::SmallButton("COPY"_T.data())) ImGui::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_NUM_RELIABLES_RESENT"_T, peer->m_num_resent_reliable_messages_batched).c_str());
ImGui::SetClipboardText(std::format("{}.{}.{}.{}:{}", }
ip.value().m_field1,
ip.value().m_field2, ImGui::Text(std::format("{}: {:X}", "VIEW_PLAYER_INFO_HOST_TOKEN"_T, g_player_service->get_selected()->get_net_data()->m_host_token).c_str());
ip.value().m_field3, ImGui::SameLine();
ip.value().m_field4, if (ImGui::Button("Copy"))
port).data()); {
ImGui::PopID(); ImGui::SetClipboardText(std::format("{:X}", g_player_service->get_selected()->get_net_data()->m_host_token).data());
// clang-format on }
ImGui::EndGroup();
ImGui::Separator();
if (ImGui::Checkbox("TRUST"_T.data(), &g_player_service->get_selected()->is_trusted))
{
auto entry = g_player_database_service->get_or_create_player(g_player_service->get_selected());
entry->is_trusted = g_player_service->get_selected()->is_trusted;
g_player_database_service->save();
}
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_EXPLOSIONS"_T.data(), &g_player_service->get_selected()->block_explosions);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_CREATE"_T.data(), &g_player_service->get_selected()->block_clone_create);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_CLONE_SYNC"_T.data(), &g_player_service->get_selected()->block_clone_sync);
ImGui::Checkbox("VIEW_PLAYER_INFO_BLOCK_NETWORK_EVENTS"_T.data(), &g_player_service->get_selected()->block_net_events);
ImGui::Checkbox("VIEW_PLAYER_INFO_LOG_CLONES"_T.data(), &g_player_service->get_selected()->log_clones);
ImGui::Separator();
if (ImGui::BeginCombo("CHAT_COMMAND_PERMISSIONS"_T.data(),
COMMAND_ACCESS_LEVELS[g_player_service->get_selected()->command_access_level.value_or(
g.session.chat_command_default_access_level)]))
{
for (const auto& [type, name] : COMMAND_ACCESS_LEVELS)
{
if (ImGui::Selectable(name,
type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level)))
{
g.session.chat_command_default_access_level = type;
g_player_database_service->get_or_create_player(g_player_service->get_selected())->command_access_level = type;
g_player_database_service->save();
}
if (type == g_player_service->get_selected()->command_access_level.value_or(g.session.chat_command_default_access_level))
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
},
false,
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data());
ImGui::SameLine();
if (ImGui::SmallButton("PLAYER_INFO_ADD_TO_DB"_T.data()))
{
g_player_database_service->get_or_create_player(g_player_service->get_selected());
}
ImGui::SameLine();
if (ImGui::SmallButton("VIEW_PLAYER_INFO_SC_PROFILE"_T.data()))
session::show_profile_by_rockstar_id(g_player_service->get_selected()->get_net_data()->m_gamer_handle.m_rockstar_id);
if (CPlayerInfo* player_info = g_player_service->get_selected()->get_player_info(); player_info != nullptr)
{
ImGui::Text(std::format("{}: {}", "WANTED_LEVEL"_T, player_info->m_wanted_level).c_str());
}
if (ped_damage_bits & (uint32_t)eEntityProofs::GOD)
{
mode_str = "PLAYER_INFO_GOD"_T;
}
else
{
if (ped_damage_bits & (uint32_t)eEntityProofs::BULLET)
{
mode_str += "PLAYER_INFO_BULLET"_T;
}
if (ped_damage_bits & (uint32_t)eEntityProofs::EXPLOSION)
{
if (!mode_str.empty())
mode_str += " ";
mode_str += "PLAYER_INFO_EXPLOSION"_T;
}
if (ped_health > 328 || ped_maxhealth > 328)
{
if (!mode_str.empty())
mode_str += " ";
mode_str += "VIEW_PLAYER_INFO_UNNATURAL_HEALTH"_T.data();
}
}
if (mode_str.empty())
{
mode_str = "NO"_T;
}
ImGui::Text("PLAYER_INFO_PROOFS"_T.data(), mode_str.c_str());
mode_str.clear();
if (ped_task_flag & (uint8_t)ePedTask::TASK_DRIVING)
{
if (auto vehicle = g_player_service->get_selected()->get_current_vehicle(); vehicle != nullptr)
{
veh_damage_bits = vehicle->m_damage_bits;
if (CVehicleModelInfo* vehicle_model_info = static_cast<CVehicleModelInfo*>(vehicle->m_model_info))
{
vehicle_name = g_gta_data_service->vehicles()[vehicle_model_info->m_name].m_display_name; // TODO
}
if (veh_damage_bits & (uint32_t)eEntityProofs::GOD)
{
mode_str = "PLAYER_INFO_GOD"_T;
} }
else else
{ {
if (net_player_data->m_force_relays) if (veh_damage_bits & (uint32_t)eEntityProofs::COLLISION)
ImGui::Text("VIEW_PLAYER_INFO_IP_HIDDEN"_T.data()); {
else mode_str += "PLAYER_INFO_COLLISION"_T;
ImGui::Text("VIEW_PLAYER_INFO_IP_UNKNOWN"_T.data()); }
if (veh_damage_bits & (uint32_t)eEntityProofs::EXPLOSION)
{
mode_str += "PLAYER_INFO_EXPLOSION"_T;
}
}
auto cxn_type = g_player_service->get_selected()->get_connection_peer() ? if (mode_str.empty())
g_player_service->get_selected()->get_connection_peer()->m_peer_address.m_connection_type : {
0; mode_str = "NO"_T;
if (g.protections.force_relay_connections && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_FORCE_RELAY_TOOLTIP"_T.data());
else if (cxn_type == 2 && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_RELAY_TOOLTIP"_T.data());
else if (cxn_type == 3 && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_PEER_RELAY_TOOLTIP"_T.data());
} }
} }
ImGui::EndListBox();
} }
ImGui::EndGroup(); else
{
vehicle_name = "PLAYER_INFO_NO_VEHICLE"_T;
}
ImGui::Text("PLAYER_INFO_VEHICLE"_T.data(), vehicle_name.c_str(), mode_str.c_str());
if (auto net_player_data = g_player_service->get_selected()->get_net_data())
{
ImGui::Text("PLAYER_INFO_RID"_T.data(), net_player_data->m_gamer_handle.m_rockstar_id);
ImGui::SameLine();
ImGui::PushID("##rid");
if (ImGui::SmallButton("COPY"_T.data()))
ImGui::SetClipboardText(std::to_string(net_player_data->m_gamer_handle.m_rockstar_id).data());
ImGui::PopID();
auto ip = g_player_service->get_selected()->get_ip_address();
auto port = g_player_service->get_selected()->get_port();
if (ip)
{
ImGui::Text("PLAYER_INFO_IP"_T.data(),
ip.value().m_field1,
ip.value().m_field2,
ip.value().m_field3,
ip.value().m_field4,
port);
ImGui::SameLine();
// clang-format off
ImGui::PushID("##ip");
if (ImGui::SmallButton("COPY"_T.data()))
ImGui::SetClipboardText(std::format("{}.{}.{}.{}:{}",
ip.value().m_field1,
ip.value().m_field2,
ip.value().m_field3,
ip.value().m_field4,
port).data());
ImGui::PopID();
// clang-format on
}
else
{
if (net_player_data->m_force_relays) // TODO: does this actually do anything?
ImGui::Text("VIEW_PLAYER_INFO_IP_HIDDEN"_T.data());
else
ImGui::Text("VIEW_PLAYER_INFO_IP_UNKNOWN"_T.data());
auto cxn_type = g_player_service->get_selected()->get_connection_peer() ?
g_player_service->get_selected()->get_connection_peer()->m_peer_address.m_connection_type :
0;
if (g.protections.force_relay_connections && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_FORCE_RELAY_TOOLTIP"_T.data());
else if (cxn_type == 2 && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_RELAY_TOOLTIP"_T.data());
else if (cxn_type == 3 && ImGui::IsItemHovered())
ImGui::SetTooltip("VIEW_PLAYER_INFO_IP_PEER_RELAY_TOOLTIP"_T.data());
}
}
} }
} }

View File

@ -6,40 +6,28 @@ namespace big
{ {
void view::player_kick() void view::player_kick()
{ {
ImGui::BeginGroup(); ImGui::SeparatorText("KICKS"_T.data());
components::sub_title("KICK"_T);
if (ImGui::BeginListBox("##kick", get_listbox_dimensions()))
{
auto const is_session_host = [] {
return gta_util::get_network()->m_game_session_ptr->is_host();
};
if (!g_player_service->get_self()->is_host()) if (!g_player_service->get_self()->is_host())
ImGui::Text("VIEW_PLAYER_KICK_HOST_AND_BREAKUP_KICK_REQUIRE_SESSION_HOST"_T.data()); ImGui::Text("VIEW_PLAYER_KICK_HOST_AND_BREAKUP_KICK_REQUIRE_SESSION_HOST"_T.data());
ImGui::BeginDisabled(!g_player_service->get_self()->is_host()); ImGui::BeginDisabled(!g_player_service->get_self()->is_host());
components::player_command_button<"hostkick">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"breakup">(g_player_service->get_selected());
ImGui::EndDisabled();
ImGui::SameLine();
components::player_command_button<"hostkick">(g_player_service->get_selected()); components::command_checkbox<"breakupcheating">();
components::player_command_button<"breakup">(g_player_service->get_selected());
ImGui::EndDisabled();
ImGui::SameLine();
components::command_checkbox<"breakupcheating">();
components::player_command_button<"smartkick">(g_player_service->get_selected()); components::player_command_button<"smartkick">(g_player_service->get_selected());
ImGui::SameLine(); ImGui::SameLine();
components::player_command_button<"oomkick">(g_player_service->get_selected()); components::player_command_button<"oomkick">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"shkick">(g_player_service->get_selected()); components::player_command_button<"shkick">(g_player_service->get_selected());
ImGui::SameLine(); ImGui::SameLine();
components::player_command_button<"endkick">(g_player_service->get_selected()); components::player_command_button<"endkick">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"desync">(g_player_service->get_selected()); components::player_command_button<"desync">(g_player_service->get_selected());
ImGui::EndListBox();
}
ImGui::EndGroup();
} }
} }

View File

@ -1,45 +1,36 @@
#include "script/globals/GPBD_FM_3.hpp"
#include "services/script_connection/script_connection_service.hpp"
#include "util/scripts.hpp"
#include "util/vehicle.hpp"
#include "views/view.hpp" #include "views/view.hpp"
#include "services/players/player_service.hpp"
namespace big namespace big
{ {
void view::player_misc() void view::player_misc()
{ {
ImGui::SeparatorText("DEBUG_TAB_MISC"_T.data());
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("DEBUG_TAB_MISC"_T); components::player_command_button<"joinceo">(g_player_service->get_selected());
if (ImGui::BeginListBox("##misc", get_listbox_dimensions())) components::player_command_button<"enterint">(g_player_service->get_selected());
{ components::player_command_button<"copyoutfit">(g_player_service->get_selected());
components::player_command_button<"joinceo">(g_player_service->get_selected()); components::player_command_button<"copymodel">(g_player_service->get_selected());
ImGui::SameLine(); components::player_command_button<"clearwanted">(g_player_service->get_selected());
components::player_command_button<"enterint">(g_player_service->get_selected()); ImGui::EndGroup();
components::player_command_button<"copyoutfit">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"copymodel">(g_player_service->get_selected());
components::player_command_button<"clearwanted">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"givehealth">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"givearmor">(g_player_service->get_selected());
components::player_command_button<"giveammo">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"giveweaps">(g_player_service->get_selected(), {});
ImGui::BeginGroup(); ImGui::SameLine();
ImGui::Checkbox("OFF_THE_RADAR"_T.data(), &g_player_service->get_selected()->off_radar);
ImGui::Checkbox("NEVER_WANTED"_T.data(), &g_player_service->get_selected()->never_wanted);
ImGui::Checkbox("SEMI_GODMODE"_T.data(), &g_player_service->get_selected()->semi_godmode);
ImGui::EndGroup();
ImGui::SameLine(); ImGui::BeginGroup();
components::player_command_button<"givehealth">(g_player_service->get_selected());
components::player_command_button<"givearmor">(g_player_service->get_selected());
components::player_command_button<"giveammo">(g_player_service->get_selected());
components::player_command_button<"giveweaps">(g_player_service->get_selected(), {});
ImGui::EndGroup();
ImGui::Checkbox("VIEW_NET_SESSION_FIX_VEHICLE"_T.data(), &g_player_service->get_selected()->fix_vehicle); ImGui::SameLine();
ImGui::EndListBox();
}
ImGui::BeginGroup();
ImGui::Checkbox("OFF_THE_RADAR"_T.data(), &g_player_service->get_selected()->off_radar);
ImGui::Checkbox("NEVER_WANTED"_T.data(), &g_player_service->get_selected()->never_wanted);
ImGui::Checkbox("SEMI_GODMODE"_T.data(), &g_player_service->get_selected()->semi_godmode);
ImGui::Checkbox("VIEW_NET_SESSION_FIX_VEHICLE"_T.data(), &g_player_service->get_selected()->fix_vehicle);
ImGui::EndGroup(); ImGui::EndGroup();
} }
} }

View File

@ -9,132 +9,116 @@ namespace big
{ {
void view::player_teleport() void view::player_teleport()
{ {
ImGui::BeginGroup(); ImGui::SeparatorText("GUI_TAB_TELEPORT"_T.data());
components::sub_title("GUI_TAB_TELEPORT"_T); components::player_command_button<"playertp">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"playervehtp">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"bring">(g_player_service->get_selected());
ImGui::SameLine();
components::button("VIEW_PLAYER_TELEPORT_YOUR_WAYPOINT"_T, [] {
Vector3 location;
if (blip::get_blip_location(location, (int)BlipIcons::Waypoint))
entity::load_ground_at_3dcoord(location), teleport::teleport_player_to_coords(g_player_service->get_selected(), location);
});
if (ImGui::BeginListBox("##teleport", get_listbox_dimensions())) components::player_command_button<"intkick">(g_player_service->get_selected(), {});
ImGui::SetNextItemWidth(300);
if (ImGui::BeginCombo("##apartment", apartment_names[g.session.send_to_apartment_idx]))
{ {
components::player_command_button<"playertp">(g_player_service->get_selected()); for (int i = 1; i < apartment_names.size(); i++)
ImGui::SameLine();
components::player_command_button<"playervehtp">(g_player_service->get_selected());
ImGui::SameLine();
components::player_command_button<"bring">(g_player_service->get_selected());
components::button("VIEW_PLAYER_TELEPORT_WAYPOINT"_T, [] {
Vector3 location;
if (blip::get_blip_location(location, (int)BlipIcons::Waypoint))
entity::load_ground_at_3dcoord(location), teleport::teleport_player_to_coords(g_player_service->get_selected(), location);
});
components::options_modal(
"VIEW_PLAYER_TELEPORT_INTERIOR_TELEPORT"_T.data(),
[] {
components::player_command_button<"intkick">(g_player_service->get_selected(), {});
if (ImGui::BeginCombo("##apartment", apartment_names[g.session.send_to_apartment_idx]))
{
for (int i = 1; i < apartment_names.size(); i++)
{
if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
{
g.session.send_to_apartment_idx = i;
}
if (i == g.session.send_to_apartment_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::player_command_button<"apartmenttp">(g_player_service->get_selected(),
{(uint64_t)g.session.send_to_apartment_idx});
if (ImGui::BeginCombo("##warehouse", warehouse_names[g.session.send_to_warehouse_idx]))
{
for (int i = 1; i < warehouse_names.size(); i++)
{
if (ImGui::Selectable(warehouse_names[i], i == g.session.send_to_warehouse_idx))
{
g.session.send_to_warehouse_idx = i;
}
if (i == g.session.send_to_warehouse_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::player_command_button<"warehousetp">(g_player_service->get_selected(),
{(uint64_t)g.session.send_to_warehouse_idx});
components::button("TP_TO_DARTS"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::Darts);
});
ImGui::SameLine();
components::button("TP_TO_FLIGHT_SCHOOL"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::PilotSchool);
});
ImGui::SameLine();
components::button("TP_TO_MAP_CENTER"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::ArmWresling);
});
components::button("TP_TO_SKYDIVE"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::Skydive);
});
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {81}, "VIEW_PLAYER_TELEPORT_TP_TO_MOC"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {123}, "VIEW_PLAYER_TELEPORT_TP_TO_CASINO"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {124}, "VIEW_PLAYER_TELEPORT_TP_TO_PENTHOUSE"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {128}, "VIEW_PLAYER_TELEPORT_TP_TO_ARCADE"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {146}, "VIEW_PLAYER_TELEPORT_TP_TO_MUSIC_LOCKER"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {148}, "VIEW_PLAYER_TELEPORT_TP_TO_RECORD_A_STUDIOS"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {149}, "VIEW_PLAYER_TELEPORT_TP_TO_CUSTOM_AUTO_SHOP"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {155}, "VIEW_PLAYER_TELEPORT_TP_TO_AGENCY"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {160}, "VIEW_PLAYER_TELEPORT_TP_TO_FREAKSHOP"_T);
ImGui::SameLine();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {161}, "VIEW_PLAYER_TELEPORT_TP_TO_MULTI_FLOOR_GARAGE"_T);
},
false,
"INTERIOR"_T.data());
if (g_player_service->get_selected()->get_ped())
{ {
static float new_location[3]; if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
auto& current_location = *reinterpret_cast<float(*)[3]>(g_player_service->get_selected()->get_ped()->get_position());
components::small_text("VIEW_PLAYER_TELEPORT_CUSTOM_TP"_T);
ImGui::SetNextItemWidth(400);
ImGui::InputFloat3("##customlocation", new_location);
components::button("GUI_TAB_TELEPORT"_T, [] {
teleport::teleport_player_to_coords(g_player_service->get_selected(), *reinterpret_cast<rage::fvector3*>(&new_location));
});
ImGui::SameLine();
if (ImGui::Button("VIEW_PLAYER_TELEPORT_GET_CURRENT"_T.data()))
{ {
std::copy(std::begin(current_location), std::end(current_location), std::begin(new_location)); g.session.send_to_apartment_idx = i;
}
if (i == g.session.send_to_apartment_idx)
{
ImGui::SetItemDefaultFocus();
} }
} }
ImGui::EndListBox(); ImGui::EndCombo();
} }
ImGui::SameLine();
components::player_command_button<"apartmenttp">(g_player_service->get_selected(),
{(uint64_t)g.session.send_to_apartment_idx});
ImGui::SetNextItemWidth(300);
if (ImGui::BeginCombo("##warehouse", warehouse_names[g.session.send_to_warehouse_idx]))
{
for (int i = 1; i < warehouse_names.size(); i++)
{
if (ImGui::Selectable(warehouse_names[i], i == g.session.send_to_warehouse_idx))
{
g.session.send_to_warehouse_idx = i;
}
if (i == g.session.send_to_warehouse_idx)
{
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
ImGui::SameLine();
components::player_command_button<"warehousetp">(g_player_service->get_selected(),
{(uint64_t)g.session.send_to_warehouse_idx});
ImGui::BeginGroup();
components::button("TP_TO_DARTS"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::Darts);
});
components::button("TP_TO_FLIGHT_SCHOOL"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::PilotSchool);
});
components::button("TP_TO_MAP_CENTER"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::ArmWresling);
});
components::button("TP_TO_SKYDIVE"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::Skydive);
});
components::player_command_button<"interiortp">(g_player_service->get_selected(), {81}, "VIEW_PLAYER_TELEPORT_TP_TO_MOC"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {123}, "VIEW_PLAYER_TELEPORT_TP_TO_CASINO"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {124}, "VIEW_PLAYER_TELEPORT_TP_TO_PENTHOUSE"_T);
ImGui::EndGroup(); ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::player_command_button<"interiortp">(g_player_service->get_selected(), {146}, "VIEW_PLAYER_TELEPORT_TP_TO_MUSIC_LOCKER"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {148}, "VIEW_PLAYER_TELEPORT_TP_TO_RECORD_A_STUDIOS"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {149}, "VIEW_PLAYER_TELEPORT_TP_TO_CUSTOM_AUTO_SHOP"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {155}, "VIEW_PLAYER_TELEPORT_TP_TO_AGENCY"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {160}, "VIEW_PLAYER_TELEPORT_TP_TO_FREAKSHOP"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {161}, "VIEW_PLAYER_TELEPORT_TP_TO_MULTI_FLOOR_GARAGE"_T);
components::player_command_button<"interiortp">(g_player_service->get_selected(), {128}, "VIEW_PLAYER_TELEPORT_TP_TO_ARCADE"_T);
ImGui::EndGroup();
if (g_player_service->get_selected()->get_ped())
{
static float new_location[3];
auto& current_location = *reinterpret_cast<float(*)[3]>(g_player_service->get_selected()->get_ped()->get_position());
components::small_text("VIEW_PLAYER_TELEPORT_CUSTOM_TP"_T);
ImGui::SetNextItemWidth(400);
ImGui::InputFloat3("##customlocation", new_location);
components::button("GUI_TAB_TELEPORT"_T, [] {
teleport::teleport_player_to_coords(g_player_service->get_selected(), *reinterpret_cast<rage::fvector3*>(&new_location));
});
ImGui::SameLine();
if (ImGui::Button("VIEW_PLAYER_TELEPORT_GET_CURRENT"_T.data()))
{
std::copy(std::begin(current_location), std::end(current_location), std::begin(new_location));
}
}
} }
} }

View File

@ -9,118 +9,110 @@ namespace big
{ {
void view::player_toxic() void view::player_toxic()
{ {
ImGui::SeparatorText("TOXIC"_T.data());
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("TOXIC"_T); components::player_command_button<"kill">(g_player_service->get_selected(), {});
if (ImGui::BeginListBox("##toxic", get_listbox_dimensions())) components::player_command_button<"explode">(g_player_service->get_selected(), {});
{ components::player_command_button<"ceokick">(g_player_service->get_selected(), {});
components::player_command_button<"kill">(g_player_service->get_selected(), {}); components::player_command_button<"ragdoll">(g_player_service->get_selected(), {});
ImGui::SameLine(); components::player_command_button<"beast">(g_player_service->get_selected(), {});
components::player_command_button<"explode">(g_player_service->get_selected(), {}); components::player_command_button<"mission">(g_player_service->get_selected(), {});
components::player_command_button<"breakgame">(g_player_service->get_selected(), {});
components::player_command_button<"ceokick">(g_player_service->get_selected(), {}); components::player_command_button<"error">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"ragdoll">(g_player_service->get_selected(), {});
components::player_command_button<"beast">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"mission">(g_player_service->get_selected(), {});
components::player_command_button<"breakgame">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"error">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"ceoraid">(g_player_service->get_selected(), {});
components::button("TRIGGER_MC_RAID"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::BikerDefend);
});
ImGui::SameLine();
components::button("TRIGGER_BUNKER_RAID"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::GunrunningDefend);
});
components::player_command_button<"sext">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"fakeban">(g_player_service->get_selected(), {});
static int wanted_level;
components::small_text("WANTED_LVL"_T);
ImGui::SliderInt("##wantedlevelslider", &wanted_level, 0, 5);
ImGui::SameLine();
components::player_command_button<"wanted">(g_player_service->get_selected(), {(uint64_t)wanted_level}, "Set");
components::player_command_button<"remweaps">(g_player_service->get_selected(), {});
components::player_command_button<"tutorial">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"golf">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"flightschool">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"darts">(g_player_service->get_selected(), {});
components::player_command_button<"badlands">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"spacemonkey">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"wizard">(g_player_service->get_selected(), {});
components::player_command_button<"qub3d">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"camhedz">(g_player_service->get_selected(), {});
components::small_text("WARP_TIME"_T);
components::button("PLUS_1_MINUTE"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_5_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 5 * 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_48_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 48 * 60 * 1000);
});
components::button("PLUS_96_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 96 * 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_200_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 200 * 60 * 1000);
});
ImGui::SameLine();
components::button("STOP_TIME"_T, [] {
toxic::set_time(g_player_service->get_selected(), INT_MAX - 3000);
});
if (ImGui::IsItemHovered())
ImGui::SetTooltip("PLAYER_TOXIC_NO_WAY_BACK"_T.data());
ImGui::Checkbox("KILL_LOOP"_T.data(), &g_player_service->get_selected()->kill_loop);
ImGui::SameLine();
ImGui::Checkbox("EXPLOSION_LOOP"_T.data(), &g_player_service->get_selected()->explosion_loop);
ImGui::Checkbox("RAGDOLL_LOOP"_T.data(), &g_player_service->get_selected()->ragdoll_loop);
ImGui::SameLine();
ImGui::Checkbox("ROT_CAM_LOOP"_T.data(), &g_player_service->get_selected()->rotate_cam_loop);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("PLAYER_TOXIC_BRING_PLAYER_OUT_GOD"_T.data());
ImGui::Checkbox("SPAM_KILLFEED"_T.data(), &g_player_service->get_selected()->spam_killfeed);
static int bounty_value = 0;
ImGui::SetNextItemWidth(300);
ImGui::SliderInt("BOUNTY"_T.data(), &bounty_value, 0, 10000);
components::command_checkbox<"anonbounty">();
ImGui::SameLine();
ImGui::PushID("setbounty");
components::button("SET"_T, [] {
troll::set_bounty_on_player(g_player_service->get_selected(), bounty_value, g.session.anonymous_bounty);
});
ImGui::PopID();
ImGui::EndListBox();
}
ImGui::EndGroup(); ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::player_command_button<"ceoraid">(g_player_service->get_selected(), {});
components::button("TRIGGER_MC_RAID"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::BikerDefend);
});
components::button("TRIGGER_BUNKER_RAID"_T, [] {
toxic::start_activity(g_player_service->get_selected(), eActivityType::GunrunningDefend);
});
components::player_command_button<"sext">(g_player_service->get_selected(), {});
components::player_command_button<"fakeban">(g_player_service->get_selected(), {});
components::player_command_button<"remweaps">(g_player_service->get_selected(), {});
components::player_command_button<"tutorial">(g_player_service->get_selected(), {});
components::player_command_button<"golf">(g_player_service->get_selected(), {});
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
components::player_command_button<"flightschool">(g_player_service->get_selected(), {});
components::player_command_button<"darts">(g_player_service->get_selected(), {});
components::player_command_button<"badlands">(g_player_service->get_selected(), {});
components::player_command_button<"spacemonkey">(g_player_service->get_selected(), {});
components::player_command_button<"wizard">(g_player_service->get_selected(), {});
components::player_command_button<"qub3d">(g_player_service->get_selected(), {});
components::player_command_button<"camhedz">(g_player_service->get_selected(), {});
ImGui::EndGroup();
ImGui::BeginGroup();
components::small_text("WARP_TIME"_T);
components::button("PLUS_1_MINUTE"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_5_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 5 * 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_48_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 48 * 60 * 1000);
});
components::button("PLUS_96_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 96 * 60 * 1000);
});
ImGui::SameLine();
components::button("PLUS_200_MINUTES"_T, [] {
toxic::warp_time_forward(g_player_service->get_selected(), 200 * 60 * 1000);
});
ImGui::SameLine();
components::button("STOP_TIME"_T, [] {
toxic::set_time(g_player_service->get_selected(), INT_MAX - 3000);
});
if (ImGui::IsItemHovered())
ImGui::SetTooltip("PLAYER_TOXIC_NO_WAY_BACK"_T.data());
ImGui::EndGroup();
ImGui::SameLine();
ImGui::BeginGroup();
static int bounty_value = 0;
ImGui::SetNextItemWidth(175);
ImGui::SliderInt("BOUNTY"_T.data(), &bounty_value, 0, 10000);
components::command_checkbox<"anonbounty">();
ImGui::SameLine();
ImGui::PushID("setbounty");
components::button("SET"_T, [] {
troll::set_bounty_on_player(g_player_service->get_selected(), bounty_value, g.session.anonymous_bounty);
});
ImGui::PopID();
ImGui::EndGroup();
ImGui::Checkbox("KILL_LOOP"_T.data(), &g_player_service->get_selected()->kill_loop);
ImGui::SameLine();
ImGui::Checkbox("EXPLOSION_LOOP"_T.data(), &g_player_service->get_selected()->explosion_loop);
ImGui::SameLine();
ImGui::Checkbox("RAGDOLL_LOOP"_T.data(), &g_player_service->get_selected()->ragdoll_loop);
ImGui::SameLine();
ImGui::Checkbox("ROT_CAM_LOOP"_T.data(), &g_player_service->get_selected()->rotate_cam_loop);
if (ImGui::IsItemHovered())
ImGui::SetTooltip("PLAYER_TOXIC_BRING_PLAYER_OUT_GOD"_T.data());
ImGui::SameLine();
ImGui::Checkbox("SPAM_KILLFEED"_T.data(), &g_player_service->get_selected()->spam_killfeed);
static int wanted_level;
components::small_text("WANTED_LVL"_T);
ImGui::SetNextItemWidth(150);
ImGui::SliderInt("##wantedlevelslider", &wanted_level, 0, 5);
ImGui::SameLine();
components::player_command_button<"wanted">(g_player_service->get_selected(), {(uint64_t)wanted_level}, "Set");
} }
} }

View File

@ -4,54 +4,41 @@ namespace big
{ {
void view::player_vehicle() void view::player_vehicle()
{ {
ImGui::SeparatorText("VEHICLE"_T.data());
ImGui::BeginGroup(); ImGui::BeginGroup();
components::sub_title("VEHICLE"_T); components::player_command_button<"vehkick">(g_player_service->get_selected(), {});
if (ImGui::BeginListBox("##veh", get_listbox_dimensions())) components::player_command_button<"deleteveh">(g_player_service->get_selected(), {});
{ components::player_command_button<"flyingveh">(g_player_service->get_selected(), {});
components::player_command_button<"vehkick">(g_player_service->get_selected(), {}); components::player_command_button<"boostveh">(g_player_service->get_selected(), {});
ImGui::SameLine(); components::player_command_button<"stopveh">(g_player_service->get_selected(), {});
components::player_command_button<"flyingveh">(g_player_service->get_selected(), {}); components::player_command_button<"flip180">(g_player_service->get_selected(), {});
components::player_command_button<"rcplayer">(g_player_service->get_selected(), {});
ImGui::EndGroup();
components::player_command_button<"boostveh">(g_player_service->get_selected(), {}); ImGui::SameLine();
ImGui::SameLine();
components::player_command_button<"stopveh">(g_player_service->get_selected(), {});
components::player_command_button<"flip180">(g_player_service->get_selected(), {}); ImGui::BeginGroup();
ImGui::SameLine(); components::player_command_button<"killengine">(g_player_service->get_selected(), {});
components::player_command_button<"rcplayer">(g_player_service->get_selected(), {}); components::player_command_button<"burstwheels">(g_player_service->get_selected(), {});
components::player_command_button<"smashwindows">(g_player_service->get_selected(), {});
components::player_command_button<"blacktint">(g_player_service->get_selected(), {});
components::player_command_button<"lockveh">(g_player_service->get_selected(), {});
components::player_command_button<"unlockveh">(g_player_service->get_selected(), {});
components::player_command_button<"opendoors">(g_player_service->get_selected(), {});
components::player_command_button<"closedoors">(g_player_service->get_selected(), {});
ImGui::EndGroup();
components::player_command_button<"killengine">(g_player_service->get_selected(), {}); ImGui::SameLine();
ImGui::SameLine();
components::player_command_button<"burstwheels">(g_player_service->get_selected(), {});
components::player_command_button<"smashwindows">(g_player_service->get_selected(), {}); ImGui::BeginGroup();
ImGui::SameLine(); components::player_command_button<"breakdoors">(g_player_service->get_selected(), {});
components::player_command_button<"blacktint">(g_player_service->get_selected(), {}); components::player_command_button<"upgradeveh">(g_player_service->get_selected(), {});
components::player_command_button<"downgradeveh">(g_player_service->get_selected(), {});
components::player_command_button<"lockveh">(g_player_service->get_selected(), {}); components::player_command_button<"svehjump">(g_player_service->get_selected(), {});
ImGui::SameLine(); components::player_command_button<"svehboost">(g_player_service->get_selected(), {});
components::player_command_button<"unlockveh">(g_player_service->get_selected(), {}); components::player_command_button<"sshuntleft">(g_player_service->get_selected(), {});
components::player_command_button<"sshuntright">(g_player_service->get_selected(), {});
components::player_command_button<"opendoors">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"closedoors">(g_player_service->get_selected(), {});
components::player_command_button<"breakdoors">(g_player_service->get_selected(), {});
components::player_command_button<"upgradeveh">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"downgradeveh">(g_player_service->get_selected(), {});
components::player_command_button<"svehjump">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"svehboost">(g_player_service->get_selected(), {});
components::player_command_button<"sshuntleft">(g_player_service->get_selected(), {});
ImGui::SameLine();
components::player_command_button<"sshuntright">(g_player_service->get_selected(), {});
ImGui::EndListBox();
}
ImGui::EndGroup(); ImGui::EndGroup();
} }
} }

View File

@ -41,16 +41,11 @@ namespace big
std::format("{} ({}){}", current_player->get_name(), current_player->id(), name_appendage).c_str()); std::format("{} ({}){}", current_player->get_name(), current_player->id(), name_appendage).c_str());
view::player_info(); view::player_info();
ImGui::SameLine();
view::player_teleport(); view::player_teleport();
view::player_kick(); view::player_kick();
ImGui::SameLine();
view::player_toxic(); view::player_toxic();
view::player_misc();
ImGui::SameLine();
view::player_vehicle(); view::player_vehicle();
view::player_misc();
} }
else else
g_gui_service->set_selected(tabs::NONE); g_gui_service->set_selected(tabs::NONE);

View File

@ -27,7 +27,8 @@ namespace big
player_icons += FONT_ICON_HOST; player_icons += FONT_ICON_HOST;
if (plyr->is_friend()) if (plyr->is_friend())
player_icons += FONT_ICON_FRIEND; player_icons += FONT_ICON_FRIEND;
if (const auto ped = plyr->get_ped(); (ped != nullptr && ped->m_ped_task_flag & (uint8_t)ePedTask::TASK_DRIVING)) if (const auto ped = plyr->get_ped(); (ped != nullptr
&& (ped->m_ped_task_flag & (uint8_t)ePedTask::TASK_DRIVING || PLAYER::IS_REMOTE_PLAYER_IN_NON_CLONED_VEHICLE(plyr->id()))))
player_icons += FONT_ICON_VEHICLE; player_icons += FONT_ICON_VEHICLE;
const auto player_iconsc = player_icons.c_str(); const auto player_iconsc = player_icons.c_str();

View File

@ -1,6 +1,5 @@
#include "core/data/block_join_reasons.hpp"
#include "backend/reactions/reaction.hpp"
#include "views/view.hpp" #include "views/view.hpp"
#include "core/data/block_join_reasons.hpp"
namespace big namespace big
{ {
@ -62,7 +61,7 @@ namespace big
ImGui::Checkbox("REACTION_BLOCK_JOINS"_T.data(), &reaction.block_joins); ImGui::Checkbox("REACTION_BLOCK_JOINS"_T.data(), &reaction.block_joins);
if (reaction.block_joins) if (reaction.block_joins)
if (ImGui::BeginCombo("BLOCK_JOIN_ALERT"_T.data(), block_join_reasons[reaction.block_join_reason])) if (ImGui::BeginCombo("BLOCK_JOIN_ALERT"_T.data(), block_join_reasons[reaction.block_join_reason]))
{ {
for (const auto& [key, value] : block_join_reasons) for (const auto& [key, value] : block_join_reasons)
{ {
bool is_selected = (reaction.block_join_reason == key); bool is_selected = (reaction.block_join_reason == key);
@ -95,12 +94,14 @@ namespace big
{ {
components::title("SETTINGS_REACTIONS"_T); components::title("SETTINGS_REACTIONS"_T);
draw_reaction(g.reactions.bounty); draw_reaction(g.reactions.bounty);
draw_reaction(g.reactions.break_game);
draw_reaction(g.reactions.ceo_kick); draw_reaction(g.reactions.ceo_kick);
draw_reaction(g.reactions.ceo_money); draw_reaction(g.reactions.ceo_money);
draw_reaction(g.reactions.chat_spam); draw_reaction(g.reactions.chat_spam);
draw_reaction(g.reactions.clear_ped_tasks); draw_reaction(g.reactions.clear_ped_tasks);
draw_reaction(g.reactions.clear_wanted_level); draw_reaction(g.reactions.clear_wanted_level);
draw_reaction(g.reactions.crash); draw_reaction(g.reactions.crash);
draw_reaction(g.reactions.delete_vehicle);
draw_reaction(g.reactions.destroy_personal_vehicle); draw_reaction(g.reactions.destroy_personal_vehicle);
draw_reaction(g.reactions.end_session_kick); draw_reaction(g.reactions.end_session_kick);
draw_reaction(g.reactions.fake_deposit); draw_reaction(g.reactions.fake_deposit);

View File

@ -40,6 +40,7 @@ namespace big
static void self(); static void self();
static void animations(); static void animations();
static void network(); static void network();
static void chat();
static void missions(); static void missions();
static void player_database(); static void player_database();
static void session_browser(); static void session_browser();

View File

@ -135,7 +135,7 @@ namespace big
PED::SET_PED_FIRING_PATTERN(ped, "FIRING_PATTERN_FULL_AUTO"_J); PED::SET_PED_FIRING_PATTERN(ped, "FIRING_PATTERN_FULL_AUTO"_J);
PED::SET_PED_SHOOT_RATE(ped, 150); PED::SET_PED_SHOOT_RATE(ped, 150);
if (!clone) if (!clone && g.world.spawn_ped.randomize_outfit)
ped::set_ped_random_component_variation(ped); ped::set_ped_random_component_variation(ped);
if (is_bodyguard) if (is_bodyguard)
@ -598,6 +598,7 @@ namespace big
ImGui::Checkbox("VIEW_SPAWN_PED_INVINCIBLE"_T.data(), &g.world.spawn_ped.spawn_invincible); ImGui::Checkbox("VIEW_SPAWN_PED_INVINCIBLE"_T.data(), &g.world.spawn_ped.spawn_invincible);
ImGui::Checkbox("VIEW_SPAWN_PED_INVISIBLE"_T.data(), &g.world.spawn_ped.spawn_invisible); ImGui::Checkbox("VIEW_SPAWN_PED_INVISIBLE"_T.data(), &g.world.spawn_ped.spawn_invisible);
ImGui::Checkbox("VIEW_SPAWN_PED_ATTACKER"_T.data(), &g.world.spawn_ped.spawn_as_attacker); ImGui::Checkbox("VIEW_SPAWN_PED_ATTACKER"_T.data(), &g.world.spawn_ped.spawn_as_attacker);
ImGui::Checkbox("VIEW_SPAWN_PED_RANDOMIZE_OUTFIT"_T.data(), &g.world.spawn_ped.randomize_outfit);
components::button("CHANGE_PLAYER_MODEL"_T, [] { components::button("CHANGE_PLAYER_MODEL"_T, [] {
if (selected_ped_type == -2) if (selected_ped_type == -2)