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:
parent
f3cf7b5983
commit
4589b87553
@ -6,7 +6,7 @@ message("AsyncLogger")
|
||||
FetchContent_Declare(
|
||||
AsyncLogger
|
||||
GIT_REPOSITORY https://github.com/Yimura/AsyncLogger.git
|
||||
GIT_TAG 80ce938277acd44767f858099920ae20f1df42ca
|
||||
GIT_TAG 6fcfd90b3f4ca4dae09c4a96e9a506e6aea06472
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
FetchContent_MakeAvailable(AsyncLogger)
|
||||
|
@ -3,7 +3,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
gtav_classes
|
||||
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
|
||||
GIT_TAG c741a3031de7981d12c97f55569f930a82556d63
|
||||
GIT_TAG 68551ec2e5b09d6fe629abb7726148127d9f9e6f
|
||||
GIT_PROGRESS TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -124,6 +124,7 @@ namespace big
|
||||
looped::session_force_thunder();
|
||||
looped::session_randomize_ceo_colors();
|
||||
looped::session_auto_kick_host();
|
||||
looped::session_force_script_host();
|
||||
looped::session_block_jobs();
|
||||
looped::session_chat_translator();
|
||||
looped::session_modder_detection();
|
||||
|
@ -74,7 +74,7 @@ namespace big
|
||||
{
|
||||
m_toggle = true;
|
||||
m_last_enabled = true;
|
||||
g_fiber_pool->queue_job([this] {
|
||||
g_fiber_pool->execute_on_game_thread([this] {
|
||||
on_enable();
|
||||
});
|
||||
}
|
||||
@ -86,7 +86,7 @@ namespace big
|
||||
{
|
||||
m_toggle = false;
|
||||
m_last_enabled = false;
|
||||
g_fiber_pool->queue_job([this] {
|
||||
g_fiber_pool->execute_on_game_thread([this] {
|
||||
on_disable();
|
||||
});
|
||||
}
|
||||
@ -97,14 +97,14 @@ namespace big
|
||||
if (m_toggle && !m_last_enabled)
|
||||
{
|
||||
m_last_enabled = true;
|
||||
g_fiber_pool->queue_job([this] {
|
||||
g_fiber_pool->execute_on_game_thread([this] {
|
||||
on_enable();
|
||||
});
|
||||
}
|
||||
else if (!m_toggle && m_last_enabled)
|
||||
{
|
||||
m_last_enabled = false;
|
||||
g_fiber_pool->queue_job([this] {
|
||||
g_fiber_pool->execute_on_game_thread([this] {
|
||||
on_disable();
|
||||
});
|
||||
}
|
||||
|
@ -18,7 +18,8 @@ namespace big
|
||||
if (!player->get_ped())
|
||||
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()->m_navigation->get_position(),
|
||||
0,
|
||||
@ -27,7 +28,7 @@ namespace big
|
||||
10000.0f,
|
||||
2,
|
||||
0,
|
||||
(1 << 4),
|
||||
(1 << 4) | 0x80000,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
|
@ -24,7 +24,7 @@ namespace big
|
||||
int64_t args[arg_count] = {(int64_t)eRemoteEvent::StartScriptBegin, (int64_t)self::id, 1 << player->id()};
|
||||
|
||||
args[3] = scriptId;
|
||||
strcpy((char*)&args[2 + 3], "0");
|
||||
strcpy((char*)&args[3 + 3], "0");
|
||||
args[3 + 16] = -1;
|
||||
args[3 + 17] = 1337;
|
||||
args[3 + 19] = arg19;
|
||||
|
@ -118,7 +118,6 @@ namespace big
|
||||
if (!stack || !net_component)
|
||||
return;
|
||||
|
||||
((CGameScriptHandlerNetComponent*)thread->m_net_component)->block_host_migration(true);
|
||||
thread->m_context.m_state = rage::eThreadState::unk_3;
|
||||
g.m_hunt_the_beast_thread = thread;
|
||||
|
||||
|
27
src/backend/commands/player/vehicle/delete_vehicle.cpp
Normal file
27
src/backend/commands/player/vehicle/delete_vehicle.cpp
Normal 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);
|
||||
}
|
@ -35,6 +35,7 @@ namespace big
|
||||
static void session_block_jobs();
|
||||
static void session_randomize_ceo_colors();
|
||||
static void session_auto_kick_host();
|
||||
static void session_force_script_host();
|
||||
static void session_chat_translator();
|
||||
static void session_modder_detection();
|
||||
|
||||
|
@ -29,8 +29,6 @@ namespace big
|
||||
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_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;
|
||||
|
||||
// perform initial setup
|
||||
|
@ -8,8 +8,8 @@ namespace big
|
||||
static bool bLastKickHost = false;
|
||||
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;
|
||||
if (kick_host && !bLastKickHost)
|
||||
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) [[unlikely]]
|
||||
{
|
||||
g_player_service->iterate([](auto& plyr) {
|
||||
// Don't kick trusted players
|
||||
|
63
src/backend/looped/session/force_script_host.cpp
Normal file
63
src/backend/looped/session/force_script_host.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
104
src/backend/looped/session/spoof_host_token.cpp
Normal file
104
src/backend/looped/session/spoof_host_token.cpp
Normal 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);
|
||||
}
|
20
src/backend/looped/spoofing/spoof_dlc_hash.cpp
Normal file
20
src/backend/looped/spoofing/spoof_dlc_hash.cpp
Normal 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);
|
||||
}
|
69
src/backend/looped/spoofing/spoof_game_data_hash.cpp
Normal file
69
src/backend/looped/spoofing/spoof_game_data_hash.cpp
Normal 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);
|
||||
}
|
@ -14,28 +14,6 @@ namespace big
|
||||
static bool bLastForceHost = false;
|
||||
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)
|
||||
{
|
||||
gta_util::execute_as_script("freemode"_J, [] {
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "script.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -2,7 +2,9 @@
|
||||
#include "gta/enums.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "util/math.hpp"
|
||||
#include <numbers>
|
||||
|
||||
namespace big
|
||||
{
|
||||
class aimbot : looped_command
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "core/enums.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "natives.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -4,7 +4,9 @@
|
||||
#include "script.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "util/math.hpp"
|
||||
#include <numbers>
|
||||
|
||||
namespace big
|
||||
{
|
||||
static timer spawning_axe_delay(200ms);
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "core/enums.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "util/math.hpp"
|
||||
#include "natives.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -2,6 +2,8 @@
|
||||
#include "core/enums.hpp"
|
||||
#include "gta/enums.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
@ -24,6 +24,8 @@ namespace big
|
||||
// Patch blocked explosions
|
||||
explosion_anti_cheat_bypass::m_can_blame_others =
|
||||
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 =
|
||||
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
@ -26,5 +26,6 @@ namespace big
|
||||
// So that lua scripts can add a custom runtime reason.
|
||||
CUSTOM_REASON,
|
||||
CHAT_SPAM,
|
||||
SENT_MODDER_BEACONS
|
||||
};
|
||||
}
|
@ -17,7 +17,7 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
|
||||
{"MsgConfigResponse", 0x5F},
|
||||
{"MsgConfigRequest", 0x48},
|
||||
{"MsgChangeSessionAttributesCmd", 0x5A},
|
||||
{"MsgAddGamerToSessionCmd", 0x6},
|
||||
{"MsgAddGamerToSessionCmd", 0x64},
|
||||
{"MsgReassignResponse", 0x10},
|
||||
{"MsgReassignNegotiate", 0x01},
|
||||
{"MsgReassignConfirm", 0x26},
|
||||
@ -88,8 +88,8 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
|
||||
{"MsgRoamingInitialBubble", 0x32},
|
||||
{"MsgVoiceStatus", 0x03},
|
||||
{"MsgTextChatStatus", 0x00},
|
||||
{"MsgJoinResponse2", 0x08},
|
||||
{"MsgJoinRequest2", 0x68},
|
||||
{"MsgSnJoinResponse", 0x08},
|
||||
{"MsgSnJoinRequest", 0x68},
|
||||
{"MsgNetTimeSync", 0x38},
|
||||
{"MsgNetComplaint", 0x55},
|
||||
{"MsgNetLagPing", 0x27},
|
||||
@ -107,8 +107,15 @@ inline const static constexpr std::pair<const char*, uint32_t> packet_types[] =
|
||||
{"Msg_0x88", 0x88},
|
||||
{"Msg_0x80", 0x80},
|
||||
{"Msg_0x28", 0x28},
|
||||
{"Msg_0x11", 0x11},
|
||||
{"MsgNatTunnelerResponse", 0x11},
|
||||
{"MsgNatTunnelerRequest", 0x15},
|
||||
{"MsgNatTunnelerUnk", 0x7F},
|
||||
{"Msg_0x45", 0x45},
|
||||
{"Msg_0x89", 0x89},
|
||||
{"Msg_0x86", 0x86},
|
||||
{"MsgDtlsCxnCommand", 0x8A},
|
||||
{"MsgSetKickVote", 0x8E},
|
||||
{"MsgTransitionHandshake", 0x8D},
|
||||
{"MsgDidInvitePlayerRequest", 0x8B},
|
||||
{"MsgDidInvitePlayerResponse", 0x8C},
|
||||
};
|
@ -10,12 +10,12 @@ namespace big
|
||||
|
||||
const RegionType regions[] = {
|
||||
{0, "CIS"},
|
||||
{1, "Africa"},
|
||||
{2, "East"},
|
||||
{1, "South America"},
|
||||
{2, "US East"},
|
||||
{3, "Europe"},
|
||||
{4, "China"},
|
||||
{5, "Australia"},
|
||||
{6, "West"},
|
||||
{6, "US West"},
|
||||
{7, "Japan"},
|
||||
{8, "Unknown"},
|
||||
};
|
||||
|
@ -83,6 +83,30 @@ namespace big
|
||||
|
||||
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
|
||||
{
|
||||
bool enabled = false;
|
||||
@ -126,8 +150,9 @@ namespace big
|
||||
|
||||
bool external_console = true;
|
||||
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{};
|
||||
|
||||
struct tunables
|
||||
@ -179,12 +204,13 @@ namespace big
|
||||
struct reactions
|
||||
{
|
||||
// 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 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_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 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 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"};
|
||||
@ -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 request_control_event{"Request Control Event", "REACTION_REQUEST_CONTROL_NOTIFY", "REACTION_REQUEST_CONTROL_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 spectate{"Spectate", "REACTION_SPECTATING_NOTIFY", "REACTION_SPECTATING_ANNOUNCE"};
|
||||
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{};
|
||||
|
||||
struct player
|
||||
@ -402,7 +428,9 @@ namespace big
|
||||
bool log_text_messages = false;
|
||||
bool decloak_players = false;
|
||||
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 player_magnet_enabled = false;
|
||||
int player_magnet_count = 32;
|
||||
@ -441,7 +469,11 @@ namespace big
|
||||
int send_to_apartment_idx = 1;
|
||||
int send_to_warehouse_idx = 1;
|
||||
|
||||
script_block_opts script_block_opts;
|
||||
|
||||
// not to be saved
|
||||
std::atomic_bool spoof_host_token_dirty = true;
|
||||
std::uint64_t original_host_token = 0;
|
||||
bool join_queued = false;
|
||||
rage::rlSessionInfo info;
|
||||
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);
|
||||
} 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{};
|
||||
|
||||
struct settings
|
||||
@ -605,8 +637,9 @@ namespace big
|
||||
bool spawn_invincible = false;
|
||||
bool spawn_invisible = 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{};
|
||||
|
||||
struct custom_time
|
||||
@ -716,7 +749,16 @@ namespace big
|
||||
|
||||
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{};
|
||||
|
||||
struct vehicle
|
||||
@ -1037,13 +1079,15 @@ namespace big
|
||||
int player_count_filter_minimum = 0;
|
||||
int player_count_filter_maximum = 32;
|
||||
|
||||
bool filter_multiplexed_sessions = false;
|
||||
|
||||
int sort_method = 0;
|
||||
int sort_direction = 0;
|
||||
|
||||
bool replace_game_matchmaking = 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{};
|
||||
|
||||
struct session_protection
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "common.hpp"
|
||||
#include "script.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
#include <script/tlsContext.hpp>
|
||||
|
||||
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()
|
||||
{
|
||||
std::unique_lock lock(m_mutex);
|
||||
|
@ -10,6 +10,7 @@ namespace big
|
||||
~fiber_pool();
|
||||
|
||||
void queue_job(std::function<void()> func);
|
||||
void execute_on_game_thread(std::function<void()> func);
|
||||
|
||||
void fiber_tick();
|
||||
static void fiber_func();
|
||||
|
@ -16,6 +16,7 @@ enum class PedBones : uint16_t;
|
||||
class CNetComplaintMgr;
|
||||
class Network;
|
||||
class CNetworkObjectMgr;
|
||||
class CHeadBlendData;
|
||||
|
||||
namespace rage
|
||||
{
|
||||
@ -44,6 +45,7 @@ namespace rage
|
||||
class fiPackfile;
|
||||
class scrNativeRegistrationTable;
|
||||
class rlSessionByGamerTaskResult;
|
||||
class SecurityPeer;
|
||||
struct rlScTaskStatus
|
||||
{
|
||||
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 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);
|
||||
|
||||
@ -215,4 +217,8 @@ namespace big::functions
|
||||
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_peer_by_security_id = rage::SecurityPeer*(*)(int id);
|
||||
|
||||
using set_head_blend_data = void(*)(CPed* ped, CHeadBlendData* data);
|
||||
}
|
||||
|
@ -104,7 +104,7 @@ namespace rage
|
||||
|
||||
virtual void _0x80() = 0; //
|
||||
|
||||
virtual void _0x88() = 0; //
|
||||
virtual void _0x88(int) = 0; //
|
||||
|
||||
virtual void* get_identifier() = 0; // 0x90
|
||||
|
||||
@ -130,7 +130,7 @@ namespace rage
|
||||
|
||||
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
|
||||
|
||||
|
@ -73,7 +73,7 @@ namespace rage
|
||||
{
|
||||
return m_bitsRead;
|
||||
}
|
||||
bool Seek(uint32_t bits)
|
||||
void Seek(uint32_t bits)
|
||||
{
|
||||
if (bits >= 0)
|
||||
{
|
||||
@ -81,7 +81,12 @@ namespace rage
|
||||
if (bits <= length)
|
||||
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)
|
||||
{
|
||||
@ -244,10 +249,11 @@ namespace rage
|
||||
template<typename T>
|
||||
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;
|
||||
ReadDword(&val, length);
|
||||
uint64_t val = 0;
|
||||
ReadQWord(&val, length);
|
||||
|
||||
return T(val);
|
||||
}
|
||||
@ -256,6 +262,7 @@ namespace rage
|
||||
inline T ReadSigned(int length)
|
||||
{
|
||||
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;
|
||||
ReadInt32(&val, length);
|
||||
|
@ -108,8 +108,8 @@ namespace rage
|
||||
|
||||
virtual void PackCloneCreate(netObject* object, CNetGamePlayer* player, datBitBuffer* buffer) = 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 _0x88() = 0;
|
||||
virtual const char* _0x90(int) = 0;
|
||||
|
@ -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)
|
||||
return m_local_participant_index;
|
||||
|
||||
if (m_num_participants <= 1)
|
||||
if (m_max_participants <= 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)
|
||||
return m_participants[i]->m_participant_index;
|
||||
|
@ -4,264 +4,7 @@
|
||||
#include "script/scriptIdBase.hpp"
|
||||
#include "script/scriptResource.hpp"
|
||||
#include "script/scriptHandler.hpp"
|
||||
#include "script/scriptHandlerMgr.hpp"
|
||||
#include "script/scriptHandlerNetComponent.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#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)
|
||||
#include "script/CGameScriptHandler.hpp"
|
||||
#include "script/CGameScriptHandlerNetComponent.hpp"
|
@ -20,6 +20,7 @@ class CWeaponInfoManager;
|
||||
class CGameScriptHandlerMgr;
|
||||
class CPedFactory;
|
||||
class GtaThread;
|
||||
class GameDataHash;
|
||||
|
||||
namespace rage
|
||||
{
|
||||
@ -195,6 +196,7 @@ namespace big
|
||||
|
||||
functions::generate_uuid m_generate_uuid;
|
||||
uint64_t* m_host_token;
|
||||
uint64_t* m_peer_id;
|
||||
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
|
||||
CCommunications** m_communications;
|
||||
@ -377,6 +379,23 @@ namespace big
|
||||
PVOID m_send_session_detail_msg;
|
||||
|
||||
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)
|
||||
static_assert(sizeof(gta_pointers) % 8 == 0, "Pointers are not properly aligned");
|
||||
|
@ -7,6 +7,11 @@
|
||||
#include <ped/CPedFactory.hpp>
|
||||
#include <script/scrProgramTable.hpp>
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class netObjectIds;
|
||||
}
|
||||
|
||||
namespace big::gta_util
|
||||
{
|
||||
inline CPed* get_local_ped()
|
||||
@ -54,6 +59,14 @@ namespace big::gta_util
|
||||
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>
|
||||
void execute_as_script(rage::scrThread* thread, F&& callback, Args&&... args)
|
||||
{
|
||||
|
@ -2,11 +2,15 @@
|
||||
|
||||
#include "pointers.hpp"
|
||||
|
||||
#include <player/CNonPhysicalPlayerData.hpp>
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
hooking::hooking() :
|
||||
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_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::unadvertise_session>("US", g_pointers->m_gta.m_unadvertise_session);
|
||||
detour_hook_helper::add<hooks::send_session_detail_msg>("SSDM", g_pointers->m_gta.m_send_session_detail_msg);
|
||||
|
||||
|
||||
detour_hook_helper::add<hooks::write_node_data>("WND", g_pointers->m_gta.m_write_node_data);
|
||||
detour_hook_helper::add<hooks::can_send_node_to_player>("CSNTP", g_pointers->m_gta.m_can_send_node_to_player);
|
||||
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;
|
||||
}
|
||||
|
||||
@ -162,6 +172,7 @@ namespace big
|
||||
{
|
||||
m_swapchain_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)));
|
||||
|
||||
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));
|
||||
m_error_packet_memmove_hook.disable();
|
||||
m_sync_data_reader_hook.disable();
|
||||
m_swapchain_hook.disable();
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "detour_hook.hpp"
|
||||
#include "vmt_hook.hpp"
|
||||
#include "vtable_hook.hpp"
|
||||
#include "call_hook.hpp"
|
||||
|
||||
#include <gta/enums.hpp>
|
||||
#include <network/netConnection.hpp> // cannot stub this
|
||||
@ -40,6 +41,8 @@ class CNetworkPlayerMgr;
|
||||
class CNetworkObjectMgr;
|
||||
class CPhysicalScriptGameStateDataNode;
|
||||
class MatchmakingId;
|
||||
class CMsgJoinRequest;
|
||||
class GenericPool;
|
||||
|
||||
enum class eAckCode : uint32_t;
|
||||
|
||||
@ -60,6 +63,7 @@ namespace rage
|
||||
class netGameEvent;
|
||||
class netSyncDataNode;
|
||||
class rlSessionDetailMsg;
|
||||
class netEvent;
|
||||
}
|
||||
|
||||
namespace big
|
||||
@ -94,7 +98,7 @@ namespace big
|
||||
static bool increment_stat_event(CNetworkIncrementStatEvent* net_event_struct, CNetGamePlayer* sender);
|
||||
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 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 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);
|
||||
|
||||
@ -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 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 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
|
||||
@ -290,6 +301,8 @@ namespace big
|
||||
vmt_hook m_swapchain_hook;
|
||||
vtable_hook m_sync_data_reader_hook;
|
||||
|
||||
call_hook m_error_packet_memmove_hook;
|
||||
|
||||
WNDPROC m_og_wndproc = nullptr;
|
||||
|
||||
static inline std::vector<detour_hook_helper> m_detour_hook_helpers;
|
||||
|
@ -5,51 +5,53 @@
|
||||
namespace big
|
||||
{
|
||||
const auto warn_bad_metrics = std::unordered_set<std::string_view>({
|
||||
"REPORTER",
|
||||
"REPORT_INVALIDMODEL",
|
||||
"MEM_NEW",
|
||||
"DEBUGGER_ATTACH",
|
||||
"XP_LOSS",
|
||||
"CF",
|
||||
"CC",
|
||||
"CNR",
|
||||
"SCRIPT",
|
||||
"CHEAT",
|
||||
"AUX_DEUX",
|
||||
"HARDWARE_OS",
|
||||
"HARDWARE_GPU",
|
||||
"HARDWARE_MOBO",
|
||||
"HARDWARE_MEM",
|
||||
"HARDWARE_CPU",
|
||||
"PCSETTINGS",
|
||||
"CASH_CREATED",
|
||||
"DR_PS",
|
||||
"IDLEKICK",
|
||||
"GSCB",
|
||||
"GSINV",
|
||||
"GSCW",
|
||||
"GSINT",
|
||||
"GARAGE_TAMPER",
|
||||
"DUPE_DETECT",
|
||||
"LAST_VEH",
|
||||
"FAIL_SERV",
|
||||
"CCF_UPDATE",
|
||||
"CODE_CRC",
|
||||
"MM",
|
||||
"RDEV",
|
||||
"RQA",
|
||||
});
|
||||
"REPORTER",
|
||||
"REPORT_INVALIDMODEL",
|
||||
"MEM_NEW",
|
||||
"DEBUGGER_ATTACH",
|
||||
"XP_LOSS",
|
||||
"CF",
|
||||
"CC",
|
||||
"CNR",
|
||||
"SCRIPT",
|
||||
"CHEAT",
|
||||
"AUX_DEUX",
|
||||
"HARDWARE_OS",
|
||||
"HARDWARE_GPU",
|
||||
"HARDWARE_MOBO",
|
||||
"HARDWARE_MEM",
|
||||
"HARDWARE_CPU",
|
||||
"PCSETTINGS",
|
||||
"CASH_CREATED",
|
||||
"DR_PS",
|
||||
"IDLEKICK",
|
||||
"GSCB",
|
||||
"GSINV",
|
||||
"GSCW",
|
||||
"GSINT",
|
||||
"GARAGE_TAMPER",
|
||||
"DUPE_DETECT",
|
||||
"LAST_VEH",
|
||||
"FAIL_SERV",
|
||||
"CCF_UPDATE",
|
||||
"CODE_CRC",
|
||||
"MM",
|
||||
"RDEV",
|
||||
"RQA",
|
||||
});
|
||||
const auto filtered_bad_metrics = std::unordered_set<std::string_view>({
|
||||
"DIG",
|
||||
"AWARD_XP",
|
||||
"WEATHER",
|
||||
"UVC",
|
||||
"W_L",
|
||||
"ESVCS",
|
||||
"EARN",
|
||||
"COLLECTIBLE",
|
||||
"FIRST_VEH",
|
||||
"RANK_UP",
|
||||
"DIG",
|
||||
"AWARD_XP",
|
||||
"WEATHER",
|
||||
"UVC",
|
||||
"W_L",
|
||||
"ESVCS",
|
||||
"EARN",
|
||||
"COLLECTIBLE",
|
||||
"FIRST_VEH",
|
||||
"RANK_UP",
|
||||
"COMMS_TEXT",
|
||||
"BLAST",
|
||||
});
|
||||
|
||||
std::string hex_encode(std::string_view input) {
|
||||
@ -103,9 +105,9 @@ namespace big
|
||||
if (g.notifications.warn_metric && is_warn_bad_metrics)
|
||||
{
|
||||
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);
|
||||
char module_name[MAX_PATH];
|
||||
@ -117,13 +119,16 @@ namespace big
|
||||
strncpy(reinterpret_cast<char*>(metric) + 0x18, result.c_str(), 0x900);
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "services/matchmaking/matchmaking_service.hpp"
|
||||
#include <network/snSession.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -8,6 +9,9 @@ namespace big
|
||||
if (g_matchmaking_service) [[likely]]
|
||||
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);
|
||||
}
|
||||
}
|
@ -18,10 +18,7 @@ namespace big
|
||||
g_fiber_pool->queue_job([max_sessions, results, num_sessions_found, status, discriminator] {
|
||||
bool result = false;
|
||||
|
||||
if (g.session.join_in_sctv_slots)
|
||||
result = g_matchmaking_service->matchmake();
|
||||
else
|
||||
result = g_matchmaking_service->matchmake(discriminator);
|
||||
result = g_matchmaking_service->matchmake(discriminator, !g.session.join_in_sctv_slots);
|
||||
|
||||
if (result)
|
||||
{
|
||||
|
22
src/hooks/misc/add_gamer_to_session.cpp
Normal file
22
src/hooks/misc/add_gamer_to_session.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include <network/CNetGamePlayerDataMsg.hpp>
|
||||
#include <network/Network.hpp>
|
||||
#include <network/RemoteGamerInfoMsg.hpp>
|
||||
#include <network/CMsgJoinRequest.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -17,12 +18,13 @@ namespace big
|
||||
info->m_gamer_info.m_nat_type = 0;
|
||||
|
||||
info->m_num_handles = 0;
|
||||
|
||||
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)
|
||||
data.m_matchmaking_group = 4;
|
||||
|
@ -15,12 +15,12 @@
|
||||
|
||||
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 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)
|
||||
@ -117,12 +117,12 @@ namespace big
|
||||
if (plyr->block_join && *g_pointers->m_gta.m_is_session_started)
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@ -131,6 +131,11 @@ namespace big
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -1135,6 +1135,8 @@ namespace big
|
||||
return g.m_syncing_object_type != eNetObjType::NET_OBJ_TYPE_SUBMARINE;
|
||||
case eTaskTypeIndex::CTaskVehicleFleeAirborne:
|
||||
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;
|
||||
@ -1261,7 +1263,8 @@ namespace big
|
||||
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 =
|
||||
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)
|
||||
{
|
||||
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");
|
||||
return true;
|
||||
}
|
||||
|
18
src/hooks/protections/create_pool_item.cpp
Normal file
18
src/hooks/protections/create_pool_item.cpp
Normal 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;
|
||||
}
|
||||
}
|
19
src/hooks/protections/error_packet_memmove.cpp
Normal file
19
src/hooks/protections/error_packet_memmove.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -12,9 +12,12 @@
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/chat.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "gta/net_object_mgr.hpp"
|
||||
|
||||
#include <network/Network.hpp>
|
||||
#include <network/netTime.hpp>
|
||||
#include <network/P2pSecurity.hpp>
|
||||
#include <network/netObjectIds.hpp>
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint32_t pos;
|
||||
@ -66,30 +75,244 @@ namespace big
|
||||
|
||||
if (buffer.Read<bool>(1))
|
||||
id.m_position_hash = buffer.Read<uint32_t>(32);
|
||||
else
|
||||
id.m_position_hash = 0;
|
||||
|
||||
if (buffer.Read<bool>(1))
|
||||
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)
|
||||
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
||||
buffer.Write<uint32_t>(id.m_hash, 32);
|
||||
buffer.Write<uint32_t>(id.m_timestamp, 32);
|
||||
|
||||
if (frame->m_data == nullptr || frame->m_length == 0)
|
||||
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
||||
if (id.m_position_hash != 0)
|
||||
{
|
||||
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;
|
||||
|
||||
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;
|
||||
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++)
|
||||
{
|
||||
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(
|
||||
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))
|
||||
return g_hooking->get_original<hooks::receive_net_message>()(netConnectionManager, a2, frame);
|
||||
int sec_id = 0;
|
||||
|
||||
|
||||
if (msgType == rage::eNetMessage::MsgRoamingJoinBubbleAck)
|
||||
return true;
|
||||
|
||||
if (player)
|
||||
if (frame)
|
||||
sec_id = frame->m_security_id;
|
||||
else
|
||||
{
|
||||
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:
|
||||
case rage::eNetMessage::MsgTextMessage2:
|
||||
{
|
||||
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;
|
||||
LOGF(stream::net_messages, WARNING, "Denying script request from {} (hash={:X}, instance={})", player->get_name(), script.m_hash, script.m_instance_id);
|
||||
return true;
|
||||
}
|
||||
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())
|
||||
{
|
||||
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;
|
||||
LOGF(stream::net_messages, WARNING, "{} sent MsgKickPlayer, but they are not the host", peer->m_info.name);
|
||||
return true;
|
||||
}
|
||||
case rage::eNetMessage::MsgScriptHostRequest:
|
||||
|
||||
if (reason == KickReason::VOTED_OUT)
|
||||
{
|
||||
CGameScriptId script;
|
||||
script_id_deserialize(script, buffer);
|
||||
|
||||
if (script.m_hash == "freemode"_J && g.session.force_script_host)
|
||||
return true;
|
||||
|
||||
break;
|
||||
g_notification_service.push_warning("PROTECTIONS"_T.data(), "YOU_HAVE_BEEN_KICKED"_T.data());
|
||||
return true;
|
||||
}
|
||||
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)
|
||||
{
|
||||
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::MsgKickPlayer:
|
||||
{
|
||||
KickReason reason = buffer.Read<KickReason>(3);
|
||||
LOGF(stream::net_messages, VERBOSE, "{} sent us a MsgKickPlayer, reason = {}", peer->m_info.name, (int)reason);
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgRadioStationSyncRequest:
|
||||
{
|
||||
if (player && player->block_radio_requests)
|
||||
return true;
|
||||
|
||||
if (!player->is_host())
|
||||
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)
|
||||
{
|
||||
if (player->block_radio_requests)
|
||||
return true;
|
||||
@ -225,100 +404,357 @@ namespace big
|
||||
if (player->m_radio_request_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)));
|
||||
g_notification_service.push_error("PROTECTIONS"_T.data(),
|
||||
std::vformat("OOM_KICK"_T, std::make_format_args(player->get_name())));
|
||||
player->block_radio_requests = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgRoamingInitialBubble:
|
||||
else
|
||||
{
|
||||
LOG(WARNING) << "Shouldn't get this again";
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (msgType)
|
||||
{
|
||||
case rage::eNetMessage::MsgScriptMigrateHost: return true;
|
||||
case rage::eNetMessage::MsgRadioStationSyncRequest:
|
||||
{
|
||||
static rate_limiter unk_player_radio_requests{1s, 6};
|
||||
static rate_limiter unk_player_radio_requests{1s, 5};
|
||||
|
||||
if (unk_player_radio_requests.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(), "OOM_KICK_UNK"_T.data());
|
||||
g_notification_service.push_error("PROTECTIONS"_T.data(), std::vformat("OOM_KICK"_T.data(), std::make_format_args(peer->m_info.name)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgTextMessage: return true;
|
||||
case rage::eNetMessage::MsgNonPhysicalData:
|
||||
|
||||
if (!session || !session->is_host())
|
||||
{
|
||||
buffer.Read<int>(7); // size
|
||||
int bubble = buffer.Read<int>(4);
|
||||
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;
|
||||
}
|
||||
LOGF(stream::net_messages, WARNING, "{} sent MsgRadioStationSyncRequest, but we are not the host", peer->m_info.name);
|
||||
return true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (g.debug.logs.packet_logs) [[unlikely]]
|
||||
case rage::eNetMessage::MsgRadioStationSync:
|
||||
{
|
||||
if (g.debug.logs.packet_logs == 1 || //ALL
|
||||
(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
|
||||
if (!session || !is_host_of_session(session, event->m_peer_id))
|
||||
{
|
||||
const char* packet_type = "<UNKNOWN>";
|
||||
for (const auto& p : packet_types)
|
||||
LOGF(stream::net_messages, WARNING, "{} sent MsgRadioStationSync, but is not the host", peer->m_info.name);
|
||||
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)
|
||||
{
|
||||
packet_type = p.first;
|
||||
break;
|
||||
}
|
||||
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());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
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);
|
||||
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);
|
||||
|
||||
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") << "] "
|
||||
<< "RECEIVED PACKET | Type: " << packet_type << " | Length: " << frame->m_length << " | Sender: "
|
||||
<< (player ? player->get_name() :
|
||||
std::format("<M:{}>, <C:{:X}>, <P:{}>",
|
||||
(int)frame->m_msg_id,
|
||||
frame->m_connection_identifier,
|
||||
frame->m_peer_id)
|
||||
.c_str())
|
||||
<< " | " << HEX_TO_UPPER((int)msgType) << std::endl;
|
||||
log.flush();
|
||||
if (msgType == rage::eNetMessage::MsgTextMessage && player->get_net_data())
|
||||
{
|
||||
g_pointers->m_gta.m_handle_chat_message(*g_pointers->m_gta.m_chat_data, nullptr, &peer->m_info.handle, message, is_team);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "gta/pools.hpp"
|
||||
#include "gta_util.hpp"
|
||||
|
||||
#include <network/netObjectIds.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -13,6 +16,38 @@ namespace big
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
if (plyr && plyr->block_clone_create) [[unlikely]]
|
||||
|
@ -12,6 +12,30 @@ namespace big
|
||||
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);
|
||||
}
|
||||
}
|
@ -18,6 +18,28 @@ namespace big
|
||||
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);
|
||||
|
||||
if (plyr && plyr->block_clone_sync) [[unlikely]]
|
||||
|
@ -104,6 +104,7 @@ namespace big
|
||||
if (!is_valid_weapon(weaponType))
|
||||
{
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
@ -258,8 +259,8 @@ namespace big
|
||||
void scan_explosion_event(CNetGamePlayer* player, rage::datBitBuffer* buffer)
|
||||
{
|
||||
uint16_t f186;
|
||||
uint16_t f208;
|
||||
int ownerNetId;
|
||||
uint16_t targetEntity;
|
||||
uint16_t ownerNetId;
|
||||
uint16_t f214;
|
||||
eExplosionTag explosionType;
|
||||
float damageScale;
|
||||
@ -276,10 +277,10 @@ namespace big
|
||||
bool f189;
|
||||
bool isInvisible;
|
||||
bool f126;
|
||||
bool f241;
|
||||
bool f243;
|
||||
bool addOwnedExplosion;
|
||||
|
||||
uint16_t f210;
|
||||
bool hasTargetEnt2;
|
||||
uint16_t targetEnt2;
|
||||
|
||||
float unkX;
|
||||
float unkY;
|
||||
@ -301,7 +302,7 @@ namespace big
|
||||
// clang-format off
|
||||
|
||||
f186 = buffer->Read<uint16_t>(16);
|
||||
f208 = buffer->Read<uint16_t>(13);
|
||||
targetEntity = buffer->Read<uint16_t>(13);
|
||||
ownerNetId = buffer->Read<uint16_t>(13);
|
||||
f214 = buffer->Read<uint16_t>(13); // 1604+
|
||||
explosionType = (eExplosionTag)buffer->ReadSigned<int>(8);// 1604+ bit size
|
||||
@ -311,7 +312,7 @@ namespace big
|
||||
posY = buffer->ReadSignedFloat(22, 27648.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);
|
||||
cameraShake = buffer->Read<int>(8) / 127.0f;
|
||||
|
||||
@ -319,10 +320,11 @@ namespace big
|
||||
f189 = buffer->Read<uint8_t>(1);
|
||||
isInvisible = buffer->Read<uint8_t>(1);
|
||||
f126 = buffer->Read<uint8_t>(1);
|
||||
f241 = buffer->Read<uint8_t>(1);
|
||||
f243 = buffer->Read<uint8_t>(1);// 1604+
|
||||
addOwnedExplosion = buffer->Read<uint8_t>(1);
|
||||
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);
|
||||
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 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
|
||||
&& 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(),
|
||||
std::vformat("BLAMED_FOR_EXPLOSION"_T,
|
||||
std::make_format_args(p_name, m_name)));
|
||||
// too many false positives, disabling it
|
||||
//session::add_infraction(g_player_service->get_by_id(player->m_player_id), Infraction::BLAME_EXPLOSION_DETECTED);
|
||||
std::make_format_args(player->get_name(),
|
||||
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);
|
||||
LOGF(stream::net_events, WARNING, "{} sent an EXPLOSION_EVENT with addOwnedExplosion enabled and with the wrong owner", player->get_name());
|
||||
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_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))
|
||||
return true;
|
||||
static const std::unordered_set<uint32_t> blocked_script_hashes = {"main_persistent"_J, "shop_controller"_J};
|
||||
|
||||
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:
|
||||
{
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
@ -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);
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -564,7 +606,6 @@ namespace big
|
||||
buffer->ReadDword(&scripted_game_event->m_args_size, 32);
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -628,8 +669,12 @@ namespace big
|
||||
// player sending this event is a modder
|
||||
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);
|
||||
g.reactions.game_anti_cheat_modder_detection.process(plyr);
|
||||
buffer->Seek(0);
|
||||
break;
|
||||
}
|
||||
case eNetworkEvents::REQUEST_CONTROL_EVENT:
|
||||
@ -671,20 +716,21 @@ namespace big
|
||||
|
||||
if (type == WorldStateDataType::Rope)
|
||||
{
|
||||
buffer->Read<int>(9); // network rope id
|
||||
buffer->Read<float>(19); // pos x
|
||||
buffer->Read<float>(19); // pos y
|
||||
buffer->Read<float>(19); // pos z
|
||||
buffer->Read<float>(19); // rot x
|
||||
buffer->Read<float>(19); // rot y
|
||||
buffer->Read<float>(19); // rot z
|
||||
buffer->Read<float>(16); // length
|
||||
buffer->Read<int>(9); // network rope id
|
||||
buffer->ReadSigned<int>(19); // pos x
|
||||
buffer->ReadSigned<int>(19); // pos y
|
||||
buffer->Read<int>(19); // pos z
|
||||
buffer->ReadSigned<int>(19); // rot x
|
||||
buffer->ReadSigned<int>(19); // rot y
|
||||
buffer->Read<int>(19); // rot z
|
||||
float max_length = buffer->ReadSignedFloat(16, 100.0f);
|
||||
int type = buffer->Read<int>(4);
|
||||
float initial_length = buffer->Read<float>(16);
|
||||
float min_length = buffer->Read<float>(16);
|
||||
float initial_length = buffer->ReadSignedFloat(16, 100.0f);
|
||||
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");
|
||||
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
@ -699,6 +745,7 @@ namespace big
|
||||
if (pop_group == 0 && (percentage == 0 || percentage == 103))
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -711,6 +758,7 @@ namespace big
|
||||
}
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -725,6 +773,7 @@ namespace big
|
||||
|
||||
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");
|
||||
g_pointers->m_gta.m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
@ -811,7 +860,6 @@ namespace big
|
||||
if (plyr && scan_play_sound_event(plyr, *buffer))
|
||||
{
|
||||
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);
|
||||
return;
|
||||
}
|
||||
@ -833,6 +881,7 @@ namespace big
|
||||
{
|
||||
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;
|
||||
}
|
||||
break;
|
||||
|
@ -21,7 +21,7 @@ namespace big
|
||||
m_program(program)
|
||||
{
|
||||
m_orig_bytecode = program->m_code_blocks;
|
||||
|
||||
|
||||
if (auto bytecode = g_script_patcher_service->get_script_bytecode(program->m_name_hash))
|
||||
program->m_code_blocks = bytecode;
|
||||
|
||||
|
12
src/hooks/spoofing/get_dlc_hash.cpp
Normal file
12
src/hooks/spoofing/get_dlc_hash.cpp
Normal 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);
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
#include <netsync/nodes/ped/CPedTaskTreeDataNode.hpp>
|
||||
#include <netsync/nodes/physical/CPhysicalScriptGameStateDataNode.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/player/CPlayerAppearanceDataNode.hpp>
|
||||
#include <netsync/nodes/player/CPlayerCameraDataNode.hpp>
|
||||
|
@ -132,11 +132,16 @@ namespace big
|
||||
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
|
||||
const auto& location = msg->Location();
|
||||
const auto level = msg->Level();
|
||||
const auto stream = msg->Stream();
|
||||
|
||||
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 << ":"
|
||||
<< location.line() << "] " << RESET_STREAM_COLOR << msg->Message() << std::flush;
|
||||
if (stream)
|
||||
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)
|
||||
@ -151,11 +156,16 @@ namespace big
|
||||
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
|
||||
const auto& location = msg->Location();
|
||||
const auto level = msg->Level();
|
||||
const auto stream = msg->Stream();
|
||||
|
||||
const auto file = std::filesystem::path(location.file_name()).filename().string();
|
||||
|
||||
m_console_out << "[" << timestamp << "]"
|
||||
<< "[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
|
||||
if (stream)
|
||||
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)
|
||||
@ -166,10 +176,15 @@ namespace big
|
||||
const auto timestamp = std::format("{0:%H:%M:%S}", msg->Timestamp());
|
||||
const auto& location = msg->Location();
|
||||
const auto level = msg->Level();
|
||||
const auto stream = msg->Stream();
|
||||
|
||||
const auto file = std::filesystem::path(location.file_name()).filename().string();
|
||||
|
||||
m_file_out << "[" << timestamp << "]"
|
||||
<< "[" << get_level_string(level) << "/" << file << ":" << location.line() << "] " << msg->Message() << std::flush;
|
||||
if (stream)
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -1,9 +1,15 @@
|
||||
#pragma once
|
||||
#include "file_manager.hpp"
|
||||
|
||||
#include <AsyncLogger/Logger.hpp>
|
||||
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
|
||||
{
|
||||
#define ADD_COLOR_TO_STREAM(color) "\x1b[" << int(color) << "m"
|
||||
|
@ -71,16 +71,6 @@ namespace big
|
||||
}
|
||||
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)
|
||||
{
|
||||
scr_functions::set_freemode_session_active({});
|
||||
|
@ -11,7 +11,7 @@ namespace big
|
||||
{
|
||||
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;
|
||||
src->set_return_value<BOOL>(TRUE);
|
||||
}
|
||||
|
@ -653,6 +653,15 @@ namespace big
|
||||
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
|
||||
{
|
||||
"PGI",
|
||||
@ -1803,6 +1812,79 @@ namespace big
|
||||
{
|
||||
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
|
||||
|
||||
|
@ -163,6 +163,7 @@ namespace big
|
||||
}},
|
||||
{"ANIMATION",
|
||||
[this] {
|
||||
// TODO: maybe inform the user of this behavior
|
||||
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);
|
||||
else
|
||||
|
@ -38,6 +38,7 @@ namespace big
|
||||
XML_MAPS,
|
||||
|
||||
NETWORK,
|
||||
CHAT,
|
||||
MISSIONS,
|
||||
SPOOFING,
|
||||
PLAYER_DATABASE,
|
||||
@ -139,8 +140,9 @@ namespace big
|
||||
TAB_DECL(NETWORK),
|
||||
view::network,
|
||||
{
|
||||
{TAB_DECL(SPOOFING), view::spoofing}},
|
||||
{TAB_DECL(CHAT), view::chat}},
|
||||
{TAB_DECL(MISSIONS), view::missions}},
|
||||
{TAB_DECL(SPOOFING), view::spoofing}},
|
||||
{TAB_DECL(PLAYER_DATABASE), view::player_database}},
|
||||
{TAB_DECL(SESSION_BROWSER), view::session_browser}},
|
||||
{TAB_DECL(STAT_EDITOR), view::stat_editor}},
|
||||
|
@ -7,6 +7,8 @@
|
||||
#include "renderer/renderer.hpp"
|
||||
#include "util/teleport.hpp"
|
||||
|
||||
#include <script/GtaThread.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
hotkey_service::hotkey_service()
|
||||
|
@ -43,7 +43,7 @@ namespace big
|
||||
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)
|
||||
{
|
||||
@ -69,6 +69,7 @@ namespace big
|
||||
static rage::rlSessionInfo result_sessions[MAX_SESSIONS_TO_FIND];
|
||||
|
||||
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))
|
||||
{
|
||||
@ -77,11 +78,26 @@ namespace big
|
||||
|
||||
if (state.status == 3)
|
||||
{
|
||||
std::unordered_map<std::uint64_t, session*> stok_map = {};
|
||||
|
||||
for (int i = 0; i < m_num_sessions_found; 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;
|
||||
|
||||
if (g.session_browser.language_filter_enabled
|
||||
@ -99,6 +115,8 @@ namespace big
|
||||
&& ((m_found_sessions[i].attributes.discriminator & (1 << 14)) == (1 << 14))
|
||||
!= (bool)g.session_browser.pool_filter)
|
||||
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)
|
||||
|
@ -24,6 +24,7 @@ namespace big
|
||||
int player_count;
|
||||
int region;
|
||||
int language;
|
||||
int multiplex_count = 1;
|
||||
};
|
||||
|
||||
struct session
|
||||
@ -35,6 +36,7 @@ namespace big
|
||||
|
||||
private:
|
||||
int m_num_sessions_found = 0;
|
||||
int m_num_valid_sessions = 0;
|
||||
bool m_active = false;
|
||||
session m_found_sessions[MAX_SESSIONS_TO_FIND];
|
||||
std::unordered_map<std::uint32_t, std::vector<MatchmakingId>> m_multiplexed_sessions;
|
||||
@ -44,7 +46,7 @@ namespace big
|
||||
public:
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
inline int get_num_valid_sessions()
|
||||
{
|
||||
return m_num_valid_sessions;
|
||||
}
|
||||
|
||||
inline session* get_found_sessions()
|
||||
{
|
||||
return m_found_sessions;
|
||||
|
@ -24,6 +24,7 @@ namespace big
|
||||
{Infraction::UNDEAD_OTR, "Had used undead OTR"},
|
||||
{Infraction::CUSTOM_REASON, ""},
|
||||
{Infraction::CHAT_SPAM, "Chat spammer"},
|
||||
{Infraction::SENT_MODDER_BEACONS, "Sent modder beacons"},
|
||||
};
|
||||
|
||||
const char* persistent_player::get_infraction_description(int infraction)
|
||||
|
@ -73,10 +73,8 @@ namespace big
|
||||
rate_limiter m_radio_station_change_rate_limit{1s, 3};
|
||||
|
||||
bool block_radio_requests = false;
|
||||
|
||||
int m_num_spawned_permanent_vehicles = 0;
|
||||
|
||||
bool m_block_permanent_vehicles = false;
|
||||
bool received_object_id_request = false;
|
||||
bool received_object_id_response = false;
|
||||
|
||||
bool is_modder = false;
|
||||
bool is_trusted = false;
|
||||
@ -104,6 +102,7 @@ namespace big
|
||||
|
||||
int spectating_player = -1;
|
||||
|
||||
menu_settings::script_block_opts script_block_opts{};
|
||||
protected:
|
||||
bool equals(const CNetGamePlayer* net_game_player) const;
|
||||
|
||||
|
@ -29,6 +29,7 @@ namespace big
|
||||
|
||||
void player_service::do_cleanup()
|
||||
{
|
||||
m_players_sending_modder_beacons.clear();
|
||||
m_selected_player = m_dummy;
|
||||
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)
|
||||
{
|
||||
m_selected_player = plyr;
|
||||
|
@ -20,6 +20,8 @@ namespace big
|
||||
player_ptr m_dummy = std::make_shared<player>(nullptr);
|
||||
player_ptr m_selected_player;
|
||||
|
||||
std::unordered_set<std::uint64_t> m_players_sending_modder_beacons;
|
||||
|
||||
public:
|
||||
player_service();
|
||||
~player_service();
|
||||
@ -40,6 +42,8 @@ namespace big
|
||||
|
||||
void player_join(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()
|
||||
{
|
||||
|
@ -178,8 +178,6 @@ namespace big
|
||||
if (!m_thread->m_stack || !m_thread->m_net_component)
|
||||
return false;
|
||||
}
|
||||
|
||||
((CGameScriptHandlerNetComponent*)m_thread->m_net_component)->block_host_migration(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -308,6 +308,14 @@ namespace big
|
||||
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))
|
||||
{
|
||||
m_local_index.selected_language = preferred_lang;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "pointers.hpp"
|
||||
#include "util/misc.hpp"
|
||||
#include "util/vehicle.hpp"
|
||||
#include "util/pools.hpp"
|
||||
#include "util/world_model.hpp"
|
||||
#include "vehicle/CVehicle.hpp"
|
||||
|
||||
|
@ -1,4 +1,29 @@
|
||||
#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
|
||||
{
|
||||
@ -350,4 +375,58 @@ namespace big::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);
|
||||
}
|
||||
}
|
||||
|
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
#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 <script/types.hpp>
|
||||
#include <rage/vector.hpp>
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class netObject;
|
||||
class CEntity;
|
||||
}
|
||||
|
||||
namespace big::entity
|
||||
{
|
||||
@ -21,4 +22,6 @@ namespace big::entity
|
||||
bool request_model(rage::joaat_t hash);
|
||||
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);
|
||||
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);
|
||||
}
|
||||
|
@ -7,15 +7,18 @@ namespace big
|
||||
{
|
||||
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_set_script_flag;
|
||||
|
||||
inline static void 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_set_script_flag->apply();
|
||||
}
|
||||
|
||||
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_blame_others->restore();
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "outfit.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "script.hpp"
|
||||
|
||||
namespace big::ped
|
||||
{
|
||||
@ -477,15 +478,37 @@ namespace big::ped
|
||||
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)
|
||||
{
|
||||
const int max_health = ENTITY::GET_ENTITY_MAX_HEALTH(self::ped);
|
||||
const int current_health = ENTITY::GET_ENTITY_HEALTH(self::ped);
|
||||
const int current_armor = PED::GET_PED_ARMOUR(self::ped);
|
||||
|
||||
PLAYER::SET_PLAYER_MODEL(self::id, ENTITY::GET_ENTITY_MODEL(target));
|
||||
script::get_current()->yield();
|
||||
PED::CLONE_PED_TO_TARGET(target, self::ped);
|
||||
if (ENTITY::GET_ENTITY_MODEL(target) != ENTITY::GET_ENTITY_MODEL(self::id))
|
||||
{
|
||||
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_HEALTH(self::ped, current_health, 0, 0);
|
||||
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))
|
||||
{
|
||||
@ -515,7 +538,7 @@ namespace big::ped
|
||||
|
||||
if (clone)
|
||||
{
|
||||
PED::CLONE_PED_TO_TARGET(clone, ped);
|
||||
clone_ped(clone, ped);
|
||||
}
|
||||
|
||||
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "pointers.hpp"
|
||||
#include "script_global.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "pools.hpp"
|
||||
|
||||
namespace big::train
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#include "vehicle.hpp"
|
||||
#include "pools.hpp"
|
||||
|
||||
namespace big::vehicle
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "views/view.hpp"
|
||||
#include "script_mgr.hpp"
|
||||
#include "pointers.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -23,6 +24,7 @@ namespace big
|
||||
{(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::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))
|
||||
{
|
||||
// allow to unload in the main title screen.
|
||||
@ -45,6 +47,7 @@ namespace big
|
||||
g_running = false;
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
ImGui::End();
|
||||
|
@ -91,11 +91,6 @@ namespace big
|
||||
{
|
||||
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());
|
||||
script::get_current()->yield(10ms);
|
||||
if (selected_thread->m_stack && selected_thread->m_net_component)
|
||||
{
|
||||
net_handler->block_host_migration(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
92
src/views/network/view_chat.cpp
Normal file
92
src/views/network/view_chat.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,11 +1,9 @@
|
||||
#include "core/data/apartment_names.hpp"
|
||||
#include "core/data/command_access_levels.hpp"
|
||||
#include "core/data/region_codes.hpp"
|
||||
#include "core/data/warehouse_names.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "hooking/hooking.hpp"
|
||||
#include "util/chat.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "util/troll.hpp"
|
||||
@ -26,125 +24,104 @@ namespace big
|
||||
const char* name;
|
||||
};
|
||||
|
||||
struct target_language_type
|
||||
void render_join_game()
|
||||
{
|
||||
const char* type;
|
||||
const char* name;
|
||||
};
|
||||
ImGui::SeparatorText("JOIN_GAME"_T.data());
|
||||
|
||||
void render_rid_joiner()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("RID_JOINER"_T);
|
||||
if (ImGui::BeginListBox("##ridjoiner", get_listbox_dimensions()))
|
||||
static uint64_t rid = 0;
|
||||
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;
|
||||
static char username[20];
|
||||
static char base64[500]{};
|
||||
session::join_by_username(username);
|
||||
};
|
||||
|
||||
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);
|
||||
ImGui::SameLine();
|
||||
components::button("JOIN_BY_RID"_T, [] {
|
||||
session::join_by_rockstar_id(rid);
|
||||
});
|
||||
components::button("COPY_SESSION_INFO"_T, [] {
|
||||
char buf[0x100]{};
|
||||
g_pointers->m_gta.m_encode_session_info(>a_util::get_network()->m_last_joined_session.m_session_info, buf, 0xA9, nullptr);
|
||||
ImGui::SetClipboardText(buf);
|
||||
});
|
||||
|
||||
components::input_text_with_hint("##usernameinput", "INPUT_USERNAME"_T, username, sizeof(username));
|
||||
ImGui::SameLine();
|
||||
if (components::button("JOIN_BY_USERNAME"_T))
|
||||
{
|
||||
session::join_by_username(username);
|
||||
};
|
||||
ImGui::Checkbox("JOIN_IN_SCTV"_T.data(), &g.session.join_in_sctv_slots);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("JOIN_IN_SCTV_DESC"_T.data());
|
||||
|
||||
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());
|
||||
});
|
||||
|
||||
components::button("COPY_SESSION_INFO"_T, [] {
|
||||
char buf[0x100]{};
|
||||
g_pointers->m_gta.m_encode_session_info(>a_util::get_network()->m_last_joined_session.m_session_info, buf, 0xA9, nullptr);
|
||||
ImGui::SetClipboardText(buf);
|
||||
});
|
||||
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::EndListBox();
|
||||
ImGui::Checkbox("PLAYER_MAGNET"_T.data(), &g.session.player_magnet_enabled);
|
||||
if (g.session.player_magnet_enabled)
|
||||
{
|
||||
ImGui::Text("PLAYER_COUNT"_T.data());
|
||||
ImGui::InputInt("##playercount", &g.session.player_magnet_count);
|
||||
}
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void render_session_switcher()
|
||||
{
|
||||
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::SameLine();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("SESSION_SELECT"_T);
|
||||
if (ImGui::BeginListBox("###session_switch", get_listbox_dimensions()))
|
||||
std::string region_str = regions[*g_pointers->m_gta.m_region_code].name;
|
||||
|
||||
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, [®ion_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);
|
||||
components::selectable(region_type.name, *g_pointers->m_gta.m_region_code == region_type.id, [®ion_type] {
|
||||
*g_pointers->m_gta.m_region_code = region_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();
|
||||
@ -154,184 +131,331 @@ namespace big
|
||||
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);
|
||||
|
||||
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();
|
||||
components::small_text("FORCE_HOST"_T);
|
||||
|
||||
components::sub_title("DEBUG_TAB_MISC"_T);
|
||||
if (ImGui::BeginListBox("##miscsession", get_listbox_dimensions()))
|
||||
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"});
|
||||
|
||||
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);
|
||||
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)
|
||||
for (int i = 0; i < token_spoof_types.size(); i++)
|
||||
{
|
||||
ImGui::Text("PLAYER_COUNT"_T.data());
|
||||
ImGui::InputInt("##playercount", &g.session.player_magnet_count);
|
||||
if (ImGui::Selectable(g_translation_service.get_translation(token_spoof_types[i]).data(), i == g.session.spoof_host_token_type))
|
||||
{
|
||||
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">();
|
||||
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();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void render_chat()
|
||||
void render_player_options()
|
||||
{
|
||||
ImGui::SeparatorText("PLAYER_OPTIONS"_T.data());
|
||||
|
||||
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());
|
||||
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::SameLine();
|
||||
|
||||
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::BeginGroup();
|
||||
components::command_button<"ceokickall">({});
|
||||
components::command_button<"vehkickall">({});
|
||||
components::command_button<"deletevehall">({});
|
||||
components::command_button<"ragdollall">({}, "RAGDOLL_PLAYERS"_T);
|
||||
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);
|
||||
if (g.session.chat_commands)
|
||||
void render_teleport_options()
|
||||
{
|
||||
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::BeginCombo("##defualtchatcommands", COMMAND_ACCESS_LEVELS[g.session.chat_command_default_access_level]))
|
||||
if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
|
||||
{
|
||||
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;
|
||||
}
|
||||
g.session.send_to_apartment_idx = i;
|
||||
}
|
||||
|
||||
if (type == g.session.chat_command_default_access_level)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
if (i == g.session.send_to_apartment_idx)
|
||||
{
|
||||
ImGui::SetItemDefaultFocus();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
void render_session_globals()
|
||||
{
|
||||
// TODO: what are we doing with this?
|
||||
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::button("PLUS_1_MINUTE"_T, [] {
|
||||
@ -359,252 +483,37 @@ namespace big
|
||||
});
|
||||
if (ImGui::IsItemHovered())
|
||||
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();
|
||||
}
|
||||
|
||||
void view::network()
|
||||
{
|
||||
render_rid_joiner();
|
||||
ImGui::SameLine();
|
||||
render_session_switcher();
|
||||
|
||||
render_misc();
|
||||
ImGui::SameLine();
|
||||
render_chat();
|
||||
|
||||
render_join_game();
|
||||
render_general_options();
|
||||
render_session_globals();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
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();
|
||||
render_force_host_options();
|
||||
render_player_options();
|
||||
render_teleport_options();
|
||||
render_session_control();
|
||||
}
|
||||
}
|
||||
|
@ -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());
|
||||
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())
|
||||
&& !selected->game_mode_id.empty())
|
||||
{
|
||||
|
@ -34,13 +34,19 @@ namespace big
|
||||
if (!session.is_valid)
|
||||
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 player = g_player_database_service->get_player_by_rockstar_id(host_rid);
|
||||
|
||||
if (g.session_browser.exclude_modder_sessions && player && player->block_join)
|
||||
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;
|
||||
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,
|
||||
"REGION"_T, regions[session.attributes.region].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);
|
||||
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::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);
|
||||
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("EXCLUDE_MODDER_SESSIONS_DESC"_T.data());
|
||||
|
||||
@ -183,9 +192,7 @@ namespace big
|
||||
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())
|
||||
ImGui::SetTooltip("REPLACE_GAME_MATCHMAKING_DESC"_T.data());
|
||||
|
||||
|
@ -166,5 +166,42 @@ namespace big
|
||||
ImGui::SliderInt("###multiplex_cnt", &g.spoofing.multiplex_count, 2, 5);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -41,280 +41,283 @@ namespace big
|
||||
|
||||
void view::player_info()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("INFO"_T);
|
||||
ImGui::SeparatorText("INFO"_T.data());
|
||||
|
||||
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;
|
||||
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{};
|
||||
ped_damage_bits = ped->m_damage_bits;
|
||||
ped_task_flag = ped->m_ped_task_flag;
|
||||
ped_health = ped->m_health;
|
||||
ped_maxhealth = ped->m_maxhealth;
|
||||
}
|
||||
|
||||
if (CPed* ped = g_player_service->get_selected()->get_ped(); ped != nullptr)
|
||||
{
|
||||
ped_damage_bits = ped->m_damage_bits;
|
||||
ped_task_flag = ped->m_ped_task_flag;
|
||||
ped_health = ped->m_health;
|
||||
ped_maxhealth = ped->m_maxhealth;
|
||||
}
|
||||
components::options_modal(
|
||||
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(),
|
||||
[ped_health, ped_maxhealth] {
|
||||
ImGui::BeginGroup();
|
||||
|
||||
components::options_modal(
|
||||
"VIEW_PLAYER_INFO_EXTRA_INFO"_T.data(),
|
||||
[ped_health, ped_maxhealth] {
|
||||
ImGui::BeginGroup();
|
||||
auto id = g_player_service->get_selected()->id();
|
||||
|
||||
auto id = g_player_service->get_selected()->id();
|
||||
|
||||
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)
|
||||
if (id != -1)
|
||||
{
|
||||
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())
|
||||
{
|
||||
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::EndGroup();
|
||||
|
||||
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();
|
||||
ImGui::BeginGroup();
|
||||
|
||||
auto ip = g_player_service->get_selected()->get_ip_address();
|
||||
auto port = g_player_service->get_selected()->get_port();
|
||||
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 (ip)
|
||||
if (auto peer = g_player_service->get_selected()->get_connection_peer())
|
||||
{
|
||||
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::Text(std::format("{}: {}", "VIEW_PLAYER_INFO_CONNECTION_TYPE"_T, get_connection_type_str(peer->m_peer_address.m_connection_type)).c_str());
|
||||
|
||||
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::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
|
||||
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("{}: {:X}", "VIEW_PLAYER_INFO_HOST_TOKEN"_T, g_player_service->get_selected()->get_net_data()->m_host_token).c_str());
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Copy"))
|
||||
{
|
||||
ImGui::SetClipboardText(std::format("{:X}", g_player_service->get_selected()->get_net_data()->m_host_token).data());
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (net_player_data->m_force_relays)
|
||||
ImGui::Text("VIEW_PLAYER_INFO_IP_HIDDEN"_T.data());
|
||||
else
|
||||
ImGui::Text("VIEW_PLAYER_INFO_IP_UNKNOWN"_T.data());
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
if (mode_str.empty())
|
||||
{
|
||||
mode_str = "NO"_T;
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,40 +6,28 @@ namespace big
|
||||
{
|
||||
void view::player_kick()
|
||||
{
|
||||
ImGui::BeginGroup();
|
||||
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();
|
||||
};
|
||||
ImGui::SeparatorText("KICKS"_T.data());
|
||||
|
||||
if (!g_player_service->get_self()->is_host())
|
||||
ImGui::Text("VIEW_PLAYER_KICK_HOST_AND_BREAKUP_KICK_REQUIRE_SESSION_HOST"_T.data());
|
||||
if (!g_player_service->get_self()->is_host())
|
||||
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::player_command_button<"breakup">(g_player_service->get_selected());
|
||||
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
components::command_checkbox<"breakupcheating">();
|
||||
components::command_checkbox<"breakupcheating">();
|
||||
|
||||
components::player_command_button<"smartkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"oomkick">(g_player_service->get_selected());
|
||||
|
||||
components::player_command_button<"shkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"endkick">(g_player_service->get_selected());
|
||||
|
||||
components::player_command_button<"desync">(g_player_service->get_selected());
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::EndGroup();
|
||||
components::player_command_button<"smartkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"oomkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"shkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"endkick">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"desync">(g_player_service->get_selected());
|
||||
}
|
||||
}
|
||||
|
@ -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 "services/players/player_service.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
void view::player_misc()
|
||||
{
|
||||
{
|
||||
ImGui::SeparatorText("DEBUG_TAB_MISC"_T.data());
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("DEBUG_TAB_MISC"_T);
|
||||
if (ImGui::BeginListBox("##misc", get_listbox_dimensions()))
|
||||
{
|
||||
components::player_command_button<"joinceo">(g_player_service->get_selected());
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"enterint">(g_player_service->get_selected());
|
||||
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(), {});
|
||||
components::player_command_button<"joinceo">(g_player_service->get_selected());
|
||||
components::player_command_button<"enterint">(g_player_service->get_selected());
|
||||
components::player_command_button<"copyoutfit">(g_player_service->get_selected());
|
||||
components::player_command_button<"copymodel">(g_player_service->get_selected());
|
||||
components::player_command_button<"clearwanted">(g_player_service->get_selected());
|
||||
ImGui::EndGroup();
|
||||
|
||||
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::EndGroup();
|
||||
ImGui::SameLine();
|
||||
|
||||
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::EndListBox();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
@ -9,132 +9,116 @@ namespace big
|
||||
{
|
||||
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());
|
||||
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())
|
||||
for (int i = 1; i < apartment_names.size(); i++)
|
||||
{
|
||||
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()))
|
||||
if (ImGui::Selectable(apartment_names[i], i == g.session.send_to_apartment_idx))
|
||||
{
|
||||
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::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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,118 +9,110 @@ namespace big
|
||||
{
|
||||
void view::player_toxic()
|
||||
{
|
||||
ImGui::SeparatorText("TOXIC"_T.data());
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("TOXIC"_T);
|
||||
if (ImGui::BeginListBox("##toxic", get_listbox_dimensions()))
|
||||
{
|
||||
components::player_command_button<"kill">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"explode">(g_player_service->get_selected(), {});
|
||||
|
||||
components::player_command_button<"ceokick">(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();
|
||||
}
|
||||
components::player_command_button<"kill">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"explode">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"ceokick">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"ragdoll">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"beast">(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<"error">(g_player_service->get_selected(), {});
|
||||
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");
|
||||
}
|
||||
}
|
@ -4,54 +4,41 @@ namespace big
|
||||
{
|
||||
void view::player_vehicle()
|
||||
{
|
||||
ImGui::SeparatorText("VEHICLE"_T.data());
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::sub_title("VEHICLE"_T);
|
||||
if (ImGui::BeginListBox("##veh", get_listbox_dimensions()))
|
||||
{
|
||||
components::player_command_button<"vehkick">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"flyingveh">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"vehkick">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"deleteveh">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"flyingveh">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"boostveh">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"stopveh">(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();
|
||||
components::player_command_button<"stopveh">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
|
||||
components::player_command_button<"flip180">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"rcplayer">(g_player_service->get_selected(), {});
|
||||
ImGui::BeginGroup();
|
||||
components::player_command_button<"killengine">(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();
|
||||
components::player_command_button<"burstwheels">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
|
||||
components::player_command_button<"smashwindows">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"blacktint">(g_player_service->get_selected(), {});
|
||||
|
||||
components::player_command_button<"lockveh">(g_player_service->get_selected(), {});
|
||||
ImGui::SameLine();
|
||||
components::player_command_button<"unlockveh">(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::BeginGroup();
|
||||
components::player_command_button<"breakdoors">(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<"svehjump">(g_player_service->get_selected(), {});
|
||||
components::player_command_button<"svehboost">(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(), {});
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
}
|
@ -41,16 +41,11 @@ namespace big
|
||||
std::format("{} ({}){}", current_player->get_name(), current_player->id(), name_appendage).c_str());
|
||||
|
||||
view::player_info();
|
||||
ImGui::SameLine();
|
||||
view::player_teleport();
|
||||
|
||||
view::player_kick();
|
||||
ImGui::SameLine();
|
||||
view::player_toxic();
|
||||
|
||||
view::player_misc();
|
||||
ImGui::SameLine();
|
||||
view::player_vehicle();
|
||||
view::player_misc();
|
||||
}
|
||||
else
|
||||
g_gui_service->set_selected(tabs::NONE);
|
||||
|
@ -27,7 +27,8 @@ namespace big
|
||||
player_icons += FONT_ICON_HOST;
|
||||
if (plyr->is_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;
|
||||
|
||||
const auto player_iconsc = player_icons.c_str();
|
||||
|
@ -1,6 +1,5 @@
|
||||
#include "core/data/block_join_reasons.hpp"
|
||||
#include "backend/reactions/reaction.hpp"
|
||||
#include "views/view.hpp"
|
||||
#include "core/data/block_join_reasons.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -62,7 +61,7 @@ namespace big
|
||||
ImGui::Checkbox("REACTION_BLOCK_JOINS"_T.data(), &reaction.block_joins);
|
||||
if (reaction.block_joins)
|
||||
if (ImGui::BeginCombo("BLOCK_JOIN_ALERT"_T.data(), block_join_reasons[reaction.block_join_reason]))
|
||||
{
|
||||
{
|
||||
for (const auto& [key, value] : block_join_reasons)
|
||||
{
|
||||
bool is_selected = (reaction.block_join_reason == key);
|
||||
@ -95,12 +94,14 @@ namespace big
|
||||
{
|
||||
components::title("SETTINGS_REACTIONS"_T);
|
||||
draw_reaction(g.reactions.bounty);
|
||||
draw_reaction(g.reactions.break_game);
|
||||
draw_reaction(g.reactions.ceo_kick);
|
||||
draw_reaction(g.reactions.ceo_money);
|
||||
draw_reaction(g.reactions.chat_spam);
|
||||
draw_reaction(g.reactions.clear_ped_tasks);
|
||||
draw_reaction(g.reactions.clear_wanted_level);
|
||||
draw_reaction(g.reactions.crash);
|
||||
draw_reaction(g.reactions.delete_vehicle);
|
||||
draw_reaction(g.reactions.destroy_personal_vehicle);
|
||||
draw_reaction(g.reactions.end_session_kick);
|
||||
draw_reaction(g.reactions.fake_deposit);
|
||||
|
@ -40,6 +40,7 @@ namespace big
|
||||
static void self();
|
||||
static void animations();
|
||||
static void network();
|
||||
static void chat();
|
||||
static void missions();
|
||||
static void player_database();
|
||||
static void session_browser();
|
||||
|
@ -135,7 +135,7 @@ namespace big
|
||||
PED::SET_PED_FIRING_PATTERN(ped, "FIRING_PATTERN_FULL_AUTO"_J);
|
||||
PED::SET_PED_SHOOT_RATE(ped, 150);
|
||||
|
||||
if (!clone)
|
||||
if (!clone && g.world.spawn_ped.randomize_outfit)
|
||||
ped::set_ped_random_component_variation(ped);
|
||||
|
||||
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_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_RANDOMIZE_OUTFIT"_T.data(), &g.world.spawn_ped.randomize_outfit);
|
||||
|
||||
components::button("CHANGE_PLAYER_MODEL"_T, [] {
|
||||
if (selected_ped_type == -2)
|
||||
|
Reference in New Issue
Block a user