mirror of
https://github.com/Mr-X-GTA/YimMenu.git
synced 2024-12-22 20:17:24 +08:00
Lessen breakup kicks and more (#625)
This commit is contained in:
parent
6f3e3cc6b3
commit
bbd13dd06d
@ -3,7 +3,7 @@ include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
gtav_classes
|
||||
GIT_REPOSITORY https://github.com/Yimura/GTAV-Classes.git
|
||||
GIT_TAG 1dc66fb37fec895c96c2b1e4944e382a83c5e993
|
||||
GIT_TAG 16f85bea73691623d1a43c4a912f94f93e509597
|
||||
GIT_PROGRESS TRUE
|
||||
CONFIGURE_COMMAND ""
|
||||
BUILD_COMMAND ""
|
||||
|
@ -126,12 +126,9 @@ namespace big
|
||||
|
||||
while (g_running)
|
||||
{
|
||||
g_player_service->iterate([](const player_entry &entry)
|
||||
{
|
||||
looped::player_never_wanted(entry.second);
|
||||
});
|
||||
|
||||
looped::player_good_options();
|
||||
looped::player_spectate();
|
||||
looped::player_remote_control_vehicle();
|
||||
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
@ -15,8 +15,9 @@ namespace big
|
||||
|
||||
static void tunables_disable_phone();
|
||||
|
||||
static void player_never_wanted(const player_ptr &player);
|
||||
static void player_good_options();
|
||||
static void player_spectate();
|
||||
static void player_remote_control_vehicle();
|
||||
|
||||
static void protections_replay_interface();
|
||||
|
||||
|
67
src/backend/looped/player/good_options.cpp
Normal file
67
src/backend/looped/player/good_options.cpp
Normal file
@ -0,0 +1,67 @@
|
||||
#include "gta/PickupRewards.h"
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/globals.hpp"
|
||||
#include "util/misc.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
// rate limit script events to prevent crashes
|
||||
static int offRadarPlayer = 0;
|
||||
static int neverWantedPlayer = 0;
|
||||
void looped::player_good_options()
|
||||
{
|
||||
if (!NETWORK::NETWORK_IS_SESSION_STARTED())
|
||||
return;
|
||||
|
||||
offRadarPlayer++;
|
||||
if (offRadarPlayer > 32)
|
||||
offRadarPlayer = 0;
|
||||
|
||||
neverWantedPlayer++;
|
||||
if (neverWantedPlayer > 32)
|
||||
neverWantedPlayer = 0;
|
||||
|
||||
g_player_service->iterate([](const player_entry& entry)
|
||||
{
|
||||
if ((g->session.off_radar_all || entry.second->off_radar) && offRadarPlayer == entry.second->id())
|
||||
globals::give_remote_otr(entry.second->id());
|
||||
});
|
||||
|
||||
g_player_service->iterate([](const player_entry& entry)
|
||||
{
|
||||
if ((g->session.never_wanted_all || entry.second->never_wanted) && PLAYER::GET_PLAYER_WANTED_LEVEL(entry.second->id()) > 0 && neverWantedPlayer == entry.second->id())
|
||||
globals::clear_wanted_player(entry.second->id());
|
||||
});
|
||||
|
||||
if (g->session.semi_godmode_all)
|
||||
{
|
||||
g_pointers->m_give_pickup_rewards(-1, REWARD_HEALTH);
|
||||
g_pointers->m_give_pickup_rewards(-1, REWARD_ARMOUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_player_service->iterate([](const player_entry& entry)
|
||||
{
|
||||
if (entry.second->semi_godmode)
|
||||
{
|
||||
if (CPed* ped = entry.second->get_ped())
|
||||
{
|
||||
if (ped->m_maxhealth == 0 || ped->m_health == 0 || misc::has_bit_set((int*)&ped->m_damage_bits, 8))
|
||||
return;
|
||||
|
||||
if (ped->m_health < ped->m_maxhealth)
|
||||
{
|
||||
g_pointers->m_give_pickup_rewards(1 << entry.second->id(), REWARD_HEALTH);
|
||||
}
|
||||
|
||||
if (ped->m_armor < 50.0f)
|
||||
{
|
||||
g_pointers->m_give_pickup_rewards(1 << entry.second->id(), REWARD_ARMOUR);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +0,0 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "util/globals.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
void looped::player_never_wanted(const player_ptr &player)
|
||||
{
|
||||
if (player->never_wanted)
|
||||
{
|
||||
globals::clear_wanted_player(player->id());
|
||||
}
|
||||
}
|
||||
}
|
50
src/backend/looped/player/remote_control_vehicle.cpp
Normal file
50
src/backend/looped/player/remote_control_vehicle.cpp
Normal file
@ -0,0 +1,50 @@
|
||||
#include "backend/looped/looped.hpp"
|
||||
#include "pointers.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "util/entity.hpp"
|
||||
#include "fiber_pool.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
void looped::player_remote_control_vehicle()
|
||||
{
|
||||
if (g->m_remote_controller_vehicle == -1)
|
||||
return;
|
||||
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(g->m_remote_controlled_vehicle))
|
||||
{
|
||||
g->m_remote_controlled_vehicle = -1;
|
||||
g->m_remote_controlled_vehicle = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ENTITY::DOES_ENTITY_EXIST(g->m_remote_controller_vehicle))
|
||||
{
|
||||
g->m_remote_controlled_vehicle = -1;
|
||||
g->m_remote_controlled_vehicle = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
if (VEHICLE::IS_VEHICLE_SEAT_FREE(g->m_remote_controller_vehicle, -1, TRUE))
|
||||
{
|
||||
auto controlled = g->m_remote_controlled_vehicle;
|
||||
auto controller = g->m_remote_controller_vehicle;
|
||||
g_fiber_pool->queue_job([controlled, controller]
|
||||
{
|
||||
if (entity::take_control_of(controlled))
|
||||
{
|
||||
ENTITY::SET_ENTITY_COLLISION(g->m_remote_controlled_vehicle, TRUE, TRUE);
|
||||
ENTITY::DETACH_ENTITY(controlled, TRUE, TRUE);
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(controlled, 0);
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED_FOR_ALL_PLAYERS(controlled, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(controlled, FALSE);
|
||||
entity::delete_entity(controller);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
g->m_remote_controller_vehicle = -1;
|
||||
g->m_remote_controlled_vehicle = -1;
|
||||
}
|
||||
}
|
||||
};
|
@ -13,7 +13,7 @@ namespace big
|
||||
std::uint64_t host_token;
|
||||
g_pointers->m_generate_uuid(&host_token);
|
||||
|
||||
host_token = g->session.force_session_host ? 1 : host_token;
|
||||
host_token = g->session.force_session_host ? (rand() % 10000) : host_token;
|
||||
|
||||
*g_pointers->m_host_token = host_token;
|
||||
|
||||
|
@ -12,7 +12,8 @@ namespace big
|
||||
SPOOFED_ROCKSTAR_ID,
|
||||
TRIGGERED_ANTICHEAT,
|
||||
TRIED_CRASH_PLAYER,
|
||||
TRIED_KICK_PLAYER
|
||||
TRIED_KICK_PLAYER,
|
||||
BLAME_EXPLOSION_DETECTED
|
||||
};
|
||||
|
||||
inline std::unordered_map<Infraction, const char*> infraction_desc =
|
||||
@ -23,6 +24,7 @@ namespace big
|
||||
{Infraction::SPOOFED_ROCKSTAR_ID, "Had spoofed RID"},
|
||||
{Infraction::TRIGGERED_ANTICHEAT, "Triggered Rockstar's anticheat"},
|
||||
{Infraction::TRIED_CRASH_PLAYER, "Tried to crash you"},
|
||||
{Infraction::TRIED_KICK_PLAYER, "Tried to kick you"}
|
||||
{Infraction::TRIED_KICK_PLAYER, "Tried to kick you"},
|
||||
{Infraction::BLAME_EXPLOSION_DETECTED, "Tried to blame someone for their explosion"}
|
||||
};
|
||||
}
|
@ -146,6 +146,7 @@ namespace big
|
||||
script_events script_events{};
|
||||
bool script_host_kick = true;
|
||||
bool rid_join = false;
|
||||
bool lessen_breakups = false; // disabled by default due to anticheat concerns
|
||||
};
|
||||
|
||||
struct self
|
||||
@ -200,6 +201,14 @@ namespace big
|
||||
bool player_magnet_enabled = false;
|
||||
int player_magnet_count = 32;
|
||||
bool is_team = false;
|
||||
bool name_spoof_enabled = false;
|
||||
bool advertise_menu = false;
|
||||
std::string spoofed_name = "";
|
||||
|
||||
// not to be saved
|
||||
bool never_wanted_all = false;
|
||||
bool off_radar_all = false;
|
||||
bool semi_godmode_all = false;
|
||||
};
|
||||
|
||||
struct settings {
|
||||
@ -406,6 +415,10 @@ namespace big
|
||||
int player_count = 0;
|
||||
|
||||
CNetGamePlayer* m_syncing_player = nullptr;
|
||||
std::unordered_map<std::uint64_t, std::uint64_t> m_spoofed_peer_ids;
|
||||
|
||||
int m_remote_controller_vehicle = -1;
|
||||
int m_remote_controlled_vehicle = -1;
|
||||
|
||||
debug debug{};
|
||||
tunables tunables{};
|
||||
@ -573,6 +586,7 @@ namespace big
|
||||
|
||||
this->protections.script_host_kick = j["protections"]["script_host_kick"];
|
||||
this->protections.rid_join = j["protections"]["rid_join"];
|
||||
this->protections.lessen_breakups = j["protections"]["lessen_breakups"];
|
||||
|
||||
this->tunables.disable_phone = j["tunables"]["disable_phone"];
|
||||
this->tunables.no_idle_kick = j["tunables"]["no_idle_kick"];
|
||||
@ -612,6 +626,9 @@ namespace big
|
||||
this->session.player_magnet_enabled = j["session"]["player_magnet_enabled"];
|
||||
this->session.player_magnet_count = j["session"]["player_magnet_count"];
|
||||
this->session.is_team = j["session"]["is_team"];
|
||||
this->session.name_spoof_enabled = j["session"]["name_spoof_enabled"];
|
||||
this->session.advertise_menu = j["session"]["advertise_menu"];
|
||||
this->session.spoofed_name = j["session"]["spoofed_name"];
|
||||
|
||||
this->settings.dev_dlc = j["settings"]["dev_dlc"];
|
||||
this->settings.hotkeys.menu_toggle = j["settings"]["hotkeys"]["menu_toggle"];
|
||||
@ -861,7 +878,8 @@ namespace big
|
||||
},
|
||||
|
||||
{ "script_host_kick", g->protections.script_host_kick },
|
||||
{ "rid_join", g->protections.rid_join }
|
||||
{ "rid_join", g->protections.rid_join },
|
||||
{ "lessen_breakups", g->protections.lessen_breakups }
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -931,7 +949,10 @@ namespace big
|
||||
{ "force_session_host", this->session.force_session_host },
|
||||
{ "player_magnet_enabled", this->session.player_magnet_enabled },
|
||||
{ "player_magnet_count", this->session.player_magnet_count },
|
||||
{ "is_team", this->session.is_team }
|
||||
{ "is_team", this->session.is_team },
|
||||
{ "name_spoof_enabled", this->session.name_spoof_enabled },
|
||||
{ "advertise_menu", this->session.advertise_menu },
|
||||
{ "spoofed_name", this->session.spoofed_name }
|
||||
}
|
||||
},
|
||||
{
|
||||
|
40
src/core/scr_globals.hpp
Normal file
40
src/core/scr_globals.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
#include "script_global.hpp"
|
||||
|
||||
namespace big::scr_globals
|
||||
{
|
||||
namespace size
|
||||
{
|
||||
constexpr int globalplayer_bd = 453;
|
||||
constexpr int gpbd_fm_3 = 599;
|
||||
constexpr int gpbd_fm_1 = 888;
|
||||
}
|
||||
|
||||
static inline script_global gsbd(2680265);
|
||||
static inline script_global gsbd_fm(1835502);
|
||||
static inline script_global gsbd_kicking(1883751);
|
||||
static inline script_global gsbd_fm_events(1920255);
|
||||
static inline script_global gsbd_block_c(2683918);
|
||||
|
||||
static inline script_global globalplayer_bd(2689235);
|
||||
static inline script_global gpbd_fm_3(1892703);
|
||||
static inline script_global gpbd_fm_1(1853348);
|
||||
|
||||
static inline script_global launcher_global(2779753);
|
||||
|
||||
static inline script_global sp(113386);
|
||||
static inline script_global mission_definition(91229);
|
||||
|
||||
static inline script_global creator_job_metadata(4718592);
|
||||
static inline script_global terminate_creator(1574607); // NETWORK::NETWORK_BAIL(1, 0, 0); fm_*_creator
|
||||
static inline script_global switch_struct(1574632);
|
||||
static inline script_global mission_creator_radar_follows_camera(2621443);
|
||||
static inline script_global mission_creator_exited(1574530);
|
||||
|
||||
static inline script_global in_multiplayer(78319); // g_bInMultiplayer
|
||||
|
||||
static inline script_global vehicle_global = script_global(1585857);
|
||||
static inline script_global mechanic_global = script_global(2815059);
|
||||
|
||||
static inline script_global spawn_global = script_global(2725439);
|
||||
}
|
@ -59,7 +59,6 @@ class CGameScriptHandlerNetwork;
|
||||
class CGameScriptHandlerMgr;
|
||||
|
||||
class CEntity;
|
||||
class CDynamicEntity;
|
||||
class CPhysical;
|
||||
|
||||
class CObject;
|
||||
|
@ -211,6 +211,49 @@ namespace rage
|
||||
|
||||
WriteQWord((uint64_t)data, length);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void WriteSigned(int length, T data)
|
||||
{
|
||||
int sign = data < 0;
|
||||
int signEx = (data < 0) ? 0xFFFFFFFF : 0;
|
||||
int d = (data ^ signEx);
|
||||
|
||||
Write<int>(1, sign);
|
||||
Write<int>(length - 1, d);
|
||||
}
|
||||
|
||||
inline float ReadFloat(int length, float divisor)
|
||||
{
|
||||
auto integer = Read<int>(length);
|
||||
|
||||
float max = (1 << length) - 1;
|
||||
return ((float)integer / max) * divisor;
|
||||
}
|
||||
|
||||
inline void WriteFloat(int length, float divisor, float value)
|
||||
{
|
||||
float max = (1 << length) - 1;
|
||||
int integer = (int)((value / divisor) * max);
|
||||
|
||||
Write<int>(length, integer);
|
||||
}
|
||||
|
||||
inline float ReadSignedFloat(int length, float divisor)
|
||||
{
|
||||
auto integer = ReadSigned<int>(length);
|
||||
|
||||
float max = (1 << (length - 1)) - 1;
|
||||
return ((float)integer / max) * divisor;
|
||||
}
|
||||
|
||||
inline void WriteSignedFloat(int length, float divisor, float value)
|
||||
{
|
||||
float max = (1 << (length - 1)) - 1;
|
||||
int integer = (int)((value / divisor) * max);
|
||||
|
||||
WriteSigned<int>(length, integer);
|
||||
}
|
||||
public:
|
||||
void* m_data; //0x0000
|
||||
uint32_t m_bitOffset; //0x0008
|
||||
@ -376,7 +419,7 @@ namespace rage
|
||||
virtual __int64 get_type() = 0;
|
||||
virtual void unk_0x20() = 0;
|
||||
virtual void unk_0x28() = 0;
|
||||
virtual bool get_extra_information(__int64* info_array, int check) = 0;
|
||||
virtual bool get_extra_information(void* info_array, int check) = 0;
|
||||
virtual void unk_0x38() = 0;
|
||||
};
|
||||
|
||||
|
@ -179,6 +179,86 @@ class CGameScriptHandlerMgr : public rage::scriptHandlerMgr
|
||||
{
|
||||
};
|
||||
|
||||
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[48]; //0x0010
|
||||
std::uint32_t m_participants; //0x0040
|
||||
};
|
||||
|
||||
static_assert(sizeof(rage::scriptHandler) == 0x60);
|
||||
static_assert(sizeof(CGameScriptHandler) == 0xA0);
|
||||
static_assert(sizeof(CGameScriptHandlerNetwork) == 0xB0);
|
||||
|
@ -76,6 +76,9 @@ namespace big
|
||||
|
||||
detour_hook_helper::add<hooks::sort_session_details>("SSD", g_pointers->m_sort_session_details);
|
||||
|
||||
detour_hook_helper::add<hooks::add_player_to_session>("APTS", g_pointers->m_add_player_to_session);
|
||||
detour_hook_helper::add<hooks::send_chat_net_message>("SCNM", g_pointers->m_send_chat_net_message);
|
||||
|
||||
g_hooking = this;
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@ class CDynamicEntityGameStateDataNode;
|
||||
class CVehicleGadgetDataNode;
|
||||
class CJoinRequestContext;
|
||||
class SessionSortEntry;
|
||||
class RemoteGamerInfoMsg;
|
||||
class CMsgTextMessage;
|
||||
|
||||
namespace rage
|
||||
{
|
||||
@ -91,6 +93,9 @@ namespace big
|
||||
static bool handle_join_request(Network* network, rage::snSession* session, rage::rlGamerInfo* player_info, CJoinRequestContext* ctx, BOOL is_transition_session);
|
||||
|
||||
static bool sort_session_details(SessionSortEntry* e1, SessionSortEntry* e2);
|
||||
|
||||
static bool add_player_to_session(rage::netConnectionManager* mgr, int receiver_msg_id, int* out_command_hndl, RemoteGamerInfoMsg* msg, int flags, void* unk);
|
||||
static bool send_chat_net_message(rage::netConnectionManager* mgr, int receiver_msg_id, CMsgTextMessage* msg, int flags, void* unk);
|
||||
};
|
||||
|
||||
class minhook_keepalive
|
||||
|
@ -1,4 +1,6 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta/net_game_event.hpp"
|
||||
#include <entities/CDynamicEntity.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
|
26
src/hooks/misc/send_chat_net_message.cpp
Normal file
26
src/hooks/misc/send_chat_net_message.cpp
Normal file
@ -0,0 +1,26 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "services/players/player_service.hpp"
|
||||
#include <network/Network.hpp>
|
||||
#include <network/CMsgTextMessage.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::send_chat_net_message(rage::netConnectionManager* mgr, int receiver_msg_id, CMsgTextMessage* msg, int flags, void* unk)
|
||||
{
|
||||
std::uint64_t host_token = -1;
|
||||
for (auto& [_, plyr] : g_player_service->players())
|
||||
{
|
||||
if (plyr->get_net_game_player()->m_msg_id == receiver_msg_id)
|
||||
{
|
||||
host_token = plyr->get_net_data()->m_host_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (g->m_spoofed_peer_ids.contains(host_token))
|
||||
msg->m_peer_id = g->m_spoofed_peer_ids[host_token];
|
||||
|
||||
return g_hooking->get_original<hooks::send_chat_net_message>()(mgr, receiver_msg_id, msg, flags, unk);
|
||||
}
|
||||
}
|
@ -11,11 +11,11 @@ namespace big
|
||||
{
|
||||
void* hooks::assign_physical_index(CNetworkPlayerMgr* netPlayerMgr, CNetGamePlayer* player, uint8_t new_index)
|
||||
{
|
||||
const auto result = g_hooking->get_original<hooks::assign_physical_index>()(netPlayerMgr, player, new_index);
|
||||
const auto* net_player_data = player->get_net_data();
|
||||
|
||||
if (new_index == static_cast<uint8_t>(-1))
|
||||
{
|
||||
g->m_spoofed_peer_ids.erase(player->get_net_data()->m_host_token);
|
||||
g_player_service->player_leave(player);
|
||||
|
||||
if (net_player_data)
|
||||
@ -29,9 +29,10 @@ namespace big
|
||||
g_notification_service->push("Player Left", std::format("{} freeing slot #{} with Rockstar ID: {}", net_player_data->m_name, player->m_player_id, net_player_data->m_gamer_handle_2.m_rockstar_id));
|
||||
}
|
||||
|
||||
return result;
|
||||
return g_hooking->get_original<hooks::assign_physical_index>()(netPlayerMgr, player, new_index);
|
||||
}
|
||||
|
||||
const auto result = g_hooking->get_original<hooks::assign_physical_index>()(netPlayerMgr, player, new_index);
|
||||
g_player_service->player_join(player);
|
||||
if (net_player_data)
|
||||
{
|
||||
|
@ -18,6 +18,7 @@ namespace big
|
||||
|
||||
void hooks::network_player_mgr_shutdown(CNetworkPlayerMgr* _this)
|
||||
{
|
||||
g->m_spoofed_peer_ids.clear();
|
||||
g_player_service->do_cleanup();
|
||||
|
||||
if (g->notifications.network_player_mgr_shutdown.log)
|
||||
|
55
src/hooks/protections/add_player_to_session.cpp
Normal file
55
src/hooks/protections/add_player_to_session.cpp
Normal file
@ -0,0 +1,55 @@
|
||||
#include "hooking.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include <network/Network.hpp>
|
||||
#include <network/RemoteGamerInfoMsg.hpp>
|
||||
|
||||
// https://stackoverflow.com/questions/8120062/generate-random-64-bit-integer
|
||||
unsigned
|
||||
static rand256()
|
||||
{
|
||||
static unsigned const limit = RAND_MAX - RAND_MAX % 256;
|
||||
unsigned result = rand();
|
||||
while (result >= limit)
|
||||
{
|
||||
result = rand();
|
||||
}
|
||||
return result % 256;
|
||||
}
|
||||
|
||||
unsigned long long
|
||||
static rand64bits()
|
||||
{
|
||||
unsigned long long results = 0ULL;
|
||||
for (int count = 8; count > 0; --count)
|
||||
{
|
||||
results = 256U * results + rand256();
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::add_player_to_session(rage::netConnectionManager* mgr, int receiver_msg_id, int* out_command_hndl, RemoteGamerInfoMsg* msg, int flags, void* unk)
|
||||
{
|
||||
if (msg->m_gamer_info.m_gamer_handle_2.m_rockstar_id == g_local_player->m_player_info->m_net_player_data.m_gamer_handle_2.m_rockstar_id && gta_util::get_network()->m_game_session_ptr->is_host() && g->protections.lessen_breakups)
|
||||
{
|
||||
std::uint64_t host_token = -1;
|
||||
|
||||
auto session = gta_util::get_network()->m_game_session_ptr;
|
||||
for (int i = 0; i < session->m_player_count; i++)
|
||||
{
|
||||
if (session->m_players[i]->m_msg_id == receiver_msg_id)
|
||||
{
|
||||
host_token = session->m_players[i]->m_player_data.m_host_token;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint64_t peer_id = rand64bits();
|
||||
g->m_spoofed_peer_ids.emplace(host_token, peer_id);
|
||||
msg->m_gamer_info.m_peer_id_2 = peer_id;
|
||||
}
|
||||
|
||||
return g_hooking->get_original<hooks::add_player_to_session>()(mgr, receiver_msg_id, out_command_hndl, msg, flags, unk);
|
||||
}
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
#include "natives.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "util/session.hpp"
|
||||
#include "util/spam.hpp"
|
||||
#include <network/Network.hpp>
|
||||
|
||||
namespace big
|
||||
@ -56,47 +57,39 @@ namespace big
|
||||
switch (msgType)
|
||||
{
|
||||
case rage::eNetMessage::MsgTextMessage:
|
||||
{
|
||||
if (g->session.log_chat_messages)
|
||||
{
|
||||
char message[256];
|
||||
uint64_t unk;
|
||||
bool is_team;
|
||||
buffer.ReadString(message, 256);
|
||||
buffer.ReadQWord(&unk, 64);
|
||||
buffer.ReadBool(&is_team);
|
||||
LOG(INFO) << "[CHAT] from " << player->get_name() << ": " << message << (is_team ? " [TEAM]" : " [ALL]");
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgTextMessage2:
|
||||
{
|
||||
if (g->session.log_text_messages)
|
||||
char message[256];
|
||||
buffer.ReadString(message, 256);
|
||||
|
||||
if (player->is_spammer)
|
||||
return true;
|
||||
|
||||
if (spam::is_text_spam(message))
|
||||
{
|
||||
char message[256];
|
||||
uint64_t unk;
|
||||
buffer.ReadString(message, 256);
|
||||
buffer.ReadQWord(&unk, 64);
|
||||
LOG(INFO) << "[TEXT] from " << player->get_name() << ": " << message;
|
||||
if (g->session.log_chat_messages)
|
||||
spam::log_chat(message, player, true);
|
||||
player->is_spammer = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g->session.log_chat_messages)
|
||||
spam::log_chat(message, player, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgScriptMigrateHost:
|
||||
{
|
||||
if (std::chrono::system_clock::now() - player->m_last_transition_msg_sent < 200ms)
|
||||
if (player->m_host_migration_rate_limit.process())
|
||||
{
|
||||
if (player->m_num_failed_transition_attempts++ == 20)
|
||||
if (player->m_host_migration_rate_limit.exceeded_last_process())
|
||||
{
|
||||
session::add_infraction(player, Infraction::TRIED_KICK_PLAYER);
|
||||
g_notification_service->push_error("Protections", std::format("{} tried to OOM kick you!", player->get_name()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->m_last_transition_msg_sent = std::chrono::system_clock::now();
|
||||
player->m_num_failed_transition_attempts = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case rage::eNetMessage::MsgRemoveGamersFromSessionCmd:
|
||||
@ -181,8 +174,11 @@ namespace big
|
||||
uint32_t num_of_tokens{};
|
||||
buffer.ReadDword(&num_of_tokens, 32);
|
||||
|
||||
if (player && host_token != player->get_net_data()->m_host_token)
|
||||
if (player && host_token != player->get_net_data()->m_host_token && !player->exposed_desync_protection)
|
||||
{
|
||||
session::add_infraction(player, Infraction::DESYNC_PROTECTION);
|
||||
player->exposed_desync_protection = true;
|
||||
}
|
||||
|
||||
return true; // block desync kicks as host
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <network/CNetGamePlayer.hpp>
|
||||
#include "gta/script_id.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include <base/CObject.hpp>
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -19,6 +20,121 @@ namespace big
|
||||
id.m_instance_id = buffer.Read<int32_t>(8);
|
||||
}
|
||||
|
||||
void scan_explosion_event(CNetGamePlayer* player, rage::datBitBuffer* buffer)
|
||||
{
|
||||
uint16_t f186;
|
||||
uint16_t f208;
|
||||
int ownerNetId;
|
||||
uint16_t f214;
|
||||
eExplosionTag explosionType;
|
||||
float damageScale;
|
||||
|
||||
float posX;
|
||||
float posY;
|
||||
float posZ;
|
||||
|
||||
bool f242;
|
||||
uint16_t f104;
|
||||
float cameraShake;
|
||||
|
||||
bool isAudible;
|
||||
bool f189;
|
||||
bool isInvisible;
|
||||
bool f126;
|
||||
bool f241;
|
||||
bool f243;
|
||||
|
||||
uint16_t f210;
|
||||
|
||||
float unkX;
|
||||
float unkY;
|
||||
float unkZ;
|
||||
|
||||
bool f190;
|
||||
bool f191;
|
||||
|
||||
uint32_t f164;
|
||||
|
||||
float posX224;
|
||||
float posY224;
|
||||
float posZ224;
|
||||
|
||||
bool f240;
|
||||
uint16_t f218;
|
||||
bool f216;
|
||||
|
||||
f186 = buffer->Read<uint16_t>(16);
|
||||
f208 = 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
|
||||
damageScale = buffer->Read<int>(8) / 255.0f;
|
||||
|
||||
posX = buffer->ReadSignedFloat(22, 27648.0f);
|
||||
posY = buffer->ReadSignedFloat(22, 27648.0f);
|
||||
posZ = buffer->ReadFloat(22, 4416.0f) - 1700.0f;
|
||||
|
||||
f242 = buffer->Read<uint8_t>(1);
|
||||
f104 = buffer->Read<uint16_t>(16);
|
||||
cameraShake = buffer->Read<int>(8) / 127.0f;
|
||||
|
||||
isAudible = buffer->Read<uint8_t>(1);
|
||||
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+
|
||||
|
||||
f210 = buffer->Read<uint16_t>(13);
|
||||
|
||||
unkX = buffer->ReadSignedFloat(16, 1.1f);
|
||||
unkY = buffer->ReadSignedFloat(16, 1.1f);
|
||||
unkZ = buffer->ReadSignedFloat(16, 1.1f);
|
||||
|
||||
f190 = buffer->Read<uint8_t>(1);
|
||||
f191 = buffer->Read<uint8_t>(1);
|
||||
|
||||
f164 = buffer->Read<uint32_t>(32);
|
||||
|
||||
if (f242)
|
||||
{
|
||||
posX224 = buffer->ReadSignedFloat(31, 27648.0f);
|
||||
posY224 = buffer->ReadSignedFloat(31, 27648.0f);
|
||||
posZ224 = buffer->ReadFloat(31, 4416.0f) - 1700.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
posX224 = 0;
|
||||
posY224 = 0;
|
||||
posZ224 = 0;
|
||||
}
|
||||
|
||||
auto f168 = buffer->Read<uint32_t>(32); // >= 1868: f_168
|
||||
|
||||
|
||||
f240 = buffer->Read<uint8_t>(1);
|
||||
if (f240)
|
||||
{
|
||||
f218 = buffer->Read<uint16_t>(16);
|
||||
|
||||
if (f191)
|
||||
{
|
||||
f216 = buffer->Read<uint8_t>(8);
|
||||
}
|
||||
}
|
||||
|
||||
buffer->Seek(0);
|
||||
|
||||
auto object = g_pointers->m_get_net_object(*g_pointers->m_network_object_mgr, ownerNetId, true);
|
||||
auto entity = object ? object->GetGameObject() : nullptr;
|
||||
|
||||
if (f208 == 0 && entity && entity->gap28 == 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)
|
||||
{
|
||||
g_notification_service->push_error("Warning!", std::format("{} blamed {} for explosion", 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);
|
||||
}
|
||||
}
|
||||
|
||||
void hooks::received_event(
|
||||
rage::netEventMgr* event_manager,
|
||||
CNetGamePlayer* source_player,
|
||||
@ -306,6 +422,25 @@ namespace big
|
||||
g->m_syncing_player = source_player;
|
||||
break;
|
||||
}
|
||||
case eNetworkEvents::NETWORK_PLAY_SOUND_EVENT:
|
||||
{
|
||||
auto plyr = g_player_service->get_by_id(source_player->m_player_id);
|
||||
if (plyr->m_play_sound_rate_limit.process())
|
||||
{
|
||||
if (plyr->m_play_sound_rate_limit.exceeded_last_process())
|
||||
{
|
||||
notify::crash_blocked(source_player, "sound spam");
|
||||
}
|
||||
g_pointers->m_send_event_ack(event_manager, source_player, target_player, event_index, event_handled_bitset);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case eNetworkEvents::EXPLOSION_EVENT:
|
||||
{
|
||||
scan_explosion_event(source_player, buffer);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1,5 +1,15 @@
|
||||
#include "hooking.hpp"
|
||||
|
||||
constexpr static auto advertisments = std::to_array(
|
||||
{
|
||||
"~h~~r~YimMenu",
|
||||
"~h~~g~YimMenu",
|
||||
"~h~~b~YimMenu",
|
||||
"~h~~y~YimMenu",
|
||||
"~h~~o~YimMenu",
|
||||
"~h~~p~YimMenu"
|
||||
});
|
||||
|
||||
namespace big
|
||||
{
|
||||
bool hooks::send_net_info_to_lobby(rage::rlGamerInfo* player, int64_t a2, int64_t a3, DWORD* a4)
|
||||
@ -31,6 +41,20 @@ namespace big
|
||||
if (g->notifications.send_net_info_to_lobby.notify)
|
||||
g_notification_service->push("Player Info Spoofing", "Sent spoofed values to lobby host.");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (g->session.name_spoof_enabled)
|
||||
{
|
||||
if (g->session.advertise_menu)
|
||||
{
|
||||
memcpy(player->m_name, advertisments[rand() % advertisments.size()], sizeof(player->m_name));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(player->m_name, g->session.spoofed_name.c_str(), sizeof(player->m_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const auto result = g_hooking->get_original<hooks::send_net_info_to_lobby>()(player, a2, a3, a4);
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include "native_hooks.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -16,5 +17,11 @@ namespace big
|
||||
|
||||
src->set_return_value(return_value);
|
||||
}
|
||||
|
||||
void NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA(rage::scrNativeCallContext* src)
|
||||
{
|
||||
*scr_globals::gsbd.as<int*>() = 4;
|
||||
src->set_return_value<BOOL>(TRUE);
|
||||
}
|
||||
}
|
||||
}
|
44
src/native_hooks/am_launcher.hpp
Normal file
44
src/native_hooks/am_launcher.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
namespace am_launcher
|
||||
{
|
||||
inline void START_NEW_SCRIPT_WITH_ARGS(rage::scrNativeCallContext* src)
|
||||
{
|
||||
const char* name = src->get_arg<const char*>(0);
|
||||
uint64_t* args = src->get_arg<uint64_t*>(1);
|
||||
int argc = src->get_arg<int>(2);
|
||||
int stackSize = src->get_arg<int>(3);
|
||||
|
||||
Hash name_hash = rage::joaat(name);
|
||||
|
||||
if (name_hash == RAGE_JOAAT("ggsm_arcade") ||
|
||||
name_hash == RAGE_JOAAT("camhedz_arcade") ||
|
||||
name_hash == RAGE_JOAAT("wizard_arcade") ||
|
||||
name_hash == RAGE_JOAAT("puzzle") ||
|
||||
name_hash == RAGE_JOAAT("fm_intro") ||
|
||||
name_hash == RAGE_JOAAT("pilot_school_mp") ||
|
||||
name_hash == RAGE_JOAAT("golf_mp") ||
|
||||
name_hash == RAGE_JOAAT("tennis_network_mp") ||
|
||||
name_hash == RAGE_JOAAT("fm_race_controler") ||
|
||||
name_hash == RAGE_JOAAT("fm_horde_controler") ||
|
||||
name_hash == RAGE_JOAAT("fm_mission_controller") ||
|
||||
name_hash == RAGE_JOAAT("fm_mission_controller_2020") ||
|
||||
name_hash == RAGE_JOAAT("fm_impromptu_dm_controler") ||
|
||||
name_hash == RAGE_JOAAT("fm_deathmatch_controler") ||
|
||||
name_hash == RAGE_JOAAT("fm_bj_race_controler") ||
|
||||
name_hash == RAGE_JOAAT("fm_survival_controller") ||
|
||||
name_hash == RAGE_JOAAT("tennis_network_mp") ||
|
||||
name_hash == RAGE_JOAAT("sctv") ||
|
||||
name_hash == RAGE_JOAAT("am_pi_menu")
|
||||
)
|
||||
{
|
||||
src->set_return_value<int>(0);
|
||||
return;
|
||||
}
|
||||
|
||||
src->set_return_value<int>(SYSTEM::START_NEW_SCRIPT_WITH_ARGS(name, (Any*)args, argc, stackSize));
|
||||
};
|
||||
}
|
||||
}
|
@ -17,5 +17,17 @@ namespace big
|
||||
else
|
||||
src->set_return_value<BOOL>(PLAYER::IS_PLAYER_PLAYING(src->get_arg<Player>(0)));
|
||||
};
|
||||
|
||||
inline void SET_ENTITY_VISIBLE(rage::scrNativeCallContext* src)
|
||||
{
|
||||
auto entity = src->get_arg<Entity>(0);
|
||||
auto toggle = src->get_arg<bool>(1);
|
||||
auto outfit = src->get_arg<bool>(2);
|
||||
|
||||
if (g->self.invisibility && entity == self::ped && toggle)
|
||||
return;
|
||||
else
|
||||
ENTITY::SET_ENTITY_VISIBLE(entity, toggle, outfit);
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,7 @@
|
||||
#include "gta_util.hpp"
|
||||
#include "shop_controller.hpp"
|
||||
#include "network_session_host.hpp"
|
||||
#include "am_launcher.hpp"
|
||||
|
||||
#include <script/scrProgram.hpp>
|
||||
#include <script/scrProgramTable.hpp>
|
||||
@ -16,14 +17,17 @@ namespace big
|
||||
native_hooks::native_hooks()
|
||||
{
|
||||
add_native_detour(0x812595A0644CE1DE, all_scripts::IS_DLC_PRESENT);
|
||||
add_native_detour(0x5D10B3795F3FC886, all_scripts::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA);
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x06843DA7060A026B, carmod_shop::SET_ENTITY_COORDS);
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x8E2530AA8ADA980E, carmod_shop::SET_ENTITY_HEADING);
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x34E710FF01247C5A, carmod_shop::SET_VEHICLE_LIGHTS);
|
||||
add_native_detour(RAGE_JOAAT("carmod_shop"), 0x767FBC2AC802EF3D, carmod_shop::STAT_GET_INT);
|
||||
add_native_detour(RAGE_JOAAT("freemode"), 0x95914459A87EBA28, freemode::NETWORK_BAIL);
|
||||
add_native_detour(RAGE_JOAAT("freemode"), 0x5E9564D8246B909A, freemode::IS_PLAYER_PLAYING);
|
||||
add_native_detour(RAGE_JOAAT("freemode"), 0xEA1C610A04DB6BBB, freemode::SET_ENTITY_VISIBLE);
|
||||
add_native_detour(RAGE_JOAAT("shop_controller"), 0xDC38CC1E35B6A5D7, shop_controller::SET_WARNING_MESSAGE_WITH_HEADER);
|
||||
add_native_detour(RAGE_JOAAT("maintransition"), 0x6F3D4ED9BEE4E61D, network::NETWORK_SESSION_HOST);
|
||||
add_native_detour(RAGE_JOAAT("am_launcher"), 0xB8BA7F44DF1575E1, am_launcher::START_NEW_SCRIPT_WITH_ARGS);
|
||||
|
||||
for (auto& entry : *g_pointers->m_script_program_table)
|
||||
if (entry.m_program)
|
||||
|
@ -542,6 +542,18 @@ namespace big
|
||||
m_sort_session_details = ptr.sub(0x10).as<PVOID>();
|
||||
});
|
||||
|
||||
// Add Player To Session
|
||||
main_batch.add("APTS", "E8 ? ? ? ? 48 8D 8D A0 01 00 00 8A D8", [this](memory::handle ptr)
|
||||
{
|
||||
m_add_player_to_session = ptr.add(1).rip().as<PVOID>();
|
||||
});
|
||||
|
||||
// Send Chat Net Message
|
||||
main_batch.add("SCNM", "E8 ? ? ? ? 41 FF C4 48 83 C5 08", [this](memory::handle ptr)
|
||||
{
|
||||
m_send_chat_net_message = ptr.add(1).rip().as<PVOID>();
|
||||
});
|
||||
|
||||
auto mem_region = memory::module("GTA5.exe");
|
||||
main_batch.run(mem_region);
|
||||
|
||||
|
@ -166,6 +166,9 @@ namespace big
|
||||
functions::queue_packet m_queue_packet;
|
||||
|
||||
PVOID m_sort_session_details;
|
||||
|
||||
PVOID m_add_player_to_session;
|
||||
PVOID m_send_chat_net_message;
|
||||
};
|
||||
|
||||
inline pointers* g_pointers{};
|
||||
|
@ -52,7 +52,9 @@ namespace big
|
||||
if (m_vmt_hook)
|
||||
{
|
||||
m_vmt_hook->disable();
|
||||
s_map.erase(m_program);
|
||||
|
||||
if (m_program)
|
||||
s_map.erase(m_program);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -73,13 +73,13 @@ namespace big
|
||||
|
||||
void mobile_service::register_vehicles()
|
||||
{
|
||||
const auto array_size = *mobile::vehicle_global.as<int*>();
|
||||
const auto array_size = *scr_globals::vehicle_global.as<int*>();
|
||||
for (int i = 0; i < array_size; i++)
|
||||
{
|
||||
if (i % 100 == 0)
|
||||
script::get_current()->yield();
|
||||
|
||||
auto veh_idx_global = mobile::vehicle_global.at(i, 142);
|
||||
auto veh_idx_global = scr_globals::vehicle_global.at(i, 142);
|
||||
|
||||
const auto hash = *veh_idx_global.at(66).as<Hash*>();
|
||||
const auto& it = m_pv_lookup.find(i);
|
||||
|
@ -41,7 +41,7 @@ namespace big
|
||||
|
||||
for (auto& p : json.items())
|
||||
{
|
||||
m_players[std::stoi(p.key())] = p.value().get<persistent_player>();
|
||||
m_players[std::stoll(p.key())] = p.value().get<persistent_player>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include "player_service.hpp"
|
||||
#include "vehicle/CVehicle.hpp"
|
||||
#include "network/snSession.hpp"
|
||||
#include "rate_limiter.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -33,21 +34,25 @@ namespace big
|
||||
[[nodiscard]] CPlayerInfo* get_player_info() const;
|
||||
[[nodiscard]] class rage::snPlayer* get_session_player();
|
||||
[[nodiscard]] class rage::snPeer* get_session_peer();
|
||||
|
||||
|
||||
[[nodiscard]] uint8_t id() const;
|
||||
|
||||
[[nodiscard]] bool is_friend() const;
|
||||
[[nodiscard]] bool is_host() const;
|
||||
[[nodiscard]] bool is_valid() const;
|
||||
|
||||
bool off_radar = false;
|
||||
bool never_wanted = false;
|
||||
bool semi_godmode = false;
|
||||
|
||||
std::chrono::system_clock::time_point m_last_transition_msg_sent{};
|
||||
int m_num_failed_transition_attempts = 0;
|
||||
rate_limiter m_host_migration_rate_limit{ 1s, 20 };
|
||||
rate_limiter m_play_sound_rate_limit{ 1s, 10 };
|
||||
|
||||
bool exposed_desync_protection = false;
|
||||
bool is_modder = false;
|
||||
bool block_join = false;
|
||||
int block_join_reason = 0;
|
||||
bool is_spammer = false;
|
||||
|
||||
protected:
|
||||
bool equals(const CNetGamePlayer* net_game_player) const;
|
||||
|
@ -30,15 +30,6 @@ namespace big
|
||||
m_players.clear();
|
||||
}
|
||||
|
||||
player_ptr player_service::get_by_name(std::string name)
|
||||
{
|
||||
std::transform(name.begin(), name.end(), name.begin(), ::tolower);
|
||||
|
||||
if (const auto it = m_players.find(name); it != m_players.end())
|
||||
return it->second;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
player_ptr player_service::get_by_msg_id(uint32_t msg_id) const
|
||||
{
|
||||
for (const auto& [_, player] : m_players)
|
||||
@ -49,7 +40,7 @@ namespace big
|
||||
|
||||
player_ptr player_service::get_by_id(uint32_t id) const
|
||||
{
|
||||
for (const auto& [name, player] : m_players)
|
||||
for (const auto& [_, player] : m_players)
|
||||
if (player->id() == id)
|
||||
return player;
|
||||
return nullptr;
|
||||
@ -57,7 +48,7 @@ namespace big
|
||||
|
||||
player_ptr player_service::get_by_host_token(uint64_t token) const
|
||||
{
|
||||
for (const auto& [name, player] : m_players)
|
||||
for (const auto& [_, player] : m_players)
|
||||
if (player->get_net_data()->m_host_token == token)
|
||||
return player;
|
||||
return nullptr;
|
||||
@ -83,10 +74,10 @@ namespace big
|
||||
if (net_game_player == nullptr || net_game_player == *m_self) return;
|
||||
|
||||
auto plyr = std::make_shared<player>(net_game_player);
|
||||
m_players.emplace(
|
||||
plyr->to_lowercase_identifier(),
|
||||
m_players.insert({
|
||||
plyr->get_name(),
|
||||
std::move(plyr)
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
void player_service::player_leave(CNetGamePlayer* net_game_player)
|
||||
@ -95,8 +86,10 @@ namespace big
|
||||
if (m_selected_player && m_selected_player->equals(net_game_player))
|
||||
m_selected_player = m_dummy;
|
||||
|
||||
auto plyr = std::make_unique<player>(net_game_player);
|
||||
m_players.erase(plyr->to_lowercase_identifier());
|
||||
if (auto it = std::find_if(m_players.begin(), m_players.end(), [net_game_player](const auto& p) { return p.second->id() == net_game_player->m_player_id; }); it != m_players.end())
|
||||
{
|
||||
m_players.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
void player_service::set_selected(player_ptr plyr)
|
||||
|
@ -7,7 +7,7 @@ namespace big
|
||||
|
||||
using player_ptr = std::shared_ptr<player>;
|
||||
using player_entry = std::pair<std::string, player_ptr>;
|
||||
using players = std::map<std::string, player_ptr>;
|
||||
using players = std::multimap<std::string, player_ptr>;
|
||||
|
||||
class player_service final
|
||||
{
|
||||
@ -33,7 +33,6 @@ namespace big
|
||||
|
||||
[[nodiscard]] player_ptr get_self();
|
||||
|
||||
[[nodiscard]] player_ptr get_by_name(std::string name);
|
||||
[[nodiscard]] player_ptr get_by_msg_id(uint32_t msg_id) const;
|
||||
[[nodiscard]] player_ptr get_by_id(uint32_t id) const;
|
||||
[[nodiscard]] player_ptr get_by_host_token(uint64_t token) const;
|
||||
@ -45,7 +44,7 @@ namespace big
|
||||
players& players()
|
||||
{ return m_players; }
|
||||
|
||||
void iterate(const std::function< void(const player_entry &entry) > func)
|
||||
void iterate(const std::function< void(const player_entry &entry)> func)
|
||||
{ for (const auto &iter : m_players) func(iter); }
|
||||
|
||||
void set_selected(player_ptr plyr);
|
||||
|
40
src/services/players/rate_limiter.hpp
Normal file
40
src/services/players/rate_limiter.hpp
Normal file
@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
namespace big
|
||||
{
|
||||
class rate_limiter
|
||||
{
|
||||
std::uint32_t m_attempts_allowed_in_time_period;
|
||||
std::chrono::milliseconds m_time_period;
|
||||
std::chrono::system_clock::time_point m_last_event_time{};
|
||||
std::uint32_t m_num_attempts_allowed = 0;
|
||||
public:
|
||||
rate_limiter(std::chrono::milliseconds time_period, std::uint32_t num_allowed_attempts) :
|
||||
m_attempts_allowed_in_time_period(num_allowed_attempts),
|
||||
m_time_period(time_period)
|
||||
{
|
||||
}
|
||||
|
||||
// Returns true if the rate limit has been exceeded
|
||||
bool process()
|
||||
{
|
||||
if (std::chrono::system_clock::now() - m_last_event_time < m_time_period)
|
||||
{
|
||||
if (++m_num_attempts_allowed > m_attempts_allowed_in_time_period)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_last_event_time = std::chrono::system_clock::now();
|
||||
m_num_attempts_allowed = 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the rate limit was exceeded by the last process() call. Use this to prevent the player from being flooded with notifications
|
||||
bool exceeded_last_process()
|
||||
{
|
||||
return (m_num_attempts_allowed - 1) == m_attempts_allowed_in_time_period;
|
||||
}
|
||||
};
|
||||
}
|
@ -32,7 +32,6 @@ namespace big::entity
|
||||
NETWORK::NETWORK_SET_ENTITY_ONLY_EXISTS_FOR_PARTICIPANTS(ent, true);
|
||||
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(ent, 0, 0, 0, 0, 0, 0);
|
||||
ENTITY::SET_ENTITY_AS_MISSION_ENTITY(ent, 1, 1);
|
||||
ENTITY::SET_ENTITY_AS_NO_LONGER_NEEDED(&ent);
|
||||
ENTITY::DELETE_ENTITY(&ent);
|
||||
}
|
||||
|
||||
@ -57,19 +56,23 @@ namespace big::entity
|
||||
return (bool)hit;
|
||||
}
|
||||
|
||||
inline bool take_control_of(Entity ent)
|
||||
inline bool take_control_of(Entity ent, int timeout = 1000)
|
||||
{
|
||||
if (NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent)) return true;
|
||||
for (uint8_t i = 0; !NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent) && i < 10; i++)
|
||||
if (NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent))
|
||||
return true;
|
||||
|
||||
for (uint8_t i = 0; !NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent) && i < timeout; i++)
|
||||
{
|
||||
NETWORK::NETWORK_REQUEST_CONTROL_OF_ENTITY(ent);
|
||||
|
||||
script::get_current()->yield(5ms);
|
||||
script::get_current()->yield();
|
||||
}
|
||||
if (!NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent)) return false;
|
||||
|
||||
if (!NETWORK::NETWORK_HAS_CONTROL_OF_ENTITY(ent))
|
||||
return false;
|
||||
|
||||
int netHandle = NETWORK::NETWORK_GET_NETWORK_ID_FROM_ENTITY(ent);
|
||||
NETWORK::SET_NETWORK_ID_CAN_MIGRATE(netHandle, true);
|
||||
NETWORK::SET_NETWORK_ID_CAN_MIGRATE(netHandle, false);
|
||||
NETWORK::NETWORK_DISABLE_PROXIMITY_MIGRATION(netHandle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1,26 +1,34 @@
|
||||
#pragma once
|
||||
#include "pointers.hpp"
|
||||
#include "script_global.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
|
||||
namespace big::globals
|
||||
{
|
||||
namespace size
|
||||
{
|
||||
constexpr int globalplayer_bd = 453;
|
||||
constexpr int gpbd_fm_3 = 599;
|
||||
constexpr int gpbd_fm_1 = 888;
|
||||
}
|
||||
|
||||
static inline script_global gpbd_fm_3(1892703);
|
||||
static inline script_global gsbd_fm_events(1920255);
|
||||
|
||||
inline void clear_wanted_player(Player target)
|
||||
{
|
||||
constexpr size_t arg_count = 3;
|
||||
int64_t args[arg_count] = {
|
||||
static_cast<int64_t>(eRemoteEvent::ClearWantedLevel),
|
||||
self::id,
|
||||
*script_global(1892703).at(target, 599).at(510).as<int*>()
|
||||
*scr_globals::gpbd_fm_3.at(target, scr_globals::size::gpbd_fm_3).at(510).as<int*>()
|
||||
};
|
||||
|
||||
g_pointers->m_trigger_script_event(1, args, arg_count, 1 << target);
|
||||
}
|
||||
|
||||
inline void give_remote_otr(Player target)
|
||||
{
|
||||
constexpr size_t arg_count = 7;
|
||||
int64_t args[arg_count] = {
|
||||
static_cast<int64_t>(eRemoteEvent::RemoteOffradar),
|
||||
(int64_t)self::id,
|
||||
(int64_t)(NETWORK::GET_NETWORK_TIME() + 1),
|
||||
0,
|
||||
true,
|
||||
false,
|
||||
*scr_globals::gpbd_fm_3.at(target, scr_globals::size::gpbd_fm_3).at(510).as<int64_t*>()
|
||||
};
|
||||
|
||||
g_pointers->m_trigger_script_event(1, args, arg_count, 1 << target);
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "core/enums.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
#include "globals.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "misc.hpp"
|
||||
@ -13,8 +14,6 @@
|
||||
namespace big::mobile
|
||||
{
|
||||
inline auto player_global = script_global(2689235);
|
||||
inline auto mechanic_global = script_global(2815059);
|
||||
inline auto vehicle_global = script_global(1585857);
|
||||
|
||||
namespace util
|
||||
{
|
||||
@ -22,7 +21,7 @@ namespace big::mobile
|
||||
inline void despawn_current_personal_vehicle()
|
||||
{
|
||||
misc::clear_bits(
|
||||
vehicle_global.at(get_current_personal_vehicle(), 142).at(103).as<int*>(),
|
||||
scr_globals::vehicle_global.at(get_current_personal_vehicle(), 142).at(103).as<int*>(),
|
||||
eVehicleFlags::TRIGGER_SPAWN_TOGGLE
|
||||
);
|
||||
}
|
||||
@ -37,7 +36,7 @@ namespace big::mobile
|
||||
{
|
||||
inline void off_radar(bool toggle)
|
||||
{
|
||||
*player_global.at(PLAYER::GET_PLAYER_INDEX(), 453).at(208).as<int*>() = toggle;
|
||||
*scr_globals::globalplayer_bd.at(PLAYER::GET_PLAYER_INDEX(), scr_globals::size::globalplayer_bd).at(208).as<int*>() = toggle;
|
||||
*script_global(2703735).at(56).as<int*>() = NETWORK::GET_NETWORK_TIME() + 1;
|
||||
}
|
||||
}
|
||||
@ -46,12 +45,12 @@ namespace big::mobile
|
||||
{
|
||||
inline void request_ammo_drop()
|
||||
{
|
||||
*script_global(mechanic_global).at(874).as<int*>() = 1;
|
||||
*script_global(scr_globals::mechanic_global).at(874).as<int*>() = 1;
|
||||
}
|
||||
|
||||
inline void request_helicopter_pickup()
|
||||
{
|
||||
*script_global(mechanic_global).at(876).as<int*>() = 1;
|
||||
*script_global(scr_globals::mechanic_global).at(876).as<int*>() = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -60,21 +59,21 @@ namespace big::mobile
|
||||
inline bool fix_index(int veh_idx, bool spawn_veh = false)
|
||||
{
|
||||
bool can_be_fixed = misc::has_bits_set(
|
||||
vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
scr_globals::vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
eVehicleFlags::DESTROYED | eVehicleFlags::HAS_INSURANCE
|
||||
);
|
||||
|
||||
if (can_be_fixed)
|
||||
{
|
||||
misc::clear_bits(
|
||||
vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
scr_globals::vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
eVehicleFlags::DESTROYED | eVehicleFlags::IMPOUNDED | eVehicleFlags::UNK2
|
||||
);
|
||||
|
||||
if (spawn_veh)
|
||||
{
|
||||
misc::set_bits(
|
||||
vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
scr_globals::vehicle_global.at(veh_idx, 142).at(103).as<int*>(),
|
||||
eVehicleFlags::TRIGGER_SPAWN_TOGGLE | eVehicleFlags::SPAWN_AT_MORS_MUTUAL
|
||||
);
|
||||
}
|
||||
@ -86,7 +85,7 @@ namespace big::mobile
|
||||
{
|
||||
int fixed_count = 0;
|
||||
|
||||
const int arr_size = *vehicle_global.as<int*>();
|
||||
const int arr_size = *scr_globals::vehicle_global.as<int*>();
|
||||
for (int i = 0; i < arr_size; i++)
|
||||
if (fix_index(i, true))
|
||||
fixed_count++;
|
||||
@ -99,12 +98,12 @@ namespace big::mobile
|
||||
{
|
||||
inline Vehicle get_personal_vehicle()
|
||||
{
|
||||
return *mechanic_global.at(298).as<Vehicle*>();
|
||||
return *scr_globals::mechanic_global.at(298).as<Vehicle*>();
|
||||
}
|
||||
|
||||
inline void summon_vehicle_by_index(int veh_idx)
|
||||
{
|
||||
if (*mechanic_global.at(958).as<int*>() != -1)
|
||||
if (*scr_globals::mechanic_global.at(958).as<int*>() != -1)
|
||||
return g_notification_service->push_warning("Vehicle", "Mechanic is not ready to deliver a vehicle right now.");
|
||||
|
||||
if (g->clone_pv.spawn_inside && self::veh)
|
||||
@ -116,10 +115,10 @@ namespace big::mobile
|
||||
|
||||
script::get_current()->yield(100ms);
|
||||
|
||||
*mechanic_global.at(924).as<int*>() = 1; // disable vehicle node distance check
|
||||
*mechanic_global.at(911).as<int*>() = 1; // tell freemode to spawn our vehicle
|
||||
*mechanic_global.at(961).as<int*>() = 0; // required
|
||||
*mechanic_global.at(958).as<int*>() = veh_idx;
|
||||
*scr_globals::mechanic_global.at(924).as<int*>() = 1; // disable vehicle node distance check
|
||||
*scr_globals::mechanic_global.at(911).as<int*>() = 1; // tell freemode to spawn our vehicle
|
||||
*scr_globals::mechanic_global.at(961).as<int*>() = 0; // required
|
||||
*scr_globals::mechanic_global.at(958).as<int*>() = veh_idx;
|
||||
|
||||
script::get_current()->yield(100ms);
|
||||
|
||||
@ -128,7 +127,7 @@ namespace big::mobile
|
||||
*script_local(freemode_thread, 18399).at(176).as<int*>() = 0; // spawn vehicle instantly
|
||||
|
||||
// blocking call till vehicle is delivered
|
||||
notify::busy_spinner("Delivering vehicle...", mechanic_global.at(958).as<int*>(), -1);
|
||||
notify::busy_spinner("Delivering vehicle...", scr_globals::mechanic_global.at(958).as<int*>(), -1);
|
||||
|
||||
if (g->clone_pv.spawn_inside)
|
||||
{
|
||||
|
@ -2,6 +2,11 @@
|
||||
#include "fiber_pool.hpp"
|
||||
#include "natives.hpp"
|
||||
#include "script.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "misc.hpp"
|
||||
#include "gta/script_handler.hpp"
|
||||
#include "script_local.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
|
||||
namespace big::scripts
|
||||
{
|
||||
@ -12,7 +17,7 @@ namespace big::scripts
|
||||
|
||||
inline bool is_running(int hash)
|
||||
{
|
||||
return SCRIPT::DOES_SCRIPT_WITH_NAME_HASH_EXIST(hash);
|
||||
return SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH(hash) > 0;
|
||||
}
|
||||
|
||||
inline void request_script(int hash)
|
||||
@ -44,4 +49,105 @@ namespace big::scripts
|
||||
if (is_running(hash)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// force launcher script over the lobby, take two
|
||||
// try to get am_launcher in a consistent state before trying to start the script taking account of all participants
|
||||
inline void start_launcher_script(int script_id)
|
||||
{
|
||||
static auto check_players_in_state = [](GtaThread* launcher, int state) -> bool
|
||||
{
|
||||
bool set = false;
|
||||
|
||||
gta_util::execute_as_script(RAGE_JOAAT("am_launcher"), [launcher, state, &set]
|
||||
{
|
||||
for (auto& [_, plyr] : g_player_service->players())
|
||||
{
|
||||
if (NETWORK::NETWORK_IS_PLAYER_A_PARTICIPANT(plyr->id()))
|
||||
{
|
||||
if (*script_local(launcher->m_stack, 230).at(plyr->id(), 3).at(2).as<int*>() == state)
|
||||
{
|
||||
set = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return set;
|
||||
};
|
||||
|
||||
// 1) Get launcher
|
||||
if (auto launcher = gta_util::find_script_thread(RAGE_JOAAT("am_launcher")))
|
||||
{
|
||||
// 2) Force host of launcher
|
||||
for (int i = 0; NETWORK::NETWORK_GET_HOST_OF_SCRIPT("am_launcher", -1, 0) != self::id; i++)
|
||||
{
|
||||
if (i > 3600)
|
||||
{
|
||||
// 2F) Failed to force host of launcher
|
||||
g_notification_service->push_error("Script", "Cannot force script host of am_launcher");
|
||||
return;
|
||||
}
|
||||
|
||||
((CGameScriptHandlerNetComponent*)launcher->m_net_component)->send_host_migration_event(g_player_service->get_self()->get_net_game_player());
|
||||
script::get_current()->yield();
|
||||
}
|
||||
|
||||
launcher->m_context.m_state = rage::eThreadState::unk_3; // prevent bad things from happening to the thread in the meantime
|
||||
|
||||
// 3) Remove players from that annoying waiting stage
|
||||
if (check_players_in_state(launcher, 5))
|
||||
{
|
||||
for (int i = 0; check_players_in_state(launcher, 5); i++)
|
||||
{
|
||||
if (i > 200)
|
||||
break; // 3F) Timeout
|
||||
|
||||
*scr_globals::launcher_global.at(3).at(1).as<int*>() = 0;
|
||||
*scr_globals::launcher_global.at(2).as<int*>() = 6;
|
||||
script::get_current()->yield(10ms);
|
||||
}
|
||||
} // State should now be 6 or 0
|
||||
|
||||
// 4) Check if a script is already being executed, and unstuck from that state if so
|
||||
if (check_players_in_state(launcher, 6))
|
||||
{
|
||||
for (int i = 0; check_players_in_state(launcher, 6); i++)
|
||||
{
|
||||
if (i > 200)
|
||||
break; // 4F) Timeout
|
||||
|
||||
*scr_globals::launcher_global.at(3).at(1).as<int*>() = 0;
|
||||
*scr_globals::launcher_global.at(2).as<int*>() = 7;
|
||||
script::get_current()->yield(10ms);
|
||||
}
|
||||
} // State should now be 7 or 0
|
||||
|
||||
// 5) Get everyone out of state 7
|
||||
if (check_players_in_state(launcher, 7))
|
||||
{
|
||||
for (int i = 0; check_players_in_state(launcher, 7); i++)
|
||||
{
|
||||
if (i > 200)
|
||||
break; // 5F) Timeout
|
||||
|
||||
*scr_globals::launcher_global.at(2).as<int*>() = 0;
|
||||
script::get_current()->yield(10ms);
|
||||
}
|
||||
} // State should now be 0
|
||||
|
||||
// 6) Actually get the script to start
|
||||
misc::set_bit(scr_globals::launcher_global.at(1).as<int*>(), 1); // run immediately
|
||||
*scr_globals::launcher_global.at(2).as<int*>() = 6; // will change to 7 shortly but that's fine as players are guaranteed not to be in the waiting stage
|
||||
*script_local(launcher->m_stack, 230).at(self::id, 3).at(2).as<int*>() = 6;
|
||||
*scr_globals::launcher_global.at(3).at(1).as<int*>() = script_id;
|
||||
|
||||
launcher->m_context.m_state = rage::eThreadState::running;
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1F) Cannot find launcher
|
||||
g_notification_service->push_error("Script", "Cannot start script, am_launcher not running locally");
|
||||
}
|
||||
}
|
||||
}
|
@ -45,9 +45,9 @@ namespace big::session
|
||||
{
|
||||
int idx = index / 32;
|
||||
int bit = index % 32;
|
||||
misc::set_bit(globals::gsbd_fm_events.at(11).at(341).at(idx, 1).as<int*>(), bit);
|
||||
misc::set_bit(globals::gsbd_fm_events.at(11).at(348).at(idx, 1).as<int*>(), bit);
|
||||
misc::set_bit(globals::gpbd_fm_3.at(self::id, globals::size::gpbd_fm_3).at(10).at(205).at(idx, 1).as<int*>(), bit);
|
||||
misc::set_bit(scr_globals::gsbd_fm_events.at(11).at(341).at(idx, 1).as<int*>(), bit);
|
||||
misc::set_bit(scr_globals::gsbd_fm_events.at(11).at(348).at(idx, 1).as<int*>(), bit);
|
||||
misc::set_bit(scr_globals::gpbd_fm_3.at(self::id, scr_globals::size::gpbd_fm_3).at(10).at(205).at(idx, 1).as<int*>(), bit);
|
||||
}
|
||||
|
||||
inline void force_thunder()
|
||||
@ -89,15 +89,18 @@ namespace big::session
|
||||
}
|
||||
}
|
||||
|
||||
g_notification_service->push_error("RID Joiner", "Target Player is offline?");
|
||||
g_notification_service->push_error("RID Joiner", "Target player is offline?");
|
||||
}
|
||||
|
||||
inline void add_infraction(player_ptr player, Infraction infraction)
|
||||
{
|
||||
auto plyr = g_player_database_service->get_or_create_player(player);
|
||||
plyr->is_modder = true;
|
||||
player->is_modder = true;
|
||||
plyr->infractions.insert((int)infraction);
|
||||
g_player_database_service->save();
|
||||
if (!plyr->infractions.contains((int)infraction))
|
||||
{
|
||||
plyr->is_modder = true;
|
||||
player->is_modder = true;
|
||||
plyr->infractions.insert((int)infraction);
|
||||
g_player_database_service->save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
52
src/util/spam.hpp
Normal file
52
src/util/spam.hpp
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
#include "services/players/player_service.hpp"
|
||||
#include "file_manager/file.hpp"
|
||||
|
||||
namespace
|
||||
{
|
||||
static const char* spam_texts[] =
|
||||
{
|
||||
"QQ",
|
||||
"WWW.",
|
||||
"www.",
|
||||
".cn",
|
||||
".CN",
|
||||
".TOP",
|
||||
".COM",
|
||||
"\xE3\x80\x90",
|
||||
"/Menu",
|
||||
"Money/",
|
||||
"Money\\\\",
|
||||
"Money\\",
|
||||
".gg",
|
||||
"--->",
|
||||
"shopgta5",
|
||||
"doit#"
|
||||
};
|
||||
}
|
||||
|
||||
namespace big::spam
|
||||
{
|
||||
inline bool is_text_spam(const char* text)
|
||||
{
|
||||
for (auto e : spam_texts)
|
||||
if (strstr(text, e) != 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void log_chat(char* msg, player_ptr player, bool is_spam)
|
||||
{
|
||||
std::ofstream spam_log(g_file_manager->get_project_file(is_spam ? "./spam.log" : "./chat.log").get_path(), std::ios::app);
|
||||
|
||||
auto& plData = *player->get_net_data();
|
||||
|
||||
spam_log << player->get_name() << " (" << plData.m_gamer_handle_2.m_rockstar_id << ") <"
|
||||
<< (int)plData.m_external_ip.m_field1 << "." << (int)plData.m_external_ip.m_field2 << "." << (int)plData.m_external_ip.m_field3 << "." << (int)plData.m_external_ip.m_field4 <<
|
||||
">: " << msg <<
|
||||
std::endl;
|
||||
|
||||
spam_log.close();
|
||||
}
|
||||
}
|
@ -7,13 +7,12 @@
|
||||
#include "script.hpp"
|
||||
#include "teleport.hpp"
|
||||
#include "script_global.hpp"
|
||||
#include "gta\VehicleValues.h"
|
||||
#include "gta/VehicleValues.h"
|
||||
#include "services/vehicle_helper/vehicle_helper.hpp"
|
||||
#include "core/scr_globals.hpp"
|
||||
|
||||
namespace big::vehicle
|
||||
{
|
||||
inline auto spawn_global = script_global(2725439);
|
||||
|
||||
inline void go_into_personal_vehicle()
|
||||
{
|
||||
*script_global(2671449).at(8).as<int*>() = 1;
|
||||
@ -202,8 +201,6 @@ namespace big::vehicle
|
||||
auto veh = VEHICLE::CREATE_VEHICLE(hash, location.x, location.y, location.z, heading, is_networked, false, false);
|
||||
*(unsigned short*)g_pointers->m_model_spawn_bypass = 0x0574;
|
||||
|
||||
script::get_current()->yield();
|
||||
|
||||
STREAMING::SET_MODEL_AS_NO_LONGER_NEEDED(hash);
|
||||
|
||||
if (*g_pointers->m_is_session_started)
|
||||
@ -227,31 +224,31 @@ namespace big::vehicle
|
||||
{
|
||||
if (idx >= 0 && idx < 142)
|
||||
{
|
||||
*spawn_global.at(27).at(idx).as<int32_t*>() = val;
|
||||
*scr_globals::spawn_global.at(27).at(idx).as<int32_t*>() = val;
|
||||
}
|
||||
}
|
||||
|
||||
// permission fix
|
||||
*spawn_global.at(27).at(1).as<int32_t*>() = 0;
|
||||
*scr_globals::spawn_global.at(27).at(1).as<int32_t*>() = 0;
|
||||
|
||||
// personal car flag
|
||||
*spawn_global.at(27).at(94).as<int32_t*>() = 14;
|
||||
*spawn_global.at(27).at(95).as<int32_t*>() = 2;
|
||||
*scr_globals::spawn_global.at(27).at(94).as<int32_t*>() = 14;
|
||||
*scr_globals::spawn_global.at(27).at(95).as<int32_t*>() = 2;
|
||||
|
||||
// mmi
|
||||
*spawn_global.at(27).at(103).as<int32_t*>() = 0;
|
||||
*scr_globals::spawn_global.at(27).at(103).as<int32_t*>() = 0;
|
||||
|
||||
// spawn location
|
||||
*spawn_global.at(7).at(0).as<float*>() = tmpLocation.x;
|
||||
*spawn_global.at(7).at(1).as<float*>() = tmpLocation.y;
|
||||
*spawn_global.at(7).at(2).as<float*>() = tmpLocation.z;
|
||||
*scr_globals::spawn_global.at(7).at(0).as<float*>() = tmpLocation.x;
|
||||
*scr_globals::spawn_global.at(7).at(1).as<float*>() = tmpLocation.y;
|
||||
*scr_globals::spawn_global.at(7).at(2).as<float*>() = tmpLocation.z;
|
||||
|
||||
// spawn non pegasus
|
||||
*spawn_global.at(3).as<int*>() = 0;
|
||||
*scr_globals::spawn_global.at(3).as<int*>() = 0;
|
||||
|
||||
// spawn signal
|
||||
int* spawn_signal = spawn_global.at(2).as<int32_t*>();
|
||||
*spawn_global.at(5).as<int32_t*>() = 1;
|
||||
int* spawn_signal = scr_globals::spawn_global.at(2).as<int32_t*>();
|
||||
*scr_globals::spawn_global.at(5).as<int32_t*>() = 1;
|
||||
*spawn_signal = 1;
|
||||
|
||||
// wait until the vehicle is spawned
|
||||
@ -666,4 +663,52 @@ namespace big::vehicle
|
||||
else
|
||||
return g_notification_service->push_warning("Vehicle", "Please be in a car first then try again.");
|
||||
}
|
||||
|
||||
inline bool remote_control_vehicle(Vehicle veh)
|
||||
{
|
||||
if (!entity::take_control_of(veh, 4000))
|
||||
{
|
||||
g_notification_service->push_warning("Remote Control", "Failed to take control of remote vehicle");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g->m_remote_controlled_vehicle == veh)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Hash model = ENTITY::GET_ENTITY_MODEL(veh);
|
||||
Vehicle spawned = vehicle::spawn(model, self::pos, 0.0f);
|
||||
|
||||
ENTITY::SET_ENTITY_ALPHA(spawned, 0, FALSE);
|
||||
if (!VEHICLE::IS_THIS_MODEL_A_BIKE(model))
|
||||
ENTITY::SET_ENTITY_VISIBLE(spawned, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(spawned, TRUE);
|
||||
|
||||
float heading = ENTITY::GET_ENTITY_HEADING(veh);
|
||||
Vector3 rotation = ENTITY::GET_ENTITY_ROTATION(veh, 2);
|
||||
Vector3 coords = ENTITY::GET_ENTITY_COORDS(veh, FALSE);
|
||||
Vector3 velocity = ENTITY::GET_ENTITY_VELOCITY(veh);
|
||||
|
||||
ENTITY::SET_ENTITY_COORDS_NO_OFFSET(spawned, coords.x, coords.y, coords.z, FALSE, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_HEADING(spawned, heading);
|
||||
ENTITY::SET_ENTITY_ROTATION(spawned, rotation.x, rotation.y, rotation.z, 2, TRUE);
|
||||
|
||||
ENTITY::SET_ENTITY_VISIBLE(veh, TRUE, FALSE);
|
||||
|
||||
ENTITY::SET_ENTITY_COLLISION(veh, FALSE, FALSE);
|
||||
ENTITY::SET_ENTITY_INVINCIBLE(veh, TRUE);
|
||||
VEHICLE::SET_VEHICLE_DOORS_LOCKED(veh, 4);
|
||||
VEHICLE::SET_VEHICLE_MAX_SPEED(veh, 0.0001f);
|
||||
ENTITY::ATTACH_ENTITY_TO_ENTITY(veh, spawned, 0, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, FALSE, FALSE, FALSE, FALSE, 0, TRUE, FALSE);
|
||||
PED::SET_PED_INTO_VEHICLE(PLAYER::PLAYER_PED_ID(), spawned, -1);
|
||||
|
||||
VEHICLE::SET_VEHICLE_ENGINE_ON(spawned, TRUE, TRUE, FALSE);
|
||||
ENTITY::SET_ENTITY_VELOCITY(spawned, velocity.x, velocity.y, velocity.z);
|
||||
VEHICLE::COPY_VEHICLE_DAMAGES(veh, spawned);
|
||||
|
||||
g->m_remote_controller_vehicle = spawned;
|
||||
g->m_remote_controlled_vehicle = veh;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include "core/data/region_codes.hpp"
|
||||
#include "gta_util.hpp"
|
||||
#include "util/notify.hpp"
|
||||
#include "util/scripts.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -74,5 +75,55 @@ namespace big
|
||||
ImGui::Checkbox("Force Session Host", &g->session.force_session_host);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Join another session to apply changes. The original host of the session must leave or be kicked. This feature is easily detectable by other mod menus, use with caution");
|
||||
|
||||
components::sub_title("Remote Name Spoofing");
|
||||
ImGui::Checkbox("Spoof Other Players' Names", &g->session.name_spoof_enabled);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Requires session host. Spoofed names will not visible locally nor to the player that had their name spoofed. Requires players to join after becoming host");
|
||||
|
||||
if (g->session.name_spoof_enabled)
|
||||
{
|
||||
ImGui::Checkbox("Advertise YimMenu", &g->session.advertise_menu);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Advertise YimMenu by spoofing player names to differently colored variants of 'YimMenu'. You will not be able to customize the name with this option enabled");
|
||||
|
||||
if (!g->session.advertise_menu)
|
||||
{
|
||||
constexpr size_t name_size = RTL_FIELD_SIZE(rage::rlGamerInfo, m_name);
|
||||
static char name[name_size];
|
||||
strcpy_s(name, sizeof(name), g->session.spoofed_name.c_str());
|
||||
|
||||
ImGui::Text("Name: ");
|
||||
ImGui::InputText("##username_input", name, sizeof(name));
|
||||
|
||||
if (name != g->session.spoofed_name)
|
||||
g->session.spoofed_name = std::string(name);
|
||||
}
|
||||
}
|
||||
|
||||
components::sub_title("All Players");
|
||||
ImGui::Checkbox("Off The Radar", &g->session.off_radar_all);
|
||||
ImGui::Checkbox("Never Wanted", &g->session.never_wanted_all);
|
||||
ImGui::Checkbox("Semi Godmode", &g->session.semi_godmode_all);
|
||||
|
||||
components::sub_title("Event Starter");
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::button("Hot Target", [] { scripts::start_launcher_script(36); });
|
||||
components::button("Kill List", [] { scripts::start_launcher_script(37); });
|
||||
components::button("Checkpoints", [] { scripts::start_launcher_script(39); });
|
||||
components::button("Challenges", [] { scripts::start_launcher_script(40); });
|
||||
components::button("Penned In", [] { scripts::start_launcher_script(41); });
|
||||
ImGui::EndGroup();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginGroup();
|
||||
components::button("Hot Property", [] { scripts::start_launcher_script(43); });
|
||||
components::button("King Of The Castle", [] { scripts::start_launcher_script(45); });
|
||||
components::button("Criminal Damage", [] { scripts::start_launcher_script(46); });
|
||||
components::button("Hunt The Beast", [] { scripts::start_launcher_script(47); });
|
||||
components::button("Business Battles", [] { scripts::start_launcher_script(114); });
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include "util/ped.hpp"
|
||||
#include "util/teleport.hpp"
|
||||
#include "views/view.hpp"
|
||||
#include "util/vehicle.hpp"
|
||||
|
||||
namespace big
|
||||
{
|
||||
@ -108,6 +109,11 @@ namespace big
|
||||
if (auto net_player_data = g_player_service->get_selected()->get_net_data(); net_player_data != nullptr)
|
||||
{
|
||||
ImGui::Text("Rockstar ID: %d", net_player_data->m_gamer_handle_2.m_rockstar_id);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Copy")) ImGui::SetClipboardText(std::to_string(net_player_data->m_gamer_handle_2.m_rockstar_id).data());
|
||||
|
||||
ImGui::Text(
|
||||
"IP Address: %d.%d.%d.%d:%d",
|
||||
net_player_data->m_external_ip.m_field1,
|
||||
@ -116,6 +122,14 @@ namespace big
|
||||
net_player_data->m_external_ip.m_field4,
|
||||
net_player_data->m_external_port
|
||||
);
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Copy")) ImGui::SetClipboardText(std::format("{}.{}.{}.{}:{}", net_player_data->m_external_ip.m_field1,
|
||||
net_player_data->m_external_ip.m_field2,
|
||||
net_player_data->m_external_ip.m_field3,
|
||||
net_player_data->m_external_ip.m_field4,
|
||||
net_player_data->m_external_port).data());
|
||||
}
|
||||
|
||||
if (ImGui::Button("Add To Database"))
|
||||
@ -149,6 +163,12 @@ namespace big
|
||||
|
||||
if (ImGui::TreeNode("Misc"))
|
||||
{
|
||||
components::button("Join CEO/MC", []
|
||||
{
|
||||
*scr_globals::gpbd_fm_3.at(self::id, scr_globals::size::gpbd_fm_3).at(10).as<int*>() = g_player_service->get_selected()->id();
|
||||
*scr_globals::gpbd_fm_3.at(self::id, scr_globals::size::gpbd_fm_3).at(10).at(26).as<int*>() = g_player_service->get_selected()->id();
|
||||
});
|
||||
|
||||
components::button("Steal Outfit", []
|
||||
{
|
||||
ped::steal_outfit(
|
||||
@ -172,8 +192,6 @@ namespace big
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::Checkbox("Never Wanted", &g_player_service->get_selected()->never_wanted);
|
||||
|
||||
components::button("Give Health", []
|
||||
{
|
||||
g_pickup_service->give_player_health(g_player_service->get_selected()->id());
|
||||
@ -198,6 +216,26 @@ namespace big
|
||||
g_pickup_service->give_player_weapons(g_player_service->get_selected()->id());
|
||||
});
|
||||
|
||||
ImGui::Checkbox("Off The Radar", &g_player_service->get_selected()->off_radar);
|
||||
ImGui::Checkbox("Never Wanted", &g_player_service->get_selected()->never_wanted);
|
||||
ImGui::Checkbox("Semi Godmode", &g_player_service->get_selected()->semi_godmode);
|
||||
|
||||
components::button("Remote Control Vehicle", []
|
||||
{
|
||||
Vehicle veh = PED::GET_VEHICLE_PED_IS_IN(PLAYER::GET_PLAYER_PED_SCRIPT_INDEX(g_player_service->get_selected()->id()), FALSE);
|
||||
if (veh == 0)
|
||||
{
|
||||
if (g->player.spectating)
|
||||
g_notification_service->push_warning("Remote Control", "Player not in a vehicle");
|
||||
else
|
||||
g_notification_service->push_warning("Remote Control", "Player not in a vehicle, try spectating the player");
|
||||
return;
|
||||
}
|
||||
|
||||
vehicle::remote_control_vehicle(veh);
|
||||
g->player.spectating = false;
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
@ -47,6 +47,9 @@ namespace big
|
||||
ImGui::Checkbox("RID Join", &g->protections.rid_join);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("This will block anyone trying to join you through Rockstar ID, including your friends");
|
||||
ImGui::Checkbox("Lessen Breakup Kicks As Host", &g->protections.lessen_breakups);
|
||||
if (ImGui::IsItemHovered())
|
||||
ImGui::SetTooltip("Attacker must join after you have become host for this to work. There are anti-cheat concerns with this feature");
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user